sonamu 0.10.12 → 0.10.13

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (513) hide show
  1. package/dist/ai/agents/agent.d.ts +1 -1
  2. package/dist/ai/agents/agent.d.ts.map +1 -1
  3. package/dist/ai/agents/agent.js +5 -6
  4. package/dist/ai/agents/types.d.ts +1 -1
  5. package/dist/ai/agents/types.d.ts.map +1 -1
  6. package/dist/ai/providers/rtzr/api.js +18 -18
  7. package/dist/ai/providers/rtzr/error.d.ts.map +1 -1
  8. package/dist/ai/providers/rtzr/error.js +17 -15
  9. package/dist/ai/providers/rtzr/model.d.ts.map +1 -1
  10. package/dist/ai/providers/rtzr/model.js +3 -2
  11. package/dist/ai/providers/rtzr/options.d.ts.map +1 -1
  12. package/dist/ai/providers/rtzr/options.js +16 -16
  13. package/dist/ai/providers/rtzr/provider.d.ts.map +1 -1
  14. package/dist/ai/providers/rtzr/provider.js +9 -9
  15. package/dist/ai/providers/rtzr/utils.d.ts.map +1 -1
  16. package/dist/ai/providers/rtzr/utils.js +1 -1
  17. package/dist/api/caster.d.ts.map +1 -1
  18. package/dist/api/caster.js +17 -17
  19. package/dist/api/code-converters.d.ts +4 -2
  20. package/dist/api/code-converters.d.ts.map +1 -1
  21. package/dist/api/code-converters.js +100 -19
  22. package/dist/api/config.d.ts +16 -1
  23. package/dist/api/config.d.ts.map +1 -1
  24. package/dist/api/config.js +28 -21
  25. package/dist/api/context.d.ts +2 -2
  26. package/dist/api/context.d.ts.map +1 -1
  27. package/dist/api/context.js +1 -1
  28. package/dist/api/decorators.d.ts.map +1 -1
  29. package/dist/api/decorators.js +18 -11
  30. package/dist/api/http-validator.d.ts +36 -0
  31. package/dist/api/http-validator.d.ts.map +1 -0
  32. package/dist/api/http-validator.js +72 -0
  33. package/dist/api/index.js +6 -4
  34. package/dist/api/sonamu.d.ts +59 -20
  35. package/dist/api/sonamu.d.ts.map +1 -1
  36. package/dist/api/sonamu.js +250 -106
  37. package/dist/api/websocket-helpers.d.ts +7 -5
  38. package/dist/api/websocket-helpers.d.ts.map +1 -1
  39. package/dist/api/websocket-helpers.js +6 -6
  40. package/dist/auth/audit-log/builders.d.ts.map +1 -1
  41. package/dist/auth/audit-log/builders.js +1 -1
  42. package/dist/auth/audit-log/client-ip.d.ts +1 -1
  43. package/dist/auth/audit-log/client-ip.d.ts.map +1 -1
  44. package/dist/auth/audit-log/client-ip.js +4 -2
  45. package/dist/auth/audit-log/events.d.ts +5 -1
  46. package/dist/auth/audit-log/events.d.ts.map +1 -1
  47. package/dist/auth/audit-log/events.js +1 -1
  48. package/dist/auth/audit-log/plugin.d.ts +0 -8
  49. package/dist/auth/audit-log/plugin.d.ts.map +1 -1
  50. package/dist/auth/audit-log/plugin.js +48 -52
  51. package/dist/auth/audit-log-ingestor.d.ts.map +1 -1
  52. package/dist/auth/audit-log-ingestor.js +16 -12
  53. package/dist/auth/auth-generator.d.ts.map +1 -1
  54. package/dist/auth/auth-generator.js +1 -1
  55. package/dist/auth/better-auth-request.d.ts.map +1 -1
  56. package/dist/auth/better-auth-request.js +6 -5
  57. package/dist/auth/knex-adapter.js +1 -1
  58. package/dist/auth/plugins/entity-definitions/index.d.ts +13 -1
  59. package/dist/auth/plugins/entity-definitions/index.d.ts.map +1 -1
  60. package/dist/auth/plugins/entity-definitions/index.js +1 -1
  61. package/dist/auth/plugins/wrappers/admin.d.ts +1 -1
  62. package/dist/bin/build-config.d.ts +25 -0
  63. package/dist/bin/build-config.d.ts.map +1 -1
  64. package/dist/bin/build-config.js +105 -2
  65. package/dist/bin/cli.js +131 -27
  66. package/dist/bin/compiler-policy.d.ts +3 -0
  67. package/dist/bin/compiler-policy.d.ts.map +1 -0
  68. package/dist/bin/compiler-policy.js +24 -0
  69. package/dist/bin/fixture.d.ts.map +1 -1
  70. package/dist/bin/fixture.js +5 -3
  71. package/dist/bin/test-command.d.ts +22 -1
  72. package/dist/bin/test-command.d.ts.map +1 -1
  73. package/dist/bin/test-command.js +18 -10
  74. package/dist/bin/ts-loader-registration.d.ts +7 -1
  75. package/dist/bin/ts-loader-registration.d.ts.map +1 -1
  76. package/dist/bin/ts-loader-registration.js +13 -4
  77. package/dist/cache/decorator.d.ts.map +1 -1
  78. package/dist/cache/decorator.js +11 -4
  79. package/dist/compress/compress.d.ts.map +1 -1
  80. package/dist/compress/compress.js +1 -1
  81. package/dist/cone/cone-generator.d.ts +14 -1
  82. package/dist/cone/cone-generator.d.ts.map +1 -1
  83. package/dist/cone/cone-generator.js +13 -9
  84. package/dist/database/_batch_update.js +1 -1
  85. package/dist/database/base-model.d.ts +22 -10
  86. package/dist/database/base-model.d.ts.map +1 -1
  87. package/dist/database/base-model.js +26 -16
  88. package/dist/database/base-model.types.d.ts +15 -3
  89. package/dist/database/base-model.types.d.ts.map +1 -1
  90. package/dist/database/db.d.ts +12 -2
  91. package/dist/database/db.d.ts.map +1 -1
  92. package/dist/database/db.js +10 -7
  93. package/dist/database/knex.d.ts.map +1 -1
  94. package/dist/database/knex.js +17 -14
  95. package/dist/database/puri.d.ts +11 -9
  96. package/dist/database/puri.d.ts.map +1 -1
  97. package/dist/database/puri.js +93 -79
  98. package/dist/database/puri.types.d.ts +21 -21
  99. package/dist/database/puri.types.d.ts.map +1 -1
  100. package/dist/database/puri.types.js +1 -1
  101. package/dist/database/upsert-builder.d.ts +12 -10
  102. package/dist/database/upsert-builder.d.ts.map +1 -1
  103. package/dist/database/upsert-builder.js +20 -12
  104. package/dist/dict/sd.d.ts.map +1 -1
  105. package/dist/dict/sd.js +1 -1
  106. package/dist/dict/sonamu-dictionary.d.ts.map +1 -1
  107. package/dist/dict/sonamu-dictionary.js +1 -1
  108. package/dist/dict/utils.d.ts.map +1 -1
  109. package/dist/dict/utils.js +7 -2
  110. package/dist/entity/entity-manager.d.ts +13 -4
  111. package/dist/entity/entity-manager.d.ts.map +1 -1
  112. package/dist/entity/entity-manager.js +19 -11
  113. package/dist/entity/entity-template-cone.d.ts +73 -5
  114. package/dist/entity/entity-template-cone.d.ts.map +1 -1
  115. package/dist/entity/entity-template-cone.js +4 -2
  116. package/dist/entity/entity.d.ts +6 -2
  117. package/dist/entity/entity.d.ts.map +1 -1
  118. package/dist/entity/entity.js +30 -28
  119. package/dist/env.d.ts +3 -1
  120. package/dist/env.d.ts.map +1 -1
  121. package/dist/env.js +1 -1
  122. package/dist/exceptions/error-handler.d.ts.map +1 -1
  123. package/dist/exceptions/error-handler.js +7 -2
  124. package/dist/exceptions/so-exceptions.d.ts +24 -20
  125. package/dist/exceptions/so-exceptions.d.ts.map +1 -1
  126. package/dist/exceptions/so-exceptions.js +4 -2
  127. package/dist/filter/utils.d.ts +7 -2
  128. package/dist/filter/utils.d.ts.map +1 -1
  129. package/dist/filter/utils.js +8 -6
  130. package/dist/index.d.ts +3 -0
  131. package/dist/index.d.ts.map +1 -1
  132. package/dist/index.js +12 -6
  133. package/dist/logger/configure.d.ts.map +1 -1
  134. package/dist/logger/configure.js +10 -10
  135. package/dist/migration/code-generation.d.ts.map +1 -1
  136. package/dist/migration/code-generation.js +50 -46
  137. package/dist/migration/index-where-predicate.d.ts.map +1 -1
  138. package/dist/migration/index-where-predicate.js +22 -8
  139. package/dist/migration/migration-set.d.ts.map +1 -1
  140. package/dist/migration/migration-set.js +1 -1
  141. package/dist/migration/migrator.d.ts +3 -2
  142. package/dist/migration/migrator.d.ts.map +1 -1
  143. package/dist/migration/migrator.js +27 -21
  144. package/dist/migration/postgresql-schema-reader.d.ts.map +1 -1
  145. package/dist/migration/postgresql-schema-reader.js +51 -36
  146. package/dist/migration/slack-confirm.d.ts.map +1 -1
  147. package/dist/migration/slack-confirm.js +1 -1
  148. package/dist/naite/naite-reporter.js +2 -2
  149. package/dist/naite/naite.d.ts +74 -15
  150. package/dist/naite/naite.d.ts.map +1 -1
  151. package/dist/naite/naite.js +5 -19
  152. package/dist/runtime-type.d.ts +6 -0
  153. package/dist/runtime-type.d.ts.map +1 -0
  154. package/dist/runtime-type.js +26 -0
  155. package/dist/ssr/hmr-opt-out.d.ts +26 -0
  156. package/dist/ssr/hmr-opt-out.d.ts.map +1 -0
  157. package/dist/ssr/hmr-opt-out.js +59 -0
  158. package/dist/ssr/renderer.d.ts.map +1 -1
  159. package/dist/ssr/renderer.js +4 -1
  160. package/dist/storage/base-file.js +14 -14
  161. package/dist/storage/buffered-file.d.ts +2 -2
  162. package/dist/storage/buffered-file.d.ts.map +1 -1
  163. package/dist/storage/buffered-file.js +12 -12
  164. package/dist/storage/s3-driver.d.ts.map +1 -1
  165. package/dist/storage/s3-driver.js +1 -1
  166. package/dist/storage/uploaded-file.d.ts +2 -2
  167. package/dist/storage/uploaded-file.d.ts.map +1 -1
  168. package/dist/storage/uploaded-file.js +8 -8
  169. package/dist/stream/sse.js +11 -11
  170. package/dist/stream/ws-core.d.ts +1 -1
  171. package/dist/stream/ws-core.d.ts.map +1 -1
  172. package/dist/stream/ws-delivery.d.ts +1 -1
  173. package/dist/stream/ws-delivery.d.ts.map +1 -1
  174. package/dist/stream/ws-delivery.js +6 -4
  175. package/dist/stream/ws-local-connection-store.d.ts.map +1 -1
  176. package/dist/stream/ws-local-connection-store.js +4 -2
  177. package/dist/stream/ws-presence-store.js +1 -1
  178. package/dist/stream/ws-registry.d.ts +4 -4
  179. package/dist/stream/ws-registry.d.ts.map +1 -1
  180. package/dist/stream/ws-registry.js +4 -2
  181. package/dist/stream/ws-telemetry.d.ts +16 -12
  182. package/dist/stream/ws-telemetry.d.ts.map +1 -1
  183. package/dist/stream/ws-telemetry.js +22 -18
  184. package/dist/stream/ws.d.ts +18 -12
  185. package/dist/stream/ws.d.ts.map +1 -1
  186. package/dist/stream/ws.js +26 -22
  187. package/dist/syncer/api-parser.js +1 -1
  188. package/dist/syncer/checksum.d.ts.map +1 -1
  189. package/dist/syncer/checksum.js +7 -8
  190. package/dist/syncer/code-generator.d.ts.map +1 -1
  191. package/dist/syncer/code-generator.js +13 -14
  192. package/dist/syncer/entity-operations.d.ts.map +1 -1
  193. package/dist/syncer/entity-operations.js +5 -6
  194. package/dist/syncer/file-copy.d.ts +5 -0
  195. package/dist/syncer/file-copy.d.ts.map +1 -0
  196. package/dist/syncer/file-copy.js +36 -0
  197. package/dist/syncer/file-patterns.d.ts +1 -0
  198. package/dist/syncer/file-patterns.d.ts.map +1 -1
  199. package/dist/syncer/file-patterns.js +5 -2
  200. package/dist/syncer/file-tracking.d.ts.map +1 -1
  201. package/dist/syncer/file-tracking.js +5 -4
  202. package/dist/syncer/filesystem-dependencies.d.ts +15 -0
  203. package/dist/syncer/filesystem-dependencies.d.ts.map +1 -0
  204. package/dist/syncer/filesystem-dependencies.js +53 -0
  205. package/dist/syncer/module-loader.d.ts +1 -1
  206. package/dist/syncer/module-loader.d.ts.map +1 -1
  207. package/dist/syncer/module-loader.js +6 -4
  208. package/dist/syncer/syncer-actions.d.ts +4 -0
  209. package/dist/syncer/syncer-actions.d.ts.map +1 -1
  210. package/dist/syncer/syncer-actions.js +34 -17
  211. package/dist/syncer/syncer.d.ts +17 -6
  212. package/dist/syncer/syncer.d.ts.map +1 -1
  213. package/dist/syncer/syncer.js +71 -29
  214. package/dist/syncer/watcher.d.ts.map +1 -1
  215. package/dist/syncer/watcher.js +3 -3
  216. package/dist/tasks/decorator.d.ts +6 -6
  217. package/dist/tasks/decorator.d.ts.map +1 -1
  218. package/dist/tasks/decorator.js +4 -4
  219. package/dist/tasks/step-wrapper.d.ts +6 -4
  220. package/dist/tasks/step-wrapper.d.ts.map +1 -1
  221. package/dist/tasks/step-wrapper.js +5 -5
  222. package/dist/tasks/workflow-manager.d.ts.map +1 -1
  223. package/dist/tasks/workflow-manager.js +13 -7
  224. package/dist/template/entity-converter.d.ts +1 -1
  225. package/dist/template/entity-converter.d.ts.map +1 -1
  226. package/dist/template/entity-converter.js +2 -2
  227. package/dist/template/helpers.d.ts +8 -6
  228. package/dist/template/helpers.d.ts.map +1 -1
  229. package/dist/template/helpers.js +1 -1
  230. package/dist/template/implementations/generated.template.d.ts.map +1 -1
  231. package/dist/template/implementations/generated.template.js +4 -4
  232. package/dist/template/implementations/generated_http.template.d.ts +7 -4
  233. package/dist/template/implementations/generated_http.template.d.ts.map +1 -1
  234. package/dist/template/implementations/generated_http.template.js +21 -21
  235. package/dist/template/implementations/generated_sso.template.d.ts.map +1 -1
  236. package/dist/template/implementations/generated_sso.template.js +6 -3
  237. package/dist/template/implementations/http_validators.template.d.ts +18 -0
  238. package/dist/template/implementations/http_validators.template.d.ts.map +1 -0
  239. package/dist/template/implementations/http_validators.template.js +127 -0
  240. package/dist/template/implementations/model.template.d.ts.map +1 -1
  241. package/dist/template/implementations/model.template.js +1 -1
  242. package/dist/template/implementations/queries.template.js +1 -1
  243. package/dist/template/implementations/sd.template.d.ts.map +1 -1
  244. package/dist/template/implementations/sd.template.js +79 -39
  245. package/dist/template/implementations/services.template.d.ts.map +1 -1
  246. package/dist/template/implementations/services.template.js +6 -4
  247. package/dist/template/implementations/view_form.template.d.ts +6 -1
  248. package/dist/template/implementations/view_form.template.d.ts.map +1 -1
  249. package/dist/template/implementations/view_form.template.js +23 -15
  250. package/dist/template/implementations/view_list.template.d.ts.map +1 -1
  251. package/dist/template/implementations/view_list.template.js +11 -6
  252. package/dist/template/template-manager.d.ts.map +1 -1
  253. package/dist/template/template-manager.js +9 -7
  254. package/dist/template/template-types.d.ts +12 -5
  255. package/dist/template/template-types.d.ts.map +1 -1
  256. package/dist/template/template-types.js +1 -1
  257. package/dist/template/template.d.ts +2 -2
  258. package/dist/template/template.d.ts.map +1 -1
  259. package/dist/template/template.js +6 -4
  260. package/dist/template/zod-converter.d.ts +0 -19
  261. package/dist/template/zod-converter.d.ts.map +1 -1
  262. package/dist/template/zod-converter.js +100 -84
  263. package/dist/testing/_relation-graph.d.ts.map +1 -1
  264. package/dist/testing/_relation-graph.js +2 -1
  265. package/dist/testing/bootstrap.d.ts.map +1 -1
  266. package/dist/testing/bootstrap.js +9 -6
  267. package/dist/testing/data-explorer.d.ts +32 -7
  268. package/dist/testing/data-explorer.d.ts.map +1 -1
  269. package/dist/testing/data-explorer.js +77 -31
  270. package/dist/testing/dev-test-routes.d.ts +8 -1
  271. package/dist/testing/dev-test-routes.d.ts.map +1 -1
  272. package/dist/testing/dev-test-routes.js +125 -108
  273. package/dist/testing/dev-vitest-manager.d.ts +54 -8
  274. package/dist/testing/dev-vitest-manager.d.ts.map +1 -1
  275. package/dist/testing/dev-vitest-manager.js +24 -9
  276. package/dist/testing/faker-mappings.d.ts +412 -1
  277. package/dist/testing/faker-mappings.d.ts.map +1 -1
  278. package/dist/testing/faker-mappings.js +1 -1
  279. package/dist/testing/filesystem.d.ts +2 -0
  280. package/dist/testing/filesystem.d.ts.map +1 -0
  281. package/dist/testing/filesystem.js +7 -0
  282. package/dist/testing/fixture-generator.d.ts +25 -8
  283. package/dist/testing/fixture-generator.d.ts.map +1 -1
  284. package/dist/testing/fixture-generator.js +132 -73
  285. package/dist/testing/fixture-loader.d.ts +3 -1
  286. package/dist/testing/fixture-loader.d.ts.map +1 -1
  287. package/dist/testing/fixture-loader.js +1 -20
  288. package/dist/testing/fixture-manager.d.ts +8 -7
  289. package/dist/testing/fixture-manager.d.ts.map +1 -1
  290. package/dist/testing/fixture-manager.js +91 -59
  291. package/dist/testing/global-setup.d.ts.map +1 -1
  292. package/dist/testing/global-setup.js +5 -2
  293. package/dist/testing/index.d.ts +2 -0
  294. package/dist/testing/index.d.ts.map +1 -1
  295. package/dist/testing/index.js +6 -3
  296. package/dist/types/types.d.ts +101 -99
  297. package/dist/types/types.d.ts.map +1 -1
  298. package/dist/types/types.js +234 -225
  299. package/dist/ui/ai-api.d.ts.map +1 -1
  300. package/dist/ui/ai-api.js +1 -1
  301. package/dist/ui/ai-client.d.ts.map +1 -1
  302. package/dist/ui/ai-client.js +28 -18
  303. package/dist/ui/api.d.ts.map +1 -1
  304. package/dist/ui/api.js +135 -128
  305. package/dist/ui/async-route.d.ts +3 -0
  306. package/dist/ui/async-route.d.ts.map +1 -0
  307. package/dist/ui/async-route.js +12 -0
  308. package/dist/ui/cdd-service.d.ts +9 -7
  309. package/dist/ui/cdd-service.d.ts.map +1 -1
  310. package/dist/ui/cdd-service.js +7 -5
  311. package/dist/ui/migrations-api.d.ts.map +1 -1
  312. package/dist/ui/migrations-api.js +17 -15
  313. package/dist/ui-web/assets/index-DV1AAq6W.js +178 -0
  314. package/dist/ui-web/index.html +1 -1
  315. package/dist/utils/formatter.d.ts.map +1 -1
  316. package/dist/utils/formatter.js +7 -5
  317. package/dist/utils/fs-utils.d.ts +3 -3
  318. package/dist/utils/fs-utils.d.ts.map +1 -1
  319. package/dist/utils/fs-utils.js +6 -6
  320. package/dist/utils/model.d.ts +3 -5
  321. package/dist/utils/model.d.ts.map +1 -1
  322. package/dist/utils/model.js +1 -1
  323. package/dist/utils/object-utils.d.ts +1 -1
  324. package/dist/utils/object-utils.d.ts.map +1 -1
  325. package/dist/utils/object-utils.js +17 -16
  326. package/dist/utils/process-utils.d.ts.map +1 -1
  327. package/dist/utils/process-utils.js +4 -2
  328. package/dist/utils/runtime-value.d.ts +13 -0
  329. package/dist/utils/runtime-value.d.ts.map +1 -0
  330. package/dist/utils/runtime-value.js +40 -0
  331. package/dist/utils/sql-parser.d.ts +8 -1
  332. package/dist/utils/sql-parser.d.ts.map +1 -1
  333. package/dist/utils/sql-parser.js +6 -3
  334. package/dist/utils/type-utils.d.ts.map +1 -1
  335. package/dist/utils/type-utils.js +10 -8
  336. package/dist/utils/utils.d.ts +2 -2
  337. package/dist/utils/utils.d.ts.map +1 -1
  338. package/dist/utils/utils.js +11 -8
  339. package/dist/utils/zod-error.d.ts.map +1 -1
  340. package/dist/utils/zod-error.js +7 -4
  341. package/dist/vector/chunking.d.ts.map +1 -1
  342. package/dist/vector/chunking.js +1 -1
  343. package/dist/vector/embedding.d.ts.map +1 -1
  344. package/dist/vector/embedding.js +1 -1
  345. package/dist/vector/types.d.ts +3 -2
  346. package/dist/vector/types.d.ts.map +1 -1
  347. package/package.json +5 -3
  348. package/src/ai/agents/agent.ts +5 -5
  349. package/src/ai/agents/types.ts +1 -1
  350. package/src/ai/providers/rtzr/__tests__/model.test.ts +2 -2
  351. package/src/ai/providers/rtzr/error.ts +5 -3
  352. package/src/ai/providers/rtzr/model.ts +3 -2
  353. package/src/ai/providers/rtzr/options.ts +10 -5
  354. package/src/ai/providers/rtzr/provider.ts +10 -10
  355. package/src/ai/providers/rtzr/utils.ts +3 -1
  356. package/src/api/__tests__/config.test.ts +11 -21
  357. package/src/api/__tests__/sonamu.http-validator.test.ts +512 -0
  358. package/src/api/__tests__/sonamu.websocket.test.ts +51 -41
  359. package/src/api/__tests__/zod-compiler-policy.test.ts +95 -0
  360. package/src/api/caster.ts +6 -8
  361. package/src/api/code-converters.ts +136 -36
  362. package/src/api/config.ts +62 -4
  363. package/src/api/context.ts +3 -3
  364. package/src/api/decorators.ts +28 -17
  365. package/src/api/http-validator.ts +149 -0
  366. package/src/api/sonamu.ts +459 -152
  367. package/src/api/websocket-helpers.ts +24 -17
  368. package/src/auth/audit-log/builders.ts +3 -2
  369. package/src/auth/audit-log/client-ip.ts +4 -2
  370. package/src/auth/audit-log/events.ts +15 -1
  371. package/src/auth/audit-log/plugin.ts +129 -200
  372. package/src/auth/audit-log-ingestor.ts +19 -15
  373. package/src/auth/auth-generator.ts +10 -5
  374. package/src/auth/better-auth-request.ts +4 -3
  375. package/src/auth/knex-adapter.ts +8 -2
  376. package/src/auth/plugins/entity-definitions/index.ts +6 -5
  377. package/src/bin/__tests__/http-validator-benchmark.test.ts +94 -0
  378. package/src/bin/__tests__/test-command.test.ts +9 -15
  379. package/src/bin/__tests__/ts-loader-register.test.ts +15 -17
  380. package/src/bin/__tests__/zod-compiler-build.test.ts +307 -0
  381. package/src/bin/build-config.ts +167 -0
  382. package/src/bin/cli.ts +153 -36
  383. package/src/bin/compiler-policy.ts +35 -0
  384. package/src/bin/fixture.ts +14 -3
  385. package/src/bin/test-command.ts +74 -29
  386. package/src/bin/ts-loader-registration.ts +22 -4
  387. package/src/cache/decorator.ts +10 -3
  388. package/src/compress/compress.ts +17 -4
  389. package/src/cone/cone-generator.ts +34 -6
  390. package/src/database/__tests__/db.test.ts +1 -0
  391. package/src/database/__tests__/puri.test.ts +16 -15
  392. package/src/database/__tests__/transaction-scope.test.ts +5 -0
  393. package/src/database/_batch_update.ts +1 -0
  394. package/src/database/base-model.ts +81 -50
  395. package/src/database/base-model.types.ts +6 -6
  396. package/src/database/db.ts +29 -19
  397. package/src/database/knex.ts +30 -17
  398. package/src/database/puri-subset.test-d.ts +17 -0
  399. package/src/database/puri.ts +181 -143
  400. package/src/database/puri.types.test-d.ts +31 -1
  401. package/src/database/puri.types.ts +23 -21
  402. package/src/database/upsert-builder.ts +75 -53
  403. package/src/dict/sd.ts +15 -5
  404. package/src/dict/sonamu-dictionary.ts +6 -6
  405. package/src/dict/utils.ts +9 -1
  406. package/src/entity/entity-manager.ts +26 -9
  407. package/src/entity/entity-template-cone.ts +5 -10
  408. package/src/entity/entity.ts +50 -34
  409. package/src/env.ts +7 -3
  410. package/src/exceptions/error-handler.ts +17 -2
  411. package/src/exceptions/so-exceptions.ts +26 -20
  412. package/src/filter/utils.ts +21 -11
  413. package/src/index.ts +3 -0
  414. package/src/logger/configure.ts +26 -18
  415. package/src/migration/__tests__/migrator.test.ts +50 -57
  416. package/src/migration/code-generation.ts +132 -104
  417. package/src/migration/index-where-predicate.ts +51 -24
  418. package/src/migration/migration-set.ts +11 -5
  419. package/src/migration/migrator.ts +68 -41
  420. package/src/migration/postgresql-schema-reader.ts +52 -47
  421. package/src/migration/slack-confirm.ts +17 -15
  422. package/src/naite/naite-reporter.ts +1 -1
  423. package/src/naite/naite.ts +97 -24
  424. package/src/runtime-type.ts +34 -0
  425. package/src/ssr/hmr-opt-out.ts +78 -0
  426. package/src/ssr/renderer.ts +6 -0
  427. package/src/storage/base-file.ts +13 -13
  428. package/src/storage/buffered-file.ts +11 -11
  429. package/src/storage/s3-driver.ts +4 -1
  430. package/src/storage/uploaded-file.ts +8 -8
  431. package/src/stream/__tests__/ws-contracts.test.ts +4 -2
  432. package/src/stream/__tests__/ws-telemetry.test.ts +1 -1
  433. package/src/stream/__tests__/ws.test.ts +30 -6
  434. package/src/stream/sse.ts +12 -11
  435. package/src/stream/ws-core.ts +1 -1
  436. package/src/stream/ws-delivery.ts +16 -7
  437. package/src/stream/ws-local-connection-store.ts +2 -3
  438. package/src/stream/ws-presence-store.ts +6 -1
  439. package/src/stream/ws-registry.ts +16 -7
  440. package/src/stream/ws-telemetry.ts +66 -43
  441. package/src/stream/ws.ts +73 -39
  442. package/src/syncer/__tests__/api-parser.websocket-type-ref.test.ts +3 -2
  443. package/src/syncer/__tests__/http-validator-registry.test.ts +137 -0
  444. package/src/syncer/api-parser.ts +67 -27
  445. package/src/syncer/checksum.ts +17 -11
  446. package/src/syncer/code-generator.ts +25 -17
  447. package/src/syncer/entity-operations.ts +3 -5
  448. package/src/syncer/file-copy.ts +46 -0
  449. package/src/syncer/file-patterns.ts +11 -8
  450. package/src/syncer/file-tracking.ts +3 -4
  451. package/src/syncer/filesystem-dependencies.ts +73 -0
  452. package/src/syncer/module-loader.ts +8 -4
  453. package/src/syncer/syncer-actions.ts +56 -18
  454. package/src/syncer/syncer.ts +116 -43
  455. package/src/syncer/watcher.ts +8 -4
  456. package/src/tasks/decorator.ts +20 -12
  457. package/src/tasks/step-wrapper.ts +19 -9
  458. package/src/tasks/workflow-manager.ts +15 -9
  459. package/src/template/__tests__/http_validators.template.test.ts +160 -0
  460. package/src/template/__tests__/services.template.mutation.test.ts +24 -23
  461. package/src/template/__tests__/services.template.websocket.test.ts +21 -25
  462. package/src/template/entity-converter.ts +5 -2
  463. package/src/template/helpers.ts +8 -9
  464. package/src/template/implementations/generated.template.ts +5 -4
  465. package/src/template/implementations/generated_http.template.ts +61 -15
  466. package/src/template/implementations/generated_sso.template.ts +15 -4
  467. package/src/template/implementations/http_validators.template.ts +175 -0
  468. package/src/template/implementations/model.template.ts +3 -1
  469. package/src/template/implementations/sd.template.ts +81 -41
  470. package/src/template/implementations/services.template.ts +2 -2
  471. package/src/template/implementations/view_form.template.ts +56 -39
  472. package/src/template/implementations/view_list.template.ts +31 -23
  473. package/src/template/template-manager.ts +15 -13
  474. package/src/template/template-types.ts +13 -5
  475. package/src/template/template.ts +4 -3
  476. package/src/template/zod-converter.ts +206 -91
  477. package/src/testing/__tests__/dev-test-routes.test.ts +85 -25
  478. package/src/testing/__tests__/dev-vitest-manager.test.ts +15 -15
  479. package/src/testing/_relation-graph.ts +4 -1
  480. package/src/testing/bootstrap.ts +12 -5
  481. package/src/testing/data-explorer.ts +102 -53
  482. package/src/testing/dev-test-routes.ts +87 -50
  483. package/src/testing/dev-vitest-manager.ts +88 -32
  484. package/src/testing/faker-mappings.ts +2 -2
  485. package/src/testing/filesystem.ts +1 -0
  486. package/src/testing/fixture-generator.ts +191 -131
  487. package/src/testing/fixture-loader.ts +5 -1
  488. package/src/testing/fixture-manager.ts +129 -90
  489. package/src/testing/global-setup.ts +7 -3
  490. package/src/testing/index.ts +5 -0
  491. package/src/types/__tests__/entity-json-schema-search-text.test.ts +9 -3
  492. package/src/types/types.ts +184 -158
  493. package/src/ui/ai-api.ts +9 -7
  494. package/src/ui/ai-client.ts +61 -56
  495. package/src/ui/api.ts +727 -616
  496. package/src/ui/async-route.ts +4 -0
  497. package/src/ui/cdd-service.ts +35 -12
  498. package/src/ui/migrations-api.ts +63 -51
  499. package/src/utils/formatter.ts +7 -3
  500. package/src/utils/fs-utils.ts +5 -5
  501. package/src/utils/model.ts +4 -5
  502. package/src/utils/object-utils.ts +32 -22
  503. package/src/utils/process-utils.ts +4 -1
  504. package/src/utils/runtime-value.ts +43 -0
  505. package/src/utils/sql-parser.ts +13 -6
  506. package/src/utils/type-utils.ts +9 -7
  507. package/src/utils/utils.ts +19 -21
  508. package/src/utils/zod-error.ts +4 -2
  509. package/src/vector/chunking.ts +6 -1
  510. package/src/vector/embedding.ts +2 -1
  511. package/src/vector/types.ts +4 -2
  512. package/tsdown.api.config.ts +5 -2
  513. package/dist/ui-web/assets/index-C0m1pk6K.js +0 -177
