sonamu 0.10.12 → 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 (513) 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 +131 -27
  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 +12 -6
  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 +3 -2
  142. package/dist/migration/migrator.d.ts.map +1 -1
  143. package/dist/migration/migrator.js +27 -21
  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/naite/naite-reporter.js +2 -2
  149. package/dist/naite/naite.d.ts +74 -15
  150. package/dist/naite/naite.d.ts.map +1 -1
  151. package/dist/naite/naite.js +5 -19
  152. package/dist/runtime-type.d.ts +6 -0
  153. package/dist/runtime-type.d.ts.map +1 -0
  154. package/dist/runtime-type.js +26 -0
  155. package/dist/ssr/hmr-opt-out.d.ts +26 -0
  156. package/dist/ssr/hmr-opt-out.d.ts.map +1 -0
  157. package/dist/ssr/hmr-opt-out.js +59 -0
  158. package/dist/ssr/renderer.d.ts.map +1 -1
  159. package/dist/ssr/renderer.js +4 -1
  160. package/dist/storage/base-file.js +14 -14
  161. package/dist/storage/buffered-file.d.ts +2 -2
  162. package/dist/storage/buffered-file.d.ts.map +1 -1
  163. package/dist/storage/buffered-file.js +12 -12
  164. package/dist/storage/s3-driver.d.ts.map +1 -1
  165. package/dist/storage/s3-driver.js +1 -1
  166. package/dist/storage/uploaded-file.d.ts +2 -2
  167. package/dist/storage/uploaded-file.d.ts.map +1 -1
  168. package/dist/storage/uploaded-file.js +8 -8
  169. package/dist/stream/sse.js +11 -11
  170. package/dist/stream/ws-core.d.ts +1 -1
  171. package/dist/stream/ws-core.d.ts.map +1 -1
  172. package/dist/stream/ws-delivery.d.ts +1 -1
  173. package/dist/stream/ws-delivery.d.ts.map +1 -1
  174. package/dist/stream/ws-delivery.js +6 -4
  175. package/dist/stream/ws-local-connection-store.d.ts.map +1 -1
  176. package/dist/stream/ws-local-connection-store.js +4 -2
  177. package/dist/stream/ws-presence-store.js +1 -1
  178. package/dist/stream/ws-registry.d.ts +4 -4
  179. package/dist/stream/ws-registry.d.ts.map +1 -1
  180. package/dist/stream/ws-registry.js +4 -2
  181. package/dist/stream/ws-telemetry.d.ts +16 -12
  182. package/dist/stream/ws-telemetry.d.ts.map +1 -1
  183. package/dist/stream/ws-telemetry.js +22 -18
  184. package/dist/stream/ws.d.ts +18 -12
  185. package/dist/stream/ws.d.ts.map +1 -1
  186. package/dist/stream/ws.js +26 -22
  187. package/dist/syncer/api-parser.js +1 -1
  188. package/dist/syncer/checksum.d.ts.map +1 -1
  189. package/dist/syncer/checksum.js +7 -8
  190. package/dist/syncer/code-generator.d.ts.map +1 -1
  191. package/dist/syncer/code-generator.js +13 -14
  192. package/dist/syncer/entity-operations.d.ts.map +1 -1
  193. package/dist/syncer/entity-operations.js +5 -6
  194. package/dist/syncer/file-copy.d.ts +5 -0
  195. package/dist/syncer/file-copy.d.ts.map +1 -0
  196. package/dist/syncer/file-copy.js +36 -0
  197. package/dist/syncer/file-patterns.d.ts +1 -0
  198. package/dist/syncer/file-patterns.d.ts.map +1 -1
  199. package/dist/syncer/file-patterns.js +5 -2
  200. package/dist/syncer/file-tracking.d.ts.map +1 -1
  201. package/dist/syncer/file-tracking.js +5 -4
  202. package/dist/syncer/filesystem-dependencies.d.ts +15 -0
  203. package/dist/syncer/filesystem-dependencies.d.ts.map +1 -0
  204. package/dist/syncer/filesystem-dependencies.js +53 -0
  205. package/dist/syncer/module-loader.d.ts +1 -1
  206. package/dist/syncer/module-loader.d.ts.map +1 -1
  207. package/dist/syncer/module-loader.js +6 -4
  208. package/dist/syncer/syncer-actions.d.ts +4 -0
  209. package/dist/syncer/syncer-actions.d.ts.map +1 -1
  210. package/dist/syncer/syncer-actions.js +34 -17
  211. package/dist/syncer/syncer.d.ts +17 -6
  212. package/dist/syncer/syncer.d.ts.map +1 -1
  213. package/dist/syncer/syncer.js +71 -29
  214. package/dist/syncer/watcher.d.ts.map +1 -1
  215. package/dist/syncer/watcher.js +3 -3
  216. package/dist/tasks/decorator.d.ts +6 -6
  217. package/dist/tasks/decorator.d.ts.map +1 -1
  218. package/dist/tasks/decorator.js +4 -4
  219. package/dist/tasks/step-wrapper.d.ts +6 -4
  220. package/dist/tasks/step-wrapper.d.ts.map +1 -1
  221. package/dist/tasks/step-wrapper.js +5 -5
  222. package/dist/tasks/workflow-manager.d.ts.map +1 -1
  223. package/dist/tasks/workflow-manager.js +13 -7
  224. package/dist/template/entity-converter.d.ts +1 -1
  225. package/dist/template/entity-converter.d.ts.map +1 -1
  226. package/dist/template/entity-converter.js +2 -2
  227. package/dist/template/helpers.d.ts +8 -6
  228. package/dist/template/helpers.d.ts.map +1 -1
  229. package/dist/template/helpers.js +1 -1
  230. package/dist/template/implementations/generated.template.d.ts.map +1 -1
  231. package/dist/template/implementations/generated.template.js +4 -4
  232. package/dist/template/implementations/generated_http.template.d.ts +7 -4
  233. package/dist/template/implementations/generated_http.template.d.ts.map +1 -1
  234. package/dist/template/implementations/generated_http.template.js +21 -21
  235. package/dist/template/implementations/generated_sso.template.d.ts.map +1 -1
  236. package/dist/template/implementations/generated_sso.template.js +6 -3
  237. package/dist/template/implementations/http_validators.template.d.ts +18 -0
  238. package/dist/template/implementations/http_validators.template.d.ts.map +1 -0
  239. package/dist/template/implementations/http_validators.template.js +127 -0
  240. package/dist/template/implementations/model.template.d.ts.map +1 -1
  241. package/dist/template/implementations/model.template.js +1 -1
  242. package/dist/template/implementations/queries.template.js +1 -1
  243. package/dist/template/implementations/sd.template.d.ts.map +1 -1
  244. package/dist/template/implementations/sd.template.js +79 -39
  245. package/dist/template/implementations/services.template.d.ts.map +1 -1
  246. package/dist/template/implementations/services.template.js +6 -4
  247. package/dist/template/implementations/view_form.template.d.ts +6 -1
  248. package/dist/template/implementations/view_form.template.d.ts.map +1 -1
  249. package/dist/template/implementations/view_form.template.js +23 -15
  250. package/dist/template/implementations/view_list.template.d.ts.map +1 -1
  251. package/dist/template/implementations/view_list.template.js +11 -6
  252. package/dist/template/template-manager.d.ts.map +1 -1
  253. package/dist/template/template-manager.js +9 -7
  254. package/dist/template/template-types.d.ts +12 -5
  255. package/dist/template/template-types.d.ts.map +1 -1
  256. package/dist/template/template-types.js +1 -1
  257. package/dist/template/template.d.ts +2 -2
  258. package/dist/template/template.d.ts.map +1 -1
  259. package/dist/template/template.js +6 -4
  260. package/dist/template/zod-converter.d.ts +0 -19
  261. package/dist/template/zod-converter.d.ts.map +1 -1
  262. package/dist/template/zod-converter.js +100 -84
  263. package/dist/testing/_relation-graph.d.ts.map +1 -1
  264. package/dist/testing/_relation-graph.js +2 -1
  265. package/dist/testing/bootstrap.d.ts.map +1 -1
  266. package/dist/testing/bootstrap.js +9 -6
  267. package/dist/testing/data-explorer.d.ts +32 -7
  268. package/dist/testing/data-explorer.d.ts.map +1 -1
  269. package/dist/testing/data-explorer.js +77 -31
  270. package/dist/testing/dev-test-routes.d.ts +8 -1
  271. package/dist/testing/dev-test-routes.d.ts.map +1 -1
  272. package/dist/testing/dev-test-routes.js +125 -108
  273. package/dist/testing/dev-vitest-manager.d.ts +54 -8
  274. package/dist/testing/dev-vitest-manager.d.ts.map +1 -1
  275. package/dist/testing/dev-vitest-manager.js +24 -9
  276. package/dist/testing/faker-mappings.d.ts +412 -1
  277. package/dist/testing/faker-mappings.d.ts.map +1 -1
  278. package/dist/testing/faker-mappings.js +1 -1
  279. package/dist/testing/filesystem.d.ts +2 -0
  280. package/dist/testing/filesystem.d.ts.map +1 -0
  281. package/dist/testing/filesystem.js +7 -0
  282. package/dist/testing/fixture-generator.d.ts +25 -8
  283. package/dist/testing/fixture-generator.d.ts.map +1 -1
  284. package/dist/testing/fixture-generator.js +132 -73
  285. package/dist/testing/fixture-loader.d.ts +3 -1
  286. package/dist/testing/fixture-loader.d.ts.map +1 -1
  287. package/dist/testing/fixture-loader.js +1 -20
  288. package/dist/testing/fixture-manager.d.ts +8 -7
  289. package/dist/testing/fixture-manager.d.ts.map +1 -1
  290. package/dist/testing/fixture-manager.js +91 -59
  291. package/dist/testing/global-setup.d.ts.map +1 -1
  292. package/dist/testing/global-setup.js +5 -2
  293. package/dist/testing/index.d.ts +2 -0
  294. package/dist/testing/index.d.ts.map +1 -1
  295. package/dist/testing/index.js +6 -3
  296. package/dist/types/types.d.ts +101 -99
  297. package/dist/types/types.d.ts.map +1 -1
  298. package/dist/types/types.js +234 -225
  299. package/dist/ui/ai-api.d.ts.map +1 -1
  300. package/dist/ui/ai-api.js +1 -1
  301. package/dist/ui/ai-client.d.ts.map +1 -1
  302. package/dist/ui/ai-client.js +28 -18
  303. package/dist/ui/api.d.ts.map +1 -1
  304. package/dist/ui/api.js +135 -128
  305. package/dist/ui/async-route.d.ts +3 -0
  306. package/dist/ui/async-route.d.ts.map +1 -0
  307. package/dist/ui/async-route.js +12 -0
  308. package/dist/ui/cdd-service.d.ts +9 -7
  309. package/dist/ui/cdd-service.d.ts.map +1 -1
  310. package/dist/ui/cdd-service.js +7 -5
  311. package/dist/ui/migrations-api.d.ts.map +1 -1
  312. package/dist/ui/migrations-api.js +17 -15
  313. package/dist/ui-web/assets/index-DV1AAq6W.js +178 -0
  314. package/dist/ui-web/index.html +1 -1
  315. package/dist/utils/formatter.d.ts.map +1 -1
  316. package/dist/utils/formatter.js +7 -5
  317. package/dist/utils/fs-utils.d.ts +3 -3
  318. package/dist/utils/fs-utils.d.ts.map +1 -1
  319. package/dist/utils/fs-utils.js +6 -6
  320. package/dist/utils/model.d.ts +3 -5
  321. package/dist/utils/model.d.ts.map +1 -1
  322. package/dist/utils/model.js +1 -1
  323. package/dist/utils/object-utils.d.ts +1 -1
  324. package/dist/utils/object-utils.d.ts.map +1 -1
  325. package/dist/utils/object-utils.js +17 -16
  326. package/dist/utils/process-utils.d.ts.map +1 -1
  327. package/dist/utils/process-utils.js +4 -2
  328. package/dist/utils/runtime-value.d.ts +13 -0
  329. package/dist/utils/runtime-value.d.ts.map +1 -0
  330. package/dist/utils/runtime-value.js +40 -0
  331. package/dist/utils/sql-parser.d.ts +8 -1
  332. package/dist/utils/sql-parser.d.ts.map +1 -1
  333. package/dist/utils/sql-parser.js +6 -3
  334. package/dist/utils/type-utils.d.ts.map +1 -1
  335. package/dist/utils/type-utils.js +10 -8
  336. package/dist/utils/utils.d.ts +2 -2
  337. package/dist/utils/utils.d.ts.map +1 -1
  338. package/dist/utils/utils.js +11 -8
  339. package/dist/utils/zod-error.d.ts.map +1 -1
  340. package/dist/utils/zod-error.js +7 -4
  341. package/dist/vector/chunking.d.ts.map +1 -1
  342. package/dist/vector/chunking.js +1 -1
  343. package/dist/vector/embedding.d.ts.map +1 -1
  344. package/dist/vector/embedding.js +1 -1
  345. package/dist/vector/types.d.ts +3 -2
  346. package/dist/vector/types.d.ts.map +1 -1
  347. package/package.json +5 -3
  348. package/src/ai/agents/agent.ts +5 -5
  349. package/src/ai/agents/types.ts +1 -1
  350. package/src/ai/providers/rtzr/__tests__/model.test.ts +2 -2
  351. package/src/ai/providers/rtzr/error.ts +5 -3
  352. package/src/ai/providers/rtzr/model.ts +3 -2
  353. package/src/ai/providers/rtzr/options.ts +10 -5
  354. package/src/ai/providers/rtzr/provider.ts +10 -10
  355. package/src/ai/providers/rtzr/utils.ts +3 -1
  356. package/src/api/__tests__/config.test.ts +11 -21
  357. package/src/api/__tests__/sonamu.http-validator.test.ts +512 -0
  358. package/src/api/__tests__/sonamu.websocket.test.ts +51 -41
  359. package/src/api/__tests__/zod-compiler-policy.test.ts +95 -0
  360. package/src/api/caster.ts +6 -8
  361. package/src/api/code-converters.ts +136 -36
  362. package/src/api/config.ts +62 -4
  363. package/src/api/context.ts +3 -3
  364. package/src/api/decorators.ts +28 -17
  365. package/src/api/http-validator.ts +149 -0
  366. package/src/api/sonamu.ts +459 -152
  367. package/src/api/websocket-helpers.ts +24 -17
  368. package/src/auth/audit-log/builders.ts +3 -2
  369. package/src/auth/audit-log/client-ip.ts +4 -2
  370. package/src/auth/audit-log/events.ts +15 -1
  371. package/src/auth/audit-log/plugin.ts +129 -200
  372. package/src/auth/audit-log-ingestor.ts +19 -15
  373. package/src/auth/auth-generator.ts +10 -5
  374. package/src/auth/better-auth-request.ts +4 -3
  375. package/src/auth/knex-adapter.ts +8 -2
  376. package/src/auth/plugins/entity-definitions/index.ts +6 -5
  377. package/src/bin/__tests__/http-validator-benchmark.test.ts +94 -0
  378. package/src/bin/__tests__/test-command.test.ts +9 -15
  379. package/src/bin/__tests__/ts-loader-register.test.ts +15 -17
  380. package/src/bin/__tests__/zod-compiler-build.test.ts +307 -0
  381. package/src/bin/build-config.ts +167 -0
  382. package/src/bin/cli.ts +153 -36
  383. package/src/bin/compiler-policy.ts +35 -0
  384. package/src/bin/fixture.ts +14 -3
  385. package/src/bin/test-command.ts +74 -29
  386. package/src/bin/ts-loader-registration.ts +22 -4
  387. package/src/cache/decorator.ts +10 -3
  388. package/src/compress/compress.ts +17 -4
  389. package/src/cone/cone-generator.ts +34 -6
  390. package/src/database/__tests__/db.test.ts +1 -0
  391. package/src/database/__tests__/puri.test.ts +16 -15
  392. package/src/database/__tests__/transaction-scope.test.ts +5 -0
  393. package/src/database/_batch_update.ts +1 -0
  394. package/src/database/base-model.ts +81 -50
  395. package/src/database/base-model.types.ts +6 -6
  396. package/src/database/db.ts +29 -19
  397. package/src/database/knex.ts +30 -17
  398. package/src/database/puri-subset.test-d.ts +17 -0
  399. package/src/database/puri.ts +181 -143
  400. package/src/database/puri.types.test-d.ts +31 -1
  401. package/src/database/puri.types.ts +23 -21
  402. package/src/database/upsert-builder.ts +75 -53
  403. package/src/dict/sd.ts +15 -5
  404. package/src/dict/sonamu-dictionary.ts +6 -6
  405. package/src/dict/utils.ts +9 -1
  406. package/src/entity/entity-manager.ts +26 -9
  407. package/src/entity/entity-template-cone.ts +5 -10
  408. package/src/entity/entity.ts +50 -34
  409. package/src/env.ts +7 -3
  410. package/src/exceptions/error-handler.ts +17 -2
  411. package/src/exceptions/so-exceptions.ts +26 -20
  412. package/src/filter/utils.ts +21 -11
  413. package/src/index.ts +3 -0
  414. package/src/logger/configure.ts +26 -18
  415. package/src/migration/__tests__/migrator.test.ts +50 -57
  416. package/src/migration/code-generation.ts +132 -104
  417. package/src/migration/index-where-predicate.ts +51 -24
  418. package/src/migration/migration-set.ts +11 -5
  419. package/src/migration/migrator.ts +68 -41
  420. package/src/migration/postgresql-schema-reader.ts +52 -47
  421. package/src/migration/slack-confirm.ts +17 -15
  422. package/src/naite/naite-reporter.ts +1 -1
  423. package/src/naite/naite.ts +97 -24
  424. package/src/runtime-type.ts +34 -0
  425. package/src/ssr/hmr-opt-out.ts +78 -0
  426. package/src/ssr/renderer.ts +6 -0
  427. package/src/storage/base-file.ts +13 -13
  428. package/src/storage/buffered-file.ts +11 -11
  429. package/src/storage/s3-driver.ts +4 -1
  430. package/src/storage/uploaded-file.ts +8 -8
  431. package/src/stream/__tests__/ws-contracts.test.ts +4 -2
  432. package/src/stream/__tests__/ws-telemetry.test.ts +1 -1
  433. package/src/stream/__tests__/ws.test.ts +30 -6
  434. package/src/stream/sse.ts +12 -11
  435. package/src/stream/ws-core.ts +1 -1
  436. package/src/stream/ws-delivery.ts +16 -7
  437. package/src/stream/ws-local-connection-store.ts +2 -3
  438. package/src/stream/ws-presence-store.ts +6 -1
  439. package/src/stream/ws-registry.ts +16 -7
  440. package/src/stream/ws-telemetry.ts +66 -43
  441. package/src/stream/ws.ts +73 -39
  442. package/src/syncer/__tests__/api-parser.websocket-type-ref.test.ts +3 -2
  443. package/src/syncer/__tests__/http-validator-registry.test.ts +137 -0
  444. package/src/syncer/api-parser.ts +67 -27
  445. package/src/syncer/checksum.ts +17 -11
  446. package/src/syncer/code-generator.ts +25 -17
  447. package/src/syncer/entity-operations.ts +3 -5
  448. package/src/syncer/file-copy.ts +46 -0
  449. package/src/syncer/file-patterns.ts +11 -8
  450. package/src/syncer/file-tracking.ts +3 -4
  451. package/src/syncer/filesystem-dependencies.ts +73 -0
  452. package/src/syncer/module-loader.ts +8 -4
  453. package/src/syncer/syncer-actions.ts +56 -18
  454. package/src/syncer/syncer.ts +116 -43
  455. package/src/syncer/watcher.ts +8 -4
  456. package/src/tasks/decorator.ts +20 -12
  457. package/src/tasks/step-wrapper.ts +19 -9
  458. package/src/tasks/workflow-manager.ts +15 -9
  459. package/src/template/__tests__/http_validators.template.test.ts +160 -0
  460. package/src/template/__tests__/services.template.mutation.test.ts +24 -23
  461. package/src/template/__tests__/services.template.websocket.test.ts +21 -25
  462. package/src/template/entity-converter.ts +5 -2
  463. package/src/template/helpers.ts +8 -9
  464. package/src/template/implementations/generated.template.ts +5 -4
  465. package/src/template/implementations/generated_http.template.ts +61 -15
  466. package/src/template/implementations/generated_sso.template.ts +15 -4
  467. package/src/template/implementations/http_validators.template.ts +175 -0
  468. package/src/template/implementations/model.template.ts +3 -1
  469. package/src/template/implementations/sd.template.ts +81 -41
  470. package/src/template/implementations/services.template.ts +2 -2
  471. package/src/template/implementations/view_form.template.ts +56 -39
  472. package/src/template/implementations/view_list.template.ts +31 -23
  473. package/src/template/template-manager.ts +15 -13
  474. package/src/template/template-types.ts +13 -5
  475. package/src/template/template.ts +4 -3
  476. package/src/template/zod-converter.ts +206 -91
  477. package/src/testing/__tests__/dev-test-routes.test.ts +85 -25
  478. package/src/testing/__tests__/dev-vitest-manager.test.ts +15 -15
  479. package/src/testing/_relation-graph.ts +4 -1
  480. package/src/testing/bootstrap.ts +12 -5
  481. package/src/testing/data-explorer.ts +102 -53
  482. package/src/testing/dev-test-routes.ts +87 -50
  483. package/src/testing/dev-vitest-manager.ts +88 -32
  484. package/src/testing/faker-mappings.ts +2 -2
  485. package/src/testing/filesystem.ts +1 -0
  486. package/src/testing/fixture-generator.ts +191 -131
  487. package/src/testing/fixture-loader.ts +5 -1
  488. package/src/testing/fixture-manager.ts +129 -90
  489. package/src/testing/global-setup.ts +7 -3
  490. package/src/testing/index.ts +5 -0
  491. package/src/types/__tests__/entity-json-schema-search-text.test.ts +9 -3
  492. package/src/types/types.ts +184 -158
  493. package/src/ui/ai-api.ts +9 -7
  494. package/src/ui/ai-client.ts +61 -56
  495. package/src/ui/api.ts +727 -616
  496. package/src/ui/async-route.ts +4 -0
  497. package/src/ui/cdd-service.ts +35 -12
  498. package/src/ui/migrations-api.ts +63 -51
  499. package/src/utils/formatter.ts +7 -3
  500. package/src/utils/fs-utils.ts +5 -5
  501. package/src/utils/model.ts +4 -5
  502. package/src/utils/object-utils.ts +32 -22
  503. package/src/utils/process-utils.ts +4 -1
  504. package/src/utils/runtime-value.ts +43 -0
  505. package/src/utils/sql-parser.ts +13 -6
  506. package/src/utils/type-utils.ts +9 -7
  507. package/src/utils/utils.ts +19 -21
  508. package/src/utils/zod-error.ts +4 -2
  509. package/src/vector/chunking.ts +6 -1
  510. package/src/vector/embedding.ts +2 -1
  511. package/src/vector/types.ts +4 -2
  512. package/tsdown.api.config.ts +5 -2
  513. package/dist/ui-web/assets/index-C0m1pk6K.js +0 -177
