sonamu 0.5.7 → 0.6.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/dist/api/base-frame.js +12 -2
- package/dist/api/caster.js +66 -2
- package/dist/api/code-converters.js +489 -2
- package/dist/api/config.d.ts +76 -0
- package/dist/api/config.d.ts.map +1 -0
- package/dist/api/config.js +32 -0
- package/dist/api/context.d.ts +1 -0
- package/dist/api/context.d.ts.map +1 -1
- package/dist/api/context.js +3 -2
- package/dist/api/decorators.d.ts.map +1 -1
- package/dist/api/decorators.js +142 -2
- package/dist/api/index.js +9 -2
- package/dist/api/sonamu.d.ts +8 -22
- package/dist/api/sonamu.d.ts.map +1 -1
- package/dist/api/sonamu.js +482 -2
- package/dist/bin/build-config.d.ts +2 -1
- package/dist/bin/build-config.d.ts.map +1 -1
- package/dist/bin/build-config.js +12 -2
- package/dist/bin/cli-wrapper.js +71 -2
- package/dist/bin/cli.js +418 -2
- package/dist/bin/hot-hook-register.d.ts +11 -0
- package/dist/bin/hot-hook-register.d.ts.map +1 -0
- package/dist/bin/hot-hook-register.js +21 -0
- package/dist/database/_batch_update.js +78 -2
- package/dist/database/base-model.js +247 -2
- package/dist/database/code-generator.js +53 -2
- package/dist/database/db.d.ts +2 -16
- package/dist/database/db.d.ts.map +1 -1
- package/dist/database/db.js +132 -2
- package/dist/database/knex-plugins/knex-on-duplicate-update.js +39 -2
- package/dist/database/puri-wrapper.js +109 -2
- package/dist/database/puri.d.ts +23 -16
- package/dist/database/puri.d.ts.map +1 -1
- package/dist/database/puri.js +539 -2
- package/dist/database/puri.types.d.ts +8 -3
- package/dist/database/puri.types.d.ts.map +1 -1
- package/dist/database/puri.types.js +3 -2
- package/dist/database/transaction-context.js +14 -2
- package/dist/database/upsert-builder.js +215 -2
- package/dist/entity/entity-manager.d.ts +3 -1
- package/dist/entity/entity-manager.d.ts.map +1 -1
- package/dist/entity/entity-manager.js +114 -2
- package/dist/entity/entity-utils.js +210 -2
- package/dist/entity/entity.d.ts.map +1 -1
- package/dist/entity/entity.js +651 -2
- package/dist/exceptions/error-handler.js +29 -2
- package/dist/exceptions/so-exceptions.js +85 -2
- package/dist/file-storage/driver.js +79 -2
- package/dist/file-storage/file-storage.js +75 -2
- package/dist/index.d.ts +2 -0
- package/dist/index.d.ts.map +1 -1
- package/dist/index.js +28 -2
- package/dist/migration/code-generation.js +558 -2
- package/dist/migration/migration-set.js +364 -2
- package/dist/migration/migrator.d.ts +0 -9
- package/dist/migration/migrator.d.ts.map +1 -1
- package/dist/migration/migrator.js +510 -2
- package/dist/migration/types.js +3 -2
- package/dist/naite/naite.d.ts +12 -0
- package/dist/naite/naite.d.ts.map +1 -0
- package/dist/naite/naite.js +72 -0
- package/dist/stream/index.js +3 -2
- package/dist/stream/sse.js +38 -2
- package/dist/syncer/api-parser.d.ts +20 -0
- package/dist/syncer/api-parser.d.ts.map +1 -0
- package/dist/syncer/api-parser.js +229 -0
- package/dist/syncer/checksum.d.ts +21 -0
- package/dist/syncer/checksum.d.ts.map +1 -0
- package/dist/syncer/checksum.js +98 -0
- package/dist/syncer/code-generator.d.ts +20 -0
- package/dist/syncer/code-generator.d.ts.map +1 -0
- package/dist/syncer/code-generator.js +141 -0
- package/dist/syncer/entity-operations.d.ts +17 -0
- package/dist/syncer/entity-operations.d.ts.map +1 -0
- package/dist/syncer/entity-operations.js +58 -0
- package/dist/syncer/file-patterns.d.ts +29 -0
- package/dist/syncer/file-patterns.d.ts.map +1 -0
- package/dist/syncer/file-patterns.js +38 -0
- package/dist/syncer/index.d.ts +6 -0
- package/dist/syncer/index.d.ts.map +1 -1
- package/dist/syncer/index.js +9 -2
- package/dist/syncer/module-loader.d.ts +35 -0
- package/dist/syncer/module-loader.d.ts.map +1 -0
- package/dist/syncer/module-loader.js +82 -0
- package/dist/syncer/syncer.d.ts +93 -108
- package/dist/syncer/syncer.d.ts.map +1 -1
- package/dist/syncer/syncer.js +375 -2
- package/dist/template/entity-converter.d.ts +14 -0
- package/dist/template/entity-converter.d.ts.map +1 -0
- package/dist/template/entity-converter.js +101 -0
- package/dist/template/helpers.d.ts +23 -0
- package/dist/template/helpers.d.ts.map +1 -0
- package/dist/template/helpers.js +64 -0
- package/dist/{templates → template/implementations}/entity.template.d.ts +3 -3
- package/dist/template/implementations/entity.template.d.ts.map +1 -0
- package/dist/template/implementations/entity.template.js +87 -0
- package/dist/{templates → template/implementations}/generated.template.d.ts +3 -3
- package/dist/template/implementations/generated.template.d.ts.map +1 -0
- package/dist/template/implementations/generated.template.js +232 -0
- package/dist/{templates → template/implementations}/generated_http.template.d.ts +3 -3
- package/dist/template/implementations/generated_http.template.d.ts.map +1 -0
- package/dist/template/implementations/generated_http.template.js +131 -0
- package/dist/{templates → template/implementations}/generated_sso.template.d.ts +3 -3
- package/dist/template/implementations/generated_sso.template.d.ts.map +1 -0
- package/dist/template/implementations/generated_sso.template.js +105 -0
- package/dist/{templates → template/implementations}/init_types.template.d.ts +3 -3
- package/dist/template/implementations/init_types.template.d.ts.map +1 -0
- package/dist/template/implementations/init_types.template.js +38 -0
- package/dist/template/implementations/model.template.d.ts +17 -0
- package/dist/template/implementations/model.template.d.ts.map +1 -0
- package/dist/template/implementations/model.template.js +171 -0
- package/dist/{templates → template/implementations}/model_test.template.d.ts +3 -3
- package/dist/template/implementations/model_test.template.d.ts.map +1 -0
- package/dist/template/implementations/model_test.template.js +35 -0
- package/dist/{templates → template/implementations}/service.template.d.ts +6 -6
- package/dist/template/implementations/service.template.d.ts.map +1 -0
- package/dist/template/implementations/service.template.js +193 -0
- package/dist/{templates → template/implementations}/view_enums_buttonset.template.d.ts +3 -3
- package/dist/template/implementations/view_enums_buttonset.template.d.ts.map +1 -0
- package/dist/template/implementations/view_enums_buttonset.template.js +31 -0
- package/dist/{templates → template/implementations}/view_enums_dropdown.template.d.ts +3 -4
- package/dist/template/implementations/view_enums_dropdown.template.d.ts.map +1 -0
- package/dist/template/implementations/view_enums_dropdown.template.js +50 -0
- package/dist/{templates → template/implementations}/view_enums_select.template.d.ts +3 -3
- package/dist/template/implementations/view_enums_select.template.d.ts.map +1 -0
- package/dist/template/implementations/view_enums_select.template.js +55 -0
- package/dist/{templates → template/implementations}/view_form.template.d.ts +5 -5
- package/dist/template/implementations/view_form.template.d.ts.map +1 -0
- package/dist/template/implementations/view_form.template.js +337 -0
- package/dist/{templates → template/implementations}/view_id_all_select.template.d.ts +3 -3
- package/dist/template/implementations/view_id_all_select.template.d.ts.map +1 -0
- package/dist/template/implementations/view_id_all_select.template.js +31 -0
- package/dist/{templates → template/implementations}/view_id_async_select.template.d.ts +3 -3
- package/dist/template/implementations/view_id_async_select.template.d.ts.map +1 -0
- package/dist/template/implementations/view_id_async_select.template.js +105 -0
- package/dist/{templates → template/implementations}/view_list.template.d.ts +5 -13
- package/dist/template/implementations/view_list.template.d.ts.map +1 -0
- package/dist/template/implementations/view_list.template.js +465 -0
- package/dist/{templates → template/implementations}/view_list_columns.template.d.ts +3 -3
- package/dist/template/implementations/view_list_columns.template.d.ts.map +1 -0
- package/dist/template/implementations/view_list_columns.template.js +49 -0
- package/dist/{templates → template/implementations}/view_search_input.template.d.ts +3 -3
- package/dist/template/implementations/view_search_input.template.d.ts.map +1 -0
- package/dist/template/implementations/view_search_input.template.js +64 -0
- package/dist/template/index.d.ts +5 -0
- package/dist/template/index.d.ts.map +1 -0
- package/dist/template/index.js +6 -0
- package/dist/template/template.d.ts +39 -0
- package/dist/template/template.d.ts.map +1 -0
- package/dist/template/template.js +47 -0
- package/dist/template/zod-converter.d.ts +18 -0
- package/dist/template/zod-converter.d.ts.map +1 -0
- package/dist/template/zod-converter.js +166 -0
- package/dist/testing/_relation-graph.js +80 -2
- package/dist/testing/fixture-manager.d.ts.map +1 -1
- package/dist/testing/fixture-manager.js +521 -2
- package/dist/types/types.d.ts +39 -40
- package/dist/types/types.d.ts.map +1 -1
- package/dist/types/types.js +289 -2
- package/dist/typings/knex.d.js +3 -2
- package/dist/utils/async-utils.d.ts +7 -0
- package/dist/utils/async-utils.d.ts.map +1 -1
- package/dist/utils/async-utils.js +57 -2
- package/dist/utils/console-util.d.ts +2 -0
- package/dist/utils/console-util.d.ts.map +1 -0
- package/dist/utils/console-util.js +6 -0
- package/dist/utils/controller.js +26 -2
- package/dist/utils/esm-utils.d.ts +45 -0
- package/dist/utils/esm-utils.d.ts.map +1 -0
- package/dist/utils/esm-utils.js +56 -0
- package/dist/utils/fs-utils.js +17 -2
- package/dist/utils/lodash-able.js +6 -2
- package/dist/utils/model.js +22 -2
- package/dist/utils/path-utils.d.ts +89 -0
- package/dist/utils/path-utils.d.ts.map +1 -0
- package/dist/utils/path-utils.js +60 -0
- package/dist/utils/process-utils.d.ts +13 -0
- package/dist/utils/process-utils.d.ts.map +1 -0
- package/dist/utils/process-utils.js +36 -0
- package/dist/utils/sql-parser.js +35 -2
- package/dist/utils/utils.d.ts +4 -7
- package/dist/utils/utils.d.ts.map +1 -1
- package/dist/utils/utils.js +33 -2
- package/dist/utils/zod-error.d.ts.map +1 -1
- package/dist/utils/zod-error.js +19 -2
- package/package.json +21 -8
- package/src/api/code-converters.ts +2 -2
- package/src/api/config.ts +142 -0
- package/src/api/context.ts +1 -0
- package/src/api/decorators.ts +1 -0
- package/src/api/sonamu.ts +81 -67
- package/src/bin/build-config.ts +2 -1
- package/src/bin/cli-wrapper.ts +10 -3
- package/src/bin/cli.ts +108 -56
- package/src/bin/hot-hook-register.ts +22 -0
- package/src/database/base-model.ts +1 -1
- package/src/database/code-generator.ts +1 -1
- package/src/database/db.ts +10 -52
- package/src/database/puri.ts +78 -53
- package/src/database/puri.types.ts +18 -5
- package/src/database/upsert-builder.ts +1 -1
- package/src/entity/entity-manager.ts +19 -15
- package/src/entity/entity.ts +4 -3
- package/src/index.ts +2 -0
- package/src/migration/code-generation.ts +1 -1
- package/src/migration/migration-set.ts +1 -1
- package/src/migration/migrator.ts +23 -152
- package/src/naite/naite.ts +70 -0
- package/src/syncer/api-parser.ts +299 -0
- package/src/syncer/checksum.ts +152 -0
- package/src/syncer/code-generator.ts +202 -0
- package/src/syncer/entity-operations.ts +68 -0
- package/src/syncer/file-patterns.ts +56 -0
- package/src/syncer/index.ts +6 -0
- package/src/syncer/module-loader.ts +125 -0
- package/src/syncer/syncer.ts +363 -1420
- package/src/template/entity-converter.ts +123 -0
- package/src/template/helpers.ts +84 -0
- package/src/{templates → template/implementations}/entity.template.ts +4 -4
- package/src/{templates → template/implementations}/generated.template.ts +9 -9
- package/src/{templates → template/implementations}/generated_http.template.ts +9 -6
- package/src/{templates → template/implementations}/generated_sso.template.ts +7 -7
- package/src/{templates → template/implementations}/init_types.template.ts +4 -4
- package/src/{templates → template/implementations}/model.template.ts +9 -9
- package/src/{templates → template/implementations}/model_test.template.ts +5 -5
- package/src/{templates → template/implementations}/service.template.ts +19 -11
- package/src/{templates → template/implementations}/view_enums_buttonset.template.ts +3 -3
- package/src/{templates → template/implementations}/view_enums_dropdown.template.ts +5 -21
- package/src/{templates → template/implementations}/view_enums_select.template.ts +4 -4
- package/src/{templates → template/implementations}/view_form.template.ts +11 -13
- package/src/{templates → template/implementations}/view_id_all_select.template.ts +3 -3
- package/src/{templates → template/implementations}/view_id_async_select.template.ts +3 -3
- package/src/{templates → template/implementations}/view_list.template.ts +13 -64
- package/src/{templates → template/implementations}/view_list_columns.template.ts +3 -3
- package/src/{templates → template/implementations}/view_search_input.template.ts +3 -3
- package/src/template/index.ts +4 -0
- package/src/template/template.ts +86 -0
- package/src/template/zod-converter.ts +219 -0
- package/src/testing/fixture-manager.ts +8 -1
- package/src/types/types.ts +38 -61
- package/src/utils/async-utils.ts +17 -0
- package/src/utils/console-util.ts +4 -0
- package/src/utils/esm-utils.ts +69 -0
- package/src/utils/path-utils.ts +102 -0
- package/src/utils/process-utils.ts +46 -0
- package/src/utils/sql-parser.ts +1 -1
- package/src/utils/utils.ts +14 -40
- package/src/utils/zod-error.ts +0 -1
- package/dist/api/base-frame.js.map +0 -1
- package/dist/api/caster.js.map +0 -1
- package/dist/api/code-converters.js.map +0 -1
- package/dist/api/context.js.map +0 -1
- package/dist/api/decorators.js.map +0 -1
- package/dist/api/index.js.map +0 -1
- package/dist/api/sonamu.js.map +0 -1
- package/dist/bin/build-config.js.map +0 -1
- package/dist/bin/cli-wrapper.js.map +0 -1
- package/dist/bin/cli.js.map +0 -1
- package/dist/database/_batch_update.js.map +0 -1
- package/dist/database/base-model.js.map +0 -1
- package/dist/database/code-generator.js.map +0 -1
- package/dist/database/db.js.map +0 -1
- package/dist/database/knex-plugins/knex-on-duplicate-update.js.map +0 -1
- package/dist/database/puri-wrapper.js.map +0 -1
- package/dist/database/puri.js.map +0 -1
- package/dist/database/puri.types.js.map +0 -1
- package/dist/database/transaction-context.js.map +0 -1
- package/dist/database/upsert-builder.js.map +0 -1
- package/dist/entity/entity-manager.js.map +0 -1
- package/dist/entity/entity-utils.js.map +0 -1
- package/dist/entity/entity.js.map +0 -1
- package/dist/exceptions/error-handler.js.map +0 -1
- package/dist/exceptions/so-exceptions.js.map +0 -1
- package/dist/file-storage/driver.js.map +0 -1
- package/dist/file-storage/file-storage.js.map +0 -1
- package/dist/index.js.map +0 -1
- package/dist/migration/code-generation.js.map +0 -1
- package/dist/migration/migration-set.js.map +0 -1
- package/dist/migration/migrator.js.map +0 -1
- package/dist/migration/types.js.map +0 -1
- package/dist/stream/index.js.map +0 -1
- package/dist/stream/sse.js.map +0 -1
- package/dist/syncer/index.js.map +0 -1
- package/dist/syncer/syncer.js.map +0 -1
- package/dist/templates/base-template.d.ts +0 -13
- package/dist/templates/base-template.d.ts.map +0 -1
- package/dist/templates/base-template.js +0 -2
- package/dist/templates/base-template.js.map +0 -1
- package/dist/templates/entity.template.d.ts.map +0 -1
- package/dist/templates/entity.template.js +0 -2
- package/dist/templates/entity.template.js.map +0 -1
- package/dist/templates/generated.template.d.ts.map +0 -1
- package/dist/templates/generated.template.js +0 -2
- package/dist/templates/generated.template.js.map +0 -1
- package/dist/templates/generated_http.template.d.ts.map +0 -1
- package/dist/templates/generated_http.template.js +0 -2
- package/dist/templates/generated_http.template.js.map +0 -1
- package/dist/templates/generated_sso.template.d.ts.map +0 -1
- package/dist/templates/generated_sso.template.js +0 -2
- package/dist/templates/generated_sso.template.js.map +0 -1
- package/dist/templates/index.d.ts +0 -2
- package/dist/templates/index.d.ts.map +0 -1
- package/dist/templates/index.js +0 -2
- package/dist/templates/index.js.map +0 -1
- package/dist/templates/init_types.template.d.ts.map +0 -1
- package/dist/templates/init_types.template.js +0 -2
- package/dist/templates/init_types.template.js.map +0 -1
- package/dist/templates/model.template.d.ts +0 -17
- package/dist/templates/model.template.d.ts.map +0 -1
- package/dist/templates/model.template.js +0 -2
- package/dist/templates/model.template.js.map +0 -1
- package/dist/templates/model_test.template.d.ts.map +0 -1
- package/dist/templates/model_test.template.js +0 -2
- package/dist/templates/model_test.template.js.map +0 -1
- package/dist/templates/service.template.d.ts.map +0 -1
- package/dist/templates/service.template.js +0 -2
- package/dist/templates/service.template.js.map +0 -1
- package/dist/templates/view_enums_buttonset.template.d.ts.map +0 -1
- package/dist/templates/view_enums_buttonset.template.js +0 -2
- package/dist/templates/view_enums_buttonset.template.js.map +0 -1
- package/dist/templates/view_enums_dropdown.template.d.ts.map +0 -1
- package/dist/templates/view_enums_dropdown.template.js +0 -2
- package/dist/templates/view_enums_dropdown.template.js.map +0 -1
- package/dist/templates/view_enums_select.template.d.ts.map +0 -1
- package/dist/templates/view_enums_select.template.js +0 -2
- package/dist/templates/view_enums_select.template.js.map +0 -1
- package/dist/templates/view_form.template.d.ts.map +0 -1
- package/dist/templates/view_form.template.js +0 -2
- package/dist/templates/view_form.template.js.map +0 -1
- package/dist/templates/view_id_all_select.template.d.ts.map +0 -1
- package/dist/templates/view_id_all_select.template.js +0 -2
- package/dist/templates/view_id_all_select.template.js.map +0 -1
- package/dist/templates/view_id_async_select.template.d.ts.map +0 -1
- package/dist/templates/view_id_async_select.template.js +0 -2
- package/dist/templates/view_id_async_select.template.js.map +0 -1
- package/dist/templates/view_list.template.d.ts.map +0 -1
- package/dist/templates/view_list.template.js +0 -2
- package/dist/templates/view_list.template.js.map +0 -1
- package/dist/templates/view_list_columns.template.d.ts.map +0 -1
- package/dist/templates/view_list_columns.template.js +0 -2
- package/dist/templates/view_list_columns.template.js.map +0 -1
- package/dist/templates/view_search_input.template.d.ts.map +0 -1
- package/dist/templates/view_search_input.template.js +0 -2
- package/dist/templates/view_search_input.template.js.map +0 -1
- package/dist/testing/_relation-graph.js.map +0 -1
- package/dist/testing/fixture-manager.js.map +0 -1
- package/dist/types/types.js.map +0 -1
- package/dist/typings/knex.d.js.map +0 -1
- package/dist/utils/async-utils.js.map +0 -1
- package/dist/utils/controller.js.map +0 -1
- package/dist/utils/fs-utils.js.map +0 -1
- package/dist/utils/lodash-able.js.map +0 -1
- package/dist/utils/model.js.map +0 -1
- package/dist/utils/sql-parser.js.map +0 -1
- package/dist/utils/utils.js.map +0 -1
- package/dist/utils/zod-error.js.map +0 -1
- package/src/templates/base-template.ts +0 -19
- package/src/templates/index.ts +0 -1
package/dist/utils/utils.js
CHANGED
|
@@ -1,2 +1,33 @@
|
|
|
1
|
-
|
|
2
|
-
|
|
1
|
+
import path from "path";
|
|
2
|
+
import fs from "fs";
|
|
3
|
+
export async function findAppRootPath() {
|
|
4
|
+
const apiRootPath = findApiRootPath();
|
|
5
|
+
return apiRootPath.split(path.sep).slice(0, -1).join(path.sep);
|
|
6
|
+
}
|
|
7
|
+
export function findApiRootPath() {
|
|
8
|
+
// NOTE: for support npm / yarn workspaces
|
|
9
|
+
const workspacePath = process.env["INIT_CWD"];
|
|
10
|
+
if (workspacePath && workspacePath.length !== 0) {
|
|
11
|
+
return workspacePath;
|
|
12
|
+
}
|
|
13
|
+
const basePath = import.meta.filename;
|
|
14
|
+
let dir = path.dirname(basePath);
|
|
15
|
+
if (dir.includes("/.yarn/")) {
|
|
16
|
+
dir = dir.split("/.yarn/")[0];
|
|
17
|
+
}
|
|
18
|
+
do {
|
|
19
|
+
if (fs.existsSync(path.join(dir, "/package.json"))) {
|
|
20
|
+
return dir.split(path.sep).join(path.sep);
|
|
21
|
+
}
|
|
22
|
+
dir = dir.split(path.sep).slice(0, -1).join(path.sep);
|
|
23
|
+
}while (dir.split(path.sep).length > 1)
|
|
24
|
+
throw new Error("Cannot find AppRoot using Sonamu -2");
|
|
25
|
+
}
|
|
26
|
+
export function nonNullable(value) {
|
|
27
|
+
return value !== null && value !== undefined;
|
|
28
|
+
}
|
|
29
|
+
export function exhaustive(_param) {
|
|
30
|
+
throw new Error(`exhaustive`);
|
|
31
|
+
}
|
|
32
|
+
|
|
33
|
+
//# sourceMappingURL=data:application/json;base64,eyJ2ZXJzaW9uIjozLCJzb3VyY2VzIjpbIi4uLy4uL3NyYy91dGlscy91dGlscy50cyJdLCJzb3VyY2VzQ29udGVudCI6WyJpbXBvcnQgcGF0aCBmcm9tIFwicGF0aFwiO1xuaW1wb3J0IGZzIGZyb20gXCJmc1wiO1xuaW1wb3J0IHsgQWJzb2x1dGVQYXRoIH0gZnJvbSBcIi4vcGF0aC11dGlsc1wiO1xuXG5leHBvcnQgYXN5bmMgZnVuY3Rpb24gZmluZEFwcFJvb3RQYXRoKCk6IFByb21pc2U8QWJzb2x1dGVQYXRoPiB7XG4gIGNvbnN0IGFwaVJvb3RQYXRoID0gZmluZEFwaVJvb3RQYXRoKCk7XG4gIHJldHVybiBhcGlSb290UGF0aFxuICAgIC5zcGxpdChwYXRoLnNlcClcbiAgICAuc2xpY2UoMCwgLTEpXG4gICAgLmpvaW4ocGF0aC5zZXApIGFzIEFic29sdXRlUGF0aDtcbn1cblxuZXhwb3J0IGZ1bmN0aW9uIGZpbmRBcGlSb290UGF0aCgpOiBBYnNvbHV0ZVBhdGgge1xuICAvLyBOT1RFOiBmb3Igc3VwcG9ydCBucG0gLyB5YXJuIHdvcmtzcGFjZXNcbiAgY29uc3Qgd29ya3NwYWNlUGF0aCA9IHByb2Nlc3MuZW52W1wiSU5JVF9DV0RcIl07XG4gIGlmICh3b3Jrc3BhY2VQYXRoICYmIHdvcmtzcGFjZVBhdGgubGVuZ3RoICE9PSAwKSB7XG4gICAgcmV0dXJuIHdvcmtzcGFjZVBhdGggYXMgQWJzb2x1dGVQYXRoO1xuICB9XG5cbiAgY29uc3QgYmFzZVBhdGggPSBpbXBvcnQubWV0YS5maWxlbmFtZTtcbiAgbGV0IGRpciA9IHBhdGguZGlybmFtZShiYXNlUGF0aCk7XG4gIGlmIChkaXIuaW5jbHVkZXMoXCIvLnlhcm4vXCIpKSB7XG4gICAgZGlyID0gZGlyLnNwbGl0KFwiLy55YXJuL1wiKVswXTtcbiAgfVxuICBkbyB7XG4gICAgaWYgKGZzLmV4aXN0c1N5bmMocGF0aC5qb2luKGRpciwgXCIvcGFja2FnZS5qc29uXCIpKSkge1xuICAgICAgcmV0dXJuIGRpci5zcGxpdChwYXRoLnNlcCkuam9pbihwYXRoLnNlcCkgYXMgQWJzb2x1dGVQYXRoO1xuICAgIH1cbiAgICBkaXIgPSBkaXIuc3BsaXQocGF0aC5zZXApLnNsaWNlKDAsIC0xKS5qb2luKHBhdGguc2VwKTtcbiAgfSB3aGlsZSAoZGlyLnNwbGl0KHBhdGguc2VwKS5sZW5ndGggPiAxKTtcbiAgdGhyb3cgbmV3IEVycm9yKFwiQ2Fubm90IGZpbmQgQXBwUm9vdCB1c2luZyBTb25hbXUgLTJcIik7XG59XG5cbmV4cG9ydCBmdW5jdGlvbiBub25OdWxsYWJsZTxUPih2YWx1ZTogVCk6IHZhbHVlIGlzIE5vbk51bGxhYmxlPFQ+IHtcbiAgcmV0dXJuIHZhbHVlICE9PSBudWxsICYmIHZhbHVlICE9PSB1bmRlZmluZWQ7XG59XG5cbmV4cG9ydCBmdW5jdGlvbiBleGhhdXN0aXZlKF9wYXJhbTogbmV2ZXIpIHtcbiAgdGhyb3cgbmV3IEVycm9yKGBleGhhdXN0aXZlYCk7XG59XG4iXSwibmFtZXMiOlsicGF0aCIsImZzIiwiZmluZEFwcFJvb3RQYXRoIiwiYXBpUm9vdFBhdGgiLCJmaW5kQXBpUm9vdFBhdGgiLCJzcGxpdCIsInNlcCIsInNsaWNlIiwiam9pbiIsIndvcmtzcGFjZVBhdGgiLCJwcm9jZXNzIiwiZW52IiwibGVuZ3RoIiwiYmFzZVBhdGgiLCJmaWxlbmFtZSIsImRpciIsImRpcm5hbWUiLCJpbmNsdWRlcyIsImV4aXN0c1N5bmMiLCJFcnJvciIsIm5vbk51bGxhYmxlIiwidmFsdWUiLCJ1bmRlZmluZWQiLCJleGhhdXN0aXZlIiwiX3BhcmFtIl0sIm1hcHBpbmdzIjoiQUFBQSxPQUFPQSxVQUFVLE9BQU87QUFDeEIsT0FBT0MsUUFBUSxLQUFLO0FBR3BCLE9BQU8sZUFBZUM7SUFDcEIsTUFBTUMsY0FBY0M7SUFDcEIsT0FBT0QsWUFDSkUsS0FBSyxDQUFDTCxLQUFLTSxHQUFHLEVBQ2RDLEtBQUssQ0FBQyxHQUFHLENBQUMsR0FDVkMsSUFBSSxDQUFDUixLQUFLTSxHQUFHO0FBQ2xCO0FBRUEsT0FBTyxTQUFTRjtJQUNkLDBDQUEwQztJQUMxQyxNQUFNSyxnQkFBZ0JDLFFBQVFDLEdBQUcsQ0FBQyxXQUFXO0lBQzdDLElBQUlGLGlCQUFpQkEsY0FBY0csTUFBTSxLQUFLLEdBQUc7UUFDL0MsT0FBT0g7SUFDVDtJQUVBLE1BQU1JLFdBQVcsWUFBWUMsUUFBUTtJQUNyQyxJQUFJQyxNQUFNZixLQUFLZ0IsT0FBTyxDQUFDSDtJQUN2QixJQUFJRSxJQUFJRSxRQUFRLENBQUMsWUFBWTtRQUMzQkYsTUFBTUEsSUFBSVYsS0FBSyxDQUFDLFVBQVUsQ0FBQyxFQUFFO0lBQy9CO0lBQ0EsR0FBRztRQUNELElBQUlKLEdBQUdpQixVQUFVLENBQUNsQixLQUFLUSxJQUFJLENBQUNPLEtBQUssbUJBQW1CO1lBQ2xELE9BQU9BLElBQUlWLEtBQUssQ0FBQ0wsS0FBS00sR0FBRyxFQUFFRSxJQUFJLENBQUNSLEtBQUtNLEdBQUc7UUFDMUM7UUFDQVMsTUFBTUEsSUFBSVYsS0FBSyxDQUFDTCxLQUFLTSxHQUFHLEVBQUVDLEtBQUssQ0FBQyxHQUFHLENBQUMsR0FBR0MsSUFBSSxDQUFDUixLQUFLTSxHQUFHO0lBQ3RELFFBQVNTLElBQUlWLEtBQUssQ0FBQ0wsS0FBS00sR0FBRyxFQUFFTSxNQUFNLEdBQUcsRUFBRztJQUN6QyxNQUFNLElBQUlPLE1BQU07QUFDbEI7QUFFQSxPQUFPLFNBQVNDLFlBQWVDLEtBQVE7SUFDckMsT0FBT0EsVUFBVSxRQUFRQSxVQUFVQztBQUNyQztBQUVBLE9BQU8sU0FBU0MsV0FBV0MsTUFBYTtJQUN0QyxNQUFNLElBQUlMLE1BQU0sQ0FBQyxVQUFVLENBQUM7QUFDOUIifQ==
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"zod-error.d.ts","sourceRoot":"","sources":["../../src/utils/zod-error.ts"],"names":[],"mappings":"
|
|
1
|
+
{"version":3,"file":"zod-error.d.ts","sourceRoot":"","sources":["../../src/utils/zod-error.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,CAAC,EAAE,MAAM,KAAK,CAAC;AAExB,KAAK,eAAe,GAAG;IACrB,IAAI,EAAE,MAAM,EAAE,CAAC;IACf,OAAO,EAAE,MAAM,CAAC;CACjB,CAAC;AAEF,wBAAgB,gBAAgB,CAAC,KAAK,EAAE,CAAC,CAAC,QAAQ,GAAG,eAAe,EAAE,CAgBrE"}
|
package/dist/utils/zod-error.js
CHANGED
|
@@ -1,2 +1,19 @@
|
|
|
1
|
-
|
|
2
|
-
|
|
1
|
+
export function humanizeZodError(error) {
|
|
2
|
+
return error.issues.map(({ path: originPath, message })=>{
|
|
3
|
+
const path = originPath.map((item)=>{
|
|
4
|
+
if (typeof item === "symbol") {
|
|
5
|
+
return item.description ?? item.toString();
|
|
6
|
+
}
|
|
7
|
+
if (typeof item === "number") {
|
|
8
|
+
return `[${item}]`;
|
|
9
|
+
}
|
|
10
|
+
return item;
|
|
11
|
+
});
|
|
12
|
+
return {
|
|
13
|
+
path,
|
|
14
|
+
message: message
|
|
15
|
+
};
|
|
16
|
+
});
|
|
17
|
+
}
|
|
18
|
+
|
|
19
|
+
//# sourceMappingURL=data:application/json;base64,eyJ2ZXJzaW9uIjozLCJzb3VyY2VzIjpbIi4uLy4uL3NyYy91dGlscy96b2QtZXJyb3IudHMiXSwic291cmNlc0NvbnRlbnQiOlsiaW1wb3J0IHsgeiB9IGZyb20gJ3pvZCc7XG5cbnR5cGUgVmFsaWRhdGlvbkVycm9yID0ge1xuICBwYXRoOiBzdHJpbmdbXTtcbiAgbWVzc2FnZTogc3RyaW5nO1xufTtcblxuZXhwb3J0IGZ1bmN0aW9uIGh1bWFuaXplWm9kRXJyb3IoZXJyb3I6IHouWm9kRXJyb3IpOiBWYWxpZGF0aW9uRXJyb3JbXSB7XG4gIHJldHVybiBlcnJvci5pc3N1ZXMubWFwKCh7ICBwYXRoOiBvcmlnaW5QYXRoLCBtZXNzYWdlIH0pID0+IHtcbiAgICBjb25zdCBwYXRoID0gb3JpZ2luUGF0aC5tYXAoaXRlbSA9PiB7XG4gICAgICBpZiAodHlwZW9mIGl0ZW0gPT09IFwic3ltYm9sXCIpIHtcbiAgICAgICAgcmV0dXJuIGl0ZW0uZGVzY3JpcHRpb24gPz8gaXRlbS50b1N0cmluZygpO1xuICAgICAgfVxuXG4gICAgICBpZiAodHlwZW9mIGl0ZW0gPT09IFwibnVtYmVyXCIpIHtcbiAgICAgICAgcmV0dXJuIGBbJHtpdGVtfV1gO1xuICAgICAgfVxuXG4gICAgICByZXR1cm4gaXRlbTtcbiAgICB9KTtcblxuICAgIHJldHVybiB7IHBhdGgsIG1lc3NhZ2U6IG1lc3NhZ2UgfTtcbiAgfSk7XG59XG4iXSwibmFtZXMiOlsiaHVtYW5pemVab2RFcnJvciIsImVycm9yIiwiaXNzdWVzIiwibWFwIiwicGF0aCIsIm9yaWdpblBhdGgiLCJtZXNzYWdlIiwiaXRlbSIsImRlc2NyaXB0aW9uIiwidG9TdHJpbmciXSwibWFwcGluZ3MiOiJBQU9BLE9BQU8sU0FBU0EsaUJBQWlCQyxLQUFpQjtJQUNoRCxPQUFPQSxNQUFNQyxNQUFNLENBQUNDLEdBQUcsQ0FBQyxDQUFDLEVBQUdDLE1BQU1DLFVBQVUsRUFBRUMsT0FBTyxFQUFFO1FBQ3JELE1BQU1GLE9BQU9DLFdBQVdGLEdBQUcsQ0FBQ0ksQ0FBQUE7WUFDMUIsSUFBSSxPQUFPQSxTQUFTLFVBQVU7Z0JBQzVCLE9BQU9BLEtBQUtDLFdBQVcsSUFBSUQsS0FBS0UsUUFBUTtZQUMxQztZQUVBLElBQUksT0FBT0YsU0FBUyxVQUFVO2dCQUM1QixPQUFPLENBQUMsQ0FBQyxFQUFFQSxLQUFLLENBQUMsQ0FBQztZQUNwQjtZQUVBLE9BQU9BO1FBQ1Q7UUFFQSxPQUFPO1lBQUVIO1lBQU1FLFNBQVNBO1FBQVE7SUFDbEM7QUFDRiJ9
|
package/package.json
CHANGED
|
@@ -1,17 +1,25 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "sonamu",
|
|
3
|
-
"version": "0.
|
|
3
|
+
"version": "0.6.0",
|
|
4
4
|
"description": "Sonamu — TypeScript Fullstack API Framework",
|
|
5
5
|
"keywords": [
|
|
6
6
|
"typescript",
|
|
7
7
|
"framework",
|
|
8
8
|
"orm"
|
|
9
9
|
],
|
|
10
|
-
"
|
|
11
|
-
"exports":
|
|
10
|
+
"type": "module",
|
|
11
|
+
"exports": {
|
|
12
|
+
".": {
|
|
13
|
+
"import": "./dist/index.js",
|
|
14
|
+
"types": "./dist/index.d.ts"
|
|
15
|
+
},
|
|
16
|
+
"./hot-hook-register": {
|
|
17
|
+
"default": "./dist/bin/hot-hook-register.js"
|
|
18
|
+
}
|
|
19
|
+
},
|
|
12
20
|
"scripts": {
|
|
13
21
|
"dev": "nodemon exec",
|
|
14
|
-
"build": "swc src
|
|
22
|
+
"build": "rm -rf dist && swc src -d dist --strip-leading-paths && tsc --emitDeclarationOnly",
|
|
15
23
|
"publish": "yarn build && yarn npm publish"
|
|
16
24
|
},
|
|
17
25
|
"license": "MIT",
|
|
@@ -52,6 +60,7 @@
|
|
|
52
60
|
"inflection": "^1.13.2",
|
|
53
61
|
"knex": "^3.1.0",
|
|
54
62
|
"lodash": "^4.17.21",
|
|
63
|
+
"lodash-es": "^4.17.21",
|
|
55
64
|
"luxon": "^3.0.3",
|
|
56
65
|
"mime-types": "^3.0.1",
|
|
57
66
|
"minimatch": "^10.0.3",
|
|
@@ -60,15 +69,16 @@
|
|
|
60
69
|
"nodemon": "^3.1.10",
|
|
61
70
|
"prompts": "^2.4.2",
|
|
62
71
|
"qs": "^6.11.0",
|
|
63
|
-
"source-map-support": "^0.5.21",
|
|
64
72
|
"tsicli": "^1.0.5",
|
|
65
73
|
"zod": "^4.1.12"
|
|
66
74
|
},
|
|
67
75
|
"devDependencies": {
|
|
68
|
-
"@sonamu-kit/
|
|
76
|
+
"@sonamu-kit/hot-hook": "^0.4.1",
|
|
77
|
+
"@sonamu-kit/ui": "^0.6.0",
|
|
69
78
|
"@swc/cli": "^0.7.8",
|
|
70
79
|
"@types/inflection": "^1.13.0",
|
|
71
80
|
"@types/lodash": "^4.14.198",
|
|
81
|
+
"@types/lodash-es": "^4.17.12",
|
|
72
82
|
"@types/luxon": "^3.0.1",
|
|
73
83
|
"@types/mime-types": "^3.0.1",
|
|
74
84
|
"@types/node": "^22",
|
|
@@ -80,10 +90,13 @@
|
|
|
80
90
|
"typescript": "^5.2.2"
|
|
81
91
|
},
|
|
82
92
|
"peerDependencies": {
|
|
93
|
+
"@sonamu-kit/hot-runner": "^0.1.1",
|
|
94
|
+
"@sonamu-kit/loader": "^2.1.2",
|
|
95
|
+
"@swc/cli": "^0.7.8",
|
|
96
|
+
"@swc/core": "^1.13.5",
|
|
83
97
|
"fastify": "^4.23.2",
|
|
84
98
|
"knex": "^3.1.0",
|
|
85
99
|
"mysql2": "^3.6.1",
|
|
86
|
-
"nodemon": "3.1.10"
|
|
87
|
-
"source-map-support": "^0.5.21"
|
|
100
|
+
"nodemon": "3.1.10"
|
|
88
101
|
}
|
|
89
102
|
}
|
|
@@ -27,7 +27,7 @@ import {
|
|
|
27
27
|
isVirtualProp,
|
|
28
28
|
} from "../types/types";
|
|
29
29
|
import { ExtendedApi } from "./decorators";
|
|
30
|
-
import type {
|
|
30
|
+
import type { core } from "zod/v4";
|
|
31
31
|
|
|
32
32
|
// <any>를 자제하고, Zod에서 제약하는 기본적인 Generic Type Parameter를 사용함.
|
|
33
33
|
type AnyZodRecord = z.ZodRecord<z.ZodString | z.ZodNumber | z.ZodSymbol, z.ZodType>;
|
|
@@ -36,7 +36,7 @@ type AnyZodArray = z.ZodArray<z.ZodType>;
|
|
|
36
36
|
type AnyZodNullable = z.ZodNullable<z.ZodType>;
|
|
37
37
|
type AnyZodOptional = z.ZodOptional<z.ZodType>;
|
|
38
38
|
type AnyZodDefault = z.ZodDefault<z.ZodType>;
|
|
39
|
-
type AnyZodLiteral = z.ZodLiteral<Literal>;
|
|
39
|
+
type AnyZodLiteral = z.ZodLiteral<core.util.Literal>;
|
|
40
40
|
type AnyZodUnion = z.ZodUnion<z.ZodType[]>;
|
|
41
41
|
|
|
42
42
|
/*
|
|
@@ -0,0 +1,142 @@
|
|
|
1
|
+
import { transformFile } from "@swc/core";
|
|
2
|
+
import { Knex } from "knex";
|
|
3
|
+
import path from "path";
|
|
4
|
+
import { exists } from "../utils/fs-utils";
|
|
5
|
+
import { unlink, writeFile } from "fs/promises";
|
|
6
|
+
import { Driver } from "../file-storage/driver";
|
|
7
|
+
import {
|
|
8
|
+
FastifyInstance,
|
|
9
|
+
FastifyReply,
|
|
10
|
+
FastifyRequest,
|
|
11
|
+
FastifyServerOptions,
|
|
12
|
+
} from "fastify";
|
|
13
|
+
import { SonamuFastifyConfig } from "../types/types";
|
|
14
|
+
import { FastifyCorsOptions } from "@fastify/cors";
|
|
15
|
+
import { FastifyFormbodyOptions } from "@fastify/formbody";
|
|
16
|
+
import { FastifyMultipartOptions } from "@fastify/multipart";
|
|
17
|
+
import { SecureSessionPluginOptions } from "@fastify/secure-session";
|
|
18
|
+
import { FastifyStaticOptions } from "@fastify/static";
|
|
19
|
+
import { QsPluginOptions } from "fastify-qs";
|
|
20
|
+
import { SsePluginOptions } from "fastify-sse-v2/lib/types";
|
|
21
|
+
import {
|
|
22
|
+
DeserializeFunction,
|
|
23
|
+
SerializeFunction,
|
|
24
|
+
} from "@fastify/passport/dist/Authenticator";
|
|
25
|
+
|
|
26
|
+
export type DatabaseConfig = Omit<Knex.Config, "connection"> & {
|
|
27
|
+
connection?: Knex.MySql2ConnectionConfig;
|
|
28
|
+
};
|
|
29
|
+
|
|
30
|
+
export type SonamuConfig = {
|
|
31
|
+
projectName?: string;
|
|
32
|
+
|
|
33
|
+
api: {
|
|
34
|
+
dir: string;
|
|
35
|
+
route: {
|
|
36
|
+
prefix: string;
|
|
37
|
+
};
|
|
38
|
+
timezone?: string;
|
|
39
|
+
};
|
|
40
|
+
sync: {
|
|
41
|
+
targets: string[]; // "web", "app" 등
|
|
42
|
+
};
|
|
43
|
+
ui?: {
|
|
44
|
+
port: number;
|
|
45
|
+
};
|
|
46
|
+
|
|
47
|
+
database: {
|
|
48
|
+
// 기본 데이터베이스 이름
|
|
49
|
+
name: string;
|
|
50
|
+
// 모든 환경에 적용될 기본 Knex 옵션
|
|
51
|
+
defaultOptions: DatabaseConfig;
|
|
52
|
+
// 환경별 설정
|
|
53
|
+
environments?: {
|
|
54
|
+
development?: DatabaseConfig;
|
|
55
|
+
development_slave?: DatabaseConfig;
|
|
56
|
+
production?: DatabaseConfig;
|
|
57
|
+
production_slave?: DatabaseConfig;
|
|
58
|
+
remote_fixture?: DatabaseConfig;
|
|
59
|
+
};
|
|
60
|
+
};
|
|
61
|
+
|
|
62
|
+
server: SonamuServerOptions;
|
|
63
|
+
};
|
|
64
|
+
|
|
65
|
+
export type SonamuServerOptions = {
|
|
66
|
+
fastify?: FastifyServerOptions;
|
|
67
|
+
|
|
68
|
+
listen?: {
|
|
69
|
+
port: number;
|
|
70
|
+
host?: string;
|
|
71
|
+
};
|
|
72
|
+
|
|
73
|
+
plugins?: {
|
|
74
|
+
cors?: boolean | FastifyCorsOptions;
|
|
75
|
+
formbody?: boolean | FastifyFormbodyOptions;
|
|
76
|
+
multipart?: boolean | FastifyMultipartOptions;
|
|
77
|
+
qs?: boolean | QsPluginOptions;
|
|
78
|
+
sse?: boolean | SsePluginOptions;
|
|
79
|
+
static?: boolean | FastifyStaticOptions;
|
|
80
|
+
session?: boolean | SecureSessionPluginOptions;
|
|
81
|
+
|
|
82
|
+
custom?: (server: FastifyInstance) => void;
|
|
83
|
+
};
|
|
84
|
+
|
|
85
|
+
auth?:
|
|
86
|
+
| boolean
|
|
87
|
+
| {
|
|
88
|
+
userSerializer: SerializeFunction<unknown, unknown>;
|
|
89
|
+
userDeserializer: DeserializeFunction<unknown, unknown>;
|
|
90
|
+
};
|
|
91
|
+
|
|
92
|
+
apiConfig: SonamuFastifyConfig;
|
|
93
|
+
|
|
94
|
+
storage?: Driver;
|
|
95
|
+
|
|
96
|
+
lifecycle?: {
|
|
97
|
+
onStart?: (server: FastifyInstance) => Promise<void> | void;
|
|
98
|
+
onShutdown?: (server: FastifyInstance) => Promise<void> | void;
|
|
99
|
+
onError?: (
|
|
100
|
+
error: Error,
|
|
101
|
+
request: FastifyRequest,
|
|
102
|
+
reply: FastifyReply
|
|
103
|
+
) => Promise<void> | void;
|
|
104
|
+
};
|
|
105
|
+
};
|
|
106
|
+
|
|
107
|
+
export type SonamuConfigExport = SonamuConfig | Promise<SonamuConfig>;
|
|
108
|
+
|
|
109
|
+
export function defineConfig(config: SonamuConfig): SonamuConfig;
|
|
110
|
+
export function defineConfig(
|
|
111
|
+
config: Promise<SonamuConfig>
|
|
112
|
+
): Promise<SonamuConfig>;
|
|
113
|
+
export function defineConfig(config: SonamuConfigExport): SonamuConfigExport {
|
|
114
|
+
return config;
|
|
115
|
+
}
|
|
116
|
+
|
|
117
|
+
export async function loadConfig(rootPath: string): Promise<SonamuConfig> {
|
|
118
|
+
const configPath = path.join(rootPath, "sonamu.config.ts");
|
|
119
|
+
if (!(await exists(configPath))) {
|
|
120
|
+
throw new Error(`Cannot find sonamu.config.ts in ${configPath}`);
|
|
121
|
+
}
|
|
122
|
+
|
|
123
|
+
const { code: configCode } = await transformFile(configPath, {
|
|
124
|
+
module: {
|
|
125
|
+
type: "es6",
|
|
126
|
+
},
|
|
127
|
+
jsc: {
|
|
128
|
+
parser: {
|
|
129
|
+
syntax: "typescript",
|
|
130
|
+
decorators: true,
|
|
131
|
+
},
|
|
132
|
+
},
|
|
133
|
+
});
|
|
134
|
+
|
|
135
|
+
const tempDir = path.join(rootPath, "dist");
|
|
136
|
+
const outputPath = path.join(tempDir, "sonamu.config.js");
|
|
137
|
+
await writeFile(outputPath, configCode);
|
|
138
|
+
const { default: config } = await import(outputPath);
|
|
139
|
+
await unlink(outputPath);
|
|
140
|
+
|
|
141
|
+
return config;
|
|
142
|
+
}
|
package/src/api/context.ts
CHANGED
package/src/api/decorators.ts
CHANGED
|
@@ -225,6 +225,7 @@ export function upload(options: UploadDecoratorOptions = {}) {
|
|
|
225
225
|
const rawFilesIterator = request.files();
|
|
226
226
|
for await (const rawFile of rawFilesIterator) {
|
|
227
227
|
if (rawFile) {
|
|
228
|
+
await rawFile.toBuffer();
|
|
228
229
|
uploadContext.files.push(new FileStorage(rawFile, storage));
|
|
229
230
|
}
|
|
230
231
|
}
|
package/src/api/sonamu.ts
CHANGED
|
@@ -4,8 +4,7 @@ import fastify from "fastify";
|
|
|
4
4
|
import { readFile } from "fs/promises";
|
|
5
5
|
import path from "path";
|
|
6
6
|
import { exists } from "../utils/fs-utils";
|
|
7
|
-
|
|
8
|
-
import type { FSWatcher } from "chokidar";
|
|
7
|
+
import chokidar, { type FSWatcher } from "chokidar";
|
|
9
8
|
import { formatInTimeZone } from "date-fns-tz";
|
|
10
9
|
import type { FastifyInstance, FastifyReply, FastifyRequest } from "fastify";
|
|
11
10
|
import type { IncomingMessage, Server, ServerResponse } from "http";
|
|
@@ -19,11 +18,7 @@ import {
|
|
|
19
18
|
import type { Driver } from "../file-storage/driver";
|
|
20
19
|
import { createSSEFactory } from "../stream/sse";
|
|
21
20
|
import type { Syncer } from "../syncer/syncer";
|
|
22
|
-
import {
|
|
23
|
-
ApiParamType,
|
|
24
|
-
SonamuFastifyConfig,
|
|
25
|
-
SonamuServerOptions,
|
|
26
|
-
} from "../types/types";
|
|
21
|
+
import { ApiParamType, SonamuFastifyConfig } from "../types/types";
|
|
27
22
|
import { isLocal, isTest } from "../utils/controller";
|
|
28
23
|
import { findApiRootPath } from "../utils/utils";
|
|
29
24
|
import { humanizeZodError } from "../utils/zod-error";
|
|
@@ -32,23 +27,14 @@ import { getZodObjectFromApi } from "./code-converters";
|
|
|
32
27
|
import type { AuthContext, Context, UploadContext } from "./context";
|
|
33
28
|
import type { ExtendedApi } from "./decorators";
|
|
34
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";
|
|
35
37
|
|
|
36
|
-
export type SonamuConfig = {
|
|
37
|
-
projectName?: string;
|
|
38
|
-
api: {
|
|
39
|
-
dir: string;
|
|
40
|
-
};
|
|
41
|
-
sync: {
|
|
42
|
-
targets: string[];
|
|
43
|
-
};
|
|
44
|
-
route: {
|
|
45
|
-
prefix: string;
|
|
46
|
-
};
|
|
47
|
-
timezone?: string;
|
|
48
|
-
ui?: {
|
|
49
|
-
port: number;
|
|
50
|
-
};
|
|
51
|
-
};
|
|
52
38
|
export type SonamuSecrets = {
|
|
53
39
|
[key: string]: string;
|
|
54
40
|
};
|
|
@@ -67,7 +53,19 @@ class SonamuClass {
|
|
|
67
53
|
if (store?.context) {
|
|
68
54
|
return store.context;
|
|
69
55
|
}
|
|
70
|
-
|
|
56
|
+
|
|
57
|
+
if (process.env.NODE_ENV === "test") {
|
|
58
|
+
// 테스팅 환경에서 컨텍스트가 주입되지 않은 경우 빈 컨텍스트 리턴
|
|
59
|
+
return {
|
|
60
|
+
request: null,
|
|
61
|
+
reply: null,
|
|
62
|
+
headers: {},
|
|
63
|
+
createSSE: () => {},
|
|
64
|
+
naiteStore: new Map<string, any>(),
|
|
65
|
+
} as unknown as Context;
|
|
66
|
+
} else {
|
|
67
|
+
throw new Error("Sonamu cannot find context");
|
|
68
|
+
}
|
|
71
69
|
}
|
|
72
70
|
|
|
73
71
|
public getUploadContext(): UploadContext {
|
|
@@ -80,11 +78,11 @@ class SonamuClass {
|
|
|
80
78
|
);
|
|
81
79
|
}
|
|
82
80
|
|
|
83
|
-
private _apiRootPath:
|
|
84
|
-
set apiRootPath(apiRootPath:
|
|
81
|
+
private _apiRootPath: AbsolutePath | null = null;
|
|
82
|
+
set apiRootPath(apiRootPath: AbsolutePath) {
|
|
85
83
|
this._apiRootPath = apiRootPath;
|
|
86
84
|
}
|
|
87
|
-
get apiRootPath():
|
|
85
|
+
get apiRootPath(): AbsolutePath {
|
|
88
86
|
if (this._apiRootPath === null) {
|
|
89
87
|
throw new Error("Sonamu has not been initialized");
|
|
90
88
|
}
|
|
@@ -157,7 +155,7 @@ class SonamuClass {
|
|
|
157
155
|
async init(
|
|
158
156
|
doSilent: boolean = false,
|
|
159
157
|
enableSync: boolean = true,
|
|
160
|
-
apiRootPath?:
|
|
158
|
+
apiRootPath?: AbsolutePath,
|
|
161
159
|
forTesting: boolean = false
|
|
162
160
|
) {
|
|
163
161
|
if (this.isInitialized) {
|
|
@@ -170,14 +168,8 @@ class SonamuClass {
|
|
|
170
168
|
|
|
171
169
|
// API 루트 패스
|
|
172
170
|
this.apiRootPath = apiRootPath ?? findApiRootPath();
|
|
173
|
-
|
|
171
|
+
this.config = await loadConfig(this.apiRootPath);
|
|
174
172
|
const secretsPath = path.join(this.apiRootPath, "sonamu.secrets.json");
|
|
175
|
-
if (!(await exists(configPath))) {
|
|
176
|
-
throw new Error(`Cannot find sonamu.config.json in ${configPath}`);
|
|
177
|
-
}
|
|
178
|
-
this.config = JSON.parse(
|
|
179
|
-
(await readFile(configPath)).toString()
|
|
180
|
-
) as SonamuConfig;
|
|
181
173
|
if (await exists(secretsPath)) {
|
|
182
174
|
this.secrets = JSON.parse(
|
|
183
175
|
(await readFile(secretsPath)).toString()
|
|
@@ -185,7 +177,7 @@ class SonamuClass {
|
|
|
185
177
|
}
|
|
186
178
|
|
|
187
179
|
// DB 로드
|
|
188
|
-
this.dbConfig =
|
|
180
|
+
this.dbConfig = DB.generateDBConfig(this.config.database);
|
|
189
181
|
!doSilent && console.log(chalk.green("DB Config Loaded!"));
|
|
190
182
|
attachOnDuplicateUpdate();
|
|
191
183
|
|
|
@@ -204,14 +196,15 @@ class SonamuClass {
|
|
|
204
196
|
this.syncer = new Syncer();
|
|
205
197
|
|
|
206
198
|
// Autoload: Models / Types / APIs
|
|
207
|
-
await this.syncer.autoloadModels();
|
|
208
199
|
await this.syncer.autoloadTypes();
|
|
200
|
+
await this.syncer.autoloadModels();
|
|
209
201
|
await this.syncer.autoloadApis();
|
|
210
202
|
|
|
211
|
-
|
|
203
|
+
await Template.autoload();
|
|
204
|
+
|
|
205
|
+
if (isLocal() && !isTest() && isHotReloadServer() && enableSync) {
|
|
212
206
|
await this.syncer.sync();
|
|
213
207
|
|
|
214
|
-
// FIXME: hmr 설정된 경우만 워처 시작
|
|
215
208
|
this.startWatcher();
|
|
216
209
|
|
|
217
210
|
this.syncer.syncUI();
|
|
@@ -221,13 +214,15 @@ class SonamuClass {
|
|
|
221
214
|
!doSilent && console.timeEnd(chalk.cyan("Sonamu.init"));
|
|
222
215
|
}
|
|
223
216
|
|
|
224
|
-
async createServer(
|
|
225
|
-
|
|
226
|
-
|
|
227
|
-
|
|
228
|
-
|
|
217
|
+
async createServer(initOptions?: {
|
|
218
|
+
enableSync?: boolean;
|
|
219
|
+
doSilent?: boolean;
|
|
220
|
+
}) {
|
|
221
|
+
if (this.isInitialized === false) {
|
|
222
|
+
await this.init(initOptions?.doSilent, initOptions?.enableSync);
|
|
229
223
|
}
|
|
230
|
-
|
|
224
|
+
|
|
225
|
+
const options = this.config.server;
|
|
231
226
|
const server = fastify(options.fastify);
|
|
232
227
|
this.server = server;
|
|
233
228
|
|
|
@@ -278,7 +273,7 @@ class SonamuClass {
|
|
|
278
273
|
this.server = server;
|
|
279
274
|
|
|
280
275
|
// timezone 설정
|
|
281
|
-
const timezone = this.config.timezone;
|
|
276
|
+
const timezone = this.config.api.timezone;
|
|
282
277
|
if (timezone) {
|
|
283
278
|
const DATE_FORMAT = "yyyy-MM-dd'T'HH:mm:ssXXX";
|
|
284
279
|
// ISO 8601 날짜 형식 정규식 (예: 2024-01-15T09:30:00.000Z)
|
|
@@ -298,7 +293,7 @@ class SonamuClass {
|
|
|
298
293
|
|
|
299
294
|
// 전체 라우팅 리스트
|
|
300
295
|
server.get(
|
|
301
|
-
`${this.config.route.prefix}/routes`,
|
|
296
|
+
`${this.config.api.route.prefix}/routes`,
|
|
302
297
|
async (_request, _reply): Promise<any> => {
|
|
303
298
|
return this.syncer.apis;
|
|
304
299
|
}
|
|
@@ -306,7 +301,7 @@ class SonamuClass {
|
|
|
306
301
|
|
|
307
302
|
// Healthcheck API
|
|
308
303
|
server.get(
|
|
309
|
-
`${this.config.route.prefix}/healthcheck`,
|
|
304
|
+
`${this.config.api.route.prefix}/healthcheck`,
|
|
310
305
|
async (_request, _reply): Promise<string> => {
|
|
311
306
|
return "ok";
|
|
312
307
|
}
|
|
@@ -317,7 +312,8 @@ class SonamuClass {
|
|
|
317
312
|
server.all("*", (request, reply) => {
|
|
318
313
|
const found = this.syncer.apis.find(
|
|
319
314
|
(api) =>
|
|
320
|
-
this.config.route.prefix + api.path ===
|
|
315
|
+
this.config.api.route.prefix + api.path ===
|
|
316
|
+
request.url.split("?")[0] &&
|
|
321
317
|
(api.options.httpMethod ?? "GET") === request.method.toUpperCase()
|
|
322
318
|
);
|
|
323
319
|
if (found) {
|
|
@@ -335,7 +331,7 @@ class SonamuClass {
|
|
|
335
331
|
// route
|
|
336
332
|
server.route({
|
|
337
333
|
method: api.options.httpMethod!,
|
|
338
|
-
url: this.config.route.prefix + api.path,
|
|
334
|
+
url: this.config.api.route.prefix + api.path,
|
|
339
335
|
handler: this.getApiHandler(api, config),
|
|
340
336
|
}); // END server.route
|
|
341
337
|
});
|
|
@@ -420,6 +416,7 @@ class SonamuClass {
|
|
|
420
416
|
reply,
|
|
421
417
|
headers: request.headers,
|
|
422
418
|
createSSE,
|
|
419
|
+
naiteStore: new Map<string, any>(),
|
|
423
420
|
// auth
|
|
424
421
|
user: request.user ?? null,
|
|
425
422
|
passport: {
|
|
@@ -462,24 +459,46 @@ class SonamuClass {
|
|
|
462
459
|
}
|
|
463
460
|
|
|
464
461
|
startWatcher(): void {
|
|
465
|
-
const watchPath =
|
|
466
|
-
|
|
462
|
+
const watchPath = [
|
|
463
|
+
path.join(this.apiRootPath, "src"),
|
|
464
|
+
path.join(this.apiRootPath, "sonamu.config.ts"),
|
|
465
|
+
];
|
|
466
|
+
|
|
467
467
|
this.watcher = chokidar.watch(watchPath, {
|
|
468
468
|
ignored: (path, stats) =>
|
|
469
|
-
|
|
470
|
-
!path.endsWith(".ts") &&
|
|
471
|
-
!path.endsWith(".json")) ||
|
|
472
|
-
path.endsWith("src/index.ts"),
|
|
469
|
+
!!stats?.isFile() && !path.endsWith(".ts") && !path.endsWith(".json"),
|
|
473
470
|
persistent: true,
|
|
474
471
|
ignoreInitial: true,
|
|
475
472
|
});
|
|
473
|
+
|
|
476
474
|
this.watcher.on("all", async (event: string, filePath: string) => {
|
|
475
|
+
const absolutePath = filePath as AbsolutePath;
|
|
476
|
+
assert(
|
|
477
|
+
absolutePath.startsWith(this.apiRootPath),
|
|
478
|
+
"File path is not within the API root path"
|
|
479
|
+
);
|
|
480
|
+
|
|
477
481
|
if (event !== "change" && event !== "add") {
|
|
478
482
|
return;
|
|
479
483
|
}
|
|
480
484
|
|
|
481
485
|
try {
|
|
482
|
-
|
|
486
|
+
// sonamu.config.ts 변경 시 재시작
|
|
487
|
+
const isConfigTs =
|
|
488
|
+
filePath === path.join(this.apiRootPath, "sonamu.config.ts");
|
|
489
|
+
|
|
490
|
+
if (isConfigTs) {
|
|
491
|
+
const relativePath = filePath.replace(this.apiRootPath, "api");
|
|
492
|
+
console.log(
|
|
493
|
+
chalk.bold(
|
|
494
|
+
`Detected(${event}): ${chalk.blue(relativePath)} - Restarting...`
|
|
495
|
+
)
|
|
496
|
+
);
|
|
497
|
+
process.kill(process.pid, "SIGUSR2");
|
|
498
|
+
return;
|
|
499
|
+
}
|
|
500
|
+
|
|
501
|
+
await this.handleFileChange(event, absolutePath);
|
|
483
502
|
} catch (e) {
|
|
484
503
|
console.error(e);
|
|
485
504
|
}
|
|
@@ -596,19 +615,18 @@ class SonamuClass {
|
|
|
596
615
|
|
|
597
616
|
private async handleFileChange(
|
|
598
617
|
event: string,
|
|
599
|
-
filePath:
|
|
618
|
+
filePath: AbsolutePath
|
|
600
619
|
): Promise<void> {
|
|
601
620
|
// 첫 번째 파일이면 HMR 시작 시간 기록
|
|
602
621
|
if (this.pendingFiles.length === 0) {
|
|
603
622
|
this.hmrStartTime = Date.now();
|
|
604
623
|
}
|
|
605
|
-
|
|
606
624
|
this.pendingFiles.push(filePath);
|
|
607
625
|
|
|
608
|
-
const relativePath =
|
|
626
|
+
const relativePath = path.relative(this.apiRootPath, filePath);
|
|
609
627
|
console.log(chalk.bold(`Detected(${event}): ${chalk.blue(relativePath)}`));
|
|
610
628
|
|
|
611
|
-
await this.syncer.syncFromWatcher(
|
|
629
|
+
await this.syncer.syncFromWatcher(event, filePath);
|
|
612
630
|
|
|
613
631
|
// 처리 완료된 파일을 대기 목록에서 제거
|
|
614
632
|
this.pendingFiles = this.pendingFiles.slice(1);
|
|
@@ -620,20 +638,16 @@ class SonamuClass {
|
|
|
620
638
|
}
|
|
621
639
|
|
|
622
640
|
private async finishHMR(): Promise<void> {
|
|
623
|
-
await this.syncer.
|
|
641
|
+
await this.syncer.renewChecksums();
|
|
624
642
|
|
|
625
643
|
const endTime = Date.now();
|
|
626
644
|
const totalTime = endTime - this.hmrStartTime;
|
|
627
645
|
const msg = `HMR Done! ${chalk.bold.white(`${totalTime}ms`)}`;
|
|
628
|
-
const margin = Math.max(0, (process.stdout.columns - msg.length) / 2);
|
|
629
646
|
|
|
630
|
-
console.log(
|
|
631
|
-
chalk.black.bgGreen(" ".repeat(margin) + msg + " ".repeat(margin))
|
|
632
|
-
);
|
|
647
|
+
console.log(chalk.black.bgGreen(centerText(msg)));
|
|
633
648
|
}
|
|
634
649
|
|
|
635
650
|
async destroy(): Promise<void> {
|
|
636
|
-
const { BaseModel } = require("../database/base-model");
|
|
637
651
|
await BaseModel.destroy();
|
|
638
652
|
await this.watcher?.close();
|
|
639
653
|
this.storage?.destroy();
|
package/src/bin/build-config.ts
CHANGED
|
@@ -5,8 +5,9 @@ export const BUILD_DIR = "dist";
|
|
|
5
5
|
|
|
6
6
|
/**
|
|
7
7
|
* SWC 빌드 명령어
|
|
8
|
+
* .swcrc 설정 사용
|
|
8
9
|
*/
|
|
9
|
-
export const SWC_BUILD_COMMAND = `swc src -d ${BUILD_DIR} --strip-leading-paths
|
|
10
|
+
export const SWC_BUILD_COMMAND = `swc src -d ${BUILD_DIR} --strip-leading-paths`;
|
|
10
11
|
|
|
11
12
|
/**
|
|
12
13
|
* TSC 타입 체크 명령어
|