sonamu 0.10.11 → 0.10.13

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (519) hide show
  1. package/dist/ai/agents/agent.d.ts +1 -1
  2. package/dist/ai/agents/agent.d.ts.map +1 -1
  3. package/dist/ai/agents/agent.js +5 -6
  4. package/dist/ai/agents/types.d.ts +1 -1
  5. package/dist/ai/agents/types.d.ts.map +1 -1
  6. package/dist/ai/providers/rtzr/api.js +18 -18
  7. package/dist/ai/providers/rtzr/error.d.ts.map +1 -1
  8. package/dist/ai/providers/rtzr/error.js +17 -15
  9. package/dist/ai/providers/rtzr/model.d.ts.map +1 -1
  10. package/dist/ai/providers/rtzr/model.js +3 -2
  11. package/dist/ai/providers/rtzr/options.d.ts.map +1 -1
  12. package/dist/ai/providers/rtzr/options.js +16 -16
  13. package/dist/ai/providers/rtzr/provider.d.ts.map +1 -1
  14. package/dist/ai/providers/rtzr/provider.js +9 -9
  15. package/dist/ai/providers/rtzr/utils.d.ts.map +1 -1
  16. package/dist/ai/providers/rtzr/utils.js +1 -1
  17. package/dist/api/caster.d.ts.map +1 -1
  18. package/dist/api/caster.js +17 -17
  19. package/dist/api/code-converters.d.ts +4 -2
  20. package/dist/api/code-converters.d.ts.map +1 -1
  21. package/dist/api/code-converters.js +100 -19
  22. package/dist/api/config.d.ts +16 -1
  23. package/dist/api/config.d.ts.map +1 -1
  24. package/dist/api/config.js +28 -21
  25. package/dist/api/context.d.ts +2 -2
  26. package/dist/api/context.d.ts.map +1 -1
  27. package/dist/api/context.js +1 -1
  28. package/dist/api/decorators.d.ts.map +1 -1
  29. package/dist/api/decorators.js +18 -11
  30. package/dist/api/http-validator.d.ts +36 -0
  31. package/dist/api/http-validator.d.ts.map +1 -0
  32. package/dist/api/http-validator.js +72 -0
  33. package/dist/api/index.js +6 -4
  34. package/dist/api/sonamu.d.ts +59 -20
  35. package/dist/api/sonamu.d.ts.map +1 -1
  36. package/dist/api/sonamu.js +250 -106
  37. package/dist/api/websocket-helpers.d.ts +7 -5
  38. package/dist/api/websocket-helpers.d.ts.map +1 -1
  39. package/dist/api/websocket-helpers.js +6 -6
  40. package/dist/auth/audit-log/builders.d.ts.map +1 -1
  41. package/dist/auth/audit-log/builders.js +1 -1
  42. package/dist/auth/audit-log/client-ip.d.ts +1 -1
  43. package/dist/auth/audit-log/client-ip.d.ts.map +1 -1
  44. package/dist/auth/audit-log/client-ip.js +4 -2
  45. package/dist/auth/audit-log/events.d.ts +5 -1
  46. package/dist/auth/audit-log/events.d.ts.map +1 -1
  47. package/dist/auth/audit-log/events.js +1 -1
  48. package/dist/auth/audit-log/plugin.d.ts +0 -8
  49. package/dist/auth/audit-log/plugin.d.ts.map +1 -1
  50. package/dist/auth/audit-log/plugin.js +48 -52
  51. package/dist/auth/audit-log-ingestor.d.ts.map +1 -1
  52. package/dist/auth/audit-log-ingestor.js +16 -12
  53. package/dist/auth/auth-generator.d.ts.map +1 -1
  54. package/dist/auth/auth-generator.js +1 -1
  55. package/dist/auth/better-auth-request.d.ts.map +1 -1
  56. package/dist/auth/better-auth-request.js +6 -5
  57. package/dist/auth/knex-adapter.js +1 -1
  58. package/dist/auth/plugins/entity-definitions/index.d.ts +13 -1
  59. package/dist/auth/plugins/entity-definitions/index.d.ts.map +1 -1
  60. package/dist/auth/plugins/entity-definitions/index.js +1 -1
  61. package/dist/auth/plugins/wrappers/admin.d.ts +1 -1
  62. package/dist/bin/build-config.d.ts +25 -0
  63. package/dist/bin/build-config.d.ts.map +1 -1
  64. package/dist/bin/build-config.js +105 -2
  65. package/dist/bin/cli.js +133 -29
  66. package/dist/bin/compiler-policy.d.ts +3 -0
  67. package/dist/bin/compiler-policy.d.ts.map +1 -0
  68. package/dist/bin/compiler-policy.js +24 -0
  69. package/dist/bin/fixture.d.ts.map +1 -1
  70. package/dist/bin/fixture.js +5 -3
  71. package/dist/bin/test-command.d.ts +22 -1
  72. package/dist/bin/test-command.d.ts.map +1 -1
  73. package/dist/bin/test-command.js +18 -10
  74. package/dist/bin/ts-loader-registration.d.ts +7 -1
  75. package/dist/bin/ts-loader-registration.d.ts.map +1 -1
  76. package/dist/bin/ts-loader-registration.js +13 -4
  77. package/dist/cache/decorator.d.ts.map +1 -1
  78. package/dist/cache/decorator.js +11 -4
  79. package/dist/compress/compress.d.ts.map +1 -1
  80. package/dist/compress/compress.js +1 -1
  81. package/dist/cone/cone-generator.d.ts +14 -1
  82. package/dist/cone/cone-generator.d.ts.map +1 -1
  83. package/dist/cone/cone-generator.js +13 -9
  84. package/dist/database/_batch_update.js +1 -1
  85. package/dist/database/base-model.d.ts +22 -10
  86. package/dist/database/base-model.d.ts.map +1 -1
  87. package/dist/database/base-model.js +26 -16
  88. package/dist/database/base-model.types.d.ts +15 -3
  89. package/dist/database/base-model.types.d.ts.map +1 -1
  90. package/dist/database/db.d.ts +12 -2
  91. package/dist/database/db.d.ts.map +1 -1
  92. package/dist/database/db.js +10 -7
  93. package/dist/database/knex.d.ts.map +1 -1
  94. package/dist/database/knex.js +17 -14
  95. package/dist/database/puri.d.ts +11 -9
  96. package/dist/database/puri.d.ts.map +1 -1
  97. package/dist/database/puri.js +93 -79
  98. package/dist/database/puri.types.d.ts +21 -21
  99. package/dist/database/puri.types.d.ts.map +1 -1
  100. package/dist/database/puri.types.js +1 -1
  101. package/dist/database/upsert-builder.d.ts +12 -10
  102. package/dist/database/upsert-builder.d.ts.map +1 -1
  103. package/dist/database/upsert-builder.js +20 -12
  104. package/dist/dict/sd.d.ts.map +1 -1
  105. package/dist/dict/sd.js +1 -1
  106. package/dist/dict/sonamu-dictionary.d.ts.map +1 -1
  107. package/dist/dict/sonamu-dictionary.js +1 -1
  108. package/dist/dict/utils.d.ts.map +1 -1
  109. package/dist/dict/utils.js +7 -2
  110. package/dist/entity/entity-manager.d.ts +13 -4
  111. package/dist/entity/entity-manager.d.ts.map +1 -1
  112. package/dist/entity/entity-manager.js +19 -11
  113. package/dist/entity/entity-template-cone.d.ts +73 -5
  114. package/dist/entity/entity-template-cone.d.ts.map +1 -1
  115. package/dist/entity/entity-template-cone.js +4 -2
  116. package/dist/entity/entity.d.ts +6 -2
  117. package/dist/entity/entity.d.ts.map +1 -1
  118. package/dist/entity/entity.js +30 -28
  119. package/dist/env.d.ts +3 -1
  120. package/dist/env.d.ts.map +1 -1
  121. package/dist/env.js +1 -1
  122. package/dist/exceptions/error-handler.d.ts.map +1 -1
  123. package/dist/exceptions/error-handler.js +7 -2
  124. package/dist/exceptions/so-exceptions.d.ts +24 -20
  125. package/dist/exceptions/so-exceptions.d.ts.map +1 -1
  126. package/dist/exceptions/so-exceptions.js +4 -2
  127. package/dist/filter/utils.d.ts +7 -2
  128. package/dist/filter/utils.d.ts.map +1 -1
  129. package/dist/filter/utils.js +8 -6
  130. package/dist/index.d.ts +3 -0
  131. package/dist/index.d.ts.map +1 -1
  132. package/dist/index.js +13 -7
  133. package/dist/logger/configure.d.ts.map +1 -1
  134. package/dist/logger/configure.js +10 -10
  135. package/dist/migration/code-generation.d.ts.map +1 -1
  136. package/dist/migration/code-generation.js +50 -46
  137. package/dist/migration/index-where-predicate.d.ts.map +1 -1
  138. package/dist/migration/index-where-predicate.js +22 -8
  139. package/dist/migration/migration-set.d.ts.map +1 -1
  140. package/dist/migration/migration-set.js +1 -1
  141. package/dist/migration/migrator.d.ts +61 -36
  142. package/dist/migration/migrator.d.ts.map +1 -1
  143. package/dist/migration/migrator.js +276 -167
  144. package/dist/migration/postgresql-schema-reader.d.ts.map +1 -1
  145. package/dist/migration/postgresql-schema-reader.js +51 -36
  146. package/dist/migration/slack-confirm.d.ts.map +1 -1
  147. package/dist/migration/slack-confirm.js +1 -1
  148. package/dist/migration/types.d.ts +54 -0
  149. package/dist/migration/types.d.ts.map +1 -1
  150. package/dist/naite/naite-reporter.js +2 -2
  151. package/dist/naite/naite.d.ts +74 -15
  152. package/dist/naite/naite.d.ts.map +1 -1
  153. package/dist/naite/naite.js +5 -19
  154. package/dist/runtime-type.d.ts +6 -0
  155. package/dist/runtime-type.d.ts.map +1 -0
  156. package/dist/runtime-type.js +26 -0
  157. package/dist/ssr/hmr-opt-out.d.ts +26 -0
  158. package/dist/ssr/hmr-opt-out.d.ts.map +1 -0
  159. package/dist/ssr/hmr-opt-out.js +59 -0
  160. package/dist/ssr/renderer.d.ts.map +1 -1
  161. package/dist/ssr/renderer.js +4 -1
  162. package/dist/storage/base-file.js +14 -14
  163. package/dist/storage/buffered-file.d.ts +2 -2
  164. package/dist/storage/buffered-file.d.ts.map +1 -1
  165. package/dist/storage/buffered-file.js +12 -12
  166. package/dist/storage/s3-driver.d.ts.map +1 -1
  167. package/dist/storage/s3-driver.js +1 -1
  168. package/dist/storage/uploaded-file.d.ts +2 -2
  169. package/dist/storage/uploaded-file.d.ts.map +1 -1
  170. package/dist/storage/uploaded-file.js +8 -8
  171. package/dist/stream/sse.js +11 -11
  172. package/dist/stream/ws-core.d.ts +1 -1
  173. package/dist/stream/ws-core.d.ts.map +1 -1
  174. package/dist/stream/ws-delivery.d.ts +1 -1
  175. package/dist/stream/ws-delivery.d.ts.map +1 -1
  176. package/dist/stream/ws-delivery.js +6 -4
  177. package/dist/stream/ws-local-connection-store.d.ts.map +1 -1
  178. package/dist/stream/ws-local-connection-store.js +4 -2
  179. package/dist/stream/ws-presence-store.js +1 -1
  180. package/dist/stream/ws-registry.d.ts +4 -4
  181. package/dist/stream/ws-registry.d.ts.map +1 -1
  182. package/dist/stream/ws-registry.js +4 -2
  183. package/dist/stream/ws-telemetry.d.ts +16 -12
  184. package/dist/stream/ws-telemetry.d.ts.map +1 -1
  185. package/dist/stream/ws-telemetry.js +22 -18
  186. package/dist/stream/ws.d.ts +18 -12
  187. package/dist/stream/ws.d.ts.map +1 -1
  188. package/dist/stream/ws.js +26 -22
  189. package/dist/syncer/api-parser.js +1 -1
  190. package/dist/syncer/checksum.d.ts.map +1 -1
  191. package/dist/syncer/checksum.js +7 -8
  192. package/dist/syncer/code-generator.d.ts.map +1 -1
  193. package/dist/syncer/code-generator.js +13 -14
  194. package/dist/syncer/entity-operations.d.ts.map +1 -1
  195. package/dist/syncer/entity-operations.js +5 -6
  196. package/dist/syncer/file-copy.d.ts +5 -0
  197. package/dist/syncer/file-copy.d.ts.map +1 -0
  198. package/dist/syncer/file-copy.js +36 -0
  199. package/dist/syncer/file-patterns.d.ts +1 -0
  200. package/dist/syncer/file-patterns.d.ts.map +1 -1
  201. package/dist/syncer/file-patterns.js +5 -2
  202. package/dist/syncer/file-tracking.d.ts.map +1 -1
  203. package/dist/syncer/file-tracking.js +5 -4
  204. package/dist/syncer/filesystem-dependencies.d.ts +15 -0
  205. package/dist/syncer/filesystem-dependencies.d.ts.map +1 -0
  206. package/dist/syncer/filesystem-dependencies.js +53 -0
  207. package/dist/syncer/module-loader.d.ts +1 -1
  208. package/dist/syncer/module-loader.d.ts.map +1 -1
  209. package/dist/syncer/module-loader.js +6 -4
  210. package/dist/syncer/syncer-actions.d.ts +4 -0
  211. package/dist/syncer/syncer-actions.d.ts.map +1 -1
  212. package/dist/syncer/syncer-actions.js +34 -17
  213. package/dist/syncer/syncer.d.ts +17 -6
  214. package/dist/syncer/syncer.d.ts.map +1 -1
  215. package/dist/syncer/syncer.js +71 -29
  216. package/dist/syncer/watcher.d.ts.map +1 -1
  217. package/dist/syncer/watcher.js +3 -3
  218. package/dist/tasks/decorator.d.ts +6 -6
  219. package/dist/tasks/decorator.d.ts.map +1 -1
  220. package/dist/tasks/decorator.js +4 -4
  221. package/dist/tasks/step-wrapper.d.ts +6 -4
  222. package/dist/tasks/step-wrapper.d.ts.map +1 -1
  223. package/dist/tasks/step-wrapper.js +5 -5
  224. package/dist/tasks/workflow-manager.d.ts.map +1 -1
  225. package/dist/tasks/workflow-manager.js +13 -7
  226. package/dist/template/entity-converter.d.ts +1 -1
  227. package/dist/template/entity-converter.d.ts.map +1 -1
  228. package/dist/template/entity-converter.js +2 -2
  229. package/dist/template/helpers.d.ts +8 -6
  230. package/dist/template/helpers.d.ts.map +1 -1
  231. package/dist/template/helpers.js +1 -1
  232. package/dist/template/implementations/generated.template.d.ts.map +1 -1
  233. package/dist/template/implementations/generated.template.js +4 -4
  234. package/dist/template/implementations/generated_http.template.d.ts +7 -4
  235. package/dist/template/implementations/generated_http.template.d.ts.map +1 -1
  236. package/dist/template/implementations/generated_http.template.js +21 -21
  237. package/dist/template/implementations/generated_sso.template.d.ts.map +1 -1
  238. package/dist/template/implementations/generated_sso.template.js +6 -3
  239. package/dist/template/implementations/http_validators.template.d.ts +18 -0
  240. package/dist/template/implementations/http_validators.template.d.ts.map +1 -0
  241. package/dist/template/implementations/http_validators.template.js +127 -0
  242. package/dist/template/implementations/model.template.d.ts.map +1 -1
  243. package/dist/template/implementations/model.template.js +1 -1
  244. package/dist/template/implementations/queries.template.js +1 -1
  245. package/dist/template/implementations/sd.template.d.ts.map +1 -1
  246. package/dist/template/implementations/sd.template.js +79 -39
  247. package/dist/template/implementations/services.template.d.ts.map +1 -1
  248. package/dist/template/implementations/services.template.js +6 -4
  249. package/dist/template/implementations/view_form.template.d.ts +6 -1
  250. package/dist/template/implementations/view_form.template.d.ts.map +1 -1
  251. package/dist/template/implementations/view_form.template.js +23 -15
  252. package/dist/template/implementations/view_list.template.d.ts.map +1 -1
  253. package/dist/template/implementations/view_list.template.js +11 -6
  254. package/dist/template/template-manager.d.ts.map +1 -1
  255. package/dist/template/template-manager.js +9 -7
  256. package/dist/template/template-types.d.ts +12 -5
  257. package/dist/template/template-types.d.ts.map +1 -1
  258. package/dist/template/template-types.js +1 -1
  259. package/dist/template/template.d.ts +2 -2
  260. package/dist/template/template.d.ts.map +1 -1
  261. package/dist/template/template.js +6 -4
  262. package/dist/template/zod-converter.d.ts +0 -19
  263. package/dist/template/zod-converter.d.ts.map +1 -1
  264. package/dist/template/zod-converter.js +100 -84
  265. package/dist/testing/_relation-graph.d.ts.map +1 -1
  266. package/dist/testing/_relation-graph.js +2 -1
  267. package/dist/testing/bootstrap.d.ts.map +1 -1
  268. package/dist/testing/bootstrap.js +9 -6
  269. package/dist/testing/data-explorer.d.ts +32 -7
  270. package/dist/testing/data-explorer.d.ts.map +1 -1
  271. package/dist/testing/data-explorer.js +77 -31
  272. package/dist/testing/dev-test-routes.d.ts +8 -1
  273. package/dist/testing/dev-test-routes.d.ts.map +1 -1
  274. package/dist/testing/dev-test-routes.js +125 -108
  275. package/dist/testing/dev-vitest-manager.d.ts +54 -8
  276. package/dist/testing/dev-vitest-manager.d.ts.map +1 -1
  277. package/dist/testing/dev-vitest-manager.js +24 -9
  278. package/dist/testing/faker-mappings.d.ts +412 -1
  279. package/dist/testing/faker-mappings.d.ts.map +1 -1
  280. package/dist/testing/faker-mappings.js +1 -1
  281. package/dist/testing/filesystem.d.ts +2 -0
  282. package/dist/testing/filesystem.d.ts.map +1 -0
  283. package/dist/testing/filesystem.js +7 -0
  284. package/dist/testing/fixture-generator.d.ts +25 -8
  285. package/dist/testing/fixture-generator.d.ts.map +1 -1
  286. package/dist/testing/fixture-generator.js +132 -73
  287. package/dist/testing/fixture-loader.d.ts +3 -1
  288. package/dist/testing/fixture-loader.d.ts.map +1 -1
  289. package/dist/testing/fixture-loader.js +1 -20
  290. package/dist/testing/fixture-manager.d.ts +8 -7
  291. package/dist/testing/fixture-manager.d.ts.map +1 -1
  292. package/dist/testing/fixture-manager.js +91 -59
  293. package/dist/testing/global-setup.d.ts.map +1 -1
  294. package/dist/testing/global-setup.js +5 -2
  295. package/dist/testing/index.d.ts +2 -0
  296. package/dist/testing/index.d.ts.map +1 -1
  297. package/dist/testing/index.js +6 -3
  298. package/dist/types/types.d.ts +101 -99
  299. package/dist/types/types.d.ts.map +1 -1
  300. package/dist/types/types.js +234 -225
  301. package/dist/ui/ai-api.d.ts.map +1 -1
  302. package/dist/ui/ai-api.js +1 -1
  303. package/dist/ui/ai-client.d.ts.map +1 -1
  304. package/dist/ui/ai-client.js +28 -18
  305. package/dist/ui/api.d.ts.map +1 -1
  306. package/dist/ui/api.js +146 -210
  307. package/dist/ui/async-route.d.ts +3 -0
  308. package/dist/ui/async-route.d.ts.map +1 -0
  309. package/dist/ui/async-route.js +12 -0
  310. package/dist/ui/cdd-service.d.ts +9 -7
  311. package/dist/ui/cdd-service.d.ts.map +1 -1
  312. package/dist/ui/cdd-service.js +7 -5
  313. package/dist/ui/migrations-api.d.ts +3 -0
  314. package/dist/ui/migrations-api.d.ts.map +1 -0
  315. package/dist/ui/migrations-api.js +215 -0
  316. package/dist/ui-web/assets/index-D3QNH-Dv.css +1 -0
  317. package/dist/ui-web/assets/index-DV1AAq6W.js +178 -0
  318. package/dist/ui-web/index.html +2 -2
  319. package/dist/utils/formatter.d.ts.map +1 -1
  320. package/dist/utils/formatter.js +7 -5
  321. package/dist/utils/fs-utils.d.ts +3 -3
  322. package/dist/utils/fs-utils.d.ts.map +1 -1
  323. package/dist/utils/fs-utils.js +6 -6
  324. package/dist/utils/model.d.ts +3 -5
  325. package/dist/utils/model.d.ts.map +1 -1
  326. package/dist/utils/model.js +1 -1
  327. package/dist/utils/object-utils.d.ts +1 -1
  328. package/dist/utils/object-utils.d.ts.map +1 -1
  329. package/dist/utils/object-utils.js +17 -16
  330. package/dist/utils/process-utils.d.ts.map +1 -1
  331. package/dist/utils/process-utils.js +4 -2
  332. package/dist/utils/runtime-value.d.ts +13 -0
  333. package/dist/utils/runtime-value.d.ts.map +1 -0
  334. package/dist/utils/runtime-value.js +40 -0
  335. package/dist/utils/sql-parser.d.ts +8 -1
  336. package/dist/utils/sql-parser.d.ts.map +1 -1
  337. package/dist/utils/sql-parser.js +6 -3
  338. package/dist/utils/type-utils.d.ts.map +1 -1
  339. package/dist/utils/type-utils.js +10 -8
  340. package/dist/utils/utils.d.ts +2 -2
  341. package/dist/utils/utils.d.ts.map +1 -1
  342. package/dist/utils/utils.js +11 -8
  343. package/dist/utils/zod-error.d.ts.map +1 -1
  344. package/dist/utils/zod-error.js +7 -4
  345. package/dist/vector/chunking.d.ts.map +1 -1
  346. package/dist/vector/chunking.js +1 -1
  347. package/dist/vector/embedding.d.ts.map +1 -1
  348. package/dist/vector/embedding.js +1 -1
  349. package/dist/vector/types.d.ts +3 -2
  350. package/dist/vector/types.d.ts.map +1 -1
  351. package/package.json +11 -7
  352. package/src/ai/agents/agent.ts +5 -5
  353. package/src/ai/agents/types.ts +1 -1
  354. package/src/ai/providers/rtzr/__tests__/model.test.ts +2 -2
  355. package/src/ai/providers/rtzr/error.ts +5 -3
  356. package/src/ai/providers/rtzr/model.ts +3 -2
  357. package/src/ai/providers/rtzr/options.ts +10 -5
  358. package/src/ai/providers/rtzr/provider.ts +10 -10
  359. package/src/ai/providers/rtzr/utils.ts +3 -1
  360. package/src/api/__tests__/config.test.ts +11 -21
  361. package/src/api/__tests__/sonamu.http-validator.test.ts +512 -0
  362. package/src/api/__tests__/sonamu.websocket.test.ts +51 -41
  363. package/src/api/__tests__/zod-compiler-policy.test.ts +95 -0
  364. package/src/api/caster.ts +6 -8
  365. package/src/api/code-converters.ts +136 -36
  366. package/src/api/config.ts +62 -4
  367. package/src/api/context.ts +3 -3
  368. package/src/api/decorators.ts +28 -17
  369. package/src/api/http-validator.ts +149 -0
  370. package/src/api/sonamu.ts +459 -152
  371. package/src/api/websocket-helpers.ts +24 -17
  372. package/src/auth/audit-log/builders.ts +3 -2
  373. package/src/auth/audit-log/client-ip.ts +4 -2
  374. package/src/auth/audit-log/events.ts +15 -1
  375. package/src/auth/audit-log/plugin.ts +129 -200
  376. package/src/auth/audit-log-ingestor.ts +19 -15
  377. package/src/auth/auth-generator.ts +10 -5
  378. package/src/auth/better-auth-request.ts +4 -3
  379. package/src/auth/knex-adapter.ts +8 -2
  380. package/src/auth/plugins/entity-definitions/index.ts +6 -5
  381. package/src/bin/__tests__/http-validator-benchmark.test.ts +94 -0
  382. package/src/bin/__tests__/test-command.test.ts +9 -15
  383. package/src/bin/__tests__/ts-loader-register.test.ts +15 -17
  384. package/src/bin/__tests__/zod-compiler-build.test.ts +307 -0
  385. package/src/bin/build-config.ts +167 -0
  386. package/src/bin/cli.ts +155 -38
  387. package/src/bin/compiler-policy.ts +35 -0
  388. package/src/bin/fixture.ts +14 -3
  389. package/src/bin/test-command.ts +74 -29
  390. package/src/bin/ts-loader-registration.ts +22 -4
  391. package/src/cache/decorator.ts +10 -3
  392. package/src/compress/compress.ts +17 -4
  393. package/src/cone/cone-generator.ts +34 -6
  394. package/src/database/__tests__/db.test.ts +1 -0
  395. package/src/database/__tests__/puri.test.ts +16 -15
  396. package/src/database/__tests__/transaction-scope.test.ts +5 -0
  397. package/src/database/_batch_update.ts +1 -0
  398. package/src/database/base-model.ts +81 -50
  399. package/src/database/base-model.types.ts +6 -6
  400. package/src/database/db.ts +29 -19
  401. package/src/database/knex.ts +30 -17
  402. package/src/database/puri-subset.test-d.ts +17 -0
  403. package/src/database/puri.ts +181 -143
  404. package/src/database/puri.types.test-d.ts +31 -1
  405. package/src/database/puri.types.ts +23 -21
  406. package/src/database/upsert-builder.ts +75 -53
  407. package/src/dict/sd.ts +15 -5
  408. package/src/dict/sonamu-dictionary.ts +6 -6
  409. package/src/dict/utils.ts +9 -1
  410. package/src/entity/entity-manager.ts +26 -9
  411. package/src/entity/entity-template-cone.ts +5 -10
  412. package/src/entity/entity.ts +50 -34
  413. package/src/env.ts +7 -3
  414. package/src/exceptions/error-handler.ts +17 -2
  415. package/src/exceptions/so-exceptions.ts +26 -20
  416. package/src/filter/utils.ts +21 -11
  417. package/src/index.ts +3 -0
  418. package/src/logger/configure.ts +26 -18
  419. package/src/migration/__tests__/migrator.test.ts +50 -57
  420. package/src/migration/code-generation.ts +132 -104
  421. package/src/migration/index-where-predicate.ts +51 -24
  422. package/src/migration/migration-set.ts +11 -5
  423. package/src/migration/migrator.ts +392 -244
  424. package/src/migration/postgresql-schema-reader.ts +52 -47
  425. package/src/migration/slack-confirm.ts +17 -15
  426. package/src/migration/types.ts +57 -0
  427. package/src/naite/naite-reporter.ts +1 -1
  428. package/src/naite/naite.ts +97 -24
  429. package/src/runtime-type.ts +34 -0
  430. package/src/ssr/hmr-opt-out.ts +78 -0
  431. package/src/ssr/renderer.ts +6 -0
  432. package/src/storage/base-file.ts +13 -13
  433. package/src/storage/buffered-file.ts +11 -11
  434. package/src/storage/s3-driver.ts +4 -1
  435. package/src/storage/uploaded-file.ts +8 -8
  436. package/src/stream/__tests__/ws-contracts.test.ts +4 -2
  437. package/src/stream/__tests__/ws-telemetry.test.ts +1 -1
  438. package/src/stream/__tests__/ws.test.ts +30 -6
  439. package/src/stream/sse.ts +12 -11
  440. package/src/stream/ws-core.ts +1 -1
  441. package/src/stream/ws-delivery.ts +16 -7
  442. package/src/stream/ws-local-connection-store.ts +2 -3
  443. package/src/stream/ws-presence-store.ts +6 -1
  444. package/src/stream/ws-registry.ts +16 -7
  445. package/src/stream/ws-telemetry.ts +66 -43
  446. package/src/stream/ws.ts +73 -39
  447. package/src/syncer/__tests__/api-parser.websocket-type-ref.test.ts +3 -2
  448. package/src/syncer/__tests__/http-validator-registry.test.ts +137 -0
  449. package/src/syncer/api-parser.ts +67 -27
  450. package/src/syncer/checksum.ts +17 -11
  451. package/src/syncer/code-generator.ts +25 -17
  452. package/src/syncer/entity-operations.ts +3 -5
  453. package/src/syncer/file-copy.ts +46 -0
  454. package/src/syncer/file-patterns.ts +11 -8
  455. package/src/syncer/file-tracking.ts +3 -4
  456. package/src/syncer/filesystem-dependencies.ts +73 -0
  457. package/src/syncer/module-loader.ts +8 -4
  458. package/src/syncer/syncer-actions.ts +56 -18
  459. package/src/syncer/syncer.ts +116 -43
  460. package/src/syncer/watcher.ts +8 -4
  461. package/src/tasks/decorator.ts +20 -12
  462. package/src/tasks/step-wrapper.ts +19 -9
  463. package/src/tasks/workflow-manager.ts +15 -9
  464. package/src/template/__tests__/http_validators.template.test.ts +160 -0
  465. package/src/template/__tests__/services.template.mutation.test.ts +24 -23
  466. package/src/template/__tests__/services.template.websocket.test.ts +21 -25
  467. package/src/template/entity-converter.ts +5 -2
  468. package/src/template/helpers.ts +8 -9
  469. package/src/template/implementations/generated.template.ts +5 -4
  470. package/src/template/implementations/generated_http.template.ts +61 -15
  471. package/src/template/implementations/generated_sso.template.ts +15 -4
  472. package/src/template/implementations/http_validators.template.ts +175 -0
  473. package/src/template/implementations/model.template.ts +3 -1
  474. package/src/template/implementations/sd.template.ts +81 -41
  475. package/src/template/implementations/services.template.ts +2 -2
  476. package/src/template/implementations/view_form.template.ts +56 -39
  477. package/src/template/implementations/view_list.template.ts +31 -23
  478. package/src/template/template-manager.ts +15 -13
  479. package/src/template/template-types.ts +13 -5
  480. package/src/template/template.ts +4 -3
  481. package/src/template/zod-converter.ts +206 -91
  482. package/src/testing/__tests__/dev-test-routes.test.ts +85 -25
  483. package/src/testing/__tests__/dev-vitest-manager.test.ts +15 -15
  484. package/src/testing/_relation-graph.ts +4 -1
  485. package/src/testing/bootstrap.ts +12 -5
  486. package/src/testing/data-explorer.ts +102 -53
  487. package/src/testing/dev-test-routes.ts +87 -50
  488. package/src/testing/dev-vitest-manager.ts +88 -32
  489. package/src/testing/faker-mappings.ts +2 -2
  490. package/src/testing/filesystem.ts +1 -0
  491. package/src/testing/fixture-generator.ts +191 -131
  492. package/src/testing/fixture-loader.ts +5 -1
  493. package/src/testing/fixture-manager.ts +129 -90
  494. package/src/testing/global-setup.ts +7 -3
  495. package/src/testing/index.ts +5 -0
  496. package/src/types/__tests__/entity-json-schema-search-text.test.ts +9 -3
  497. package/src/types/types.ts +184 -158
  498. package/src/ui/ai-api.ts +9 -7
  499. package/src/ui/ai-client.ts +61 -56
  500. package/src/ui/api.ts +726 -770
  501. package/src/ui/async-route.ts +4 -0
  502. package/src/ui/cdd-service.ts +35 -12
  503. package/src/ui/migrations-api.ts +381 -0
  504. package/src/utils/formatter.ts +7 -3
  505. package/src/utils/fs-utils.ts +5 -5
  506. package/src/utils/model.ts +4 -5
  507. package/src/utils/object-utils.ts +32 -22
  508. package/src/utils/process-utils.ts +4 -1
  509. package/src/utils/runtime-value.ts +43 -0
  510. package/src/utils/sql-parser.ts +13 -6
  511. package/src/utils/type-utils.ts +9 -7
  512. package/src/utils/utils.ts +19 -21
  513. package/src/utils/zod-error.ts +4 -2
  514. package/src/vector/chunking.ts +6 -1
  515. package/src/vector/embedding.ts +2 -1
  516. package/src/vector/types.ts +4 -2
  517. package/tsdown.api.config.ts +5 -2
  518. package/dist/ui-web/assets/index-CJf8uJYf.js +0 -176
  519. package/dist/ui-web/assets/index-GMMIVGja.css +0 -1