@@ -1,3 +1,4 @@
1
+ import path from "path";
1
2
  /**
2
3
  * zod-converter 구성
3
4
  * 1. 유틸리티
@@ -18,8 +19,6 @@
18
19
  * - resolveRenderType
19
20
  */
20
21
 
21
- import path from "path";
22
-
23
22
  import inflection from "inflection";
24
23
  import { z } from "zod";
25
24
 
@@ -65,6 +64,7 @@ import {
65
64
  } from "../types/types";
66
65
  import { createImportUrl } from "../utils/esm-utils";
67
66
  import { runtimePath } from "../utils/path-utils";
67
+ import { isObjectValue, isStringValue } from "../utils/runtime-value";
68
68
 
69
69
  // <any>를 자제하고, Zod에서 제약하는 기본적인 Generic Type Parameter를 사용함.
70
70
  type AnyZodRecord = z.ZodRecord<z.ZodString | z.ZodNumber | z.ZodSymbol, z.ZodType>;
@@ -102,33 +102,28 @@ function getBuiltInSchemaName(zodType: z.ZodType): string | undefined {
102
102
  * Zod 4에서는 z.email(), z.uuid() 등 독립적인 함수 형태를 사용합니다.
103
103
  */
104
104
  function zodFormatToCode(format: ZodStringFormat): string {
105
- // ISO 포맷은 z.iso.xxx() 형태
106
- const isoFormats: Record<string, string> = {
107
- isoDate: "z.iso.date()",
108
- isoTime: "z.iso.time()",
109
- isoDatetime: "z.iso.datetime()",
110
- isoDuration: "z.iso.duration()",
111
- };
112
-
113
- // hash 포맷은 z.hash("algorithm") 형태
114
- const hashFormats: Record<string, string> = {
115
- hashMd5: 'z.hash("md5")',
116
- hashSha1: 'z.hash("sha1")',
117
- hashSha256: 'z.hash("sha256")',
118
- hashSha384: 'z.hash("sha384")',
119
- hashSha512: 'z.hash("sha512")',
120
- };
121
-
122
- if (format in isoFormats) {
123
- return isoFormats[format];
124
- }
125
-
126
- if (format in hashFormats) {
127
- return hashFormats[format];
105
+ switch (format) {
106
+ case "isoDate":
107
+ return "z.iso.date()";
108
+ case "isoTime":
109
+ return "z.iso.time()";
110
+ case "isoDatetime":
111
+ return "z.iso.datetime()";
112
+ case "isoDuration":
113
+ return "z.iso.duration()";
114
+ case "hashMd5":
115
+ return 'z.hash("md5")';
116
+ case "hashSha1":
117
+ return 'z.hash("sha1")';
118
+ case "hashSha256":
119
+ return 'z.hash("sha256")';
120
+ case "hashSha384":
121
+ return 'z.hash("sha384")';
122
+ case "hashSha512":
123
+ return 'z.hash("sha512")';
124
+ default:
125
+ return `z.${format}()`;
128
126
  }
129
-
130
- // 기본 포맷은 z.xxx() 형태 (Zod 4)
131
- return `z.${format}()`;
132
127
  }
133
128
 
134
129
  /**
@@ -136,8 +131,45 @@ function zodFormatToCode(format: ZodStringFormat): string {
136
131
  * Zod 4에서는 z.email(), z.uuid() 등 독립적인 함수 형태를 사용합니다.
137
132
  */
138
133
  function zodFormatToType(format: ZodStringFormat): z.ZodType {
139
- // ISO 포맷은 z.iso.xxx() 형태
140
134
  switch (format) {
135
+ case "email":
136
+ return z.email();
137
+ case "uuid":
138
+ return z.uuid();
139
+ case "url":
140
+ return z.url();
141
+ case "httpUrl":
142
+ return z.httpUrl();
143
+ case "hostname":
144
+ return z.hostname();
145
+ case "emoji":
146
+ return z.emoji();
147
+ case "base64":
148
+ return z.base64();
149
+ case "base64url":
150
+ return z.base64url();
151
+ case "hex":
152
+ return z.hex();
153
+ case "jwt":
154
+ return z.jwt();
155
+ case "nanoid":
156
+ return z.nanoid();
157
+ case "cuid":
158
+ return z.cuid();
159
+ case "cuid2":
160
+ return z.cuid2();
161
+ case "ulid":
162
+ return z.ulid();
163
+ case "ipv4":
164
+ return z.ipv4();
165
+ case "ipv6":
166
+ return z.ipv6();
167
+ case "mac":
168
+ return z.mac();
169
+ case "cidrv4":
170
+ return z.cidrv4();
171
+ case "cidrv6":
172
+ return z.cidrv6();
141
173
  case "isoDate":
142
174
  return z.iso.date();
143
175
  case "isoTime":
@@ -146,7 +178,6 @@ function zodFormatToType(format: ZodStringFormat): z.ZodType {
146
178
  return z.iso.datetime();
147
179
  case "isoDuration":
148
180
  return z.iso.duration();
149
- // hash 포맷은 z.hash("algorithm") 형태
150
181
  case "hashMd5":
151
182
  return z.hash("md5");
152
183
  case "hashSha1":
@@ -157,9 +188,6 @@ function zodFormatToType(format: ZodStringFormat): z.ZodType {
157
188
  return z.hash("sha384");
158
189
  case "hashSha512":
159
190
  return z.hash("sha512");
160
- // 기본 포맷은 z.xxx() 형태 (Zod 4)
161
- default:
162
- return (z as unknown as Record<string, () => z.ZodType>)[format]();
163
191
  }
164
192
  }
165
193
 
@@ -170,8 +198,15 @@ function zodFormatToType(format: ZodStringFormat): z.ZodType {
170
198
  */
171
199
  export async function getZodTypeById(zodTypeId: string): Promise<z.ZodTypeAny> {
172
200
  // 내장 타입 처리
173
- if ((BUILT_IN_TYPE_IDS as readonly string[]).includes(zodTypeId)) {
174
- const builtInType = BUILT_IN_TYPES[zodTypeId as keyof typeof BUILT_IN_TYPES];
201
+ if (
202
+ /* SAFETY: 선행 Zod 종류 분기와 템플릿 입력 계약이 이 값의 타입을 보장한다. */ (
203
+ BUILT_IN_TYPE_IDS as readonly string[]
204
+ ).includes(zodTypeId)
205
+ ) {
206
+ const builtInType =
207
+ BUILT_IN_TYPES[
208
+ /* SAFETY: 선행 Zod 종류 분기와 템플릿 입력 계약이 이 값의 타입을 보장한다. */ zodTypeId as keyof typeof BUILT_IN_TYPES
209
+ ];
175
210
  if (!builtInType) {
176
211
  throw new Error(`내장 타입 ${zodTypeId}의 스키마가 정의되지 않았습니다`);
177
212
  }
@@ -215,7 +250,9 @@ export async function propToZodType(prop: EntityProp): Promise<z.ZodTypeAny> {
215
250
  if (prop.zodFormat) {
216
251
  zodType = zodFormatToType(prop.zodFormat);
217
252
  if (prop.length && "max" in zodType) {
218
- zodType = (zodType as z.ZodString).max(prop.length);
253
+ zodType = /* SAFETY: 선행 Zod 종류 분기와 템플릿 입력 계약이 이 값의 타입을 보장한다. */ (
254
+ zodType as z.ZodString
255
+ ).max(prop.length);
219
256
  }
220
257
  } else if (prop.length) {
221
258
  zodType = z.string().max(prop.length);
@@ -227,7 +264,10 @@ export async function propToZodType(prop: EntityProp): Promise<z.ZodTypeAny> {
227
264
  if (prop.zodFormat) {
228
265
  elementType = zodFormatToType(prop.zodFormat);
229
266
  if (prop.length && "max" in elementType) {
230
- elementType = (elementType as z.ZodString).max(prop.length);
267
+ elementType =
268
+ /* SAFETY: 선행 Zod 종류 분기와 템플릿 입력 계약이 이 값의 타입을 보장한다. */ (
269
+ elementType as z.ZodString
270
+ ).max(prop.length);
231
271
  }
232
272
  } else if (prop.length) {
233
273
  elementType = z.string().max(prop.length);
@@ -280,8 +320,14 @@ export async function propToZodType(prop: EntityProp): Promise<z.ZodTypeAny> {
280
320
  throw new Error(`prop을 zodType으로 변환하는데 실패 ${prop}}`);
281
321
  }
282
322
 
283
- if ((prop as { unsigned?: boolean }).unsigned) {
284
- zodType = (zodType as z.ZodNumber).nonnegative();
323
+ if (
324
+ /* SAFETY: 선행 Zod 종류 분기와 템플릿 입력 계약이 이 값의 타입을 보장한다. */ (
325
+ prop as { unsigned?: boolean }
326
+ ).unsigned
327
+ ) {
328
+ zodType = /* SAFETY: 선행 Zod 종류 분기와 템플릿 입력 계약이 이 값의 타입을 보장한다. */ (
329
+ zodType as z.ZodNumber
330
+ ).nonnegative();
285
331
  }
286
332
  if (prop.nullable) {
287
333
  zodType = zodType.nullable();
@@ -357,7 +403,11 @@ export function propToZodTypeDef(prop: EntityProp, injectImportKeys: string[]):
357
403
  stmt = `${prop.name}: z.uuid().array()`;
358
404
  } else if (isJsonProp(prop)) {
359
405
  // 내장 타입인 경우 스키마 이름으로 변환
360
- if ((BUILT_IN_TYPE_IDS as readonly string[]).includes(prop.id)) {
406
+ if (
407
+ /* SAFETY: 선행 Zod 종류 분기와 템플릿 입력 계약이 이 값의 타입을 보장한다. */ (
408
+ BUILT_IN_TYPE_IDS as readonly string[]
409
+ ).includes(prop.id)
410
+ ) {
361
411
  const schemaName = prop.id === "SonamuFile" ? "SonamuFileSchema" : "SonamuFileArraySchema";
362
412
  stmt = `${prop.name}: ${schemaName}`;
363
413
  injectImportKeys.push(schemaName);
@@ -394,7 +444,11 @@ export function propToZodTypeDef(prop: EntityProp, injectImportKeys: string[]):
394
444
  return "// unable to resolve";
395
445
  }
396
446
 
397
- if ((prop as { unsigned?: boolean }).unsigned) {
447
+ if (
448
+ /* SAFETY: 선행 Zod 종류 분기와 템플릿 입력 계약이 이 값의 타입을 보장한다. */ (
449
+ prop as { unsigned?: boolean }
450
+ ).unsigned
451
+ ) {
398
452
  stmt += ".nonnegative()";
399
453
  }
400
454
  if (prop.nullable) {
@@ -456,17 +510,26 @@ export function zodTypeToTsTypeDef(zt: z.ZodType): string {
456
510
  case "date":
457
511
  return "Date";
458
512
  case "nullable":
459
- return `${zodTypeToTsTypeDef((zt as AnyZodNullable).def.innerType)} | null`;
513
+ return `${zodTypeToTsTypeDef(/* SAFETY: 선행 Zod 종류 분기와 템플릿 입력 계약이 이 값의 타입을 보장한다. */ (zt as AnyZodNullable).def.innerType)} | null`;
460
514
  case "default":
461
- return zodTypeToTsTypeDef((zt as AnyZodDefault).def.innerType);
515
+ return zodTypeToTsTypeDef(
516
+ /* SAFETY: 선행 Zod 종류 분기와 템플릿 입력 계약이 이 값의 타입을 보장한다. */ (
517
+ zt as AnyZodDefault
518
+ ).def.innerType,
519
+ );
462
520
  case "record": {
463
- const recordType = zt as AnyZodRecord;
521
+ const recordType =
522
+ /* SAFETY: 선행 Zod 종류 분기와 템플릿 입력 계약이 이 값의 타입을 보장한다. */ zt as AnyZodRecord;
464
523
  return `{ [ key: ${zodTypeToTsTypeDef(recordType.def.keyType)} ]: ${zodTypeToTsTypeDef(recordType.def.valueType)}}`;
465
524
  }
466
525
  case "literal":
467
- return Array.from((zt as z.ZodLiteral).values)
526
+ return Array.from(
527
+ /* SAFETY: 선행 Zod 종류 분기와 템플릿 입력 계약이 이 값의 타입을 보장한다. */ (
528
+ zt as z.ZodLiteral
529
+ ).values,
530
+ )
468
531
  .map((value) => {
469
- if (typeof value === "string") {
532
+ if (isStringValue(value)) {
470
533
  return `"${value}"`;
471
534
  }
472
535
 
@@ -482,31 +545,39 @@ export function zodTypeToTsTypeDef(zt: z.ZodType): string {
482
545
  })
483
546
  .join(" | ");
484
547
  case "union":
485
- return `${(zt as AnyZodUnion).options
486
- .map((option) => zodTypeToTsTypeDef(option))
487
- .join(" | ")}`;
548
+ return `${
549
+ /* SAFETY: 선행 Zod 종류 분기와 템플릿 입력 계약이 이 값의 타입을 보장한다. */ (
550
+ zt as AnyZodUnion
551
+ ).options
552
+ .map((option) => zodTypeToTsTypeDef(option))
553
+ .join(" | ")
554
+ }`;
488
555
  case "enum":
489
- return `${(zt as z.ZodEnum).options.map((val) => `"${val}"`).join(" | ")}`;
556
+ return `${/* SAFETY: 선행 Zod 종류 분기와 템플릿 입력 계약이 이 값의 타입을 보장한다. */ (zt as z.ZodEnum).options.map((val) => `"${val}"`).join(" | ")}`;
490
557
  case "array":
491
- return `${zodTypeToTsTypeDef((zt as AnyZodArray).element)}[]`;
558
+ return `${zodTypeToTsTypeDef(/* SAFETY: 선행 Zod 종류 분기와 템플릿 입력 계약이 이 값의 타입을 보장한다. */ (zt as AnyZodArray).element)}[]`;
492
559
  case "object": {
493
- const shape = (zt as AnyZodObject).shape;
560
+ const objectFields = /* SAFETY: Zod의 object 판별 분기가 객체 필드 계약을 보장한다. */ (
561
+ zt as AnyZodObject
562
+ )["shape"];
494
563
  return [
495
564
  "{",
496
- ...Object.keys(shape).map((key) => {
497
- if (shape[key].def.type === "optional") {
498
- return `${key}?: ${zodTypeToTsTypeDef(shape[key].def.innerType)},`;
565
+ ...Object.keys(objectFields).map((key) => {
566
+ if (objectFields[key].def.type === "optional") {
567
+ return `${key}?: ${zodTypeToTsTypeDef(objectFields[key].def.innerType)},`;
499
568
  } else {
500
- return `${key}: ${zodTypeToTsTypeDef(shape[key])},`;
569
+ return `${key}: ${zodTypeToTsTypeDef(objectFields[key])},`;
501
570
  }
502
571
  }),
503
572
  "}",
504
573
  ].join("\n");
505
574
  }
506
575
  case "optional":
507
- return `${zodTypeToTsTypeDef((zt as AnyZodOptional).def.innerType)} | undefined`;
576
+ return `${zodTypeToTsTypeDef(/* SAFETY: 선행 Zod 종류 분기와 템플릿 입력 계약이 이 값의 타입을 보장한다. */ (zt as AnyZodOptional).def.innerType)} | undefined`;
508
577
  case "template_literal": {
509
- const def = (zt as AnyZodTemplateLiteral).def;
578
+ const def = /* SAFETY: 선행 Zod 종류 분기와 템플릿 입력 계약이 이 값의 타입을 보장한다. */ (
579
+ zt as AnyZodTemplateLiteral
580
+ ).def;
510
581
 
511
582
  // 빈 template literal은 string으로 폴백
512
583
  if (!def.parts || def.parts.length === 0) {
@@ -514,15 +585,17 @@ export function zodTypeToTsTypeDef(zt: z.ZodType): string {
514
585
  }
515
586
 
516
587
  // 각 part를 TypeScript 타입 문자열로 변환
517
- const parts = def.parts.map((part: unknown) => {
588
+ const parts = def.parts.map((part) => {
518
589
  // 리터럴 값 (string, number, boolean, null, undefined)
519
- if (typeof part === "string") {
590
+ if (isStringValue(part)) {
520
591
  return `${part}`;
521
592
  }
522
593
 
523
594
  // ZodType - 재귀적으로 변환
524
- if (part && typeof part === "object" && (part as z.ZodType)._zod) {
525
- const innerType = zodTypeToTsTypeDef(part as z.ZodType);
595
+ if (part && isObjectValue(part) && part instanceof z.ZodType) {
596
+ const innerType = zodTypeToTsTypeDef(
597
+ /* SAFETY: 선행 Zod 종류 분기와 템플릿 입력 계약이 이 값의 타입을 보장한다. */ part as z.ZodType,
598
+ );
526
599
  return `$\{${innerType}}`;
527
600
  }
528
601
 
@@ -571,21 +644,31 @@ export function zodTypeToZodCode(zt: z.ZodType, injectImportKeys: string[] = [])
571
644
  case "never":
572
645
  return "z.never()";
573
646
  case "nullable":
574
- return `${zodTypeToZodCode((zt as AnyZodNullable).def.innerType, injectImportKeys)}.nullable()`;
647
+ return `${zodTypeToZodCode(/* SAFETY: 선행 Zod 종류 분기와 템플릿 입력 계약이 이 값의 타입을 보장한다. */ (zt as AnyZodNullable).def.innerType, injectImportKeys)}.nullable()`;
575
648
  case "default": {
576
- const zDefaultDef = (zt as AnyZodDefault).def;
649
+ const zDefaultDef =
650
+ /* SAFETY: 선행 Zod 종류 분기와 템플릿 입력 계약이 이 값의 타입을 보장한다. */ (
651
+ zt as AnyZodDefault
652
+ ).def;
577
653
  return `${zodTypeToZodCode(zDefaultDef.innerType, injectImportKeys)}.default(${zDefaultDef.defaultValue})`;
578
654
  }
579
655
  case "record": {
580
- const zRecordDef = (zt as AnyZodRecord).def;
656
+ const zRecordDef =
657
+ /* SAFETY: 선행 Zod 종류 분기와 템플릿 입력 계약이 이 값의 타입을 보장한다. */ (
658
+ zt as AnyZodRecord
659
+ ).def;
581
660
  return `z.record(${zodTypeToZodCode(zRecordDef.keyType, injectImportKeys)}, ${zodTypeToZodCode(
582
661
  zRecordDef.valueType,
583
662
  injectImportKeys,
584
663
  )})`;
585
664
  }
586
665
  case "literal": {
587
- const items = Array.from((zt as z.ZodLiteral<string | number>).values).map((value) => {
588
- if (typeof value === "string") {
666
+ const items = Array.from(
667
+ /* SAFETY: 선행 Zod 종류 분기와 템플릿 입력 계약이 이 값의 타입을 보장한다. */ (
668
+ zt as z.ZodLiteral<string | number>
669
+ ).values,
670
+ ).map((value) => {
671
+ if (isStringValue(value)) {
589
672
  return `"${value}"`;
590
673
  }
591
674
 
@@ -606,32 +689,44 @@ export function zodTypeToZodCode(zt: z.ZodType, injectImportKeys: string[] = [])
606
689
  return `z.literal([${items.join(", ")}])`;
607
690
  }
608
691
  case "union":
609
- return `z.union([${(zt as AnyZodUnion).def.options
610
- .map((option: z.ZodType) => zodTypeToZodCode(option, injectImportKeys))
611
- .join(",")}])`;
692
+ return `z.union([${
693
+ /* SAFETY: 선행 Zod 종류 분기와 템플릿 입력 계약이 이 값의 타입을 보장한다. */ (
694
+ zt as AnyZodUnion
695
+ ).def.options
696
+ .map((option: z.ZodType) => zodTypeToZodCode(option, injectImportKeys))
697
+ .join(",")
698
+ }])`;
612
699
  case "enum":
613
700
  // NOTE: z.enum(["A", "B"])도 z.enum({ A: "A", B: "B" })로 처리됨.
614
- return `z.enum({${Object.entries((zt as z.ZodEnum).def.entries)
615
- .map(([key, val]) => (typeof val === "string" ? `${key}: "${val}"` : `${key}: ${val}`))
701
+ return `z.enum({${Object.entries(
702
+ /* SAFETY: 선행 Zod 종류 분기와 템플릿 입력 계약이 이 값의 타입을 보장한다. */ (
703
+ zt as z.ZodEnum
704
+ ).def.entries,
705
+ )
706
+ .map(([key, val]) => (isStringValue(val) ? `${key}: "${val}"` : `${key}: ${val}`))
616
707
  .join(", ")}})`;
617
708
  case "array":
618
- return `z.array(${zodTypeToZodCode((zt as z.ZodArray<z.ZodType>).def.element, injectImportKeys)})`;
709
+ return `z.array(${zodTypeToZodCode(/* SAFETY: 선행 Zod 종류 분기와 템플릿 입력 계약이 이 값의 타입을 보장한다. */ (zt as z.ZodArray<z.ZodType>).def.element, injectImportKeys)})`;
619
710
  case "object": {
620
- const shape = (zt as AnyZodObject).shape;
711
+ const objectFields = /* SAFETY: Zod의 object 판별 분기가 객체 필드 계약을 보장한다. */ (
712
+ zt as AnyZodObject
713
+ )["shape"];
621
714
  return [
622
715
  "z.object({",
623
- ...Object.keys(shape).map(
624
- (key) => `${key}: ${zodTypeToZodCode(shape[key], injectImportKeys)},`,
716
+ ...Object.keys(objectFields).map(
717
+ (key) => `${key}: ${zodTypeToZodCode(objectFields[key], injectImportKeys)},`,
625
718
  ),
626
719
  "})",
627
720
  ].join("\n");
628
721
  }
629
722
  case "optional":
630
- return `${zodTypeToZodCode((zt as z.ZodOptional<z.ZodType>).def.innerType, injectImportKeys)}.optional()`;
723
+ return `${zodTypeToZodCode(/* SAFETY: 선행 Zod 종류 분기와 템플릿 입력 계약이 이 값의 타입을 보장한다. */ (zt as z.ZodOptional<z.ZodType>).def.innerType, injectImportKeys)}.optional()`;
631
724
  case "file":
632
725
  return `z.file()`;
633
726
  case "template_literal": {
634
- const def = (zt as AnyZodTemplateLiteral).def;
727
+ const def = /* SAFETY: 선행 Zod 종류 분기와 템플릿 입력 계약이 이 값의 타입을 보장한다. */ (
728
+ zt as AnyZodTemplateLiteral
729
+ ).def;
635
730
 
636
731
  // 빈 template literal
637
732
  if (!def.parts || def.parts.length === 0) {
@@ -639,14 +734,17 @@ export function zodTypeToZodCode(zt: z.ZodType, injectImportKeys: string[] = [])
639
734
  }
640
735
 
641
736
  // 각 part를 Zod 코드 문자열로 변환
642
- const parts = def.parts.map((part: unknown) => {
737
+ const parts = def.parts.map((part) => {
643
738
  // 문자열 리터럴
644
- if (typeof part === "string") {
739
+ if (isStringValue(part)) {
645
740
  return `"${part}"`;
646
741
  }
647
742
  // ZodType - 재귀적으로 변환
648
- if (part && typeof part === "object" && (part as z.ZodType)._zod) {
649
- return zodTypeToZodCode(part as z.ZodType, injectImportKeys);
743
+ if (part && isObjectValue(part) && part instanceof z.ZodType) {
744
+ return zodTypeToZodCode(
745
+ /* SAFETY: 선행 Zod 종류 분기와 템플릿 입력 계약이 이 값의 타입을 보장한다. */ part as z.ZodType,
746
+ injectImportKeys,
747
+ );
650
748
  }
651
749
 
652
750
  // 폴백
@@ -656,7 +754,10 @@ export function zodTypeToZodCode(zt: z.ZodType, injectImportKeys: string[] = [])
656
754
  return `z.templateLiteral([${parts.join(", ")}])`;
657
755
  }
658
756
  case "intersection": {
659
- const zIntersectionDef = (zt as z.ZodIntersection<z.ZodType, z.ZodType>).def;
757
+ const zIntersectionDef =
758
+ /* SAFETY: 선행 Zod 종류 분기와 템플릿 입력 계약이 이 값의 타입을 보장한다. */ (
759
+ zt as z.ZodIntersection<z.ZodType, z.ZodType>
760
+ ).def;
660
761
  return `z.intersection(${zodTypeToZodCode(
661
762
  zIntersectionDef.left,
662
763
  injectImportKeys,
@@ -708,9 +809,9 @@ export function zodTypeToRenderingNode(
708
809
 
709
810
  // 일반 케이스: ZodObject 체크
710
811
  if (zodType instanceof z.ZodObject) {
711
- const columnKeys = Object.keys(zodType.shape);
812
+ const columnKeys = Object.keys(zodType["shape"]);
712
813
  const children = columnKeys.map((key) => {
713
- const innerType = zodType.shape[key];
814
+ const innerType = zodType["shape"][key];
714
815
  return zodTypeToRenderingNode(innerType, key);
715
816
  });
716
817
  return {
@@ -719,7 +820,10 @@ export function zodTypeToRenderingNode(
719
820
  children,
720
821
  };
721
822
  } else if (zodType instanceof z.ZodArray) {
722
- const innerType = (zodType as z.ZodArray<z.ZodTypeAny>).def.element;
823
+ const innerType =
824
+ /* SAFETY: 선행 Zod 종류 분기와 템플릿 입력 계약이 이 값의 타입을 보장한다. */ (
825
+ zodType as z.ZodArray<z.ZodTypeAny>
826
+ ).def.element;
723
827
  // vector 타입 판별: number 배열이면서 embedding, vector 등의 이름을 가진 경우
724
828
  if (
725
829
  innerType instanceof z.ZodNumber &&
@@ -736,19 +840,30 @@ export function zodTypeToRenderingNode(
736
840
  element: zodTypeToRenderingNode(innerType, baseKey),
737
841
  };
738
842
  } else if (zodType instanceof z.ZodUnion) {
739
- const optionNodes = (zodType as z.ZodUnion<z.ZodType[]>).def.options.map((opt) =>
740
- zodTypeToRenderingNode(opt, baseKey),
741
- );
843
+ const optionNodes =
844
+ /* SAFETY: 선행 Zod 종류 분기와 템플릿 입력 계약이 이 값의 타입을 보장한다. */ (
845
+ zodType as z.ZodUnion<z.ZodType[]>
846
+ ).def.options.map((opt) => zodTypeToRenderingNode(opt, baseKey));
742
847
  // TODO: ZodUnion이 들어있는 경우 핸들링
743
848
  return optionNodes[0];
744
849
  } else if (zodType instanceof z.ZodOptional) {
745
850
  return {
746
- ...zodTypeToRenderingNode((zodType as z.ZodOptional<z.ZodType>).def.innerType, baseKey),
851
+ ...zodTypeToRenderingNode(
852
+ /* SAFETY: 선행 Zod 종류 분기와 템플릿 입력 계약이 이 값의 타입을 보장한다. */ (
853
+ zodType as z.ZodOptional<z.ZodType>
854
+ ).def.innerType,
855
+ baseKey,
856
+ ),
747
857
  optional: true,
748
858
  };
749
859
  } else if (zodType instanceof z.ZodNullable) {
750
860
  return {
751
- ...zodTypeToRenderingNode((zodType as z.ZodNullable<z.ZodType>).def.innerType, baseKey),
861
+ ...zodTypeToRenderingNode(
862
+ /* SAFETY: 선행 Zod 종류 분기와 템플릿 입력 계약이 이 값의 타입을 보장한다. */ (
863
+ zodType as z.ZodNullable<z.ZodType>
864
+ ).def.innerType,
865
+ baseKey,
866
+ ),
752
867
  nullable: true,
753
868
  };
754
869
  } else {
@@ -1,37 +1,35 @@
1
1
  import Fastify from "fastify";
2
2
  import { afterEach, beforeEach, describe, expect, it, vi } from "vitest";
3
3
 
4
+ import { type DevTestRouteManager } from "../dev-test-routes";
5
+ import { registerDevTestRoutes } from "../dev-test-routes";
4
6
  import { type ManagerStatus, type RunResult } from "../dev-vitest-manager";
5
7
 
6
- // vi.hoisted를 사용하여 mock 객체를 vi.mock 호이스팅 이전에 초기화
7
- const mockManager = vi.hoisted(() => ({
8
+ // 라우트가 의존하는 매니저 기능을 모두 제공하는 테스트 대역입니다.
9
+ const mockManager = {
8
10
  start: vi.fn(),
9
11
  run: vi.fn(),
10
12
  getStatus: vi.fn(),
13
+ emitEvent: vi.fn(),
14
+ addEventListener: vi.fn(),
15
+ removeEventListener: vi.fn(),
11
16
  shutdown: vi.fn(),
12
- }));
13
-
14
- // DevVitestManager를 모킹하여 new DevVitestManager()가 mockManager 인스턴스를 반환하도록 설정
15
- vi.mock("../dev-vitest-manager", () => {
16
- // oxlint-disable-next-line prefer-arrow-callback -- vi.fn 생성자 모킹에는 function 키워드가 필요
17
- const MockDevVitestManager = vi.fn(function () {
18
- return mockManager;
19
- });
20
- return { DevVitestManager: MockDevVitestManager };
21
- });
22
-
23
- import { registerDevTestRoutes } from "../dev-test-routes";
17
+ } satisfies DevTestRouteManager;
24
18
 
25
19
  const defaultConfig = {
26
20
  enabled: true as const,
27
21
  routePrefix: "/__test__",
28
22
  };
23
+ const dependencies = {
24
+ manager: mockManager,
25
+ apiRootPath: "/tmp/fixture-api",
26
+ sseAvailable: false,
27
+ };
29
28
 
30
29
  const okRunResult: RunResult = {
31
30
  ok: true,
32
31
  summary: { total: 3, passed: 2, failed: 0, skipped: 1, durationMs: 42 },
33
- failed: [],
34
- traces: [],
32
+ results: [],
35
33
  };
36
34
 
37
35
  const okStatus: ManagerStatus = {
@@ -50,7 +48,7 @@ describe("registerDevTestRoutes", () => {
50
48
  mockManager.run.mockResolvedValue(okRunResult);
51
49
  mockManager.getStatus.mockReturnValue(okStatus);
52
50
  mockManager.shutdown.mockResolvedValue(undefined);
53
- await registerDevTestRoutes(app, defaultConfig);
51
+ await registerDevTestRoutes(app, defaultConfig, dependencies);
54
52
  });
55
53
 
56
54
  afterEach(async () => {
@@ -83,10 +81,13 @@ describe("registerDevTestRoutes", () => {
83
81
  payload: { files: ["foo.test.ts"], pattern: "my test" },
84
82
  });
85
83
 
86
- expect(mockManager.run).toHaveBeenCalledWith({
87
- files: ["foo.test.ts"],
88
- pattern: "my test",
89
- });
84
+ expect(mockManager.run).toHaveBeenCalledWith(
85
+ {
86
+ files: ["foo.test.ts"],
87
+ pattern: "my test",
88
+ },
89
+ expect.any(String),
90
+ );
90
91
  });
91
92
 
92
93
  it("manager.run()이 오류를 던지면 500을 반환한다", async () => {
@@ -136,10 +137,14 @@ describe("registerDevTestRoutes", () => {
136
137
  mockManager.getStatus.mockReturnValue(okStatus);
137
138
  mockManager.shutdown.mockResolvedValue(undefined);
138
139
 
139
- await registerDevTestRoutes(customApp, {
140
- enabled: true,
141
- routePrefix: "/api/test",
142
- });
140
+ await registerDevTestRoutes(
141
+ customApp,
142
+ {
143
+ enabled: true,
144
+ routePrefix: "/api/test",
145
+ },
146
+ dependencies,
147
+ );
143
148
 
144
149
  const res = await customApp.inject({ method: "GET", url: "/api/test/status" });
145
150
  expect(res.statusCode).toBe(200);
@@ -147,4 +152,59 @@ describe("registerDevTestRoutes", () => {
147
152
  await customApp.close();
148
153
  });
149
154
  });
155
+
156
+ describe("GET /__test__/events (SSE)", () => {
157
+ it("snapshot 이벤트가 sseAvailable을 포함한 상태를 발행한다", async () => {
158
+ const sseApp = Fastify();
159
+ const { FastifySSEPlugin } = await import("fastify-sse-v2");
160
+ await sseApp.register(FastifySSEPlugin);
161
+ mockManager.start.mockResolvedValue(undefined);
162
+ mockManager.getStatus.mockReturnValue(okStatus);
163
+ mockManager.shutdown.mockResolvedValue(undefined);
164
+
165
+ await registerDevTestRoutes(sseApp, defaultConfig, {
166
+ ...dependencies,
167
+ sseAvailable: true,
168
+ });
169
+ const baseUrl = await sseApp.listen({ port: 0, host: "127.0.0.1" });
170
+
171
+ const abortController = new AbortController();
172
+ try {
173
+ const res = await fetch(baseUrl + "/__test__/events", {
174
+ headers: { accept: "text/event-stream" },
175
+ signal: abortController.signal,
176
+ });
177
+ expect(res.body).not.toBeNull();
178
+ if (res.body === null) throw new Error("SSE 응답 본문이 비어 있습니다");
179
+
180
+ // 첫 snapshot 프레임이 도착할 때까지 스트림을 읽습니다.
181
+ const reader = res.body.getReader();
182
+ const decoder = new TextDecoder();
183
+ let buffer = "";
184
+ while (!buffer.includes("event: snapshot")) {
185
+ const { done, value } = await reader.read();
186
+ if (done) break;
187
+ buffer += decoder.decode(value, { stream: true });
188
+ }
189
+
190
+ const dataLine = buffer.split("\n").find((line) => line.startsWith("data: "));
191
+ expect(dataLine).toBeDefined();
192
+ if (dataLine === undefined) throw new Error("snapshot data 프레임이 없습니다");
193
+
194
+ const payload: { status: ManagerStatus & { sseAvailable?: boolean } } = JSON.parse(
195
+ dataLine.slice("data: ".length),
196
+ );
197
+ // SSE 스냅샷 상태는 HTTP status 응답과 같은 형태(sseAvailable 포함)여야 합니다.
198
+ expect(payload.status).toEqual({
199
+ ready: true,
200
+ running: false,
201
+ lastRunAt: null,
202
+ sseAvailable: true,
203
+ });
204
+ } finally {
205
+ abortController.abort();
206
+ await sseApp.close();
207
+ }
208
+ });
209
+ });
150
210
  });