sonamu 0.10.11 → 0.10.13

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (519) hide show
  1. package/dist/ai/agents/agent.d.ts +1 -1
  2. package/dist/ai/agents/agent.d.ts.map +1 -1
  3. package/dist/ai/agents/agent.js +5 -6
  4. package/dist/ai/agents/types.d.ts +1 -1
  5. package/dist/ai/agents/types.d.ts.map +1 -1
  6. package/dist/ai/providers/rtzr/api.js +18 -18
  7. package/dist/ai/providers/rtzr/error.d.ts.map +1 -1
  8. package/dist/ai/providers/rtzr/error.js +17 -15
  9. package/dist/ai/providers/rtzr/model.d.ts.map +1 -1
  10. package/dist/ai/providers/rtzr/model.js +3 -2
  11. package/dist/ai/providers/rtzr/options.d.ts.map +1 -1
  12. package/dist/ai/providers/rtzr/options.js +16 -16
  13. package/dist/ai/providers/rtzr/provider.d.ts.map +1 -1
  14. package/dist/ai/providers/rtzr/provider.js +9 -9
  15. package/dist/ai/providers/rtzr/utils.d.ts.map +1 -1
  16. package/dist/ai/providers/rtzr/utils.js +1 -1
  17. package/dist/api/caster.d.ts.map +1 -1
  18. package/dist/api/caster.js +17 -17
  19. package/dist/api/code-converters.d.ts +4 -2
  20. package/dist/api/code-converters.d.ts.map +1 -1
  21. package/dist/api/code-converters.js +100 -19
  22. package/dist/api/config.d.ts +16 -1
  23. package/dist/api/config.d.ts.map +1 -1
  24. package/dist/api/config.js +28 -21
  25. package/dist/api/context.d.ts +2 -2
  26. package/dist/api/context.d.ts.map +1 -1
  27. package/dist/api/context.js +1 -1
  28. package/dist/api/decorators.d.ts.map +1 -1
  29. package/dist/api/decorators.js +18 -11
  30. package/dist/api/http-validator.d.ts +36 -0
  31. package/dist/api/http-validator.d.ts.map +1 -0
  32. package/dist/api/http-validator.js +72 -0
  33. package/dist/api/index.js +6 -4
  34. package/dist/api/sonamu.d.ts +59 -20
  35. package/dist/api/sonamu.d.ts.map +1 -1
  36. package/dist/api/sonamu.js +250 -106
  37. package/dist/api/websocket-helpers.d.ts +7 -5
  38. package/dist/api/websocket-helpers.d.ts.map +1 -1
  39. package/dist/api/websocket-helpers.js +6 -6
  40. package/dist/auth/audit-log/builders.d.ts.map +1 -1
  41. package/dist/auth/audit-log/builders.js +1 -1
  42. package/dist/auth/audit-log/client-ip.d.ts +1 -1
  43. package/dist/auth/audit-log/client-ip.d.ts.map +1 -1
  44. package/dist/auth/audit-log/client-ip.js +4 -2
  45. package/dist/auth/audit-log/events.d.ts +5 -1
  46. package/dist/auth/audit-log/events.d.ts.map +1 -1
  47. package/dist/auth/audit-log/events.js +1 -1
  48. package/dist/auth/audit-log/plugin.d.ts +0 -8
  49. package/dist/auth/audit-log/plugin.d.ts.map +1 -1
  50. package/dist/auth/audit-log/plugin.js +48 -52
  51. package/dist/auth/audit-log-ingestor.d.ts.map +1 -1
  52. package/dist/auth/audit-log-ingestor.js +16 -12
  53. package/dist/auth/auth-generator.d.ts.map +1 -1
  54. package/dist/auth/auth-generator.js +1 -1
  55. package/dist/auth/better-auth-request.d.ts.map +1 -1
  56. package/dist/auth/better-auth-request.js +6 -5
  57. package/dist/auth/knex-adapter.js +1 -1
  58. package/dist/auth/plugins/entity-definitions/index.d.ts +13 -1
  59. package/dist/auth/plugins/entity-definitions/index.d.ts.map +1 -1
  60. package/dist/auth/plugins/entity-definitions/index.js +1 -1
  61. package/dist/auth/plugins/wrappers/admin.d.ts +1 -1
  62. package/dist/bin/build-config.d.ts +25 -0
  63. package/dist/bin/build-config.d.ts.map +1 -1
  64. package/dist/bin/build-config.js +105 -2
  65. package/dist/bin/cli.js +133 -29
  66. package/dist/bin/compiler-policy.d.ts +3 -0
  67. package/dist/bin/compiler-policy.d.ts.map +1 -0
  68. package/dist/bin/compiler-policy.js +24 -0
  69. package/dist/bin/fixture.d.ts.map +1 -1
  70. package/dist/bin/fixture.js +5 -3
  71. package/dist/bin/test-command.d.ts +22 -1
  72. package/dist/bin/test-command.d.ts.map +1 -1
  73. package/dist/bin/test-command.js +18 -10
  74. package/dist/bin/ts-loader-registration.d.ts +7 -1
  75. package/dist/bin/ts-loader-registration.d.ts.map +1 -1
  76. package/dist/bin/ts-loader-registration.js +13 -4
  77. package/dist/cache/decorator.d.ts.map +1 -1
  78. package/dist/cache/decorator.js +11 -4
  79. package/dist/compress/compress.d.ts.map +1 -1
  80. package/dist/compress/compress.js +1 -1
  81. package/dist/cone/cone-generator.d.ts +14 -1
  82. package/dist/cone/cone-generator.d.ts.map +1 -1
  83. package/dist/cone/cone-generator.js +13 -9
  84. package/dist/database/_batch_update.js +1 -1
  85. package/dist/database/base-model.d.ts +22 -10
  86. package/dist/database/base-model.d.ts.map +1 -1
  87. package/dist/database/base-model.js +26 -16
  88. package/dist/database/base-model.types.d.ts +15 -3
  89. package/dist/database/base-model.types.d.ts.map +1 -1
  90. package/dist/database/db.d.ts +12 -2
  91. package/dist/database/db.d.ts.map +1 -1
  92. package/dist/database/db.js +10 -7
  93. package/dist/database/knex.d.ts.map +1 -1
  94. package/dist/database/knex.js +17 -14
  95. package/dist/database/puri.d.ts +11 -9
  96. package/dist/database/puri.d.ts.map +1 -1
  97. package/dist/database/puri.js +93 -79
  98. package/dist/database/puri.types.d.ts +21 -21
  99. package/dist/database/puri.types.d.ts.map +1 -1
  100. package/dist/database/puri.types.js +1 -1
  101. package/dist/database/upsert-builder.d.ts +12 -10
  102. package/dist/database/upsert-builder.d.ts.map +1 -1
  103. package/dist/database/upsert-builder.js +20 -12
  104. package/dist/dict/sd.d.ts.map +1 -1
  105. package/dist/dict/sd.js +1 -1
  106. package/dist/dict/sonamu-dictionary.d.ts.map +1 -1
  107. package/dist/dict/sonamu-dictionary.js +1 -1
  108. package/dist/dict/utils.d.ts.map +1 -1
  109. package/dist/dict/utils.js +7 -2
  110. package/dist/entity/entity-manager.d.ts +13 -4
  111. package/dist/entity/entity-manager.d.ts.map +1 -1
  112. package/dist/entity/entity-manager.js +19 -11
  113. package/dist/entity/entity-template-cone.d.ts +73 -5
  114. package/dist/entity/entity-template-cone.d.ts.map +1 -1
  115. package/dist/entity/entity-template-cone.js +4 -2
  116. package/dist/entity/entity.d.ts +6 -2
  117. package/dist/entity/entity.d.ts.map +1 -1
  118. package/dist/entity/entity.js +30 -28
  119. package/dist/env.d.ts +3 -1
  120. package/dist/env.d.ts.map +1 -1
  121. package/dist/env.js +1 -1
  122. package/dist/exceptions/error-handler.d.ts.map +1 -1
  123. package/dist/exceptions/error-handler.js +7 -2
  124. package/dist/exceptions/so-exceptions.d.ts +24 -20
  125. package/dist/exceptions/so-exceptions.d.ts.map +1 -1
  126. package/dist/exceptions/so-exceptions.js +4 -2
  127. package/dist/filter/utils.d.ts +7 -2
  128. package/dist/filter/utils.d.ts.map +1 -1
  129. package/dist/filter/utils.js +8 -6
  130. package/dist/index.d.ts +3 -0
  131. package/dist/index.d.ts.map +1 -1
  132. package/dist/index.js +13 -7
  133. package/dist/logger/configure.d.ts.map +1 -1
  134. package/dist/logger/configure.js +10 -10
  135. package/dist/migration/code-generation.d.ts.map +1 -1
  136. package/dist/migration/code-generation.js +50 -46
  137. package/dist/migration/index-where-predicate.d.ts.map +1 -1
  138. package/dist/migration/index-where-predicate.js +22 -8
  139. package/dist/migration/migration-set.d.ts.map +1 -1
  140. package/dist/migration/migration-set.js +1 -1
  141. package/dist/migration/migrator.d.ts +61 -36
  142. package/dist/migration/migrator.d.ts.map +1 -1
  143. package/dist/migration/migrator.js +276 -167
  144. package/dist/migration/postgresql-schema-reader.d.ts.map +1 -1
  145. package/dist/migration/postgresql-schema-reader.js +51 -36
  146. package/dist/migration/slack-confirm.d.ts.map +1 -1
  147. package/dist/migration/slack-confirm.js +1 -1
  148. package/dist/migration/types.d.ts +54 -0
  149. package/dist/migration/types.d.ts.map +1 -1
  150. package/dist/naite/naite-reporter.js +2 -2
  151. package/dist/naite/naite.d.ts +74 -15
  152. package/dist/naite/naite.d.ts.map +1 -1
  153. package/dist/naite/naite.js +5 -19
  154. package/dist/runtime-type.d.ts +6 -0
  155. package/dist/runtime-type.d.ts.map +1 -0
  156. package/dist/runtime-type.js +26 -0
  157. package/dist/ssr/hmr-opt-out.d.ts +26 -0
  158. package/dist/ssr/hmr-opt-out.d.ts.map +1 -0
  159. package/dist/ssr/hmr-opt-out.js +59 -0
  160. package/dist/ssr/renderer.d.ts.map +1 -1
  161. package/dist/ssr/renderer.js +4 -1
  162. package/dist/storage/base-file.js +14 -14
  163. package/dist/storage/buffered-file.d.ts +2 -2
  164. package/dist/storage/buffered-file.d.ts.map +1 -1
  165. package/dist/storage/buffered-file.js +12 -12
  166. package/dist/storage/s3-driver.d.ts.map +1 -1
  167. package/dist/storage/s3-driver.js +1 -1
  168. package/dist/storage/uploaded-file.d.ts +2 -2
  169. package/dist/storage/uploaded-file.d.ts.map +1 -1
  170. package/dist/storage/uploaded-file.js +8 -8
  171. package/dist/stream/sse.js +11 -11
  172. package/dist/stream/ws-core.d.ts +1 -1
  173. package/dist/stream/ws-core.d.ts.map +1 -1
  174. package/dist/stream/ws-delivery.d.ts +1 -1
  175. package/dist/stream/ws-delivery.d.ts.map +1 -1
  176. package/dist/stream/ws-delivery.js +6 -4
  177. package/dist/stream/ws-local-connection-store.d.ts.map +1 -1
  178. package/dist/stream/ws-local-connection-store.js +4 -2
  179. package/dist/stream/ws-presence-store.js +1 -1
  180. package/dist/stream/ws-registry.d.ts +4 -4
  181. package/dist/stream/ws-registry.d.ts.map +1 -1
  182. package/dist/stream/ws-registry.js +4 -2
  183. package/dist/stream/ws-telemetry.d.ts +16 -12
  184. package/dist/stream/ws-telemetry.d.ts.map +1 -1
  185. package/dist/stream/ws-telemetry.js +22 -18
  186. package/dist/stream/ws.d.ts +18 -12
  187. package/dist/stream/ws.d.ts.map +1 -1
  188. package/dist/stream/ws.js +26 -22
  189. package/dist/syncer/api-parser.js +1 -1
  190. package/dist/syncer/checksum.d.ts.map +1 -1
  191. package/dist/syncer/checksum.js +7 -8
  192. package/dist/syncer/code-generator.d.ts.map +1 -1
  193. package/dist/syncer/code-generator.js +13 -14
  194. package/dist/syncer/entity-operations.d.ts.map +1 -1
  195. package/dist/syncer/entity-operations.js +5 -6
  196. package/dist/syncer/file-copy.d.ts +5 -0
  197. package/dist/syncer/file-copy.d.ts.map +1 -0
  198. package/dist/syncer/file-copy.js +36 -0
  199. package/dist/syncer/file-patterns.d.ts +1 -0
  200. package/dist/syncer/file-patterns.d.ts.map +1 -1
  201. package/dist/syncer/file-patterns.js +5 -2
  202. package/dist/syncer/file-tracking.d.ts.map +1 -1
  203. package/dist/syncer/file-tracking.js +5 -4
  204. package/dist/syncer/filesystem-dependencies.d.ts +15 -0
  205. package/dist/syncer/filesystem-dependencies.d.ts.map +1 -0
  206. package/dist/syncer/filesystem-dependencies.js +53 -0
  207. package/dist/syncer/module-loader.d.ts +1 -1
  208. package/dist/syncer/module-loader.d.ts.map +1 -1
  209. package/dist/syncer/module-loader.js +6 -4
  210. package/dist/syncer/syncer-actions.d.ts +4 -0
  211. package/dist/syncer/syncer-actions.d.ts.map +1 -1
  212. package/dist/syncer/syncer-actions.js +34 -17
  213. package/dist/syncer/syncer.d.ts +17 -6
  214. package/dist/syncer/syncer.d.ts.map +1 -1
  215. package/dist/syncer/syncer.js +71 -29
  216. package/dist/syncer/watcher.d.ts.map +1 -1
  217. package/dist/syncer/watcher.js +3 -3
  218. package/dist/tasks/decorator.d.ts +6 -6
  219. package/dist/tasks/decorator.d.ts.map +1 -1
  220. package/dist/tasks/decorator.js +4 -4
  221. package/dist/tasks/step-wrapper.d.ts +6 -4
  222. package/dist/tasks/step-wrapper.d.ts.map +1 -1
  223. package/dist/tasks/step-wrapper.js +5 -5
  224. package/dist/tasks/workflow-manager.d.ts.map +1 -1
  225. package/dist/tasks/workflow-manager.js +13 -7
  226. package/dist/template/entity-converter.d.ts +1 -1
  227. package/dist/template/entity-converter.d.ts.map +1 -1
  228. package/dist/template/entity-converter.js +2 -2
  229. package/dist/template/helpers.d.ts +8 -6
  230. package/dist/template/helpers.d.ts.map +1 -1
  231. package/dist/template/helpers.js +1 -1
  232. package/dist/template/implementations/generated.template.d.ts.map +1 -1
  233. package/dist/template/implementations/generated.template.js +4 -4
  234. package/dist/template/implementations/generated_http.template.d.ts +7 -4
  235. package/dist/template/implementations/generated_http.template.d.ts.map +1 -1
  236. package/dist/template/implementations/generated_http.template.js +21 -21
  237. package/dist/template/implementations/generated_sso.template.d.ts.map +1 -1
  238. package/dist/template/implementations/generated_sso.template.js +6 -3
  239. package/dist/template/implementations/http_validators.template.d.ts +18 -0
  240. package/dist/template/implementations/http_validators.template.d.ts.map +1 -0
  241. package/dist/template/implementations/http_validators.template.js +127 -0
  242. package/dist/template/implementations/model.template.d.ts.map +1 -1
  243. package/dist/template/implementations/model.template.js +1 -1
  244. package/dist/template/implementations/queries.template.js +1 -1
  245. package/dist/template/implementations/sd.template.d.ts.map +1 -1
  246. package/dist/template/implementations/sd.template.js +79 -39
  247. package/dist/template/implementations/services.template.d.ts.map +1 -1
  248. package/dist/template/implementations/services.template.js +6 -4
  249. package/dist/template/implementations/view_form.template.d.ts +6 -1
  250. package/dist/template/implementations/view_form.template.d.ts.map +1 -1
  251. package/dist/template/implementations/view_form.template.js +23 -15
  252. package/dist/template/implementations/view_list.template.d.ts.map +1 -1
  253. package/dist/template/implementations/view_list.template.js +11 -6
  254. package/dist/template/template-manager.d.ts.map +1 -1
  255. package/dist/template/template-manager.js +9 -7
  256. package/dist/template/template-types.d.ts +12 -5
  257. package/dist/template/template-types.d.ts.map +1 -1
  258. package/dist/template/template-types.js +1 -1
  259. package/dist/template/template.d.ts +2 -2
  260. package/dist/template/template.d.ts.map +1 -1
  261. package/dist/template/template.js +6 -4
  262. package/dist/template/zod-converter.d.ts +0 -19
  263. package/dist/template/zod-converter.d.ts.map +1 -1
  264. package/dist/template/zod-converter.js +100 -84
  265. package/dist/testing/_relation-graph.d.ts.map +1 -1
  266. package/dist/testing/_relation-graph.js +2 -1
  267. package/dist/testing/bootstrap.d.ts.map +1 -1
  268. package/dist/testing/bootstrap.js +9 -6
  269. package/dist/testing/data-explorer.d.ts +32 -7
  270. package/dist/testing/data-explorer.d.ts.map +1 -1
  271. package/dist/testing/data-explorer.js +77 -31
  272. package/dist/testing/dev-test-routes.d.ts +8 -1
  273. package/dist/testing/dev-test-routes.d.ts.map +1 -1
  274. package/dist/testing/dev-test-routes.js +125 -108
  275. package/dist/testing/dev-vitest-manager.d.ts +54 -8
  276. package/dist/testing/dev-vitest-manager.d.ts.map +1 -1
  277. package/dist/testing/dev-vitest-manager.js +24 -9
  278. package/dist/testing/faker-mappings.d.ts +412 -1
  279. package/dist/testing/faker-mappings.d.ts.map +1 -1
  280. package/dist/testing/faker-mappings.js +1 -1
  281. package/dist/testing/filesystem.d.ts +2 -0
  282. package/dist/testing/filesystem.d.ts.map +1 -0
  283. package/dist/testing/filesystem.js +7 -0
  284. package/dist/testing/fixture-generator.d.ts +25 -8
  285. package/dist/testing/fixture-generator.d.ts.map +1 -1
  286. package/dist/testing/fixture-generator.js +132 -73
  287. package/dist/testing/fixture-loader.d.ts +3 -1
  288. package/dist/testing/fixture-loader.d.ts.map +1 -1
  289. package/dist/testing/fixture-loader.js +1 -20
  290. package/dist/testing/fixture-manager.d.ts +8 -7
  291. package/dist/testing/fixture-manager.d.ts.map +1 -1
  292. package/dist/testing/fixture-manager.js +91 -59
  293. package/dist/testing/global-setup.d.ts.map +1 -1
  294. package/dist/testing/global-setup.js +5 -2
  295. package/dist/testing/index.d.ts +2 -0
  296. package/dist/testing/index.d.ts.map +1 -1
  297. package/dist/testing/index.js +6 -3
  298. package/dist/types/types.d.ts +101 -99
  299. package/dist/types/types.d.ts.map +1 -1
  300. package/dist/types/types.js +234 -225
  301. package/dist/ui/ai-api.d.ts.map +1 -1
  302. package/dist/ui/ai-api.js +1 -1
  303. package/dist/ui/ai-client.d.ts.map +1 -1
  304. package/dist/ui/ai-client.js +28 -18
  305. package/dist/ui/api.d.ts.map +1 -1
  306. package/dist/ui/api.js +146 -210
  307. package/dist/ui/async-route.d.ts +3 -0
  308. package/dist/ui/async-route.d.ts.map +1 -0
  309. package/dist/ui/async-route.js +12 -0
  310. package/dist/ui/cdd-service.d.ts +9 -7
  311. package/dist/ui/cdd-service.d.ts.map +1 -1
  312. package/dist/ui/cdd-service.js +7 -5
  313. package/dist/ui/migrations-api.d.ts +3 -0
  314. package/dist/ui/migrations-api.d.ts.map +1 -0
  315. package/dist/ui/migrations-api.js +215 -0
  316. package/dist/ui-web/assets/index-D3QNH-Dv.css +1 -0
  317. package/dist/ui-web/assets/index-DV1AAq6W.js +178 -0
  318. package/dist/ui-web/index.html +2 -2
  319. package/dist/utils/formatter.d.ts.map +1 -1
  320. package/dist/utils/formatter.js +7 -5
  321. package/dist/utils/fs-utils.d.ts +3 -3
  322. package/dist/utils/fs-utils.d.ts.map +1 -1
  323. package/dist/utils/fs-utils.js +6 -6
  324. package/dist/utils/model.d.ts +3 -5
  325. package/dist/utils/model.d.ts.map +1 -1
  326. package/dist/utils/model.js +1 -1
  327. package/dist/utils/object-utils.d.ts +1 -1
  328. package/dist/utils/object-utils.d.ts.map +1 -1
  329. package/dist/utils/object-utils.js +17 -16
  330. package/dist/utils/process-utils.d.ts.map +1 -1
  331. package/dist/utils/process-utils.js +4 -2
  332. package/dist/utils/runtime-value.d.ts +13 -0
  333. package/dist/utils/runtime-value.d.ts.map +1 -0
  334. package/dist/utils/runtime-value.js +40 -0
  335. package/dist/utils/sql-parser.d.ts +8 -1
  336. package/dist/utils/sql-parser.d.ts.map +1 -1
  337. package/dist/utils/sql-parser.js +6 -3
  338. package/dist/utils/type-utils.d.ts.map +1 -1
  339. package/dist/utils/type-utils.js +10 -8
  340. package/dist/utils/utils.d.ts +2 -2
  341. package/dist/utils/utils.d.ts.map +1 -1
  342. package/dist/utils/utils.js +11 -8
  343. package/dist/utils/zod-error.d.ts.map +1 -1
  344. package/dist/utils/zod-error.js +7 -4
  345. package/dist/vector/chunking.d.ts.map +1 -1
  346. package/dist/vector/chunking.js +1 -1
  347. package/dist/vector/embedding.d.ts.map +1 -1
  348. package/dist/vector/embedding.js +1 -1
  349. package/dist/vector/types.d.ts +3 -2
  350. package/dist/vector/types.d.ts.map +1 -1
  351. package/package.json +11 -7
  352. package/src/ai/agents/agent.ts +5 -5
  353. package/src/ai/agents/types.ts +1 -1
  354. package/src/ai/providers/rtzr/__tests__/model.test.ts +2 -2
  355. package/src/ai/providers/rtzr/error.ts +5 -3
  356. package/src/ai/providers/rtzr/model.ts +3 -2
  357. package/src/ai/providers/rtzr/options.ts +10 -5
  358. package/src/ai/providers/rtzr/provider.ts +10 -10
  359. package/src/ai/providers/rtzr/utils.ts +3 -1
  360. package/src/api/__tests__/config.test.ts +11 -21
  361. package/src/api/__tests__/sonamu.http-validator.test.ts +512 -0
  362. package/src/api/__tests__/sonamu.websocket.test.ts +51 -41
  363. package/src/api/__tests__/zod-compiler-policy.test.ts +95 -0
  364. package/src/api/caster.ts +6 -8
  365. package/src/api/code-converters.ts +136 -36
  366. package/src/api/config.ts +62 -4
  367. package/src/api/context.ts +3 -3
  368. package/src/api/decorators.ts +28 -17
  369. package/src/api/http-validator.ts +149 -0
  370. package/src/api/sonamu.ts +459 -152
  371. package/src/api/websocket-helpers.ts +24 -17
  372. package/src/auth/audit-log/builders.ts +3 -2
  373. package/src/auth/audit-log/client-ip.ts +4 -2
  374. package/src/auth/audit-log/events.ts +15 -1
  375. package/src/auth/audit-log/plugin.ts +129 -200
  376. package/src/auth/audit-log-ingestor.ts +19 -15
  377. package/src/auth/auth-generator.ts +10 -5
  378. package/src/auth/better-auth-request.ts +4 -3
  379. package/src/auth/knex-adapter.ts +8 -2
  380. package/src/auth/plugins/entity-definitions/index.ts +6 -5
  381. package/src/bin/__tests__/http-validator-benchmark.test.ts +94 -0
  382. package/src/bin/__tests__/test-command.test.ts +9 -15
  383. package/src/bin/__tests__/ts-loader-register.test.ts +15 -17
  384. package/src/bin/__tests__/zod-compiler-build.test.ts +307 -0
  385. package/src/bin/build-config.ts +167 -0
  386. package/src/bin/cli.ts +155 -38
  387. package/src/bin/compiler-policy.ts +35 -0
  388. package/src/bin/fixture.ts +14 -3
  389. package/src/bin/test-command.ts +74 -29
  390. package/src/bin/ts-loader-registration.ts +22 -4
  391. package/src/cache/decorator.ts +10 -3
  392. package/src/compress/compress.ts +17 -4
  393. package/src/cone/cone-generator.ts +34 -6
  394. package/src/database/__tests__/db.test.ts +1 -0
  395. package/src/database/__tests__/puri.test.ts +16 -15
  396. package/src/database/__tests__/transaction-scope.test.ts +5 -0
  397. package/src/database/_batch_update.ts +1 -0
  398. package/src/database/base-model.ts +81 -50
  399. package/src/database/base-model.types.ts +6 -6
  400. package/src/database/db.ts +29 -19
  401. package/src/database/knex.ts +30 -17
  402. package/src/database/puri-subset.test-d.ts +17 -0
  403. package/src/database/puri.ts +181 -143
  404. package/src/database/puri.types.test-d.ts +31 -1
  405. package/src/database/puri.types.ts +23 -21
  406. package/src/database/upsert-builder.ts +75 -53
  407. package/src/dict/sd.ts +15 -5
  408. package/src/dict/sonamu-dictionary.ts +6 -6
  409. package/src/dict/utils.ts +9 -1
  410. package/src/entity/entity-manager.ts +26 -9
  411. package/src/entity/entity-template-cone.ts +5 -10
  412. package/src/entity/entity.ts +50 -34
  413. package/src/env.ts +7 -3
  414. package/src/exceptions/error-handler.ts +17 -2
  415. package/src/exceptions/so-exceptions.ts +26 -20
  416. package/src/filter/utils.ts +21 -11
  417. package/src/index.ts +3 -0
  418. package/src/logger/configure.ts +26 -18
  419. package/src/migration/__tests__/migrator.test.ts +50 -57
  420. package/src/migration/code-generation.ts +132 -104
  421. package/src/migration/index-where-predicate.ts +51 -24
  422. package/src/migration/migration-set.ts +11 -5
  423. package/src/migration/migrator.ts +392 -244
  424. package/src/migration/postgresql-schema-reader.ts +52 -47
  425. package/src/migration/slack-confirm.ts +17 -15
  426. package/src/migration/types.ts +57 -0
  427. package/src/naite/naite-reporter.ts +1 -1
  428. package/src/naite/naite.ts +97 -24
  429. package/src/runtime-type.ts +34 -0
  430. package/src/ssr/hmr-opt-out.ts +78 -0
  431. package/src/ssr/renderer.ts +6 -0
  432. package/src/storage/base-file.ts +13 -13
  433. package/src/storage/buffered-file.ts +11 -11
  434. package/src/storage/s3-driver.ts +4 -1
  435. package/src/storage/uploaded-file.ts +8 -8
  436. package/src/stream/__tests__/ws-contracts.test.ts +4 -2
  437. package/src/stream/__tests__/ws-telemetry.test.ts +1 -1
  438. package/src/stream/__tests__/ws.test.ts +30 -6
  439. package/src/stream/sse.ts +12 -11
  440. package/src/stream/ws-core.ts +1 -1
  441. package/src/stream/ws-delivery.ts +16 -7
  442. package/src/stream/ws-local-connection-store.ts +2 -3
  443. package/src/stream/ws-presence-store.ts +6 -1
  444. package/src/stream/ws-registry.ts +16 -7
  445. package/src/stream/ws-telemetry.ts +66 -43
  446. package/src/stream/ws.ts +73 -39
  447. package/src/syncer/__tests__/api-parser.websocket-type-ref.test.ts +3 -2
  448. package/src/syncer/__tests__/http-validator-registry.test.ts +137 -0
  449. package/src/syncer/api-parser.ts +67 -27
  450. package/src/syncer/checksum.ts +17 -11
  451. package/src/syncer/code-generator.ts +25 -17
  452. package/src/syncer/entity-operations.ts +3 -5
  453. package/src/syncer/file-copy.ts +46 -0
  454. package/src/syncer/file-patterns.ts +11 -8
  455. package/src/syncer/file-tracking.ts +3 -4
  456. package/src/syncer/filesystem-dependencies.ts +73 -0
  457. package/src/syncer/module-loader.ts +8 -4
  458. package/src/syncer/syncer-actions.ts +56 -18
  459. package/src/syncer/syncer.ts +116 -43
  460. package/src/syncer/watcher.ts +8 -4
  461. package/src/tasks/decorator.ts +20 -12
  462. package/src/tasks/step-wrapper.ts +19 -9
  463. package/src/tasks/workflow-manager.ts +15 -9
  464. package/src/template/__tests__/http_validators.template.test.ts +160 -0
  465. package/src/template/__tests__/services.template.mutation.test.ts +24 -23
  466. package/src/template/__tests__/services.template.websocket.test.ts +21 -25
  467. package/src/template/entity-converter.ts +5 -2
  468. package/src/template/helpers.ts +8 -9
  469. package/src/template/implementations/generated.template.ts +5 -4
  470. package/src/template/implementations/generated_http.template.ts +61 -15
  471. package/src/template/implementations/generated_sso.template.ts +15 -4
  472. package/src/template/implementations/http_validators.template.ts +175 -0
  473. package/src/template/implementations/model.template.ts +3 -1
  474. package/src/template/implementations/sd.template.ts +81 -41
  475. package/src/template/implementations/services.template.ts +2 -2
  476. package/src/template/implementations/view_form.template.ts +56 -39
  477. package/src/template/implementations/view_list.template.ts +31 -23
  478. package/src/template/template-manager.ts +15 -13
  479. package/src/template/template-types.ts +13 -5
  480. package/src/template/template.ts +4 -3
  481. package/src/template/zod-converter.ts +206 -91
  482. package/src/testing/__tests__/dev-test-routes.test.ts +85 -25
  483. package/src/testing/__tests__/dev-vitest-manager.test.ts +15 -15
  484. package/src/testing/_relation-graph.ts +4 -1
  485. package/src/testing/bootstrap.ts +12 -5
  486. package/src/testing/data-explorer.ts +102 -53
  487. package/src/testing/dev-test-routes.ts +87 -50
  488. package/src/testing/dev-vitest-manager.ts +88 -32
  489. package/src/testing/faker-mappings.ts +2 -2
  490. package/src/testing/filesystem.ts +1 -0
  491. package/src/testing/fixture-generator.ts +191 -131
  492. package/src/testing/fixture-loader.ts +5 -1
  493. package/src/testing/fixture-manager.ts +129 -90
  494. package/src/testing/global-setup.ts +7 -3
  495. package/src/testing/index.ts +5 -0
  496. package/src/types/__tests__/entity-json-schema-search-text.test.ts +9 -3
  497. package/src/types/types.ts +184 -158
  498. package/src/ui/ai-api.ts +9 -7
  499. package/src/ui/ai-client.ts +61 -56
  500. package/src/ui/api.ts +726 -770
  501. package/src/ui/async-route.ts +4 -0
  502. package/src/ui/cdd-service.ts +35 -12
  503. package/src/ui/migrations-api.ts +381 -0
  504. package/src/utils/formatter.ts +7 -3
  505. package/src/utils/fs-utils.ts +5 -5
  506. package/src/utils/model.ts +4 -5
  507. package/src/utils/object-utils.ts +32 -22
  508. package/src/utils/process-utils.ts +4 -1
  509. package/src/utils/runtime-value.ts +43 -0
  510. package/src/utils/sql-parser.ts +13 -6
  511. package/src/utils/type-utils.ts +9 -7
  512. package/src/utils/utils.ts +19 -21
  513. package/src/utils/zod-error.ts +4 -2
  514. package/src/vector/chunking.ts +6 -1
  515. package/src/vector/embedding.ts +2 -1
  516. package/src/vector/types.ts +4 -2
  517. package/tsdown.api.config.ts +5 -2
  518. package/dist/ui-web/assets/index-CJf8uJYf.js +0 -176
  519. package/dist/ui-web/assets/index-GMMIVGja.css +0 -1
