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
@@ -1,8 +1,8 @@
1
1
  import { mkdir, mkdtemp, rm, writeFile } from "node:fs/promises";
2
2
  import os from "node:os";
3
3
  import path from "node:path";
4
- import { pathToFileURL } from "node:url";
5
4
 
5
+ import { type FastifyInstance } from "fastify";
6
6
  import { afterEach, beforeEach, describe, expect, it, vi } from "vitest";
7
7
 
8
8
  const tsLoaderRegisterStateKey = Symbol.for("sonamu.ts-loader-register.state");
@@ -16,7 +16,8 @@ type GlobalWithTsLoaderRegisterState = typeof globalThis & {
16
16
  };
17
17
 
18
18
  function resetRegisterState() {
19
- const globalState = globalThis as GlobalWithTsLoaderRegisterState;
19
+ const globalState =
20
+ /* SAFETY: API 데코레이터와 Zod 검증기 등록 계약이 이 값의 타입을 보장한다. */ globalThis as GlobalWithTsLoaderRegisterState;
20
21
  delete globalState[tsLoaderRegisterStateKey];
21
22
  }
22
23
 
@@ -143,14 +144,12 @@ describe("loadConfig", () => {
143
144
  beforeEach(() => {
144
145
  vi.resetModules();
145
146
  vi.restoreAllMocks();
146
- vi.unmock("../../bin/ts-loader-registration");
147
147
  resetRegisterState();
148
148
  });
149
149
 
150
150
  afterEach(async () => {
151
151
  vi.resetModules();
152
152
  vi.restoreAllMocks();
153
- vi.unmock("../../bin/ts-loader-registration");
154
153
  resetRegisterState();
155
154
 
156
155
  if (originalHot === undefined) {
@@ -183,12 +182,9 @@ describe("loadConfig", () => {
183
182
 
184
183
  process.env.VITEST = "true";
185
184
  const ensureTsLoaderRegistered = vi.fn(async () => {});
186
- vi.doMock("../../bin/ts-loader-registration", () => ({
187
- ensureTsLoaderRegistered,
188
- }));
189
185
 
190
186
  const { loadConfig } = await import("../config");
191
- const config = await loadConfig(rootPath);
187
+ const config = await loadConfig(rootPath, { ensureTsLoaderRegistered });
192
188
 
193
189
  expect(ensureTsLoaderRegistered).toHaveBeenCalledTimes(1);
194
190
  expect(ensureTsLoaderRegistered).toHaveBeenCalledWith(rootPath);
@@ -203,12 +199,9 @@ describe("loadConfig", () => {
203
199
  delete process.env.HOT;
204
200
  delete process.env.VITEST;
205
201
  const ensureTsLoaderRegistered = vi.fn(async () => {});
206
- vi.doMock("../../bin/ts-loader-registration", () => ({
207
- ensureTsLoaderRegistered,
208
- }));
209
202
 
210
203
  const { loadConfig } = await import("../config");
211
- const config = await loadConfig(rootPath);
204
+ const config = await loadConfig(rootPath, { ensureTsLoaderRegistered });
212
205
 
213
206
  expect(ensureTsLoaderRegistered).not.toHaveBeenCalled();
214
207
  expect(config.api.dir).toBe("./dist");
@@ -221,21 +214,18 @@ describe("loadConfig", () => {
221
214
  await writeSourceFixture(rootPath);
222
215
 
223
216
  process.env.VITEST = "true";
224
- vi.unmock("../../bin/ts-loader-registration");
225
217
  const { loadConfig } = await import("../config");
226
- const supportModule = await import(
227
- pathToFileURL(path.join(rootPath, "src", "support.ts")).href
228
- );
229
-
230
218
  const firstConfig = await loadConfig(rootPath);
231
219
  const secondConfig = await loadConfig(rootPath);
220
+ const fastify =
221
+ /* SAFETY: API 데코레이터와 Zod 검증기 등록 계약이 이 값의 타입을 보장한다. */ {} as FastifyInstance;
232
222
 
233
- expect(firstConfig.server.fastify).toBe(supportModule.fastifyOptions);
234
- expect(firstConfig.server.plugins?.custom).toBe(supportModule.customPlugin);
223
+ expect(firstConfig.server.fastify).toStrictEqual({ keepAliveTimeout: 4321 });
224
+ expect(firstConfig.server.plugins?.custom?.(fastify)).toBe("plugin");
235
225
  expect(firstConfig.test?.parallel).toBe(true);
236
226
  expect(firstConfig.test?.maxWorkers).toBe(3);
237
227
  expect(firstConfig.test?.devRunner?.enabled).toBe(true);
238
- expect(secondConfig.server.plugins?.custom).toBe(supportModule.customPlugin);
239
- expect(secondConfig.server.fastify).toBe(supportModule.fastifyOptions);
228
+ expect(secondConfig.server.plugins?.custom?.(fastify)).toBe("plugin");
229
+ expect(secondConfig.server.fastify).toStrictEqual({ keepAliveTimeout: 4321 });
240
230
  });
241
231
  });
@@ -0,0 +1,512 @@
1
+ import { mkdir, mkdtemp, rm, writeFile } from "node:fs/promises";
2
+ import os from "node:os";
3
+ import path from "node:path";
4
+
5
+ import { type FastifyReply, type FastifyRequest } from "fastify";
6
+ import { afterEach, beforeEach, describe, expect, it, vi } from "vitest";
7
+ import { z, ZodError } from "zod";
8
+
9
+ import { type SonamuFastifyConfig } from "../../types/types";
10
+ import { type Context } from "../context";
11
+ import { type ExtendedApi } from "../decorators";
12
+ import {
13
+ assertHttpValidatorRegistry,
14
+ createHttpValidator,
15
+ defaultHttpValidatorDependencies,
16
+ getHttpValidatorFingerprint,
17
+ getHttpValidatorRouteKey,
18
+ type HttpValidatorDependencies,
19
+ } from "../http-validator";
20
+ import {
21
+ defaultSonamuHttpValidatorDependencies,
22
+ Sonamu,
23
+ type SonamuHttpValidatorDependencies,
24
+ } from "../sonamu";
25
+
26
+ const createSchema = vi.fn(defaultHttpValidatorDependencies.createSchema);
27
+ const applyCaster = vi.fn(defaultHttpValidatorDependencies.applyCaster);
28
+ const compileJit = vi.fn(defaultHttpValidatorDependencies.compileJit);
29
+ const validatorDependencies: HttpValidatorDependencies = {
30
+ createSchema,
31
+ applyCaster,
32
+ compileJit,
33
+ };
34
+ const createValidator = vi.fn((options: Parameters<typeof createHttpValidator>[0]) =>
35
+ createHttpValidator(options, validatorDependencies),
36
+ );
37
+ const assertRegistry = vi.fn(assertHttpValidatorRegistry);
38
+ const lifecycleDependencies: SonamuHttpValidatorDependencies = {
39
+ createValidator,
40
+ assertRegistry,
41
+ };
42
+
43
+ function createApi(parameterType: "number" | "string" = "number"): ExtendedApi {
44
+ return {
45
+ modelName: "ReportModel",
46
+ methodName: "findPage",
47
+ path: "/report/findPage",
48
+ options: {
49
+ httpMethod: "GET",
50
+ },
51
+ typeParameters: [],
52
+ parameters: [
53
+ {
54
+ name: "page",
55
+ type: parameterType,
56
+ optional: false,
57
+ },
58
+ ],
59
+ returnType: "unknown",
60
+ };
61
+ }
62
+
63
+ function createRequest<Query extends object>(query: Query): FastifyRequest {
64
+ return /* SAFETY: API 데코레이터와 Zod 검증기 등록 계약이 이 값의 타입을 보장한다. */ {
65
+ headers: {},
66
+ method: "GET",
67
+ query,
68
+ url: "/report/findPage",
69
+ } as FastifyRequest;
70
+ }
71
+
72
+ describe("REST HTTP validator 생명주기", () => {
73
+ const originalState = Sonamu.captureTestingSnapshot();
74
+ const originalVitest = process.env.VITEST;
75
+ const originalHot = process.env.HOT;
76
+ const tempRoots: string[] = [];
77
+
78
+ beforeEach(() => {
79
+ vi.clearAllMocks();
80
+ createSchema.mockImplementation(defaultHttpValidatorDependencies.createSchema);
81
+ applyCaster.mockImplementation(defaultHttpValidatorDependencies.applyCaster);
82
+ compileJit.mockImplementation(defaultHttpValidatorDependencies.compileJit);
83
+ createValidator.mockImplementation((options) =>
84
+ createHttpValidator(options, validatorDependencies),
85
+ );
86
+ assertRegistry.mockImplementation(defaultSonamuHttpValidatorDependencies.assertRegistry);
87
+ Reflect.set(Sonamu, "httpValidators", new WeakMap());
88
+ Reflect.set(Sonamu, "pendingHttpValidators", new WeakMap());
89
+ Reflect.set(Sonamu, "aotHttpValidatorRegistry", undefined);
90
+ Reflect.set(Sonamu, "preparedApis", []);
91
+ });
92
+
93
+ afterEach(async () => {
94
+ Sonamu.restoreTestingSnapshot(originalState);
95
+ if (originalVitest === undefined) {
96
+ delete process.env.VITEST;
97
+ } else {
98
+ process.env.VITEST = originalVitest;
99
+ }
100
+ if (originalHot === undefined) {
101
+ delete process.env.HOT;
102
+ } else {
103
+ process.env.HOT = originalHot;
104
+ }
105
+ vi.restoreAllMocks();
106
+ await Promise.all(
107
+ tempRoots.splice(0).map((rootPath) => rm(rootPath, { recursive: true, force: true })),
108
+ );
109
+ });
110
+
111
+ it("같은 REST handler에서 최종 validator를 한 번만 만들고 coercion과 Zod 오류 계약을 유지한다", async () => {
112
+ const api = createApi();
113
+ const types = {
114
+ PageSchema: z.number(),
115
+ };
116
+ const reply = /* SAFETY: API 데코레이터와 Zod 검증기 등록 계약이 이 값의 타입을 보장한다. */ {
117
+ type: vi.fn().mockReturnThis(),
118
+ } as FastifyReply;
119
+ const config = /* SAFETY: API 데코레이터와 Zod 검증기 등록 계약이 이 값의 타입을 보장한다. */ {
120
+ contextProvider(defaultContext: Context) {
121
+ return defaultContext;
122
+ },
123
+ guardHandler() {},
124
+ } as SonamuFastifyConfig;
125
+
126
+ Reflect.set(Sonamu, "configValue", {
127
+ sync: { targets: [] },
128
+ validation: { zodCompiler: false },
129
+ });
130
+ Reflect.set(Sonamu, "syncerValue", { types });
131
+ vi.spyOn(Sonamu, "createContext").mockResolvedValue(
132
+ /* SAFETY: API 데코레이터와 Zod 검증기 등록 계약이 이 값의 타입을 보장한다. */ {
133
+ transport: "http",
134
+ } as Context,
135
+ );
136
+ vi.spyOn(Sonamu, "invokeModelMethod").mockImplementation(async (_api, args) => args);
137
+
138
+ const handler = await Sonamu.createApiHandler(api, config, undefined, lifecycleDependencies);
139
+
140
+ expect(createSchema).toHaveBeenCalledTimes(1);
141
+ const converterCall = createSchema.mock.calls[0];
142
+ expect(converterCall?.[0]).toBe(api);
143
+ expect(converterCall?.[1]).toEqual(types);
144
+ expect(converterCall?.[1]).not.toBe(types);
145
+ expect(applyCaster).toHaveBeenCalledTimes(1);
146
+
147
+ await expect(handler(createRequest({ page: "2" }), reply)).resolves.toEqual([2]);
148
+ await expect(handler(createRequest({ page: "invalid" }), reply)).rejects.toMatchObject({
149
+ statusCode: 400,
150
+ payload: {
151
+ zodError: expect.any(ZodError),
152
+ },
153
+ });
154
+
155
+ expect(createSchema).toHaveBeenCalledTimes(1);
156
+ expect(applyCaster).toHaveBeenCalledTimes(1);
157
+ expect(compileJit).not.toHaveBeenCalled();
158
+ });
159
+
160
+ it("JIT를 첫 parse 전에 eager 설치하고 registry 없이 검증한다", async () => {
161
+ const events: string[] = [];
162
+ compileJit.mockImplementation(async (schema) => {
163
+ const parse = schema.parse.bind(schema);
164
+ const safeParse = schema.safeParse.bind(schema);
165
+ Object.defineProperties(schema, {
166
+ parse: {
167
+ configurable: true,
168
+ value<Input>(input: Input) {
169
+ events.push("parse");
170
+ return parse(input);
171
+ },
172
+ },
173
+ safeParse: {
174
+ configurable: true,
175
+ value<Input>(input: Input) {
176
+ return safeParse(input);
177
+ },
178
+ },
179
+ });
180
+ events.push("jit");
181
+ return schema;
182
+ });
183
+
184
+ const validator = await createHttpValidator(
185
+ {
186
+ api: createApi(),
187
+ policy: { api: "jit", targets: {} },
188
+ types: {},
189
+ },
190
+ validatorDependencies,
191
+ );
192
+
193
+ expect(compileJit).toHaveBeenCalledWith(expect.any(z.ZodType), { eager: true });
194
+ expect(validator.parse({ page: "3" })).toEqual({ page: 3 });
195
+ expect(events).toEqual(["jit", "parse"]);
196
+ });
197
+
198
+ it("JIT가 public parse method를 교체하지 않으면 첫 parse 전에 setup을 실패시킨다", async () => {
199
+ compileJit.mockImplementation(async (schema) => schema);
200
+
201
+ await expect(
202
+ createHttpValidator(
203
+ {
204
+ api: createApi(),
205
+ policy: { api: "jit", targets: {} },
206
+ types: {},
207
+ },
208
+ validatorDependencies,
209
+ ),
210
+ ).rejects.toThrow();
211
+ expect(compileJit).toHaveBeenCalledWith(expect.any(z.ZodType), { eager: true });
212
+ });
213
+
214
+ it("AOT registry의 fingerprint와 route coverage 불일치를 거부한다", () => {
215
+ const api = createApi();
216
+ const validator = z.object({ page: z.number() });
217
+ const validators = new Map([[getHttpValidatorRouteKey(api), validator]]);
218
+
219
+ expect(() =>
220
+ assertHttpValidatorRegistry([api], {
221
+ fingerprint: "stale",
222
+ validators,
223
+ }),
224
+ ).toThrow(/fingerprint mismatch/);
225
+ expect(() =>
226
+ assertHttpValidatorRegistry([api], {
227
+ fingerprint: getHttpValidatorFingerprint([api]),
228
+ validators: new Map(),
229
+ }),
230
+ ).toThrow(/coverage mismatch/);
231
+ });
232
+
233
+ it("AOT registry validator를 우선 선택하고 source 실행에서는 명시적으로 fallback한다", async () => {
234
+ const api = createApi();
235
+ const compiled = z.object({ page: z.number() });
236
+ const registry = {
237
+ fingerprint: getHttpValidatorFingerprint([api]),
238
+ validators: new Map([[getHttpValidatorRouteKey(api), compiled]]),
239
+ };
240
+
241
+ await expect(
242
+ createHttpValidator({
243
+ api,
244
+ policy: { api: "aot", targets: {} },
245
+ types: {},
246
+ aotRegistry: registry,
247
+ }),
248
+ ).resolves.toBe(compiled);
249
+
250
+ const sourceFallback = await createHttpValidator({
251
+ api,
252
+ policy: { api: "aot", targets: {} },
253
+ types: {},
254
+ allowAotSourceFallback: true,
255
+ });
256
+ expect(sourceFallback).not.toBe(compiled);
257
+ expect(sourceFallback.parse({ page: "4" })).toEqual({ page: 4 });
258
+
259
+ await expect(
260
+ createHttpValidator({
261
+ api,
262
+ policy: { api: "aot", targets: {} },
263
+ types: {},
264
+ }),
265
+ ).rejects.toThrow(/registry is missing/);
266
+ });
267
+
268
+ it("metadata refresh가 실패하면 기존 cache를 유지하고 성공 후 새 validator를 재사용한다", async () => {
269
+ const firstApi = createApi("number");
270
+ const revisedApi = createApi("string");
271
+ const config = /* SAFETY: API 데코레이터와 Zod 검증기 등록 계약이 이 값의 타입을 보장한다. */ {
272
+ contextProvider(defaultContext: Context) {
273
+ return defaultContext;
274
+ },
275
+ guardHandler() {},
276
+ } as SonamuFastifyConfig;
277
+ Reflect.set(Sonamu, "configValue", {
278
+ sync: { targets: [] },
279
+ validation: { zodCompiler: false },
280
+ });
281
+ Reflect.set(Sonamu, "syncerValue", { apis: [firstApi], types: {} });
282
+
283
+ await Sonamu.refreshHttpValidators(lifecycleDependencies);
284
+ Sonamu.createApiHandler(firstApi, config, undefined, lifecycleDependencies);
285
+ expect(createSchema).toHaveBeenCalledTimes(1);
286
+
287
+ Reflect.set(Sonamu, "syncerValue", { apis: [revisedApi], types: {} });
288
+ createSchema.mockImplementationOnce(() => {
289
+ throw new Error("metadata refresh failed");
290
+ });
291
+ await expect(Sonamu.refreshHttpValidators(lifecycleDependencies)).rejects.toThrow(
292
+ "metadata refresh failed",
293
+ );
294
+
295
+ Sonamu.createApiHandler(firstApi, config, undefined, lifecycleDependencies);
296
+ expect(createSchema).toHaveBeenCalledTimes(2);
297
+
298
+ await Sonamu.refreshHttpValidators(lifecycleDependencies);
299
+ Sonamu.createApiHandler(revisedApi, config, undefined, lifecycleDependencies);
300
+ expect(createSchema).toHaveBeenCalledTimes(3);
301
+ });
302
+
303
+ it("HMR source에서 opt-out에서 AOT로 전환하면 새 metadata를 fallback validator로 교체한다", async () => {
304
+ process.env.VITEST = "true";
305
+ const firstApi = createApi("number");
306
+ const revisedApi = createApi("string");
307
+ const reply = /* SAFETY: API 데코레이터와 Zod 검증기 등록 계약이 이 값의 타입을 보장한다. */ {
308
+ type: vi.fn().mockReturnThis(),
309
+ } as FastifyReply;
310
+ const config = /* SAFETY: API 데코레이터와 Zod 검증기 등록 계약이 이 값의 타입을 보장한다. */ {
311
+ contextProvider(defaultContext: Context) {
312
+ return defaultContext;
313
+ },
314
+ guardHandler() {},
315
+ } as SonamuFastifyConfig;
316
+ vi.spyOn(Sonamu, "createContext").mockResolvedValue(
317
+ /* SAFETY: API 데코레이터와 Zod 검증기 등록 계약이 이 값의 타입을 보장한다. */ {
318
+ transport: "http",
319
+ } as Context,
320
+ );
321
+ vi.spyOn(Sonamu, "invokeModelMethod").mockImplementation(async (_api, args) => args);
322
+ Reflect.set(Sonamu, "configValue", {
323
+ sync: { targets: [] },
324
+ validation: { zodCompiler: false },
325
+ });
326
+ Reflect.set(Sonamu, "syncerValue", { apis: [firstApi], types: {} });
327
+
328
+ await Sonamu.refreshHttpValidators(lifecycleDependencies);
329
+ const firstHandler = Sonamu.createApiHandler(
330
+ firstApi,
331
+ config,
332
+ undefined,
333
+ lifecycleDependencies,
334
+ );
335
+ await expect(firstHandler(createRequest({ page: "5" }), reply)).resolves.toEqual([5]);
336
+
337
+ Reflect.set(Sonamu, "configValue", {
338
+ sync: { targets: [] },
339
+ validation: { zodCompiler: { api: "aot" } },
340
+ });
341
+ Reflect.set(Sonamu, "syncerValue", { apis: [revisedApi], types: {} });
342
+ await Sonamu.refreshHttpValidators(lifecycleDependencies);
343
+ const revisedHandler = Sonamu.createApiHandler(
344
+ revisedApi,
345
+ config,
346
+ undefined,
347
+ lifecycleDependencies,
348
+ );
349
+ await expect(revisedHandler(createRequest({ page: "5" }), reply)).resolves.toEqual(["5"]);
350
+
351
+ Sonamu.createApiHandler(revisedApi, config, undefined, lifecycleDependencies);
352
+ expect(createSchema).toHaveBeenCalledTimes(2);
353
+ });
354
+
355
+ it("HMR refresh는 API, validator, model registry를 준비 완료 snapshot으로 함께 공개한다", async () => {
356
+ process.env.VITEST = "true";
357
+ const previousApi = createApi("number");
358
+ const revisedApi = {
359
+ ...createApi("string"),
360
+ methodName: "findPageV2",
361
+ };
362
+ const previousModel = {
363
+ findPage<Page>(page: Page) {
364
+ return { modelRevision: "previous", value: page };
365
+ },
366
+ };
367
+ const revisedModel = {
368
+ findPageV2<Page>(page: Page) {
369
+ return { modelRevision: "revised", value: page };
370
+ },
371
+ };
372
+ const request = /* SAFETY: API 데코레이터와 Zod 검증기 등록 계약이 이 값의 타입을 보장한다. */ {
373
+ ...createRequest({ page: "5" }),
374
+ url: "/api/report/findPage",
375
+ } as FastifyRequest;
376
+ const reply = /* SAFETY: API 데코레이터와 Zod 검증기 등록 계약이 이 값의 타입을 보장한다. */ {
377
+ type: vi.fn().mockReturnThis(),
378
+ } as FastifyReply;
379
+ const config = /* SAFETY: API 데코레이터와 Zod 검증기 등록 계약이 이 값의 타입을 보장한다. */ {
380
+ contextProvider(defaultContext: Context) {
381
+ return defaultContext;
382
+ },
383
+ guardHandler() {},
384
+ } as SonamuFastifyConfig;
385
+ const invokeDevRequest = async () => {
386
+ const handler = await Sonamu.handleDevApiRequestForTesting(request, config);
387
+ if (handler === null) {
388
+ throw new Error("개발 API handler를 찾지 못했습니다");
389
+ }
390
+ return await handler(request, reply);
391
+ };
392
+
393
+ Reflect.set(Sonamu, "configValue", {
394
+ api: { route: { prefix: "/api" } },
395
+ sync: { targets: [] },
396
+ validation: { zodCompiler: false },
397
+ });
398
+ Reflect.set(Sonamu, "syncerValue", {
399
+ apis: [previousApi],
400
+ models: { ReportModel: previousModel },
401
+ types: {},
402
+ });
403
+ vi.spyOn(Sonamu, "createContext").mockResolvedValue(
404
+ /* SAFETY: API 데코레이터와 Zod 검증기 등록 계약이 이 값의 타입을 보장한다. */ {
405
+ transport: "http",
406
+ } as Context,
407
+ );
408
+
409
+ await Sonamu.refreshHttpValidators(lifecycleDependencies);
410
+ createValidator.mockClear();
411
+
412
+ type Validator = Awaited<ReturnType<typeof createHttpValidator>>;
413
+ let rejectRefresh: ((error: Error) => void) | undefined;
414
+ const blockedValidator = new Promise<Validator>((_resolve, reject) => {
415
+ rejectRefresh = (error) => reject(error);
416
+ });
417
+ createValidator.mockImplementationOnce(async () => await blockedValidator);
418
+ Reflect.set(Sonamu, "syncerValue", {
419
+ apis: [revisedApi],
420
+ models: { ReportModel: revisedModel },
421
+ types: {},
422
+ });
423
+
424
+ const failedRefresh = Sonamu.refreshHttpValidators(lifecycleDependencies);
425
+ const refreshSetupCalls = createValidator.mock.calls.length;
426
+ const duringRefresh = await invokeDevRequest();
427
+ const callsAfterRequest = createValidator.mock.calls.length;
428
+ if (rejectRefresh === undefined) {
429
+ throw new Error("refresh 실패 제어가 준비되지 않았습니다");
430
+ }
431
+ rejectRefresh(new Error("metadata refresh failed"));
432
+ await expect(failedRefresh).rejects.toThrow("metadata refresh failed");
433
+ const afterFailure = await invokeDevRequest();
434
+ const callsAfterFailedRequest = createValidator.mock.calls.length;
435
+
436
+ await Sonamu.refreshHttpValidators(lifecycleDependencies);
437
+ const afterSuccess = await invokeDevRequest();
438
+
439
+ expect(refreshSetupCalls).toBe(1);
440
+ expect(callsAfterRequest).toBe(1);
441
+ expect(callsAfterFailedRequest).toBe(1);
442
+ expect(duringRefresh).toEqual({ modelRevision: "previous", value: 5 });
443
+ expect(afterFailure).toEqual({ modelRevision: "previous", value: 5 });
444
+ expect(afterSuccess).toEqual({ modelRevision: "revised", value: "5" });
445
+ expect(createValidator).toHaveBeenCalledTimes(2);
446
+ });
447
+
448
+ it("built AOT refresh는 metadata revision마다 registry를 한 번만 검증하고 plain validator를 만들지 않는다", async () => {
449
+ delete process.env.VITEST;
450
+ delete process.env.HOT;
451
+ const config = /* SAFETY: API 데코레이터와 Zod 검증기 등록 계약이 이 값의 타입을 보장한다. */ {
452
+ contextProvider(defaultContext: Context) {
453
+ return defaultContext;
454
+ },
455
+ guardHandler() {},
456
+ } as SonamuFastifyConfig;
457
+ const createRegistryRoot = async (apis: ExtendedApi[]): Promise<string> => {
458
+ const apiRootPath = await mkdtemp(path.join(os.tmpdir(), "sonamu-built-aot-refresh-test-"));
459
+ tempRoots.push(apiRootPath);
460
+ const registryPath = path.join(
461
+ apiRootPath,
462
+ "dist/application/sonamu.validators.generated.js",
463
+ );
464
+ await mkdir(path.dirname(registryPath), { recursive: true });
465
+ const entries = apis.map(
466
+ (api) =>
467
+ `[${JSON.stringify(getHttpValidatorRouteKey(api))}, { parse(input) { return input; } }]`,
468
+ );
469
+ await writeFile(
470
+ registryPath,
471
+ [
472
+ `export const fingerprint = ${JSON.stringify(getHttpValidatorFingerprint(apis))};`,
473
+ `export const validators = new Map([${entries.join(",")}]);`,
474
+ "",
475
+ ].join("\n"),
476
+ );
477
+ return apiRootPath;
478
+ };
479
+ const firstApis = [
480
+ createApi("number"),
481
+ { ...createApi("number"), methodName: "findOther", path: "/report/findOther" },
482
+ ];
483
+ const revisedApis = [
484
+ createApi("string"),
485
+ { ...createApi("string"), methodName: "findOther", path: "/report/findOther" },
486
+ ];
487
+ Reflect.set(Sonamu, "configValue", {
488
+ sync: { targets: [] },
489
+ validation: { zodCompiler: { api: "aot" } },
490
+ });
491
+
492
+ Reflect.set(Sonamu, "apiRootPathValue", await createRegistryRoot(firstApis));
493
+ Reflect.set(Sonamu, "syncerValue", { apis: firstApis, types: {} });
494
+ await Sonamu.refreshHttpValidators(lifecycleDependencies);
495
+ for (const api of firstApis) {
496
+ Sonamu.createApiHandler(api, config, undefined, lifecycleDependencies);
497
+ Sonamu.createApiHandler(api, config, undefined, lifecycleDependencies);
498
+ }
499
+
500
+ Reflect.set(Sonamu, "apiRootPathValue", await createRegistryRoot(revisedApis));
501
+ Reflect.set(Sonamu, "syncerValue", { apis: revisedApis, types: {} });
502
+ await Sonamu.refreshHttpValidators(lifecycleDependencies);
503
+ for (const api of revisedApis) {
504
+ Sonamu.createApiHandler(api, config, undefined, lifecycleDependencies);
505
+ Sonamu.createApiHandler(api, config, undefined, lifecycleDependencies);
506
+ }
507
+
508
+ expect(assertRegistry).toHaveBeenCalledTimes(2);
509
+ expect(createSchema).not.toHaveBeenCalled();
510
+ expect(applyCaster).not.toHaveBeenCalled();
511
+ });
512
+ });