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
|
@@ -0,0 +1,73 @@
|
|
|
1
|
+
import {
|
|
2
|
+
constants,
|
|
3
|
+
type MakeDirectoryOptions,
|
|
4
|
+
type PathLike,
|
|
5
|
+
type RmOptions,
|
|
6
|
+
type Stats,
|
|
7
|
+
} from "node:fs";
|
|
8
|
+
import { access, mkdir, readFile, rm, stat, unlink, writeFile } from "node:fs/promises";
|
|
9
|
+
|
|
10
|
+
export type SyncerFilesystemDependencies = {
|
|
11
|
+
access(path: PathLike, mode?: number): Promise<void>;
|
|
12
|
+
mkdir(path: PathLike, options?: MakeDirectoryOptions): Promise<string | undefined>;
|
|
13
|
+
readFile(path: PathLike, encoding: BufferEncoding): Promise<string>;
|
|
14
|
+
rm(path: PathLike, options?: RmOptions): Promise<void>;
|
|
15
|
+
stat(path: PathLike): Promise<Stats>;
|
|
16
|
+
unlink(path: PathLike): Promise<void>;
|
|
17
|
+
writeFile(
|
|
18
|
+
path: PathLike,
|
|
19
|
+
data: string | NodeJS.ArrayBufferView,
|
|
20
|
+
encoding?: BufferEncoding,
|
|
21
|
+
): Promise<void>;
|
|
22
|
+
};
|
|
23
|
+
|
|
24
|
+
const defaults: SyncerFilesystemDependencies = {
|
|
25
|
+
access: (path, mode) => access(path, mode),
|
|
26
|
+
mkdir: (path, options) => mkdir(path, options),
|
|
27
|
+
readFile: (path, encoding) => readFile(path, encoding),
|
|
28
|
+
rm: (path, options) => rm(path, options),
|
|
29
|
+
stat: (path) => stat(path),
|
|
30
|
+
unlink: (path) => unlink(path),
|
|
31
|
+
writeFile: (path, data, encoding) => writeFile(path, data, encoding),
|
|
32
|
+
};
|
|
33
|
+
|
|
34
|
+
export const syncerFilesystem: SyncerFilesystemDependencies = { ...defaults };
|
|
35
|
+
|
|
36
|
+
export async function syncerFileExists(path: PathLike): Promise<boolean> {
|
|
37
|
+
try {
|
|
38
|
+
await syncerFilesystem.access(path, constants.F_OK);
|
|
39
|
+
return true;
|
|
40
|
+
} catch {
|
|
41
|
+
return false;
|
|
42
|
+
}
|
|
43
|
+
}
|
|
44
|
+
|
|
45
|
+
/** 테스트와 임베딩 환경에서 Syncer의 파일시스템 경계를 교체합니다. */
|
|
46
|
+
export function configureSyncerFilesystem(
|
|
47
|
+
dependencies: Partial<SyncerFilesystemDependencies>,
|
|
48
|
+
): () => void {
|
|
49
|
+
const restorers: Array<() => void> = [];
|
|
50
|
+
const override = <Key extends keyof SyncerFilesystemDependencies>(key: Key): void => {
|
|
51
|
+
if (!(key in dependencies)) return;
|
|
52
|
+
|
|
53
|
+
const previousDependency = syncerFilesystem[key];
|
|
54
|
+
Object.assign(syncerFilesystem, { [key]: dependencies[key] });
|
|
55
|
+
restorers.push(() => Object.assign(syncerFilesystem, { [key]: previousDependency }));
|
|
56
|
+
};
|
|
57
|
+
|
|
58
|
+
override("access");
|
|
59
|
+
override("mkdir");
|
|
60
|
+
override("readFile");
|
|
61
|
+
override("rm");
|
|
62
|
+
override("stat");
|
|
63
|
+
override("unlink");
|
|
64
|
+
override("writeFile");
|
|
65
|
+
|
|
66
|
+
let configured = true;
|
|
67
|
+
return () => {
|
|
68
|
+
if (!configured) return;
|
|
69
|
+
configured = false;
|
|
70
|
+
|
|
71
|
+
for (const restore of restorers) restore();
|
|
72
|
+
};
|
|
73
|
+
}
|
|
@@ -11,6 +11,7 @@ import { globAsync } from "../utils/async-utils";
|
|
|
11
11
|
import { importMembers } from "../utils/esm-utils";
|
|
12
12
|
import { runtimePath } from "../utils/path-utils";
|
|
13
13
|
import { type AbsolutePath } from "../utils/path-utils";
|
|
14
|
+
import { isFunctionValue, isObjectValue } from "../utils/runtime-value";
|
|
14
15
|
import { readApisFromFile } from "./api-parser";
|
|
15
16
|
|
|
16
17
|
export type LoadedApis = ExtendedApi[];
|
|
@@ -35,7 +36,10 @@ export async function loadApis(): Promise<LoadedApis> {
|
|
|
35
36
|
Sonamu.apiRootPath,
|
|
36
37
|
"src/application/**/*.{model,frame}.ts", // !! runtimePath 안 씀 주의 !!
|
|
37
38
|
);
|
|
38
|
-
const modelPaths =
|
|
39
|
+
const modelPaths =
|
|
40
|
+
/* SAFETY: TypeScript AST 파싱과 동기화 입력 계약이 이 값의 타입을 보장한다. */ (await globAsync(
|
|
41
|
+
modelPathsPattern,
|
|
42
|
+
)) as AbsolutePath[];
|
|
39
43
|
|
|
40
44
|
const apis: LoadedApis = [];
|
|
41
45
|
for (const filePath of modelPaths) {
|
|
@@ -125,16 +129,16 @@ export async function loadWorkflows() {
|
|
|
125
129
|
importedMembers
|
|
126
130
|
.filter(({ value }) => {
|
|
127
131
|
return (
|
|
128
|
-
|
|
132
|
+
isObjectValue(value) &&
|
|
129
133
|
value !== null &&
|
|
130
134
|
"type" in value &&
|
|
131
135
|
value.type === "workflow" &&
|
|
132
136
|
"fn" in value &&
|
|
133
|
-
|
|
137
|
+
isFunctionValue(value.fn)
|
|
134
138
|
);
|
|
135
139
|
})
|
|
136
140
|
.map(({ value }) => {
|
|
137
|
-
return value as WorkflowMetadata;
|
|
141
|
+
return /* SAFETY: TypeScript AST 파싱과 동기화 입력 계약이 이 값의 타입을 보장한다. */ value as WorkflowMetadata;
|
|
138
142
|
}),
|
|
139
143
|
);
|
|
140
144
|
}
|
|
@@ -1,5 +1,4 @@
|
|
|
1
1
|
import assert from "assert";
|
|
2
|
-
import { mkdir, readFile, writeFile } from "fs/promises";
|
|
3
2
|
import path, { dirname } from "path";
|
|
4
3
|
|
|
5
4
|
import chalk from "chalk";
|
|
@@ -10,10 +9,12 @@ import { AlreadyProcessedException } from "../exceptions/so-exceptions";
|
|
|
10
9
|
import { Naite } from "../naite/naite";
|
|
11
10
|
import { isTest } from "../utils/controller";
|
|
12
11
|
import { formatCode } from "../utils/formatter";
|
|
13
|
-
import { copyFileWithReplaceCoreToShared, exists } from "../utils/fs-utils";
|
|
14
12
|
import { type AbsolutePath } from "../utils/path-utils";
|
|
13
|
+
import { isObjectValue } from "../utils/runtime-value";
|
|
15
14
|
import { generateTemplate } from "./code-generator";
|
|
15
|
+
import { copyFileWithReplaceCoreToShared } from "./file-copy";
|
|
16
16
|
import { trackWritten } from "./file-tracking";
|
|
17
|
+
import { syncerFileExists, syncerFilesystem } from "./filesystem-dependencies";
|
|
17
18
|
|
|
18
19
|
// web/.sonamu.env 에 현재 설정값 저장
|
|
19
20
|
export async function actionSyncConfig() {
|
|
@@ -22,8 +23,11 @@ export async function actionSyncConfig() {
|
|
|
22
23
|
|
|
23
24
|
Naite.t("actionSyncConfig", { content });
|
|
24
25
|
await Promise.all([
|
|
25
|
-
...Sonamu.config.sync.targets.map(
|
|
26
|
-
|
|
26
|
+
...Sonamu.config.sync.targets.map((target) => {
|
|
27
|
+
return syncerFilesystem.writeFile(
|
|
28
|
+
path.join(Sonamu.appRootPath, target, ".sonamu.env"),
|
|
29
|
+
content,
|
|
30
|
+
);
|
|
27
31
|
}),
|
|
28
32
|
generateTemplate("generated_sso", {}, { overwrite: true }),
|
|
29
33
|
]);
|
|
@@ -88,6 +92,30 @@ export async function actionGenerateHttps(): Promise<AbsolutePath> {
|
|
|
88
92
|
return res;
|
|
89
93
|
}
|
|
90
94
|
|
|
95
|
+
/**
|
|
96
|
+
* 최종 REST caster를 담는 API 전용 validator registry를 재생성합니다.
|
|
97
|
+
*/
|
|
98
|
+
export async function actionGenerateHttpValidators(): Promise<AbsolutePath> {
|
|
99
|
+
const registryPath =
|
|
100
|
+
/* SAFETY: TypeScript AST 파싱과 동기화 입력 계약이 이 값의 타입을 보장한다. */ path.join(
|
|
101
|
+
Sonamu.apiRootPath,
|
|
102
|
+
"src/application/sonamu.validators.generated.ts",
|
|
103
|
+
) as AbsolutePath;
|
|
104
|
+
const policy = Sonamu.config.validation?.zodCompiler;
|
|
105
|
+
const isAot = isObjectValue(policy) && policy !== null && policy.api === "aot";
|
|
106
|
+
if (!isAot) {
|
|
107
|
+
// opt-out/JIT 전환 뒤 AOT compile import가 애플리케이션에 남지 않도록 산출물도 함께 정리합니다.
|
|
108
|
+
if (await syncerFileExists(registryPath)) {
|
|
109
|
+
await syncerFilesystem.unlink(registryPath);
|
|
110
|
+
}
|
|
111
|
+
return registryPath;
|
|
112
|
+
}
|
|
113
|
+
|
|
114
|
+
const [generatedPath] = await generateTemplate("http_validators", {}, { overwrite: true });
|
|
115
|
+
assert(generatedPath);
|
|
116
|
+
return generatedPath;
|
|
117
|
+
}
|
|
118
|
+
|
|
91
119
|
/**
|
|
92
120
|
* queries.generated.ts 재생성합니다.
|
|
93
121
|
* @returns 생성된 파일 경로 배열.
|
|
@@ -137,8 +165,8 @@ export async function actionSyncFilesToTargets(tsPaths: AbsolutePath[]): Promise
|
|
|
137
165
|
.replace(`/${apiDir}/`, `/${target}/`)
|
|
138
166
|
.replace("/application/", "/services/");
|
|
139
167
|
const dir = dirname(dst);
|
|
140
|
-
if (!(await
|
|
141
|
-
await mkdir(dir, { recursive: true });
|
|
168
|
+
if (!(await syncerFileExists(dir))) {
|
|
169
|
+
await syncerFilesystem.mkdir(dir, { recursive: true });
|
|
142
170
|
}
|
|
143
171
|
const syncHeader = [
|
|
144
172
|
"/**",
|
|
@@ -147,7 +175,9 @@ export async function actionSyncFilesToTargets(tsPaths: AbsolutePath[]): Promise
|
|
|
147
175
|
" */",
|
|
148
176
|
].join("\n");
|
|
149
177
|
await copyFileWithReplaceCoreToShared(realSrc, dst, syncHeader);
|
|
150
|
-
await trackWritten(
|
|
178
|
+
await trackWritten(
|
|
179
|
+
/* SAFETY: TypeScript AST 파싱과 동기화 입력 계약이 이 값의 타입을 보장한다. */ dst as AbsolutePath,
|
|
180
|
+
);
|
|
151
181
|
!isTest() &&
|
|
152
182
|
console.log(
|
|
153
183
|
chalk.bold("Copied: ") + chalk.blue(dst.replace(`${Sonamu.appRootPath}/`, "")),
|
|
@@ -174,7 +204,9 @@ export async function actionCopySharedToTargetsIfNotExists(): Promise<void> {
|
|
|
174
204
|
import.meta.dirname.replace("/dist/", "/src/"),
|
|
175
205
|
"../dict/utils.ts",
|
|
176
206
|
);
|
|
177
|
-
const dictUtilsCode = (await
|
|
207
|
+
const dictUtilsCode = (await syncerFileExists(dictUtilsPath))
|
|
208
|
+
? await syncerFilesystem.readFile(dictUtilsPath, "utf-8")
|
|
209
|
+
: "";
|
|
178
210
|
|
|
179
211
|
// 특정 변수 치환을 위해서 사용합니다.
|
|
180
212
|
const convertMap = {
|
|
@@ -192,16 +224,16 @@ export async function actionCopySharedToTargetsIfNotExists(): Promise<void> {
|
|
|
192
224
|
import.meta.dirname.replace("/dist/", "/src/"),
|
|
193
225
|
`../shared/${target}.shared.ts.txt`,
|
|
194
226
|
);
|
|
195
|
-
if (!(await
|
|
227
|
+
if (!(await syncerFileExists(srcPath))) {
|
|
196
228
|
continue;
|
|
197
229
|
}
|
|
198
|
-
if (!(await
|
|
230
|
+
if (!(await syncerFileExists(path.join(Sonamu.appRootPath, target)))) {
|
|
199
231
|
throw new Error(
|
|
200
232
|
`Tried to copy sonamu.shared.ts to target '${target}' but the target directory does not exist. Please check your project directory structure.`,
|
|
201
233
|
);
|
|
202
234
|
}
|
|
203
235
|
|
|
204
|
-
const fullText = await readFile(srcPath, "utf-8");
|
|
236
|
+
const fullText = await syncerFilesystem.readFile(srcPath, "utf-8");
|
|
205
237
|
const convertedText = Object.entries(convertMap).reduce(
|
|
206
238
|
(acc, [key, value]) => acc.replace(`$[[${key}]]`, value),
|
|
207
239
|
fullText,
|
|
@@ -211,8 +243,8 @@ export async function actionCopySharedToTargetsIfNotExists(): Promise<void> {
|
|
|
211
243
|
const destPath = path.join(Sonamu.appRootPath, target, "src/services/sonamu.shared.ts");
|
|
212
244
|
|
|
213
245
|
// 정말 혹시나지만 target 디렉토리는 있어도 src/services 디렉토리는 없을 수 있으므로 미리 생성해줍니다.
|
|
214
|
-
if (!(await
|
|
215
|
-
await mkdir(path.dirname(destPath), { recursive: true });
|
|
246
|
+
if (!(await syncerFileExists(path.dirname(destPath)))) {
|
|
247
|
+
await syncerFilesystem.mkdir(path.dirname(destPath), { recursive: true });
|
|
216
248
|
console.warn(`Created directory '${path.dirname(destPath)}' because it did not exist.`);
|
|
217
249
|
}
|
|
218
250
|
|
|
@@ -221,11 +253,11 @@ export async function actionCopySharedToTargetsIfNotExists(): Promise<void> {
|
|
|
221
253
|
// 최초 1회만 생성하고 이후에는 덮어쓰지 않습니다.
|
|
222
254
|
// 템플릿 내용($[[dictUtils]] 등)이 변경되었을 때 반영이 필요하면,
|
|
223
255
|
// 해당 파일을 삭제한 뒤 `pnpm sonamu sync`로 재생성하면 됩니다.
|
|
224
|
-
if (await
|
|
256
|
+
if (await syncerFileExists(destPath)) {
|
|
225
257
|
continue;
|
|
226
258
|
}
|
|
227
259
|
|
|
228
|
-
await writeFile(destPath, await formatCode(convertedText, destPath));
|
|
260
|
+
await syncerFilesystem.writeFile(destPath, await formatCode(convertedText, destPath));
|
|
229
261
|
!isTest() &&
|
|
230
262
|
console.log(chalk.bold("Copied: ") + chalk.blue(path.relative(Sonamu.appRootPath, destPath)));
|
|
231
263
|
}
|
|
@@ -244,7 +276,11 @@ export async function actionSyncSonamuDictionary(): Promise<void> {
|
|
|
244
276
|
const { targets } = Sonamu.config.sync;
|
|
245
277
|
const i18nConfig = Sonamu.config.i18n;
|
|
246
278
|
|
|
247
|
-
const targetList =
|
|
279
|
+
const targetList =
|
|
280
|
+
/* SAFETY: TypeScript AST 파싱과 동기화 입력 계약이 이 값의 타입을 보장한다. */ [
|
|
281
|
+
"api",
|
|
282
|
+
...targets,
|
|
283
|
+
] as ("api" | "web" | "app")[];
|
|
248
284
|
|
|
249
285
|
const apiI18nDir = path.join(Sonamu.appRootPath, Sonamu.config.api.dir, "src/i18n");
|
|
250
286
|
|
|
@@ -273,7 +309,7 @@ async function syncLocaleFiles(
|
|
|
273
309
|
const targetI18nDir = path.join(Sonamu.appRootPath, target, "src/i18n");
|
|
274
310
|
|
|
275
311
|
// 디렉토리가 없으면 생성
|
|
276
|
-
await mkdir(targetI18nDir, { recursive: true });
|
|
312
|
+
await syncerFilesystem.mkdir(targetI18nDir, { recursive: true });
|
|
277
313
|
|
|
278
314
|
for (const locale of locales) {
|
|
279
315
|
const sourceFile = path.join(apiI18nDir, `${locale}.ts`);
|
|
@@ -286,7 +322,9 @@ async function syncLocaleFiles(
|
|
|
286
322
|
" */",
|
|
287
323
|
].join("\n");
|
|
288
324
|
await copyFileWithReplaceCoreToShared(sourceFile, targetFile, syncHeader);
|
|
289
|
-
await trackWritten(
|
|
325
|
+
await trackWritten(
|
|
326
|
+
/* SAFETY: TypeScript AST 파싱과 동기화 입력 계약이 이 값의 타입을 보장한다. */ targetFile as AbsolutePath,
|
|
327
|
+
);
|
|
290
328
|
!isTest() &&
|
|
291
329
|
console.log(chalk.bold("Copied: ") + chalk.cyan(`${target}/src/i18n/${locale}.ts`));
|
|
292
330
|
}
|
package/src/syncer/syncer.ts
CHANGED
|
@@ -1,12 +1,11 @@
|
|
|
1
1
|
import assert from "assert";
|
|
2
2
|
import { EventEmitter } from "events";
|
|
3
|
-
import { unlink } from "fs/promises";
|
|
4
3
|
import path from "path";
|
|
5
4
|
|
|
6
5
|
import { hot } from "@sonamu-kit/hmr-hook";
|
|
7
6
|
import chalk from "chalk";
|
|
8
7
|
import { minimatch } from "minimatch";
|
|
9
|
-
import {
|
|
8
|
+
import { unique } from "radashi";
|
|
10
9
|
import { type z } from "zod";
|
|
11
10
|
|
|
12
11
|
import { registeredApis } from "../api/decorators";
|
|
@@ -22,20 +21,36 @@ import { type TemplateOptions } from "../types/types";
|
|
|
22
21
|
import { mapAsync, reduceAsync } from "../utils/async-utils";
|
|
23
22
|
import { centerText } from "../utils/console-util";
|
|
24
23
|
import { isTest } from "../utils/controller";
|
|
25
|
-
import { exists } from "../utils/fs-utils";
|
|
26
24
|
import { type AbsolutePath } from "../utils/path-utils";
|
|
27
25
|
import { runWithGracefulShutdown } from "../utils/process-utils";
|
|
26
|
+
import { isObjectValue } from "../utils/runtime-value";
|
|
28
27
|
import { findChangedFilesUsingChecksums, renewChecksums } from "./checksum";
|
|
29
28
|
import { generateTemplate, renderTemplate } from "./code-generator";
|
|
30
29
|
import { createEntity, delEntity } from "./entity-operations";
|
|
31
30
|
import { getChecksumPatternGroup, getChecksumPatternGroupInAbsolutePath } from "./file-patterns";
|
|
32
31
|
import { type FileType } from "./file-patterns";
|
|
32
|
+
import { syncerFileExists, syncerFilesystem } from "./filesystem-dependencies";
|
|
33
33
|
import { loadApis, loadModels, loadTypes, loadWorkflows } from "./module-loader";
|
|
34
34
|
import { type LoadedApis, type LoadedModels, type LoadedTypes } from "./module-loader";
|
|
35
35
|
import * as SyncerActions from "./syncer-actions";
|
|
36
36
|
|
|
37
|
-
type
|
|
38
|
-
|
|
37
|
+
type DiffGroupKey = FileType | "unknown";
|
|
38
|
+
type DiffGroups = Partial<Record<DiffGroupKey, AbsolutePath[]>>;
|
|
39
|
+
|
|
40
|
+
export interface SyncerDependencies {
|
|
41
|
+
actionCopySharedToTargetsIfNotExists: typeof SyncerActions.actionCopySharedToTargetsIfNotExists;
|
|
42
|
+
actionGenerateHttpValidators: typeof SyncerActions.actionGenerateHttpValidators;
|
|
43
|
+
actionGenerateSsrEntryServerIfNotExists: typeof SyncerActions.actionGenerateSsrEntryServerIfNotExists;
|
|
44
|
+
findChangedFilesUsingChecksums: typeof findChangedFilesUsingChecksums;
|
|
45
|
+
renewChecksums: typeof renewChecksums;
|
|
46
|
+
}
|
|
47
|
+
|
|
48
|
+
const defaultSyncerDependencies: SyncerDependencies = {
|
|
49
|
+
actionCopySharedToTargetsIfNotExists: SyncerActions.actionCopySharedToTargetsIfNotExists,
|
|
50
|
+
actionGenerateHttpValidators: SyncerActions.actionGenerateHttpValidators,
|
|
51
|
+
actionGenerateSsrEntryServerIfNotExists: SyncerActions.actionGenerateSsrEntryServerIfNotExists,
|
|
52
|
+
findChangedFilesUsingChecksums,
|
|
53
|
+
renewChecksums,
|
|
39
54
|
};
|
|
40
55
|
|
|
41
56
|
export class Syncer {
|
|
@@ -45,6 +60,8 @@ export class Syncer {
|
|
|
45
60
|
workflows: Map<string, WorkflowMetadata[]> = new Map();
|
|
46
61
|
eventEmitter: EventEmitter = new EventEmitter();
|
|
47
62
|
|
|
63
|
+
constructor(private readonly dependencies: SyncerDependencies = defaultSyncerDependencies) {}
|
|
64
|
+
|
|
48
65
|
/**
|
|
49
66
|
* 체크섬이 변경된 부분에 대해 싱크를 진행합니다.
|
|
50
67
|
* dev 서버가 처음 떴을 때, sonamu sync 할 때 실행됩니다. 이후에는 hmrAndSync 경로를 타요.
|
|
@@ -54,12 +71,15 @@ export class Syncer {
|
|
|
54
71
|
// 초기 부트스트랩! 얘네들은 idempotent하고 가볍기 때문에 무지성 실행해도 됩니다.
|
|
55
72
|
// 얘네들은 sonamu.lock에 들어가지도 않고 따라서 HMR 경로를 타지도 않는 친구들입니다.
|
|
56
73
|
// 그래서 아무 때나 그냥 돌려주면 되는데, hmrAndSync에서 매번 하는 것은 낭비이니 여기서 한 번만 합니다.
|
|
57
|
-
await
|
|
58
|
-
await
|
|
74
|
+
await this.dependencies.actionCopySharedToTargetsIfNotExists();
|
|
75
|
+
await this.dependencies.actionGenerateSsrEntryServerIfNotExists();
|
|
59
76
|
|
|
60
77
|
// 바뀐 것이 없으면 그냥 넘어가요.
|
|
61
|
-
const changedFiles = await findChangedFilesUsingChecksums();
|
|
78
|
+
const changedFiles = await this.dependencies.findChangedFilesUsingChecksums();
|
|
62
79
|
if (changedFiles.length === 0) {
|
|
80
|
+
if (await this.reconcileHttpValidatorRegistry()) {
|
|
81
|
+
await this.dependencies.renewChecksums();
|
|
82
|
+
}
|
|
63
83
|
console.log(chalk.black.bgGreen(centerText("All files are synced!")));
|
|
64
84
|
return;
|
|
65
85
|
}
|
|
@@ -71,14 +91,31 @@ export class Syncer {
|
|
|
71
91
|
async () => {
|
|
72
92
|
// 얘가 싱크 작업 수행하는 본체입니다.
|
|
73
93
|
await this.doSyncActions(changedFiles);
|
|
94
|
+
await this.reconcileHttpValidatorRegistry();
|
|
74
95
|
|
|
75
96
|
// 싱크 액션이 끝나면 항상 체크섬을 다시 갱신합니다.
|
|
76
|
-
await renewChecksums();
|
|
97
|
+
await this.dependencies.renewChecksums();
|
|
77
98
|
},
|
|
78
99
|
{ whenThisHappens: "SIGUSR2", waitForUpTo: 20000 },
|
|
79
100
|
);
|
|
80
101
|
}
|
|
81
102
|
|
|
103
|
+
private async reconcileHttpValidatorRegistry(): Promise<boolean> {
|
|
104
|
+
const registryPath = path.join(
|
|
105
|
+
Sonamu.apiRootPath,
|
|
106
|
+
"src/application/sonamu.validators.generated.ts",
|
|
107
|
+
);
|
|
108
|
+
const policy = Sonamu.config.validation?.zodCompiler;
|
|
109
|
+
const isAot = isObjectValue(policy) && policy !== null && policy.api === "aot";
|
|
110
|
+
if (isAot === (await syncerFileExists(registryPath))) {
|
|
111
|
+
return false;
|
|
112
|
+
}
|
|
113
|
+
|
|
114
|
+
// 변경 목록이 registry 삭제를 놓쳐도 checksum 갱신 전에 정책과 산출물을 다시 맞춥니다.
|
|
115
|
+
await this.dependencies.actionGenerateHttpValidators();
|
|
116
|
+
return true;
|
|
117
|
+
}
|
|
118
|
+
|
|
82
119
|
/**
|
|
83
120
|
* 강제 풀-싱크: lock을 무시하고 처음부터 다시 싱크합니다.
|
|
84
121
|
*
|
|
@@ -88,8 +125,8 @@ export class Syncer {
|
|
|
88
125
|
*/
|
|
89
126
|
async forceSync(): Promise<void> {
|
|
90
127
|
const lockPath = path.join(Sonamu.apiRootPath, "sonamu.lock");
|
|
91
|
-
if (await
|
|
92
|
-
await unlink(lockPath);
|
|
128
|
+
if (await syncerFileExists(lockPath)) {
|
|
129
|
+
await syncerFilesystem.unlink(lockPath);
|
|
93
130
|
}
|
|
94
131
|
await this.sync();
|
|
95
132
|
}
|
|
@@ -137,6 +174,7 @@ export class Syncer {
|
|
|
137
174
|
await this.autoloadApis();
|
|
138
175
|
await this.autoloadWorkflows();
|
|
139
176
|
await this.autoloadSsrRoutes();
|
|
177
|
+
await Sonamu.refreshHttpValidators();
|
|
140
178
|
|
|
141
179
|
this.eventEmitter.emit("onHMRCompleted");
|
|
142
180
|
}
|
|
@@ -182,7 +220,11 @@ export class Syncer {
|
|
|
182
220
|
// 그러니 안심하고 invalidate 해도 됩니다.
|
|
183
221
|
// 테스트 환경에서는 hot.invalidateFile시 초기 에러가 발생하기 때문에 invalidate 하지 않습니다.
|
|
184
222
|
if (!isTest()) {
|
|
185
|
-
const invalidatedPaths =
|
|
223
|
+
const invalidatedPaths =
|
|
224
|
+
/* SAFETY: TypeScript AST 파싱과 동기화 입력 계약이 이 값의 타입을 보장한다. */ (await hot.invalidateFile(
|
|
225
|
+
diffFilePath,
|
|
226
|
+
event,
|
|
227
|
+
)) as AbsolutePath[];
|
|
186
228
|
|
|
187
229
|
if (invalidatedPaths.length > 0) {
|
|
188
230
|
console.log(chalk.bold(`🔄 Invalidated:`));
|
|
@@ -271,7 +313,7 @@ export class Syncer {
|
|
|
271
313
|
clearSSRRoutes();
|
|
272
314
|
|
|
273
315
|
// ssr 폴더 없으면 스킵
|
|
274
|
-
if (!(await
|
|
316
|
+
if (!(await syncerFileExists(ssrConfigPath))) {
|
|
275
317
|
return;
|
|
276
318
|
}
|
|
277
319
|
|
|
@@ -302,7 +344,10 @@ export class Syncer {
|
|
|
302
344
|
*/
|
|
303
345
|
async doSyncActions(diffFilePaths: AbsolutePath[]): Promise<{ diffTypes: FileType[] }> {
|
|
304
346
|
const diffGroups = this.calculateDiffGroups(diffFilePaths);
|
|
305
|
-
const diffTypes =
|
|
347
|
+
const diffTypes =
|
|
348
|
+
/* SAFETY: TypeScript AST 파싱과 동기화 입력 계약이 이 값의 타입을 보장한다. */ Object.keys(
|
|
349
|
+
diffGroups,
|
|
350
|
+
) as FileType[];
|
|
306
351
|
|
|
307
352
|
// 여기는 별로 중요한 파트는 아닙니다.
|
|
308
353
|
// 아래의 if 전개를 깔끔하게 하려고 만든 DSL 같은 거라서, 무시하셔도 됩니다.
|
|
@@ -324,11 +369,27 @@ export class Syncer {
|
|
|
324
369
|
}
|
|
325
370
|
|
|
326
371
|
if (changeMatches("config")) {
|
|
327
|
-
await this.handleConfigChanges(
|
|
372
|
+
await this.handleConfigChanges();
|
|
328
373
|
}
|
|
329
374
|
|
|
330
375
|
if (changeMatches("i18n", "entity" /*레이블*/, "config" /*defaultLocale등*/)) {
|
|
331
|
-
await this.handleSonamuDictionaryRelatedChanges(
|
|
376
|
+
await this.handleSonamuDictionaryRelatedChanges();
|
|
377
|
+
}
|
|
378
|
+
|
|
379
|
+
const metadataChanged = diffTypes.some((type) =>
|
|
380
|
+
["entity", "types", "model", "frame", "config"].includes(type),
|
|
381
|
+
);
|
|
382
|
+
if (changeMatches("httpValidatorsGenerated") && !metadataChanged) {
|
|
383
|
+
// registry 자체 drift는 최신 in-memory metadata로 즉시 덮어써 lock 갱신 전에 정합성을 복구합니다.
|
|
384
|
+
await this.dependencies.actionGenerateHttpValidators();
|
|
385
|
+
}
|
|
386
|
+
|
|
387
|
+
if (metadataChanged) {
|
|
388
|
+
// 모든 생성/복사 액션 뒤 최신 metadata를 다시 읽어 registry를 한 번만 확정합니다.
|
|
389
|
+
await this.autoloadTypes();
|
|
390
|
+
await this.autoloadModels();
|
|
391
|
+
await this.autoloadApis();
|
|
392
|
+
await this.dependencies.actionGenerateHttpValidators();
|
|
332
393
|
}
|
|
333
394
|
|
|
334
395
|
if (nothingMatches()) {
|
|
@@ -343,22 +404,26 @@ export class Syncer {
|
|
|
343
404
|
};
|
|
344
405
|
}
|
|
345
406
|
|
|
346
|
-
calculateDiffGroups(diffFiles: AbsolutePath[])
|
|
407
|
+
calculateDiffGroups(diffFiles: AbsolutePath[]) {
|
|
347
408
|
const patternGroup = getChecksumPatternGroup();
|
|
348
|
-
const fileTypes =
|
|
349
|
-
|
|
350
|
-
|
|
351
|
-
|
|
409
|
+
const fileTypes =
|
|
410
|
+
/* SAFETY: TypeScript AST 파싱과 동기화 입력 계약이 이 값의 타입을 보장한다. */ Object.keys(
|
|
411
|
+
patternGroup,
|
|
412
|
+
) as FileType[];
|
|
413
|
+
|
|
414
|
+
const diffGroups: DiffGroups = {};
|
|
415
|
+
for (const filePath of diffFiles) {
|
|
416
|
+
// 절대 경로를 appRoot 기준 상대 경로로 바꿔 체크섬 패턴과 비교한다.
|
|
352
417
|
const relativePath = path.relative(Sonamu.appRootPath, filePath);
|
|
353
|
-
|
|
354
|
-
|
|
355
|
-
|
|
356
|
-
|
|
357
|
-
|
|
358
|
-
|
|
359
|
-
|
|
360
|
-
|
|
361
|
-
|
|
418
|
+
const fileType = fileTypes.find((candidate) =>
|
|
419
|
+
minimatch(relativePath, patternGroup[candidate]),
|
|
420
|
+
);
|
|
421
|
+
const groupKey: DiffGroupKey = relativePath.startsWith("..")
|
|
422
|
+
? "unknown"
|
|
423
|
+
: (fileType ?? "unknown");
|
|
424
|
+
(diffGroups[groupKey] ??= []).push(filePath);
|
|
425
|
+
}
|
|
426
|
+
return diffGroups;
|
|
362
427
|
}
|
|
363
428
|
|
|
364
429
|
private changeMatcher(diffTypes: FileType[], diffGroups: DiffGroups) {
|
|
@@ -404,12 +469,13 @@ export class Syncer {
|
|
|
404
469
|
const entity = EntityManager.get(entityId);
|
|
405
470
|
|
|
406
471
|
// 프로젝트에 생성되어야 하는 .ts 파일의 경로입니다.
|
|
407
|
-
const typeFilePath =
|
|
408
|
-
|
|
409
|
-
|
|
410
|
-
|
|
472
|
+
const typeFilePath =
|
|
473
|
+
/* SAFETY: TypeScript AST 파싱과 동기화 입력 계약이 이 값의 타입을 보장한다. */ path.join(
|
|
474
|
+
Sonamu.apiRootPath,
|
|
475
|
+
`src/application/${entity.names.fs}/${entity.names.fs}.types.ts`,
|
|
476
|
+
) as AbsolutePath;
|
|
411
477
|
|
|
412
|
-
if (entity.parentId === undefined && !(await
|
|
478
|
+
if (entity.parentId === undefined && !(await syncerFileExists(typeFilePath))) {
|
|
413
479
|
// *.types.ts가 만들어집니다.
|
|
414
480
|
const types = await SyncerActions.actionGenerateInitialTypes(entityId);
|
|
415
481
|
|
|
@@ -464,11 +530,15 @@ export class Syncer {
|
|
|
464
530
|
await SyncerActions.actionSyncFilesToTargets(tsPaths);
|
|
465
531
|
}
|
|
466
532
|
|
|
467
|
-
async handleConfigChanges(
|
|
533
|
+
async handleConfigChanges(): Promise<void> {
|
|
534
|
+
if (process.env.HOT === "yes") {
|
|
535
|
+
const { loadConfig } = await import("../api/config");
|
|
536
|
+
Sonamu.config = await loadConfig(Sonamu.apiRootPath);
|
|
537
|
+
}
|
|
468
538
|
await SyncerActions.actionSyncConfig();
|
|
469
539
|
}
|
|
470
540
|
|
|
471
|
-
async handleSonamuDictionaryRelatedChanges(
|
|
541
|
+
async handleSonamuDictionaryRelatedChanges(): Promise<void> {
|
|
472
542
|
await SyncerActions.actionSyncSonamuDictionary();
|
|
473
543
|
}
|
|
474
544
|
|
|
@@ -508,7 +578,7 @@ export class Syncer {
|
|
|
508
578
|
return {
|
|
509
579
|
subPath,
|
|
510
580
|
fullPath,
|
|
511
|
-
isExists: await
|
|
581
|
+
isExists: await syncerFileExists(fullPath),
|
|
512
582
|
};
|
|
513
583
|
}
|
|
514
584
|
|
|
@@ -535,7 +605,7 @@ export class Syncer {
|
|
|
535
605
|
if (key.startsWith("view_enums")) {
|
|
536
606
|
await mapAsync(enumsKeys, async (componentId) => {
|
|
537
607
|
const { target, path: p } = tpl.getTargetAndPath(names, componentId);
|
|
538
|
-
result[`${key}__${componentId}`] = await
|
|
608
|
+
result[`${key}__${componentId}`] = await syncerFileExists(
|
|
539
609
|
path.join(Sonamu.appRootPath, target, p),
|
|
540
610
|
);
|
|
541
611
|
});
|
|
@@ -546,17 +616,20 @@ export class Syncer {
|
|
|
546
616
|
const { targets } = Sonamu.config.sync;
|
|
547
617
|
if (target.includes(":target")) {
|
|
548
618
|
await mapAsync(targets, async (t) => {
|
|
549
|
-
result[`${key}__${t}`] = await
|
|
619
|
+
result[`${key}__${t}`] = await syncerFileExists(
|
|
550
620
|
path.join(Sonamu.appRootPath, target.replace(":target", t), p),
|
|
551
621
|
);
|
|
552
622
|
});
|
|
553
623
|
} else {
|
|
554
|
-
result[key] = await
|
|
624
|
+
result[key] = await syncerFileExists(path.join(Sonamu.appRootPath, target, p));
|
|
555
625
|
}
|
|
556
626
|
|
|
557
627
|
return result;
|
|
558
628
|
},
|
|
559
|
-
{} as Record
|
|
629
|
+
/* SAFETY: TypeScript AST 파싱과 동기화 입력 계약이 이 값의 타입을 보장한다. */ {} as Record<
|
|
630
|
+
`${TemplateKey}${string}`,
|
|
631
|
+
boolean
|
|
632
|
+
>,
|
|
560
633
|
);
|
|
561
634
|
}
|
|
562
635
|
|
|
@@ -599,6 +672,6 @@ export class Syncer {
|
|
|
599
672
|
* 하위호환용 프록시 메소드입니다.
|
|
600
673
|
*/
|
|
601
674
|
async renewChecksums(): Promise<void> {
|
|
602
|
-
return await renewChecksums();
|
|
675
|
+
return await this.dependencies.renewChecksums();
|
|
603
676
|
}
|
|
604
677
|
}
|
package/src/syncer/watcher.ts
CHANGED
|
@@ -3,7 +3,7 @@ import { type Stats } from "node:fs";
|
|
|
3
3
|
import path from "path";
|
|
4
4
|
|
|
5
5
|
import chalk from "chalk";
|
|
6
|
-
import
|
|
6
|
+
import { type FSWatcher, watch } from "chokidar";
|
|
7
7
|
import { minimatch } from "minimatch";
|
|
8
8
|
|
|
9
9
|
import { Sonamu } from "../api";
|
|
@@ -22,7 +22,7 @@ export async function setupWatcher(
|
|
|
22
22
|
// api 본인뿐 아니라 sync target들의 src도 봅니다.
|
|
23
23
|
// target 산출물(sonamu.generated, services.generated, i18n copy 등)이 외부에서
|
|
24
24
|
// 변경되는 경우를 drift로 잡아 워닝을 띄우기 위함입니다.
|
|
25
|
-
const watcher =
|
|
25
|
+
const watcher = watch(apiAndTargetsSrcPaths(), {
|
|
26
26
|
ignored: ignoreIfExtensionIsNotOneOf(".ts", ".json", ".http"),
|
|
27
27
|
persistent: true,
|
|
28
28
|
ignoreInitial: true,
|
|
@@ -49,7 +49,8 @@ export async function setupWatcher(
|
|
|
49
49
|
});
|
|
50
50
|
|
|
51
51
|
watcher.on("all", (event: string, filePath: string) => {
|
|
52
|
-
const absolutePath =
|
|
52
|
+
const absolutePath =
|
|
53
|
+
/* SAFETY: TypeScript AST 파싱과 동기화 입력 계약이 이 값의 타입을 보장한다. */ filePath as AbsolutePath;
|
|
53
54
|
assert(
|
|
54
55
|
absolutePath.startsWith(Sonamu.appRootPath),
|
|
55
56
|
"File path is not within the app root path",
|
|
@@ -92,7 +93,10 @@ function apiAndTargetsSrcPaths() {
|
|
|
92
93
|
* 따라서 "이 확장자만 허용"을 표현하려면 *다른 확장자에 대해 true*를 반환해야 합니다.
|
|
93
94
|
*/
|
|
94
95
|
function ignoreIfExtensionIsNotOneOf(...allowedExtensions: `.${string}`[]) {
|
|
95
|
-
const isAllowed = (ext: string) =>
|
|
96
|
+
const isAllowed = (ext: string) =>
|
|
97
|
+
/* SAFETY: TypeScript AST 파싱과 동기화 입력 계약이 이 값의 타입을 보장한다. */ (
|
|
98
|
+
allowedExtensions as string[]
|
|
99
|
+
).includes(ext);
|
|
96
100
|
|
|
97
101
|
return (p: string, stats?: Stats) => !!stats?.isFile() && !isAllowed(path.extname(p));
|
|
98
102
|
}
|