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,137 @@
|
|
|
1
|
+
import { access, mkdir, mkdtemp, rm, writeFile } from "node:fs/promises";
|
|
2
|
+
import os from "node:os";
|
|
3
|
+
import path from "node:path";
|
|
4
|
+
|
|
5
|
+
import { afterEach, describe, expect, it, vi } from "vitest";
|
|
6
|
+
|
|
7
|
+
import { type SonamuConfig } from "../../api/config";
|
|
8
|
+
import { Sonamu } from "../../api/sonamu";
|
|
9
|
+
import { type AbsolutePath } from "../../utils/path-utils";
|
|
10
|
+
import { Syncer, type SyncerDependencies } from "../syncer";
|
|
11
|
+
import { actionGenerateHttpValidators } from "../syncer-actions";
|
|
12
|
+
|
|
13
|
+
function toAbsolutePath(filePath: string): AbsolutePath {
|
|
14
|
+
if (!path.isAbsolute(filePath)) {
|
|
15
|
+
throw new Error(`절대 경로가 필요합니다: ${filePath}`);
|
|
16
|
+
}
|
|
17
|
+
// SAFETY: path.isAbsolute 검사로 AbsolutePath 계약을 확인했다.
|
|
18
|
+
return filePath as AbsolutePath;
|
|
19
|
+
}
|
|
20
|
+
|
|
21
|
+
function createDependencies() {
|
|
22
|
+
return {
|
|
23
|
+
actionCopySharedToTargetsIfNotExists: vi
|
|
24
|
+
.fn<SyncerDependencies["actionCopySharedToTargetsIfNotExists"]>()
|
|
25
|
+
.mockResolvedValue(undefined),
|
|
26
|
+
actionGenerateHttpValidators: vi.fn<SyncerDependencies["actionGenerateHttpValidators"]>(),
|
|
27
|
+
actionGenerateSsrEntryServerIfNotExists: vi
|
|
28
|
+
.fn<SyncerDependencies["actionGenerateSsrEntryServerIfNotExists"]>()
|
|
29
|
+
.mockResolvedValue([]),
|
|
30
|
+
findChangedFilesUsingChecksums: vi.fn<SyncerDependencies["findChangedFilesUsingChecksums"]>(),
|
|
31
|
+
renewChecksums: vi.fn<SyncerDependencies["renewChecksums"]>().mockResolvedValue(undefined),
|
|
32
|
+
} satisfies SyncerDependencies;
|
|
33
|
+
}
|
|
34
|
+
|
|
35
|
+
const testConfig = {
|
|
36
|
+
api: { dir: "api", route: { prefix: "/api" } },
|
|
37
|
+
i18n: { defaultLocale: "ko", supportedLocales: ["ko"] },
|
|
38
|
+
sync: { targets: [] },
|
|
39
|
+
database: {},
|
|
40
|
+
server: {
|
|
41
|
+
apiConfig: {
|
|
42
|
+
contextProvider: (defaultContext) => defaultContext,
|
|
43
|
+
guardHandler: () => undefined,
|
|
44
|
+
},
|
|
45
|
+
},
|
|
46
|
+
} satisfies SonamuConfig;
|
|
47
|
+
|
|
48
|
+
describe("HTTP validator registry sync 정리", () => {
|
|
49
|
+
const tempRoots: string[] = [];
|
|
50
|
+
|
|
51
|
+
afterEach(async () => {
|
|
52
|
+
vi.restoreAllMocks();
|
|
53
|
+
await Promise.all(
|
|
54
|
+
tempRoots.splice(0).map((rootPath) => rm(rootPath, { recursive: true, force: true })),
|
|
55
|
+
);
|
|
56
|
+
});
|
|
57
|
+
|
|
58
|
+
it.each([
|
|
59
|
+
{ label: "opt-out", value: false as const },
|
|
60
|
+
{ label: "JIT", value: { api: "jit" as const } },
|
|
61
|
+
])("$label 정책은 남아 있는 generated registry를 제거한다", async ({ value }) => {
|
|
62
|
+
const apiRootPath = await mkdtemp(path.join(os.tmpdir(), "sonamu-registry-sync-test-"));
|
|
63
|
+
tempRoots.push(apiRootPath);
|
|
64
|
+
const registryPath = path.join(apiRootPath, "src/application/sonamu.validators.generated.ts");
|
|
65
|
+
await mkdir(path.dirname(registryPath), { recursive: true });
|
|
66
|
+
await writeFile(registryPath, "export const validators = new Map();\n");
|
|
67
|
+
Sonamu.apiRootPath = toAbsolutePath(apiRootPath);
|
|
68
|
+
Sonamu.config = {
|
|
69
|
+
...testConfig,
|
|
70
|
+
api: { ...testConfig.api, dir: "." },
|
|
71
|
+
validation: { zodCompiler: value },
|
|
72
|
+
};
|
|
73
|
+
|
|
74
|
+
await actionGenerateHttpValidators();
|
|
75
|
+
|
|
76
|
+
await expect(access(registryPath)).rejects.toMatchObject({ code: "ENOENT" });
|
|
77
|
+
});
|
|
78
|
+
|
|
79
|
+
it("registry-only drift를 경고로 넘기지 않고 즉시 재생성한다", async () => {
|
|
80
|
+
const appRootPath = await mkdtemp(path.join(os.tmpdir(), "sonamu-registry-drift-test-"));
|
|
81
|
+
tempRoots.push(appRootPath);
|
|
82
|
+
const apiRootPath = path.join(appRootPath, "api");
|
|
83
|
+
const registryPath = toAbsolutePath(
|
|
84
|
+
path.join(apiRootPath, "src/application/sonamu.validators.generated.ts"),
|
|
85
|
+
);
|
|
86
|
+
await mkdir(path.dirname(registryPath), { recursive: true });
|
|
87
|
+
await writeFile(registryPath, "// drifted registry\n");
|
|
88
|
+
Sonamu.apiRootPath = toAbsolutePath(apiRootPath);
|
|
89
|
+
Sonamu.config = {
|
|
90
|
+
...testConfig,
|
|
91
|
+
validation: { zodCompiler: { api: "aot" } },
|
|
92
|
+
};
|
|
93
|
+
const dependencies = createDependencies();
|
|
94
|
+
dependencies.actionGenerateHttpValidators.mockResolvedValue(registryPath);
|
|
95
|
+
dependencies.findChangedFilesUsingChecksums.mockResolvedValue([registryPath]);
|
|
96
|
+
vi.spyOn(console, "warn").mockImplementation(() => {});
|
|
97
|
+
|
|
98
|
+
await new Syncer(dependencies).sync();
|
|
99
|
+
|
|
100
|
+
expect(dependencies.actionGenerateHttpValidators).toHaveBeenCalledTimes(1);
|
|
101
|
+
expect(dependencies.renewChecksums).toHaveBeenCalledTimes(1);
|
|
102
|
+
});
|
|
103
|
+
|
|
104
|
+
it("삭제된 registry가 checksum 변경 목록에서 빠져도 다른 tracked 변경 처리 중 복구한다", async () => {
|
|
105
|
+
const appRootPath = await mkdtemp(path.join(os.tmpdir(), "sonamu-missing-registry-test-"));
|
|
106
|
+
tempRoots.push(appRootPath);
|
|
107
|
+
const apiRootPath = path.join(appRootPath, "api");
|
|
108
|
+
const registryPath = toAbsolutePath(
|
|
109
|
+
path.join(apiRootPath, "src/application/sonamu.validators.generated.ts"),
|
|
110
|
+
);
|
|
111
|
+
const unrelatedPath = toAbsolutePath(
|
|
112
|
+
path.join(apiRootPath, "src/application/queries.generated.ts"),
|
|
113
|
+
);
|
|
114
|
+
await mkdir(path.dirname(unrelatedPath), { recursive: true });
|
|
115
|
+
await writeFile(unrelatedPath, "// unrelated tracked change\n");
|
|
116
|
+
Sonamu.apiRootPath = toAbsolutePath(apiRootPath);
|
|
117
|
+
Sonamu.config = {
|
|
118
|
+
...testConfig,
|
|
119
|
+
validation: { zodCompiler: { api: "aot" } },
|
|
120
|
+
};
|
|
121
|
+
const order: string[] = [];
|
|
122
|
+
const dependencies = createDependencies();
|
|
123
|
+
dependencies.actionGenerateHttpValidators.mockImplementation(async () => {
|
|
124
|
+
order.push("registry");
|
|
125
|
+
return registryPath;
|
|
126
|
+
});
|
|
127
|
+
dependencies.findChangedFilesUsingChecksums.mockResolvedValue([unrelatedPath]);
|
|
128
|
+
dependencies.renewChecksums.mockImplementation(async () => {
|
|
129
|
+
order.push("checksum");
|
|
130
|
+
});
|
|
131
|
+
vi.spyOn(console, "warn").mockImplementation(() => {});
|
|
132
|
+
|
|
133
|
+
await new Syncer(dependencies).sync();
|
|
134
|
+
|
|
135
|
+
expect(order).toEqual(["registry", "checksum"]);
|
|
136
|
+
});
|
|
137
|
+
});
|
package/src/syncer/api-parser.ts
CHANGED
|
@@ -77,7 +77,7 @@ export async function readApisFromFile(filePath: AbsolutePath): Promise<Extended
|
|
|
77
77
|
return resolveParamDec(
|
|
78
78
|
{
|
|
79
79
|
name: paramDec.name,
|
|
80
|
-
type: paramDec.type as ts.TypeNode,
|
|
80
|
+
type: /* SAFETY: TypeScript AST 파싱과 동기화 입력 계약이 이 값의 타입을 보장한다. */ paramDec.type as ts.TypeNode,
|
|
81
81
|
optional: paramDec.questionToken !== undefined || paramDec.initializer !== undefined,
|
|
82
82
|
defaultDef,
|
|
83
83
|
},
|
|
@@ -253,7 +253,10 @@ function resolveTypeNode(typeNode: ts.TypeNode): ApiParamType {
|
|
|
253
253
|
case ts.SyntaxKind.VoidKeyword:
|
|
254
254
|
return "void";
|
|
255
255
|
case ts.SyntaxKind.LiteralType: {
|
|
256
|
-
const literal =
|
|
256
|
+
const literal =
|
|
257
|
+
/* SAFETY: TypeScript AST 파싱과 동기화 입력 계약이 이 값의 타입을 보장한다. */ (
|
|
258
|
+
typeNode as ts.LiteralTypeNode
|
|
259
|
+
).literal;
|
|
257
260
|
if (ts.isStringLiteral(literal)) {
|
|
258
261
|
return {
|
|
259
262
|
t: "string-literal",
|
|
@@ -278,35 +281,46 @@ function resolveTypeNode(typeNode: ts.TypeNode): ApiParamType {
|
|
|
278
281
|
}
|
|
279
282
|
}
|
|
280
283
|
case ts.SyntaxKind.ArrayType: {
|
|
281
|
-
const arrNode =
|
|
284
|
+
const arrNode =
|
|
285
|
+
/* SAFETY: TypeScript AST 파싱과 동기화 입력 계약이 이 값의 타입을 보장한다. */ typeNode as ts.ArrayTypeNode;
|
|
282
286
|
return {
|
|
283
287
|
t: "array",
|
|
284
288
|
elementsType: resolveTypeNode(arrNode.elementType),
|
|
285
289
|
};
|
|
286
290
|
}
|
|
287
291
|
case ts.SyntaxKind.TypeLiteral: {
|
|
288
|
-
const literalNode =
|
|
292
|
+
const literalNode =
|
|
293
|
+
/* SAFETY: TypeScript AST 파싱과 동기화 입력 계약이 이 값의 타입을 보장한다. */ typeNode as ts.TypeLiteralNode;
|
|
289
294
|
return {
|
|
290
295
|
t: "object",
|
|
291
296
|
props: literalNode.members.map((member) => {
|
|
292
297
|
if (ts.isIndexSignatureDeclaration(member)) {
|
|
293
298
|
assert(member.parameters[0]);
|
|
294
299
|
const res = resolveParamDec({
|
|
295
|
-
name:
|
|
296
|
-
|
|
300
|
+
name: /* SAFETY: TypeScript AST 파싱과 동기화 입력 계약이 이 값의 타입을 보장한다. */ member
|
|
301
|
+
.parameters[0].name as ts.Identifier,
|
|
302
|
+
type: /* SAFETY: TypeScript AST 파싱과 동기화 입력 계약이 이 값의 타입을 보장한다. */ member
|
|
303
|
+
.parameters[0].type as ts.TypeNode,
|
|
297
304
|
});
|
|
298
305
|
|
|
299
306
|
return resolveParamDec({
|
|
300
|
-
name: {
|
|
307
|
+
name: /* SAFETY: TypeScript AST 파싱과 동기화 입력 계약이 이 값의 타입을 보장한다. */ {
|
|
301
308
|
escapedText: `[${res.name}${res.optional ? "?" : ""}: ${res.type}]`,
|
|
302
309
|
} as ts.Identifier,
|
|
303
310
|
type: member.type,
|
|
304
311
|
});
|
|
305
312
|
} else {
|
|
306
313
|
return resolveParamDec({
|
|
307
|
-
name:
|
|
308
|
-
|
|
309
|
-
|
|
314
|
+
name: /* SAFETY: TypeScript AST 파싱과 동기화 입력 계약이 이 값의 타입을 보장한다. */ /* SAFETY: TypeScript AST 파싱과 동기화 입력 계약이 이 값의 타입을 보장한다. */ (
|
|
315
|
+
member as ts.PropertySignature
|
|
316
|
+
).name as ts.Identifier,
|
|
317
|
+
type: /* SAFETY: TypeScript AST 파싱과 동기화 입력 계약이 이 값의 타입을 보장한다. */ /* SAFETY: TypeScript AST 파싱과 동기화 입력 계약이 이 값의 타입을 보장한다. */ (
|
|
318
|
+
member as ts.PropertySignature
|
|
319
|
+
).type as ts.TypeNode,
|
|
320
|
+
optional:
|
|
321
|
+
/* SAFETY: TypeScript AST 파싱과 동기화 입력 계약이 이 값의 타입을 보장한다. */ (
|
|
322
|
+
member as ts.PropertySignature
|
|
323
|
+
).questionToken !== undefined,
|
|
310
324
|
});
|
|
311
325
|
}
|
|
312
326
|
}),
|
|
@@ -315,26 +329,40 @@ function resolveTypeNode(typeNode: ts.TypeNode): ApiParamType {
|
|
|
315
329
|
case ts.SyntaxKind.TypeReference:
|
|
316
330
|
return {
|
|
317
331
|
t: "ref",
|
|
318
|
-
id:
|
|
319
|
-
|
|
320
|
-
|
|
321
|
-
|
|
332
|
+
id: /* SAFETY: TypeScript AST 파싱과 동기화 입력 계약이 이 값의 타입을 보장한다. */ /* SAFETY: TypeScript AST 파싱과 동기화 입력 계약이 이 값의 타입을 보장한다. */ (
|
|
333
|
+
(typeNode as ts.TypeReferenceNode).typeName as ts.Identifier
|
|
334
|
+
).escapedText.toString(),
|
|
335
|
+
args: /* SAFETY: TypeScript AST 파싱과 동기화 입력 계약이 이 값의 타입을 보장한다. */ (
|
|
336
|
+
typeNode as ts.TypeReferenceNode
|
|
337
|
+
).typeArguments?.map((typeArg) => resolveTypeNode(typeArg)),
|
|
322
338
|
};
|
|
323
339
|
case ts.SyntaxKind.UnionType:
|
|
324
340
|
return {
|
|
325
341
|
t: "union",
|
|
326
|
-
types:
|
|
342
|
+
types: /* SAFETY: TypeScript AST 파싱과 동기화 입력 계약이 이 값의 타입을 보장한다. */ (
|
|
343
|
+
typeNode as ts.UnionTypeNode
|
|
344
|
+
).types.map((type) => resolveTypeNode(type)),
|
|
327
345
|
};
|
|
328
346
|
case ts.SyntaxKind.IntersectionType:
|
|
329
347
|
return {
|
|
330
348
|
t: "intersection",
|
|
331
|
-
types:
|
|
349
|
+
types: /* SAFETY: TypeScript AST 파싱과 동기화 입력 계약이 이 값의 타입을 보장한다. */ (
|
|
350
|
+
typeNode as ts.IntersectionTypeNode
|
|
351
|
+
).types.map((type) => resolveTypeNode(type)),
|
|
332
352
|
};
|
|
333
353
|
case ts.SyntaxKind.IndexedAccessType:
|
|
334
354
|
return {
|
|
335
355
|
t: "indexed-access",
|
|
336
|
-
object: resolveTypeNode(
|
|
337
|
-
|
|
356
|
+
object: resolveTypeNode(
|
|
357
|
+
/* SAFETY: TypeScript AST 파싱과 동기화 입력 계약이 이 값의 타입을 보장한다. */ (
|
|
358
|
+
typeNode as ts.IndexedAccessTypeNode
|
|
359
|
+
).objectType,
|
|
360
|
+
),
|
|
361
|
+
index: resolveTypeNode(
|
|
362
|
+
/* SAFETY: TypeScript AST 파싱과 동기화 입력 계약이 이 값의 타입을 보장한다. */ (
|
|
363
|
+
typeNode as ts.IndexedAccessTypeNode
|
|
364
|
+
).indexType,
|
|
365
|
+
),
|
|
338
366
|
};
|
|
339
367
|
case ts.SyntaxKind.TupleType:
|
|
340
368
|
if (ts.isTupleTypeNode(typeNode)) {
|
|
@@ -347,18 +375,29 @@ function resolveTypeNode(typeNode: ts.TypeNode): ApiParamType {
|
|
|
347
375
|
case ts.SyntaxKind.ParenthesizedType:
|
|
348
376
|
// 괄호로 묶인 타입 (예: (A & B)[] 에서 (A & B))
|
|
349
377
|
// 내부 타입을 재귀적으로 resolve
|
|
350
|
-
return resolveTypeNode(
|
|
378
|
+
return resolveTypeNode(
|
|
379
|
+
/* SAFETY: TypeScript AST 파싱과 동기화 입력 계약이 이 값의 타입을 보장한다. */ (
|
|
380
|
+
typeNode as ts.ParenthesizedTypeNode
|
|
381
|
+
).type,
|
|
382
|
+
);
|
|
351
383
|
|
|
352
384
|
case ts.SyntaxKind.FunctionType:
|
|
353
385
|
return {
|
|
354
386
|
t: "function",
|
|
355
|
-
parameters:
|
|
356
|
-
|
|
357
|
-
|
|
358
|
-
|
|
359
|
-
|
|
360
|
-
|
|
361
|
-
|
|
387
|
+
parameters:
|
|
388
|
+
/* SAFETY: TypeScript AST 파싱과 동기화 입력 계약이 이 값의 타입을 보장한다. */ (
|
|
389
|
+
typeNode as ts.FunctionTypeNode
|
|
390
|
+
).parameters.map((param) => ({
|
|
391
|
+
name: param.name.getText(),
|
|
392
|
+
type: param.type ? resolveTypeNode(param.type) : "unknown",
|
|
393
|
+
optional: param.questionToken !== undefined,
|
|
394
|
+
defaultDef: undefined,
|
|
395
|
+
})),
|
|
396
|
+
returnType: resolveTypeNode(
|
|
397
|
+
/* SAFETY: TypeScript AST 파싱과 동기화 입력 계약이 이 값의 타입을 보장한다. */ (
|
|
398
|
+
typeNode as ts.FunctionTypeNode
|
|
399
|
+
).type,
|
|
400
|
+
),
|
|
362
401
|
};
|
|
363
402
|
case undefined:
|
|
364
403
|
throw new Error(`typeNode undefined`);
|
|
@@ -377,7 +416,8 @@ function resolveParamDec(
|
|
|
377
416
|
},
|
|
378
417
|
index: number = 0,
|
|
379
418
|
): ApiParam {
|
|
380
|
-
const name =
|
|
419
|
+
const name =
|
|
420
|
+
/* SAFETY: TypeScript AST 파싱과 동기화 입력 계약이 이 값의 타입을 보장한다. */ paramDec.name as ts.Identifier;
|
|
381
421
|
const type = resolveTypeNode(paramDec.type);
|
|
382
422
|
|
|
383
423
|
if (name === undefined) {
|
package/src/syncer/checksum.ts
CHANGED
|
@@ -1,6 +1,5 @@
|
|
|
1
1
|
import crypto from "crypto";
|
|
2
2
|
import { createReadStream, type PathLike } from "fs";
|
|
3
|
-
import { readFile, writeFile } from "fs/promises";
|
|
4
3
|
import path from "path";
|
|
5
4
|
|
|
6
5
|
import equal from "fast-deep-equal";
|
|
@@ -8,10 +7,10 @@ import { isEqual } from "radashi";
|
|
|
8
7
|
|
|
9
8
|
import { Sonamu } from "../api/sonamu";
|
|
10
9
|
import { globAsync } from "../utils/async-utils";
|
|
11
|
-
import { exists } from "../utils/fs-utils";
|
|
12
10
|
import { type AbsolutePath, type AppRelativePath } from "../utils/path-utils";
|
|
13
11
|
import { differenceWith } from "../utils/utils";
|
|
14
12
|
import { getChecksumPatternGroupInAbsolutePath, GLOB_EXCLUDE } from "./file-patterns";
|
|
13
|
+
import { syncerFileExists, syncerFilesystem } from "./filesystem-dependencies";
|
|
15
14
|
|
|
16
15
|
type PathAndChecksum = {
|
|
17
16
|
path: AbsolutePath;
|
|
@@ -61,7 +60,10 @@ async function getCurrentChecksums(): Promise<PathAndChecksum[]> {
|
|
|
61
60
|
|
|
62
61
|
// 동일 파일이 여러 패턴에 매치될 수 있으므로(예: sd.generated.ts는 generated와 sdGenerated에 모두 매치)
|
|
63
62
|
// 중복 제거 후 안정 정렬.
|
|
64
|
-
const filePaths =
|
|
63
|
+
const filePaths =
|
|
64
|
+
/* SAFETY: TypeScript AST 파싱과 동기화 입력 계약이 이 값의 타입을 보장한다. */ Array.from(
|
|
65
|
+
new Set(allPaths),
|
|
66
|
+
).toSorted() as AbsolutePath[];
|
|
65
67
|
|
|
66
68
|
return await Promise.all(
|
|
67
69
|
filePaths.map(async (filePath) => {
|
|
@@ -75,17 +77,18 @@ async function getCurrentChecksums(): Promise<PathAndChecksum[]> {
|
|
|
75
77
|
|
|
76
78
|
async function getPreviousChecksums(): Promise<PathAndChecksum[]> {
|
|
77
79
|
const checksumFilePath = getChecksumFilePath();
|
|
78
|
-
if (!(await
|
|
80
|
+
if (!(await syncerFileExists(checksumFilePath))) {
|
|
79
81
|
return [];
|
|
80
82
|
}
|
|
81
83
|
|
|
82
84
|
try {
|
|
83
|
-
const previousChecksums =
|
|
84
|
-
|
|
85
|
+
const previousChecksums =
|
|
86
|
+
/* SAFETY: TypeScript AST 파싱과 동기화 입력 계약이 이 값의 타입을 보장한다. */ JSON.parse(
|
|
87
|
+
await syncerFilesystem.readFile(checksumFilePath, "utf-8"),
|
|
88
|
+
).map((r: { path: AppRelativePath; checksum: string }) => ({
|
|
85
89
|
path: path.join(Sonamu.appRootPath, r.path), // 체크섬 파일에서 읽을 때: appRoot 상대 경로 → 절대 경로
|
|
86
90
|
checksum: r.checksum,
|
|
87
|
-
})
|
|
88
|
-
) as PathAndChecksum[];
|
|
91
|
+
})) as PathAndChecksum[];
|
|
89
92
|
return previousChecksums;
|
|
90
93
|
} catch (e) {
|
|
91
94
|
// 체크섬 파일이 손상된 경우 빈 배열 반환 (전체 재동기화 유도)
|
|
@@ -98,7 +101,10 @@ async function getPreviousChecksums(): Promise<PathAndChecksum[]> {
|
|
|
98
101
|
}
|
|
99
102
|
|
|
100
103
|
function getChecksumFilePath(): AbsolutePath {
|
|
101
|
-
return path.join(
|
|
104
|
+
return /* SAFETY: TypeScript AST 파싱과 동기화 입력 계약이 이 값의 타입을 보장한다. */ path.join(
|
|
105
|
+
Sonamu.apiRootPath,
|
|
106
|
+
"sonamu.lock",
|
|
107
|
+
) as AbsolutePath;
|
|
102
108
|
}
|
|
103
109
|
|
|
104
110
|
async function saveChecksums(checksums: PathAndChecksum[]): Promise<void> {
|
|
@@ -109,8 +115,8 @@ async function saveChecksums(checksums: PathAndChecksum[]): Promise<void> {
|
|
|
109
115
|
path: path.relative(Sonamu.appRootPath, r.path), // 체크섬 파일에 저장할 때: 절대 경로 → appRoot 상대 경로
|
|
110
116
|
checksum: r.checksum,
|
|
111
117
|
}))
|
|
112
|
-
.
|
|
113
|
-
await writeFile(checksumFilePath, JSON.stringify(serialized, null, 2), "utf-8");
|
|
118
|
+
.toSorted((a, b) => a.path.localeCompare(b.path));
|
|
119
|
+
await syncerFilesystem.writeFile(checksumFilePath, JSON.stringify(serialized, null, 2), "utf-8");
|
|
114
120
|
}
|
|
115
121
|
|
|
116
122
|
async function getChecksumOfFile(filePath: PathLike): Promise<string> {
|
|
@@ -1,4 +1,3 @@
|
|
|
1
|
-
import { mkdir, writeFile } from "fs/promises";
|
|
2
1
|
import path from "path";
|
|
3
2
|
|
|
4
3
|
import chalk from "chalk";
|
|
@@ -21,10 +20,10 @@ import {
|
|
|
21
20
|
import { everyAsync, filterAsync } from "../utils/async-utils";
|
|
22
21
|
import { isTest } from "../utils/controller";
|
|
23
22
|
import { formatCode } from "../utils/formatter";
|
|
24
|
-
import { exists } from "../utils/fs-utils";
|
|
25
23
|
import { wrapIf } from "../utils/lodash-able";
|
|
26
24
|
import { type AbsolutePath } from "../utils/path-utils";
|
|
27
25
|
import { trackWritten } from "./file-tracking";
|
|
26
|
+
import { syncerFileExists, syncerFilesystem } from "./filesystem-dependencies";
|
|
28
27
|
|
|
29
28
|
/**
|
|
30
29
|
* 템플릿을 렌더링하고 파일로 생성합니다.
|
|
@@ -51,8 +50,8 @@ export async function generateTemplate<T extends TemplateKey>(
|
|
|
51
50
|
// 템플릿 렌더
|
|
52
51
|
const pathAndCodes = (
|
|
53
52
|
await Promise.all(
|
|
54
|
-
keys.map(async (
|
|
55
|
-
return await renderTemplate(
|
|
53
|
+
keys.map(async (templateKey) => {
|
|
54
|
+
return await renderTemplate(templateKey, templateOptions);
|
|
56
55
|
}),
|
|
57
56
|
)
|
|
58
57
|
).flat();
|
|
@@ -65,7 +64,10 @@ export async function generateTemplate<T extends TemplateKey>(
|
|
|
65
64
|
const { targets } = Sonamu.config.sync;
|
|
66
65
|
const filePath = `${Sonamu.appRootPath}/${pathAndCode.path}`;
|
|
67
66
|
const dstFilePaths = targets.map((target) => filePath.replace("/:target/", `/${target}/`));
|
|
68
|
-
return await everyAsync(
|
|
67
|
+
return await everyAsync(
|
|
68
|
+
dstFilePaths,
|
|
69
|
+
async (dstPath) => !(await syncerFileExists(dstPath)),
|
|
70
|
+
);
|
|
69
71
|
});
|
|
70
72
|
}
|
|
71
73
|
})();
|
|
@@ -103,8 +105,8 @@ export async function renderTemplate<T extends keyof TemplateOptions>(
|
|
|
103
105
|
if (rendered.preTemplates) {
|
|
104
106
|
preTemplateResolved = (
|
|
105
107
|
await Promise.all(
|
|
106
|
-
rendered.preTemplates.map(({ key, options }) => {
|
|
107
|
-
return renderTemplate(
|
|
108
|
+
rendered.preTemplates.map(({ key: preTemplateKey, options: preTemplateOptions }) => {
|
|
109
|
+
return renderTemplate(preTemplateKey, preTemplateOptions);
|
|
108
110
|
}),
|
|
109
111
|
)
|
|
110
112
|
).flat();
|
|
@@ -122,7 +124,10 @@ async function resolveRenderedTemplate(
|
|
|
122
124
|
const { target, path: filePath, body, importKeys, customHeaders } = result;
|
|
123
125
|
|
|
124
126
|
// import 할 대상의 대상 path 추출
|
|
125
|
-
const builtInSchemaNames = Object.values(BUILT_IN_TYPES).map(
|
|
127
|
+
const builtInSchemaNames = Object.values(BUILT_IN_TYPES).map(
|
|
128
|
+
(info) =>
|
|
129
|
+
/* SAFETY: TypeScript AST 파싱과 동기화 입력 계약이 이 값의 타입을 보장한다. */ info.schemaName as string,
|
|
130
|
+
);
|
|
126
131
|
const importDefs = importKeys
|
|
127
132
|
// 내장 타입 스키마는 이미 sonamu에서 import되므로 제외
|
|
128
133
|
.filter((importKey) => !builtInSchemaNames.includes(importKey))
|
|
@@ -157,7 +162,7 @@ async function resolveRenderedTemplate(
|
|
|
157
162
|
}
|
|
158
163
|
return r;
|
|
159
164
|
},
|
|
160
|
-
[] as {
|
|
165
|
+
/* SAFETY: TypeScript AST 파싱과 동기화 입력 계약이 이 값의 타입을 보장한다. */ [] as {
|
|
161
166
|
keys: string[];
|
|
162
167
|
from: string;
|
|
163
168
|
}[],
|
|
@@ -178,12 +183,12 @@ async function resolveRenderedTemplate(
|
|
|
178
183
|
return [header, body].join("\n\n");
|
|
179
184
|
} else {
|
|
180
185
|
Naite.t("resolveRenderedTemplate:beforeFormat", { key, header, body });
|
|
181
|
-
const
|
|
186
|
+
const formattedCode = await formatCode(
|
|
182
187
|
[header, body].join("\n\n"),
|
|
183
188
|
`${Sonamu.appRootPath}/${filePath}`,
|
|
184
189
|
);
|
|
185
|
-
Naite.t(`resolveRenderedTemplate:formatted:${key}`,
|
|
186
|
-
return
|
|
190
|
+
Naite.t(`resolveRenderedTemplate:formatted:${key}`, formattedCode);
|
|
191
|
+
return formattedCode;
|
|
187
192
|
}
|
|
188
193
|
})();
|
|
189
194
|
|
|
@@ -196,18 +201,21 @@ async function resolveRenderedTemplate(
|
|
|
196
201
|
async function writeCodeToPathEachTarget(pathAndCode: PathAndCode): Promise<AbsolutePath[]> {
|
|
197
202
|
const { targets } = Sonamu.config.sync;
|
|
198
203
|
const { appRootPath } = Sonamu;
|
|
199
|
-
const filePath =
|
|
204
|
+
const filePath =
|
|
205
|
+
/* SAFETY: TypeScript AST 파싱과 동기화 입력 계약이 이 값의 타입을 보장한다. */ `${Sonamu.appRootPath}/${pathAndCode.path}` as AbsolutePath;
|
|
200
206
|
|
|
201
207
|
const dstFilePaths = unique(
|
|
202
|
-
|
|
208
|
+
/* SAFETY: TypeScript AST 파싱과 동기화 입력 계약이 이 값의 타입을 보장한다. */ targets.map(
|
|
209
|
+
(target) => filePath.replace("/:target/", `/${target}/`),
|
|
210
|
+
) as AbsolutePath[],
|
|
203
211
|
);
|
|
204
212
|
return await Promise.all(
|
|
205
213
|
dstFilePaths.map(async (dstFilePath) => {
|
|
206
214
|
const dir = path.dirname(dstFilePath);
|
|
207
|
-
if (!(await
|
|
208
|
-
await mkdir(dir, { recursive: true });
|
|
215
|
+
if (!(await syncerFileExists(dir))) {
|
|
216
|
+
await syncerFilesystem.mkdir(dir, { recursive: true });
|
|
209
217
|
}
|
|
210
|
-
await writeFile(dstFilePath, pathAndCode.code);
|
|
218
|
+
await syncerFilesystem.writeFile(dstFilePath, pathAndCode.code);
|
|
211
219
|
// 방금 우리가 쓴 path를 등록 → dev watcher의 후속 change 이벤트가
|
|
212
220
|
// 외부 변경으로 오인되지 않도록 거름 가드 자료 제공.
|
|
213
221
|
await trackWritten(dstFilePath);
|
|
@@ -1,5 +1,3 @@
|
|
|
1
|
-
import { rm } from "fs/promises";
|
|
2
|
-
|
|
3
1
|
import chalk from "chalk";
|
|
4
2
|
|
|
5
3
|
import { Sonamu } from "../api/sonamu";
|
|
@@ -8,8 +6,8 @@ import { EntityManager } from "../entity/entity-manager";
|
|
|
8
6
|
import { BadRequestException } from "../exceptions/so-exceptions";
|
|
9
7
|
import { type TemplateOptions } from "../types/types";
|
|
10
8
|
import { isTest } from "../utils/controller";
|
|
11
|
-
import { exists } from "../utils/fs-utils";
|
|
12
9
|
import { generateTemplate } from "./code-generator";
|
|
10
|
+
import { syncerFileExists, syncerFilesystem } from "./filesystem-dependencies";
|
|
13
11
|
|
|
14
12
|
/**
|
|
15
13
|
* 새로운 엔티티를 생성합니다.
|
|
@@ -53,9 +51,9 @@ export async function delEntity(entityId: string): Promise<{ delPaths: string[]
|
|
|
53
51
|
})(); // iife
|
|
54
52
|
|
|
55
53
|
for (const delPath of delPaths) {
|
|
56
|
-
if (await
|
|
54
|
+
if (await syncerFileExists(delPath)) {
|
|
57
55
|
!isTest() && console.log(chalk.red(`DELETE ${delPath}`));
|
|
58
|
-
await rm(delPath, { recursive: true, force: true });
|
|
56
|
+
await syncerFilesystem.rm(delPath, { recursive: true, force: true });
|
|
59
57
|
} else {
|
|
60
58
|
!isTest() && console.log(chalk.yellow(`NOT_EXISTS ${delPath}`));
|
|
61
59
|
}
|
|
@@ -0,0 +1,46 @@
|
|
|
1
|
+
import path, { dirname } from "node:path";
|
|
2
|
+
|
|
3
|
+
import { formatCode } from "../utils/formatter";
|
|
4
|
+
import { syncerFileExists, syncerFilesystem } from "./filesystem-dependencies";
|
|
5
|
+
|
|
6
|
+
/**
|
|
7
|
+
* Syncer 파일시스템 경계를 통해 파일을 복사하고 클라이언트용 import 경로를 변환합니다.
|
|
8
|
+
*/
|
|
9
|
+
export async function copyFileWithReplaceCoreToShared(
|
|
10
|
+
fromPath: string,
|
|
11
|
+
toPath: string,
|
|
12
|
+
syncHeader?: string,
|
|
13
|
+
): Promise<boolean> {
|
|
14
|
+
if (!(await syncerFileExists(fromPath))) {
|
|
15
|
+
return false;
|
|
16
|
+
}
|
|
17
|
+
|
|
18
|
+
const oldFileContent = await syncerFilesystem.readFile(fromPath, "utf-8");
|
|
19
|
+
let newFileContent = replaceCoreImport(oldFileContent, toPath);
|
|
20
|
+
|
|
21
|
+
if (syncHeader) {
|
|
22
|
+
const generatedBlockRegex = /\/\*\*\r?\n \* @generated\r?\n[\s\S]*?\*\/\r?\n(\r?\n)*/;
|
|
23
|
+
newFileContent = generatedBlockRegex.test(newFileContent)
|
|
24
|
+
? newFileContent.replace(generatedBlockRegex, `${syncHeader}\n\n`)
|
|
25
|
+
: `${syncHeader}\n\n${newFileContent}`;
|
|
26
|
+
}
|
|
27
|
+
|
|
28
|
+
if (toPath.endsWith(".ts") || toPath.endsWith(".tsx")) {
|
|
29
|
+
newFileContent = await formatCode(newFileContent, toPath);
|
|
30
|
+
}
|
|
31
|
+
|
|
32
|
+
await syncerFilesystem.writeFile(toPath, newFileContent);
|
|
33
|
+
return true;
|
|
34
|
+
}
|
|
35
|
+
|
|
36
|
+
function replaceCoreImport(source: string, toPath: string): string {
|
|
37
|
+
const srcMatch = toPath.match(/^(.+\/src)\//);
|
|
38
|
+
if (!srcMatch) {
|
|
39
|
+
return source;
|
|
40
|
+
}
|
|
41
|
+
|
|
42
|
+
const servicesDir = path.join(srcMatch[1], "services");
|
|
43
|
+
const relativePath = path.relative(dirname(toPath), servicesDir);
|
|
44
|
+
const sharedPath = relativePath === "" ? "./sonamu.shared" : `${relativePath}/sonamu.shared`;
|
|
45
|
+
return source.replace(/from "sonamu(\/dict)?"/g, `from "${sharedPath}"`);
|
|
46
|
+
}
|
|
@@ -56,6 +56,7 @@ export function getChecksumPatternGroup() {
|
|
|
56
56
|
// 여기에는 Sonamu의 모든 sync 산출물이 있는 것은 아닙니다.
|
|
57
57
|
// sonamu.shared.ts와 entry-server.generated.tsx와 같은
|
|
58
58
|
// sync 초반 1회성 부트스트랩 파일들은 관리 안 하기 때문에 여기에 리스팅도 안 합니다.
|
|
59
|
+
httpValidatorsGenerated: api("src/application/**/sonamu.validators.generated.ts"),
|
|
59
60
|
generated: api("src/application/**/*.generated.{ts,tsx,sso.ts}"),
|
|
60
61
|
generatedCopied: targets("src/services/**/sonamu.generated.{ts,tsx}"),
|
|
61
62
|
httpGenerated: api("src/application/**/*.generated.http"),
|
|
@@ -67,6 +68,11 @@ export function getChecksumPatternGroup() {
|
|
|
67
68
|
} satisfies Record<string, AppRelativePath>;
|
|
68
69
|
}
|
|
69
70
|
|
|
71
|
+
// Node 내장 fs.glob의 brace expansion은 단일 멤버 {x}를 풀지 않으므로, 멤버가 1개일 때는 alternation 없이 직접 결합합니다.
|
|
72
|
+
function braceJoin(dirs: readonly string[]) {
|
|
73
|
+
return dirs.length === 1 ? dirs[0] : `{${dirs.join(",")}}`;
|
|
74
|
+
}
|
|
75
|
+
|
|
70
76
|
/**
|
|
71
77
|
* 위치 카테고리별 글롭 빌더를 만들어 반환합니다.
|
|
72
78
|
* - api(rest): api 디렉토리에 한정
|
|
@@ -77,16 +83,13 @@ function globBuilders() {
|
|
|
77
83
|
const apiDir = Sonamu.config.api.dir;
|
|
78
84
|
const targetDirs = Sonamu.config.sync.targets;
|
|
79
85
|
|
|
80
|
-
// Node 내장 fs.glob의 brace expansion은 단일 멤버 {x}를 풀지 않으므로, 멤버가 1개일 때는 alternation 없이 직접 결합합니다.
|
|
81
|
-
const braceJoin = (dirs: readonly string[]) =>
|
|
82
|
-
dirs.length === 1 ? dirs[0] : `{${dirs.join(",")}}`;
|
|
83
|
-
|
|
84
86
|
return {
|
|
85
|
-
api: (pathFromApi: string) =>
|
|
87
|
+
api: (pathFromApi: string) =>
|
|
88
|
+
/* SAFETY: TypeScript AST 파싱과 동기화 입력 계약이 이 값의 타입을 보장한다. */ `${apiDir}/${pathFromApi}` as AppRelativePath,
|
|
86
89
|
targets: (pathFromTarget: string) =>
|
|
87
|
-
`${braceJoin(targetDirs)}/${pathFromTarget}` as AppRelativePath,
|
|
90
|
+
/* SAFETY: TypeScript AST 파싱과 동기화 입력 계약이 이 값의 타입을 보장한다. */ `${braceJoin(targetDirs)}/${pathFromTarget}` as AppRelativePath,
|
|
88
91
|
anywhere: (pathFromAnywhere: string) =>
|
|
89
|
-
`${braceJoin([apiDir, ...targetDirs])}/${pathFromAnywhere}` as AppRelativePath,
|
|
92
|
+
/* SAFETY: TypeScript AST 파싱과 동기화 입력 계약이 이 값의 타입을 보장한다. */ `${braceJoin([apiDir, ...targetDirs])}/${pathFromAnywhere}` as AppRelativePath,
|
|
90
93
|
};
|
|
91
94
|
}
|
|
92
95
|
|
|
@@ -110,7 +113,7 @@ export const GLOB_EXCLUDE = ["**/node_modules/**", "**/dist/**", "**/build/**",
|
|
|
110
113
|
*/
|
|
111
114
|
export function getChecksumPatternGroupInAbsolutePath(): GlobPattern<AbsolutePath> {
|
|
112
115
|
const group = getChecksumPatternGroup();
|
|
113
|
-
return Object.fromEntries(
|
|
116
|
+
return /* SAFETY: TypeScript AST 파싱과 동기화 입력 계약이 이 값의 타입을 보장한다. */ Object.fromEntries(
|
|
114
117
|
Object.entries(group).map(([key, value]) => [
|
|
115
118
|
key,
|
|
116
119
|
path.join(Sonamu.appRootPath, value), // appRoot 상대 경로 → 절대 경로
|
|
@@ -1,6 +1,5 @@
|
|
|
1
|
-
import { stat } from "fs/promises";
|
|
2
|
-
|
|
3
1
|
import { type AbsolutePath } from "../utils/path-utils";
|
|
2
|
+
import { syncerFilesystem } from "./filesystem-dependencies";
|
|
4
3
|
|
|
5
4
|
export const fileWrittenAt = new Map<AbsolutePath, number>();
|
|
6
5
|
|
|
@@ -9,7 +8,7 @@ export const fileWrittenAt = new Map<AbsolutePath, number>();
|
|
|
9
8
|
* 디스크에서 mtime을 직접 읽어 정확한 값으로 등록합니다.
|
|
10
9
|
*/
|
|
11
10
|
export async function trackWritten(filePath: AbsolutePath): Promise<void> {
|
|
12
|
-
const fileStat = await stat(filePath);
|
|
11
|
+
const fileStat = await syncerFilesystem.stat(filePath);
|
|
13
12
|
fileWrittenAt.set(filePath, fileStat.mtimeMs);
|
|
14
13
|
}
|
|
15
14
|
|
|
@@ -22,6 +21,6 @@ export async function isLastChangedByMe(filePath: AbsolutePath): Promise<boolean
|
|
|
22
21
|
if (registered === undefined) {
|
|
23
22
|
return false;
|
|
24
23
|
}
|
|
25
|
-
const fileStat = await stat(filePath);
|
|
24
|
+
const fileStat = await syncerFilesystem.stat(filePath);
|
|
26
25
|
return fileStat.mtimeMs <= registered;
|
|
27
26
|
}
|