@@ -1,7 +1,32 @@
1
1
  import SqlParser from "node-sql-parser";
2
2
 
3
+ import { isBooleanValue } from "../runtime-type";
4
+ import { isNumberValue, isObjectValue, isStringValue } from "../utils/runtime-value";
5
+
3
6
  const INDEX_WHERE_SQL_PARSER = new SqlParser.Parser();
4
7
 
8
+ type SqlAstValue = null | undefined | boolean | number | string | SqlAstValue[] | SqlAstRecord;
9
+ interface SqlAstRecord {
10
+ [key: string]: SqlAstValue;
11
+ }
12
+
13
+ function parseSqlAstValue<Value>(value: Value): SqlAstValue {
14
+ if (value === null) return null;
15
+ if (value === undefined) return undefined;
16
+ if (isBooleanValue(value)) return value;
17
+ if (isNumberValue(value)) return value;
18
+ if (isStringValue(value)) return value;
19
+ if (Array.isArray(value)) {
20
+ return value.map(parseSqlAstValue);
21
+ }
22
+ if (isObjectValue(value)) {
23
+ return Object.fromEntries(
24
+ Object.entries(value).map(([key, child]) => [key, parseSqlAstValue(child)]),
25
+ );
26
+ }
27
+ throw new Error("지원하지 않는 SQL AST 값입니다");
28
+ }
29
+
5
30
  /**
6
31
  * Migration DDL 출력에 사용할 index predicate를 정리한다.
7
32
  * 원본 SQL 표현은 보존하고, 빈 문자열과 전체를 감싼 괄호만 제거한다.
@@ -56,9 +81,11 @@ function removeOuterSqlParentheses(source: string): string {
56
81
  function normalizeIndexWherePredicateByAst(where: string): string | undefined {
57
82
  try {
58
83
  // node-sql-parser는 raw predicate를 직접 파싱하지 않으므로 임시 SELECT WHERE로 감싼다.
59
- const parsed = INDEX_WHERE_SQL_PARSER.astify(
60
- `SELECT * FROM __sonamu_index_predicate_source WHERE ${where}`,
61
- { database: "postgresql" },
84
+ const parsed = parseSqlAstValue(
85
+ INDEX_WHERE_SQL_PARSER.astify(
86
+ `SELECT * FROM __sonamu_index_predicate_source WHERE ${where}`,
87
+ { database: "postgresql" },
88
+ ),
62
89
  );
63
90
  const statement = Array.isArray(parsed) ? parsed[0] : parsed;
64
91
  if (!isSqlAstRecord(statement)) {
@@ -71,7 +98,7 @@ function normalizeIndexWherePredicateByAst(where: string): string | undefined {
71
98
  }
72
99
  }
73
100
 
74
- function serializeIndexWhereAst(node: unknown): string {
101
+ function serializeIndexWhereAst(node: SqlAstValue): string {
75
102
  // PostgreSQL이 IN을 ANY(ARRAY[...])로 재작성하므로 membership은 먼저 특수 처리한다.
76
103
  const membership = serializeSqlMembershipPredicate(node);
77
104
  if (membership) {
@@ -139,7 +166,7 @@ function serializeIndexWhereAst(node: unknown): string {
139
166
  }
140
167
  }
141
168
 
142
- function serializeSqlMembershipPredicate(node: unknown): string | undefined {
169
+ function serializeSqlMembershipPredicate(node: SqlAstValue): string | undefined {
143
170
  if (!isSqlAstRecord(node) || getSqlAstString(node, "type") !== "binary_expr") {
144
171
  return undefined;
145
172
  }
@@ -166,7 +193,7 @@ function serializeSqlMembershipPredicate(node: unknown): string | undefined {
166
193
  return `membership:${left}:in:[${values.join(",")}]`;
167
194
  }
168
195
 
169
- function serializeSqlMembershipValues(values: unknown[] | undefined): string[] | undefined {
196
+ function serializeSqlMembershipValues(values: SqlAstValue[] | undefined): string[] | undefined {
170
197
  if (!values) {
171
198
  return undefined;
172
199
  }
@@ -176,7 +203,7 @@ function serializeSqlMembershipValues(values: unknown[] | undefined): string[] |
176
203
  return [...new Set(serialized)].toSorted();
177
204
  }
178
205
 
179
- function getSqlAnyArrayElements(node: unknown): unknown[] | undefined {
206
+ function getSqlAnyArrayElements(node: SqlAstValue): SqlAstValue[] | undefined {
180
207
  if (!isSqlAstRecord(node) || getSqlAstString(node, "type") !== "function") {
181
208
  return undefined;
182
209
  }
@@ -193,7 +220,7 @@ function getSqlAnyArrayElements(node: unknown): unknown[] | undefined {
193
220
  return serializeSqlArrayElements(stripTextLikeSqlCast(arg));
194
221
  }
195
222
 
196
- function serializeSqlArrayElements(node: unknown): unknown[] {
223
+ function serializeSqlArrayElements(node: SqlAstValue): SqlAstValue[] {
197
224
  if (!isSqlAstRecord(node)) {
198
225
  return [];
199
226
  }
@@ -206,7 +233,7 @@ function serializeSqlArrayElements(node: unknown): unknown[] {
206
233
  return serializeSqlExprList(node);
207
234
  }
208
235
 
209
- function serializeSqlExprList(node: unknown): unknown[] {
236
+ function serializeSqlExprList(node: SqlAstValue): SqlAstValue[] {
210
237
  if (!isSqlAstRecord(node)) {
211
238
  return [];
212
239
  }
@@ -219,7 +246,7 @@ function serializeSqlExprList(node: unknown): unknown[] {
219
246
  return [node];
220
247
  }
221
248
 
222
- function stripTextLikeSqlCast(node: unknown): unknown {
249
+ function stripTextLikeSqlCast(node: SqlAstValue): SqlAstValue {
223
250
  if (!isSqlAstRecord(node) || getSqlAstString(node, "type") !== "cast") {
224
251
  return node;
225
252
  }
@@ -233,13 +260,13 @@ function stripTextLikeSqlCast(node: unknown): unknown {
233
260
  return stripTextLikeSqlCast(node.expr);
234
261
  }
235
262
 
236
- function isSqlStringLiteralLike(node: unknown): boolean {
263
+ function isSqlStringLiteralLike(node: SqlAstValue): boolean {
237
264
  // 문자열 literal에 붙은 text 계열 cast는 membership 비교에서 의미가 같다.
238
265
  const stripped = stripTextLikeSqlCast(node);
239
266
  return isSqlAstRecord(stripped) && getSqlAstString(stripped, "type") === "single_quote_string";
240
267
  }
241
268
 
242
- function getSqlCastTargetType(node: Record<string, unknown>): string | undefined {
269
+ function getSqlCastTargetType(node: SqlAstRecord): string | undefined {
243
270
  if (!Array.isArray(node.target)) {
244
271
  return undefined;
245
272
  }
@@ -270,24 +297,24 @@ function normalizeSqlDataType(type: string): string {
270
297
  .replace(/^character varying$/, "varchar");
271
298
  }
272
299
 
273
- function serializeSqlColumnRef(node: Record<string, unknown>): string {
300
+ function serializeSqlColumnRef(node: SqlAstRecord): string {
274
301
  const table = serializeSqlIdentifierNode(node.table);
275
302
  const column = serializeSqlIdentifierNode(node.column);
276
303
  return `column:${table ? `${table}.` : ""}${column}`;
277
304
  }
278
305
 
279
- function serializeSqlIdentifierNode(node: unknown): string {
280
- if (typeof node === "string") {
306
+ function serializeSqlIdentifierNode(node: SqlAstValue): string {
307
+ if (isStringValue(node)) {
281
308
  return normalizeSqlIdentifier(node);
282
309
  }
283
310
 
284
311
  // quoted identifier와 function name의 AST shape 차이를 같은 identifier 문자열로 흡수한다.
285
312
  if (isSqlAstRecord(node)) {
286
- if (typeof node.value === "string") {
313
+ if (isStringValue(node.value)) {
287
314
  return normalizeSqlIdentifier(node.value);
288
315
  }
289
316
 
290
- if (isSqlAstRecord(node.expr) && typeof node.expr.value === "string") {
317
+ if (isSqlAstRecord(node.expr) && isStringValue(node.expr.value)) {
291
318
  return normalizeSqlIdentifier(node.expr.value);
292
319
  }
293
320
  }
@@ -295,9 +322,9 @@ function serializeSqlIdentifierNode(node: unknown): string {
295
322
  return "";
296
323
  }
297
324
 
298
- function getSqlFunctionName(node: Record<string, unknown>): string {
325
+ function getSqlFunctionName(node: SqlAstRecord): string {
299
326
  const name = node.name;
300
- if (typeof name === "string") {
327
+ if (isStringValue(name)) {
301
328
  return normalizeSqlIdentifier(name);
302
329
  }
303
330
 
@@ -324,7 +351,7 @@ function normalizeSqlOperator(operator: string | undefined): string {
324
351
  return (operator ?? "").trim().toUpperCase().replace(/\s+/g, " ");
325
352
  }
326
353
 
327
- function serializeUnknownSqlAstRecord(node: Record<string, unknown>): string {
354
+ function serializeUnknownSqlAstRecord(node: SqlAstRecord): string {
328
355
  // 아직 명시적으로 다루지 않는 AST 노드는 key 정렬로 최소한 안정적인 비교값을 만든다.
329
356
  const entries = Object.entries(node)
330
357
  .filter(([key]) => key !== "parentheses")
@@ -334,13 +361,13 @@ function serializeUnknownSqlAstRecord(node: Record<string, unknown>): string {
334
361
  return `record:{${entries.join(",")}}`;
335
362
  }
336
363
 
337
- function isSqlAstRecord(value: unknown): value is Record<string, unknown> {
338
- return typeof value === "object" && value !== null && !Array.isArray(value);
364
+ function isSqlAstRecord(value: SqlAstValue): value is SqlAstRecord {
365
+ return isObjectValue(value) && value !== null && !Array.isArray(value);
339
366
  }
340
367
 
341
- function getSqlAstString(node: Record<string, unknown>, key: string): string | undefined {
368
+ function getSqlAstString(node: SqlAstRecord, key: string): string | undefined {
342
369
  const value = node[key];
343
- return typeof value === "string" ? value : undefined;
370
+ return isStringValue(value) ? value : undefined;
344
371
  }
345
372
 
346
373
  function findMatchingParenthesisInSql(source: string, openIndex: number): number {
@@ -199,10 +199,14 @@ export function getMigrationSetFromEntity(entity: Entity): MigrationSetAndJoinTa
199
199
  },
200
200
  {
201
201
  table: entity.table,
202
- columns: [] as MigrationColumn[],
203
- indexes: [] as MigrationIndex[],
204
- foreigns: [] as MigrationForeign[],
205
- joinTables: [] as MigrationJoinTable[],
202
+ columns:
203
+ /* SAFETY: Knex와 PostgreSQL 스키마 조회 계약이 이 값의 타입을 보장한다. */ [] as MigrationColumn[],
204
+ indexes:
205
+ /* SAFETY: Knex와 PostgreSQL 스키마 조회 계약이 이 값의 타입을 보장한다. */ [] as MigrationIndex[],
206
+ foreigns:
207
+ /* SAFETY: Knex와 PostgreSQL 스키마 조회 계약이 이 값의 타입을 보장한다. */ [] as MigrationForeign[],
208
+ joinTables:
209
+ /* SAFETY: Knex와 PostgreSQL 스키마 조회 계약이 이 값의 타입을 보장한다. */ [] as MigrationJoinTable[],
206
210
  },
