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
@@ -0,0 +1,4 @@
1
+ /** Fastify가 비동기 실패를 오류 처리기로 전달할 수 있도록 Promise를 반환합니다. */
2
+ export function forwardAsyncErrors<Result>(handler: () => Promise<Result>): Promise<Result> {
3
+ return Promise.resolve().then(handler);
4
+ }
@@ -4,6 +4,7 @@ import os from "os";
4
4
  import path from "path";
5
5
 
6
6
  import { Sonamu } from "../api/sonamu";
7
+ import { isStringValue } from "../utils/runtime-value";
7
8
  import {
8
9
  type CddAcEntry,
9
10
  type CddAcFile,
@@ -17,6 +18,22 @@ import {
17
18
  type CddTreeNode,
18
19
  } from "./cdd-types";
19
20
 
21
+ interface CddTreeResult {
22
+ exists: boolean;
23
+ tree: CddTreeNode[];
24
+ }
25
+ interface EditorCliConfig {
26
+ cli: string;
27
+ waitFlag: string;
28
+ }
29
+ interface EditorCliResolution {
30
+ bin: string;
31
+ args: string[];
32
+ }
33
+ interface CddRulesResult {
34
+ rules: CddRuleSummary[];
35
+ }
36
+
20
37
  export type {
21
38
  CddAcEntry,
22
39
  CddAcFile,
@@ -93,7 +110,7 @@ function scanDirectory(dirPath: string, relativeTo: string): CddTreeNode[] {
93
110
  }
94
111
 
95
112
  /** contract/ 디렉터리의 트리 구조를 반환 */
96
- export function getCddTree(): { exists: boolean; tree: CddTreeNode[] } {
113
+ export function getCddTree(): CddTreeResult {
97
114
  const contractDir = getContractDir();
98
115
  if (!fs.existsSync(contractDir)) {
99
116
  return { exists: false, tree: [] };
@@ -142,17 +159,17 @@ export async function editContent(
142
159
  }
143
160
 
144
161
  /** 에디터별 앱 번들 내 CLI 경로 + --wait 플래그 매핑 */
145
- const EDITOR_CLI_MAP: Record<string, { cli: string; waitFlag: string }> = {
162
+ const EDITOR_CLI_MAP = {
146
163
  "Visual Studio Code": { cli: "Contents/Resources/app/bin/code", waitFlag: "--wait" },
147
164
  Zed: { cli: "Contents/MacOS/cli", waitFlag: "--wait" },
148
165
  Cursor: { cli: "Contents/Resources/app/bin/cursor", waitFlag: "--wait" },
149
- };
166
+ } satisfies Record<string, EditorCliConfig>;
150
167
 
151
168
  /** 앱 번들 CLI 경로를 resolve. wait=false이면 --wait 플래그를 생략 */
152
- function resolveEditorCli(options?: { wait?: boolean }): { bin: string; args: string[] } {
169
+ function resolveEditorCli(options?: { wait?: boolean }): EditorCliResolution {
153
170
  const wait = options?.wait ?? true;
154
171
  const appName = Sonamu.config.externalEditor ?? "Visual Studio Code";
155
- const mapping = EDITOR_CLI_MAP[appName];
172
+ const mapping = Object.entries(EDITOR_CLI_MAP).find(([name]) => name === appName)?.[1];
156
173
  if (!mapping) {
157
174
  throw new Error(
158
175
  `지원되지 않는 에디터입니다: ${appName} (지원: ${Object.keys(EDITOR_CLI_MAP).join(", ")})`,
@@ -218,7 +235,7 @@ export function openSourceFile(filePath: string): void {
218
235
  * ======================================================================== */
219
236
 
220
237
  /** contract/rules/ 디렉터리 내 .rules.json 파일 목록 반환 */
221
- export function listRules(): { rules: CddRuleSummary[] } {
238
+ export function listRules(): CddRulesResult {
222
239
  const contractDir = getContractDir();
223
240
  const rulesDir = path.join(contractDir, "rules");
224
241
  if (!fs.existsSync(rulesDir)) return { rules: [] };
@@ -235,11 +252,13 @@ export function listRules(): { rules: CddRuleSummary[] } {
235
252
 
236
253
  try {
237
254
  const raw = fs.readFileSync(absPath, "utf-8");
238
- const doc = JSON.parse(raw) as { description?: string; rules?: unknown[] };
255
+ const doc = /* SAFETY: UI 도구의 Zod 입력 스키마가 이 값의 타입을 보장한다. */ JSON.parse(
256
+ raw,
257
+ ) as { description?: string; rules?: unknown[] };
239
258
  rules.push({
240
259
  key,
241
260
  path: relPath,
242
- description: typeof doc.description === "string" ? doc.description : "",
261
+ description: isStringValue(doc.description) ? doc.description : "",
243
262
  ruleCount: Array.isArray(doc.rules) ? doc.rules.length : 0,
244
263
  });
245
264
  } catch (err) {
@@ -266,12 +285,14 @@ export function readRule(ruleKey: string): CddRuleDetail {
266
285
  }
267
286
 
268
287
  const raw = fs.readFileSync(absPath, "utf-8");
269
- const doc = JSON.parse(raw) as { description?: string; rules?: CddRuleEntry[] };
288
+ const doc = /* SAFETY: UI 도구의 Zod 입력 스키마가 이 값의 타입을 보장한다. */ JSON.parse(
289
+ raw,
290
+ ) as { description?: string; rules?: CddRuleEntry[] };
270
291
 
271
292
  return {
272
293
  key: ruleKey,
273
294
  path: `rules/${ruleKey}.rules.json`,
274
- description: typeof doc.description === "string" ? doc.description : "",
295
+ description: isStringValue(doc.description) ? doc.description : "",
275
296
  rules: Array.isArray(doc.rules) ? doc.rules : [],
276
297
  };
277
298
  }
@@ -287,7 +308,9 @@ export function addRule(req: CddAddRuleRequest): CddRuleDetail {
287
308
  }
288
309
 
289
310
  const raw = fs.readFileSync(absPath, "utf-8");
290
- const doc = JSON.parse(raw) as { description?: string; rules?: CddRuleEntry[] };
311
+ const doc = /* SAFETY: UI 도구의 Zod 입력 스키마가 이 값의 타입을 보장한다. */ JSON.parse(
312
+ raw,
313
+ ) as { description?: string; rules?: CddRuleEntry[] };
291
314
  const rules: CddRuleEntry[] = Array.isArray(doc.rules) ? doc.rules : [];
292
315
 
293
316
  const nextId = generateNextRuleId(rules);
@@ -308,7 +331,7 @@ export function addRule(req: CddAddRuleRequest): CddRuleDetail {
308
331
  return {
309
332
  key: req.ruleKey,
310
333
  path: `rules/${req.ruleKey}.rules.json`,
311
- description: typeof doc.description === "string" ? doc.description : "",
334
+ description: isStringValue(doc.description) ? doc.description : "",
312
335
  rules,
313
336
  };
314
337
  }
@@ -20,6 +20,7 @@ import {
20
20
  type MigrationStreamEvent,
21
21
  type MigrationTarget,
22
22
  } from "../migration/types";
23
+ import { forwardAsyncErrors } from "./async-route";
23
24
 
24
25
  type ApprovalReady = { type: "ready" };
25
26
  type ApprovalResult = ApprovalReady | SlackConfirmPendingResult;
@@ -39,7 +40,8 @@ function assertTargets(migrator: Migrator, targets: MigrationTarget[]): void {
39
40
  }
40
41
 
41
42
  function targetRequiresApproval(slack: SlackConfirm, target: MigrationTarget): boolean {
42
- const connection = Sonamu.dbConfig[target]?.connection as { host?: string } | undefined;
43
+ const connection = /* SAFETY: UI 도구의 Zod 입력 스키마가 이 값의 타입을 보장한다. */ Sonamu
44
+ .dbConfig[target]?.connection as { host?: string } | undefined;
43
45
  const remote = !LOCAL_HOSTS.has((connection?.host ?? "localhost").toLowerCase());
44
46
  return remote && slack.isTargetRequiresApproval(target);
45
47
  }
@@ -251,58 +253,65 @@ export async function registerMigrationsApi(server: FastifyInstance) {
251
253
  connections: migrator.getConnections(),
252
254
  }));
253
255
  server.get("/api/migrations/codes", async () => ({ codes: await migrator.getMigrationCodes() }));
254
- server.get<{ Querystring: { codeName: string } }>("/api/migrations/code", async (request) => {
255
- const migrationCode = (await migrator.getMigrationCodes()).find(
256
- ({ name }) => name === request.query.codeName,
257
- );
258
- if (migrationCode === undefined) {
259
- throw new BadRequestException(SD("error.badRequest"));
260
- }
261
- return { code: await readFile(migrationCode.path, "utf8") };
262
- });
263
- server.get<{ Querystring: { connKey?: MigrationTarget } }>(
264
- "/api/migrations/status",
265
- async (request) => {
256
+ server.get<{ Querystring: { codeName: string } }>("/api/migrations/code", (request) =>
257
+ forwardAsyncErrors(async () => {
258
+ const migrationCode = (await migrator.getMigrationCodes()).find(
259
+ ({ name }) => name === request.query.codeName,
260
+ );
261
+ if (migrationCode === undefined) {
262
+ throw new BadRequestException(SD("error.badRequest"));
263
+ }
264
+ return { code: await readFile(migrationCode.path, "utf8") };
265
+ }),
266
+ );
267
+ server.get<{ Querystring: { connKey?: MigrationTarget } }>("/api/migrations/status", (request) =>
268
+ forwardAsyncErrors(async () => {
266
269
  if (request.query.connKey === undefined) {
267
270
  return { status: await migrator.getStatus() };
268
271
  }
269
272
  return { status: await migrator.getConnectionStatus(request.query.connKey) };
270
- },
273
+ }),
271
274
  );
272
275
  server.get<{ Querystring: { compareConnKey: MigrationTarget } }>(
273
276
  "/api/migrations/prepared-codes",
274
- async (request) => ({
275
- preparedCodes: await migrator.getPreparedCodes(request.query.compareConnKey),
276
- }),
277
+ (request) =>
278
+ forwardAsyncErrors(async () => ({
279
+ preparedCodes: await migrator.getPreparedCodes(request.query.compareConnKey),
280
+ })),
277
281
  );
278
282
 
279
- server.post<{ Body: ApplyBody }>("/api/migrations/request-approval", async (request) => {
280
- return requestApproval(migrator, request.body.targets, request.body.requestor);
281
- });
283
+ server.post<{ Body: ApplyBody }>("/api/migrations/request-approval", (request) =>
284
+ forwardAsyncErrors(async () => {
285
+ return requestApproval(migrator, request.body.targets, request.body.requestor);
286
+ }),
287
+ );
282
288
  server.post<{ Body: { channel: string; ts: string } }>(
283
289
  "/api/migrations/checkApproval",
284
- async (request) => {
285
- const slack = new SlackConfirm();
286
- return slack.isConfigured()
287
- ? slack.checkApproval(request.body.channel, request.body.ts)
288
- : { approved: true, rejected: false };
289
- },
290
+ (request) =>
291
+ forwardAsyncErrors(async () => {
292
+ const slack = new SlackConfirm();
293
+ return slack.isConfigured()
294
+ ? slack.checkApproval(request.body.channel, request.body.ts)
295
+ : { approved: true, rejected: false };
296
+ }),
290
297
  );
291
298
  server.post<{
292
299
  Body: { channel: string; ts: string; reason: string; requestor?: string };
293
- }>("/api/migrations/forceApproval", async (request) => {
294
- const slack = new SlackConfirm();
295
- if (!slack.isConfigured()) {
296
- throw new BadRequestException(SD("sonamu.error.slackConfirmNotConfigured"));
297
- }
298
- await slack.forceApproval(
299
- request.body.channel,
300
- request.body.ts,
301
- request.body.reason,
302
- request.body.requestor,
303
- );
304
- return { success: true };
305
- });
300
+ }>("/api/migrations/forceApproval", (request) =>
301
+ forwardAsyncErrors(async () => {
302
+ const slack = new SlackConfirm();
303
+ if (!slack.isConfigured()) {
304
+ throw new BadRequestException(SD("sonamu.error.slackConfirmNotConfigured"));
305
+ }
306
+ await slack.forceApproval(
307
+ request.body.channel,
308
+ request.body.ts,
309
+ request.body.reason,
310
+ request.body.requestor,
311
+ );
312
+ return { success: true };
313
+ }),
314
+ );
306
315
 
307
316
  server.post("/api/migrations/shadow", async (_request, reply) => {
308
317
  return sendMigrationStream(reply, "shadow", [], (onProgress) => {
@@ -343,7 +352,8 @@ export async function registerMigrationsApi(server: FastifyInstance) {
343
352
 
344
353
  server.post<{ Body: { compareConnKey?: MigrationTarget } }>(
345
354
  "/api/migrations/generatePreparedCodes",
346
- async (request) => migrator.generatePreparedCodes(request.body.compareConnKey),
355
+ (request) =>
356
+ forwardAsyncErrors(async () => migrator.generatePreparedCodes(request.body.compareConnKey)),
347
357
  );
348
358
 
349
359
  // 이전 UI 번들과 외부 스크립트가 새 서버에서도 한 릴리스 동안 동작하도록 유지합니다.
@@ -355,15 +365,17 @@ export async function registerMigrationsApi(server: FastifyInstance) {
355
365
  forceReason?: string;
356
366
  requestor?: string;
357
367
  };
358
- }>("/api/migrations/runAction", async (request) => {
359
- if (request.body.action === "shadow") {
360
- return migrator.runShadowTest();
361
- }
362
- if (request.body.action === "apply") {
363
- return runLegacyApply(migrator, request.body);
364
- }
365
- assertTargets(migrator, request.body.targets);
366
- await getAvailableTargetStatuses(migrator, request.body.targets);
367
- return migrator.rollback(request.body.targets);
368
- });
368
+ }>("/api/migrations/runAction", (request) =>
369
+ forwardAsyncErrors(async () => {
370
+ if (request.body.action === "shadow") {
371
+ return migrator.runShadowTest();
372
+ }
373
+ if (request.body.action === "apply") {
374
+ return runLegacyApply(migrator, request.body);
375
+ }
376
+ assertTargets(migrator, request.body.targets);
377
+ await getAvailableTargetStatuses(migrator, request.body.targets);
378
+ return migrator.rollback(request.body.targets);
379
+ }),
380
+ );
369
381
  }
@@ -10,8 +10,9 @@ import { format, type FormatConfig } from "oxfmt";
10
10
  import { cached } from "./async-utils";
11
11
  import { isTest } from "./controller";
12
12
  import { execute } from "./process-utils";
13
+ import { isNumberValue } from "./runtime-value";
13
14
 
14
- const _require = createRequire(import.meta.url);
15
+ const requireFromHere = createRequire(import.meta.url);
15
16
 
16
17
  /**
17
18
  * 코드를 프로젝트의 oxfmt + oxlint 설정에 맞춰 포매팅한 문자열을 반환합니다.
@@ -75,9 +76,11 @@ async function loadOxfmtConfig(): Promise<FormatConfig> {
75
76
  while (true) {
76
77
  const candidate = join(dir, ".oxfmtrc.json");
77
78
  try {
79
+ // SAFETY: 선행 분기와 함수 계약이 이 타입을 보장합니다.
78
80
  cachedOxfmtConfig = JSON.parse(await readFile(candidate, "utf-8")) as FormatConfig;
79
81
  return cachedOxfmtConfig;
80
82
  } catch (e) {
83
+ // SAFETY: 선행 분기와 함수 계약이 이 타입을 보장합니다.
81
84
  if ((e as NodeJS.ErrnoException).code !== "ENOENT") {
82
85
  !isTest() && console.error(`Failed to load ${candidate}:`, e);
83
86
  break;
@@ -121,7 +124,8 @@ async function runOxlint(code: string): Promise<string> {
121
124
  });
122
125
  } catch (e) {
123
126
  // lint 위반 시 exit code != 0이지만 --fix는 적용됨. exec 자체 실패만 throw.
124
- if (typeof (e as Error & { code?: number }).code !== "number") {
127
+ // SAFETY: 선행 분기와 함수 계약이 이 타입을 보장합니다.
128
+ if (!isNumberValue((e as Error & { code?: number }).code)) {
125
129
  throw e;
126
130
  }
127
131
  }
@@ -138,7 +142,7 @@ async function runOxlint(code: string): Promise<string> {
138
142
 
139
143
  function resolveOxlintBin(): string {
140
144
  try {
141
- return _require.resolve("oxlint/bin/oxlint");
145
+ return requireFromHere.resolve("oxlint/bin/oxlint");
142
146
  } catch {
143
147
  return "oxlint";
144
148
  }
@@ -8,12 +8,12 @@ import { formatCode } from "./formatter";
8
8
  /**
9
9
  * fs/promises에는 exists가 없어요. 대신 access가 있습니다.
10
10
  * 근데 얘는 인터페이스가 쓰기 불편해요. 그래서 감싸주었습니다.
11
- * @param path
11
+ * @param targetPath
12
12
  * @returns
13
13
  */
14
- export async function exists(path: PathLike): Promise<boolean> {
14
+ export async function exists(targetPath: PathLike): Promise<boolean> {
15
15
  try {
16
- await access(path, constants.F_OK);
16
+ await access(targetPath, constants.F_OK);
17
17
  return true;
18
18
  } catch {
19
19
  return false;
@@ -21,9 +21,9 @@ export async function exists(path: PathLike): Promise<boolean> {
21
21
  }
22
22
 
23
23
  // 디렉토리가 아니라 파일만 존재하는지 확인합니다.
24
- export async function fileExists(path: PathLike): Promise<boolean> {
24
+ export async function fileExists(targetPath: PathLike): Promise<boolean> {
25
25
  try {
26
- const stats = await stat(path);
26
+ const stats = await stat(targetPath);
27
27
  return stats.isFile();
28
28
  } catch {
29
29
  return false;
@@ -1,9 +1,7 @@
1
- import { type SonamuQueryMode } from "../types/types";
1
+ import { type SonamuQueryMode, type SonamuSemanticParams } from "../types/types";
2
2
 
3
3
  // semanticQuery가 있으면 similarity를 추가하는 조건부 타입
4
- type WithSimilarity<LP, T> = LP extends { semanticQuery: Record<string, unknown> }
5
- ? T & { similarity: number }
6
- : T;
4
+ type WithSimilarity<LP, T> = "semanticQuery" extends keyof LP ? T & { similarity: number } : T;
7
5
 
8
6
  export type ListResult<
9
7
  LP extends { queryMode?: SonamuQueryMode },
@@ -20,6 +18,7 @@ export function asArray<T>(param: T | T[]): T[] {
20
18
  if (Array.isArray(param)) {
21
19
  return param;
22
20
  } else {
21
+ // SAFETY: 선행 분기와 함수 계약이 이 타입을 보장합니다.
23
22
  return [param] as T[];
24
23
  }
25
24
  }
@@ -39,5 +38,5 @@ export interface BaseListParams {
39
38
  page?: number;
40
39
  keyword?: string;
41
40
  queryMode?: "list" | "count" | "both";
42
- semanticQuery?: Record<string, unknown>;
41
+ semanticQuery?: SonamuSemanticParams["semanticQuery"];
43
42
  }
@@ -1,3 +1,12 @@
1
+ import {
2
+ isBigIntValue,
3
+ isFunctionValue,
4
+ isNumberValue,
5
+ isObjectValue,
6
+ isStringValue,
7
+ isSymbolValue,
8
+ } from "./runtime-value";
9
+
1
10
  type Primitive = string | number | boolean | null | undefined;
2
11
 
3
12
  type TypedArray =
@@ -84,8 +93,8 @@ export interface SerializableCheckResult {
84
93
  * isSerializable({ fn: () => {} }) // { valid: false, reason: "Function at fn" }
85
94
  * isSerializable({ deep: { nested: Promise.resolve() } }) // { valid: false, reason: "Promise at deep.nested" }
86
95
  */
87
- export function isSerializable(
88
- value: unknown,
96
+ export function isSerializable<Value>(
97
+ value: Value,
89
98
  path: string[] = [],
90
99
  seen: WeakSet<object> = new WeakSet(),
91
100
  ): SerializableCheckResult {
@@ -94,23 +103,26 @@ export function isSerializable(
94
103
  return { valid: true };
95
104
  }
96
105
 
97
- const type = typeof value;
98
- if (type === "string" || type === "number" || type === "boolean" || type === "undefined") {
99
- return { valid: true };
100
- }
101
- if (type === "bigint") {
106
+ if (
107
+ isStringValue(value) ||
108
+ isNumberValue(value) ||
109
+ value === true ||
110
+ value === false ||
111
+ value === undefined ||
112
+ isBigIntValue(value)
113
+ ) {
102
114
  return { valid: true };
103
115
  }
104
116
 
105
- if (type === "function") {
117
+ if (isFunctionValue(value)) {
106
118
  return { valid: false, reason: `Function at ${formatPath(path)}` };
107
119
  }
108
- if (type === "symbol") {
120
+ if (isSymbolValue(value)) {
109
121
  return { valid: false, reason: `Symbol at ${formatPath(path)}` };
110
122
  }
111
123
 
112
- if (type === "object") {
113
- const obj = value as object;
124
+ if (isObjectValue(value)) {
125
+ const obj = value;
114
126
 
115
127
  if (obj instanceof Promise) {
116
128
  return { valid: false, reason: `Promise at ${formatPath(path)}` };
@@ -126,7 +138,7 @@ export function isSerializable(
126
138
  if (obj instanceof WeakSet) {
127
139
  return { valid: false, reason: `WeakSet at ${formatPath(path)}` };
128
140
  }
129
- if (typeof WeakRef !== "undefined" && obj instanceof WeakRef) {
141
+ if ("WeakRef" in globalThis && obj instanceof WeakRef) {
130
142
  return { valid: false, reason: `WeakRef at ${formatPath(path)}` };
131
143
  }
132
144
 
@@ -179,13 +191,11 @@ export function isSerializable(
179
191
 
180
192
  // Vitest는 Error를 허용하지만 속성은 직렬화 필요
181
193
  if (obj instanceof Error) {
182
- const errorProps = Object.keys(obj).filter((k) => !["name", "message", "stack"].includes(k));
183
- for (const key of errorProps) {
184
- const result = isSerializable(
185
- (obj as unknown as Record<string, unknown>)[key],
186
- [...path, key],
187
- seen,
188
- );
194
+ const errorEntries = Object.entries(obj).filter(
195
+ ([key]) => !["name", "message", "stack"].includes(key),
196
+ );
197
+ for (const [key, nestedValue] of errorEntries) {
198
+ const result = isSerializable(nestedValue, [...path, key], seen);
189
199
  if (!result.valid) return result;
190
200
  }
191
201
  return { valid: true };
@@ -201,14 +211,14 @@ export function isSerializable(
201
211
  };
202
212
  }
203
213
 
204
- for (const key of Object.keys(obj)) {
205
- const result = isSerializable((obj as Record<string, unknown>)[key], [...path, key], seen);
214
+ for (const [key, nestedValue] of Object.entries(obj)) {
215
+ const result = isSerializable(nestedValue, [...path, key], seen);
206
216
  if (!result.valid) return result;
207
217
  }
208
218
  return { valid: true };
209
219
  }
210
220
 
211
- return { valid: false, reason: `Unknown type (${type}) at ${formatPath(path)}` };
221
+ return { valid: false, reason: `Unknown value at ${formatPath(path)}` };
212
222
  }
213
223
 
214
224
  function formatPath(path: string[]): string {
@@ -4,6 +4,8 @@ import { promisify } from "util";
4
4
 
5
5
  import chalk from "chalk";
6
6
 
7
+ import { isStringValue } from "./runtime-value";
8
+
7
9
  const execFileAsync = promisify(execFile);
8
10
 
9
11
  /**
@@ -16,7 +18,7 @@ export async function execute(
16
18
  options?: ExecFileOptions,
17
19
  ): Promise<string> {
18
20
  const { stdout } = await execFileAsync(bin, args, options);
19
- return typeof stdout === "string" ? stdout : stdout.toString();
21
+ return isStringValue(stdout) ? stdout : stdout.toString();
20
22
  }
21
23
 
22
24
  /**
@@ -37,6 +39,7 @@ export async function runWithGracefulShutdown(
37
39
  waitForUpTo: 20000,
38
40
  },
39
41
  ): Promise<void> {
42
+ // SAFETY: 선행 분기와 함수 계약이 이 타입을 보장합니다.
40
43
  let isRunning = true as boolean;
41
44
 
42
45
  const abortController = new AbortController();
@@ -0,0 +1,43 @@
1
+ function hasPrimitiveTag<Value>(value: Value, tag: string): boolean {
2
+ return Object.prototype.toString.call(value) === tag && Object(value) !== value;
3
+ }
4
+
5
+ /** 런타임 값이 원시 문자열인지 판별합니다. */
6
+ export function isStringValue<Value>(value: Value): value is Value & string {
7
+ return hasPrimitiveTag(value, "[object String]");
8
+ }
9
+
10
+ /** 런타임 값이 원시 숫자인지 판별합니다. */
11
+ export function isNumberValue<Value>(value: Value): value is Value & number {
12
+ return hasPrimitiveTag(value, "[object Number]");
13
+ }
14
+
15
+ /** 런타임 값이 원시 심벌인지 판별합니다. */
16
+ export function isSymbolValue<Value>(value: Value): value is Value & symbol {
17
+ return hasPrimitiveTag(value, "[object Symbol]");
18
+ }
19
+
20
+ /** 런타임 값이 원시 bigint인지 판별합니다. */
21
+ export function isBigIntValue<Value>(value: Value): value is Value & bigint {
22
+ return hasPrimitiveTag(value, "[object BigInt]");
23
+ }
24
+
25
+ /** 런타임 값이 함수인지 판별합니다. */
26
+ export function isFunctionValue<Value>(value: Value): value is Value & CallableFunction {
27
+ try {
28
+ const tag = Object.prototype.toString.call(value);
29
+ return (
30
+ tag === "[object Function]" ||
31
+ tag === "[object AsyncFunction]" ||
32
+ tag === "[object GeneratorFunction]" ||
33
+ tag === "[object AsyncGeneratorFunction]"
34
+ );
35
+ } catch {
36
+ return false;
37
+ }
38
+ }
39
+
40
+ /** null과 함수를 제외한 객체 표현인지 판별합니다. */
41
+ export function isObjectValue<Value>(value: Value): value is Value & object {
42
+ return value !== null && Object(value) === value && !isFunctionValue(value);
43
+ }
@@ -9,15 +9,21 @@ import {
9
9
  } from "node-sql-parser";
10
10
  import { unique } from "radashi";
11
11
 
12
+ import { isObjectValue, isStringValue } from "./runtime-value";
12
13
  import { nonNullable } from "./utils";
13
14
 
14
- export function getTableName(expr: ColumnRef) {
15
- if ("table" in expr && expr.table !== null) {
16
- return typeof expr.table === "string"
17
- ? expr.table
18
- : (expr.table as { type: string; value: string }).value;
15
+ type ParserColumnRef = Omit<ColumnRef, "table"> & {
16
+ table?: string | { type: string; value: string } | null;
17
+ };
18
+
19
+ export function getTableName(expr: ParserColumnRef) {
20
+ const table = expr.table;
21
+ if (isStringValue(table)) {
22
+ return table;
19
23
  }
20
- return null;
24
+ return isObjectValue(table) && "value" in table && isStringValue(table.value)
25
+ ? table.value
26
+ : null;
21
27
  }
22
28
 
23
29
  // where 조건에 사용된 테이블명을 추출
@@ -29,6 +35,7 @@ export function getTableNamesFromWhere(ast: AST | AST[]): string[] {
29
35
 
30
36
  const extractTableName = (expr: Expr | ExpressionValue): string[] => {
31
37
  if (expr.type === "column_ref") {
38
+ // SAFETY: 선행 분기와 함수 계약이 이 타입을 보장합니다.
32
39
  const table = getTableName(expr as ColumnRef);
33
40
  return table ? [table] : [];
34
41
  } else if (expr.type === "binary_expr" && "left" in expr) {
@@ -1,3 +1,4 @@
1
+ import { isObjectValue } from "./runtime-value";
1
2
  // 타입을 펼쳐서 보여주는 유틸리티 (객체에만 사용해야 함)
2
3
  type Expand<T> = T extends infer O ? { [K in keyof O]: O[K] } : never;
3
4
 
@@ -32,9 +33,9 @@ export function withProp<T extends object, P extends string, V>(
32
33
  const result = structuredClone(obj);
33
34
 
34
35
  // oxlint-disable-next-line @typescript-eslint/no-explicit-any -- 범용 배열 요소 타입
35
- const setDeep = (current: any, keys: string[], value: V): void => {
36
- if (keys.length === 0) return;
37
- const [key, ...rest] = keys;
36
+ const setDeep = (current: any, pathKeys: string[]): void => {
37
+ if (pathKeys.length === 0) return;
38
+ const [key, ...rest] = pathKeys;
38
39
 
39
40
  if (rest.length === 0) {
40
41
  if (Array.isArray(current)) {
@@ -45,21 +46,22 @@ export function withProp<T extends object, P extends string, V>(
45
46
  current[key] = value;
46
47
  }
47
48
  } else {
48
- if (!(key in current) || typeof current[key] !== "object") {
49
+ if (!(key in current) || !isObjectValue(current[key])) {
49
50
  current[key] = {};
50
51
  }
51
52
  if (Array.isArray(current[key])) {
52
53
  // oxlint-disable-next-line @typescript-eslint/no-explicit-any -- 범용 배열 요소 타입
53
54
  current[key].forEach((item: any) => {
54
- setDeep(item, rest, value);
55
+ setDeep(item, rest);
55
56
  });
56
57
  } else {
57
- setDeep(current[key], rest, value);
58
+ setDeep(current[key], rest);
58
59
  }
59
60
  }
60
61
  };
61
62
 
62
- setDeep(result, keys, value);
63
+ setDeep(result, keys);
64
+ // SAFETY: 선행 분기와 함수 계약이 이 타입을 보장합니다.
63
65
  return result as SetPath<T, P, V>;
64
66
  }
65
67