@things-factory/board-ai 10.0.0-beta.108

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 (329) hide show
  1. package/PLAN-styling-tools.md +1253 -0
  2. package/client/components/board-ai-chat.test.ts +149 -0
  3. package/client/components/board-ai-chat.ts +2574 -0
  4. package/client/components/chat-echo-dedup.test.ts +116 -0
  5. package/client/components/chat-echo-dedup.ts +89 -0
  6. package/client/components/chat-input-builder.ts +47 -0
  7. package/client/components/default-catalog-entries.test.ts +59 -0
  8. package/client/components/default-catalog-entries.ts +100 -0
  9. package/client/components/default-slash-templates.test.ts +55 -0
  10. package/client/components/default-slash-templates.ts +129 -0
  11. package/client/components/markdown.test.ts +518 -0
  12. package/client/components/markdown.ts +508 -0
  13. package/client/components/mention-popup-helpers.ts +433 -0
  14. package/client/components/mention-popup.test.ts +588 -0
  15. package/client/components/mention-popup.ts +238 -0
  16. package/client/index.ts +11 -0
  17. package/client/tsconfig.json +13 -0
  18. package/client/utils/board-edit-patch.ts +374 -0
  19. package/config/config.development.js +43 -0
  20. package/config/config.production.js +15 -0
  21. package/dist-client/client/components/board-ai-chat.d.ts +277 -0
  22. package/dist-client/client/components/board-ai-chat.js +2444 -0
  23. package/dist-client/client/components/board-ai-chat.js.map +1 -0
  24. package/dist-client/client/components/board-ai-chat.test.d.ts +1 -0
  25. package/dist-client/client/components/board-ai-chat.test.js +138 -0
  26. package/dist-client/client/components/board-ai-chat.test.js.map +1 -0
  27. package/dist-client/client/components/chat-echo-dedup.d.ts +45 -0
  28. package/dist-client/client/components/chat-echo-dedup.js +58 -0
  29. package/dist-client/client/components/chat-echo-dedup.js.map +1 -0
  30. package/dist-client/client/components/chat-echo-dedup.test.d.ts +1 -0
  31. package/dist-client/client/components/chat-echo-dedup.test.js +101 -0
  32. package/dist-client/client/components/chat-echo-dedup.test.js.map +1 -0
  33. package/dist-client/client/components/chat-input-builder.d.ts +39 -0
  34. package/dist-client/client/components/chat-input-builder.js +26 -0
  35. package/dist-client/client/components/chat-input-builder.js.map +1 -0
  36. package/dist-client/client/components/default-catalog-entries.d.ts +15 -0
  37. package/dist-client/client/components/default-catalog-entries.js +86 -0
  38. package/dist-client/client/components/default-catalog-entries.js.map +1 -0
  39. package/dist-client/client/components/default-catalog-entries.test.d.ts +1 -0
  40. package/dist-client/client/components/default-catalog-entries.test.js +52 -0
  41. package/dist-client/client/components/default-catalog-entries.test.js.map +1 -0
  42. package/dist-client/client/components/default-slash-templates.d.ts +17 -0
  43. package/dist-client/client/components/default-slash-templates.js +113 -0
  44. package/dist-client/client/components/default-slash-templates.js.map +1 -0
  45. package/dist-client/client/components/default-slash-templates.test.d.ts +1 -0
  46. package/dist-client/client/components/default-slash-templates.test.js +51 -0
  47. package/dist-client/client/components/default-slash-templates.test.js.map +1 -0
  48. package/dist-client/client/components/markdown.d.ts +60 -0
  49. package/dist-client/client/components/markdown.js +422 -0
  50. package/dist-client/client/components/markdown.js.map +1 -0
  51. package/dist-client/client/components/markdown.test.d.ts +1 -0
  52. package/dist-client/client/components/markdown.test.js +418 -0
  53. package/dist-client/client/components/markdown.test.js.map +1 -0
  54. package/dist-client/client/components/mention-popup-helpers.d.ts +165 -0
  55. package/dist-client/client/components/mention-popup-helpers.js +330 -0
  56. package/dist-client/client/components/mention-popup-helpers.js.map +1 -0
  57. package/dist-client/client/components/mention-popup.d.ts +35 -0
  58. package/dist-client/client/components/mention-popup.js +223 -0
  59. package/dist-client/client/components/mention-popup.js.map +1 -0
  60. package/dist-client/client/components/mention-popup.test.d.ts +1 -0
  61. package/dist-client/client/components/mention-popup.test.js +474 -0
  62. package/dist-client/client/components/mention-popup.test.js.map +1 -0
  63. package/dist-client/client/index.d.ts +11 -0
  64. package/dist-client/client/index.js +12 -0
  65. package/dist-client/client/index.js.map +1 -0
  66. package/dist-client/client/utils/board-edit-patch.d.ts +157 -0
  67. package/dist-client/client/utils/board-edit-patch.js +284 -0
  68. package/dist-client/client/utils/board-edit-patch.js.map +1 -0
  69. package/dist-client/server/service/agentic-loop.d.ts +87 -0
  70. package/dist-client/server/service/agentic-loop.js +276 -0
  71. package/dist-client/server/service/agentic-loop.js.map +1 -0
  72. package/dist-client/server/service/assistant.d.ts +84 -0
  73. package/dist-client/server/service/assistant.js +2220 -0
  74. package/dist-client/server/service/assistant.js.map +1 -0
  75. package/dist-client/server/service/catalog-resolver.d.ts +18 -0
  76. package/dist-client/server/service/catalog-resolver.js +93 -0
  77. package/dist-client/server/service/catalog-resolver.js.map +1 -0
  78. package/dist-client/server/service/component-tree.d.ts +68 -0
  79. package/dist-client/server/service/component-tree.js +68 -0
  80. package/dist-client/server/service/component-tree.js.map +1 -0
  81. package/dist-client/server/service/mention-resolver.d.ts +96 -0
  82. package/dist-client/server/service/mention-resolver.js +172 -0
  83. package/dist-client/server/service/mention-resolver.js.map +1 -0
  84. package/dist-client/server/service/prefab-registry.d.ts +73 -0
  85. package/dist-client/server/service/prefab-registry.js +252 -0
  86. package/dist-client/server/service/prefab-registry.js.map +1 -0
  87. package/dist-client/server/service/styling/clear-tools.d.ts +15 -0
  88. package/dist-client/server/service/styling/clear-tools.js +50 -0
  89. package/dist-client/server/service/styling/clear-tools.js.map +1 -0
  90. package/dist-client/server/service/styling/color-utils.d.ts +43 -0
  91. package/dist-client/server/service/styling/color-utils.js +205 -0
  92. package/dist-client/server/service/styling/color-utils.js.map +1 -0
  93. package/dist-client/server/service/styling/copy-tools.d.ts +27 -0
  94. package/dist-client/server/service/styling/copy-tools.js +78 -0
  95. package/dist-client/server/service/styling/copy-tools.js.map +1 -0
  96. package/dist-client/server/service/styling/effect-tools.d.ts +45 -0
  97. package/dist-client/server/service/styling/effect-tools.js +85 -0
  98. package/dist-client/server/service/styling/effect-tools.js.map +1 -0
  99. package/dist-client/server/service/styling/fill-tools.d.ts +60 -0
  100. package/dist-client/server/service/styling/fill-tools.js +226 -0
  101. package/dist-client/server/service/styling/fill-tools.js.map +1 -0
  102. package/dist-client/server/service/styling/material-tools.d.ts +32 -0
  103. package/dist-client/server/service/styling/material-tools.js +88 -0
  104. package/dist-client/server/service/styling/material-tools.js.map +1 -0
  105. package/dist-client/server/service/styling/read-tools.d.ts +34 -0
  106. package/dist-client/server/service/styling/read-tools.js +42 -0
  107. package/dist-client/server/service/styling/read-tools.js.map +1 -0
  108. package/dist-client/server/service/styling/registry.d.ts +91 -0
  109. package/dist-client/server/service/styling/registry.js +345 -0
  110. package/dist-client/server/service/styling/registry.js.map +1 -0
  111. package/dist-client/server/service/styling/stroke-tools.d.ts +35 -0
  112. package/dist-client/server/service/styling/stroke-tools.js +94 -0
  113. package/dist-client/server/service/styling/stroke-tools.js.map +1 -0
  114. package/dist-client/server/service/styling/text-tools.d.ts +32 -0
  115. package/dist-client/server/service/styling/text-tools.js +101 -0
  116. package/dist-client/server/service/styling/text-tools.js.map +1 -0
  117. package/dist-client/server/service/types.d.ts +265 -0
  118. package/dist-client/server/service/types.js +2 -0
  119. package/dist-client/server/service/types.js.map +1 -0
  120. package/dist-client/server/service/validation/board-model-schema.d.ts +8311 -0
  121. package/dist-client/server/service/validation/board-model-schema.js +402 -0
  122. package/dist-client/server/service/validation/board-model-schema.js.map +1 -0
  123. package/dist-client/server/service/validation/tool-validation.d.ts +31 -0
  124. package/dist-client/server/service/validation/tool-validation.js +193 -0
  125. package/dist-client/server/service/validation/tool-validation.js.map +1 -0
  126. package/dist-client/tsconfig.tsbuildinfo +1 -0
  127. package/dist-server/index.d.ts +23 -0
  128. package/dist-server/index.js +27 -0
  129. package/dist-server/index.js.map +1 -0
  130. package/dist-server/service/agentic-loop.d.ts +87 -0
  131. package/dist-server/service/agentic-loop.js +280 -0
  132. package/dist-server/service/agentic-loop.js.map +1 -0
  133. package/dist-server/service/apply-patch.d.ts +47 -0
  134. package/dist-server/service/apply-patch.js +369 -0
  135. package/dist-server/service/apply-patch.js.map +1 -0
  136. package/dist-server/service/assistant.d.ts +84 -0
  137. package/dist-server/service/assistant.js +2237 -0
  138. package/dist-server/service/assistant.js.map +1 -0
  139. package/dist-server/service/board-ai-resolver.d.ts +54 -0
  140. package/dist-server/service/board-ai-resolver.js +409 -0
  141. package/dist-server/service/board-ai-resolver.js.map +1 -0
  142. package/dist-server/service/catalog-resolver.d.ts +18 -0
  143. package/dist-server/service/catalog-resolver.js +98 -0
  144. package/dist-server/service/catalog-resolver.js.map +1 -0
  145. package/dist-server/service/chat-message/chat-message-broadcast.d.ts +13 -0
  146. package/dist-server/service/chat-message/chat-message-broadcast.js +13 -0
  147. package/dist-server/service/chat-message/chat-message-broadcast.js.map +1 -0
  148. package/dist-server/service/chat-message/chat-message-publish.d.ts +6 -0
  149. package/dist-server/service/chat-message/chat-message-publish.js +27 -0
  150. package/dist-server/service/chat-message/chat-message-publish.js.map +1 -0
  151. package/dist-server/service/chat-message/chat-message-subscription.d.ts +8 -0
  152. package/dist-server/service/chat-message/chat-message-subscription.js +53 -0
  153. package/dist-server/service/chat-message/chat-message-subscription.js.map +1 -0
  154. package/dist-server/service/chat-message/chat-message.d.ts +56 -0
  155. package/dist-server/service/chat-message/chat-message.js +149 -0
  156. package/dist-server/service/chat-message/chat-message.js.map +1 -0
  157. package/dist-server/service/chat-message/index.d.ts +5 -0
  158. package/dist-server/service/chat-message/index.js +12 -0
  159. package/dist-server/service/chat-message/index.js.map +1 -0
  160. package/dist-server/service/chat-session/chat-session.d.ts +31 -0
  161. package/dist-server/service/chat-session/chat-session.js +131 -0
  162. package/dist-server/service/chat-session/chat-session.js.map +1 -0
  163. package/dist-server/service/chat-session/index.d.ts +3 -0
  164. package/dist-server/service/chat-session/index.js +7 -0
  165. package/dist-server/service/chat-session/index.js.map +1 -0
  166. package/dist-server/service/chat-session-participant/chat-session-participant.d.ts +30 -0
  167. package/dist-server/service/chat-session-participant/chat-session-participant.js +112 -0
  168. package/dist-server/service/chat-session-participant/chat-session-participant.js.map +1 -0
  169. package/dist-server/service/chat-session-participant/index.d.ts +4 -0
  170. package/dist-server/service/chat-session-participant/index.js +10 -0
  171. package/dist-server/service/chat-session-participant/index.js.map +1 -0
  172. package/dist-server/service/chat-session-participant/invite-notification.d.ts +27 -0
  173. package/dist-server/service/chat-session-participant/invite-notification.js +30 -0
  174. package/dist-server/service/chat-session-participant/invite-notification.js.map +1 -0
  175. package/dist-server/service/chat-session-participant/presence.d.ts +4 -0
  176. package/dist-server/service/chat-session-participant/presence.js +22 -0
  177. package/dist-server/service/chat-session-participant/presence.js.map +1 -0
  178. package/dist-server/service/chat-session-resolver.d.ts +20 -0
  179. package/dist-server/service/chat-session-resolver.js +356 -0
  180. package/dist-server/service/chat-session-resolver.js.map +1 -0
  181. package/dist-server/service/component-tree.d.ts +68 -0
  182. package/dist-server/service/component-tree.js +73 -0
  183. package/dist-server/service/component-tree.js.map +1 -0
  184. package/dist-server/service/index.d.ts +20 -0
  185. package/dist-server/service/index.js +34 -0
  186. package/dist-server/service/index.js.map +1 -0
  187. package/dist-server/service/mention-marker.d.ts +78 -0
  188. package/dist-server/service/mention-marker.js +162 -0
  189. package/dist-server/service/mention-marker.js.map +1 -0
  190. package/dist-server/service/mention-resolver.d.ts +96 -0
  191. package/dist-server/service/mention-resolver.js +177 -0
  192. package/dist-server/service/mention-resolver.js.map +1 -0
  193. package/dist-server/service/patch-entry/board-patch-broadcast.d.ts +13 -0
  194. package/dist-server/service/patch-entry/board-patch-broadcast.js +13 -0
  195. package/dist-server/service/patch-entry/board-patch-broadcast.js.map +1 -0
  196. package/dist-server/service/patch-entry/board-patch-subscription.d.ts +12 -0
  197. package/dist-server/service/patch-entry/board-patch-subscription.js +63 -0
  198. package/dist-server/service/patch-entry/board-patch-subscription.js.map +1 -0
  199. package/dist-server/service/patch-entry/index.d.ts +4 -0
  200. package/dist-server/service/patch-entry/index.js +12 -0
  201. package/dist-server/service/patch-entry/index.js.map +1 -0
  202. package/dist-server/service/patch-entry/patch-entry.d.ts +16 -0
  203. package/dist-server/service/patch-entry/patch-entry.js +96 -0
  204. package/dist-server/service/patch-entry/patch-entry.js.map +1 -0
  205. package/dist-server/service/prefab-registry.d.ts +73 -0
  206. package/dist-server/service/prefab-registry.js +258 -0
  207. package/dist-server/service/prefab-registry.js.map +1 -0
  208. package/dist-server/service/styling/clear-tools.d.ts +15 -0
  209. package/dist-server/service/styling/clear-tools.js +53 -0
  210. package/dist-server/service/styling/clear-tools.js.map +1 -0
  211. package/dist-server/service/styling/color-utils.d.ts +43 -0
  212. package/dist-server/service/styling/color-utils.js +210 -0
  213. package/dist-server/service/styling/color-utils.js.map +1 -0
  214. package/dist-server/service/styling/copy-tools.d.ts +27 -0
  215. package/dist-server/service/styling/copy-tools.js +81 -0
  216. package/dist-server/service/styling/copy-tools.js.map +1 -0
  217. package/dist-server/service/styling/effect-tools.d.ts +45 -0
  218. package/dist-server/service/styling/effect-tools.js +90 -0
  219. package/dist-server/service/styling/effect-tools.js.map +1 -0
  220. package/dist-server/service/styling/fill-tools.d.ts +60 -0
  221. package/dist-server/service/styling/fill-tools.js +229 -0
  222. package/dist-server/service/styling/fill-tools.js.map +1 -0
  223. package/dist-server/service/styling/material-tools.d.ts +32 -0
  224. package/dist-server/service/styling/material-tools.js +92 -0
  225. package/dist-server/service/styling/material-tools.js.map +1 -0
  226. package/dist-server/service/styling/read-tools.d.ts +34 -0
  227. package/dist-server/service/styling/read-tools.js +45 -0
  228. package/dist-server/service/styling/read-tools.js.map +1 -0
  229. package/dist-server/service/styling/registry.d.ts +91 -0
  230. package/dist-server/service/styling/registry.js +352 -0
  231. package/dist-server/service/styling/registry.js.map +1 -0
  232. package/dist-server/service/styling/stroke-tools.d.ts +35 -0
  233. package/dist-server/service/styling/stroke-tools.js +97 -0
  234. package/dist-server/service/styling/stroke-tools.js.map +1 -0
  235. package/dist-server/service/styling/text-tools.d.ts +32 -0
  236. package/dist-server/service/styling/text-tools.js +105 -0
  237. package/dist-server/service/styling/text-tools.js.map +1 -0
  238. package/dist-server/service/subscribe-auth.d.ts +14 -0
  239. package/dist-server/service/subscribe-auth.js +33 -0
  240. package/dist-server/service/subscribe-auth.js.map +1 -0
  241. package/dist-server/service/types.d.ts +265 -0
  242. package/dist-server/service/types.js +3 -0
  243. package/dist-server/service/types.js.map +1 -0
  244. package/dist-server/service/validation/board-model-schema.d.ts +8311 -0
  245. package/dist-server/service/validation/board-model-schema.js +409 -0
  246. package/dist-server/service/validation/board-model-schema.js.map +1 -0
  247. package/dist-server/service/validation/tool-validation.d.ts +31 -0
  248. package/dist-server/service/validation/tool-validation.js +196 -0
  249. package/dist-server/service/validation/tool-validation.js.map +1 -0
  250. package/dist-server/tsconfig.tsbuildinfo +1 -0
  251. package/package.json +48 -0
  252. package/server/index.ts +23 -0
  253. package/server/service/agentic-loop.test.ts +705 -0
  254. package/server/service/agentic-loop.ts +431 -0
  255. package/server/service/apply-patch-drift.test.ts +829 -0
  256. package/server/service/apply-patch.test.ts +757 -0
  257. package/server/service/apply-patch.ts +411 -0
  258. package/server/service/assistant-integration.test.ts +922 -0
  259. package/server/service/assistant-llm-smoke.test.ts +296 -0
  260. package/server/service/assistant.test.ts +2034 -0
  261. package/server/service/assistant.ts +2378 -0
  262. package/server/service/board-ai-resolver.ts +407 -0
  263. package/server/service/catalog-resolver.test.ts +137 -0
  264. package/server/service/catalog-resolver.ts +102 -0
  265. package/server/service/chat-message/chat-message-broadcast.integration.test.ts +73 -0
  266. package/server/service/chat-message/chat-message-broadcast.test.ts +40 -0
  267. package/server/service/chat-message/chat-message-broadcast.ts +27 -0
  268. package/server/service/chat-message/chat-message-publish.ts +22 -0
  269. package/server/service/chat-message/chat-message-subscription.ts +41 -0
  270. package/server/service/chat-message/chat-message.ts +169 -0
  271. package/server/service/chat-message/index.ts +12 -0
  272. package/server/service/chat-session/chat-session.ts +130 -0
  273. package/server/service/chat-session/index.ts +5 -0
  274. package/server/service/chat-session-participant/chat-session-participant.ts +110 -0
  275. package/server/service/chat-session-participant/index.ts +6 -0
  276. package/server/service/chat-session-participant/invite-notification.test.ts +30 -0
  277. package/server/service/chat-session-participant/invite-notification.ts +48 -0
  278. package/server/service/chat-session-participant/presence.test.ts +39 -0
  279. package/server/service/chat-session-participant/presence.ts +21 -0
  280. package/server/service/chat-session-resolver.ts +312 -0
  281. package/server/service/component-tree.test.ts +248 -0
  282. package/server/service/component-tree.ts +135 -0
  283. package/server/service/index.ts +32 -0
  284. package/server/service/mention-marker.extract.test.ts +61 -0
  285. package/server/service/mention-marker.test.ts +228 -0
  286. package/server/service/mention-marker.ts +184 -0
  287. package/server/service/mention-resolver.test.ts +273 -0
  288. package/server/service/mention-resolver.ts +264 -0
  289. package/server/service/patch-entry/board-patch-broadcast.ts +24 -0
  290. package/server/service/patch-entry/board-patch-subscription.test.ts +40 -0
  291. package/server/service/patch-entry/board-patch-subscription.ts +50 -0
  292. package/server/service/patch-entry/index.ts +12 -0
  293. package/server/service/patch-entry/patch-entry.ts +89 -0
  294. package/server/service/prefab-registry.test.ts +172 -0
  295. package/server/service/prefab-registry.ts +332 -0
  296. package/server/service/styling/clear-tools.test.ts +164 -0
  297. package/server/service/styling/clear-tools.ts +69 -0
  298. package/server/service/styling/color-utils.test.ts +130 -0
  299. package/server/service/styling/color-utils.ts +226 -0
  300. package/server/service/styling/copy-tools.test.ts +152 -0
  301. package/server/service/styling/copy-tools.ts +115 -0
  302. package/server/service/styling/effect-tools.test.ts +277 -0
  303. package/server/service/styling/effect-tools.ts +124 -0
  304. package/server/service/styling/fill-tools.test.ts +331 -0
  305. package/server/service/styling/fill-tools.ts +293 -0
  306. package/server/service/styling/material-tools.test.ts +294 -0
  307. package/server/service/styling/material-tools.ts +114 -0
  308. package/server/service/styling/read-tools.test.ts +78 -0
  309. package/server/service/styling/read-tools.ts +67 -0
  310. package/server/service/styling/registry.test.ts +203 -0
  311. package/server/service/styling/registry.ts +423 -0
  312. package/server/service/styling/stroke-tools.test.ts +245 -0
  313. package/server/service/styling/stroke-tools.ts +145 -0
  314. package/server/service/styling/text-tools.test.ts +253 -0
  315. package/server/service/styling/text-tools.ts +131 -0
  316. package/server/service/styling/tier1-tools.test.ts +300 -0
  317. package/server/service/subscribe-auth.test.ts +57 -0
  318. package/server/service/subscribe-auth.ts +34 -0
  319. package/server/service/types.ts +235 -0
  320. package/server/service/validation/board-model-schema.test.ts +778 -0
  321. package/server/service/validation/board-model-schema.ts +446 -0
  322. package/server/service/validation/tool-validation.ts +228 -0
  323. package/things-factory.config.js +1 -0
  324. package/translations/en.json +49 -0
  325. package/translations/ja.json +48 -0
  326. package/translations/ko.json +49 -0
  327. package/translations/ms.json +48 -0
  328. package/translations/zh.json +48 -0
  329. package/tsconfig.json +9 -0