207
211
  );
208
212
 
@@ -268,6 +272,8 @@ function resolveEntityPropTypeToMigrationColumnType(prop: EntityProp): Migration
268
272
  return "tsvector";
269
273
  default:
270
274
  exhaustive(prop);
271
- throw new Error(`Unknown entity prop type: ${(prop as { type: string }).type}`);
275
+ throw new Error(
276
+ `Unknown entity prop type: ${/* SAFETY: Knex와 PostgreSQL 스키마 조회 계약이 이 값의 타입을 보장한다. */ (prop as { type: string }).type}`,
277
+ );
272
278
  }
273
279
  }
@@ -18,6 +18,7 @@ import { Naite } from "../naite/naite";
18
18
  import { type GenMigrationCode, type MigrationSet } from "../types/types";
19
19
  import { isLocal, isTest } from "../utils/controller";
20
20
  import { exists } from "../utils/fs-utils";
21
+ import { isObjectValue, isStringValue } from "../utils/runtime-value";
21
22
  import { generateAlterCode, generateCreateCode } from "./code-generation";
22
23
  import { getMigrationSetFromEntity } from "./migration-set";
23
24
  import { PostgreSQLSchemaReader } from "./postgresql-schema-reader";
@@ -40,12 +41,16 @@ export type MigrationResult = {
40
41
  applied: string[];
41
42
  }[];
