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