sonamu 0.6.0 → 0.7.0
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/.swcrc.project-default +18 -0
- package/bin/cli.js +24 -0
- package/dist/ai/agents/agent.d.ts +11 -0
- package/dist/ai/agents/agent.d.ts.map +1 -0
- package/dist/ai/agents/agent.js +65 -0
- package/dist/ai/agents/index.d.ts +3 -0
- package/dist/ai/agents/index.d.ts.map +1 -0
- package/dist/ai/agents/index.js +4 -0
- package/dist/ai/agents/types.d.ts +43 -0
- package/dist/ai/agents/types.d.ts.map +1 -0
- package/dist/ai/agents/types.js +3 -0
- package/dist/ai/index.d.ts +2 -0
- package/dist/ai/index.d.ts.map +1 -0
- package/dist/ai/index.js +3 -0
- package/dist/ai/providers/rtzr/api.d.ts +22 -0
- package/dist/ai/providers/rtzr/api.d.ts.map +1 -0
- package/dist/ai/providers/rtzr/api.js +28 -0
- package/dist/ai/providers/rtzr/error.d.ts +18 -0
- package/dist/ai/providers/rtzr/error.d.ts.map +1 -0
- package/dist/ai/providers/rtzr/error.js +29 -0
- package/dist/ai/providers/rtzr/index.d.ts +5 -0
- package/dist/ai/providers/rtzr/index.d.ts.map +1 -0
- package/dist/ai/providers/rtzr/index.js +6 -0
- package/dist/ai/providers/rtzr/model.d.ts +52 -0
- package/dist/ai/providers/rtzr/model.d.ts.map +1 -0
- package/dist/ai/providers/rtzr/model.js +137 -0
- package/dist/ai/providers/rtzr/options.d.ts +7 -0
- package/dist/ai/providers/rtzr/options.d.ts.map +1 -0
- package/dist/ai/providers/rtzr/options.js +47 -0
- package/dist/ai/providers/rtzr/provider.d.ts +18 -0
- package/dist/ai/providers/rtzr/provider.d.ts.map +1 -0
- package/dist/ai/providers/rtzr/provider.js +54 -0
- package/dist/ai/providers/rtzr/utils.d.ts +19 -0
- package/dist/ai/providers/rtzr/utils.d.ts.map +1 -0
- package/dist/ai/providers/rtzr/utils.js +88 -0
- package/dist/api/base-frame.d.ts +2 -2
- package/dist/api/base-frame.d.ts.map +1 -1
- package/dist/api/base-frame.js +2 -1
- package/dist/api/caster.d.ts.map +1 -1
- package/dist/api/caster.js +6 -1
- package/dist/api/code-converters.d.ts +58 -14
- package/dist/api/code-converters.d.ts.map +1 -1
- package/dist/api/code-converters.js +178 -409
- package/dist/api/config.d.ts +27 -13
- package/dist/api/config.d.ts.map +1 -1
- package/dist/api/config.js +19 -26
- package/dist/api/context.d.ts +4 -3
- package/dist/api/context.d.ts.map +1 -1
- package/dist/api/context.js +1 -1
- package/dist/api/decorators.d.ts +20 -6
- package/dist/api/decorators.d.ts.map +1 -1
- package/dist/api/decorators.js +111 -18
- package/dist/api/index.d.ts +2 -2
- package/dist/api/index.d.ts.map +1 -1
- package/dist/api/index.js +3 -3
- package/dist/api/sonamu.d.ts +7 -7
- package/dist/api/sonamu.d.ts.map +1 -1
- package/dist/api/sonamu.js +83 -51
- package/dist/api/validator.d.ts +6 -0
- package/dist/api/validator.d.ts.map +1 -0
- package/dist/api/validator.js +81 -0
- package/dist/bin/build-config.d.ts +5 -1
- package/dist/bin/build-config.d.ts.map +1 -1
- package/dist/bin/build-config.js +5 -2
- package/dist/bin/cli.js +165 -64
- package/dist/bin/loader-register.d.ts +2 -0
- package/dist/bin/loader-register.d.ts.map +1 -0
- package/dist/bin/loader-register.js +34 -0
- package/dist/database/_batch_update.d.ts +5 -3
- package/dist/database/_batch_update.d.ts.map +1 -1
- package/dist/database/_batch_update.js +30 -13
- package/dist/database/base-model.d.ts +96 -10
- package/dist/database/base-model.d.ts.map +1 -1
- package/dist/database/base-model.js +232 -89
- package/dist/database/base-model.types.d.ts +93 -0
- package/dist/database/base-model.types.d.ts.map +1 -0
- package/dist/database/base-model.types.js +10 -0
- package/dist/database/code-generator.d.ts +1 -1
- package/dist/database/code-generator.d.ts.map +1 -1
- package/dist/database/code-generator.js +11 -10
- package/dist/database/db.d.ts +5 -6
- package/dist/database/db.d.ts.map +1 -1
- package/dist/database/db.js +22 -25
- package/dist/database/puri-subset.test-d.js +81 -0
- package/dist/database/puri-subset.types.d.ts +123 -0
- package/dist/database/puri-subset.types.d.ts.map +1 -0
- package/dist/database/puri-subset.types.js +16 -0
- package/dist/database/puri-wrapper.d.ts +13 -11
- package/dist/database/puri-wrapper.d.ts.map +1 -1
- package/dist/database/puri-wrapper.js +2 -2
- package/dist/database/puri.d.ts +25 -14
- package/dist/database/puri.d.ts.map +1 -1
- package/dist/database/puri.js +83 -21
- package/dist/database/puri.types.d.ts +21 -7
- package/dist/database/puri.types.d.ts.map +1 -1
- package/dist/database/puri.types.js +4 -1
- package/dist/database/transaction-context.d.ts +1 -1
- package/dist/database/transaction-context.d.ts.map +1 -1
- package/dist/database/transaction-context.js +1 -1
- package/dist/database/upsert-builder.d.ts +9 -3
- package/dist/database/upsert-builder.d.ts.map +1 -1
- package/dist/database/upsert-builder.js +228 -78
- package/dist/entity/entity-manager.d.ts +165 -2
- package/dist/entity/entity-manager.d.ts.map +1 -1
- package/dist/entity/entity-manager.js +26 -10
- package/dist/entity/entity.d.ts +5 -3
- package/dist/entity/entity.d.ts.map +1 -1
- package/dist/entity/entity.js +153 -54
- package/dist/exceptions/error-handler.d.ts +1 -1
- package/dist/exceptions/error-handler.d.ts.map +1 -1
- package/dist/exceptions/error-handler.js +1 -1
- package/dist/exceptions/so-exceptions.d.ts +1 -1
- package/dist/exceptions/so-exceptions.d.ts.map +1 -1
- package/dist/exceptions/so-exceptions.js +1 -1
- package/dist/file-storage/driver.d.ts +1 -1
- package/dist/file-storage/driver.d.ts.map +1 -1
- package/dist/file-storage/driver.js +1 -1
- package/dist/file-storage/file-storage.js +2 -2
- package/dist/index.d.ts +18 -11
- package/dist/index.d.ts.map +1 -1
- package/dist/index.js +19 -13
- package/dist/migration/code-generation.d.ts +1 -1
- package/dist/migration/code-generation.d.ts.map +1 -1
- package/dist/migration/code-generation.js +123 -67
- package/dist/migration/migration-set.d.ts +2 -10
- package/dist/migration/migration-set.d.ts.map +1 -1
- package/dist/migration/migration-set.js +67 -218
- package/dist/migration/migrator.d.ts +24 -73
- package/dist/migration/migrator.d.ts.map +1 -1
- package/dist/migration/migrator.js +121 -301
- package/dist/migration/postgresql-schema-reader.d.ts +51 -0
- package/dist/migration/postgresql-schema-reader.d.ts.map +1 -0
- package/dist/migration/postgresql-schema-reader.js +245 -0
- package/dist/migration/types.d.ts +6 -38
- package/dist/migration/types.d.ts.map +1 -1
- package/dist/migration/types.js +1 -1
- package/dist/naite/messaging-types.d.ts +43 -0
- package/dist/naite/messaging-types.d.ts.map +1 -0
- package/dist/naite/messaging-types.js +7 -0
- package/dist/naite/naite-reporter.d.ts +41 -0
- package/dist/naite/naite-reporter.d.ts.map +1 -0
- package/dist/naite/naite-reporter.js +102 -0
- package/dist/naite/naite.d.ts +91 -8
- package/dist/naite/naite.d.ts.map +1 -1
- package/dist/naite/naite.js +285 -41
- package/dist/stream/sse.d.ts +2 -2
- package/dist/stream/sse.d.ts.map +1 -1
- package/dist/stream/sse.js +1 -1
- package/dist/syncer/api-parser.d.ts +3 -13
- package/dist/syncer/api-parser.d.ts.map +1 -1
- package/dist/syncer/api-parser.js +67 -56
- package/dist/syncer/checksum.d.ts +2 -2
- package/dist/syncer/checksum.d.ts.map +1 -1
- package/dist/syncer/checksum.js +11 -11
- package/dist/syncer/code-generator.d.ts +3 -3
- package/dist/syncer/code-generator.d.ts.map +1 -1
- package/dist/syncer/code-generator.js +37 -17
- package/dist/syncer/entity-operations.d.ts +2 -2
- package/dist/syncer/entity-operations.d.ts.map +1 -1
- package/dist/syncer/entity-operations.js +9 -8
- package/dist/syncer/file-patterns.d.ts +1 -1
- package/dist/syncer/file-patterns.d.ts.map +1 -1
- package/dist/syncer/file-patterns.js +1 -1
- package/dist/syncer/index.d.ts +4 -4
- package/dist/syncer/index.d.ts.map +1 -1
- package/dist/syncer/index.js +5 -5
- package/dist/syncer/module-loader.d.ts +4 -4
- package/dist/syncer/module-loader.d.ts.map +1 -1
- package/dist/syncer/module-loader.js +17 -12
- package/dist/syncer/syncer.d.ts +31 -24
- package/dist/syncer/syncer.d.ts.map +1 -1
- package/dist/syncer/syncer.js +92 -45
- 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 +15 -8
- package/dist/template/helpers.d.ts +2 -2
- package/dist/template/helpers.d.ts.map +1 -1
- package/dist/template/helpers.js +3 -3
- package/dist/template/implementations/entity.template.d.ts +2 -2
- package/dist/template/implementations/entity.template.d.ts.map +1 -1
- package/dist/template/implementations/entity.template.js +4 -5
- package/dist/template/implementations/generated.template.d.ts +2 -3
- package/dist/template/implementations/generated.template.d.ts.map +1 -1
- package/dist/template/implementations/generated.template.js +46 -29
- package/dist/template/implementations/generated_http.template.d.ts +2 -3
- package/dist/template/implementations/generated_http.template.d.ts.map +1 -1
- package/dist/template/implementations/generated_http.template.js +9 -9
- package/dist/template/implementations/generated_sso.template.d.ts +3 -4
- package/dist/template/implementations/generated_sso.template.d.ts.map +1 -1
- package/dist/template/implementations/generated_sso.template.js +54 -25
- package/dist/template/implementations/init_types.template.d.ts +2 -2
- package/dist/template/implementations/init_types.template.d.ts.map +1 -1
- package/dist/template/implementations/init_types.template.js +2 -2
- package/dist/template/implementations/model.template.d.ts +2 -2
- package/dist/template/implementations/model.template.d.ts.map +1 -1
- package/dist/template/implementations/model.template.js +47 -37
- package/dist/template/implementations/model_test.template.d.ts +2 -2
- package/dist/template/implementations/model_test.template.d.ts.map +1 -1
- package/dist/template/implementations/model_test.template.js +2 -2
- package/dist/template/implementations/service.template.d.ts +4 -4
- package/dist/template/implementations/service.template.d.ts.map +1 -1
- package/dist/template/implementations/service.template.js +24 -16
- package/dist/template/implementations/view_enums_buttonset.template.d.ts +2 -2
- package/dist/template/implementations/view_enums_buttonset.template.d.ts.map +1 -1
- package/dist/template/implementations/view_enums_buttonset.template.js +1 -1
- package/dist/template/implementations/view_enums_dropdown.template.d.ts +2 -2
- package/dist/template/implementations/view_enums_dropdown.template.d.ts.map +1 -1
- package/dist/template/implementations/view_enums_dropdown.template.js +2 -2
- package/dist/template/implementations/view_enums_select.template.d.ts +2 -2
- package/dist/template/implementations/view_enums_select.template.d.ts.map +1 -1
- package/dist/template/implementations/view_enums_select.template.js +2 -2
- package/dist/template/implementations/view_form.template.d.ts +2 -2
- package/dist/template/implementations/view_form.template.d.ts.map +1 -1
- package/dist/template/implementations/view_form.template.js +4 -4
- package/dist/template/implementations/view_id_all_select.template.d.ts +2 -2
- package/dist/template/implementations/view_id_all_select.template.d.ts.map +1 -1
- package/dist/template/implementations/view_id_all_select.template.js +1 -1
- package/dist/template/implementations/view_id_async_select.template.d.ts +2 -2
- package/dist/template/implementations/view_id_async_select.template.d.ts.map +1 -1
- package/dist/template/implementations/view_id_async_select.template.js +1 -1
- package/dist/template/implementations/view_list.template.d.ts +2 -2
- package/dist/template/implementations/view_list.template.d.ts.map +1 -1
- package/dist/template/implementations/view_list.template.js +29 -19
- package/dist/template/implementations/view_list_columns.template.d.ts +3 -3
- package/dist/template/implementations/view_list_columns.template.d.ts.map +1 -1
- package/dist/template/implementations/view_list_columns.template.js +1 -1
- package/dist/template/implementations/view_search_input.template.d.ts +2 -2
- package/dist/template/implementations/view_search_input.template.d.ts.map +1 -1
- package/dist/template/implementations/view_search_input.template.js +1 -1
- package/dist/template/index.d.ts +4 -2
- package/dist/template/index.d.ts.map +1 -1
- package/dist/template/index.js +5 -3
- package/dist/template/template-manager.d.ts +56 -0
- package/dist/template/template-manager.d.ts.map +1 -0
- package/dist/template/template-manager.js +125 -0
- package/dist/template/template-types.d.ts +16 -0
- package/dist/template/template-types.d.ts.map +1 -0
- package/dist/template/template-types.js +7 -0
- package/dist/template/template.d.ts +12 -2
- package/dist/template/template.d.ts.map +1 -1
- package/dist/template/template.js +19 -6
- package/dist/template/zod-converter.d.ts +40 -7
- package/dist/template/zod-converter.d.ts.map +1 -1
- package/dist/template/zod-converter.js +341 -58
- package/dist/testing/_relation-graph.d.ts +1 -1
- package/dist/testing/_relation-graph.d.ts.map +1 -1
- package/dist/testing/_relation-graph.js +12 -3
- package/dist/testing/fixture-manager.d.ts +42 -11
- package/dist/testing/fixture-manager.d.ts.map +1 -1
- package/dist/testing/fixture-manager.js +338 -236
- package/dist/types/types.d.ts +709 -104
- package/dist/types/types.d.ts.map +1 -1
- package/dist/types/types.js +309 -52
- package/dist/typings/knex.d.js +2 -2
- package/dist/utils/async-utils.d.ts.map +1 -1
- package/dist/utils/async-utils.js +3 -3
- package/dist/utils/console-util.js +1 -1
- package/dist/utils/controller.d.ts +1 -0
- package/dist/utils/controller.d.ts.map +1 -1
- package/dist/utils/controller.js +4 -1
- package/dist/utils/esm-utils.d.ts +0 -6
- package/dist/utils/esm-utils.d.ts.map +1 -1
- package/dist/utils/esm-utils.js +2 -9
- package/dist/utils/formatter.d.ts +3 -0
- package/dist/utils/formatter.d.ts.map +1 -0
- package/dist/utils/formatter.js +110 -0
- package/dist/utils/fs-utils.d.ts +1 -1
- package/dist/utils/fs-utils.d.ts.map +1 -1
- package/dist/utils/fs-utils.js +1 -1
- package/dist/utils/lodash-able.d.ts.map +1 -1
- package/dist/utils/lodash-able.js +1 -1
- package/dist/utils/object-utils.d.ts +44 -0
- package/dist/utils/object-utils.d.ts.map +1 -0
- package/dist/utils/object-utils.js +191 -0
- package/dist/utils/path-utils.d.ts +1 -1
- package/dist/utils/path-utils.d.ts.map +1 -1
- package/dist/utils/path-utils.js +3 -3
- package/dist/utils/process-utils.js +1 -1
- package/dist/utils/sql-parser.d.ts +5 -1
- package/dist/utils/sql-parser.d.ts.map +1 -1
- package/dist/utils/sql-parser.js +14 -3
- package/dist/utils/type-utils.d.ts +23 -0
- package/dist/utils/type-utils.d.ts.map +1 -0
- package/dist/utils/type-utils.js +45 -0
- package/dist/utils/utils.d.ts +7 -1
- package/dist/utils/utils.d.ts.map +1 -1
- package/dist/utils/utils.js +44 -5
- package/dist/utils/zod-error.d.ts +1 -1
- package/dist/utils/zod-error.d.ts.map +1 -1
- package/dist/utils/zod-error.js +1 -1
- package/package.json +54 -29
- package/src/ai/agents/agent.ts +87 -0
- package/src/ai/agents/index.ts +2 -0
- package/src/ai/agents/types.ts +47 -0
- package/src/ai/index.ts +1 -0
- package/src/ai/providers/rtzr/api.ts +37 -0
- package/src/ai/providers/rtzr/error.ts +34 -0
- package/src/ai/providers/rtzr/index.ts +4 -0
- package/src/ai/providers/rtzr/model.ts +201 -0
- package/src/ai/providers/rtzr/options.ts +49 -0
- package/src/ai/providers/rtzr/provider.ts +91 -0
- package/src/ai/providers/rtzr/utils.ts +127 -0
- package/src/api/base-frame.ts +4 -2
- package/src/api/caster.ts +17 -23
- package/src/api/code-converters.ts +176 -533
- package/src/api/config.ts +39 -56
- package/src/api/context.ts +7 -18
- package/src/api/decorators.ts +175 -46
- package/src/api/index.ts +2 -2
- package/src/api/sonamu.ts +133 -124
- package/src/api/validator.ts +83 -0
- package/src/bin/build-config.ts +7 -1
- package/src/bin/cli.ts +192 -110
- package/src/bin/loader-register.ts +38 -0
- package/src/database/_batch_update.ts +46 -31
- package/src/database/base-model.ts +390 -182
- package/src/database/base-model.types.ts +155 -0
- package/src/database/code-generator.ts +13 -32
- package/src/database/db.ts +36 -50
- package/src/database/puri-subset.test-d.ts +471 -0
- package/src/database/puri-subset.types.ts +195 -0
- package/src/database/puri-wrapper.ts +58 -67
- package/src/database/puri.ts +182 -126
- package/src/database/puri.types.ts +64 -31
- package/src/database/transaction-context.ts +1 -1
- package/src/database/upsert-builder.ts +262 -132
- package/src/entity/entity-manager.ts +36 -28
- package/src/entity/entity.ts +330 -249
- package/src/exceptions/error-handler.ts +3 -3
- package/src/exceptions/so-exceptions.ts +11 -11
- package/src/file-storage/driver.ts +5 -5
- package/src/file-storage/file-storage.ts +2 -2
- package/src/index.ts +18 -12
- package/src/migration/code-generation.ts +185 -172
- package/src/migration/migration-set.ts +80 -293
- package/src/migration/migrator.ts +182 -425
- package/src/migration/mysql-schema-reader.ts.txt +272 -0
- package/src/migration/postgresql-schema-reader.ts +310 -0
- package/src/migration/types.ts +6 -39
- package/src/naite/messaging-types.ts +51 -0
- package/src/naite/naite-reporter.ts +128 -0
- package/src/naite/naite.ts +378 -33
- package/src/shared/web.shared.ts.txt +20 -24
- package/src/stream/sse.ts +5 -5
- package/src/syncer/api-parser.ts +52 -69
- package/src/syncer/checksum.ts +25 -37
- package/src/syncer/code-generator.ts +58 -62
- package/src/syncer/entity-operations.ts +12 -15
- package/src/syncer/file-patterns.ts +2 -2
- package/src/syncer/index.ts +4 -4
- package/src/syncer/module-loader.ts +28 -25
- package/src/syncer/syncer.ts +155 -162
- package/src/template/entity-converter.ts +18 -27
- package/src/template/helpers.ts +8 -11
- package/src/template/implementations/entity.template.ts +6 -6
- package/src/template/implementations/generated.template.ts +99 -99
- package/src/template/implementations/generated_http.template.ts +21 -54
- package/src/template/implementations/generated_sso.template.ts +78 -65
- package/src/template/implementations/init_types.template.ts +4 -6
- package/src/template/implementations/model.template.ts +47 -38
- package/src/template/implementations/model_test.template.ts +3 -3
- package/src/template/implementations/service.template.ts +56 -80
- package/src/template/implementations/view_enums_buttonset.template.ts +2 -2
- package/src/template/implementations/view_enums_dropdown.template.ts +4 -4
- package/src/template/implementations/view_enums_select.template.ts +3 -3
- package/src/template/implementations/view_form.template.ts +34 -75
- package/src/template/implementations/view_id_all_select.template.ts +2 -2
- package/src/template/implementations/view_id_async_select.template.ts +9 -23
- package/src/template/implementations/view_list.template.ts +54 -95
- package/src/template/implementations/view_list_columns.template.ts +4 -10
- package/src/template/implementations/view_search_input.template.ts +2 -2
- package/src/template/index.ts +4 -2
- package/src/template/template-manager.ts +166 -0
- package/src/template/template-types.ts +16 -0
- package/src/template/template.ts +29 -10
- package/src/template/zod-converter.ts +407 -101
- package/src/testing/_relation-graph.ts +18 -11
- package/src/testing/fixture-manager.ts +468 -362
- package/src/types/types.ts +516 -248
- package/src/typings/knex.d.ts +7 -9
- package/src/utils/async-utils.ts +8 -12
- package/src/utils/console-util.ts +1 -1
- package/src/utils/controller.ts +3 -0
- package/src/utils/esm-utils.ts +8 -18
- package/src/utils/formatter.ts +109 -0
- package/src/utils/fs-utils.ts +1 -1
- package/src/utils/lodash-able.ts +1 -4
- package/src/utils/object-utils.ts +217 -0
- package/src/utils/path-utils.ts +3 -6
- package/src/utils/process-utils.ts +1 -1
- package/src/utils/sql-parser.ts +23 -5
- package/src/utils/type-utils.ts +83 -0
- package/src/utils/utils.ts +58 -9
- package/src/utils/zod-error.ts +3 -3
- package/dist/bin/cli-wrapper.d.ts +0 -3
- package/dist/bin/cli-wrapper.d.ts.map +0 -1
- package/dist/bin/cli-wrapper.js +0 -72
- package/dist/database/knex-plugins/knex-on-duplicate-update.d.ts +0 -2
- package/dist/database/knex-plugins/knex-on-duplicate-update.d.ts.map +0 -1
- package/dist/database/knex-plugins/knex-on-duplicate-update.js +0 -39
- package/dist/entity/entity-utils.d.ts +0 -61
- package/dist/entity/entity-utils.d.ts.map +0 -1
- package/dist/entity/entity-utils.js +0 -210
- package/src/bin/cli-wrapper.ts +0 -82
- package/src/database/knex-plugins/knex-on-duplicate-update.ts +0 -45
- package/src/entity/entity-utils.ts +0 -291
package/src/api/sonamu.ts
CHANGED
|
@@ -1,42 +1,22 @@
|
|
|
1
|
+
import assert from "assert";
|
|
1
2
|
import { AsyncLocalStorage } from "async_hooks";
|
|
2
|
-
import
|
|
3
|
-
import fastify from "fastify";
|
|
4
|
-
import { readFile } from "fs/promises";
|
|
5
|
-
import path from "path";
|
|
6
|
-
import { exists } from "../utils/fs-utils";
|
|
7
|
-
import chokidar, { type FSWatcher } from "chokidar";
|
|
8
|
-
import { formatInTimeZone } from "date-fns-tz";
|
|
3
|
+
import type { FSWatcher } from "chokidar";
|
|
9
4
|
import type { FastifyInstance, FastifyReply, FastifyRequest } from "fastify";
|
|
10
5
|
import type { IncomingMessage, Server, ServerResponse } from "http";
|
|
11
|
-
import
|
|
12
|
-
import {
|
|
13
|
-
import {
|
|
14
|
-
import {
|
|
15
|
-
BadRequestException,
|
|
16
|
-
NotFoundException,
|
|
17
|
-
} from "../exceptions/so-exceptions";
|
|
6
|
+
import path from "path";
|
|
7
|
+
import type { ZodObject } from "zod";
|
|
8
|
+
import type { SonamuDBConfig } from "../database/db";
|
|
18
9
|
import type { Driver } from "../file-storage/driver";
|
|
19
|
-
import {
|
|
10
|
+
import { Naite } from "../naite/naite";
|
|
20
11
|
import type { Syncer } from "../syncer/syncer";
|
|
21
|
-
import {
|
|
22
|
-
import {
|
|
23
|
-
import {
|
|
24
|
-
import { humanizeZodError } from "../utils/zod-error";
|
|
25
|
-
import { fastifyCaster } from "./caster";
|
|
26
|
-
import { getZodObjectFromApi } from "./code-converters";
|
|
12
|
+
import type { SonamuFastifyConfig } from "../types/types";
|
|
13
|
+
import type { AbsolutePath } from "../utils/path-utils";
|
|
14
|
+
import type { SonamuConfig, SonamuServerOptions } from "./config";
|
|
27
15
|
import type { AuthContext, Context, UploadContext } from "./context";
|
|
28
16
|
import type { ExtendedApi } from "./decorators";
|
|
29
|
-
import fastifyPassport from "@fastify/passport";
|
|
30
|
-
import { loadConfig, SonamuConfig, SonamuServerOptions } from "./config";
|
|
31
|
-
import { AbsolutePath } from "../utils/path-utils";
|
|
32
|
-
import { isHotReloadServer } from "../utils/esm-utils";
|
|
33
|
-
import { Template } from "../template";
|
|
34
|
-
import assert from "assert";
|
|
35
|
-
import { centerText } from "../utils/console-util";
|
|
36
|
-
import { BaseModel } from "../database/base-model";
|
|
37
17
|
|
|
38
18
|
export type SonamuSecrets = {
|
|
39
|
-
|
|
19
|
+
anthropic_api_key?: string;
|
|
40
20
|
};
|
|
41
21
|
class SonamuClass {
|
|
42
22
|
public isInitialized: boolean = false;
|
|
@@ -61,6 +41,7 @@ class SonamuClass {
|
|
|
61
41
|
reply: null,
|
|
62
42
|
headers: {},
|
|
63
43
|
createSSE: () => {},
|
|
44
|
+
// biome-ignore lint/suspicious/noExplicitAny: 테스팅 환경에서 컨텍스트가 주입되지 않은 경우 빈 컨텍스트 리턴
|
|
64
45
|
naiteStore: new Map<string, any>(),
|
|
65
46
|
} as unknown as Context;
|
|
66
47
|
} else {
|
|
@@ -73,9 +54,7 @@ class SonamuClass {
|
|
|
73
54
|
if (store?.uploadContext) {
|
|
74
55
|
return store.uploadContext;
|
|
75
56
|
}
|
|
76
|
-
throw new Error(
|
|
77
|
-
"Sonamu cannot find upload context. Did you use @upload decorator?"
|
|
78
|
-
);
|
|
57
|
+
throw new Error("Sonamu cannot find upload context. Did you use @upload decorator?");
|
|
79
58
|
}
|
|
80
59
|
|
|
81
60
|
private _apiRootPath: AbsolutePath | null = null;
|
|
@@ -86,7 +65,7 @@ class SonamuClass {
|
|
|
86
65
|
if (this._apiRootPath === null) {
|
|
87
66
|
throw new Error("Sonamu has not been initialized");
|
|
88
67
|
}
|
|
89
|
-
return this._apiRootPath
|
|
68
|
+
return this._apiRootPath;
|
|
90
69
|
}
|
|
91
70
|
get appRootPath(): string {
|
|
92
71
|
return this.apiRootPath.split(path.sep).slice(0, -1).join(path.sep);
|
|
@@ -100,7 +79,7 @@ class SonamuClass {
|
|
|
100
79
|
if (this._dbConfig === null) {
|
|
101
80
|
throw new Error("Sonamu has not been initialized");
|
|
102
81
|
}
|
|
103
|
-
return this._dbConfig
|
|
82
|
+
return this._dbConfig;
|
|
104
83
|
}
|
|
105
84
|
|
|
106
85
|
private _syncer: Syncer | null = null;
|
|
@@ -111,7 +90,7 @@ class SonamuClass {
|
|
|
111
90
|
if (this._syncer === null) {
|
|
112
91
|
throw new Error("Sonamu has not been initialized");
|
|
113
92
|
}
|
|
114
|
-
return this._syncer
|
|
93
|
+
return this._syncer;
|
|
115
94
|
}
|
|
116
95
|
|
|
117
96
|
private _config: SonamuConfig | null = null;
|
|
@@ -156,30 +135,39 @@ class SonamuClass {
|
|
|
156
135
|
doSilent: boolean = false,
|
|
157
136
|
enableSync: boolean = true,
|
|
158
137
|
apiRootPath?: AbsolutePath,
|
|
159
|
-
forTesting: boolean = false
|
|
138
|
+
forTesting: boolean = false,
|
|
160
139
|
) {
|
|
161
140
|
if (this.isInitialized) {
|
|
162
141
|
return;
|
|
163
142
|
}
|
|
164
|
-
|
|
165
|
-
|
|
166
|
-
|
|
167
|
-
);
|
|
143
|
+
|
|
144
|
+
if (!doSilent) {
|
|
145
|
+
const chalk = (await import("chalk")).default;
|
|
146
|
+
console.time(chalk.cyan(`Sonamu.init${forTesting ? " for testing" : ""}`));
|
|
147
|
+
}
|
|
168
148
|
|
|
169
149
|
// API 루트 패스
|
|
150
|
+
const { findApiRootPath } = await import("../utils/utils");
|
|
170
151
|
this.apiRootPath = apiRootPath ?? findApiRootPath();
|
|
152
|
+
|
|
153
|
+
const { loadConfig } = await import("./config");
|
|
171
154
|
this.config = await loadConfig(this.apiRootPath);
|
|
172
|
-
|
|
173
|
-
|
|
174
|
-
|
|
175
|
-
|
|
176
|
-
|
|
155
|
+
// sonamu.config.ts 기본값 설정
|
|
156
|
+
this.config.database.database = this.config.database.database ?? "postgresql";
|
|
157
|
+
|
|
158
|
+
if (process.env.ANTHROPIC_API_KEY) {
|
|
159
|
+
this.secrets = {
|
|
160
|
+
anthropic_api_key: process.env.ANTHROPIC_API_KEY,
|
|
161
|
+
};
|
|
177
162
|
}
|
|
178
163
|
|
|
179
164
|
// DB 로드
|
|
165
|
+
const { DB } = await import("../database/db");
|
|
180
166
|
this.dbConfig = DB.generateDBConfig(this.config.database);
|
|
181
|
-
|
|
182
|
-
|
|
167
|
+
if (!doSilent) {
|
|
168
|
+
const chalk = (await import("chalk")).default;
|
|
169
|
+
console.log(chalk.green("DB Config Loaded!"));
|
|
170
|
+
}
|
|
183
171
|
|
|
184
172
|
// 테스팅인 경우 엔티티 로드 & 싱크 없이 중단
|
|
185
173
|
if (forTesting) {
|
|
@@ -200,29 +188,38 @@ class SonamuClass {
|
|
|
200
188
|
await this.syncer.autoloadModels();
|
|
201
189
|
await this.syncer.autoloadApis();
|
|
202
190
|
|
|
203
|
-
await
|
|
191
|
+
const { TemplateManager } = await import("../template");
|
|
192
|
+
await TemplateManager.autoload();
|
|
204
193
|
|
|
194
|
+
const { isLocal, isTest } = await import("../utils/controller");
|
|
195
|
+
if (isLocal()) {
|
|
196
|
+
// 로컬에서는 코드 생성을 위해 Biome 셋업이 필요함 (현재 apiRootPath 전달하여 실행)
|
|
197
|
+
(await import("../utils/formatter")).setupBiome(this.apiRootPath);
|
|
198
|
+
}
|
|
199
|
+
|
|
200
|
+
const { isHotReloadServer } = await import("../utils/controller");
|
|
205
201
|
if (isLocal() && !isTest() && isHotReloadServer() && enableSync) {
|
|
206
202
|
await this.syncer.sync();
|
|
207
203
|
|
|
208
|
-
this.startWatcher();
|
|
204
|
+
await this.startWatcher();
|
|
209
205
|
|
|
210
206
|
this.syncer.syncUI();
|
|
211
207
|
}
|
|
212
208
|
|
|
213
209
|
this.isInitialized = true;
|
|
214
|
-
!doSilent
|
|
210
|
+
if (!doSilent) {
|
|
211
|
+
const chalk = (await import("chalk")).default;
|
|
212
|
+
console.timeEnd(chalk.cyan("Sonamu.init"));
|
|
213
|
+
}
|
|
215
214
|
}
|
|
216
215
|
|
|
217
|
-
async createServer(initOptions?: {
|
|
218
|
-
enableSync?: boolean;
|
|
219
|
-
doSilent?: boolean;
|
|
220
|
-
}) {
|
|
216
|
+
async createServer(initOptions?: { enableSync?: boolean; doSilent?: boolean }) {
|
|
221
217
|
if (this.isInitialized === false) {
|
|
222
218
|
await this.init(initOptions?.doSilent, initOptions?.enableSync);
|
|
223
219
|
}
|
|
224
220
|
|
|
225
221
|
const options = this.config.server;
|
|
222
|
+
const fastify = (await import("fastify")).default;
|
|
226
223
|
const server = fastify(options.fastify);
|
|
227
224
|
this.server = server;
|
|
228
225
|
|
|
@@ -233,17 +230,15 @@ class SonamuClass {
|
|
|
233
230
|
|
|
234
231
|
// 플러그인 등록
|
|
235
232
|
if (options.plugins) {
|
|
236
|
-
this.registerPlugins(server, options.plugins);
|
|
233
|
+
await this.registerPlugins(server, options.plugins);
|
|
237
234
|
}
|
|
238
235
|
|
|
239
236
|
if (options.auth) {
|
|
240
237
|
if (!options.plugins?.session) {
|
|
241
|
-
throw new Error(
|
|
242
|
-
"Auth requires session plugin. Please add plugins.session configuration."
|
|
243
|
-
);
|
|
238
|
+
throw new Error("Auth requires session plugin. Please add plugins.session configuration.");
|
|
244
239
|
}
|
|
245
240
|
|
|
246
|
-
this.registerAuth(server, options.auth);
|
|
241
|
+
await this.registerAuth(server, options.auth);
|
|
247
242
|
}
|
|
248
243
|
|
|
249
244
|
// API 라우팅 설정
|
|
@@ -264,7 +259,7 @@ class SonamuClass {
|
|
|
264
259
|
options?: {
|
|
265
260
|
enableSync?: boolean;
|
|
266
261
|
doSilent?: boolean;
|
|
267
|
-
}
|
|
262
|
+
},
|
|
268
263
|
) {
|
|
269
264
|
if (this.isInitialized === false) {
|
|
270
265
|
await this.init(options?.doSilent, options?.enableSync);
|
|
@@ -275,28 +270,43 @@ class SonamuClass {
|
|
|
275
270
|
// timezone 설정
|
|
276
271
|
const timezone = this.config.api.timezone;
|
|
277
272
|
if (timezone) {
|
|
278
|
-
|
|
273
|
+
// 타임존에 맞게 응답 날짜 스트링을 변환해주어야 합니다.
|
|
274
|
+
// 가령 timezone이 "Asia/Seoul" 이면
|
|
275
|
+
// "2025-11-21T00:00:00.000Z" 를 "2025-11-21T09:00:00+09:00" 으로 변환해주어야 합니다.
|
|
276
|
+
const { formatInTimeZone } = await import("date-fns-tz");
|
|
277
|
+
|
|
279
278
|
// ISO 8601 날짜 형식 정규식 (예: 2024-01-15T09:30:00.000Z)
|
|
280
279
|
const ISO_DATE_REGEX = /^\d{4}-\d{2}-\d{2}T\d{2}:\d{2}:\d{2}(\.\d{3})?Z$/;
|
|
281
280
|
|
|
281
|
+
// T를 둘러싼 작은따옴표가 없다면 "2025-11-19176354618900018:56:29+09:00"와 같은 결과가 나옵니다.
|
|
282
|
+
// 이는 date-fns 특입니다.
|
|
283
|
+
// 이렇게 해도 괜찮습니다. "2025-11-19T18:56:29+09:00" 모양으로 잘 나옵니다.
|
|
284
|
+
const DATE_FORMAT = "yyyy-MM-dd'T'HH:mm:ssXXX";
|
|
285
|
+
|
|
282
286
|
server.setReplySerializer((payload) => {
|
|
283
287
|
return JSON.stringify(payload, (_key, value) => {
|
|
284
288
|
if (typeof value === "string" && ISO_DATE_REGEX.test(value)) {
|
|
285
|
-
return formatInTimeZone(
|
|
289
|
+
return formatInTimeZone(
|
|
290
|
+
new Date(value),
|
|
291
|
+
timezone as `${string}/${string}`,
|
|
292
|
+
DATE_FORMAT,
|
|
293
|
+
);
|
|
286
294
|
}
|
|
287
295
|
return value;
|
|
288
296
|
});
|
|
289
297
|
});
|
|
290
|
-
!options?.doSilent
|
|
298
|
+
if (!options?.doSilent) {
|
|
299
|
+
const chalk = (await import("chalk")).default;
|
|
291
300
|
console.log(chalk.green(`Timezone set to ${timezone}`));
|
|
301
|
+
}
|
|
292
302
|
}
|
|
293
303
|
|
|
294
304
|
// 전체 라우팅 리스트
|
|
295
305
|
server.get(
|
|
296
306
|
`${this.config.api.route.prefix}/routes`,
|
|
297
|
-
async (_request, _reply): Promise<
|
|
307
|
+
async (_request, _reply): Promise<typeof this.syncer.apis> => {
|
|
298
308
|
return this.syncer.apis;
|
|
299
|
-
}
|
|
309
|
+
},
|
|
300
310
|
);
|
|
301
311
|
|
|
302
312
|
// Healthcheck API
|
|
@@ -304,25 +314,26 @@ class SonamuClass {
|
|
|
304
314
|
`${this.config.api.route.prefix}/healthcheck`,
|
|
305
315
|
async (_request, _reply): Promise<string> => {
|
|
306
316
|
return "ok";
|
|
307
|
-
}
|
|
317
|
+
},
|
|
308
318
|
);
|
|
309
319
|
|
|
310
320
|
// API 라우팅 (로컬HMR 상태와 구분)
|
|
321
|
+
const { isLocal } = await import("../utils/controller");
|
|
311
322
|
if (isLocal()) {
|
|
312
|
-
server.all("*", (request, reply) => {
|
|
323
|
+
server.all("*", async (request, reply) => {
|
|
313
324
|
const found = this.syncer.apis.find(
|
|
314
325
|
(api) =>
|
|
315
|
-
this.config.api.route.prefix + api.path ===
|
|
316
|
-
|
|
317
|
-
(api.options.httpMethod ?? "GET") === request.method.toUpperCase()
|
|
326
|
+
this.config.api.route.prefix + api.path === request.url.split("?")[0] &&
|
|
327
|
+
(api.options.httpMethod ?? "GET") === request.method.toUpperCase(),
|
|
318
328
|
);
|
|
319
329
|
if (found) {
|
|
320
330
|
return this.getApiHandler(found, config)(request, reply);
|
|
321
331
|
}
|
|
332
|
+
const { NotFoundException } = await import("../exceptions/so-exceptions");
|
|
322
333
|
throw new NotFoundException("존재하지 않는 API 접근입니다.");
|
|
323
334
|
});
|
|
324
335
|
} else {
|
|
325
|
-
this.syncer.apis
|
|
336
|
+
for (const api of this.syncer.apis) {
|
|
326
337
|
// model
|
|
327
338
|
if (this.syncer.models[api.modelName] === undefined) {
|
|
328
339
|
throw new Error(`정의되지 않은 모델에 접근 ${api.modelName}`);
|
|
@@ -330,24 +341,23 @@ class SonamuClass {
|
|
|
330
341
|
|
|
331
342
|
// route
|
|
332
343
|
server.route({
|
|
333
|
-
method: api.options.httpMethod
|
|
344
|
+
method: api.options.httpMethod ?? "GET",
|
|
334
345
|
url: this.config.api.route.prefix + api.path,
|
|
335
346
|
handler: this.getApiHandler(api, config),
|
|
336
347
|
}); // END server.route
|
|
337
|
-
}
|
|
348
|
+
}
|
|
338
349
|
}
|
|
339
350
|
}
|
|
340
351
|
|
|
341
|
-
getApiHandler(
|
|
342
|
-
|
|
343
|
-
|
|
344
|
-
|
|
345
|
-
): Promise<unknown> => {
|
|
346
|
-
(api.options.guards ?? []).every((guard) =>
|
|
347
|
-
config.guardHandler(guard, request, api)
|
|
348
|
-
);
|
|
352
|
+
getApiHandler(
|
|
353
|
+
api: ExtendedApi,
|
|
354
|
+
config: SonamuFastifyConfig,
|
|
355
|
+
): (request: FastifyRequest, reply: FastifyReply) => Promise<unknown> {
|
|
356
|
+
return async (request: FastifyRequest, reply: FastifyReply): Promise<unknown> => {
|
|
357
|
+
(api.options.guards ?? []).every((guard) => config.guardHandler(guard, request, api));
|
|
349
358
|
|
|
350
359
|
// 파라미터 정보로 zod 스키마 빌드
|
|
360
|
+
const { getZodObjectFromApi } = await import("./code-converters");
|
|
351
361
|
const ReqType = getZodObjectFromApi(api, this.syncer.types);
|
|
352
362
|
|
|
353
363
|
// request 파싱
|
|
@@ -356,12 +366,16 @@ class SonamuClass {
|
|
|
356
366
|
[key: string]: unknown;
|
|
357
367
|
};
|
|
358
368
|
try {
|
|
369
|
+
const { fastifyCaster } = await import("./caster");
|
|
359
370
|
reqBody = fastifyCaster(ReqType).parse(request[which] ?? {});
|
|
360
371
|
} catch (e) {
|
|
372
|
+
const { ZodError } = await import("zod");
|
|
361
373
|
if (e instanceof ZodError) {
|
|
374
|
+
const { humanizeZodError } = await import("../utils/zod-error");
|
|
362
375
|
const messages = humanizeZodError(e)
|
|
363
376
|
.map((issue) => issue.message)
|
|
364
377
|
.join(" ");
|
|
378
|
+
const { BadRequestException } = await import("../exceptions/so-exceptions");
|
|
365
379
|
throw new BadRequestException(messages, {
|
|
366
380
|
zodError: e,
|
|
367
381
|
});
|
|
@@ -398,15 +412,12 @@ class SonamuClass {
|
|
|
398
412
|
}
|
|
399
413
|
|
|
400
414
|
// createSSEFactory 함수에 미리 request의 socket과 reply를 바인딩.
|
|
415
|
+
const { createSSEFactory } = await import("../stream/sse");
|
|
401
416
|
const createSSE = (<T extends ZodObject>(
|
|
402
417
|
_request: FastifyRequest,
|
|
403
418
|
_reply: FastifyReply,
|
|
404
|
-
_events: T
|
|
405
|
-
) => createSSEFactory(_request.socket, _reply, _events)).bind(
|
|
406
|
-
null,
|
|
407
|
-
request,
|
|
408
|
-
reply
|
|
409
|
-
);
|
|
419
|
+
_events: T,
|
|
420
|
+
) => createSSEFactory(_request.socket, _reply, _events)).bind(null, request, reply);
|
|
410
421
|
|
|
411
422
|
const context: Context = {
|
|
412
423
|
...(await Promise.resolve(
|
|
@@ -416,26 +427,24 @@ class SonamuClass {
|
|
|
416
427
|
reply,
|
|
417
428
|
headers: request.headers,
|
|
418
429
|
createSSE,
|
|
419
|
-
naiteStore:
|
|
430
|
+
naiteStore: Naite.createStore(),
|
|
420
431
|
// auth
|
|
421
432
|
user: request.user ?? null,
|
|
422
433
|
passport: {
|
|
423
|
-
login: request.login.bind(
|
|
424
|
-
|
|
425
|
-
) as AuthContext["passport"]["login"],
|
|
426
|
-
logout: request.logout.bind(
|
|
427
|
-
request
|
|
428
|
-
) as AuthContext["passport"]["logout"],
|
|
434
|
+
login: request.login.bind(request) as AuthContext["passport"]["login"],
|
|
435
|
+
logout: request.logout.bind(request) as AuthContext["passport"]["logout"],
|
|
429
436
|
},
|
|
430
437
|
},
|
|
431
438
|
request,
|
|
432
|
-
reply
|
|
433
|
-
)
|
|
439
|
+
reply,
|
|
440
|
+
),
|
|
434
441
|
)),
|
|
435
442
|
};
|
|
436
443
|
|
|
437
444
|
const model = this.syncer.models[api.modelName];
|
|
438
445
|
return this.asyncLocalStorage.run({ context }, async () => {
|
|
446
|
+
const { ApiParamType } = await import("../types/types");
|
|
447
|
+
// biome-ignore lint/suspicious/noExplicitAny: model은 모델 인스턴스이므로 메서드 호출 가능
|
|
439
448
|
const result = await (model as any)[api.methodName].apply(
|
|
440
449
|
model,
|
|
441
450
|
api.parameters.map((param) => {
|
|
@@ -445,7 +454,7 @@ class SonamuClass {
|
|
|
445
454
|
} else {
|
|
446
455
|
return reqBody[param.name];
|
|
447
456
|
}
|
|
448
|
-
})
|
|
457
|
+
}),
|
|
449
458
|
);
|
|
450
459
|
reply.type(api.options.contentType ?? "application/json");
|
|
451
460
|
|
|
@@ -458,12 +467,13 @@ class SonamuClass {
|
|
|
458
467
|
};
|
|
459
468
|
}
|
|
460
469
|
|
|
461
|
-
startWatcher(): void {
|
|
470
|
+
async startWatcher(): Promise<void> {
|
|
462
471
|
const watchPath = [
|
|
463
472
|
path.join(this.apiRootPath, "src"),
|
|
464
473
|
path.join(this.apiRootPath, "sonamu.config.ts"),
|
|
465
474
|
];
|
|
466
475
|
|
|
476
|
+
const chokidar = (await import("chokidar")).default;
|
|
467
477
|
this.watcher = chokidar.watch(watchPath, {
|
|
468
478
|
ignored: (path, stats) =>
|
|
469
479
|
!!stats?.isFile() && !path.endsWith(".ts") && !path.endsWith(".json"),
|
|
@@ -475,7 +485,7 @@ class SonamuClass {
|
|
|
475
485
|
const absolutePath = filePath as AbsolutePath;
|
|
476
486
|
assert(
|
|
477
487
|
absolutePath.startsWith(this.apiRootPath),
|
|
478
|
-
"File path is not within the API root path"
|
|
488
|
+
"File path is not within the API root path",
|
|
479
489
|
);
|
|
480
490
|
|
|
481
491
|
if (event !== "change" && event !== "add") {
|
|
@@ -484,15 +494,13 @@ class SonamuClass {
|
|
|
484
494
|
|
|
485
495
|
try {
|
|
486
496
|
// sonamu.config.ts 변경 시 재시작
|
|
487
|
-
const isConfigTs =
|
|
488
|
-
filePath === path.join(this.apiRootPath, "sonamu.config.ts");
|
|
497
|
+
const isConfigTs = filePath === path.join(this.apiRootPath, "sonamu.config.ts");
|
|
489
498
|
|
|
490
499
|
if (isConfigTs) {
|
|
491
500
|
const relativePath = filePath.replace(this.apiRootPath, "api");
|
|
501
|
+
const chalk = (await import("chalk")).default;
|
|
492
502
|
console.log(
|
|
493
|
-
chalk.bold(
|
|
494
|
-
`Detected(${event}): ${chalk.blue(relativePath)} - Restarting...`
|
|
495
|
-
)
|
|
503
|
+
chalk.bold(`Detected(${event}): ${chalk.blue(relativePath)} - Restarting...`),
|
|
496
504
|
);
|
|
497
505
|
process.kill(process.pid, "SIGUSR2");
|
|
498
506
|
return;
|
|
@@ -517,10 +525,7 @@ class SonamuClass {
|
|
|
517
525
|
}
|
|
518
526
|
}
|
|
519
527
|
|
|
520
|
-
private registerPlugins(
|
|
521
|
-
server: FastifyInstance,
|
|
522
|
-
plugins: SonamuServerOptions["plugins"]
|
|
523
|
-
) {
|
|
528
|
+
private async registerPlugins(server: FastifyInstance, plugins: SonamuServerOptions["plugins"]) {
|
|
524
529
|
if (!plugins) {
|
|
525
530
|
return;
|
|
526
531
|
}
|
|
@@ -535,23 +540,23 @@ class SonamuClass {
|
|
|
535
540
|
session: "@fastify/secure-session",
|
|
536
541
|
} as const;
|
|
537
542
|
|
|
538
|
-
const registerPlugin = <K extends keyof NonNullable<typeof plugins>>(
|
|
543
|
+
const registerPlugin = async <K extends keyof NonNullable<typeof plugins>>(
|
|
539
544
|
key: K,
|
|
540
|
-
pluginName: string
|
|
545
|
+
pluginName: string,
|
|
541
546
|
) => {
|
|
542
547
|
const option = plugins[key];
|
|
543
548
|
if (!option) return;
|
|
544
549
|
|
|
545
550
|
if (option === true) {
|
|
546
|
-
server.register(import(pluginName));
|
|
551
|
+
server.register((await import(pluginName)).default);
|
|
547
552
|
} else {
|
|
548
|
-
server.register(import(pluginName), option);
|
|
553
|
+
server.register((await import(pluginName)).default, option);
|
|
549
554
|
}
|
|
550
555
|
};
|
|
551
556
|
|
|
552
|
-
|
|
553
|
-
registerPlugin(key as keyof typeof plugins, pluginName);
|
|
554
|
-
}
|
|
557
|
+
for (const [key, pluginName] of Object.entries(pluginsModules)) {
|
|
558
|
+
await registerPlugin(key as keyof typeof plugins, pluginName);
|
|
559
|
+
}
|
|
555
560
|
|
|
556
561
|
if (plugins.custom) {
|
|
557
562
|
plugins.custom(server);
|
|
@@ -560,16 +565,16 @@ class SonamuClass {
|
|
|
560
565
|
|
|
561
566
|
private async registerAuth(
|
|
562
567
|
server: FastifyInstance,
|
|
563
|
-
options: NonNullable<SonamuServerOptions["auth"]
|
|
568
|
+
options: NonNullable<SonamuServerOptions["auth"]>,
|
|
564
569
|
) {
|
|
570
|
+
// await import("fastify");
|
|
571
|
+
const fastifyPassport = (await import("@fastify/passport")).default;
|
|
565
572
|
server.register(fastifyPassport.initialize());
|
|
566
573
|
server.register(fastifyPassport.secureSession());
|
|
567
574
|
|
|
568
575
|
if (typeof options === "boolean") {
|
|
569
576
|
fastifyPassport.registerUserSerializer(async (user, _request) => user);
|
|
570
|
-
fastifyPassport.registerUserDeserializer(
|
|
571
|
-
async (serialized, _request) => serialized
|
|
572
|
-
);
|
|
577
|
+
fastifyPassport.registerUserDeserializer(async (serialized, _request) => serialized);
|
|
573
578
|
} else {
|
|
574
579
|
fastifyPassport.registerUserSerializer(options.userSerializer);
|
|
575
580
|
fastifyPassport.registerUserDeserializer(options.userDeserializer);
|
|
@@ -608,15 +613,13 @@ class SonamuClass {
|
|
|
608
613
|
await options.lifecycle?.onStart?.(server);
|
|
609
614
|
})
|
|
610
615
|
.catch(async (err) => {
|
|
616
|
+
const chalk = (await import("chalk")).default;
|
|
611
617
|
console.error(chalk.red("Failed to start server:", err));
|
|
612
618
|
await shutdown();
|
|
613
619
|
});
|
|
614
620
|
}
|
|
615
621
|
|
|
616
|
-
private async handleFileChange(
|
|
617
|
-
event: string,
|
|
618
|
-
filePath: AbsolutePath
|
|
619
|
-
): Promise<void> {
|
|
622
|
+
private async handleFileChange(event: string, filePath: AbsolutePath): Promise<void> {
|
|
620
623
|
// 첫 번째 파일이면 HMR 시작 시간 기록
|
|
621
624
|
if (this.pendingFiles.length === 0) {
|
|
622
625
|
this.hmrStartTime = Date.now();
|
|
@@ -624,6 +627,7 @@ class SonamuClass {
|
|
|
624
627
|
this.pendingFiles.push(filePath);
|
|
625
628
|
|
|
626
629
|
const relativePath = path.relative(this.apiRootPath, filePath);
|
|
630
|
+
const chalk = (await import("chalk")).default;
|
|
627
631
|
console.log(chalk.bold(`Detected(${event}): ${chalk.blue(relativePath)}`));
|
|
628
632
|
|
|
629
633
|
await this.syncer.syncFromWatcher(event, filePath);
|
|
@@ -642,12 +646,17 @@ class SonamuClass {
|
|
|
642
646
|
|
|
643
647
|
const endTime = Date.now();
|
|
644
648
|
const totalTime = endTime - this.hmrStartTime;
|
|
649
|
+
const [chalk, { centerText }] = await Promise.all([
|
|
650
|
+
(await import("chalk")).default,
|
|
651
|
+
import("../utils/console-util"),
|
|
652
|
+
]);
|
|
645
653
|
const msg = `HMR Done! ${chalk.bold.white(`${totalTime}ms`)}`;
|
|
646
654
|
|
|
647
655
|
console.log(chalk.black.bgGreen(centerText(msg)));
|
|
648
656
|
}
|
|
649
657
|
|
|
650
658
|
async destroy(): Promise<void> {
|
|
659
|
+
const { BaseModel } = await import("../database/base-model");
|
|
651
660
|
await BaseModel.destroy();
|
|
652
661
|
await this.watcher?.close();
|
|
653
662
|
this.storage?.destroy();
|
|
@@ -0,0 +1,83 @@
|
|
|
1
|
+
export const RESERVED_KEYWORDS = new Set([
|
|
2
|
+
"abstract",
|
|
3
|
+
"arguments",
|
|
4
|
+
"async",
|
|
5
|
+
"await",
|
|
6
|
+
"boolean",
|
|
7
|
+
"break",
|
|
8
|
+
"byte",
|
|
9
|
+
"case",
|
|
10
|
+
"catch",
|
|
11
|
+
"char",
|
|
12
|
+
"class",
|
|
13
|
+
"const",
|
|
14
|
+
"continue",
|
|
15
|
+
"debugger",
|
|
16
|
+
"default",
|
|
17
|
+
"delete",
|
|
18
|
+
"do",
|
|
19
|
+
"double",
|
|
20
|
+
"else",
|
|
21
|
+
"enum",
|
|
22
|
+
"eval",
|
|
23
|
+
"export",
|
|
24
|
+
"extends",
|
|
25
|
+
"false",
|
|
26
|
+
"final",
|
|
27
|
+
"finally",
|
|
28
|
+
"float",
|
|
29
|
+
"for",
|
|
30
|
+
"function",
|
|
31
|
+
"goto",
|
|
32
|
+
"if",
|
|
33
|
+
"implements",
|
|
34
|
+
"import",
|
|
35
|
+
"in",
|
|
36
|
+
"instanceof",
|
|
37
|
+
"int",
|
|
38
|
+
"interface",
|
|
39
|
+
"let",
|
|
40
|
+
"long",
|
|
41
|
+
"native",
|
|
42
|
+
"new",
|
|
43
|
+
"null",
|
|
44
|
+
"package",
|
|
45
|
+
"private",
|
|
46
|
+
"protected",
|
|
47
|
+
"public",
|
|
48
|
+
"return",
|
|
49
|
+
"short",
|
|
50
|
+
"static",
|
|
51
|
+
"super",
|
|
52
|
+
"switch",
|
|
53
|
+
"synchronized",
|
|
54
|
+
"this",
|
|
55
|
+
"throw",
|
|
56
|
+
"throws",
|
|
57
|
+
"transient",
|
|
58
|
+
"true",
|
|
59
|
+
"try",
|
|
60
|
+
"typeof",
|
|
61
|
+
"using",
|
|
62
|
+
"var",
|
|
63
|
+
"void",
|
|
64
|
+
"volatile",
|
|
65
|
+
"while",
|
|
66
|
+
"with",
|
|
67
|
+
"yield",
|
|
68
|
+
]);
|
|
69
|
+
|
|
70
|
+
export class ApiValidationError extends Error {
|
|
71
|
+
constructor(message: string) {
|
|
72
|
+
super(`[Sonamu API Validation] ${message}`);
|
|
73
|
+
this.name = "ApiValidationError";
|
|
74
|
+
}
|
|
75
|
+
}
|
|
76
|
+
|
|
77
|
+
export function validateMethodName(methodName: string) {
|
|
78
|
+
if (RESERVED_KEYWORDS.has(methodName)) {
|
|
79
|
+
throw new ApiValidationError(
|
|
80
|
+
`Method name ${methodName} is a reserved keyword. Please choose a different name.`,
|
|
81
|
+
);
|
|
82
|
+
}
|
|
83
|
+
}
|
package/src/bin/build-config.ts
CHANGED
|
@@ -1,3 +1,8 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* 소스 코드가 담길 디렉토리 경로
|
|
3
|
+
*/
|
|
4
|
+
export const SRC_DIR = "src";
|
|
5
|
+
|
|
1
6
|
/**
|
|
2
7
|
* 빌드 결과물이 담길 디렉토리 경로
|
|
3
8
|
*/
|
|
@@ -7,7 +12,8 @@ export const BUILD_DIR = "dist";
|
|
|
7
12
|
* SWC 빌드 명령어
|
|
8
13
|
* .swcrc 설정 사용
|
|
9
14
|
*/
|
|
10
|
-
export const SWC_BUILD_COMMAND =
|
|
15
|
+
export const SWC_BUILD_COMMAND = (configFilePath: string) =>
|
|
16
|
+
`swc ${SRC_DIR} -d ${BUILD_DIR} --config-file ${configFilePath} --strip-leading-paths`;
|
|
11
17
|
|
|
12
18
|
/**
|
|
13
19
|
* TSC 타입 체크 명령어
|