@@ -0,0 +1,27 @@
1
+ "use strict";
2
+ Object.defineProperty(exports, "__esModule", { value: true });
3
+ exports.publishChatMessage = publishChatMessage;
4
+ /*
5
+ * chat-message 방송 publisher — pubsub 의존, 데코레이터 없음.
6
+ *
7
+ * 데코레이터 resolver(chat-message-subscription.ts)와 분리한 이유: babel-jest 가 파라미터
8
+ * 데코레이터(@Root/@Arg)를 파싱 못 해 그 파일을 테스트에서 import 할 수 없다. 이 모듈은
9
+ * 데코레이터가 없어 통합 테스트가 실제 publish→방송 경로를 직접 구동할 수 있다.
10
+ */
11
+ const shell_1 = require("@things-factory/shell");
12
+ const chat_message_broadcast_js_1 = require("./chat-message-broadcast.js");
13
+ /**
14
+ * ChatMessage 영속 직후 호출 — 같은 세션 구독자에게 방송.
15
+ * sessionId 없으면 skip. pubsub 미가용/실패해도 본 흐름(영속 완료)을 막지 않는다.
16
+ */
17
+ function publishChatMessage(payload) {
18
+ if (!payload.sessionId)
19
+ return;
20
+ try {
21
+ shell_1.pubsub.publish(chat_message_broadcast_js_1.CHAT_MESSAGE_TOPIC, payload);
22
+ }
23
+ catch {
24
+ /* 방송 생략 — 영속은 이미 끝남 */
25
+ }
26
+ }
27
+ //# sourceMappingURL=chat-message-publish.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"chat-message-publish.js","sourceRoot":"","sources":["../../../server/service/chat-message/chat-message-publish.ts"],"names":[],"mappings":";;AAcA,gDAOC;AArBD;;;;;;GAMG;AACH,iDAA8C;AAC9C,2EAAyF;AAEzF;;;GAGG;AACH,SAAgB,kBAAkB,CAAC,OAA2B;IAC5D,IAAI,CAAC,OAAO,CAAC,SAAS;QAAE,OAAM;IAC9B,IAAI,CAAC;QACH,cAAM,CAAC,OAAO,CAAC,8CAAkB,EAAE,OAAO,CAAC,CAAA;IAC7C,CAAC;IAAC,MAAM,CAAC;QACP,uBAAuB;IACzB,CAAC;AACH,CAAC","sourcesContent":["/*\n * chat-message 방송 publisher — pubsub 의존, 데코레이터 없음.\n *\n * 데코레이터 resolver(chat-message-subscription.ts)와 분리한 이유: babel-jest 가 파라미터\n * 데코레이터(@Root/@Arg)를 파싱 못 해 그 파일을 테스트에서 import 할 수 없다. 이 모듈은\n * 데코레이터가 없어 통합 테스트가 실제 publish→방송 경로를 직접 구동할 수 있다.\n */\nimport { pubsub } from '@things-factory/shell'\nimport { CHAT_MESSAGE_TOPIC, type ChatMessagePayload } from './chat-message-broadcast.js'\n\n/**\n * ChatMessage 영속 직후 호출 — 같은 세션 구독자에게 방송.\n * sessionId 없으면 skip. pubsub 미가용/실패해도 본 흐름(영속 완료)을 막지 않는다.\n */\nexport function publishChatMessage(payload: ChatMessagePayload): void {\n if (!payload.sessionId) return\n try {\n pubsub.publish(CHAT_MESSAGE_TOPIC, payload)\n } catch {\n /* 방송 생략 — 영속은 이미 끝남 */\n }\n}\n"]}
@@ -0,0 +1,8 @@
1
+ import { ChatMessage } from './chat-message.js';
2
+ import { type ChatMessagePayload } from './chat-message-broadcast.js';
3
+ export { publishChatMessage } from './chat-message-publish.js';
4
+ export { CHAT_MESSAGE_TOPIC, chatMessageFilter } from './chat-message-broadcast.js';
5
+ export type { ChatMessagePayload } from './chat-message-broadcast.js';
6
+ export declare class BoardChatMessageSubscription {
7
+ chatMessageActivity(payload: ChatMessagePayload, sessionId: string): ChatMessage;
8
+ }
@@ -0,0 +1,53 @@
1
+ "use strict";
2
+ Object.defineProperty(exports, "__esModule", { value: true });
3
+ exports.BoardChatMessageSubscription = exports.chatMessageFilter = exports.CHAT_MESSAGE_TOPIC = exports.publishChatMessage = void 0;
4
+ const tslib_1 = require("tslib");
5
+ /*
6
+ * BoardChatMessageSubscription (Phase Board-AI C4 — 그룹챗 메시지 실시간 방송).
7
+ *
8
+ * ChatMessage(사용자 / AI / system) 가 영속될 때마다 같은 세션 구독자에게 방송 →
9
+ * 그룹챗의 척추. 클라이언트(board-ai-chat)가 구독해 원격 메시지를 transcript 에 append.
10
+ * 자기 발신 에코는 클라이언트가 message.id 로 dedup (mutation 응답으로 이미 렌더).
11
+ *
12
+ * patch spine(board-patch-subscription.ts)과 동일 패턴 — PubSub + graphql-ws, domain 격리.
13
+ * 차이: 필터 키가 board 가 아닌 sessionId (채팅은 ChatSession 단위).
14
+ * 순수 로직(토픽/필터)은 chat-message-broadcast.ts (테스트 가능). 여기엔 pubsub 의존만.
15
+ */
16
+ const type_graphql_1 = require("type-graphql");
17
+ const graphql_yoga_1 = require("graphql-yoga");
18
+ const shell_1 = require("@things-factory/shell");
19
+ const chat_message_js_1 = require("./chat-message.js");
20
+ const chat_message_broadcast_js_1 = require("./chat-message-broadcast.js");
21
+ const subscribe_auth_js_1 = require("../subscribe-auth.js");
22
+ // publishChatMessage 는 데코레이터 없는 chat-message-publish.ts 에 분리 (테스트 import 가능).
23
+ var chat_message_publish_js_1 = require("./chat-message-publish.js");
24
+ Object.defineProperty(exports, "publishChatMessage", { enumerable: true, get: function () { return chat_message_publish_js_1.publishChatMessage; } });
25
+ var chat_message_broadcast_js_2 = require("./chat-message-broadcast.js");
26
+ Object.defineProperty(exports, "CHAT_MESSAGE_TOPIC", { enumerable: true, get: function () { return chat_message_broadcast_js_2.CHAT_MESSAGE_TOPIC; } });
27
+ Object.defineProperty(exports, "chatMessageFilter", { enumerable: true, get: function () { return chat_message_broadcast_js_2.chatMessageFilter; } });
28
+ let BoardChatMessageSubscription = class BoardChatMessageSubscription {
29
+ chatMessageActivity(payload, sessionId) {
30
+ return payload.message;
31
+ }
32
+ };
33
+ exports.BoardChatMessageSubscription = BoardChatMessageSubscription;
34
+ tslib_1.__decorate([
35
+ (0, type_graphql_1.Subscription)({
36
+ description: 'Subscribes to chat messages (user / assistant / system) of a session for real-time group chat.',
37
+ subscribe: async ({ args, context }) => {
38
+ const { domain, user } = context.state;
39
+ const { sessionId } = args;
40
+ await (0, subscribe_auth_js_1.assertDomainSubscribeAllowed)(domain, user, (d, u) => process.superUserGranted(d, u));
41
+ return (0, graphql_yoga_1.pipe)(shell_1.pubsub.subscribe(chat_message_broadcast_js_1.CHAT_MESSAGE_TOPIC), (0, graphql_yoga_1.filter)((0, chat_message_broadcast_js_1.chatMessageFilter)(domain.id, sessionId)));
42
+ }
43
+ }),
44
+ tslib_1.__param(0, (0, type_graphql_1.Root)()),
45
+ tslib_1.__param(1, (0, type_graphql_1.Arg)('sessionId')),
46
+ tslib_1.__metadata("design:type", Function),
47
+ tslib_1.__metadata("design:paramtypes", [Object, String]),
48
+ tslib_1.__metadata("design:returntype", chat_message_js_1.ChatMessage)
49
+ ], BoardChatMessageSubscription.prototype, "chatMessageActivity", null);
50
+ exports.BoardChatMessageSubscription = BoardChatMessageSubscription = tslib_1.__decorate([
51
+ (0, type_graphql_1.Resolver)(chat_message_js_1.ChatMessage)
52
+ ], BoardChatMessageSubscription);
53
+ //# sourceMappingURL=chat-message-subscription.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"chat-message-subscription.js","sourceRoot":"","sources":["../../../server/service/chat-message/chat-message-subscription.ts"],"names":[],"mappings":";;;;AAAA;;;;;;;;;;GAUG;AACH,+CAAgE;AAChE,+CAA2C;AAC3C,iDAA8C;AAC9C,uDAA+C;AAC/C,2EAA4G;AAC5G,4DAAmE;AAEnE,8EAA8E;AAC9E,qEAA8D;AAArD,6HAAA,kBAAkB,OAAA;AAC3B,yEAAmF;AAA1E,+HAAA,kBAAkB,OAAA;AAAE,8HAAA,iBAAiB,OAAA;AAIvC,IAAM,4BAA4B,GAAlC,MAAM,4BAA4B;IAavC,mBAAmB,CAAS,OAA2B,EAAoB,SAAiB;QAC1F,OAAO,OAAO,CAAC,OAAO,CAAA;IACxB,CAAC;CACF,CAAA;AAhBY,oEAA4B;AAavC;IAZC,IAAA,2BAAY,EAAC;QACZ,WAAW,EACT,gGAAgG;QAClG,SAAS,EAAE,KAAK,EAAE,EAAE,IAAI,EAAE,OAAO,EAAE,EAAE,EAAE;YACrC,MAAM,EAAE,MAAM,EAAE,IAAI,EAAE,GAAG,OAAO,CAAC,KAAK,CAAA;YACtC,MAAM,EAAE,SAAS,EAAE,GAAG,IAAI,CAAA;YAE1B,MAAM,IAAA,gDAA4B,EAAC,MAAM,EAAE,IAAI,EAAE,CAAC,CAAC,EAAE,CAAC,EAAE,EAAE,CAAC,OAAO,CAAC,gBAAgB,CAAC,CAAC,EAAE,CAAC,CAAC,CAAC,CAAA;YAE1F,OAAO,IAAA,mBAAI,EAAC,cAAM,CAAC,SAAS,CAAC,8CAAkB,CAAC,EAAE,IAAA,qBAAM,EAAC,IAAA,6CAAiB,EAAC,MAAM,CAAC,EAAE,EAAE,SAAS,CAAC,CAAC,CAAC,CAAA;QACpG,CAAC;KACF,CAAC;IACmB,mBAAA,IAAA,mBAAI,GAAE,CAAA;IAA+B,mBAAA,IAAA,kBAAG,EAAC,WAAW,CAAC,CAAA;;;4CAAqB,6BAAW;uEAEzG;uCAfU,4BAA4B;IADxC,IAAA,uBAAQ,EAAC,6BAAW,CAAC;GACT,4BAA4B,CAgBxC","sourcesContent":["/*\n * BoardChatMessageSubscription (Phase Board-AI C4 — 그룹챗 메시지 실시간 방송).\n *\n * ChatMessage(사용자 / AI / system) 가 영속될 때마다 같은 세션 구독자에게 방송 →\n * 그룹챗의 척추. 클라이언트(board-ai-chat)가 구독해 원격 메시지를 transcript 에 append.\n * 자기 발신 에코는 클라이언트가 message.id 로 dedup (mutation 응답으로 이미 렌더).\n *\n * patch spine(board-patch-subscription.ts)과 동일 패턴 — PubSub + graphql-ws, domain 격리.\n * 차이: 필터 키가 board 가 아닌 sessionId (채팅은 ChatSession 단위).\n * 순수 로직(토픽/필터)은 chat-message-broadcast.ts (테스트 가능). 여기엔 pubsub 의존만.\n */\nimport { Resolver, Subscription, Root, Arg } from 'type-graphql'\nimport { filter, pipe } from 'graphql-yoga'\nimport { pubsub } from '@things-factory/shell'\nimport { ChatMessage } from './chat-message.js'\nimport { CHAT_MESSAGE_TOPIC, chatMessageFilter, type ChatMessagePayload } from './chat-message-broadcast.js'\nimport { assertDomainSubscribeAllowed } from '../subscribe-auth.js'\n\n// publishChatMessage 는 데코레이터 없는 chat-message-publish.ts 에 분리 (테스트 import 가능).\nexport { publishChatMessage } from './chat-message-publish.js'\nexport { CHAT_MESSAGE_TOPIC, chatMessageFilter } from './chat-message-broadcast.js'\nexport type { ChatMessagePayload } from './chat-message-broadcast.js'\n\n@Resolver(ChatMessage)\nexport class BoardChatMessageSubscription {\n @Subscription({\n description:\n 'Subscribes to chat messages (user / assistant / system) of a session for real-time group chat.',\n subscribe: async ({ args, context }) => {\n const { domain, user } = context.state\n const { sessionId } = args\n\n await assertDomainSubscribeAllowed(domain, user, (d, u) => process.superUserGranted(d, u))\n\n return pipe(pubsub.subscribe(CHAT_MESSAGE_TOPIC), filter(chatMessageFilter(domain.id, sessionId)))\n }\n })\n chatMessageActivity(@Root() payload: ChatMessagePayload, @Arg('sessionId') sessionId: string): ChatMessage {\n return payload.message\n }\n}\n"]}
@@ -0,0 +1,56 @@
1
+ import { User } from '@things-factory/auth-base';
2
+ import { ChatSession } from '../chat-session/chat-session.js';
3
+ export declare class ChatMessage {
4
+ readonly id?: string;
5
+ session?: ChatSession;
6
+ sessionId?: string;
7
+ role: string;
8
+ content: string;
9
+ relatedPatchId?: string;
10
+ relatedImportSessionId?: string;
11
+ /**
12
+ * AI 가 응답을 만드는 동안 호출한 도구 trace — JSON-stringified.
13
+ *
14
+ * 컬럼은 string (PatchEntry.ops 와 동일 패턴), GraphQL 노출은 toolUsagesJson getter
15
+ * 로 parse 된 객체. UI 의 fold-able 박스 ("AI 가 이런 도구를 사용했습니다") 가
16
+ * 페이지 reload / loadHistory 후에도 살아있도록 영속.
17
+ *
18
+ * 형태: ToolUsage[] (assistant.ts 의 시간순 trace, summarizeToolResult 로 압축).
19
+ * null 이면 도구 호출 없었던 메시지 (text-only 응답).
20
+ */
21
+ toolUsages?: string;
22
+ /** GraphQL 노출용 — JSON 배열로 parse. */
23
+ get toolUsagesJson(): any;
24
+ /**
25
+ * 메시지를 일으킨 사용자.
26
+ * - role='user' → 보낸 사용자
27
+ * - role='assistant' → 그 응답을 트리거한 사용자 (직전 user 메시지의 작성자)
28
+ * - role='system' → 시스템 액션을 일으킨 사용자 (예: 직접 편집한 사용자)
29
+ *
30
+ * nullable — legacy 메시지 (이 필드 추가 이전에 작성) 는 null. 또한 ad-hoc 모드 / 시스템
31
+ * 자동 메시지 중 사용자 컨텍스트가 없는 경우도 null 가능.
32
+ */
33
+ creator?: User;
34
+ creatorId?: string;
35
+ updater?: User;
36
+ updaterId?: string;
37
+ /**
38
+ * 부모 메시지 — 이 메시지가 "응답하는 대상" / "이어가는 메시지" 의 id.
39
+ *
40
+ * 의미 (role 별):
41
+ * - 'user' → 직전 in-session 메시지 (보통 assistant 또는 system). 첫 turn 은 null.
42
+ * - 'assistant' → 이 응답이 답하는 user 메시지. (regenerate 로 같은 user 메시지를 부모로
43
+ * 하는 형제 assistant 메시지가 생기면 자연스럽게 branching tree 가 됨)
44
+ * - 'system' → 직전 in-session 메시지 (timeline 연속성 유지).
45
+ *
46
+ * 이 한 컬럼으로 향후 어떤 흐름이든 표현 가능 — linear chain / branching (regenerate) /
47
+ * tree (replies-to-specific-message) 등. UI/쿼리는 점진 도입.
48
+ *
49
+ * onDelete: 'SET NULL' — 부모 메시지가 삭제돼도 child 는 남되 dangling 마킹.
50
+ */
51
+ parentMessage?: ChatMessage;
52
+ parentMessageId?: string;
53
+ createdAt?: Date;
54
+ updatedAt?: Date;
55
+ deletedAt?: Date;
56
+ }
@@ -0,0 +1,149 @@
1
+ "use strict";
2
+ Object.defineProperty(exports, "__esModule", { value: true });
3
+ exports.ChatMessage = void 0;
4
+ const tslib_1 = require("tslib");
5
+ /**
6
+ * ChatMessage — ChatSession 의 한 메시지.
7
+ *
8
+ * role: 'user' | 'assistant' | 'system'
9
+ * 'system' 은 사용자 직접 편집/import 진행 등 시스템이 자동 생성하는 컨텍스트 메시지.
10
+ *
11
+ * relatedPatchId / relatedImportSessionId 로 메시지가 트리거한 패치·임포트와 연결.
12
+ */
13
+ const typeorm_1 = require("typeorm");
14
+ const type_graphql_1 = require("type-graphql");
15
+ const graphql_scalars_1 = require("graphql-scalars");
16
+ const auth_base_1 = require("@things-factory/auth-base");
17
+ const env_1 = require("@things-factory/env");
18
+ const chat_session_js_1 = require("../chat-session/chat-session.js");
19
+ const ORMCONFIG = env_1.config.get('ormconfig', {});
20
+ const DATABASE_TYPE = ORMCONFIG.type;
21
+ let ChatMessage = class ChatMessage {
22
+ /** GraphQL 노출용 — JSON 배열로 parse. */
23
+ get toolUsagesJson() {
24
+ if (!this.toolUsages)
25
+ return null;
26
+ try {
27
+ return JSON.parse(this.toolUsages);
28
+ }
29
+ catch {
30
+ return null;
31
+ }
32
+ }
33
+ };
34
+ exports.ChatMessage = ChatMessage;
35
+ tslib_1.__decorate([
36
+ (0, typeorm_1.PrimaryGeneratedColumn)('uuid'),
37
+ (0, type_graphql_1.Field)(type => type_graphql_1.ID, { nullable: true }),
38
+ tslib_1.__metadata("design:type", String)
39
+ ], ChatMessage.prototype, "id", void 0);
40
+ tslib_1.__decorate([
41
+ (0, typeorm_1.ManyToOne)(type => chat_session_js_1.ChatSession, session => session.messages, { onDelete: 'CASCADE' }),
42
+ tslib_1.__metadata("design:type", chat_session_js_1.ChatSession)
43
+ ], ChatMessage.prototype, "session", void 0);
44
+ tslib_1.__decorate([
45
+ (0, typeorm_1.RelationId)((message) => message.session),
46
+ tslib_1.__metadata("design:type", String)
47
+ ], ChatMessage.prototype, "sessionId", void 0);
48
+ tslib_1.__decorate([
49
+ (0, typeorm_1.Column)({ type: 'varchar', length: 16 }),
50
+ (0, type_graphql_1.Field)({ description: "'user' | 'assistant' | 'system'" }),
51
+ tslib_1.__metadata("design:type", String)
52
+ ], ChatMessage.prototype, "role", void 0);
53
+ tslib_1.__decorate([
54
+ (0, typeorm_1.Column)({
55
+ type: DATABASE_TYPE == 'mysql' || DATABASE_TYPE == 'mariadb'
56
+ ? 'longtext'
57
+ : DATABASE_TYPE == 'oracle'
58
+ ? 'clob'
59
+ : DATABASE_TYPE == 'mssql'
60
+ ? 'nvarchar'
61
+ : 'text',
62
+ length: DATABASE_TYPE == 'mssql' ? 'MAX' : undefined
63
+ }),
64
+ (0, type_graphql_1.Field)({ description: 'Message content' }),
65
+ tslib_1.__metadata("design:type", String)
66
+ ], ChatMessage.prototype, "content", void 0);
67
+ tslib_1.__decorate([
68
+ (0, typeorm_1.Column)({ nullable: true }),
69
+ (0, type_graphql_1.Field)({ nullable: true, description: 'PatchEntry.id this message triggered (if any).' }),
70
+ tslib_1.__metadata("design:type", String)
71
+ ], ChatMessage.prototype, "relatedPatchId", void 0);
72
+ tslib_1.__decorate([
73
+ (0, typeorm_1.Column)({ nullable: true }),
74
+ (0, type_graphql_1.Field)({ nullable: true, description: 'ImportSession.id this message triggered (if any).' }),
75
+ tslib_1.__metadata("design:type", String)
76
+ ], ChatMessage.prototype, "relatedImportSessionId", void 0);
77
+ tslib_1.__decorate([
78
+ (0, typeorm_1.Column)({
79
+ type: DATABASE_TYPE == 'mysql' || DATABASE_TYPE == 'mariadb'
80
+ ? 'longtext'
81
+ : DATABASE_TYPE == 'oracle'
82
+ ? 'clob'
83
+ : DATABASE_TYPE == 'mssql'
84
+ ? 'nvarchar'
85
+ : 'text',
86
+ length: DATABASE_TYPE == 'mssql' ? 'MAX' : undefined,
87
+ nullable: true
88
+ }),
89
+ tslib_1.__metadata("design:type", String)
90
+ ], ChatMessage.prototype, "toolUsages", void 0);
91
+ tslib_1.__decorate([
92
+ (0, type_graphql_1.Field)(() => graphql_scalars_1.GraphQLJSON, {
93
+ nullable: true,
94
+ description: 'Tool usage trace — array of {name, arguments, result, kind}. Only on assistant messages.'
95
+ }),
96
+ tslib_1.__metadata("design:type", Object),
97
+ tslib_1.__metadata("design:paramtypes", [])
98
+ ], ChatMessage.prototype, "toolUsagesJson", null);
99
+ tslib_1.__decorate([
100
+ (0, typeorm_1.ManyToOne)(type => auth_base_1.User, { nullable: true }),
101
+ (0, type_graphql_1.Field)(type => auth_base_1.User, { nullable: true, description: 'User who triggered this message.' }),
102
+ tslib_1.__metadata("design:type", auth_base_1.User)
103
+ ], ChatMessage.prototype, "creator", void 0);
104
+ tslib_1.__decorate([
105
+ (0, typeorm_1.RelationId)((message) => message.creator),
106
+ tslib_1.__metadata("design:type", String)
107
+ ], ChatMessage.prototype, "creatorId", void 0);
108
+ tslib_1.__decorate([
109
+ (0, typeorm_1.ManyToOne)(type => auth_base_1.User, { nullable: true }),
110
+ (0, type_graphql_1.Field)(type => auth_base_1.User, { nullable: true, description: 'Last user to update this message (for future edit support).' }),
111
+ tslib_1.__metadata("design:type", auth_base_1.User)
112
+ ], ChatMessage.prototype, "updater", void 0);
113
+ tslib_1.__decorate([
114
+ (0, typeorm_1.RelationId)((message) => message.updater),
115
+ tslib_1.__metadata("design:type", String)
116
+ ], ChatMessage.prototype, "updaterId", void 0);
117
+ tslib_1.__decorate([
118
+ (0, typeorm_1.ManyToOne)(type => ChatMessage, { nullable: true, onDelete: 'SET NULL' }),
119
+ tslib_1.__metadata("design:type", ChatMessage)
120
+ ], ChatMessage.prototype, "parentMessage", void 0);
121
+ tslib_1.__decorate([
122
+ (0, typeorm_1.RelationId)((message) => message.parentMessage),
123
+ (0, type_graphql_1.Field)({
124
+ nullable: true,
125
+ description: 'Id of the message this one is in-response-to / continues. Enables linear / branching / tree structures.'
126
+ }),
127
+ tslib_1.__metadata("design:type", String)
128
+ ], ChatMessage.prototype, "parentMessageId", void 0);
129
+ tslib_1.__decorate([
130
+ (0, typeorm_1.CreateDateColumn)(),
131
+ (0, type_graphql_1.Field)({ nullable: true, description: 'Creation timestamp.' }),
132
+ tslib_1.__metadata("design:type", Date)
133
+ ], ChatMessage.prototype, "createdAt", void 0);
134
+ tslib_1.__decorate([
135
+ (0, typeorm_1.UpdateDateColumn)(),
136
+ (0, type_graphql_1.Field)({ nullable: true, description: 'Last update timestamp (relevant once message editing is supported).' }),
137
+ tslib_1.__metadata("design:type", Date)
138
+ ], ChatMessage.prototype, "updatedAt", void 0);
139
+ tslib_1.__decorate([
140
+ (0, typeorm_1.DeleteDateColumn)(),
141
+ (0, type_graphql_1.Field)({ nullable: true, description: 'Soft delete timestamp.' }),
142
+ tslib_1.__metadata("design:type", Date)
143
+ ], ChatMessage.prototype, "deletedAt", void 0);
144
+ exports.ChatMessage = ChatMessage = tslib_1.__decorate([
145
+ (0, typeorm_1.Entity)(),
146
+ (0, typeorm_1.Index)('ix_chat_message_1', (message) => [message.session, message.createdAt]),
147
+ (0, type_graphql_1.ObjectType)({ description: 'A single chat message in a ChatSession.' })
148
+ ], ChatMessage);
149
+ //# sourceMappingURL=chat-message.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"chat-message.js","sourceRoot":"","sources":["../../../server/service/chat-message/chat-message.ts"],"names":[],"mappings":"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","sourcesContent":["/**\n * ChatMessage — ChatSession 의 한 메시지.\n *\n * role: 'user' | 'assistant' | 'system'\n * 'system' 은 사용자 직접 편집/import 진행 등 시스템이 자동 생성하는 컨텍스트 메시지.\n *\n * relatedPatchId / relatedImportSessionId 로 메시지가 트리거한 패치·임포트와 연결.\n */\nimport {\n Column,\n CreateDateColumn,\n DeleteDateColumn,\n Entity,\n Index,\n ManyToOne,\n PrimaryGeneratedColumn,\n RelationId,\n UpdateDateColumn\n} from 'typeorm'\nimport { Field, ID, ObjectType } from 'type-graphql'\nimport { GraphQLJSON } from 'graphql-scalars'\n\nimport { User } from '@things-factory/auth-base'\nimport { config } from '@things-factory/env'\n\nimport { ChatSession } from '../chat-session/chat-session.js'\n\nconst ORMCONFIG = config.get('ormconfig', {})\nconst DATABASE_TYPE = ORMCONFIG.type\n\n@Entity()\n@Index('ix_chat_message_1', (message: ChatMessage) => [message.session, message.createdAt])\n@ObjectType({ description: 'A single chat message in a ChatSession.' })\nexport class ChatMessage {\n @PrimaryGeneratedColumn('uuid')\n @Field(type => ID, { nullable: true })\n readonly id?: string\n\n @ManyToOne(type => ChatSession, session => session.messages, { onDelete: 'CASCADE' })\n session?: ChatSession\n\n @RelationId((message: ChatMessage) => message.session)\n sessionId?: string\n\n @Column({ type: 'varchar', length: 16 })\n @Field({ description: \"'user' | 'assistant' | 'system'\" })\n role!: string\n\n @Column({\n type:\n DATABASE_TYPE == 'mysql' || DATABASE_TYPE == 'mariadb'\n ? 'longtext'\n : DATABASE_TYPE == 'oracle'\n ? 'clob'\n : DATABASE_TYPE == 'mssql'\n ? 'nvarchar'\n : 'text',\n length: DATABASE_TYPE == 'mssql' ? 'MAX' : undefined\n })\n @Field({ description: 'Message content' })\n content!: string\n\n @Column({ nullable: true })\n @Field({ nullable: true, description: 'PatchEntry.id this message triggered (if any).' })\n relatedPatchId?: string\n\n @Column({ nullable: true })\n @Field({ nullable: true, description: 'ImportSession.id this message triggered (if any).' })\n relatedImportSessionId?: string\n\n /**\n * AI 가 응답을 만드는 동안 호출한 도구 trace — JSON-stringified.\n *\n * 컬럼은 string (PatchEntry.ops 와 동일 패턴), GraphQL 노출은 toolUsagesJson getter\n * 로 parse 된 객체. UI 의 fold-able 박스 (\"AI 가 이런 도구를 사용했습니다\") 가\n * 페이지 reload / loadHistory 후에도 살아있도록 영속.\n *\n * 형태: ToolUsage[] (assistant.ts 의 시간순 trace, summarizeToolResult 로 압축).\n * null 이면 도구 호출 없었던 메시지 (text-only 응답).\n */\n @Column({\n type:\n DATABASE_TYPE == 'mysql' || DATABASE_TYPE == 'mariadb'\n ? 'longtext'\n : DATABASE_TYPE == 'oracle'\n ? 'clob'\n : DATABASE_TYPE == 'mssql'\n ? 'nvarchar'\n : 'text',\n length: DATABASE_TYPE == 'mssql' ? 'MAX' : undefined,\n nullable: true\n })\n toolUsages?: string\n\n /** GraphQL 노출용 — JSON 배열로 parse. */\n @Field(() => GraphQLJSON, {\n nullable: true,\n description:\n 'Tool usage trace — array of {name, arguments, result, kind}. Only on assistant messages.'\n })\n get toolUsagesJson(): any {\n if (!this.toolUsages) return null\n try {\n return JSON.parse(this.toolUsages)\n } catch {\n return null\n }\n }\n\n /**\n * 메시지를 일으킨 사용자.\n * - role='user' → 보낸 사용자\n * - role='assistant' → 그 응답을 트리거한 사용자 (직전 user 메시지의 작성자)\n * - role='system' → 시스템 액션을 일으킨 사용자 (예: 직접 편집한 사용자)\n *\n * nullable — legacy 메시지 (이 필드 추가 이전에 작성) 는 null. 또한 ad-hoc 모드 / 시스템\n * 자동 메시지 중 사용자 컨텍스트가 없는 경우도 null 가능.\n */\n @ManyToOne(type => User, { nullable: true })\n @Field(type => User, { nullable: true, description: 'User who triggered this message.' })\n creator?: User\n\n @RelationId((message: ChatMessage) => message.creator)\n creatorId?: string\n\n @ManyToOne(type => User, { nullable: true })\n @Field(type => User, { nullable: true, description: 'Last user to update this message (for future edit support).' })\n updater?: User\n\n @RelationId((message: ChatMessage) => message.updater)\n updaterId?: string\n\n /**\n * 부모 메시지 — 이 메시지가 \"응답하는 대상\" / \"이어가는 메시지\" 의 id.\n *\n * 의미 (role 별):\n * - 'user' → 직전 in-session 메시지 (보통 assistant 또는 system). 첫 turn 은 null.\n * - 'assistant' → 이 응답이 답하는 user 메시지. (regenerate 로 같은 user 메시지를 부모로\n * 하는 형제 assistant 메시지가 생기면 자연스럽게 branching tree 가 됨)\n * - 'system' → 직전 in-session 메시지 (timeline 연속성 유지).\n *\n * 이 한 컬럼으로 향후 어떤 흐름이든 표현 가능 — linear chain / branching (regenerate) /\n * tree (replies-to-specific-message) 등. UI/쿼리는 점진 도입.\n *\n * onDelete: 'SET NULL' — 부모 메시지가 삭제돼도 child 는 남되 dangling 마킹.\n */\n @ManyToOne(type => ChatMessage, { nullable: true, onDelete: 'SET NULL' })\n parentMessage?: ChatMessage\n\n @RelationId((message: ChatMessage) => message.parentMessage)\n @Field({\n nullable: true,\n description:\n 'Id of the message this one is in-response-to / continues. Enables linear / branching / tree structures.'\n })\n parentMessageId?: string\n\n @CreateDateColumn()\n @Field({ nullable: true, description: 'Creation timestamp.' })\n createdAt?: Date\n\n @UpdateDateColumn()\n @Field({ nullable: true, description: 'Last update timestamp (relevant once message editing is supported).' })\n updatedAt?: Date\n\n @DeleteDateColumn()\n @Field({ nullable: true, description: 'Soft delete timestamp.' })\n deletedAt?: Date\n}\n"]}
@@ -0,0 +1,5 @@
1
+ import { ChatMessage } from './chat-message.js';
2
+ export { ChatMessage };
3
+ export { BoardChatMessageSubscription, publishChatMessage, CHAT_MESSAGE_TOPIC, chatMessageFilter } from './chat-message-subscription.js';
4
+ export type { ChatMessagePayload } from './chat-message-subscription.js';
5
+ export declare const entities: (typeof ChatMessage)[];
@@ -0,0 +1,12 @@
1
+ "use strict";
2
+ Object.defineProperty(exports, "__esModule", { value: true });
3
+ exports.entities = exports.chatMessageFilter = exports.CHAT_MESSAGE_TOPIC = exports.publishChatMessage = exports.BoardChatMessageSubscription = exports.ChatMessage = void 0;
4
+ const chat_message_js_1 = require("./chat-message.js");
5
+ Object.defineProperty(exports, "ChatMessage", { enumerable: true, get: function () { return chat_message_js_1.ChatMessage; } });
6
+ var chat_message_subscription_js_1 = require("./chat-message-subscription.js");
7
+ Object.defineProperty(exports, "BoardChatMessageSubscription", { enumerable: true, get: function () { return chat_message_subscription_js_1.BoardChatMessageSubscription; } });
8
+ Object.defineProperty(exports, "publishChatMessage", { enumerable: true, get: function () { return chat_message_subscription_js_1.publishChatMessage; } });
9
+ Object.defineProperty(exports, "CHAT_MESSAGE_TOPIC", { enumerable: true, get: function () { return chat_message_subscription_js_1.CHAT_MESSAGE_TOPIC; } });
10
+ Object.defineProperty(exports, "chatMessageFilter", { enumerable: true, get: function () { return chat_message_subscription_js_1.chatMessageFilter; } });
11
+ exports.entities = [chat_message_js_1.ChatMessage];
12
+ //# sourceMappingURL=index.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"index.js","sourceRoot":"","sources":["../../../server/service/chat-message/index.ts"],"names":[],"mappings":";;;AAAA,uDAA+C;AAEtC,4FAFA,6BAAW,OAEA;AACpB,+EAKuC;AAJrC,4IAAA,4BAA4B,OAAA;AAC5B,kIAAA,kBAAkB,OAAA;AAClB,kIAAA,kBAAkB,OAAA;AAClB,iIAAA,iBAAiB,OAAA;AAIN,QAAA,QAAQ,GAAG,CAAC,6BAAW,CAAC,CAAA","sourcesContent":["import { ChatMessage } from './chat-message.js'\n\nexport { ChatMessage }\nexport {\n BoardChatMessageSubscription,\n publishChatMessage,\n CHAT_MESSAGE_TOPIC,\n chatMessageFilter\n} from './chat-message-subscription.js'\nexport type { ChatMessagePayload } from './chat-message-subscription.js'\n\nexport const entities = [ChatMessage]\n"]}
@@ -0,0 +1,31 @@
1
+ import { Domain } from '@things-factory/shell';
2
+ import { User } from '@things-factory/auth-base';
3
+ import { ChatMessage } from '../chat-message/chat-message.js';
4
+ import { PatchEntry } from '../patch-entry/patch-entry.js';
5
+ export declare class ChatSession {
6
+ readonly id?: string;
7
+ domain?: Domain;
8
+ domainId?: string;
9
+ /** Board.id 와 연결. Board 가 owning side 가 될 예정. 1:N — 한 보드에 여러 세션 가능. */
10
+ boardId?: string;
11
+ /**
12
+ * 세션의 사용자 정의 이름 (탭 레이블 / 세션 식별 표시용).
13
+ *
14
+ * nullable — 미설정 시 UI 가 fallback 라벨 ("세션 N" 또는 createdAt 기반) 사용. 사용자가
15
+ * 다중 세션 운영 시 의미 부여 (예: "초기 설계", "운영 시뮬레이션", "사용자A 의 사적 세션").
16
+ */
17
+ name?: string;
18
+ creator?: User;
19
+ creatorId?: string;
20
+ updater?: User;
21
+ updaterId?: string;
22
+ /** 토큰 절감용 — 오래된 메시지를 LLM 으로 압축한 요약. Phase 2 에서 작성. */
23
+ lastSummary?: string;
24
+ /** 사용 모델 식별 — 'anthropic:claude-sonnet-4-6' 등 */
25
+ aiClientId?: string;
26
+ createdAt?: Date;
27
+ updatedAt?: Date;
28
+ deletedAt?: Date;
29
+ messages?: ChatMessage[];
30
+ patches?: PatchEntry[];
31
+ }
@@ -0,0 +1,131 @@
1
+ "use strict";
2
+ Object.defineProperty(exports, "__esModule", { value: true });
3
+ exports.ChatSession = void 0;
4
+ const tslib_1 = require("tslib");
5
+ /**
6
+ * ChatSession — Board 와 결합되는 AI 협력 세션.
7
+ *
8
+ * 한 보드에 여러 세션 가능 — DB 레벨 unique 제약 없음.
9
+ *
10
+ * 향후 폭증할 세션 분화 차원 (예: thread / 사용자별 / 컨텍스트별 design vs ops /
11
+ * archived / forked from clone / agent별) 을 미리 차단하지 않기 위해 구조 자체는 1:N
12
+ * 으로 열어둠. 단일 세션 정책 (현재 UX) 은 app 레벨 idempotent 로직 — `startBoardAISession`
13
+ * 이 boardId 매칭 시 기존 세션 반환, `chatSessionByBoard` 가 첫 매칭 반환.
14
+ *
15
+ * 미래에 다중 세션 활성화 시 discriminator 컬럼 (kind / name / threadId / creatorId 등)
16
+ * 을 그때 추가. 마이그레이션 부담 최소화 — 현재는 unique 만 풀어 자리 마련.
17
+ *
18
+ * board-service 의 Board 가 owning side 가 될 예정 (ChatSession FK).
19
+ */
20
+ const typeorm_1 = require("typeorm");
21
+ const type_graphql_1 = require("type-graphql");
22
+ const shell_1 = require("@things-factory/shell");
23
+ const auth_base_1 = require("@things-factory/auth-base");
24
+ const env_1 = require("@things-factory/env");
25
+ const chat_message_js_1 = require("../chat-message/chat-message.js");
26
+ const patch_entry_js_1 = require("../patch-entry/patch-entry.js");
27
+ const ORMCONFIG = env_1.config.get('ormconfig', {});
28
+ const DATABASE_TYPE = ORMCONFIG.type;
29
+ let ChatSession = class ChatSession {
30
+ };
31
+ exports.ChatSession = ChatSession;
32
+ tslib_1.__decorate([
33
+ (0, typeorm_1.PrimaryGeneratedColumn)('uuid'),
34
+ (0, type_graphql_1.Field)(type => type_graphql_1.ID, { nullable: true }),
35
+ tslib_1.__metadata("design:type", String)
36
+ ], ChatSession.prototype, "id", void 0);
37
+ tslib_1.__decorate([
38
+ (0, typeorm_1.ManyToOne)(type => shell_1.Domain),
39
+ (0, type_graphql_1.Field)(type => shell_1.Domain, { nullable: true }),
40
+ tslib_1.__metadata("design:type", shell_1.Domain)
41
+ ], ChatSession.prototype, "domain", void 0);
42
+ tslib_1.__decorate([
43
+ (0, typeorm_1.RelationId)((session) => session.domain),
44
+ tslib_1.__metadata("design:type", String)
45
+ ], ChatSession.prototype, "domainId", void 0);
46
+ tslib_1.__decorate([
47
+ (0, typeorm_1.Column)({ nullable: true }),
48
+ (0, type_graphql_1.Field)({
49
+ nullable: true,
50
+ description: 'Connected Board id. Multiple sessions per board allowed (future: threads / per-user / contexts).'
51
+ }),
52
+ tslib_1.__metadata("design:type", String)
53
+ ], ChatSession.prototype, "boardId", void 0);
54
+ tslib_1.__decorate([
55
+ (0, typeorm_1.Column)({ nullable: true, length: 200 }),
56
+ (0, type_graphql_1.Field)({ nullable: true, description: 'User-given name of this session (tab label / identification).' }),
57
+ tslib_1.__metadata("design:type", String)
58
+ ], ChatSession.prototype, "name", void 0);
59
+ tslib_1.__decorate([
60
+ (0, typeorm_1.ManyToOne)(type => auth_base_1.User),
61
+ (0, type_graphql_1.Field)(type => auth_base_1.User, { nullable: true, description: 'User who created this session.' }),
62
+ tslib_1.__metadata("design:type", auth_base_1.User)
63
+ ], ChatSession.prototype, "creator", void 0);
64
+ tslib_1.__decorate([
65
+ (0, typeorm_1.RelationId)((session) => session.creator),
66
+ tslib_1.__metadata("design:type", String)
67
+ ], ChatSession.prototype, "creatorId", void 0);
68
+ tslib_1.__decorate([
69
+ (0, typeorm_1.ManyToOne)(type => auth_base_1.User),
70
+ (0, type_graphql_1.Field)(type => auth_base_1.User, { nullable: true, description: 'User who last updated this session.' }),
71
+ tslib_1.__metadata("design:type", auth_base_1.User)
72
+ ], ChatSession.prototype, "updater", void 0);
73
+ tslib_1.__decorate([
74
+ (0, typeorm_1.RelationId)((session) => session.updater),
75
+ tslib_1.__metadata("design:type", String)
76
+ ], ChatSession.prototype, "updaterId", void 0);
77
+ tslib_1.__decorate([
78
+ (0, typeorm_1.Column)({
79
+ nullable: true,
80
+ type: DATABASE_TYPE == 'mysql' || DATABASE_TYPE == 'mariadb'
81
+ ? 'longtext'
82
+ : DATABASE_TYPE == 'oracle'
83
+ ? 'clob'
84
+ : DATABASE_TYPE == 'mssql'
85
+ ? 'nvarchar'
86
+ : 'text',
87
+ length: DATABASE_TYPE == 'mssql' ? 'MAX' : undefined
88
+ }),
89
+ (0, type_graphql_1.Field)({ nullable: true, description: 'Compressed summary of older messages (for token saving).' }),
90
+ tslib_1.__metadata("design:type", String)
91
+ ], ChatSession.prototype, "lastSummary", void 0);
92
+ tslib_1.__decorate([
93
+ (0, typeorm_1.Column)({ nullable: true }),
94
+ (0, type_graphql_1.Field)({ nullable: true }),
95
+ tslib_1.__metadata("design:type", String)
96
+ ], ChatSession.prototype, "aiClientId", void 0);
97
+ tslib_1.__decorate([
98
+ (0, typeorm_1.CreateDateColumn)(),
99
+ (0, type_graphql_1.Field)({ nullable: true }),
100
+ tslib_1.__metadata("design:type", Date)
101
+ ], ChatSession.prototype, "createdAt", void 0);
102
+ tslib_1.__decorate([
103
+ (0, typeorm_1.UpdateDateColumn)(),
104
+ (0, type_graphql_1.Field)({ nullable: true }),
105
+ tslib_1.__metadata("design:type", Date)
106
+ ], ChatSession.prototype, "updatedAt", void 0);
107
+ tslib_1.__decorate([
108
+ (0, typeorm_1.DeleteDateColumn)(),
109
+ tslib_1.__metadata("design:type", Date
110
+ // ── 관계 (TypeORM 만, GraphQL 노출은 별도 query 통해 페이징) ──
111
+ )
112
+ ], ChatSession.prototype, "deletedAt", void 0);
113
+ tslib_1.__decorate([
114
+ (0, typeorm_1.OneToMany)(type => chat_message_js_1.ChatMessage, message => message.session),
115
+ tslib_1.__metadata("design:type", Array)
116
+ ], ChatSession.prototype, "messages", void 0);
117
+ tslib_1.__decorate([
118
+ (0, typeorm_1.OneToMany)(type => patch_entry_js_1.PatchEntry, patch => patch.session),
119
+ tslib_1.__metadata("design:type", Array)
120
+ ], ChatSession.prototype, "patches", void 0);
121
+ exports.ChatSession = ChatSession = tslib_1.__decorate([
122
+ (0, typeorm_1.Entity)()
123
+ // 인덱스는 조회 성능용으로 유지 (chatSessionByBoard 가 [domain, boardId] 로 자주 쿼리).
124
+ // unique 제약은 의도적으로 제거 — 한 보드에 여러 세션을 미래에 허용하기 위함.
125
+ ,
126
+ (0, typeorm_1.Index)('ix_chat_session_1', (session) => [session.domain, session.boardId]),
127
+ (0, type_graphql_1.ObjectType)({
128
+ description: 'AI 협력 세션 — Board 와 결합. 한 보드에 여러 세션 가능 (thread / 사용자별 / 컨텍스트별 등 미래 확장).'
129
+ })
130
+ ], ChatSession);
131
+ //# sourceMappingURL=chat-session.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"chat-session.js","sourceRoot":"","sources":["../../../server/service/chat-session/chat-session.ts"],"names":[],"mappings":"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","sourcesContent":["/**\n * ChatSession — Board 와 결합되는 AI 협력 세션.\n *\n * 한 보드에 여러 세션 가능 — DB 레벨 unique 제약 없음.\n *\n * 향후 폭증할 세션 분화 차원 (예: thread / 사용자별 / 컨텍스트별 design vs ops /\n * archived / forked from clone / agent별) 을 미리 차단하지 않기 위해 구조 자체는 1:N\n * 으로 열어둠. 단일 세션 정책 (현재 UX) 은 app 레벨 idempotent 로직 — `startBoardAISession`\n * 이 boardId 매칭 시 기존 세션 반환, `chatSessionByBoard` 가 첫 매칭 반환.\n *\n * 미래에 다중 세션 활성화 시 discriminator 컬럼 (kind / name / threadId / creatorId 등)\n * 을 그때 추가. 마이그레이션 부담 최소화 — 현재는 unique 만 풀어 자리 마련.\n *\n * board-service 의 Board 가 owning side 가 될 예정 (ChatSession FK).\n */\nimport {\n Column,\n CreateDateColumn,\n DeleteDateColumn,\n Entity,\n Index,\n ManyToOne,\n OneToMany,\n PrimaryGeneratedColumn,\n RelationId,\n UpdateDateColumn\n} from 'typeorm'\nimport { Field, ID, ObjectType } from 'type-graphql'\n\nimport { Domain } from '@things-factory/shell'\nimport { User } from '@things-factory/auth-base'\nimport { config } from '@things-factory/env'\n\nimport { ChatMessage } from '../chat-message/chat-message.js'\nimport { PatchEntry } from '../patch-entry/patch-entry.js'\n\nconst ORMCONFIG = config.get('ormconfig', {})\nconst DATABASE_TYPE = ORMCONFIG.type\n\n@Entity()\n// 인덱스는 조회 성능용으로 유지 (chatSessionByBoard 가 [domain, boardId] 로 자주 쿼리).\n// unique 제약은 의도적으로 제거 — 한 보드에 여러 세션을 미래에 허용하기 위함.\n@Index('ix_chat_session_1', (session: ChatSession) => [session.domain, session.boardId])\n@ObjectType({\n description: 'AI 협력 세션 — Board 와 결합. 한 보드에 여러 세션 가능 (thread / 사용자별 / 컨텍스트별 등 미래 확장).'\n})\nexport class ChatSession {\n @PrimaryGeneratedColumn('uuid')\n @Field(type => ID, { nullable: true })\n readonly id?: string\n\n @ManyToOne(type => Domain)\n @Field(type => Domain, { nullable: true })\n domain?: Domain\n\n @RelationId((session: ChatSession) => session.domain)\n domainId?: string\n\n /** Board.id 와 연결. Board 가 owning side 가 될 예정. 1:N — 한 보드에 여러 세션 가능. */\n @Column({ nullable: true })\n @Field({\n nullable: true,\n description:\n 'Connected Board id. Multiple sessions per board allowed (future: threads / per-user / contexts).'\n })\n boardId?: string\n\n /**\n * 세션의 사용자 정의 이름 (탭 레이블 / 세션 식별 표시용).\n *\n * nullable — 미설정 시 UI 가 fallback 라벨 (\"세션 N\" 또는 createdAt 기반) 사용. 사용자가\n * 다중 세션 운영 시 의미 부여 (예: \"초기 설계\", \"운영 시뮬레이션\", \"사용자A 의 사적 세션\").\n */\n @Column({ nullable: true, length: 200 })\n @Field({ nullable: true, description: 'User-given name of this session (tab label / identification).' })\n name?: string\n\n @ManyToOne(type => User)\n @Field(type => User, { nullable: true, description: 'User who created this session.' })\n creator?: User\n\n @RelationId((session: ChatSession) => session.creator)\n creatorId?: string\n\n @ManyToOne(type => User)\n @Field(type => User, { nullable: true, description: 'User who last updated this session.' })\n updater?: User\n\n @RelationId((session: ChatSession) => session.updater)\n updaterId?: string\n\n /** 토큰 절감용 — 오래된 메시지를 LLM 으로 압축한 요약. Phase 2 에서 작성. */\n @Column({\n nullable: true,\n type:\n DATABASE_TYPE == 'mysql' || DATABASE_TYPE == 'mariadb'\n ? 'longtext'\n : DATABASE_TYPE == 'oracle'\n ? 'clob'\n : DATABASE_TYPE == 'mssql'\n ? 'nvarchar'\n : 'text',\n length: DATABASE_TYPE == 'mssql' ? 'MAX' : undefined\n })\n @Field({ nullable: true, description: 'Compressed summary of older messages (for token saving).' })\n lastSummary?: string\n\n /** 사용 모델 식별 — 'anthropic:claude-sonnet-4-6' 등 */\n @Column({ nullable: true })\n @Field({ nullable: true })\n aiClientId?: string\n\n @CreateDateColumn()\n @Field({ nullable: true })\n createdAt?: Date\n\n @UpdateDateColumn()\n @Field({ nullable: true })\n updatedAt?: Date\n\n @DeleteDateColumn()\n deletedAt?: Date\n\n // ── 관계 (TypeORM 만, GraphQL 노출은 별도 query 통해 페이징) ──\n @OneToMany(type => ChatMessage, message => message.session)\n messages?: ChatMessage[]\n\n @OneToMany(type => PatchEntry, patch => patch.session)\n patches?: PatchEntry[]\n}\n"]}
@@ -0,0 +1,3 @@
1
+ import { ChatSession } from './chat-session.js';
2
+ export { ChatSession };
3
+ export declare const entities: (typeof ChatSession)[];
@@ -0,0 +1,7 @@
1
+ "use strict";
2
+ Object.defineProperty(exports, "__esModule", { value: true });
3
+ exports.entities = exports.ChatSession = void 0;
4
+ const chat_session_js_1 = require("./chat-session.js");
5
+ Object.defineProperty(exports, "ChatSession", { enumerable: true, get: function () { return chat_session_js_1.ChatSession; } });
6
+ exports.entities = [chat_session_js_1.ChatSession];
7
+ //# sourceMappingURL=index.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"index.js","sourceRoot":"","sources":["../../../server/service/chat-session/index.ts"],"names":[],"mappings":";;;AAAA,uDAA+C;AAEtC,4FAFA,6BAAW,OAEA;AAEP,QAAA,QAAQ,GAAG,CAAC,6BAAW,CAAC,CAAA","sourcesContent":["import { ChatSession } from './chat-session.js'\n\nexport { ChatSession }\n\nexport const entities = [ChatSession]\n"]}
@@ -0,0 +1,30 @@
1
+ import { Domain } from '@things-factory/shell';
2
+ import { User } from '@things-factory/auth-base';
3
+ import { ChatSession } from '../chat-session/chat-session.js';
4
+ export declare class ChatSessionParticipant {
5
+ readonly id?: string;
6
+ domain?: Domain;
7
+ domainId?: string;
8
+ session?: ChatSession;
9
+ sessionId?: string;
10
+ user?: User;
11
+ userId?: string;
12
+ /**
13
+ * 참여자의 역할.
14
+ * - 'owner': 세션 만든 사람. rename / delete 권한.
15
+ * - 'member': 일반 참여자. 메시지 송수신.
16
+ * - 'viewer': 읽기 전용 (미래 권한 정책 활성화 시).
17
+ *
18
+ * 시작은 'owner' / 'member' 둘로 충분. 더 세분화 필요해지면 enum 확장.
19
+ */
20
+ role: string;
21
+ /** 마지막 활동 시각 — presence indicator. nullable. */
22
+ lastSeenAt?: Date;
23
+ creator?: User;
24
+ creatorId?: string;
25
+ updater?: User;
26
+ updaterId?: string;
27
+ createdAt?: Date;
28
+ updatedAt?: Date;
29
+ deletedAt?: Date;
30
+ }