package/src/bin/cli.ts CHANGED
@@ -1,6 +1,6 @@
1
1
  import assert from "assert";
2
- import { execSync, spawn } from "child_process";
3
- import { mkdir, readdir, writeFile } from "fs/promises";
2
+ import { spawn, spawnSync } from "child_process";
3
+ import { mkdir, open, readFile, readdir, rm, writeFile } from "fs/promises";
4
4
  import { createRequire } from "module";
5
5
  import path from "path";
6
6
  import process from "process";
@@ -31,19 +31,88 @@ import { exists } from "../utils/fs-utils";
31
31
  import { findApiRootPath, findAppRootPath } from "../utils/utils";
32
32
  import { API_ARTIFACTS, WEB_ARTIFACTS } from "./build-config";
33
33
  import { type BuildArtifact } from "./build-config";
34
+ import {
35
+ assertApiZodCompilerBuildOutput,
36
+ createApiZodCompilerBuildWrapper,
37
+ HTTP_VALIDATOR_REGISTRY_BUILD_PATH,
38
+ HTTP_VALIDATOR_REGISTRY_SOURCE_PATH,
39
+ } from "./build-config";
40
+ import { loadBuildCompilerPolicy } from "./compiler-policy";
34
41
  import { fixtureExploreCommand, fixtureFetchCommand, fixtureGenCommand } from "./fixture";