@@ -0,0 +1,137 @@
1
+ import { access, mkdir, mkdtemp, rm, writeFile } from "node:fs/promises";
2
+ import os from "node:os";
3
+ import path from "node:path";
4
+
5
+ import { afterEach, describe, expect, it, vi } from "vitest";
6
+
7
+ import { type SonamuConfig } from "../../api/config";
8
+ import { Sonamu } from "../../api/sonamu";
9
+ import { type AbsolutePath } from "../../utils/path-utils";
10
+ import { Syncer, type SyncerDependencies } from "../syncer";
11
+ import { actionGenerateHttpValidators } from "../syncer-actions";
12
+
13
+ function toAbsolutePath(filePath: string): AbsolutePath {
14
+ if (!path.isAbsolute(filePath)) {
15
+ throw new Error(`절대 경로가 필요합니다: ${filePath}`);
16
+ }
17
+ // SAFETY: path.isAbsolute 검사로 AbsolutePath 계약을 확인했다.
18
+ return filePath as AbsolutePath;
19
+ }
20
+
21
+ function createDependencies() {
22
+ return {
23
+ actionCopySharedToTargetsIfNotExists: vi
24
+ .fn<SyncerDependencies["actionCopySharedToTargetsIfNotExists"]>()
25
+ .mockResolvedValue(undefined),
26
+ actionGenerateHttpValidators: vi.fn<SyncerDependencies["actionGenerateHttpValidators"]>(),
27
+ actionGenerateSsrEntryServerIfNotExists: vi
28
+ .fn<SyncerDependencies["actionGenerateSsrEntryServerIfNotExists"]>()
29
+ .mockResolvedValue([]),
30
+ findChangedFilesUsingChecksums: vi.fn<SyncerDependencies["findChangedFilesUsingChecksums"]>(),
31
+ renewChecksums: vi.fn<SyncerDependencies["renewChecksums"]>().mockResolvedValue(undefined),
32
+ } satisfies SyncerDependencies;
33
+ }
34
+
35
+ const testConfig = {
36
+ api: { dir: "api", route: { prefix: "/api" } },
37
+ i18n: { defaultLocale: "ko", supportedLocales: ["ko"] },
38
+ sync: { targets: [] },
39
+ database: {},
40
+ server: {
41
+ apiConfig: {
42
+ contextProvider: (defaultContext) => defaultContext,
43
+ guardHandler: () => undefined,
44
+ },
45
+ },
46
+ } satisfies SonamuConfig;
47
+
48
+ describe("HTTP validator registry sync 정리", () => {
49
+ const tempRoots: string[] = [];
50
+
51
+ afterEach(async () => {
52
+ vi.restoreAllMocks();
53
+ await Promise.all(
54
+ tempRoots.splice(0).map((rootPath) => rm(rootPath, { recursive: true, force: true })),
55
+ );
56
+ });
57
+
58
+ it.each([
59
+ { label: "opt-out", value: false as const },
60
+ { label: "JIT", value: { api: "jit" as const } },
61
+ ])("$label 정책은 남아 있는 generated registry를 제거한다", async ({ value }) => {
62
+ const apiRootPath = await mkdtemp(path.join(os.tmpdir(), "sonamu-registry-sync-test-"));
63
+ tempRoots.push(apiRootPath);
64
+ const registryPath = path.join(apiRootPath, "src/application/sonamu.validators.generated.ts");
65
+ await mkdir(path.dirname(registryPath), { recursive: true });
66
+ await writeFile(registryPath, "export const validators = new Map();\n");
67
+ Sonamu.apiRootPath = toAbsolutePath(apiRootPath);
68
+ Sonamu.config = {
69
+ ...testConfig,
70
+ api: { ...testConfig.api, dir: "." },
71
+ validation: { zodCompiler: value },
72
+ };
73
+
74
+ await actionGenerateHttpValidators();
75
+
76
+ await expect(access(registryPath)).rejects.toMatchObject({ code: "ENOENT" });
77
+ });
78
+
79
+ it("registry-only drift를 경고로 넘기지 않고 즉시 재생성한다", async () => {
80
+ const appRootPath = await mkdtemp(path.join(os.tmpdir(), "sonamu-registry-drift-test-"));
81
+ tempRoots.push(appRootPath);
82
+ const apiRootPath = path.join(appRootPath, "api");
83
+ const registryPath = toAbsolutePath(
84
+ path.join(apiRootPath, "src/application/sonamu.validators.generated.ts"),
85
+ );
86
+ await mkdir(path.dirname(registryPath), { recursive: true });
87
+ await writeFile(registryPath, "// drifted registry\n");
88
+ Sonamu.apiRootPath = toAbsolutePath(apiRootPath);
89
+ Sonamu.config = {
90
+ ...testConfig,
91
+ validation: { zodCompiler: { api: "aot" } },
92
+ };
93
+ const dependencies = createDependencies();
94
+ dependencies.actionGenerateHttpValidators.mockResolvedValue(registryPath);
95
+ dependencies.findChangedFilesUsingChecksums.mockResolvedValue([registryPath]);
96
+ vi.spyOn(console, "warn").mockImplementation(() => {});
97
+
98
+ await new Syncer(dependencies).sync();
99
+
100
+ expect(dependencies.actionGenerateHttpValidators).toHaveBeenCalledTimes(1);
101
+ expect(dependencies.renewChecksums).toHaveBeenCalledTimes(1);
102
+ });
103
+
104
+ it("삭제된 registry가 checksum 변경 목록에서 빠져도 다른 tracked 변경 처리 중 복구한다", async () => {
105
+ const appRootPath = await mkdtemp(path.join(os.tmpdir(), "sonamu-missing-registry-test-"));
106
+ tempRoots.push(appRootPath);
107
+ const apiRootPath = path.join(appRootPath, "api");
108
+ const registryPath = toAbsolutePath(
109
+ path.join(apiRootPath, "src/application/sonamu.validators.generated.ts"),
110
+ );
111
+ const unrelatedPath = toAbsolutePath(
112
+ path.join(apiRootPath, "src/application/queries.generated.ts"),
113
+ );
114
+ await mkdir(path.dirname(unrelatedPath), { recursive: true });
115
+ await writeFile(unrelatedPath, "// unrelated tracked change\n");
116
+ Sonamu.apiRootPath = toAbsolutePath(apiRootPath);
117
+ Sonamu.config = {
118
+ ...testConfig,
119
+ validation: { zodCompiler: { api: "aot" } },
120
+ };
121
+ const order: string[] = [];
122
+ const dependencies = createDependencies();
123
+ dependencies.actionGenerateHttpValidators.mockImplementation(async () => {
124
+ order.push("registry");
125
+ return registryPath;
126
+ });
127
+ dependencies.findChangedFilesUsingChecksums.mockResolvedValue([unrelatedPath]);
128
+ dependencies.renewChecksums.mockImplementation(async () => {
129
+ order.push("checksum");
130
+ });
131
+ vi.spyOn(console, "warn").mockImplementation(() => {});
132
+
133
+ await new Syncer(dependencies).sync();
134
+
135
+ expect(order).toEqual(["registry", "checksum"]);
136
+ });
137
+ });
@@ -77,7 +77,7 @@ export async function readApisFromFile(filePath: AbsolutePath): Promise<Extended
77
77
  return resolveParamDec(
78
78
  {
79
79
  name: paramDec.name,
80
- type: paramDec.type as ts.TypeNode,
80
+ type: /* SAFETY: TypeScript AST 파싱과 동기화 입력 계약이 이 값의 타입을 보장한다. */ paramDec.type as ts.TypeNode,
81
81
  optional: paramDec.questionToken !== undefined || paramDec.initializer !== undefined,
82
82
  defaultDef,
83
83
  },
@@ -253,7 +253,10 @@ function resolveTypeNode(typeNode: ts.TypeNode): ApiParamType {
253
253
  case ts.SyntaxKind.VoidKeyword:
254
254
  return "void";
255
255
  case ts.SyntaxKind.LiteralType: {
256
- const literal = (typeNode as ts.LiteralTypeNode).literal;
256
+ const literal =
257
+ /* SAFETY: TypeScript AST 파싱과 동기화 입력 계약이 이 값의 타입을 보장한다. */ (
258
+ typeNode as ts.LiteralTypeNode
259
+ ).literal;
257
260
  if (ts.isStringLiteral(literal)) {
258
261
  return {
259
262
  t: "string-literal",
@@ -278,35 +281,46 @@ function resolveTypeNode(typeNode: ts.TypeNode): ApiParamType {
278
281
  }
279
282
  }
280
283
  case ts.SyntaxKind.ArrayType: {
281
- const arrNode = typeNode as ts.ArrayTypeNode;
284
+ const arrNode =
285
+ /* SAFETY: TypeScript AST 파싱과 동기화 입력 계약이 이 값의 타입을 보장한다. */ typeNode as ts.ArrayTypeNode;
282
286
  return {
283
287
  t: "array",
284
288
  elementsType: resolveTypeNode(arrNode.elementType),
285
289
  };
286
290
  }
287
291
  case ts.SyntaxKind.TypeLiteral: {
288
- const literalNode = typeNode as ts.TypeLiteralNode;
292
+ const literalNode =
293
+ /* SAFETY: TypeScript AST 파싱과 동기화 입력 계약이 이 값의 타입을 보장한다. */ typeNode as ts.TypeLiteralNode;
289
294
  return {
290
295
  t: "object",
291
296
  props: literalNode.members.map((member) => {
292
297
  if (ts.isIndexSignatureDeclaration(member)) {
293
298
  assert(member.parameters[0]);
294
299
  const res = resolveParamDec({
295
- name: member.parameters[0].name as ts.Identifier,
296
- type: member.parameters[0].type as ts.TypeNode,
300
+ name: /* SAFETY: TypeScript AST 파싱과 동기화 입력 계약이 이 값의 타입을 보장한다. */ member
301
+ .parameters[0].name as ts.Identifier,
302
+ type: /* SAFETY: TypeScript AST 파싱과 동기화 입력 계약이 이 값의 타입을 보장한다. */ member
303
+ .parameters[0].type as ts.TypeNode,
297
304
  });
298
305
 
299
306
  return resolveParamDec({
300
- name: {
307
+ name: /* SAFETY: TypeScript AST 파싱과 동기화 입력 계약이 이 값의 타입을 보장한다. */ {
301
308
  escapedText: `[${res.name}${res.optional ? "?" : ""}: ${res.type}]`,
302
309
  } as ts.Identifier,
303
310
  type: member.type,
304
311
  });
305
312
  } else {
306
313
  return resolveParamDec({
307
- name: (member as ts.PropertySignature).name as ts.Identifier,
308
- type: (member as ts.PropertySignature).type as ts.TypeNode,
309
- optional: (member as ts.PropertySignature).questionToken !== undefined,
314
+ name: /* SAFETY: TypeScript AST 파싱과 동기화 입력 계약이 이 값의 타입을 보장한다. */ /* SAFETY: TypeScript AST 파싱과 동기화 입력 계약이 이 값의 타입을 보장한다. */ (
315
+ member as ts.PropertySignature
316
+ ).name as ts.Identifier,
317
+ type: /* SAFETY: TypeScript AST 파싱과 동기화 입력 계약이 이 값의 타입을 보장한다. */ /* SAFETY: TypeScript AST 파싱과 동기화 입력 계약이 이 값의 타입을 보장한다. */ (
318
+ member as ts.PropertySignature
319
+ ).type as ts.TypeNode,
320
+ optional:
321
+ /* SAFETY: TypeScript AST 파싱과 동기화 입력 계약이 이 값의 타입을 보장한다. */ (
322
+ member as ts.PropertySignature
323
+ ).questionToken !== undefined,
310
324
  });
311
325
  }
312
326
  }),
@@ -315,26 +329,40 @@ function resolveTypeNode(typeNode: ts.TypeNode): ApiParamType {
315
329
  case ts.SyntaxKind.TypeReference:
316
330
  return {
317
331
  t: "ref",
318
- id: ((typeNode as ts.TypeReferenceNode).typeName as ts.Identifier).escapedText.toString(),
319
- args: (typeNode as ts.TypeReferenceNode).typeArguments?.map((typeArg) =>
320
- resolveTypeNode(typeArg),
321
- ),
332
+ id: /* SAFETY: TypeScript AST 파싱과 동기화 입력 계약이 이 값의 타입을 보장한다. */ /* SAFETY: TypeScript AST 파싱과 동기화 입력 계약이 이 값의 타입을 보장한다. */ (
333
+ (typeNode as ts.TypeReferenceNode).typeName as ts.Identifier
334
+ ).escapedText.toString(),
335
+ args: /* SAFETY: TypeScript AST 파싱과 동기화 입력 계약이 이 값의 타입을 보장한다. */ (
336
+ typeNode as ts.TypeReferenceNode
337
+ ).typeArguments?.map((typeArg) => resolveTypeNode(typeArg)),
322
338
  };
323
339
  case ts.SyntaxKind.UnionType:
324
340
  return {
325
341
  t: "union",
326
- types: (typeNode as ts.UnionTypeNode).types.map((type) => resolveTypeNode(type)),
342
+ types: /* SAFETY: TypeScript AST 파싱과 동기화 입력 계약이 이 값의 타입을 보장한다. */ (
343
+ typeNode as ts.UnionTypeNode
344
+ ).types.map((type) => resolveTypeNode(type)),
327
345
  };
328
346
  case ts.SyntaxKind.IntersectionType:
329
347
  return {
330
348
  t: "intersection",
331
- types: (typeNode as ts.IntersectionTypeNode).types.map((type) => resolveTypeNode(type)),
349
+ types: /* SAFETY: TypeScript AST 파싱과 동기화 입력 계약이 이 값의 타입을 보장한다. */ (
350
+ typeNode as ts.IntersectionTypeNode
351
+ ).types.map((type) => resolveTypeNode(type)),
332
352
  };
333
353
  case ts.SyntaxKind.IndexedAccessType:
334
354
  return {
335
355
  t: "indexed-access",
336
- object: resolveTypeNode((typeNode as ts.IndexedAccessTypeNode).objectType),
337
- index: resolveTypeNode((typeNode as ts.IndexedAccessTypeNode).indexType),
356
+ object: resolveTypeNode(
357
+ /* SAFETY: TypeScript AST 파싱과 동기화 입력 계약이 이 값의 타입을 보장한다. */ (
358
+ typeNode as ts.IndexedAccessTypeNode
359
+ ).objectType,
360
+ ),
361
+ index: resolveTypeNode(
362
+ /* SAFETY: TypeScript AST 파싱과 동기화 입력 계약이 이 값의 타입을 보장한다. */ (
363
+ typeNode as ts.IndexedAccessTypeNode
364
+ ).indexType,
365
+ ),
338
366
  };
339
367
  case ts.SyntaxKind.TupleType:
340
368
  if (ts.isTupleTypeNode(typeNode)) {
@@ -347,18 +375,29 @@ function resolveTypeNode(typeNode: ts.TypeNode): ApiParamType {
347
375
  case ts.SyntaxKind.ParenthesizedType:
348
376
  // 괄호로 묶인 타입 (예: (A & B)[] 에서 (A & B))
349
377
  // 내부 타입을 재귀적으로 resolve
350
- return resolveTypeNode((typeNode as ts.ParenthesizedTypeNode).type);
378
+ return resolveTypeNode(
379
+ /* SAFETY: TypeScript AST 파싱과 동기화 입력 계약이 이 값의 타입을 보장한다. */ (
380
+ typeNode as ts.ParenthesizedTypeNode
381
+ ).type,
382
+ );
351
383
 
352
384
  case ts.SyntaxKind.FunctionType:
353
385
  return {
354
386
  t: "function",
355
- parameters: (typeNode as ts.FunctionTypeNode).parameters.map((param) => ({
356
- name: param.name.getText(),
357
- type: param.type ? resolveTypeNode(param.type) : "unknown",
358
- optional: param.questionToken !== undefined,
359
- defaultDef: undefined,
360
- })),
361
- returnType: resolveTypeNode((typeNode as ts.FunctionTypeNode).type),
387
+ parameters:
388
+ /* SAFETY: TypeScript AST 파싱과 동기화 입력 계약이 이 값의 타입을 보장한다. */ (
389
+ typeNode as ts.FunctionTypeNode
390
+ ).parameters.map((param) => ({
391
+ name: param.name.getText(),
392
+ type: param.type ? resolveTypeNode(param.type) : "unknown",
393
+ optional: param.questionToken !== undefined,
394
+ defaultDef: undefined,
395
+ })),
396
+ returnType: resolveTypeNode(
397
+ /* SAFETY: TypeScript AST 파싱과 동기화 입력 계약이 이 값의 타입을 보장한다. */ (
398
+ typeNode as ts.FunctionTypeNode
399
+ ).type,
400
+ ),
362
401
  };
363
402
  case undefined:
364
403
  throw new Error(`typeNode undefined`);
@@ -377,7 +416,8 @@ function resolveParamDec(
377
416
  },
378
417
  index: number = 0,
379
418
  ): ApiParam {
380
- const name = paramDec.name as ts.Identifier;
419
+ const name =
420
+ /* SAFETY: TypeScript AST 파싱과 동기화 입력 계약이 이 값의 타입을 보장한다. */ paramDec.name as ts.Identifier;
381
421
  const type = resolveTypeNode(paramDec.type);
382
422
 
383
423
  if (name === undefined) {
@@ -1,6 +1,5 @@
1
1
  import crypto from "crypto";
2
2
  import { createReadStream, type PathLike } from "fs";
3
- import { readFile, writeFile } from "fs/promises";
4
3
  import path from "path";
5
4
 
6
5
  import equal from "fast-deep-equal";
@@ -8,10 +7,10 @@ import { isEqual } from "radashi";
8
7
 
9
8
  import { Sonamu } from "../api/sonamu";
10
9
  import { globAsync } from "../utils/async-utils";
11
- import { exists } from "../utils/fs-utils";
12
10
  import { type AbsolutePath, type AppRelativePath } from "../utils/path-utils";
13
11
  import { differenceWith } from "../utils/utils";
14
12
  import { getChecksumPatternGroupInAbsolutePath, GLOB_EXCLUDE } from "./file-patterns";
13
+ import { syncerFileExists, syncerFilesystem } from "./filesystem-dependencies";
15
14
 
16
15
  type PathAndChecksum = {
17
16
  path: AbsolutePath;
@@ -61,7 +60,10 @@ async function getCurrentChecksums(): Promise<PathAndChecksum[]> {
61
60
 
62
61
  // 동일 파일이 여러 패턴에 매치될 수 있으므로(예: sd.generated.ts는 generated와 sdGenerated에 모두 매치)
63
62
  // 중복 제거 후 안정 정렬.
64
- const filePaths = Array.from(new Set(allPaths)).toSorted() as AbsolutePath[];
63
+ const filePaths =
64
+ /* SAFETY: TypeScript AST 파싱과 동기화 입력 계약이 이 값의 타입을 보장한다. */ Array.from(
65
+ new Set(allPaths),
66
+ ).toSorted() as AbsolutePath[];
65
67
 
66
68
  return await Promise.all(
67
69
  filePaths.map(async (filePath) => {
@@ -75,17 +77,18 @@ async function getCurrentChecksums(): Promise<PathAndChecksum[]> {
75
77
 
76
78
  async function getPreviousChecksums(): Promise<PathAndChecksum[]> {
77
79
  const checksumFilePath = getChecksumFilePath();
78
- if (!(await exists(checksumFilePath))) {
80
+ if (!(await syncerFileExists(checksumFilePath))) {
79
81
  return [];
80
82
  }
81
83
 
82
84
  try {
83
- const previousChecksums = JSON.parse(await readFile(checksumFilePath, "utf-8")).map(
84
- (r: { path: AppRelativePath; checksum: string }) => ({
85
+ const previousChecksums =
86
+ /* SAFETY: TypeScript AST 파싱과 동기화 입력 계약이 이 값의 타입을 보장한다. */ JSON.parse(
87
+ await syncerFilesystem.readFile(checksumFilePath, "utf-8"),
88
+ ).map((r: { path: AppRelativePath; checksum: string }) => ({
85
89
  path: path.join(Sonamu.appRootPath, r.path), // 체크섬 파일에서 읽을 때: appRoot 상대 경로 → 절대 경로
86
90
  checksum: r.checksum,
87
- }),
88
- ) as PathAndChecksum[];
91
+ })) as PathAndChecksum[];
89
92
  return previousChecksums;
90
93
  } catch (e) {
91
94
  // 체크섬 파일이 손상된 경우 빈 배열 반환 (전체 재동기화 유도)
@@ -98,7 +101,10 @@ async function getPreviousChecksums(): Promise<PathAndChecksum[]> {
98
101
  }
99
102
 
100
103
  function getChecksumFilePath(): AbsolutePath {
101
- return path.join(Sonamu.apiRootPath, "sonamu.lock") as AbsolutePath;
104
+ return /* SAFETY: TypeScript AST 파싱과 동기화 입력 계약이 이 값의 타입을 보장한다. */ path.join(
105
+ Sonamu.apiRootPath,
106
+ "sonamu.lock",
107
+ ) as AbsolutePath;
102
108
  }
103
109
 
104
110
  async function saveChecksums(checksums: PathAndChecksum[]): Promise<void> {
@@ -109,8 +115,8 @@ async function saveChecksums(checksums: PathAndChecksum[]): Promise<void> {
109
115
  path: path.relative(Sonamu.appRootPath, r.path), // 체크섬 파일에 저장할 때: 절대 경로 → appRoot 상대 경로
110
116
  checksum: r.checksum,
111
117
  }))
112
- .sort((a, b) => a.path.localeCompare(b.path));
113
- await writeFile(checksumFilePath, JSON.stringify(serialized, null, 2), "utf-8");
118
+ .toSorted((a, b) => a.path.localeCompare(b.path));
119
+ await syncerFilesystem.writeFile(checksumFilePath, JSON.stringify(serialized, null, 2), "utf-8");
114
120
  }
115
121
 
116
122
  async function getChecksumOfFile(filePath: PathLike): Promise<string> {
@@ -1,4 +1,3 @@
1
- import { mkdir, writeFile } from "fs/promises";
2
1
  import path from "path";
3
2
 
4
3
  import chalk from "chalk";
@@ -21,10 +20,10 @@ import {
21
20
  import { everyAsync, filterAsync } from "../utils/async-utils";
22
21
  import { isTest } from "../utils/controller";
23
22
  import { formatCode } from "../utils/formatter";
24
- import { exists } from "../utils/fs-utils";
25
23
  import { wrapIf } from "../utils/lodash-able";
26
24
  import { type AbsolutePath } from "../utils/path-utils";
27
25
  import { trackWritten } from "./file-tracking";
26
+ import { syncerFileExists, syncerFilesystem } from "./filesystem-dependencies";
28
27
 
29
28
  /**
30
29
  * 템플릿을 렌더링하고 파일로 생성합니다.
@@ -51,8 +50,8 @@ export async function generateTemplate<T extends TemplateKey>(
51
50
  // 템플릿 렌더
52
51
  const pathAndCodes = (
53
52
  await Promise.all(
54
- keys.map(async (key) => {
55
- return await renderTemplate(key, templateOptions);
53
+ keys.map(async (templateKey) => {
54
+ return await renderTemplate(templateKey, templateOptions);
56
55
  }),
57
56
  )
58
57
  ).flat();
@@ -65,7 +64,10 @@ export async function generateTemplate<T extends TemplateKey>(
65
64
  const { targets } = Sonamu.config.sync;
66
65
  const filePath = `${Sonamu.appRootPath}/${pathAndCode.path}`;
67
66
  const dstFilePaths = targets.map((target) => filePath.replace("/:target/", `/${target}/`));
68
- return await everyAsync(dstFilePaths, async (dstPath) => !(await exists(dstPath)));
67
+ return await everyAsync(
68
+ dstFilePaths,
69
+ async (dstPath) => !(await syncerFileExists(dstPath)),
70
+ );
69
71
  });
70
72
  }
71
73
  })();
@@ -103,8 +105,8 @@ export async function renderTemplate<T extends keyof TemplateOptions>(
103
105
  if (rendered.preTemplates) {
104
106
  preTemplateResolved = (
105
107
  await Promise.all(
106
- rendered.preTemplates.map(({ key, options }) => {
107
- return renderTemplate(key, options);
108
+ rendered.preTemplates.map(({ key: preTemplateKey, options: preTemplateOptions }) => {
109
+ return renderTemplate(preTemplateKey, preTemplateOptions);
108
110
  }),
109
111
  )
110
112
  ).flat();
@@ -122,7 +124,10 @@ async function resolveRenderedTemplate(
122
124
  const { target, path: filePath, body, importKeys, customHeaders } = result;
123
125
 
124
126
  // import 할 대상의 대상 path 추출
125
- const builtInSchemaNames = Object.values(BUILT_IN_TYPES).map((info) => info.schemaName as string);
127
+ const builtInSchemaNames = Object.values(BUILT_IN_TYPES).map(
128
+ (info) =>
129
+ /* SAFETY: TypeScript AST 파싱과 동기화 입력 계약이 이 값의 타입을 보장한다. */ info.schemaName as string,
130
+ );
126
131
  const importDefs = importKeys
127
132
  // 내장 타입 스키마는 이미 sonamu에서 import되므로 제외
128
133
  .filter((importKey) => !builtInSchemaNames.includes(importKey))
@@ -157,7 +162,7 @@ async function resolveRenderedTemplate(
157
162
  }
158
163
  return r;
159
164
  },
160
- [] as {
165
+ /* SAFETY: TypeScript AST 파싱과 동기화 입력 계약이 이 값의 타입을 보장한다. */ [] as {
161
166
  keys: string[];
162
167
  from: string;
163
168
  }[],
@@ -178,12 +183,12 @@ async function resolveRenderedTemplate(
178
183
  return [header, body].join("\n\n");
179
184
  } else {
180
185
  Naite.t("resolveRenderedTemplate:beforeFormat", { key, header, body });
181
- const formatted = await formatCode(
186
+ const formattedCode = await formatCode(
182
187
  [header, body].join("\n\n"),
183
188
  `${Sonamu.appRootPath}/${filePath}`,
184
189
  );
185
- Naite.t(`resolveRenderedTemplate:formatted:${key}`, formatted);
186
- return formatted;
190
+ Naite.t(`resolveRenderedTemplate:formatted:${key}`, formattedCode);
191
+ return formattedCode;
187
192
  }
188
193
  })();
189
194
 
@@ -196,18 +201,21 @@ async function resolveRenderedTemplate(
196
201
  async function writeCodeToPathEachTarget(pathAndCode: PathAndCode): Promise<AbsolutePath[]> {
197
202
  const { targets } = Sonamu.config.sync;
198
203
  const { appRootPath } = Sonamu;
199
- const filePath = `${Sonamu.appRootPath}/${pathAndCode.path}` as AbsolutePath;
204
+ const filePath =
205
+ /* SAFETY: TypeScript AST 파싱과 동기화 입력 계약이 이 값의 타입을 보장한다. */ `${Sonamu.appRootPath}/${pathAndCode.path}` as AbsolutePath;
200
206
 
201
207
  const dstFilePaths = unique(
202
- targets.map((target) => filePath.replace("/:target/", `/${target}/`)) as AbsolutePath[],
208
+ /* SAFETY: TypeScript AST 파싱과 동기화 입력 계약이 이 값의 타입을 보장한다. */ targets.map(
209
+ (target) => filePath.replace("/:target/", `/${target}/`),
210
+ ) as AbsolutePath[],
203
211
  );
204
212
  return await Promise.all(
205
213
  dstFilePaths.map(async (dstFilePath) => {
206
214
  const dir = path.dirname(dstFilePath);
207
- if (!(await exists(dir))) {
208
- await mkdir(dir, { recursive: true });
215
+ if (!(await syncerFileExists(dir))) {
216
+ await syncerFilesystem.mkdir(dir, { recursive: true });
209
217
  }
210
- await writeFile(dstFilePath, pathAndCode.code);
218
+ await syncerFilesystem.writeFile(dstFilePath, pathAndCode.code);
211
219
  // 방금 우리가 쓴 path를 등록 → dev watcher의 후속 change 이벤트가
212
220
  // 외부 변경으로 오인되지 않도록 거름 가드 자료 제공.
213
221
  await trackWritten(dstFilePath);
@@ -1,5 +1,3 @@
1
- import { rm } from "fs/promises";
2
-
3
1
  import chalk from "chalk";
4
2
 
5
3
  import { Sonamu } from "../api/sonamu";
@@ -8,8 +6,8 @@ import { EntityManager } from "../entity/entity-manager";
8
6
  import { BadRequestException } from "../exceptions/so-exceptions";
9
7
  import { type TemplateOptions } from "../types/types";
10
8
  import { isTest } from "../utils/controller";
11
- import { exists } from "../utils/fs-utils";
12
9
  import { generateTemplate } from "./code-generator";
10
+ import { syncerFileExists, syncerFilesystem } from "./filesystem-dependencies";
13
11
 
14
12
  /**
15
13
  * 새로운 엔티티를 생성합니다.
@@ -53,9 +51,9 @@ export async function delEntity(entityId: string): Promise<{ delPaths: string[]
53
51
  })(); // iife
54
52
 
55
53
  for (const delPath of delPaths) {
56
- if (await exists(delPath)) {
54
+ if (await syncerFileExists(delPath)) {
57
55
  !isTest() && console.log(chalk.red(`DELETE ${delPath}`));
58
- await rm(delPath, { recursive: true, force: true });
56
+ await syncerFilesystem.rm(delPath, { recursive: true, force: true });
59
57
  } else {
60
58
  !isTest() && console.log(chalk.yellow(`NOT_EXISTS ${delPath}`));
61
59
  }
@@ -0,0 +1,46 @@
1
+ import path, { dirname } from "node:path";
2
+
3
+ import { formatCode } from "../utils/formatter";
4
+ import { syncerFileExists, syncerFilesystem } from "./filesystem-dependencies";
5
+
6
+ /**
7
+ * Syncer 파일시스템 경계를 통해 파일을 복사하고 클라이언트용 import 경로를 변환합니다.
8
+ */
9
+ export async function copyFileWithReplaceCoreToShared(
10
+ fromPath: string,
11
+ toPath: string,
12
+ syncHeader?: string,
13
+ ): Promise<boolean> {
14
+ if (!(await syncerFileExists(fromPath))) {
15
+ return false;
16
+ }
17
+
18
+ const oldFileContent = await syncerFilesystem.readFile(fromPath, "utf-8");
19
+ let newFileContent = replaceCoreImport(oldFileContent, toPath);
20
+
21
+ if (syncHeader) {
22
+ const generatedBlockRegex = /\/\*\*\r?\n \* @generated\r?\n[\s\S]*?\*\/\r?\n(\r?\n)*/;
23
+ newFileContent = generatedBlockRegex.test(newFileContent)
24
+ ? newFileContent.replace(generatedBlockRegex, `${syncHeader}\n\n`)
25
+ : `${syncHeader}\n\n${newFileContent}`;
26
+ }
27
+
28
+ if (toPath.endsWith(".ts") || toPath.endsWith(".tsx")) {
29
+ newFileContent = await formatCode(newFileContent, toPath);
30
+ }
31
+
32
+ await syncerFilesystem.writeFile(toPath, newFileContent);
33
+ return true;
34
+ }
35
+
36
+ function replaceCoreImport(source: string, toPath: string): string {
37
+ const srcMatch = toPath.match(/^(.+\/src)\//);
38
+ if (!srcMatch) {
39
+ return source;
40
+ }
41
+
42
+ const servicesDir = path.join(srcMatch[1], "services");
43
+ const relativePath = path.relative(dirname(toPath), servicesDir);
44
+ const sharedPath = relativePath === "" ? "./sonamu.shared" : `${relativePath}/sonamu.shared`;
45
+ return source.replace(/from "sonamu(\/dict)?"/g, `from "${sharedPath}"`);
46
+ }
@@ -56,6 +56,7 @@ export function getChecksumPatternGroup() {
56
56
  // 여기에는 Sonamu의 모든 sync 산출물이 있는 것은 아닙니다.
57
57
  // sonamu.shared.ts와 entry-server.generated.tsx와 같은
58
58
  // sync 초반 1회성 부트스트랩 파일들은 관리 안 하기 때문에 여기에 리스팅도 안 합니다.
59
+ httpValidatorsGenerated: api("src/application/**/sonamu.validators.generated.ts"),
59
60
  generated: api("src/application/**/*.generated.{ts,tsx,sso.ts}"),
60
61
  generatedCopied: targets("src/services/**/sonamu.generated.{ts,tsx}"),
61
62
  httpGenerated: api("src/application/**/*.generated.http"),
@@ -67,6 +68,11 @@ export function getChecksumPatternGroup() {
67
68
  } satisfies Record<string, AppRelativePath>;
68
69
  }
69
70
 
71
+ // Node 내장 fs.glob의 brace expansion은 단일 멤버 {x}를 풀지 않으므로, 멤버가 1개일 때는 alternation 없이 직접 결합합니다.
72
+ function braceJoin(dirs: readonly string[]) {
73
+ return dirs.length === 1 ? dirs[0] : `{${dirs.join(",")}}`;
74
+ }
75
+
70
76
  /**
71
77
  * 위치 카테고리별 글롭 빌더를 만들어 반환합니다.
72
78
  * - api(rest): api 디렉토리에 한정
@@ -77,16 +83,13 @@ function globBuilders() {
77
83
  const apiDir = Sonamu.config.api.dir;
78
84
  const targetDirs = Sonamu.config.sync.targets;
79
85
 
80
- // Node 내장 fs.glob의 brace expansion은 단일 멤버 {x}를 풀지 않으므로, 멤버가 1개일 때는 alternation 없이 직접 결합합니다.
81
- const braceJoin = (dirs: readonly string[]) =>
82
- dirs.length === 1 ? dirs[0] : `{${dirs.join(",")}}`;
83
-
84
86
  return {
85
- api: (pathFromApi: string) => `${apiDir}/${pathFromApi}` as AppRelativePath,
87
+ api: (pathFromApi: string) =>
88
+ /* SAFETY: TypeScript AST 파싱과 동기화 입력 계약이 이 값의 타입을 보장한다. */ `${apiDir}/${pathFromApi}` as AppRelativePath,
86
89
  targets: (pathFromTarget: string) =>
87
- `${braceJoin(targetDirs)}/${pathFromTarget}` as AppRelativePath,
90
+ /* SAFETY: TypeScript AST 파싱과 동기화 입력 계약이 이 값의 타입을 보장한다. */ `${braceJoin(targetDirs)}/${pathFromTarget}` as AppRelativePath,
88
91
  anywhere: (pathFromAnywhere: string) =>
89
- `${braceJoin([apiDir, ...targetDirs])}/${pathFromAnywhere}` as AppRelativePath,
92
+ /* SAFETY: TypeScript AST 파싱과 동기화 입력 계약이 이 값의 타입을 보장한다. */ `${braceJoin([apiDir, ...targetDirs])}/${pathFromAnywhere}` as AppRelativePath,
90
93
  };
91
94
  }
92
95
 
@@ -110,7 +113,7 @@ export const GLOB_EXCLUDE = ["**/node_modules/**", "**/dist/**", "**/build/**",
110
113
  */
111
114
  export function getChecksumPatternGroupInAbsolutePath(): GlobPattern<AbsolutePath> {
112
115
  const group = getChecksumPatternGroup();
113
- return Object.fromEntries(
116
+ return /* SAFETY: TypeScript AST 파싱과 동기화 입력 계약이 이 값의 타입을 보장한다. */ Object.fromEntries(
114
117
  Object.entries(group).map(([key, value]) => [
115
118
  key,
116
119
  path.join(Sonamu.appRootPath, value), // appRoot 상대 경로 → 절대 경로
@@ -1,6 +1,5 @@
1
- import { stat } from "fs/promises";
2
-
3
1
  import { type AbsolutePath } from "../utils/path-utils";
2
+ import { syncerFilesystem } from "./filesystem-dependencies";
4
3
 
5
4
  export const fileWrittenAt = new Map<AbsolutePath, number>();
6
5
 
@@ -9,7 +8,7 @@ export const fileWrittenAt = new Map<AbsolutePath, number>();
9
8
  * 디스크에서 mtime을 직접 읽어 정확한 값으로 등록합니다.
10
9
  */
11
10
  export async function trackWritten(filePath: AbsolutePath): Promise<void> {
12
- const fileStat = await stat(filePath);
11
+ const fileStat = await syncerFilesystem.stat(filePath);
13
12
  fileWrittenAt.set(filePath, fileStat.mtimeMs);
14
13
  }
15
14
 
@@ -22,6 +21,6 @@ export async function isLastChangedByMe(filePath: AbsolutePath): Promise<boolean
22
21
  if (registered === undefined) {
23
22
  return false;
24
23
  }
25
- const fileStat = await stat(filePath);
24
+ const fileStat = await syncerFilesystem.stat(filePath);
26
25
  return fileStat.mtimeMs <= registered;
27
26
  }