42
43
 
44
+ function padDatePart(number: number, size: number = 2): string {
45
+ return number.toString().padStart(size, "0");
46
+ }
47
+
43
48
  export class MigrationTargetExecutionError extends Error {
44
49
  constructor(
45
50
  public readonly connKey: MigrationTarget | "shadow",
46
- caught: unknown,
51
+ cause: unknown,
47
52
  ) {
48
- super(caught instanceof Error ? caught.message : String(caught));
53
+ super(cause instanceof Error ? cause.message : String(cause));
49
54
  this.name = "MigrationTargetExecutionError";
50
55
  }
51
56
  }
@@ -82,23 +87,29 @@ function withTimeout<T>(promise: Promise<T>, ms: number, onTimeout: () => Error)
82
87
  * CLI 리팩토링 시점에서 제거해주셔도 무방합니다.
83
88
  */
84
89
  export class Migrator {
85
- private isMissingMigrationTableError(error: unknown): boolean {
86
- if (typeof error !== "object" || error === null) {
90
+ private isMissingMigrationTableError<Value>(error: Value): boolean {
91
+ if (!isObjectValue(error) || error === null) {
87
92
  return false;
88
93
  }
89
94
 
90
- const maybePostgresError = error as { code?: unknown; message?: unknown };
95
+ const maybePostgresError =
96
+ /* SAFETY: Knex와 PostgreSQL 스키마 조회 계약이 이 값의 타입을 보장한다. */ error as {
97
+ code?: unknown;
98
+ message?: unknown;
99
+ };
91
100
  return (
92
101
  maybePostgresError.code === "42P01" &&
93
- typeof maybePostgresError.message === "string" &&
102
+ isStringValue(maybePostgresError.message) &&
94
103
  maybePostgresError.message.includes("knex_migrations")
95
104
  );
96
105
  }
97
106
 
98
- private getMigrationTargetKeys(): MigrationTarget[] {
99
- const connKeys = Object.keys(Sonamu.dbConfig).filter(
100
- (key) => !key.endsWith("_readonly"),
101
- ) as (keyof SonamuDBConfig)[];
107
+ /** 현재 실행 환경에서 허용된 마이그레이션 대상 키를 반환합니다. */
108
+ getMigrationTargetKeys(): MigrationTarget[] {
109
+ const connKeys =
110
+ /* SAFETY: Knex와 PostgreSQL 스키마 조회 계약이 이 값의 타입을 보장한다. */ Object.keys(
111
+ Sonamu.dbConfig,
112
+ ).filter((key) => !key.endsWith("_readonly")) as (keyof SonamuDBConfig)[];
102
113
 
103
114
  if (isLocal()) {
104
115
  return connKeys;
@@ -146,16 +157,20 @@ export class Migrator {
146
157
  return results;
147
158
  }
148
159
 
149
- private migrationName(migration: unknown): string {
150
- if (typeof migration === "string") {
160
+ private migrationName<Value>(migration: Value): string {
161
+ if (isStringValue(migration)) {
151
162
  return path.basename(migration);
152
163
  }
153
- if (typeof migration === "object" && migration !== null) {
154
- const candidate = migration as { file?: unknown; name?: unknown };
155
- if (typeof candidate.file === "string") {
164
+ if (isObjectValue(migration) && migration !== null) {
165
+ const candidate =
166
+ /* SAFETY: Knex와 PostgreSQL 스키마 조회 계약이 이 값의 타입을 보장한다. */ migration as {
167
+ file?: unknown;
168
+ name?: unknown;
169
+ };
170
+ if (isStringValue(candidate.file)) {
156
171
  return path.basename(candidate.file);
157
172
  }
158
- if (typeof candidate.name === "string") {
173
+ if (isStringValue(candidate.name)) {
159
174
  return path.basename(candidate.name);
160
175
  }
161
176
  }
@@ -177,7 +192,7 @@ export class Migrator {
177
192
  options?: MigrationRunOptions,
178
193
  ): Knex.MigratorConfigWithLifecycleHooks {
179
194
  let files: string[] = [];
180
- const emitFile = (type: "file-start" | "file-executed", migration: unknown) => {
195
+ const emitFile = <Value>(type: "file-start" | "file-executed", migration: Value) => {
181
196
  const file = this.migrationName(migration);
182
197
  const index = Math.max(files.indexOf(file), 0);
183
198
  this.emitProgress(options, {
@@ -221,7 +236,10 @@ export class Migrator {
221
236
  getConnections(): MigrationConnectionMeta[] {
222
237
  const slackConfirm = new SlackConfirm();
223
238
  return this.getMigrationTargetKeys().map((connKey) => {
224
- const connection = Sonamu.dbConfig[connKey].connection as Knex.PgConnectionConfig;
239
+ const connection =
240
+ /* SAFETY: Knex와 PostgreSQL 스키마 조회 계약이 이 값의 타입을 보장한다. */ Sonamu.dbConfig[
241
+ connKey
242
+ ].connection as Knex.PgConnectionConfig;
225
243
  const host = connection.host ?? "localhost";
226
244
  return {
227
245
  connKey,
@@ -272,11 +290,13 @@ export class Migrator {
272
290
  const startedAt = performance.now();
273
291
  const codes = await this.getMigrationCodes();
274
292
  const knexOptions = Sonamu.dbConfig[connKey];
275
- const connection = knexOptions.connection as Knex.PgConnectionConfig;
293
+ const connection =
294
+ /* SAFETY: Knex와 PostgreSQL 스키마 조회 계약이 이 값의 타입을 보장한다. */ knexOptions.connection as Knex.PgConnectionConfig;
295
+ // SAFETY: Knex가 제공한 PostgreSQL 연결 구성을 복사해 timeout 필드만 덮어쓴다.
276
296
  const tConn = createKnexInstance({
277
297
  ...knexOptions,
278
298
  connection: {
279
- ...(connection as Record<string, unknown>),
299
+ ...connection,
280
300
  connectionTimeoutMillis: MIGRATION_CONN_TIMEOUT_MS,
281
301
  },
282
302
  pool: {
@@ -306,32 +326,33 @@ export class Migrator {
306
326
  const pending: string[] = await tConn.migrate.list().then(
307
327
  ([, files]: [unknown[], { file: string }[]]) =>
308
328
  files.map(({ file }) => file.replace(/\.ts$/, "")),
309
- (caught: unknown) => {
310
- if (this.isMissingMigrationTableError(caught)) {
329
+ (cause: unknown) => {
330
+ if (this.isMissingMigrationTableError(cause)) {
311
331
  return codes.map(({ name }) => name);
312
332
  }
313
- error ??= caught instanceof Error ? caught.message : String(caught);
333
+ error ??= cause instanceof Error ? cause.message : String(cause);
314
334
  return [];
315
335
  },
316
336
  );
317
337
  const currentVersion: string | "none" | "error" = await tConn.migrate
318
338
  .currentVersion()
319
- .catch((caught: unknown) => {
320
- if (this.isMissingMigrationTableError(caught)) {
339
+ .catch((cause: unknown) => {
340
+ if (this.isMissingMigrationTableError(cause)) {
321
341
  return "none" as const;
322
342
  }
323
- error ??= caught instanceof Error ? caught.message : String(caught);
343
+ error ??= cause instanceof Error ? cause.message : String(cause);
324
344
  return "error" as const;
325
345
  });
326
346
  Naite.t("migrator:getStatus:status", status);
327
- return {
347
+ const connectionStatus: MigrationConnectionStatus = {
328
348
  connKey,
329
349
  currentVersion,
330
350
  status,
331
351
  pending,
332
352
  latencyMs: performance.now() - startedAt,
333
- ...(error === undefined ? {} : { error }),
334
353
  };
354
+ if (error !== undefined) connectionStatus.error = error;
355
+ return connectionStatus;
335
356
  } catch (caught) {
336
357
  const error = caught instanceof Error ? caught.message : String(caught);
337
358
  console.warn(
@@ -397,12 +418,15 @@ export class Migrator {
397
418
  const conns = connections.map((connection, index) => {
398
419
  const status = connectionStatuses[index];
399
420
  assert(status !== undefined);
400
- const configured = Sonamu.dbConfig[connection.connKey].connection as Knex.PgConnectionConfig;
421
+ const configured =
422
+ /* SAFETY: Knex와 PostgreSQL 스키마 조회 계약이 이 값의 타입을 보장한다. */ Sonamu.dbConfig[
423
+ connection.connKey
424
+ ].connection as Knex.PgConnectionConfig;
401
425
  return {
402
426
  name: connection.name,
403
427
  connKey: connection.connKey,
404
428
  connString:
405
- `pg://${configured.user ?? ""}@${configured.host}:${configured.port}/${configured.database}` as ConnString,
429
+ /* SAFETY: Knex와 PostgreSQL 스키마 조회 계약이 이 값의 타입을 보장한다. */ `pg://${configured.user ?? ""}@${configured.host}:${configured.port}/${configured.database}` as ConnString,
406
430
  currentVersion: status.currentVersion,
407
431
  status: status.status,
408
432
  pending: status.pending,
@@ -484,10 +508,12 @@ export class Migrator {
484
508
  options: Sonamu.dbConfig[target],
485
509
  }))
486
510
  .filter((c) => c.options !== undefined),
487
- ({ options }) =>
488
- `${(options.connection as Knex.PgConnectionConfig).host}:${
489
- (options.connection as Knex.PgConnectionConfig).port ?? 5432
490
- }/${(options.connection as Knex.PgConnectionConfig).database}`,
511
+ ({ options: dbOptions }) =>
512
+ `${/* SAFETY: Knex와 PostgreSQL 스키마 조회 계약이 이 값의 타입을 보장한다. */ (dbOptions.connection as Knex.PgConnectionConfig).host}:${
513
+ /* SAFETY: Knex와 PostgreSQL 스키마 조회 계약이 이 값의 타입을 보장한다. */ (
514
+ dbOptions.connection as Knex.PgConnectionConfig
515
+ ).port ?? 5432
516
+ }/${/* SAFETY: Knex와 PostgreSQL 스키마 조회 계약이 이 값의 타입을 보장한다. */ (dbOptions.connection as Knex.PgConnectionConfig).database}`,
491
517
  );
492
518
 
493
519
  // get connections
@@ -515,14 +541,13 @@ export class Migrator {
515
541
 
516
542
  private genDateTag(index: number, baseDate: Date = new Date()): string {
517
543
  const date = new Date(baseDate.getTime() + index * 1000);
518
- const pad = (num: number, size: number = 2) => num.toString().padStart(size, "0");
519
544
  return (
520
545
  date.getFullYear().toString() +
521
- pad(date.getMonth() + 1) +
522
- pad(date.getDate()) +
523
- pad(date.getHours()) +
524
- pad(date.getMinutes()) +
525
- pad(date.getSeconds())
546
+ padDatePart(date.getMonth() + 1) +
547
+ padDatePart(date.getDate()) +
548
+ padDatePart(date.getHours()) +
549
+ padDatePart(date.getMinutes()) +
550
+ padDatePart(date.getSeconds())
526
551
  );
527
552
  }
528
553
 
@@ -635,7 +660,9 @@ export class Migrator {
635
660
  * @category 분리형 마이그레이션 API
636
661
  */
637
662
  async runShadowTest(options?: MigrationRunOptions): Promise<MigrationResult> {
638
- const baseTestConn = Sonamu.dbConfig.test.connection as Knex.PgConnectionConfig;
663
+ const baseTestConn =
664
+ /* SAFETY: Knex와 PostgreSQL 스키마 조회 계약이 이 값의 타입을 보장한다. */ Sonamu.dbConfig
665
+ .test.connection as Knex.PgConnectionConfig;
639
666
  const workerId = process.env.SONAMU_WORKER_DB === "true" ? process.env.VITEST_POOL_ID : null;
640
667
  const templateDatabase =
641
668
  workerId !== null ? `${baseTestConn.database}_${workerId ?? "1"}` : baseTestConn.database;
@@ -164,7 +164,8 @@ class PostgreSQLSchemaReaderClass {
164
164
  );
165
165
 
166
166
  // indexes 처리
167
- const indexes: MigrationIndex[] = Object.keys(dbIndexesGroup).map((indexName) => {
167
+ const indexes: MigrationIndex[] = [];
168
+ for (const indexName of Object.keys(dbIndexesGroup)) {
168
169
  const currentIndexes = dbIndexesGroup[indexName]?.toSorted(
169
170
  (left, right) => left.column_order - right.column_order,
170
171
  );
@@ -180,34 +181,42 @@ class PostgreSQLSchemaReaderClass {
180
181
  parsedIndexDefinition.accessMethod ?? firstIndex.index_type,
181
182
  );
182
183
 
183
- return {
184
+ const indexColumns: MigrationIndex["columns"] = [];
185
+ for (const currentIndex of currentIndexes) {
186
+ const opclass = this.extractIndexColumnOpclass(
187
+ parsedIndexDefinition.columnDefinitions[currentIndex.column_order - 1],
188
+ );
189
+ const column: MigrationIndex["columns"][number] = {
190
+ name: currentIndex.column_name,
191
+ };
192
+ if (opclass) {
193
+ Object.assign(column, { opclass });
194
+ }
195
+ switch (using) {
196
+ case "btree":
197
+ Object.assign(column, {
198
+ sortOrder: currentIndex.sort_order,
199
+ nullsFirst: currentIndex.nulls_first,
200
+ });
201
+ break;
202
+ }
203
+ indexColumns.push(column);
204
+ }
205
+ const index: MigrationIndex = {
184
206
  type: restoredIndexType,
185
207
  name: indexName,
186
- columns: currentIndexes.map((idx) => ({
187
- name: idx.column_name,
188
- ...(this.extractIndexColumnOpclass(
189
- parsedIndexDefinition.columnDefinitions[idx.column_order - 1],
190
- )
191
- ? {
192
- opclass: this.extractIndexColumnOpclass(
193
- parsedIndexDefinition.columnDefinitions[idx.column_order - 1],
194
- ),
195
- }
196
- : {}),
197
- ...(using === "btree"
198
- ? {
199
- sortOrder: idx.sort_order,
200
- nullsFirst: idx.nulls_first,
201
- }
202
- : {}),
203
- })),
204
-
208
+ columns: indexColumns,
205
209
  nullsNotDistinct: firstIndex.nulls_not_distinct,
206
- ...(firstIndex.predicate ? { where: firstIndex.predicate } : {}),
207
- ...(using ? { using } : {}),
208
210
  ...this.parseVectorIndexOptions(restoredIndexType, parsedIndexDefinition.withOptions),
209
211
  };
210
- });
212
+ if (firstIndex.predicate) {
213
+ index.where = firstIndex.predicate;
214
+ }
215
+ if (using) {
216
+ index.using = using;
217
+ }
218
+ indexes.push(index);
219
+ }
211
220
 
212
221
  // foreigns 처리
213
222
  const foreigns: MigrationForeign[] = dbForeigns.map((dbForeign) => {
@@ -231,14 +240,14 @@ class PostgreSQLSchemaReaderClass {
231
240
  * PostgreSQL의 constraint action을 Knex 형식으로 변환
232
241
  */
233
242
  private mapConstraintAction(action: string): RelationOn {
234
- const actionMap: Record<string, RelationOn> = {
235
- "NO ACTION": "NO ACTION",
236
- RESTRICT: "RESTRICT",
237
- CASCADE: "CASCADE",
238
- "SET NULL": "SET NULL",
239
- "SET DEFAULT": "SET DEFAULT",
240
- };
241
- return actionMap[action] ?? "NO ACTION";
243
+ const actionMap = new Map<string, RelationOn>([
244
+ ["NO ACTION", "NO ACTION"],
245
+ ["RESTRICT", "RESTRICT"],
246
+ ["CASCADE", "CASCADE"],
247
+ ["SET NULL", "SET NULL"],
248
+ ["SET DEFAULT", "SET DEFAULT"],
249
+ ]);
250
+ return actionMap.get(action) ?? "NO ACTION";
242
251
  }
243
252
 
244
253
  /**
@@ -277,7 +286,9 @@ class PostgreSQLSchemaReaderClass {
277
286
  AND c.table_schema = 'public'
278
287
  ORDER BY c.ordinal_position
279
288
  `;
280
- const columns = (await compareDB.raw(columnsQuery, [tableName])).rows as PgColumn[];
289
+ const columns = /* SAFETY: Knex와 PostgreSQL 스키마 조회 계약이 이 값의 타입을 보장한다. */ (
290
+ await compareDB.raw(columnsQuery, [tableName])
291
+ ).rows as PgColumn[];
281
292
  if (columns.length === 0) {
282
293
  throw new Error(`Table not found: ${tableName}`);
283
294
  }
@@ -398,7 +409,7 @@ class PostgreSQLSchemaReaderClass {
398
409
  return undefined;
399
410
  }
400
411
 
401
- return normalized as MigrationIndex["using"];
412
+ return /* SAFETY: Knex와 PostgreSQL 스키마 조회 계약이 이 값의 타입을 보장한다. */ normalized as MigrationIndex["using"];
402
413
  }
403
414
 
404
415
  private parseVectorIndexOptions(
@@ -406,14 +417,12 @@ class PostgreSQLSchemaReaderClass {
406
417
  withOptions: Record<string, string>,
407
418
  ): Pick<MigrationIndex, "m" | "efConstruction" | "lists"> {
408
419
  if (type === "hnsw") {
409
- return {
410
- ...(this.parseIntegerOption(withOptions.m) !== undefined
411
- ? { m: this.parseIntegerOption(withOptions.m) }
412
- : {}),
413
- ...(this.parseIntegerOption(withOptions.ef_construction) !== undefined
414
- ? { efConstruction: this.parseIntegerOption(withOptions.ef_construction) }
415
- : {}),
416
- };
420
+ const options: Pick<MigrationIndex, "m" | "efConstruction"> = {};
421
+ const m = this.parseIntegerOption(withOptions.m);
422
+ const efConstruction = this.parseIntegerOption(withOptions.ef_construction);
423
+ if (m !== undefined) options.m = m;
424
+ if (efConstruction !== undefined) options.efConstruction = efConstruction;
425
+ return options;
417
426
  }
418
427
 
419
428
  if (type === "ivfflat") {
@@ -456,11 +465,7 @@ class PostgreSQLSchemaReaderClass {
456
465
  return tokens.at(-1);
457
466
  }
458
467
 
459
- private parseIndexDefinition(indexDefinition: string): {
460
- accessMethod?: string;
461
- columnDefinitions: string[];
462
- withOptions: Record<string, string>;
463
- } {
468
+ private parseIndexDefinition(indexDefinition: string) {
464
469
  const accessMethod = indexDefinition.match(/\bUSING\s+([a-z_][\w]*)/i)?.[1]?.toLowerCase();
465
470
  const usingMatchIndex = indexDefinition.search(/\bUSING\b/i);
466
471
  const columnsStart = usingMatchIndex >= 0 ? indexDefinition.indexOf("(", usingMatchIndex) : -1;
@@ -138,12 +138,13 @@ export class SlackConfirm {
138
138
  throw new Error(`Slack API HTTP error: ${response.status}`);
139
139
  }
140
140
 
141
- const data = (await response.json()) as {
142
- ok: boolean;
143
- error?: string;
144
- channel: string;
145
- ts: string;
146
- };
141
+ const data =
142
+ /* SAFETY: Knex와 PostgreSQL 스키마 조회 계약이 이 값의 타입을 보장한다. */ (await response.json()) as {
143
+ ok: boolean;
144
+ error?: string;
145
+ channel: string;
146
+ ts: string;
147
+ };
147
148
  if (!data.ok) {
148
149
  throw new Error(`Slack API error: ${data.error}`);
149
150
  }
@@ -202,16 +203,17 @@ ${migrationsText}`;
202
203
  throw new Error(`Slack API HTTP error: ${response.status}`);
203
204
  }
204
205
 
205
- const data = (await response.json()) as {
206
- ok: boolean;
207
- error?: string;
208
- message?: {
209
- reactions?: Array<{
210
- name: string;
211
- users?: string[];
212
- }>;
206
+ const data =
207
+ /* SAFETY: Knex와 PostgreSQL 스키마 조회 계약이 이 값의 타입을 보장한다. */ (await response.json()) as {
208
+ ok: boolean;
209
+ error?: string;
210
+ message?: {
211
+ reactions?: Array<{
212
+ name: string;
213
+ users?: string[];
214
+ }>;
215
+ };
213
216
  };
214
- };
215
217
  if (!data.ok) {
216
218
  throw new Error(`Slack API error: ${data.error}`);
217
219
  }
@@ -103,7 +103,7 @@ class NaiteReporterClass {
103
103
  private async send(data: NaiteMessagingTypes.NaiteMessage): Promise<void> {
104
104
  const msg = `${JSON.stringify(data)}\n`;
105
105
 
106
- await this.ensureConnection().catch((_) => {});
106
+ await this.ensureConnection().catch(() => {});
107
107
 
108
108
  if (this.connected && this.socket) {
109
109
  this.socket.write(msg);