35
42
  import { getMigrateRunTargets } from "./migrate-targets";
36
43
  import { testCommand } from "./test-command";
37
44
 
38
45
  let migrator: Migrator;
39
46
 
47
+ function runMysql(
48
+ args: string[],
49
+ stdio: [number | "ignore", number | "inherit", "inherit"] = ["ignore", "inherit", "inherit"],
50
+ ) {
51
+ const result = spawnSync("mysql", args, { stdio });
52
+ if (result.error) {
53
+ throw result.error;
54
+ }
55
+ if (result.status !== 0) {
56
+ throw new Error(`mysql 명령이 종료 코드 ${result.status ?? "unknown"}로 실패했습니다.`);
57
+ }
58
+ }
59
+
60
+ async function writeMysqlDump(args: string[], outputPath: string) {
61
+ const output = await open(outputPath, "w");
62
+ try {
63
+ const result = spawnSync("mysqldump", args, { stdio: ["ignore", output.fd, "inherit"] });
64
+ if (result.error) {
65
+ throw result.error;
66
+ }
67
+ if (result.status !== 0) {
68
+ throw new Error(`mysqldump 명령이 종료 코드 ${result.status ?? "unknown"}로 실패했습니다.`);
69
+ }
70
+ } finally {
71
+ await output.close();
72
+ }
73
+ }
74
+
75
+ async function runMysqlWithInput(args: string[], inputPath: string) {
76
+ const input = await open(inputPath, "r");
77
+ try {
78
+ runMysql(args, [input.fd, "inherit", "inherit"]);
79
+ } finally {
80
+ await input.close();
81
+ }
82
+ }
83
+
84
+ function openInCode(pathToOpen: string) {
85
+ const result = spawnSync("code", [pathToOpen], { stdio: ["ignore", "inherit", "inherit"] });
86
+ if (result.error) {
87
+ throw result.error;
88
+ }
89
+ if (result.status !== 0) {
90
+ throw new Error(`code 명령이 종료 코드 ${result.status ?? "unknown"}로 실패했습니다.`);
91
+ }
92
+ }
93
+
94
+ function mysqlConnectionArgs(connection: Knex.ConnectionConfig) {
95
+ return [
96
+ `-h${String(connection.host)}`,
97
+ `-u${String(connection.user)}`,
98
+ `-p${String(connection.password)}`,
99
+ ];
100
+ }
101
+
102
+ function copyToClipboard(value: string) {
103
+ const result = spawnSync("pbcopy", [], { input: value, stdio: ["pipe", "inherit", "inherit"] });
104
+ if (result.error) {
105
+ throw result.error;
106
+ }
107
+ if (result.status !== 0) {
108
+ throw new Error(`pbcopy 명령이 종료 코드 ${result.status ?? "unknown"}로 실패했습니다.`);
109
+ }
110
+ }
111
+
40
112
  /**
41
113
  * CLI 옵션을 파싱하는 헬퍼 함수
42
114
  */
