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/api.ts
CHANGED
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
import { execSync } from "child_process";
|
|
1
|
+
import { execFileSync, execSync } from "child_process";
|
|
2
2
|
import fs from "fs";
|
|
3
3
|
import path from "path";
|
|
4
4
|
|
|
@@ -19,13 +19,9 @@ import {
|
|
|
19
19
|
isSoException,
|
|
20
20
|
ServiceUnavailableException,
|
|
21
21
|
} from "../exceptions/so-exceptions";
|
|
22
|
-
import { Migrator } from "../migration/migrator";
|
|
23
|
-
import { type MigrationResult } from "../migration/migrator";
|
|
24
|
-
import { SlackConfirm } from "../migration/slack-confirm";
|
|
25
|
-
import { type SlackConfirmPendingResult } from "../migration/slack-confirm";
|
|
26
22
|
import { TemplateManager } from "../template/template-manager";
|
|
27
|
-
import { DataExplorer } from "../testing/data-explorer";
|
|
28
|
-
import { FixtureGenerator } from "../testing/fixture-generator";
|
|
23
|
+
import { DataExplorer, type DataExplorerOptions } from "../testing/data-explorer";
|
|
24
|
+
import { FixtureGenerator, type FixtureGenerationSpec } from "../testing/fixture-generator";
|
|
29
25
|
import { FixtureManager } from "../testing/fixture-manager";
|
|
30
26
|
import { type DuplicateCheckOptions } from "../testing/fixture-manager";
|
|
31
27
|
import { BUILT_IN_TYPE_IDS, TemplateKey } from "../types/types";
|
|
@@ -39,8 +35,10 @@ import {
|
|
|
39
35
|
type FlattenSubsetRow,
|
|
40
36
|
type PathAndCode,
|
|
41
37
|
} from "../types/types";
|
|
38
|
+
import { isObjectValue } from "../utils/runtime-value";
|
|
42
39
|
import { nonNullable } from "../utils/utils";
|
|
43
40
|
import { setAiApi } from "./ai-api";
|
|
41
|
+
import { forwardAsyncErrors } from "./async-route";
|
|
44
42
|
import { type CddAddRuleRequest } from "./cdd-service";
|
|
45
43
|
import {
|
|
46
44
|
addRule,
|
|
@@ -52,35 +50,45 @@ import {
|
|
|
52
50
|
readContent,
|
|
53
51
|
readRule,
|
|
54
52
|
} from "./cdd-service";
|
|
53
|
+
import { registerMigrationsApi } from "./migrations-api";
|
|
55
54
|
|
|
56
|
-
|
|
57
|
-
|
|
58
|
-
|
|
59
|
-
|
|
60
|
-
const migrator = new Migrator();
|
|
61
|
-
|
|
62
|
-
// waitForHMRCompleted
|
|
63
|
-
async function waitForHMRCompleted<T>(fn: () => Promise<T>): Promise<T> {
|
|
64
|
-
const waitPromise = new Promise<void>((resolve) => {
|
|
65
|
-
const handler = () => {
|
|
66
|
-
clearTimeout(timeout);
|
|
67
|
-
resolve();
|
|
68
|
-
};
|
|
55
|
+
interface EntityTemplateInput {
|
|
56
|
+
entityId: string;
|
|
57
|
+
enumId?: string;
|
|
58
|
+
}
|
|
69
59
|
|
|
70
|
-
|
|
71
|
-
|
|
72
|
-
|
|
73
|
-
|
|
60
|
+
async function waitForHMRCompleted<T>(fn: () => Promise<T>): Promise<T> {
|
|
61
|
+
const waitPromise = new Promise<void>((resolve) => {
|
|
62
|
+
const handler = () => {
|
|
63
|
+
clearTimeout(timeout);
|
|
64
|
+
resolve();
|
|
65
|
+
};
|
|
74
66
|
|
|
75
|
-
|
|
76
|
-
|
|
67
|
+
const timeout = setTimeout(() => {
|
|
68
|
+
Sonamu.syncer.eventEmitter.off("onHMRCompleted", handler);
|
|
69
|
+
resolve();
|
|
70
|
+
}, 1500);
|
|
77
71
|
|
|
78
|
-
|
|
79
|
-
|
|
80
|
-
return result;
|
|
81
|
-
}
|
|
72
|
+
Sonamu.syncer.eventEmitter.once("onHMRCompleted", handler);
|
|
73
|
+
});
|
|
82
74
|
|
|
75
|
+
const result = await fn();
|
|
76
|
+
await waitPromise;
|
|
77
|
+
return result;
|
|
78
|
+
}
|
|
79
|
+
|
|
80
|
+
function flattenSubsetRows(subsetRows: EntitySubsetRow[]): FlattenSubsetRow[] {
|
|
81
|
+
return subsetRows.flatMap((subsetRow) => {
|
|
82
|
+
const { children, ...sRow } = subsetRow;
|
|
83
|
+
return [sRow, ...flattenSubsetRows(children)];
|
|
84
|
+
});
|
|
85
|
+
}
|
|
86
|
+
|
|
87
|
+
export async function sonamuUIApiPlugin(fastify: FastifyInstance) {
|
|
88
|
+
fastify.register(
|
|
89
|
+
async (server) => {
|
|
83
90
|
await setAiApi(server);
|
|
91
|
+
await registerMigrationsApi(server);
|
|
84
92
|
|
|
85
93
|
server.get("/api/sonamu/config", async () => {
|
|
86
94
|
return Sonamu.config;
|
|
@@ -92,165 +100,188 @@ export async function sonamuUIApiPlugin(fastify: FastifyInstance) {
|
|
|
92
100
|
preset?: "types" | "entity.json" | "generated";
|
|
93
101
|
absPath?: string;
|
|
94
102
|
};
|
|
95
|
-
}>("/api/tools/openVscode",
|
|
96
|
-
|
|
97
|
-
|
|
98
|
-
|
|
99
|
-
|
|
100
|
-
|
|
101
|
-
|
|
102
|
-
|
|
103
|
-
|
|
104
|
-
|
|
105
|
-
|
|
106
|
-
|
|
107
|
-
|
|
108
|
-
|
|
109
|
-
|
|
110
|
-
|
|
111
|
-
|
|
103
|
+
}>("/api/tools/openVscode", (request) =>
|
|
104
|
+
forwardAsyncErrors(async () => {
|
|
105
|
+
const { entityId, preset, absPath } = request.query;
|
|
106
|
+
|
|
107
|
+
const targetPath = (() => {
|
|
108
|
+
if (entityId && preset) {
|
|
109
|
+
const entity = EntityManager.get(entityId);
|
|
110
|
+
const { names } = entity;
|
|
111
|
+
|
|
112
|
+
const { apiRootPath } = Sonamu;
|
|
113
|
+
const filename = (() => {
|
|
114
|
+
switch (preset) {
|
|
115
|
+
case "types":
|
|
116
|
+
return `${names.fs}.types.ts`;
|
|
117
|
+
case "entity.json":
|
|
118
|
+
return `${names.fs}.entity.json`;
|
|
119
|
+
case "generated":
|
|
120
|
+
return `${names.fs}.generated.ts`;
|
|
121
|
+
}
|
|
122
|
+
return undefined;
|
|
123
|
+
})();
|
|
124
|
+
return `${apiRootPath}/src/application/${entity.names.parentFs}/${filename}`;
|
|
125
|
+
} else {
|
|
126
|
+
if (!absPath) {
|
|
127
|
+
throw new BadRequestException(SD("sonamu.error.presetOrAbsPathRequired"));
|
|
112
128
|
}
|
|
113
|
-
|
|
114
|
-
return `${apiRootPath}/src/application/${entity.names.parentFs}/${filename}`;
|
|
115
|
-
} else {
|
|
116
|
-
if (!absPath) {
|
|
117
|
-
throw new BadRequestException(SD("sonamu.error.presetOrAbsPathRequired"));
|
|
129
|
+
return absPath;
|
|
118
130
|
}
|
|
119
|
-
|
|
131
|
+
})();
|
|
132
|
+
execSync(`code ${targetPath}`);
|
|
133
|
+
}),
|
|
134
|
+
);
|
|
135
|
+
|
|
136
|
+
server.get<{
|
|
137
|
+
Querystring: {
|
|
138
|
+
editor: "vscode" | "cursor" | "zed";
|
|
139
|
+
absPath: string;
|
|
140
|
+
};
|
|
141
|
+
}>("/api/tools/openEditor", (request) =>
|
|
142
|
+
forwardAsyncErrors(async () => {
|
|
143
|
+
const commands = {
|
|
144
|
+
vscode: "code",
|
|
145
|
+
cursor: "cursor",
|
|
146
|
+
zed: "zed",
|
|
147
|
+
} as const;
|
|
148
|
+
const command = commands[request.query.editor];
|
|
149
|
+
if (command === undefined) {
|
|
150
|
+
throw new BadRequestException(SD("error.badRequest"));
|
|
120
151
|
}
|
|
121
|
-
|
|
122
|
-
|
|
123
|
-
|
|
152
|
+
|
|
153
|
+
// 셸을 거치지 않아 파일 경로가 명령으로 해석되지 않도록 합니다.
|
|
154
|
+
execFileSync(command, [request.query.absPath]);
|
|
155
|
+
}),
|
|
156
|
+
);
|
|
124
157
|
|
|
125
158
|
server.get<{
|
|
126
159
|
Querystring: {
|
|
127
160
|
origin: string;
|
|
128
161
|
entityId?: string;
|
|
129
162
|
};
|
|
130
|
-
}>("/api/tools/getSuggestion",
|
|
131
|
-
|
|
132
|
-
|
|
133
|
-
|
|
134
|
-
|
|
135
|
-
|
|
136
|
-
|
|
137
|
-
|
|
138
|
-
|
|
139
|
-
|
|
140
|
-
|
|
141
|
-
|
|
142
|
-
|
|
143
|
-
|
|
144
|
-
|
|
145
|
-
|
|
146
|
-
|
|
147
|
-
|
|
148
|
-
|
|
149
|
-
|
|
150
|
-
|
|
151
|
-
|
|
152
|
-
|
|
153
|
-
|
|
154
|
-
|
|
155
|
-
|
|
156
|
-
|
|
157
|
-
|
|
158
|
-
|
|
159
|
-
|
|
160
|
-
|
|
161
|
-
|
|
162
|
-
|
|
163
|
-
|
|
164
|
-
|
|
165
|
-
|
|
166
|
-
|
|
167
|
-
|
|
168
|
-
|
|
169
|
-
|
|
170
|
-
|
|
171
|
-
|
|
172
|
-
|
|
173
|
-
|
|
174
|
-
|
|
175
|
-
|
|
176
|
-
|
|
177
|
-
|
|
178
|
-
|
|
179
|
-
|
|
180
|
-
|
|
181
|
-
|
|
182
|
-
|
|
183
|
-
|
|
184
|
-
const
|
|
185
|
-
|
|
186
|
-
|
|
187
|
-
|
|
188
|
-
|
|
189
|
-
|
|
190
|
-
|
|
191
|
-
|
|
192
|
-
|
|
193
|
-
entity.props.forEach((prop) => {
|
|
194
|
-
if (glossary.has(prop.name)) {
|
|
195
|
-
return;
|
|
196
|
-
}
|
|
197
|
-
if (prop.desc) {
|
|
198
|
-
glossary.set(prop.name, prop.desc.replace(entity.title ?? "", "{EntityID}"));
|
|
163
|
+
}>("/api/tools/getSuggestion", (request) =>
|
|
164
|
+
forwardAsyncErrors(async () => {
|
|
165
|
+
const { origin, entityId } = request.query;
|
|
166
|
+
|
|
167
|
+
// 치환 용어집
|
|
168
|
+
const glossary = new Map<string, string>([
|
|
169
|
+
["status", "상태"],
|
|
170
|
+
["type", "타입"],
|
|
171
|
+
["image", "이미지"],
|
|
172
|
+
["images", "이미지리스트"],
|
|
173
|
+
["url", "URL"],
|
|
174
|
+
["id", "ID"],
|
|
175
|
+
["name", `{EntityID}명`],
|
|
176
|
+
["title", "{EntityID}명"],
|
|
177
|
+
["parent", "상위{EntityID}"],
|
|
178
|
+
["desc", "설명"],
|
|
179
|
+
["at", "일시"],
|
|
180
|
+
["created", "등록"],
|
|
181
|
+
["updated", "수정"],
|
|
182
|
+
["deleted", "삭제"],
|
|
183
|
+
["by", "유저"],
|
|
184
|
+
["date", "일자"],
|
|
185
|
+
["time", "시간"],
|
|
186
|
+
["ko", "(한글)"],
|
|
187
|
+
["en", "(영문)"],
|
|
188
|
+
["krw", "(원)"],
|
|
189
|
+
["usd", "(USD)"],
|
|
190
|
+
["color", "컬러"],
|
|
191
|
+
["code", "코드"],
|
|
192
|
+
["x", "X좌표"],
|
|
193
|
+
["y", "Y좌표"],
|
|
194
|
+
["current", "현재"],
|
|
195
|
+
["stock", "재고"],
|
|
196
|
+
["total", "총"],
|
|
197
|
+
["admin", "관리자"],
|
|
198
|
+
["group", "그룹"],
|
|
199
|
+
["item", "아이템"],
|
|
200
|
+
["cnt", "수량"],
|
|
201
|
+
["price", "가격"],
|
|
202
|
+
["preset", "프리셋"],
|
|
203
|
+
["acct", "계좌"],
|
|
204
|
+
["tel", "전화번호"],
|
|
205
|
+
["no", "번호"],
|
|
206
|
+
["body", "내용"],
|
|
207
|
+
["content", "내용"],
|
|
208
|
+
["orderno", "정렬순서"],
|
|
209
|
+
["priority", "우선순위"],
|
|
210
|
+
["text", "텍스트"],
|
|
211
|
+
["key", "키"],
|
|
212
|
+
["sum", "합산"],
|
|
213
|
+
["expected", "예상"],
|
|
214
|
+
["actual", "실제"],
|
|
215
|
+
]);
|
|
216
|
+
// 전체 엔티티 순회하며, 엔티티 타이틀과 프롭 설명을 치환 용어집에 추가
|
|
217
|
+
for (const glossaryEntityId of EntityManager.getAllIds()) {
|
|
218
|
+
const glossaryEntity = EntityManager.get(glossaryEntityId);
|
|
219
|
+
if ((glossaryEntity.title ?? "") !== "") {
|
|
220
|
+
glossary.set(inflection.underscore(glossaryEntity.id), glossaryEntity.title);
|
|
221
|
+
glossary.set(
|
|
222
|
+
inflection.underscore(inflection.pluralize(glossaryEntity.id)),
|
|
223
|
+
`${glossaryEntity.title}리스트`,
|
|
224
|
+
);
|
|
199
225
|
}
|
|
200
|
-
});
|
|
201
|
-
}
|
|
202
226
|
|
|
203
|
-
|
|
204
|
-
|
|
205
|
-
|
|
206
|
-
|
|
207
|
-
|
|
208
|
-
|
|
209
|
-
|
|
210
|
-
|
|
211
|
-
|
|
212
|
-
|
|
213
|
-
|
|
214
|
-
];
|
|
215
|
-
});
|
|
216
|
-
|
|
217
|
-
// 조합을 순회하며, 치환 용어집에 있는 단어가 포함된 경우, 치환 용어로 치환
|
|
218
|
-
const REPLACED_PREFIX = "#REPLACED//"; // 치환된 단어를 join 이후에도 식별하기 위해 prefix 추가
|
|
219
|
-
let remainArr: string[] = [...words];
|
|
220
|
-
for (const comb of combinations) {
|
|
221
|
-
const remainStr = remainArr.join("_");
|
|
222
|
-
if (remainStr.includes(comb.w) && glossary.has(comb.w)) {
|
|
223
|
-
remainArr = remainStr
|
|
224
|
-
.replace(comb.w, REPLACED_PREFIX + glossary.get(comb.w))
|
|
225
|
-
.split("_");
|
|
226
|
-
}
|
|
227
|
+
glossaryEntity.props.forEach((prop) => {
|
|
228
|
+
if (glossary.has(prop.name)) {
|
|
229
|
+
return;
|
|
230
|
+
}
|
|
231
|
+
if (prop.desc) {
|
|
232
|
+
glossary.set(
|
|
233
|
+
prop.name,
|
|
234
|
+
prop.desc.replace(glossaryEntity.title ?? "", "{EntityID}"),
|
|
235
|
+
);
|
|
236
|
+
}
|
|
237
|
+
});
|
|
227
238
|
}
|
|
228
239
|
|
|
229
|
-
|
|
230
|
-
|
|
231
|
-
|
|
232
|
-
|
|
233
|
-
|
|
234
|
-
|
|
240
|
+
const suggested = (() => {
|
|
241
|
+
// 단어 분리, 가능한 조합 생성
|
|
242
|
+
const words = origin.split("_");
|
|
243
|
+
const combinations = [...range(words.length, 0, -1)].flatMap((len) => {
|
|
244
|
+
return [
|
|
245
|
+
...range(0, words.length - len + 1, (idx) => {
|
|
246
|
+
return {
|
|
247
|
+
len,
|
|
248
|
+
w: words.slice(idx, idx + len).join("_"),
|
|
249
|
+
};
|
|
250
|
+
}),
|
|
251
|
+
];
|
|
252
|
+
});
|
|
253
|
+
|
|
254
|
+
// 조합을 순회하며, 치환 용어집에 있는 단어가 포함된 경우, 치환 용어로 치환
|
|
255
|
+
const REPLACED_PREFIX = "#REPLACED//"; // 치환된 단어를 join 이후에도 식별하기 위해 prefix 추가
|
|
256
|
+
let remainArr: string[] = [...words];
|
|
257
|
+
for (const comb of combinations) {
|
|
258
|
+
const remainStr = remainArr.join("_");
|
|
259
|
+
if (remainStr.includes(comb.w) && glossary.has(comb.w)) {
|
|
260
|
+
remainArr = remainStr
|
|
261
|
+
.replace(comb.w, REPLACED_PREFIX + glossary.get(comb.w))
|
|
262
|
+
.split("_");
|
|
235
263
|
}
|
|
236
|
-
}
|
|
237
|
-
.join("")
|
|
238
|
-
.replace(/{EntityID}/g, entityId ? EntityManager.get(entityId).title : "");
|
|
239
|
-
})();
|
|
264
|
+
}
|
|
240
265
|
|
|
241
|
-
|
|
242
|
-
|
|
266
|
+
return remainArr
|
|
267
|
+
.map((r) => {
|
|
268
|
+
if (r.startsWith(REPLACED_PREFIX)) {
|
|
269
|
+
return r.replace(REPLACED_PREFIX, "");
|
|
270
|
+
} else {
|
|
271
|
+
return r.toUpperCase();
|
|
272
|
+
}
|
|
273
|
+
})
|
|
274
|
+
.join("")
|
|
275
|
+
.replace(/{EntityID}/g, entityId ? EntityManager.get(entityId).title : "");
|
|
276
|
+
})();
|
|
277
|
+
|
|
278
|
+
return { suggested };
|
|
279
|
+
}),
|
|
280
|
+
);
|
|
243
281
|
|
|
244
282
|
server.get("/api/entity/findMany", async () => {
|
|
245
283
|
const entityIds = EntityManager.getAllIds();
|
|
246
284
|
|
|
247
|
-
function flattenSubsetRows(subsetRows: EntitySubsetRow[]): FlattenSubsetRow[] {
|
|
248
|
-
return subsetRows.flatMap((subsetRow) => {
|
|
249
|
-
const { children, ...sRow } = subsetRow;
|
|
250
|
-
return [sRow, ...flattenSubsetRows(children)];
|
|
251
|
-
});
|
|
252
|
-
}
|
|
253
|
-
|
|
254
285
|
const entities = await Promise.all(
|
|
255
286
|
entityIds.map((entityId) => {
|
|
256
287
|
const entity = EntityManager.get(entityId);
|
|
@@ -292,45 +323,55 @@ export async function sonamuUIApiPlugin(fastify: FastifyInstance) {
|
|
|
292
323
|
filter?: "enums" | "types";
|
|
293
324
|
reload?: "1";
|
|
294
325
|
};
|
|
295
|
-
}>(
|
|
296
|
-
|
|
326
|
+
}>(
|
|
327
|
+
"/api/entity/typeIds",
|
|
328
|
+
(request): Promise<{ typeIds: string[] }> =>
|
|
329
|
+
forwardAsyncErrors(async () => {
|
|
330
|
+
const { filter, reload } = request.query;
|
|
297
331
|
|
|
298
|
-
|
|
299
|
-
|
|
300
|
-
|
|
332
|
+
if (reload === "1") {
|
|
333
|
+
await Sonamu.syncer.autoloadTypes();
|
|
334
|
+
}
|
|
301
335
|
|
|
302
|
-
|
|
303
|
-
|
|
304
|
-
|
|
305
|
-
|
|
306
|
-
|
|
336
|
+
const typeIds = (() => {
|
|
337
|
+
// 프로젝트에서 정의한 타입들
|
|
338
|
+
const projectTypeIds = Object.entries(Sonamu.syncer.types)
|
|
339
|
+
.filter(([_typeId, zodType]) => {
|
|
340
|
+
const { _zod: zodMetadata } = zodType;
|
|
341
|
+
return (
|
|
342
|
+
/* SAFETY: UI 도구의 Zod 입력 스키마가 이 값의 타입을 보장한다. */ (zodMetadata
|
|
343
|
+
.def.type as string) !== "enum"
|
|
344
|
+
);
|
|
345
|
+
})
|
|
346
|
+
.map(([typeId, _zodType]) => typeId);
|
|
307
347
|
|
|
308
|
-
|
|
309
|
-
|
|
348
|
+
// 내장 타입들 (sonamu 코어에서 제공)
|
|
349
|
+
const builtInTypeIds = [...BUILT_IN_TYPE_IDS];
|
|
310
350
|
|
|
311
|
-
|
|
312
|
-
|
|
351
|
+
// 모든 타입 병합
|
|
352
|
+
const allTypeIds = [...builtInTypeIds, ...projectTypeIds];
|
|
313
353
|
|
|
314
|
-
|
|
315
|
-
|
|
316
|
-
|
|
354
|
+
if (filter === "types") {
|
|
355
|
+
return allTypeIds;
|
|
356
|
+
}
|
|
317
357
|
|
|
318
|
-
|
|
319
|
-
|
|
320
|
-
|
|
321
|
-
|
|
358
|
+
const enumIds = EntityManager.getAllIds().flatMap((entityId) => {
|
|
359
|
+
const entity = EntityManager.get(entityId);
|
|
360
|
+
return Object.keys(entity.enumLabels);
|
|
361
|
+
});
|
|
322
362
|
|
|
323
|
-
|
|
324
|
-
|
|
325
|
-
|
|
326
|
-
|
|
327
|
-
|
|
328
|
-
|
|
363
|
+
if (filter === "enums") {
|
|
364
|
+
return enumIds;
|
|
365
|
+
} else {
|
|
366
|
+
return [...allTypeIds, ...enumIds];
|
|
367
|
+
}
|
|
368
|
+
})();
|
|
329
369
|
|
|
330
|
-
|
|
331
|
-
|
|
332
|
-
|
|
333
|
-
|
|
370
|
+
return {
|
|
371
|
+
typeIds,
|
|
372
|
+
};
|
|
373
|
+
}),
|
|
374
|
+
);
|
|
334
375
|
|
|
335
376
|
server.post<{
|
|
336
377
|
Body: {
|
|
@@ -341,25 +382,29 @@ export async function sonamuUIApiPlugin(fastify: FastifyInstance) {
|
|
|
341
382
|
parentId?: string;
|
|
342
383
|
};
|
|
343
384
|
};
|
|
344
|
-
}>("/api/entity/create",
|
|
345
|
-
|
|
346
|
-
|
|
347
|
-
|
|
385
|
+
}>("/api/entity/create", (request) =>
|
|
386
|
+
forwardAsyncErrors(async () => {
|
|
387
|
+
return await waitForHMRCompleted(async () => {
|
|
388
|
+
const { form } = request.body;
|
|
389
|
+
await Sonamu.syncer.createEntity({ ...form, entityId: form.id });
|
|
348
390
|
|
|
349
|
-
|
|
350
|
-
|
|
351
|
-
|
|
391
|
+
return 1;
|
|
392
|
+
});
|
|
393
|
+
}),
|
|
394
|
+
);
|
|
352
395
|
|
|
353
396
|
server.post<{
|
|
354
397
|
Body: {
|
|
355
398
|
entityId: string;
|
|
356
399
|
};
|
|
357
|
-
}>("/api/entity/del",
|
|
358
|
-
|
|
359
|
-
|
|
360
|
-
|
|
361
|
-
|
|
362
|
-
|
|
400
|
+
}>("/api/entity/del", (request) =>
|
|
401
|
+
forwardAsyncErrors(async () => {
|
|
402
|
+
return await waitForHMRCompleted(async () => {
|
|
403
|
+
const { entityId } = request.body;
|
|
404
|
+
return await Sonamu.syncer.delEntity(entityId);
|
|
405
|
+
});
|
|
406
|
+
}),
|
|
407
|
+
);
|
|
363
408
|
|
|
364
409
|
server.post<{
|
|
365
410
|
Body: {
|
|
@@ -370,18 +415,20 @@ export async function sonamuUIApiPlugin(fastify: FastifyInstance) {
|
|
|
370
415
|
parentId?: string;
|
|
371
416
|
};
|
|
372
417
|
};
|
|
373
|
-
}>("/api/entity/modifyEntityBase",
|
|
374
|
-
|
|
375
|
-
|
|
376
|
-
|
|
377
|
-
|
|
378
|
-
|
|
379
|
-
|
|
380
|
-
|
|
418
|
+
}>("/api/entity/modifyEntityBase", (request) =>
|
|
419
|
+
forwardAsyncErrors(async () => {
|
|
420
|
+
return await waitForHMRCompleted(async () => {
|
|
421
|
+
const { entityId, newValues } = request.body;
|
|
422
|
+
const entity = EntityManager.get(entityId);
|
|
423
|
+
entity.title = newValues.title;
|
|
424
|
+
entity.table = newValues.table;
|
|
425
|
+
entity.parentId = newValues.parentId;
|
|
426
|
+
await entity.save();
|
|
381
427
|
|
|
382
|
-
|
|
383
|
-
|
|
384
|
-
|
|
428
|
+
return 1;
|
|
429
|
+
});
|
|
430
|
+
}),
|
|
431
|
+
);
|
|
385
432
|
|
|
386
433
|
server.post<{
|
|
387
434
|
Body: {
|
|
@@ -390,40 +437,44 @@ export async function sonamuUIApiPlugin(fastify: FastifyInstance) {
|
|
|
390
437
|
fields: string[];
|
|
391
438
|
fieldsInternal?: string[];
|
|
392
439
|
};
|
|
393
|
-
}>("/api/entity/modifySubset",
|
|
394
|
-
|
|
395
|
-
|
|
396
|
-
|
|
397
|
-
|
|
398
|
-
|
|
399
|
-
if (fieldsInternal
|
|
400
|
-
|
|
401
|
-
|
|
402
|
-
|
|
440
|
+
}>("/api/entity/modifySubset", (request) =>
|
|
441
|
+
forwardAsyncErrors(async () => {
|
|
442
|
+
return await waitForHMRCompleted(async () => {
|
|
443
|
+
const { entityId, subsetKey, fields, fieldsInternal } = request.body;
|
|
444
|
+
const entity = EntityManager.get(entityId);
|
|
445
|
+
entity.subsets[subsetKey] = fields;
|
|
446
|
+
if (fieldsInternal !== undefined) {
|
|
447
|
+
if (fieldsInternal.length > 0) {
|
|
448
|
+
entity.subsetsInternal[subsetKey] = fieldsInternal;
|
|
449
|
+
} else {
|
|
450
|
+
delete entity.subsetsInternal[subsetKey];
|
|
451
|
+
}
|
|
403
452
|
}
|
|
404
|
-
|
|
405
|
-
await entity.save();
|
|
453
|
+
await entity.save();
|
|
406
454
|
|
|
407
|
-
|
|
408
|
-
|
|
409
|
-
|
|
455
|
+
return { updated: fields, updatedInternal: fieldsInternal };
|
|
456
|
+
});
|
|
457
|
+
}),
|
|
458
|
+
);
|
|
410
459
|
|
|
411
460
|
server.post<{
|
|
412
461
|
Body: {
|
|
413
462
|
entityId: string;
|
|
414
463
|
subsetKey: string;
|
|
415
464
|
};
|
|
416
|
-
}>("/api/entity/delSubset",
|
|
417
|
-
|
|
418
|
-
|
|
419
|
-
|
|
420
|
-
|
|
421
|
-
|
|
422
|
-
|
|
465
|
+
}>("/api/entity/delSubset", (request) =>
|
|
466
|
+
forwardAsyncErrors(async () => {
|
|
467
|
+
return await waitForHMRCompleted(async () => {
|
|
468
|
+
const { entityId, subsetKey } = request.body;
|
|
469
|
+
const entity = EntityManager.get(entityId);
|
|
470
|
+
delete entity.subsets[subsetKey];
|
|
471
|
+
delete entity.subsetsInternal[subsetKey];
|
|
472
|
+
await entity.save();
|
|
423
473
|
|
|
424
|
-
|
|
425
|
-
|
|
426
|
-
|
|
474
|
+
return 1;
|
|
475
|
+
});
|
|
476
|
+
}),
|
|
477
|
+
);
|
|
427
478
|
|
|
428
479
|
server.post<{
|
|
429
480
|
Body: {
|
|
@@ -431,14 +482,16 @@ export async function sonamuUIApiPlugin(fastify: FastifyInstance) {
|
|
|
431
482
|
newProp: EntityProp;
|
|
432
483
|
at?: number;
|
|
433
484
|
};
|
|
434
|
-
}>("/api/entity/createProp",
|
|
435
|
-
|
|
436
|
-
|
|
437
|
-
|
|
438
|
-
|
|
439
|
-
|
|
440
|
-
|
|
441
|
-
|
|
485
|
+
}>("/api/entity/createProp", (request) =>
|
|
486
|
+
forwardAsyncErrors(async () => {
|
|
487
|
+
return await waitForHMRCompleted(async () => {
|
|
488
|
+
const { entityId, at, newProp } = request.body;
|
|
489
|
+
const entity = EntityManager.get(entityId);
|
|
490
|
+
await entity.createProp(newProp, at);
|
|
491
|
+
return true;
|
|
492
|
+
});
|
|
493
|
+
}),
|
|
494
|
+
);
|
|
442
495
|
|
|
443
496
|
server.post<{
|
|
444
497
|
Body: {
|
|
@@ -446,31 +499,35 @@ export async function sonamuUIApiPlugin(fastify: FastifyInstance) {
|
|
|
446
499
|
newProp: EntityProp;
|
|
447
500
|
at: number;
|
|
448
501
|
};
|
|
449
|
-
}>("/api/entity/modifyProp",
|
|
450
|
-
|
|
451
|
-
|
|
502
|
+
}>("/api/entity/modifyProp", (request) =>
|
|
503
|
+
forwardAsyncErrors(async () => {
|
|
504
|
+
return await waitForHMRCompleted(async () => {
|
|
505
|
+
const { entityId, at, newProp } = request.body;
|
|
452
506
|
|
|
453
|
-
|
|
454
|
-
|
|
507
|
+
const entity = EntityManager.get(entityId);
|
|
508
|
+
entity.modifyProp(newProp, at);
|
|
455
509
|
|
|
456
|
-
|
|
457
|
-
|
|
458
|
-
|
|
510
|
+
return true;
|
|
511
|
+
});
|
|
512
|
+
}),
|
|
513
|
+
);
|
|
459
514
|
|
|
460
515
|
server.post<{
|
|
461
516
|
Body: {
|
|
462
517
|
entityId: string;
|
|
463
518
|
at: number;
|
|
464
519
|
};
|
|
465
|
-
}>("/api/entity/delProp",
|
|
466
|
-
|
|
467
|
-
|
|
520
|
+
}>("/api/entity/delProp", (request) =>
|
|
521
|
+
forwardAsyncErrors(async () => {
|
|
522
|
+
return await waitForHMRCompleted(async () => {
|
|
523
|
+
const { entityId, at } = request.body;
|
|
468
524
|
|
|
469
|
-
|
|
470
|
-
|
|
471
|
-
|
|
472
|
-
|
|
473
|
-
|
|
525
|
+
const entity = EntityManager.get(entityId);
|
|
526
|
+
entity.delProp(at);
|
|
527
|
+
return true;
|
|
528
|
+
});
|
|
529
|
+
}),
|
|
530
|
+
);
|
|
474
531
|
|
|
475
532
|
server.post<{
|
|
476
533
|
Body: {
|
|
@@ -478,76 +535,84 @@ export async function sonamuUIApiPlugin(fastify: FastifyInstance) {
|
|
|
478
535
|
at: number;
|
|
479
536
|
to: number;
|
|
480
537
|
};
|
|
481
|
-
}>("/api/entity/moveProp",
|
|
482
|
-
|
|
483
|
-
|
|
538
|
+
}>("/api/entity/moveProp", (request) =>
|
|
539
|
+
forwardAsyncErrors(async () => {
|
|
540
|
+
return await waitForHMRCompleted(async () => {
|
|
541
|
+
const { entityId, at, to } = request.body;
|
|
484
542
|
|
|
485
|
-
|
|
486
|
-
|
|
543
|
+
const entity = EntityManager.get(entityId);
|
|
544
|
+
entity.moveProp(at, to);
|
|
487
545
|
|
|
488
|
-
|
|
489
|
-
|
|
490
|
-
|
|
546
|
+
return true;
|
|
547
|
+
});
|
|
548
|
+
}),
|
|
549
|
+
);
|
|
491
550
|
|
|
492
551
|
server.post<{
|
|
493
552
|
Body: {
|
|
494
553
|
entityId: string;
|
|
495
554
|
indexes: EntityIndex[];
|
|
496
555
|
};
|
|
497
|
-
}>("/api/entity/modifyIndexes",
|
|
498
|
-
|
|
499
|
-
|
|
500
|
-
|
|
501
|
-
|
|
502
|
-
|
|
556
|
+
}>("/api/entity/modifyIndexes", (request) =>
|
|
557
|
+
forwardAsyncErrors(async () => {
|
|
558
|
+
return await waitForHMRCompleted(async () => {
|
|
559
|
+
const { entityId, indexes } = request.body;
|
|
560
|
+
const entity = EntityManager.get(entityId);
|
|
561
|
+
entity.indexes = indexes;
|
|
562
|
+
await entity.save();
|
|
503
563
|
|
|
504
|
-
|
|
505
|
-
|
|
506
|
-
|
|
564
|
+
return { updated: indexes };
|
|
565
|
+
});
|
|
566
|
+
}),
|
|
567
|
+
);
|
|
507
568
|
|
|
508
569
|
server.post<{
|
|
509
570
|
Body: {
|
|
510
571
|
entityId: string;
|
|
511
572
|
enumLabels: Entity["enumLabels"];
|
|
512
573
|
};
|
|
513
|
-
}>("/api/entity/modifyEnumLabels",
|
|
514
|
-
|
|
515
|
-
|
|
516
|
-
|
|
517
|
-
|
|
518
|
-
|
|
574
|
+
}>("/api/entity/modifyEnumLabels", (request) =>
|
|
575
|
+
forwardAsyncErrors(async () => {
|
|
576
|
+
return await waitForHMRCompleted(async () => {
|
|
577
|
+
const { entityId, enumLabels } = request.body;
|
|
578
|
+
const entity = EntityManager.get(entityId);
|
|
579
|
+
entity.enumLabels = enumLabels;
|
|
580
|
+
await entity.save();
|
|
519
581
|
|
|
520
|
-
|
|
521
|
-
|
|
522
|
-
|
|
582
|
+
return { updated: enumLabels };
|
|
583
|
+
});
|
|
584
|
+
}),
|
|
585
|
+
);
|
|
523
586
|
|
|
524
587
|
server.post<{
|
|
525
588
|
Body: {
|
|
526
589
|
entityId: string;
|
|
527
590
|
newEnumId: string;
|
|
528
591
|
};
|
|
529
|
-
}>("/api/entity/createEnumId",
|
|
530
|
-
|
|
531
|
-
|
|
532
|
-
|
|
592
|
+
}>("/api/entity/createEnumId", (request) =>
|
|
593
|
+
forwardAsyncErrors(async () => {
|
|
594
|
+
return await waitForHMRCompleted(async () => {
|
|
595
|
+
const { entityId, newEnumId } = request.body;
|
|
596
|
+
const entity = EntityManager.get(entityId);
|
|
533
597
|
|
|
534
|
-
|
|
535
|
-
|
|
536
|
-
|
|
598
|
+
if (entity.enumLabels[newEnumId]) {
|
|
599
|
+
throw new Error(`이미 존재하는 enumId입니다: ${newEnumId}`);
|
|
600
|
+
}
|
|
537
601
|
|
|
538
|
-
|
|
539
|
-
|
|
540
|
-
|
|
541
|
-
|
|
542
|
-
|
|
543
|
-
|
|
544
|
-
|
|
545
|
-
|
|
546
|
-
|
|
602
|
+
entity.enumLabels[newEnumId] = newEnumId.endsWith("Status")
|
|
603
|
+
? {
|
|
604
|
+
active: "노출",
|
|
605
|
+
hidden: "숨김",
|
|
606
|
+
}
|
|
607
|
+
: {
|
|
608
|
+
"": "",
|
|
609
|
+
};
|
|
610
|
+
await entity.save();
|
|
547
611
|
|
|
548
|
-
|
|
549
|
-
|
|
550
|
-
|
|
612
|
+
return 1;
|
|
613
|
+
});
|
|
614
|
+
}),
|
|
615
|
+
);
|
|
551
616
|
|
|
552
617
|
server.post<{
|
|
553
618
|
Body: {
|
|
@@ -557,58 +622,62 @@ export async function sonamuUIApiPlugin(fastify: FastifyInstance) {
|
|
|
557
622
|
after: string;
|
|
558
623
|
};
|
|
559
624
|
};
|
|
560
|
-
}>("/api/entity/modifyEnumId",
|
|
561
|
-
|
|
562
|
-
|
|
563
|
-
|
|
564
|
-
|
|
565
|
-
const
|
|
566
|
-
|
|
567
|
-
|
|
568
|
-
|
|
569
|
-
|
|
570
|
-
|
|
625
|
+
}>("/api/entity/modifyEnumId", (request) =>
|
|
626
|
+
forwardAsyncErrors(async () => {
|
|
627
|
+
return await waitForHMRCompleted(async () => {
|
|
628
|
+
const { entityId, enumId } = request.body;
|
|
629
|
+
const entityIds = EntityManager.getAllIds();
|
|
630
|
+
const isExists = entityIds.some((candidateEntityId) => {
|
|
631
|
+
const candidateEntity = EntityManager.get(candidateEntityId);
|
|
632
|
+
return Object.keys(candidateEntity.enumLabels).includes(enumId.after);
|
|
633
|
+
});
|
|
634
|
+
if (isExists) {
|
|
635
|
+
throw new Error(`이미 존재하는 EnumId입니다: ${enumId.after}`);
|
|
636
|
+
}
|
|
571
637
|
|
|
572
|
-
|
|
573
|
-
|
|
574
|
-
|
|
638
|
+
const entity = EntityManager.get(entityId);
|
|
639
|
+
entity.enumLabels[enumId.after] = entity.enumLabels[enumId.before];
|
|
640
|
+
delete entity.enumLabels[enumId.before];
|
|
575
641
|
|
|
576
|
-
|
|
642
|
+
await entity.save();
|
|
577
643
|
|
|
578
|
-
|
|
579
|
-
|
|
580
|
-
|
|
581
|
-
|
|
582
|
-
|
|
644
|
+
for (const relatedEntityId of entityIds) {
|
|
645
|
+
const relatedEntity = EntityManager.get(relatedEntityId);
|
|
646
|
+
for (const prop of relatedEntity.props) {
|
|
647
|
+
if (prop.type === "enum" && prop.id === enumId.before) {
|
|
648
|
+
prop.id = enumId.after;
|
|
649
|
+
}
|
|
583
650
|
}
|
|
651
|
+
await relatedEntity.save();
|
|
584
652
|
}
|
|
585
|
-
|
|
586
|
-
|
|
587
|
-
|
|
588
|
-
});
|
|
653
|
+
});
|
|
654
|
+
}),
|
|
655
|
+
);
|
|
589
656
|
|
|
590
657
|
server.post<{
|
|
591
658
|
Body: {
|
|
592
659
|
entityId: string;
|
|
593
660
|
enumId: string;
|
|
594
661
|
};
|
|
595
|
-
}>("/api/entity/deleteEnumId",
|
|
596
|
-
|
|
597
|
-
|
|
598
|
-
|
|
599
|
-
|
|
600
|
-
|
|
601
|
-
|
|
602
|
-
|
|
603
|
-
|
|
604
|
-
|
|
605
|
-
|
|
662
|
+
}>("/api/entity/deleteEnumId", (request) =>
|
|
663
|
+
forwardAsyncErrors(async () => {
|
|
664
|
+
return await waitForHMRCompleted(async () => {
|
|
665
|
+
const { entityId, enumId } = request.body;
|
|
666
|
+
|
|
667
|
+
const entityIds = EntityManager.getAllIds();
|
|
668
|
+
const isReferenced = entityIds
|
|
669
|
+
.flatMap((referencingEntityId) => EntityManager.get(referencingEntityId).props)
|
|
670
|
+
.some((prop) => prop.type === "enum" && prop.id === enumId);
|
|
671
|
+
if (isReferenced) {
|
|
672
|
+
throw new Error(`${enumId}를 참조하는 프로퍼티가 존재합니다.`);
|
|
673
|
+
}
|
|
606
674
|
|
|
607
|
-
|
|
608
|
-
|
|
609
|
-
|
|
610
|
-
|
|
611
|
-
|
|
675
|
+
const entity = EntityManager.get(entityId);
|
|
676
|
+
delete entity.enumLabels[enumId];
|
|
677
|
+
await entity.save();
|
|
678
|
+
});
|
|
679
|
+
}),
|
|
680
|
+
);
|
|
612
681
|
|
|
613
682
|
server.post<{
|
|
614
683
|
Body: {
|
|
@@ -619,28 +688,32 @@ export async function sonamuUIApiPlugin(fastify: FastifyInstance) {
|
|
|
619
688
|
subsetKey?: string;
|
|
620
689
|
cone: Cone;
|
|
621
690
|
};
|
|
622
|
-
}>("/api/entity/updateCone",
|
|
623
|
-
|
|
624
|
-
|
|
625
|
-
|
|
691
|
+
}>("/api/entity/updateCone", (request) =>
|
|
692
|
+
forwardAsyncErrors(async () => {
|
|
693
|
+
return await waitForHMRCompleted(async () => {
|
|
694
|
+
const { entityId, target, propName, enumId, subsetKey, cone } = request.body;
|
|
695
|
+
const entity = EntityManager.get(entityId);
|
|
626
696
|
|
|
627
|
-
|
|
628
|
-
|
|
629
|
-
|
|
630
|
-
|
|
631
|
-
|
|
632
|
-
|
|
697
|
+
if (target === "entity") {
|
|
698
|
+
entity.cone = cone;
|
|
699
|
+
} else if (target === "prop" && propName) {
|
|
700
|
+
const prop = entity.props.find((p) => p.name === propName);
|
|
701
|
+
if (prop) {
|
|
702
|
+
/* SAFETY: UI 도구의 Zod 입력 스키마가 이 값의 타입을 보장한다. */ (
|
|
703
|
+
prop as { cone?: Cone }
|
|
704
|
+
).cone = cone;
|
|
705
|
+
}
|
|
706
|
+
} else if (target === "enum" && enumId) {
|
|
707
|
+
entity.enumCones[enumId] = cone;
|
|
708
|
+
} else if (target === "subset" && subsetKey) {
|
|
709
|
+
entity.subsetCones[subsetKey] = cone;
|
|
633
710
|
}
|
|
634
|
-
} else if (target === "enum" && enumId) {
|
|
635
|
-
entity.enumCones[enumId] = cone;
|
|
636
|
-
} else if (target === "subset" && subsetKey) {
|
|
637
|
-
entity.subsetCones[subsetKey] = cone;
|
|
638
|
-
}
|
|
639
711
|
|
|
640
|
-
|
|
641
|
-
|
|
642
|
-
|
|
643
|
-
|
|
712
|
+
await entity.save();
|
|
713
|
+
return true;
|
|
714
|
+
});
|
|
715
|
+
}),
|
|
716
|
+
);
|
|
644
717
|
|
|
645
718
|
server.post<{
|
|
646
719
|
Body: {
|
|
@@ -658,6 +731,7 @@ export async function sonamuUIApiPlugin(fastify: FastifyInstance) {
|
|
|
658
731
|
const entity = EntityManager.get(entityId);
|
|
659
732
|
|
|
660
733
|
// locale 기본값: Sonamu.config.i18n.defaultLocale 사용
|
|
734
|
+
// SAFETY: i18n 구성 스키마가 지원 locale을 ko/en/ja로 제한한다.
|
|
661
735
|
const effectiveLocale =
|
|
662
736
|
locale ?? (Sonamu.config.i18n.defaultLocale as "ko" | "en" | "ja");
|
|
663
737
|
|
|
@@ -713,221 +787,55 @@ export async function sonamuUIApiPlugin(fastify: FastifyInstance) {
|
|
|
713
787
|
Querystring: {
|
|
714
788
|
entityId: string;
|
|
715
789
|
};
|
|
716
|
-
}>("/api/entity/getTableColumns",
|
|
717
|
-
|
|
718
|
-
|
|
719
|
-
|
|
720
|
-
|
|
721
|
-
|
|
722
|
-
|
|
723
|
-
server.get("/api/migrations/status", async () => {
|
|
724
|
-
const status = await migrator.getStatus();
|
|
725
|
-
|
|
726
|
-
return { status };
|
|
727
|
-
});
|
|
728
|
-
|
|
729
|
-
server.post<{
|
|
730
|
-
Body: {
|
|
731
|
-
action: "apply" | "rollback" | "shadow";
|
|
732
|
-
targets: (keyof SonamuDBConfig)[];
|
|
733
|
-
force?: boolean;
|
|
734
|
-
forceReason?: string;
|
|
735
|
-
requestor?: string;
|
|
736
|
-
};
|
|
737
|
-
}>(
|
|
738
|
-
"/api/migrations/runAction",
|
|
739
|
-
async (request): Promise<MigrationResult | SlackConfirmPendingResult> => {
|
|
740
|
-
const { action, targets, force, forceReason, requestor } = request.body;
|
|
741
|
-
|
|
742
|
-
if (action === "shadow") {
|
|
743
|
-
return migrator.runShadowTest();
|
|
744
|
-
}
|
|
745
|
-
|
|
746
|
-
// Slack 승인 체크 (apply 시에만)
|
|
747
|
-
if (action === "apply") {
|
|
748
|
-
const slackConfirm = new SlackConfirm();
|
|
749
|
-
const requiresApproval = targets.some((t) => slackConfirm.isTargetRequiresApproval(t));
|
|
750
|
-
|
|
751
|
-
// 로컬 DB인 경우 승인 스킵
|
|
752
|
-
const localHosts = ["localhost", "127.0.0.1", "0.0.0.0", "::1"];
|
|
753
|
-
const isLocalTarget = targets.every((target) => {
|
|
754
|
-
const targetConfig = Sonamu.dbConfig[target];
|
|
755
|
-
const host = (targetConfig?.connection as { host?: string })?.host ?? "localhost";
|
|
756
|
-
return localHosts.includes(host.toLowerCase());
|
|
757
|
-
});
|
|
758
|
-
|
|
759
|
-
if (requiresApproval && slackConfirm.isConfigured() && !isLocalTarget) {
|
|
760
|
-
const { conns } = await migrator.getStatus();
|
|
761
|
-
|
|
762
|
-
// 모든 타겟 DB에서 pending인 마이그레이션의 합집합을 구합니다.
|
|
763
|
-
const pendingMigrations = [
|
|
764
|
-
...new Set(
|
|
765
|
-
conns
|
|
766
|
-
.filter((conn) => targets.includes(conn.connKey))
|
|
767
|
-
.flatMap((conn) => conn.pending),
|
|
768
|
-
),
|
|
769
|
-
];
|
|
770
|
-
|
|
771
|
-
if (pendingMigrations.length > 0) {
|
|
772
|
-
// 기존 승인 요청 확인
|
|
773
|
-
const existing = await slackConfirm.getExistingRequest(pendingMigrations);
|
|
774
|
-
|
|
775
|
-
if (existing) {
|
|
776
|
-
// 기존 요청이 있으면 승인 상태 확인
|
|
777
|
-
const { approved, rejected } = await slackConfirm.checkApproval(
|
|
778
|
-
existing.channel,
|
|
779
|
-
existing.ts,
|
|
780
|
-
);
|
|
781
|
-
|
|
782
|
-
if (approved) {
|
|
783
|
-
// 승인됨 → 실행
|
|
784
|
-
const result = await migrator.runAction(action, targets);
|
|
785
|
-
if (result.length > 0) {
|
|
786
|
-
await slackConfirm.logExecution(
|
|
787
|
-
existing.channel,
|
|
788
|
-
existing.ts,
|
|
789
|
-
result,
|
|
790
|
-
requestor,
|
|
791
|
-
);
|
|
792
|
-
}
|
|
793
|
-
return result;
|
|
794
|
-
} else if (rejected) {
|
|
795
|
-
throw new BadRequestException(SD("sonamu.error.migrationRejected"));
|
|
796
|
-
} else if (force) {
|
|
797
|
-
// Force 진행
|
|
798
|
-
await slackConfirm.forceApproval(
|
|
799
|
-
existing.channel,
|
|
800
|
-
existing.ts,
|
|
801
|
-
forceReason ?? "사유 없음",
|
|
802
|
-
requestor,
|
|
803
|
-
);
|
|
804
|
-
const result = await migrator.runAction(action, targets);
|
|
805
|
-
if (result.length > 0) {
|
|
806
|
-
await slackConfirm.logExecution(
|
|
807
|
-
existing.channel,
|
|
808
|
-
existing.ts,
|
|
809
|
-
result,
|
|
810
|
-
requestor,
|
|
811
|
-
);
|
|
812
|
-
}
|
|
813
|
-
return result;
|
|
814
|
-
} else {
|
|
815
|
-
// 대기중
|
|
816
|
-
return {
|
|
817
|
-
type: "pending",
|
|
818
|
-
channel: existing.channel,
|
|
819
|
-
ts: existing.ts,
|
|
820
|
-
};
|
|
821
|
-
}
|
|
822
|
-
} else {
|
|
823
|
-
// 새 승인 요청 발송
|
|
824
|
-
const { channel, ts } = await slackConfirm.postApprovalRequest(
|
|
825
|
-
pendingMigrations,
|
|
826
|
-
targets,
|
|
827
|
-
requestor,
|
|
828
|
-
);
|
|
829
|
-
await slackConfirm.saveRequest(pendingMigrations, channel, ts);
|
|
830
|
-
|
|
831
|
-
return {
|
|
832
|
-
type: "pending",
|
|
833
|
-
channel,
|
|
834
|
-
ts,
|
|
835
|
-
};
|
|
836
|
-
}
|
|
837
|
-
}
|
|
838
|
-
}
|
|
839
|
-
}
|
|
840
|
-
|
|
841
|
-
return migrator.runAction(action, targets);
|
|
842
|
-
},
|
|
790
|
+
}>("/api/entity/getTableColumns", (request) =>
|
|
791
|
+
forwardAsyncErrors(async () => {
|
|
792
|
+
const { entityId } = request.query;
|
|
793
|
+
const entity = EntityManager.get(entityId);
|
|
794
|
+
const columns = entity.getTableColumns();
|
|
795
|
+
return { columns };
|
|
796
|
+
}),
|
|
843
797
|
);
|
|
844
798
|
|
|
845
|
-
server.post<{
|
|
846
|
-
Body: {
|
|
847
|
-
channel: string;
|
|
848
|
-
ts: string;
|
|
849
|
-
};
|
|
850
|
-
}>("/api/migrations/checkApproval", async (request) => {
|
|
851
|
-
const { channel, ts } = request.body;
|
|
852
|
-
const slackConfirm = new SlackConfirm();
|
|
853
|
-
|
|
854
|
-
if (!slackConfirm.isConfigured()) {
|
|
855
|
-
return { approved: true, rejected: false };
|
|
856
|
-
}
|
|
857
|
-
|
|
858
|
-
return slackConfirm.checkApproval(channel, ts);
|
|
859
|
-
});
|
|
860
|
-
|
|
861
|
-
server.post<{
|
|
862
|
-
Body: {
|
|
863
|
-
channel: string;
|
|
864
|
-
ts: string;
|
|
865
|
-
reason: string;
|
|
866
|
-
requestor?: string;
|
|
867
|
-
};
|
|
868
|
-
}>("/api/migrations/forceApproval", async (request) => {
|
|
869
|
-
const { channel, ts, reason, requestor } = request.body;
|
|
870
|
-
const slackConfirm = new SlackConfirm();
|
|
871
|
-
|
|
872
|
-
if (!slackConfirm.isConfigured()) {
|
|
873
|
-
throw new BadRequestException(SD("sonamu.error.slackConfirmNotConfigured"));
|
|
874
|
-
}
|
|
875
|
-
|
|
876
|
-
await slackConfirm.forceApproval(channel, ts, reason, requestor);
|
|
877
|
-
return { success: true };
|
|
878
|
-
});
|
|
879
|
-
|
|
880
|
-
server.post<{
|
|
881
|
-
Body: {
|
|
882
|
-
codeNames: string[];
|
|
883
|
-
};
|
|
884
|
-
}>("/api/migrations/delCodes", async (request) => {
|
|
885
|
-
const { codeNames } = request.body;
|
|
886
|
-
return await migrator.delCodes(codeNames);
|
|
887
|
-
});
|
|
888
|
-
|
|
889
|
-
server.post("/api/migrations/generatePreparedCodes", async (_requestt) => {
|
|
890
|
-
return await migrator.generatePreparedCodes();
|
|
891
|
-
});
|
|
892
|
-
|
|
893
799
|
server.post<{
|
|
894
800
|
Body: {
|
|
895
801
|
entityIds: string[];
|
|
896
802
|
templateKeys: string[];
|
|
897
803
|
};
|
|
898
|
-
}>("/api/scaffolding/getStatus",
|
|
899
|
-
|
|
900
|
-
|
|
901
|
-
|
|
902
|
-
|
|
903
|
-
|
|
904
|
-
|
|
804
|
+
}>("/api/scaffolding/getStatus", (request) =>
|
|
805
|
+
forwardAsyncErrors(async () => {
|
|
806
|
+
const { entityIds, templateKeys: _templateKeys } = request.body;
|
|
807
|
+
if ((entityIds ?? []).length === 0) {
|
|
808
|
+
throw new BadRequestException(SD("sonamu.error.entityIdsRequired"));
|
|
809
|
+
} else if ((_templateKeys ?? []).length === 0) {
|
|
810
|
+
throw new BadRequestException(SD("sonamu.error.templateKeysRequired"));
|
|
811
|
+
}
|
|
905
812
|
|
|
906
|
-
|
|
907
|
-
|
|
908
|
-
|
|
813
|
+
// sorting
|
|
814
|
+
entityIds.sort((a, b) => (a < b ? -1 : a > b ? 1 : 0));
|
|
815
|
+
const templateKeys = TemplateKey.options.filter((tk) => _templateKeys.includes(tk));
|
|
909
816
|
|
|
910
|
-
|
|
911
|
-
|
|
912
|
-
|
|
817
|
+
const combinations = entityIds.flatMap((entityId) => {
|
|
818
|
+
return templateKeys.map((templateKey) => [entityId, templateKey]);
|
|
819
|
+
});
|
|
913
820
|
|
|
914
|
-
|
|
915
|
-
|
|
916
|
-
|
|
917
|
-
|
|
918
|
-
|
|
919
|
-
|
|
920
|
-
|
|
921
|
-
|
|
922
|
-
|
|
923
|
-
|
|
924
|
-
|
|
925
|
-
|
|
926
|
-
|
|
927
|
-
|
|
928
|
-
|
|
929
|
-
|
|
930
|
-
|
|
821
|
+
const statuses = await Promise.all(
|
|
822
|
+
combinations.map(async ([entityId, templateKey]) => {
|
|
823
|
+
const { subPath, fullPath, isExists } = await Sonamu.syncer.checkExistsGenCode(
|
|
824
|
+
entityId,
|
|
825
|
+
/* SAFETY: UI 도구의 Zod 입력 스키마가 이 값의 타입을 보장한다. */ templateKey as TemplateKey,
|
|
826
|
+
);
|
|
827
|
+
return {
|
|
828
|
+
entityId,
|
|
829
|
+
templateKey,
|
|
830
|
+
subPath,
|
|
831
|
+
fullPath,
|
|
832
|
+
isExists,
|
|
833
|
+
};
|
|
834
|
+
}),
|
|
835
|
+
);
|
|
836
|
+
return { statuses };
|
|
837
|
+
}),
|
|
838
|
+
);
|
|
931
839
|
|
|
932
840
|
server.post<{
|
|
933
841
|
Body: {
|
|
@@ -938,54 +846,53 @@ export async function sonamuUIApiPlugin(fastify: FastifyInstance) {
|
|
|
938
846
|
overwrite?: boolean;
|
|
939
847
|
}[];
|
|
940
848
|
};
|
|
941
|
-
}>("/api/scaffolding/generate",
|
|
942
|
-
|
|
943
|
-
|
|
944
|
-
|
|
945
|
-
|
|
946
|
-
|
|
947
|
-
// 1. 모든 템플릿에서 필요한 dict 키를 수집
|
|
948
|
-
const keys = options.flatMap(({ templateKey }) => {
|
|
949
|
-
const template = TemplateManager.get(templateKey);
|
|
950
|
-
return template.getRequiredDictKeys() ?? [];
|
|
951
|
-
});
|
|
849
|
+
}>("/api/scaffolding/generate", (request) =>
|
|
850
|
+
forwardAsyncErrors(async () => {
|
|
851
|
+
const { options } = request.body;
|
|
852
|
+
if (options.length === 0) {
|
|
853
|
+
throw new BadRequestException(SD("sonamu.error.optionsRequired"));
|
|
854
|
+
}
|
|
952
855
|
|
|
953
|
-
|
|
954
|
-
|
|
856
|
+
// 1. 모든 템플릿에서 필요한 dict 키를 수집
|
|
857
|
+
const keys = options.flatMap(({ templateKey }) => {
|
|
858
|
+
const template = TemplateManager.get(templateKey);
|
|
859
|
+
return template.getRequiredDictKeys() ?? [];
|
|
860
|
+
});
|
|
955
861
|
|
|
956
|
-
|
|
957
|
-
|
|
958
|
-
|
|
959
|
-
|
|
960
|
-
|
|
961
|
-
|
|
962
|
-
|
|
963
|
-
|
|
964
|
-
|
|
965
|
-
|
|
966
|
-
|
|
967
|
-
|
|
968
|
-
|
|
969
|
-
|
|
970
|
-
|
|
971
|
-
|
|
972
|
-
|
|
973
|
-
|
|
974
|
-
|
|
975
|
-
|
|
976
|
-
|
|
977
|
-
|
|
978
|
-
|
|
862
|
+
// 2. target별로 ensureDictKeys 호출 (순차 처리)
|
|
863
|
+
await sonamuDictionary.ensureDictKeys([...new Set(keys)]);
|
|
864
|
+
|
|
865
|
+
// 3. 템플릿 생성 (병렬 처리)
|
|
866
|
+
const result = await Promise.all(
|
|
867
|
+
options.map(async ({ entityId, templateKey, enumId, overwrite }) => {
|
|
868
|
+
try {
|
|
869
|
+
return await Sonamu.syncer.generateTemplate(
|
|
870
|
+
/* SAFETY: UI 도구의 Zod 입력 스키마가 이 값의 타입을 보장한다. */ templateKey as TemplateKey,
|
|
871
|
+
/* SAFETY: UI 도구의 Zod 입력 스키마가 Entity 템플릿 옵션을 보장한다. */ {
|
|
872
|
+
entityId,
|
|
873
|
+
enumId,
|
|
874
|
+
} as EntityTemplateInput,
|
|
875
|
+
{
|
|
876
|
+
overwrite,
|
|
877
|
+
},
|
|
878
|
+
);
|
|
879
|
+
} catch (e) {
|
|
880
|
+
if (isSoException(e) && e.statusCode === 541) {
|
|
881
|
+
return null;
|
|
882
|
+
} else {
|
|
883
|
+
console.error(e);
|
|
884
|
+
throw e;
|
|
885
|
+
}
|
|
979
886
|
}
|
|
980
|
-
}
|
|
981
|
-
|
|
982
|
-
);
|
|
887
|
+
}),
|
|
888
|
+
);
|
|
983
889
|
|
|
984
|
-
|
|
985
|
-
|
|
986
|
-
|
|
987
|
-
|
|
988
|
-
|
|
890
|
+
if (result.filter(nonNullable).length === 0) {
|
|
891
|
+
throw new ServiceUnavailableException(SD("sonamu.error.allFilesGenerated"));
|
|
892
|
+
}
|
|
893
|
+
return result;
|
|
894
|
+
}),
|
|
895
|
+
);
|
|
989
896
|
|
|
990
897
|
server.post<{
|
|
991
898
|
Body: {
|
|
@@ -995,48 +902,63 @@ export async function sonamuUIApiPlugin(fastify: FastifyInstance) {
|
|
|
995
902
|
enumId?: string;
|
|
996
903
|
};
|
|
997
904
|
};
|
|
998
|
-
}>(
|
|
999
|
-
|
|
905
|
+
}>(
|
|
906
|
+
"/api/scaffolding/preview",
|
|
907
|
+
(request): Promise<{ pathAndCodes: PathAndCode[] }> =>
|
|
908
|
+
forwardAsyncErrors(async () => {
|
|
909
|
+
const { option } = request.body;
|
|
1000
910
|
|
|
1001
|
-
|
|
1002
|
-
|
|
1003
|
-
|
|
1004
|
-
|
|
1005
|
-
|
|
1006
|
-
|
|
911
|
+
try {
|
|
912
|
+
const { templateKey, ...templateOptions } = option;
|
|
913
|
+
const pathAndCodes = await Sonamu.syncer.renderTemplate(
|
|
914
|
+
/* SAFETY: UI 도구의 Zod 입력 스키마가 이 값의 타입을 보장한다. */ templateKey as TemplateKey,
|
|
915
|
+
templateOptions,
|
|
916
|
+
);
|
|
1007
917
|
|
|
1008
|
-
|
|
1009
|
-
|
|
1010
|
-
|
|
1011
|
-
|
|
1012
|
-
|
|
1013
|
-
|
|
918
|
+
return { pathAndCodes };
|
|
919
|
+
} catch (e) {
|
|
920
|
+
console.error(e);
|
|
921
|
+
throw e;
|
|
922
|
+
}
|
|
923
|
+
}),
|
|
924
|
+
);
|
|
1014
925
|
|
|
1015
|
-
server.post("/api/fixture",
|
|
1016
|
-
|
|
1017
|
-
sourceDB
|
|
1018
|
-
|
|
1019
|
-
|
|
1020
|
-
|
|
1021
|
-
|
|
926
|
+
server.post("/api/fixture", (request) =>
|
|
927
|
+
forwardAsyncErrors(async () => {
|
|
928
|
+
const { sourceDB, targetDB, search, duplicateCheck } =
|
|
929
|
+
/* SAFETY: UI 도구의 Zod 입력 스키마가 이 값의 타입을 보장한다. */ request.body as {
|
|
930
|
+
sourceDB: keyof SonamuDBConfig;
|
|
931
|
+
targetDB: keyof SonamuDBConfig;
|
|
932
|
+
search: FixtureSearchOptions;
|
|
933
|
+
duplicateCheck?: DuplicateCheckOptions;
|
|
934
|
+
};
|
|
1022
935
|
|
|
1023
|
-
|
|
1024
|
-
|
|
936
|
+
return FixtureManager.getFixtures(sourceDB, targetDB, search, duplicateCheck);
|
|
937
|
+
}),
|
|
938
|
+
);
|
|
1025
939
|
|
|
1026
|
-
server.post("/api/fixture/import",
|
|
1027
|
-
|
|
1028
|
-
db
|
|
1029
|
-
|
|
1030
|
-
|
|
940
|
+
server.post("/api/fixture/import", (request) =>
|
|
941
|
+
forwardAsyncErrors(async () => {
|
|
942
|
+
const { db, fixtures } =
|
|
943
|
+
/* SAFETY: UI 도구의 Zod 입력 스키마가 이 값의 타입을 보장한다. */ request.body as {
|
|
944
|
+
db: keyof SonamuDBConfig;
|
|
945
|
+
fixtures: FixtureRecord[];
|
|
946
|
+
};
|
|
1031
947
|
|
|
1032
|
-
|
|
1033
|
-
|
|
948
|
+
return FixtureManager.insertFixtures(db, fixtures);
|
|
949
|
+
}),
|
|
950
|
+
);
|
|
1034
951
|
|
|
1035
|
-
server.post("/api/fixture/addFixtureLoader",
|
|
1036
|
-
|
|
952
|
+
server.post("/api/fixture/addFixtureLoader", (request) =>
|
|
953
|
+
forwardAsyncErrors(async () => {
|
|
954
|
+
const { code } =
|
|
955
|
+
/* SAFETY: UI 도구의 Zod 입력 스키마가 이 값의 타입을 보장한다. */ request.body as {
|
|
956
|
+
code: string;
|
|
957
|
+
};
|
|
1037
958
|
|
|
1038
|
-
|
|
1039
|
-
|
|
959
|
+
return FixtureManager.addFixtureLoader(code);
|
|
960
|
+
}),
|
|
961
|
+
);
|
|
1040
962
|
|
|
1041
963
|
server.get("/api/i18n/dictionary", async () => {
|
|
1042
964
|
return sonamuDictionary.getDictionary();
|
|
@@ -1053,14 +975,16 @@ export async function sonamuUIApiPlugin(fastify: FastifyInstance) {
|
|
|
1053
975
|
.send(buffer);
|
|
1054
976
|
});
|
|
1055
977
|
|
|
1056
|
-
server.post("/api/i18n/import",
|
|
1057
|
-
|
|
1058
|
-
|
|
1059
|
-
|
|
1060
|
-
|
|
1061
|
-
|
|
1062
|
-
|
|
1063
|
-
|
|
978
|
+
server.post("/api/i18n/import", (request) =>
|
|
979
|
+
forwardAsyncErrors(async () => {
|
|
980
|
+
const data = await request.file();
|
|
981
|
+
if (!data) {
|
|
982
|
+
throw new BadRequestException(SD("sonamu.error.fileNotUploaded"));
|
|
983
|
+
}
|
|
984
|
+
const buffer = await data.toBuffer();
|
|
985
|
+
return sonamuDictionary.importFromExcel(buffer);
|
|
986
|
+
}),
|
|
987
|
+
);
|
|
1064
988
|
|
|
1065
989
|
server.post<{
|
|
1066
990
|
Body: {
|
|
@@ -1069,33 +993,41 @@ export async function sonamuUIApiPlugin(fastify: FastifyInstance) {
|
|
|
1069
993
|
source: "entity" | "project" | "sonamu";
|
|
1070
994
|
values: Record<string, string>;
|
|
1071
995
|
};
|
|
1072
|
-
}>("/api/i18n/update",
|
|
1073
|
-
|
|
1074
|
-
|
|
1075
|
-
|
|
996
|
+
}>("/api/i18n/update", (request) =>
|
|
997
|
+
forwardAsyncErrors(async () => {
|
|
998
|
+
await sonamuDictionary.updateEntry(request.body);
|
|
999
|
+
return { success: true };
|
|
1000
|
+
}),
|
|
1001
|
+
);
|
|
1076
1002
|
|
|
1077
1003
|
server.post<{
|
|
1078
1004
|
Body: {
|
|
1079
1005
|
key: string;
|
|
1080
1006
|
values: Record<string, string>;
|
|
1081
1007
|
};
|
|
1082
|
-
}>("/api/i18n/create",
|
|
1083
|
-
|
|
1084
|
-
|
|
1085
|
-
|
|
1008
|
+
}>("/api/i18n/create", (request) =>
|
|
1009
|
+
forwardAsyncErrors(async () => {
|
|
1010
|
+
await sonamuDictionary.createEntry(request.body);
|
|
1011
|
+
return { success: true };
|
|
1012
|
+
}),
|
|
1013
|
+
);
|
|
1086
1014
|
|
|
1087
1015
|
server.post<{
|
|
1088
1016
|
Body: {
|
|
1089
1017
|
key: string;
|
|
1090
1018
|
};
|
|
1091
|
-
}>("/api/i18n/delete",
|
|
1092
|
-
|
|
1093
|
-
|
|
1094
|
-
|
|
1019
|
+
}>("/api/i18n/delete", (request) =>
|
|
1020
|
+
forwardAsyncErrors(async () => {
|
|
1021
|
+
await sonamuDictionary.deleteEntry(request.body.key);
|
|
1022
|
+
return { success: true };
|
|
1023
|
+
}),
|
|
1024
|
+
);
|
|
1095
1025
|
|
|
1096
|
-
server.post<{ Body: { keys: string[] } }>("/api/i18n/checkUsage",
|
|
1097
|
-
|
|
1098
|
-
|
|
1026
|
+
server.post<{ Body: { keys: string[] } }>("/api/i18n/checkUsage", (request) =>
|
|
1027
|
+
forwardAsyncErrors(async () => {
|
|
1028
|
+
return sonamuDictionary.checkUsage(request.body.keys);
|
|
1029
|
+
}),
|
|
1030
|
+
);
|
|
1099
1031
|
|
|
1100
1032
|
// Tasks API
|
|
1101
1033
|
server.get("/api/tasks/status", async () => {
|
|
@@ -1123,61 +1055,71 @@ export async function sonamuUIApiPlugin(fastify: FastifyInstance) {
|
|
|
1123
1055
|
createdAfter?: string;
|
|
1124
1056
|
createdBefore?: string;
|
|
1125
1057
|
};
|
|
1126
|
-
}>("/api/tasks/workflowRuns",
|
|
1127
|
-
|
|
1128
|
-
|
|
1129
|
-
|
|
1130
|
-
|
|
1131
|
-
|
|
1132
|
-
|
|
1133
|
-
|
|
1134
|
-
|
|
1135
|
-
|
|
1136
|
-
|
|
1137
|
-
|
|
1138
|
-
|
|
1139
|
-
|
|
1140
|
-
|
|
1058
|
+
}>("/api/tasks/workflowRuns", (request) =>
|
|
1059
|
+
forwardAsyncErrors(async () => {
|
|
1060
|
+
const backend = Sonamu.workflows.backend;
|
|
1061
|
+
const { limit, after, before, order, status, workflowName, createdAfter, createdBefore } =
|
|
1062
|
+
request.query;
|
|
1063
|
+
return backend.listWorkflowRuns({
|
|
1064
|
+
limit: limit ? Number.parseInt(limit, 10) : undefined,
|
|
1065
|
+
after,
|
|
1066
|
+
before,
|
|
1067
|
+
order,
|
|
1068
|
+
status: status ? status.split(",") : undefined,
|
|
1069
|
+
workflowName: workflowName || undefined,
|
|
1070
|
+
createdAfter: createdAfter ? new Date(createdAfter) : undefined,
|
|
1071
|
+
createdBefore: createdBefore ? new Date(createdBefore) : undefined,
|
|
1072
|
+
});
|
|
1073
|
+
}),
|
|
1074
|
+
);
|
|
1141
1075
|
|
|
1142
1076
|
server.get<{
|
|
1143
1077
|
Params: { id: string };
|
|
1144
|
-
}>("/api/tasks/workflowRuns/:id",
|
|
1145
|
-
|
|
1146
|
-
|
|
1147
|
-
|
|
1148
|
-
|
|
1149
|
-
|
|
1150
|
-
|
|
1151
|
-
|
|
1152
|
-
|
|
1153
|
-
|
|
1078
|
+
}>("/api/tasks/workflowRuns/:id", (request) =>
|
|
1079
|
+
forwardAsyncErrors(async () => {
|
|
1080
|
+
const backend = Sonamu.workflows.backend;
|
|
1081
|
+
const workflowRun = await backend.getWorkflowRun({
|
|
1082
|
+
workflowRunId: request.params.id,
|
|
1083
|
+
});
|
|
1084
|
+
if (!workflowRun) {
|
|
1085
|
+
throw new Error(`Workflow run not found: ${request.params.id}`);
|
|
1086
|
+
}
|
|
1087
|
+
return workflowRun;
|
|
1088
|
+
}),
|
|
1089
|
+
);
|
|
1154
1090
|
|
|
1155
1091
|
server.post<{
|
|
1156
1092
|
Params: { id: string };
|
|
1157
|
-
}>("/api/tasks/workflowRuns/:id/cancel",
|
|
1158
|
-
|
|
1159
|
-
|
|
1160
|
-
|
|
1161
|
-
|
|
1162
|
-
|
|
1093
|
+
}>("/api/tasks/workflowRuns/:id/cancel", (request) =>
|
|
1094
|
+
forwardAsyncErrors(async () => {
|
|
1095
|
+
const backend = Sonamu.workflows.backend;
|
|
1096
|
+
return backend.cancelWorkflowRun({
|
|
1097
|
+
workflowRunId: request.params.id,
|
|
1098
|
+
});
|
|
1099
|
+
}),
|
|
1100
|
+
);
|
|
1163
1101
|
|
|
1164
1102
|
server.post<{
|
|
1165
1103
|
Params: { id: string };
|
|
1166
|
-
}>("/api/tasks/workflowRuns/:id/pause",
|
|
1167
|
-
|
|
1168
|
-
|
|
1169
|
-
|
|
1170
|
-
|
|
1171
|
-
|
|
1104
|
+
}>("/api/tasks/workflowRuns/:id/pause", (request) =>
|
|
1105
|
+
forwardAsyncErrors(async () => {
|
|
1106
|
+
const backend = Sonamu.workflows.backend;
|
|
1107
|
+
return backend.pauseWorkflowRun({
|
|
1108
|
+
workflowRunId: request.params.id,
|
|
1109
|
+
});
|
|
1110
|
+
}),
|
|
1111
|
+
);
|
|
1172
1112
|
|
|
1173
1113
|
server.post<{
|
|
1174
1114
|
Params: { id: string };
|
|
1175
|
-
}>("/api/tasks/workflowRuns/:id/resume",
|
|
1176
|
-
|
|
1177
|
-
|
|
1178
|
-
|
|
1179
|
-
|
|
1180
|
-
|
|
1115
|
+
}>("/api/tasks/workflowRuns/:id/resume", (request) =>
|
|
1116
|
+
forwardAsyncErrors(async () => {
|
|
1117
|
+
const backend = Sonamu.workflows.backend;
|
|
1118
|
+
return backend.resumeWorkflowRun({
|
|
1119
|
+
workflowRunId: request.params.id,
|
|
1120
|
+
});
|
|
1121
|
+
}),
|
|
1122
|
+
);
|
|
1181
1123
|
|
|
1182
1124
|
server.get<{
|
|
1183
1125
|
Params: { id: string };
|
|
@@ -1186,32 +1128,36 @@ export async function sonamuUIApiPlugin(fastify: FastifyInstance) {
|
|
|
1186
1128
|
after?: string;
|
|
1187
1129
|
before?: string;
|
|
1188
1130
|
};
|
|
1189
|
-
}>("/api/tasks/workflowRuns/:id/steps",
|
|
1190
|
-
|
|
1191
|
-
|
|
1192
|
-
|
|
1193
|
-
|
|
1194
|
-
|
|
1195
|
-
|
|
1196
|
-
|
|
1197
|
-
|
|
1198
|
-
|
|
1131
|
+
}>("/api/tasks/workflowRuns/:id/steps", (request) =>
|
|
1132
|
+
forwardAsyncErrors(async () => {
|
|
1133
|
+
const backend = Sonamu.workflows.backend;
|
|
1134
|
+
const { limit, after, before } = request.query;
|
|
1135
|
+
return backend.listStepAttempts({
|
|
1136
|
+
workflowRunId: request.params.id,
|
|
1137
|
+
limit: limit ? Number.parseInt(limit, 10) : undefined,
|
|
1138
|
+
after,
|
|
1139
|
+
before,
|
|
1140
|
+
});
|
|
1141
|
+
}),
|
|
1142
|
+
);
|
|
1199
1143
|
|
|
1200
1144
|
/**
|
|
1201
1145
|
* Health Check API
|
|
1202
1146
|
* MCP 도구가 Sonamu 서버를 자동 감지하기 위한 엔드포인트
|
|
1203
1147
|
*/
|
|
1204
|
-
server.get("/api/sonamu/health",
|
|
1205
|
-
|
|
1206
|
-
|
|
1207
|
-
|
|
1208
|
-
|
|
1209
|
-
|
|
1210
|
-
|
|
1211
|
-
|
|
1212
|
-
|
|
1213
|
-
|
|
1214
|
-
|
|
1148
|
+
server.get("/api/sonamu/health", (request) =>
|
|
1149
|
+
forwardAsyncErrors(async () => {
|
|
1150
|
+
const address = request.server.server.address();
|
|
1151
|
+
const port = address && isObjectValue(address) ? address.port : 0;
|
|
1152
|
+
|
|
1153
|
+
return {
|
|
1154
|
+
ok: true,
|
|
1155
|
+
project: process.cwd().split("/").pop() || "unknown",
|
|
1156
|
+
port,
|
|
1157
|
+
timestamp: new Date().toISOString(),
|
|
1158
|
+
};
|
|
1159
|
+
}),
|
|
1160
|
+
);
|
|
1215
1161
|
|
|
1216
1162
|
/**
|
|
1217
1163
|
* Fixture 생성 API
|
|
@@ -1220,7 +1166,7 @@ export async function sonamuUIApiPlugin(fastify: FastifyInstance) {
|
|
|
1220
1166
|
Body: {
|
|
1221
1167
|
entity: string;
|
|
1222
1168
|
count?: number;
|
|
1223
|
-
overrides?:
|
|
1169
|
+
overrides?: FixtureGenerationSpec["overrides"];
|
|
1224
1170
|
targetDb?: "fixture" | "test";
|
|
1225
1171
|
};
|
|
1226
1172
|
}>("/api/sonamu/fixture/generate", async (request, reply) => {
|
|
@@ -1271,7 +1217,7 @@ export async function sonamuUIApiPlugin(fastify: FastifyInstance) {
|
|
|
1271
1217
|
entity: string;
|
|
1272
1218
|
strategy: "sample" | "recent" | "random" | "query";
|
|
1273
1219
|
limit?: number;
|
|
1274
|
-
where?:
|
|
1220
|
+
where?: DataExplorerOptions["where"];
|
|
1275
1221
|
};
|
|
1276
1222
|
}>("/api/sonamu/fixture/explore", async (request, reply) => {
|
|
1277
1223
|
const { entity, strategy, limit = 10, where } = request.body;
|
|
@@ -1420,35 +1366,45 @@ export async function sonamuUIApiPlugin(fastify: FastifyInstance) {
|
|
|
1420
1366
|
return getCddTree();
|
|
1421
1367
|
});
|
|
1422
1368
|
|
|
1423
|
-
server.post<{ Body: { filePath: string } }>("/api/cdd/readContent",
|
|
1424
|
-
|
|
1425
|
-
|
|
1426
|
-
|
|
1369
|
+
server.post<{ Body: { filePath: string } }>("/api/cdd/readContent", (request) =>
|
|
1370
|
+
forwardAsyncErrors(async () => {
|
|
1371
|
+
const { filePath } = request.body;
|
|
1372
|
+
return readContent(filePath);
|
|
1373
|
+
}),
|
|
1374
|
+
);
|
|
1427
1375
|
|
|
1428
|
-
server.post<{ Body: { filePath: string } }>("/api/cdd/editContent",
|
|
1429
|
-
|
|
1430
|
-
|
|
1431
|
-
|
|
1376
|
+
server.post<{ Body: { filePath: string } }>("/api/cdd/editContent", (request) =>
|
|
1377
|
+
forwardAsyncErrors(async () => {
|
|
1378
|
+
const { filePath } = request.body;
|
|
1379
|
+
return editContent(filePath);
|
|
1380
|
+
}),
|
|
1381
|
+
);
|
|
1432
1382
|
|
|
1433
|
-
server.post<{ Body: { filePath: string } }>("/api/cdd/openSource",
|
|
1434
|
-
|
|
1435
|
-
|
|
1436
|
-
|
|
1437
|
-
|
|
1383
|
+
server.post<{ Body: { filePath: string } }>("/api/cdd/openSource", (request) =>
|
|
1384
|
+
forwardAsyncErrors(async () => {
|
|
1385
|
+
const { filePath } = request.body;
|
|
1386
|
+
openSourceFile(filePath);
|
|
1387
|
+
return { success: true };
|
|
1388
|
+
}),
|
|
1389
|
+
);
|
|
1438
1390
|
|
|
1439
1391
|
// CDD Rules API
|
|
1440
1392
|
server.get("/api/cdd/rules", async () => {
|
|
1441
1393
|
return listRules();
|
|
1442
1394
|
});
|
|
1443
1395
|
|
|
1444
|
-
server.post<{ Body: { ruleKey: string } }>("/api/cdd/readRule",
|
|
1445
|
-
|
|
1446
|
-
|
|
1447
|
-
|
|
1396
|
+
server.post<{ Body: { ruleKey: string } }>("/api/cdd/readRule", (request) =>
|
|
1397
|
+
forwardAsyncErrors(async () => {
|
|
1398
|
+
const { ruleKey } = request.body;
|
|
1399
|
+
return readRule(ruleKey);
|
|
1400
|
+
}),
|
|
1401
|
+
);
|
|
1448
1402
|
|
|
1449
|
-
server.post<{ Body: CddAddRuleRequest }>("/api/cdd/addRule",
|
|
1450
|
-
|
|
1451
|
-
|
|
1403
|
+
server.post<{ Body: CddAddRuleRequest }>("/api/cdd/addRule", (request) =>
|
|
1404
|
+
forwardAsyncErrors(async () => {
|
|
1405
|
+
return addRule(request.body);
|
|
1406
|
+
}),
|
|
1407
|
+
);
|
|
1452
1408
|
|
|
1453
1409
|
// CDD AC API
|
|
1454
1410
|
server.get("/api/cdd/ac", async () => {
|