43
- function parseCliOptions(argv: string[] = process.argv): {
44
- flags: Set<string>; // --regenerate, --ai, --no-cones 등
45
- options: Record<string, string>; // --locale ko 등
46
- } {
115
+ function parseCliOptions(argv: string[] = process.argv) {
47
116
  const flags = new Set<string>();
48
117
  const options: Record<string, string> = {};
49
118
 
@@ -388,8 +457,8 @@ async function dev_web() {
388
457
  * API 빌드 설정 파일 경로를 결정합니다.
389
458
  * 프로젝트 루트에 `tsdown.config.ts`가 있으면 그것을, 없으면 sonamu 기본 설정을 사용합니다.
390
459
  */
391
- async function resolveApiBuildConfigPath(): Promise<string> {
392
- const localConfigPath = path.join(process.cwd(), "tsdown.config.ts");
460
+ async function resolveApiBuildConfigPath(apiRootPath: string): Promise<string> {
461
+ const localConfigPath = path.join(apiRootPath, "tsdown.config.ts");
393
462
 
394
463
  try {
395
464
  if (await exists(localConfigPath)) {
@@ -421,22 +490,46 @@ async function build_all() {
421
490
  * Sonamu.init 없이 호출될 것을 상정하여 구현되었습니다.
422
491
  */
423
492
  async function build_api() {
424
- const appRoot = findAppRootPath();
425
- const configFilePath = await resolveApiBuildConfigPath();
493
+ const apiRootPath = findApiRootPath();
494
+ const baseConfigPath = await resolveApiBuildConfigPath(apiRootPath);
495
+ const policy = await loadBuildCompilerPolicy(apiRootPath);
496
+ const registryPath = path.join(apiRootPath, HTTP_VALIDATOR_REGISTRY_SOURCE_PATH);
497
+ const configFilePath = await createApiZodCompilerBuildWrapper({
498
+ apiRootPath,
499
+ baseConfigPath,
500
+ policy,
501
+ registryPath,
502
+ });
503
+ const temporaryConfigPath = configFilePath === baseConfigPath ? undefined : configFilePath;
426
504
 
427
505
  const apiStartedAt = Date.now();
428
506
  try {
429
507
  for (const artifact of API_ARTIFACTS) {
430
- const cwd = path.join(appRoot, artifact.projectPath);
508
+ const cwd = apiRootPath;
431
509
  printTaskHeader(artifact.name, artifact.description, cwd);
432
510
 
433
511
  await runBuildSteps(artifact, { cwd, buildCommandArgs: { configFilePath } });
434
512
  }
513
+ if (policy.api === "aot") {
514
+ const outputPath = path.join(apiRootPath, HTTP_VALIDATOR_REGISTRY_BUILD_PATH);
515
+ if (!(await exists(outputPath))) {
516
+ throw new Error(`Built HTTP validator registry not found: ${outputPath}`);
517
+ }
518
+ assertApiZodCompilerBuildOutput([
519
+ {
520
+ code: await readFile(outputPath, "utf8"),
521
+ path: outputPath,
522
+ },
523
+ ]);
524
+ }
435
525
  printBuildSummary("API", true, Date.now() - apiStartedAt);
436
526
  } catch (e) {
437
527
  printBuildSummary("API", false, Date.now() - apiStartedAt);
438
- console.error(e);
439
- process.exit(1);
528
+ throw e;
529
+ } finally {
530
+ if (temporaryConfigPath !== undefined) {
531
+ await rm(temporaryConfigPath, { force: true });
532
+ }
440
533
  }
441
534
  }
442
535
 
@@ -527,7 +620,6 @@ async function start() {
527
620
  return;
528
621
  }
529
622
 
530
- const { spawn } = await import("child_process");
531
623
  const serverProcess = spawn(
532
624
  process.execPath,
533
625
  ["--enable-source-maps", "-r", "dotenv/config", entryPoint],
@@ -554,12 +646,12 @@ async function setupFixtureManager() {
554
646
 
555
647
  async function migrate_apply(targets: (keyof SonamuDBConfig)[]) {
556
648
  await setupMigrator();
557
- await migrator.runAction("apply", targets);
649
+ await migrator.apply(targets);
558
650
  }
559
651
 
560
652
  async function migrate_run() {
561
653
  await setupMigrator();
562
- await migrator.runAction("apply", getMigrateRunTargets());
654
+ await migrator.apply(getMigrateRunTargets());
563
655
  }
564
656
 
565
657
  async function migrate_generate() {
@@ -597,7 +689,7 @@ async function migrate_status() {
597
689
 
598
690
  async function fixture_init() {
599
691
  const srcConfig = Sonamu.dbConfig[getSonamuEnvironment()];
600
- const targets = [
692
+ const targets = /* SAFETY: CLI 파서와 빌드 도구 입력 계약이 이 값의 타입을 보장한다. */ [
601
693
  {
602
694
  label: "(REMOTE) Fixture DB",
603
695
  config: Sonamu.dbConfig.fixture,
@@ -606,8 +698,12 @@ async function fixture_init() {
606
698
  label: "(LOCAL) Testing DB",
607
699
  config: Sonamu.dbConfig.test,
608
700
  toSkip: (() => {
609
- const remoteConn = Sonamu.dbConfig.fixture.connection as Knex.ConnectionConfig;
610
- const localConn = Sonamu.dbConfig.test.connection as Knex.ConnectionConfig;
701
+ const remoteConn =
702
+ /* SAFETY: CLI 파서와 빌드 도구 입력 계약이 이 값의 타입을 보장한다. */ Sonamu.dbConfig
703
+ .fixture.connection as Knex.ConnectionConfig;
704
+ const localConn =
705
+ /* SAFETY: CLI 파서와 빌드 도구 입력 계약이 이 값의 타입을 보장한다. */ Sonamu.dbConfig
706
+ .test.connection as Knex.ConnectionConfig;
611
707
  return remoteConn.host === localConn.host && remoteConn.database === localConn.database;
612
708
  })(),
613
709
  },
@@ -620,35 +716,56 @@ async function fixture_init() {
620
716
  // 1. 기준DB 스키마를 덤프
621
717
  console.log("DUMP...");
622
718
  const dumpFilename = `/tmp/sonamu-fixture-init-${Date.now()}.sql`;
623
- const srcConn = srcConfig.connection as Knex.ConnectionConfig;
719
+ const srcConn =
720
+ /* SAFETY: CLI 파서와 빌드 도구 입력 계약이 이 값의 타입을 보장한다. */ srcConfig.connection as Knex.ConnectionConfig;
624
721
  const migrationsDump = `/tmp/sonamu-fixture-init-migrations-${Date.now()}.sql`;
625
- execSync(
626
- `mysqldump -h${srcConn.host} -u${srcConn.user} -p${srcConn.password} --single-transaction -d --no-create-db --triggers ${srcConn.database} > ${dumpFilename}`,
722
+ await writeMysqlDump(
723
+ [
724
+ ...mysqlConnectionArgs(srcConn),
725
+ "--single-transaction",
726
+ "-d",
727
+ "--no-create-db",
728
+ "--triggers",
729
+ String(srcConn.database),
730
+ ],
731
+ dumpFilename,
627
732
  );
628
- const _db = knex(srcConfig);
629
- const [[migrations]] = await _db.raw(
733
+ const sourceDb = knex(srcConfig);
734
+ const [[migrations]] = await sourceDb.raw(
630
735
  "SELECT COUNT(*) as count FROM information_schema.tables WHERE table_schema = ? AND table_name = 'knex_migrations'",
631
736
  [srcConn.database],
632
737
  );
633
738
  if (migrations.count > 0) {
634
- execSync(
635
- `mysqldump -h${srcConn.host} -u${srcConn.user} -p${srcConn.password} --single-transaction --no-create-db --triggers ${srcConn.database} knex_migrations knex_migrations_lock > ${migrationsDump}`,
739
+ await writeMysqlDump(
740
+ [
741
+ ...mysqlConnectionArgs(srcConn),
742
+ "--single-transaction",
743
+ "--no-create-db",
744
+ "--triggers",
745
+ String(srcConn.database),
746
+ "knex_migrations",
747
+ "knex_migrations_lock",
748
+ ],
749
+ migrationsDump,
636
750
  );
637
751
  }
638
752
 
639
753
  // 2. 대상DB 각각에 대하여 존재여부 확인 후 붓기
640
754
  for (const { label, config, toSkip } of targets) {
641
- const conn = config.connection as Knex.ConnectionConfig;
755
+ const conn =
756
+ /* SAFETY: CLI 파서와 빌드 도구 입력 계약이 이 값의 타입을 보장한다. */ config.connection as Knex.ConnectionConfig;
642
757
 
643
758
  if (toSkip === true) {
644
759
  console.log(chalk.red(`${label}: Skipped!`));
645
760
  continue;
646
761
  }
647
762
 
763
+ // SAFETY: Sonamu DB 구성은 Knex 연결 구성으로 검증된 뒤 이 명령에 전달된다.
764
+ const databaseConnection = (config.connection ?? {}) as Knex.ConnectionConfig;
648
765
  const db = knex({
649
766
  ...config,
650
767
  connection: {
651
- ...((config.connection ?? {}) as Knex.ConnectionConfig),
768
+ ...databaseConnection,
652
769
  database: undefined,
653
770
  },
654
771
  });
@@ -660,18 +777,20 @@ async function fixture_init() {
660
777
  }
661
778
 
662
779
  console.log(`SYNC to ${label}...`);
663
- const mysqlCmd = `mysql -h${conn.host} -u${conn.user} -p${conn.password}`;
664
- execSync(`${mysqlCmd} -e 'DROP DATABASE IF EXISTS \`${conn.database}\`'`);
665
- execSync(`${mysqlCmd} -e 'CREATE DATABASE \`${conn.database}\`'`);
666
- execSync(`${mysqlCmd} ${conn.database} < ${dumpFilename}`);
780
+ const connectionArgs = mysqlConnectionArgs(conn);
781
+ const database = String(conn.database);
782
+ const escapedDatabase = database.replaceAll("`", "``");
783
+ runMysql([...connectionArgs, "-e", `DROP DATABASE IF EXISTS \`${escapedDatabase}\``]);
784
+ runMysql([...connectionArgs, "-e", `CREATE DATABASE \`${escapedDatabase}\``]);
785
+ await runMysqlWithInput([...connectionArgs, database], dumpFilename);
667
786
  if (await exists(migrationsDump)) {
668
- execSync(`${mysqlCmd} ${conn.database} < ${migrationsDump}`);
787
+ await runMysqlWithInput([...connectionArgs, database], migrationsDump);
669
788
  }
670
789
 
671
790
  await db.destroy();
672
791
  }
673
792
 
674
- await _db.destroy();
793
+ await sourceDb.destroy();
675
794
  }
676
795
 
677
796
  async function fixture_import(entityId: string, recordIds: number[]) {
@@ -799,14 +918,14 @@ async function stub_practice(name: string) {
799
918
  ].join("\n");
800
919
  await writeFile(dstPath, code);
801
920
 
802
- execSync(`code ${dstPath}`);
921
+ openInCode(dstPath);
803
922
 
804
923
  const runCode = `yarn node -r dotenv/config --enable-source-maps dist/practices/${fileName.replace(
805
924
  ".ts",
806
925
  ".js",
807
926
  )}`;
808
927
  console.log(`${chalk.blue(runCode)} copied to clipboard.`);
809
- execSync(`echo "${runCode}" | pbcopy`);
928
+ copyToClipboard(runCode);
810
929
  }
811
930
 
812
931
  async function stub_entity(entityId: string) {
@@ -822,7 +941,6 @@ async function stub_entity(entityId: string) {
822
941
  return;
823
942
  }
824
943
 
825
- const { EntityManager } = await import("../entity/entity-manager");
826
944
  const entity = EntityManager.get(entityId);
827
945
  if (!entity) {
828
946
  console.error(`Entity not found: ${entityId}`);
@@ -879,7 +997,6 @@ async function stub_entity(entityId: string) {
879
997
  * ANTHROPIC_API_KEY 필요 (sonamu.secret.ts 또는 환경변수)
880
998
  */
881
999
  async function cone_gen(entityId: string) {
882
- const { EntityManager } = await import("../entity/entity-manager");
883
1000
  const { flags, options } = parseCliOptions();
884
1001
 
885
1002
  // --all 옵션: 모든 entity cone 생성
@@ -0,0 +1,35 @@
1
+ import { pathToFileURL } from "node:url";
2
+
3
+ import { normalizeZodCompilerPolicy, type NormalizedZodCompilerPolicy } from "../api/config";
4
+ import { applyCurrentSnapshotToProcessEnv } from "../env";
5
+ import { isFunctionValue, isObjectValue } from "../utils/runtime-value";
6
+ import { ensureTsLoaderRegistered } from "./ts-loader-registration";
7
+
8
+ type BuildSourceConfig = {
9
+ validation?: {
10
+ zodCompiler?: unknown;
11
+ };
12
+ };
13
+
14
+ export async function loadBuildCompilerPolicy(
15
+ apiRootPath: string,
16
+ ): Promise<NormalizedZodCompilerPolicy> {
17
+ applyCurrentSnapshotToProcessEnv(apiRootPath);
18
+ await ensureTsLoaderRegistered(apiRootPath);
19
+
20
+ const configUrl = pathToFileURL(`${apiRootPath}/src/sonamu.config.ts`);
21
+ configUrl.searchParams.set("sonamu-build", `${Date.now()}-${Math.random()}`);
22
+ const imported =
23
+ /* SAFETY: CLI 파서와 빌드 도구 입력 계약이 이 값의 타입을 보장한다. */ (await import(
24
+ configUrl.href
25
+ )) as { default: unknown };
26
+ const configured = isFunctionValue(imported.default)
27
+ ? await Promise.resolve(imported.default())
28
+ : await Promise.resolve(imported.default);
29
+ if (!isObjectValue(configured) || configured === null || Array.isArray(configured)) {
30
+ throw new Error("sonamu.config.ts must export a configuration object");
31
+ }
32
+
33
+ const config: BuildSourceConfig = configured;
34
+ return normalizeZodCompilerPolicy(config.validation?.zodCompiler);
35
+ }
@@ -1,5 +1,6 @@
1
1
  import chalk from "chalk";
2
2
  import prompts from "prompts";
3
+ import { z } from "zod";
3
4
 
4
5
  import { Sonamu } from "../api/sonamu";
5
6
  import { DB } from "../database/db";
@@ -23,6 +24,16 @@ interface FixtureCommandOptions {
23
24
  "no-cache"?: boolean;
24
25
  }
25
26
 
27
+ interface SignupBody {
28
+ name: string;
29
+ email: string;
30
+ username: string;
31
+ password: string;
32
+ display_username?: string;
33
+ }
34
+
35
+ const SignupErrorResponse = z.object({ code: z.string().optional() }).passthrough();
36
+
26
37
  /**
27
38
  * username을 일반적인 규칙(영문자 시작, 영문자/숫자만, 1-20자)에 맞도록 정규화합니다.
28
39
  */
@@ -162,7 +173,7 @@ export async function fixtureGenCommand(options: FixtureCommandOptions) {
162
173
  const displayUsername =
163
174
  userData.display_username !== undefined ? String(userData.display_username) : undefined;
164
175
 
165
- const body: Record<string, unknown> = {
176
+ const body: SignupBody = {
166
177
  name,
167
178
  email,
168
179
  username,
@@ -181,8 +192,8 @@ export async function fixtureGenCommand(options: FixtureCommandOptions) {
181
192
  const response = await Sonamu.auth.handler(req);
182
193
 
183
194
  if (!response.ok) {
184
- const responseData = (await response.json()) as Record<string, unknown>;
185
- const code = typeof responseData.code === "string" ? responseData.code : undefined;
195
+ const responseData = SignupErrorResponse.parse(await response.json());
196
+ const code = responseData.code;
186
197
  if (code === "USER_ALREADY_EXISTS") {
187
198
  console.log(chalk.yellow(` ⚠️ ${email} 이미 존재 - 건너뜁니다.`));
188
199
  continue;
@@ -2,17 +2,58 @@ import path from "node:path";
2
2
 
3
3
  import chalk from "chalk";
4
4
 
5
- import { type SonamuConfig } from "../api/config";
6
5
  import { loadConfig } from "../api/config";
7
6
  import { type RunResult, type TestCaseResult } from "../testing";
7
+ import { isStringValue } from "../utils/runtime-value";
8
8
  import { findApiRootPath } from "../utils/utils";
9
9
 
10
- async function loadDevServerConfig(): Promise<SonamuConfig> {
10
+ interface TestServerLocation {
11
+ host: string;
12
+ port: number;
13
+ routePrefix: string;
14
+ baseUrl: string;
15
+ }
16
+
17
+ interface TestRunPayload {
18
+ files?: string[];
19
+ pattern?: string;
20
+ }
21
+
22
+ type TestCommandConfig = {
23
+ server: {
24
+ listen?: {
25
+ host?: string;
26
+ port?: number;
27
+ };
28
+ };
29
+ test?: {
30
+ devRunner?: {
31
+ enabled?: boolean;
32
+ routePrefix?: string;
33
+ };
34
+ };
35
+ };
36
+
37
+ export interface TestCommandDependencies {
38
+ fetch: typeof globalThis.fetch;
39
+ findApiRootPath: typeof findApiRootPath;
40
+ loadConfig: (apiRootPath: string) => Promise<TestCommandConfig>;
41
+ }
42
+
43
+ const testCommandDependencies: TestCommandDependencies = {
44
+ fetch: globalThis.fetch,
45
+ findApiRootPath,
46
+ loadConfig,
47
+ };
48
+
49
+ async function loadDevServerConfig(
50
+ dependencies: TestCommandDependencies,
51
+ ): Promise<TestCommandConfig> {
11
52
  const prevVitest = process.env.VITEST;
12
53
  process.env.VITEST = "true";
13
54
  try {
14
- const apiRootPath = findApiRootPath();
15
- return await loadConfig(apiRootPath);
55
+ const apiRootPath = dependencies.findApiRootPath();
56
+ return await dependencies.loadConfig(apiRootPath);
16
57
  } finally {
17
58
  if (prevVitest === undefined) {
18
59
  delete process.env.VITEST;
@@ -22,22 +63,19 @@ async function loadDevServerConfig(): Promise<SonamuConfig> {
22
63
  }
23
64
  }
24
65
 
25
- function resolveTestBaseUrl(config: SonamuConfig): {
26
- host: string;
27
- port: number;
28
- routePrefix: string;
29
- baseUrl: string;
30
- } {
66
+ function resolveTestBaseUrl(config: TestCommandConfig): TestServerLocation {
31
67
  const port = config.server.listen?.port ?? 3000;
32
68
  const host = config.server.listen?.host ?? "localhost";
33
69
  const routePrefix = config.test?.devRunner?.routePrefix ?? "/__test__";
34
70
  return { host, port, routePrefix, baseUrl: `http://${host}:${port}${routePrefix}` };
35
71
  }
36
72
 
37
- export async function testCommand(): Promise<void> {
73
+ export async function testCommand(
74
+ dependencies: TestCommandDependencies = testCommandDependencies,
75
+ ): Promise<void> {
38
76
  const args = process.argv.slice(3);
39
77
 
40
- const config = await loadDevServerConfig();
78
+ const config = await loadDevServerConfig(dependencies);
41
79
 
42
80
  // process.argv 파싱: sonamu test [file...] --pattern "이름" --traces --status
43
81
  const files: string[] = [];
@@ -59,7 +97,7 @@ export async function testCommand(): Promise<void> {
59
97
  }
60
98
 
61
99
  if (showStatus) {
62
- return testStatusCommand(config);
100
+ return testStatusCommand(config, dependencies.fetch);
63
101
  }
64
102
 
65
103
  if (!config.test?.devRunner?.enabled) {
@@ -74,7 +112,7 @@ export async function testCommand(): Promise<void> {
74
112
  const { baseUrl } = resolveTestBaseUrl(config);
75
113
  const url = `${baseUrl}/run`;
76
114
 
77
- const payload: { files?: string[]; pattern?: string } = {};
115
+ const payload: TestRunPayload = {};
78
116
  if (files.length > 0) {
79
117
  payload.files = files;
80
118
  }
@@ -83,7 +121,7 @@ export async function testCommand(): Promise<void> {
83
121
  }
84
122
 
85
123
  try {
86
- const response = await fetch(url, {
124
+ const response = await dependencies.fetch(url, {
87
125
  method: "POST",
88
126
  headers: { "Content-Type": "application/json" },
89
127
  body: JSON.stringify(payload),
@@ -99,7 +137,10 @@ export async function testCommand(): Promise<void> {
99
137
  }
100
138
 
101
139
  if (response.status === 500) {
102
- const errorBody = (await response.json()) as { error?: string };
140
+ const errorBody =
141
+ /* SAFETY: CLI 파서와 빌드 도구 입력 계약이 이 값의 타입을 보장한다. */ (await response.json()) as {
142
+ error?: string;
143
+ };
103
144
  console.error(chalk.red("Vitest 인스턴스가 아직 준비되지 않았습니다"));
104
145
  if (errorBody.error) {
105
146
  console.error(chalk.red(errorBody.error));
@@ -112,7 +153,8 @@ export async function testCommand(): Promise<void> {
112
153
  process.exit(1);
113
154
  }
114
155
 
115
- const result = (await response.json()) as RunResult;
156
+ const result =
157
+ /* SAFETY: CLI 파서와 빌드 도구 입력 계약이 이 값의 타입을 보장한다. */ (await response.json()) as RunResult;
116
158
 
117
159
  const { passed, failed: failedCount, total, durationMs } = result.summary;
118
160
  const passedStr = chalk.green(`${passed} passed`);
@@ -141,10 +183,9 @@ export async function testCommand(): Promise<void> {
141
183
  console.log(` ${chalk.dim(path.basename(file))}`);
142
184
  for (const trace of traces) {
143
185
  const loc = `${path.basename(trace.filePath)}:${trace.lineNumber}`;
144
- const valueStr =
145
- typeof trace.value === "string"
146
- ? trace.value
147
- : (JSON.stringify(trace.value, null, 2) ?? "undefined");
186
+ const valueStr = isStringValue(trace.value)
187
+ ? trace.value
188
+ : (JSON.stringify(trace.value, null, 2) ?? "undefined");
148
189
  console.log(`\n ${chalk.yellow(`[${trace.key}]`)} ${chalk.dim(loc)}`);
149
190
  const indented = valueStr.split("\n").join("\n ");
150
191
  console.log(` ${indented}`);
@@ -195,7 +236,10 @@ function collectTracesFromResults(
195
236
  return result;
196
237
  }
197
238
 
198
- async function testStatusCommand(config: SonamuConfig): Promise<void> {
239
+ async function testStatusCommand(
240
+ config: TestCommandConfig,
241
+ fetchRequest: typeof globalThis.fetch,
242
+ ): Promise<void> {
199
243
  if (!config.test?.devRunner?.enabled) {
200
244
  console.error(
201
245
  chalk.red(
@@ -209,19 +253,20 @@ async function testStatusCommand(config: SonamuConfig): Promise<void> {
209
253
  const url = `${baseUrl}/status`;
210
254
 
211
255
  try {
212
- const response = await fetch(url);
256
+ const response = await fetchRequest(url);
213
257
 
214
258
  if (!response.ok) {
215
259
  console.error(chalk.red(`예상하지 못한 응답: ${response.status}`));
216
260
  process.exit(1);
217
261
  }
218
262
 
219
- const status = (await response.json()) as {
220
- ready: boolean;
221
- running: boolean;
222
- lastRunAt: string | null;
223
- sseAvailable: boolean;
224
- };
263
+ const status =
264
+ /* SAFETY: CLI 파서와 빌드 도구 입력 계약이 이 값의 타입을 보장한다. */ (await response.json()) as {
265
+ ready: boolean;
266
+ running: boolean;
267
+ lastRunAt: string | null;
268
+ sseAvailable: boolean;
269
+ };
225
270
 
226
271
  console.log(chalk.bold("DevRunner 상태:"));
227
272
  console.log(` ready: ${status.ready ? chalk.green("true") : chalk.red("false")}`);
@@ -13,8 +13,23 @@ type GlobalWithTsLoaderRegisterState = typeof globalThis & {
13
13
  [tsLoaderRegisterStateKey]?: TsLoaderRegisterState;
14
14
  };
15
15
 
16
+ export interface TsLoaderRegistrationDependencies {
17
+ registerLoader: (specifier: string, options: { parentURL: string }) => void;
18
+ resolveLoaderPath: () => string;
19
+ }
20
+
21
+ const tsLoaderRegistrationDependencies: TsLoaderRegistrationDependencies = {
22
+ registerLoader(specifier, options) {
23
+ register(specifier, options);
24
+ },
25
+ resolveLoaderPath() {
26
+ return require.resolve("@sonamu-kit/ts-loader/loader");
27
+ },
28
+ };
29
+
16
30
  function getTsLoaderRegisterState(): TsLoaderRegisterState {
17
- const globalState = globalThis as GlobalWithTsLoaderRegisterState;
31
+ const globalState =
32
+ /* SAFETY: CLI 파서와 빌드 도구 입력 계약이 이 값의 타입을 보장한다. */ globalThis as GlobalWithTsLoaderRegisterState;
18
33
 
19
34
  if (!globalState[tsLoaderRegisterStateKey]) {
20
35
  globalState[tsLoaderRegisterStateKey] = { registered: false };
@@ -23,16 +38,19 @@ function getTsLoaderRegisterState(): TsLoaderRegisterState {
23
38
  return globalState[tsLoaderRegisterStateKey];
24
39
  }
25
40
 
26
- export async function ensureTsLoaderRegistered(apiRoot: string): Promise<void> {
41
+ export async function ensureTsLoaderRegistered(
42
+ apiRoot: string,
43
+ dependencies: TsLoaderRegistrationDependencies = tsLoaderRegistrationDependencies,
44
+ ): Promise<void> {
27
45
  const state = getTsLoaderRegisterState();
28
46
  if (state.registered) {
29
47
  return;
30
48
  }
31
49
 
32
50
  void apiRoot;
33
- const loaderPath = require.resolve("@sonamu-kit/ts-loader/loader");
51
+ const loaderPath = dependencies.resolveLoaderPath();
34
52
 
35
- register(pathToFileURL(loaderPath).href, {
53
+ dependencies.registerLoader(pathToFileURL(loaderPath).href, {
36
54
  parentURL: import.meta.url,
37
55
  });
38
56
  state.registered = true;