@rubytech/create-sitedesk-code 0.1.521 → 0.1.522

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 (255) hide show
  1. package/dist/index.js +17 -3
  2. package/package.json +1 -1
  3. package/payload/platform/lib/account-schema-regions/package-lock.json +12 -0
  4. package/payload/platform/lib/active-rules/package-lock.json +12 -0
  5. package/payload/platform/lib/mcp-lifeline/package-lock.json +12 -0
  6. package/payload/platform/plugins/admin/skills/platform-architecture/SKILL.md +43 -6
  7. package/payload/platform/plugins/admin/skills/whats-new/SKILL.md +6 -0
  8. package/payload/platform/plugins/docs/references/admin-ui.md +10 -0
  9. package/payload/platform/plugins/docs/references/internals.md +4 -0
  10. package/payload/platform/plugins/docs/references/outlook-guide.md +27 -4
  11. package/payload/platform/plugins/outlook/.claude-plugin/plugin.json +1 -1
  12. package/payload/platform/plugins/outlook/PLUGIN.md +9 -1
  13. package/payload/platform/plugins/outlook/mcp/dist/__tests__/delegated-resolve.test.d.ts +2 -0
  14. package/payload/platform/plugins/outlook/mcp/dist/__tests__/delegated-resolve.test.d.ts.map +1 -0
  15. package/payload/platform/plugins/outlook/mcp/dist/__tests__/delegated-resolve.test.js +151 -0
  16. package/payload/platform/plugins/outlook/mcp/dist/__tests__/delegated-resolve.test.js.map +1 -0
  17. package/payload/platform/plugins/outlook/mcp/dist/__tests__/delegated-store.test.d.ts +2 -0
  18. package/payload/platform/plugins/outlook/mcp/dist/__tests__/delegated-store.test.d.ts.map +1 -0
  19. package/payload/platform/plugins/outlook/mcp/dist/__tests__/delegated-store.test.js +151 -0
  20. package/payload/platform/plugins/outlook/mcp/dist/__tests__/delegated-store.test.js.map +1 -0
  21. package/payload/platform/plugins/outlook/mcp/dist/__tests__/device-flow.test.js +38 -4
  22. package/payload/platform/plugins/outlook/mcp/dist/__tests__/device-flow.test.js.map +1 -1
  23. package/payload/platform/plugins/outlook/mcp/dist/__tests__/graph-client-prefix-wiring.test.d.ts +2 -0
  24. package/payload/platform/plugins/outlook/mcp/dist/__tests__/graph-client-prefix-wiring.test.d.ts.map +1 -0
  25. package/payload/platform/plugins/outlook/mcp/dist/__tests__/graph-client-prefix-wiring.test.js +146 -0
  26. package/payload/platform/plugins/outlook/mcp/dist/__tests__/graph-client-prefix-wiring.test.js.map +1 -0
  27. package/payload/platform/plugins/outlook/mcp/dist/__tests__/mailbox-list-delegated.test.d.ts +2 -0
  28. package/payload/platform/plugins/outlook/mcp/dist/__tests__/mailbox-list-delegated.test.d.ts.map +1 -0
  29. package/payload/platform/plugins/outlook/mcp/dist/__tests__/mailbox-list-delegated.test.js +120 -0
  30. package/payload/platform/plugins/outlook/mcp/dist/__tests__/mailbox-list-delegated.test.js.map +1 -0
  31. package/payload/platform/plugins/outlook/mcp/dist/__tests__/mailbox-list.test.js +8 -8
  32. package/payload/platform/plugins/outlook/mcp/dist/__tests__/mailbox-list.test.js.map +1 -1
  33. package/payload/platform/plugins/outlook/mcp/dist/__tests__/mailbox-path-prefix.test.d.ts +2 -0
  34. package/payload/platform/plugins/outlook/mcp/dist/__tests__/mailbox-path-prefix.test.d.ts.map +1 -0
  35. package/payload/platform/plugins/outlook/mcp/dist/__tests__/mailbox-path-prefix.test.js +27 -0
  36. package/payload/platform/plugins/outlook/mcp/dist/__tests__/mailbox-path-prefix.test.js.map +1 -0
  37. package/payload/platform/plugins/outlook/mcp/dist/__tests__/shared-mail-only-guard.test.d.ts +2 -0
  38. package/payload/platform/plugins/outlook/mcp/dist/__tests__/shared-mail-only-guard.test.d.ts.map +1 -0
  39. package/payload/platform/plugins/outlook/mcp/dist/__tests__/shared-mail-only-guard.test.js +70 -0
  40. package/payload/platform/plugins/outlook/mcp/dist/__tests__/shared-mail-only-guard.test.js.map +1 -0
  41. package/payload/platform/plugins/outlook/mcp/dist/__tests__/shared-mailbox-add.test.d.ts +2 -0
  42. package/payload/platform/plugins/outlook/mcp/dist/__tests__/shared-mailbox-add.test.d.ts.map +1 -0
  43. package/payload/platform/plugins/outlook/mcp/dist/__tests__/shared-mailbox-add.test.js +152 -0
  44. package/payload/platform/plugins/outlook/mcp/dist/__tests__/shared-mailbox-add.test.js.map +1 -0
  45. package/payload/platform/plugins/outlook/mcp/dist/auth/delegated-store.d.ts +57 -0
  46. package/payload/platform/plugins/outlook/mcp/dist/auth/delegated-store.d.ts.map +1 -0
  47. package/payload/platform/plugins/outlook/mcp/dist/auth/delegated-store.js +163 -0
  48. package/payload/platform/plugins/outlook/mcp/dist/auth/delegated-store.js.map +1 -0
  49. package/payload/platform/plugins/outlook/mcp/dist/auth/device-flow.d.ts +12 -0
  50. package/payload/platform/plugins/outlook/mcp/dist/auth/device-flow.d.ts.map +1 -1
  51. package/payload/platform/plugins/outlook/mcp/dist/auth/device-flow.js +21 -1
  52. package/payload/platform/plugins/outlook/mcp/dist/auth/device-flow.js.map +1 -1
  53. package/payload/platform/plugins/outlook/mcp/dist/auth/mailbox-registry.d.ts +35 -4
  54. package/payload/platform/plugins/outlook/mcp/dist/auth/mailbox-registry.d.ts.map +1 -1
  55. package/payload/platform/plugins/outlook/mcp/dist/auth/mailbox-registry.js +92 -10
  56. package/payload/platform/plugins/outlook/mcp/dist/auth/mailbox-registry.js.map +1 -1
  57. package/payload/platform/plugins/outlook/mcp/dist/index.js +106 -3
  58. package/payload/platform/plugins/outlook/mcp/dist/index.js.map +1 -1
  59. package/payload/platform/plugins/outlook/mcp/dist/lib/graph-client.d.ts +49 -0
  60. package/payload/platform/plugins/outlook/mcp/dist/lib/graph-client.d.ts.map +1 -1
  61. package/payload/platform/plugins/outlook/mcp/dist/lib/graph-client.js +126 -8
  62. package/payload/platform/plugins/outlook/mcp/dist/lib/graph-client.js.map +1 -1
  63. package/payload/platform/plugins/outlook/mcp/dist/tools/mailbox-info.d.ts +13 -0
  64. package/payload/platform/plugins/outlook/mcp/dist/tools/mailbox-info.d.ts.map +1 -1
  65. package/payload/platform/plugins/outlook/mcp/dist/tools/mailbox-info.js +9 -0
  66. package/payload/platform/plugins/outlook/mcp/dist/tools/mailbox-info.js.map +1 -1
  67. package/payload/platform/plugins/outlook/mcp/dist/tools/mailbox-list.d.ts +42 -8
  68. package/payload/platform/plugins/outlook/mcp/dist/tools/mailbox-list.d.ts.map +1 -1
  69. package/payload/platform/plugins/outlook/mcp/dist/tools/mailbox-list.js +59 -19
  70. package/payload/platform/plugins/outlook/mcp/dist/tools/mailbox-list.js.map +1 -1
  71. package/payload/platform/plugins/outlook/mcp/dist/tools/shared-mailbox-add.d.ts +47 -0
  72. package/payload/platform/plugins/outlook/mcp/dist/tools/shared-mailbox-add.d.ts.map +1 -0
  73. package/payload/platform/plugins/outlook/mcp/dist/tools/shared-mailbox-add.js +67 -0
  74. package/payload/platform/plugins/outlook/mcp/dist/tools/shared-mailbox-add.js.map +1 -0
  75. package/payload/platform/plugins/outlook/mcp/dist/tools/shared-mailbox-remove.d.ts +12 -0
  76. package/payload/platform/plugins/outlook/mcp/dist/tools/shared-mailbox-remove.d.ts.map +1 -0
  77. package/payload/platform/plugins/outlook/mcp/dist/tools/shared-mailbox-remove.js +18 -0
  78. package/payload/platform/plugins/outlook/mcp/dist/tools/shared-mailbox-remove.js.map +1 -0
  79. package/payload/platform/plugins/outlook/references/auth.md +15 -2
  80. package/payload/platform/plugins/outlook/references/graph-surfaces.md +8 -0
  81. package/payload/platform/plugins/outlook/skills/outlook/SKILL.md +21 -1
  82. package/payload/platform/services/claude-session-manager/dist/canonical-tool-names.generated.d.ts.map +1 -1
  83. package/payload/platform/services/claude-session-manager/dist/canonical-tool-names.generated.js +2 -0
  84. package/payload/platform/services/claude-session-manager/dist/canonical-tool-names.generated.js.map +1 -1
  85. package/payload/platform/templates/specialists/agents/personal-assistant.md +1 -1
  86. package/payload/server/{chunk-AZLT4LVO.js → chunk-K7CJGZPU.js} +419 -189
  87. package/payload/server/{manager-CQBSUJXR.js → manager-RKL7JZ4Y.js} +3 -1
  88. package/payload/server/public/activity.html +5 -5
  89. package/payload/server/public/agents.html +4 -4
  90. package/payload/server/public/assets/{AdminLoginScreens-Dar_MMJm.js → AdminLoginScreens-zc2_qqh-.js} +1 -1
  91. package/payload/server/public/assets/AdminLoginScreens-zc2_qqh-.js.br +0 -0
  92. package/payload/server/public/assets/AdminLoginScreens-zc2_qqh-.js.gz +0 -0
  93. package/payload/server/public/assets/{AdminShell-CpaI2F_p.js → AdminShell-IGUdTx5q.js} +1 -1
  94. package/payload/server/public/assets/AdminShell-IGUdTx5q.js.br +0 -0
  95. package/payload/server/public/assets/{AdminShell-CpaI2F_p.js.gz → AdminShell-IGUdTx5q.js.gz} +0 -0
  96. package/payload/server/public/assets/{activity-B1rt4GIy.js → activity-DVgO8YuM.js} +1 -1
  97. package/payload/server/public/assets/activity-DVgO8YuM.js.br +0 -0
  98. package/payload/server/public/assets/activity-DVgO8YuM.js.gz +0 -0
  99. package/payload/server/public/assets/admin-xtpM7fgl.js +1 -0
  100. package/payload/server/public/assets/admin-xtpM7fgl.js.br +0 -0
  101. package/payload/server/public/assets/admin-xtpM7fgl.js.gz +0 -0
  102. package/payload/server/public/assets/{agents-BXq8woVf.js → agents-P0nTIxo-.js} +1 -1
  103. package/payload/server/public/assets/agents-P0nTIxo-.js.br +0 -0
  104. package/payload/server/public/assets/agents-P0nTIxo-.js.gz +0 -0
  105. package/payload/server/public/assets/{browser-1QSCPl3X.js → browser-Mw7DY3ft.js} +1 -1
  106. package/payload/server/public/assets/browser-Mw7DY3ft.js.br +0 -0
  107. package/payload/server/public/assets/browser-Mw7DY3ft.js.gz +0 -0
  108. package/payload/server/public/assets/{calendar-D009qWVV.js → calendar-B9gvL_1_.js} +1 -1
  109. package/payload/server/public/assets/calendar-B9gvL_1_.js.br +0 -0
  110. package/payload/server/public/assets/calendar-B9gvL_1_.js.gz +0 -0
  111. package/payload/server/public/assets/chat-DBGqh4wg.js +1 -0
  112. package/payload/server/public/assets/chat-DBGqh4wg.js.br +2 -0
  113. package/payload/server/public/assets/chat-DBGqh4wg.js.gz +0 -0
  114. package/payload/server/public/assets/chevron-left-Bl4vpOM0.js +1 -0
  115. package/payload/server/public/assets/chevron-left-Bl4vpOM0.js.br +0 -0
  116. package/payload/server/public/assets/chevron-right-BExigCnp.js +1 -0
  117. package/payload/server/public/assets/chevron-right-BExigCnp.js.br +0 -0
  118. package/payload/server/public/assets/clock-D8TJvgJC.js +1 -0
  119. package/payload/server/public/assets/clock-D8TJvgJC.js.br +0 -0
  120. package/payload/server/public/assets/data-HfFSxaC2.js +1 -0
  121. package/payload/server/public/assets/data-HfFSxaC2.js.br +0 -0
  122. package/payload/server/public/assets/data-HfFSxaC2.js.gz +0 -0
  123. package/payload/server/public/assets/{file-text-DwGAfCsd.js → file-text-dYBnXNEX.js} +1 -1
  124. package/payload/server/public/assets/file-text-dYBnXNEX.js.br +0 -0
  125. package/payload/server/public/assets/file-text-dYBnXNEX.js.gz +0 -0
  126. package/payload/server/public/assets/{graph-D-DGlfhW.js → graph-CDyzd1Et.js} +1 -1
  127. package/payload/server/public/assets/graph-CDyzd1Et.js.br +0 -0
  128. package/payload/server/public/assets/graph-CDyzd1Et.js.gz +0 -0
  129. package/payload/server/public/assets/{graph-labels-BbX3fXzl.js → graph-labels-D1LkKiJr.js} +1 -1
  130. package/payload/server/public/assets/graph-labels-D1LkKiJr.js.br +0 -0
  131. package/payload/server/public/assets/graph-labels-D1LkKiJr.js.gz +0 -0
  132. package/payload/server/public/assets/{maximize-2-C_-KapxH.js → maximize-2-M-iSaznd.js} +1 -1
  133. package/payload/server/public/assets/maximize-2-M-iSaznd.js.br +0 -0
  134. package/payload/server/public/assets/maximize-2-M-iSaznd.js.gz +0 -0
  135. package/payload/server/public/assets/{operator-CFrZVcv6.js → operator-9jfCv1Fg.js} +1 -1
  136. package/payload/server/public/assets/operator-9jfCv1Fg.js.br +0 -0
  137. package/payload/server/public/assets/operator-9jfCv1Fg.js.gz +0 -0
  138. package/payload/server/public/assets/{page-E74MYB18.js → page-CZ-73FAk.js} +1 -1
  139. package/payload/server/public/assets/page-CZ-73FAk.js.br +0 -0
  140. package/payload/server/public/assets/page-CZ-73FAk.js.gz +0 -0
  141. package/payload/server/public/assets/{page-CHt62f1_.js → page-CjwSt7kx.js} +1 -1
  142. package/payload/server/public/assets/page-CjwSt7kx.js.br +0 -0
  143. package/payload/server/public/assets/page-CjwSt7kx.js.gz +0 -0
  144. package/payload/server/public/assets/{public-CI6K1sNW.js → public-CN-ltC8x.js} +1 -1
  145. package/payload/server/public/assets/public-CN-ltC8x.js.br +0 -0
  146. package/payload/server/public/assets/public-CN-ltC8x.js.gz +0 -0
  147. package/payload/server/public/assets/{rotate-ccw-PWu_QGrD.js → rotate-ccw-Buopsc22.js} +1 -1
  148. package/payload/server/public/assets/rotate-ccw-Buopsc22.js.br +0 -0
  149. package/payload/server/public/assets/rotate-ccw-Buopsc22.js.gz +0 -0
  150. package/payload/server/public/assets/{routines-Cp3_XS7S.js → routines-C-yr8ddT.js} +1 -1
  151. package/payload/server/public/assets/routines-C-yr8ddT.js.br +0 -0
  152. package/payload/server/public/assets/routines-C-yr8ddT.js.gz +0 -0
  153. package/payload/server/public/assets/{skills-g8HvunPA.js → skills-DiiuVzDK.js} +1 -1
  154. package/payload/server/public/assets/skills-DiiuVzDK.js.br +0 -0
  155. package/payload/server/public/assets/skills-DiiuVzDK.js.gz +0 -0
  156. package/payload/server/public/assets/tasks-CnHIfn2_.js +1 -0
  157. package/payload/server/public/assets/tasks-CnHIfn2_.js.br +0 -0
  158. package/payload/server/public/assets/tasks-CnHIfn2_.js.gz +0 -0
  159. package/payload/server/public/assets/{time-entry-format-BXWuQ6Sw.js → time-entry-format-BBokCF-D.js} +1 -1
  160. package/payload/server/public/assets/time-entry-format-BBokCF-D.js.br +0 -0
  161. package/payload/server/public/assets/time-entry-format-BBokCF-D.js.gz +0 -0
  162. package/payload/server/public/assets/{triangle-alert-BNshRC13.js → triangle-alert-C_AcpTW5.js} +1 -1
  163. package/payload/server/public/assets/triangle-alert-C_AcpTW5.js.br +0 -0
  164. package/payload/server/public/assets/triangle-alert-C_AcpTW5.js.gz +0 -0
  165. package/payload/server/public/assets/{useCopyFeedback-CwTZ9DqH.js → useCopyFeedback-TdimmPVR.js} +1 -1
  166. package/payload/server/public/assets/useCopyFeedback-TdimmPVR.js.br +0 -0
  167. package/payload/server/public/assets/useCopyFeedback-TdimmPVR.js.gz +0 -0
  168. package/payload/server/public/assets/{useSubAccountSwitcher-BuUYMDWl.js → useSubAccountSwitcher-BwHqV55p.js} +1 -1
  169. package/payload/server/public/assets/useSubAccountSwitcher-BwHqV55p.js.br +0 -0
  170. package/payload/server/public/assets/{useSubAccountSwitcher-BuUYMDWl.js.gz → useSubAccountSwitcher-BwHqV55p.js.gz} +0 -0
  171. package/payload/server/public/assets/{useSubAccountSwitcher-dzDnmWq9.css → useSubAccountSwitcher-CsrPYqtm.css} +1 -1
  172. package/payload/server/public/assets/useSubAccountSwitcher-CsrPYqtm.css.br +0 -0
  173. package/payload/server/public/assets/{useSubAccountSwitcher-dzDnmWq9.css.gz → useSubAccountSwitcher-CsrPYqtm.css.gz} +0 -0
  174. package/payload/server/public/assets/{useVoiceRecorder-BGqV5R6u.js → useVoiceRecorder-BT2738ZS.js} +1 -1
  175. package/payload/server/public/assets/useVoiceRecorder-BT2738ZS.js.br +0 -0
  176. package/payload/server/public/assets/useVoiceRecorder-BT2738ZS.js.gz +0 -0
  177. package/payload/server/public/assets/{wrench-DQ045Pyk.js → wrench-B51s5kGA.js} +1 -1
  178. package/payload/server/public/assets/wrench-B51s5kGA.js.br +0 -0
  179. package/payload/server/public/assets/wrench-B51s5kGA.js.gz +0 -0
  180. package/payload/server/public/browser.html +4 -4
  181. package/payload/server/public/calendar.html +7 -7
  182. package/payload/server/public/chat.html +13 -13
  183. package/payload/server/public/data.html +11 -11
  184. package/payload/server/public/graph.html +9 -9
  185. package/payload/server/public/index.html +14 -14
  186. package/payload/server/public/operator.html +14 -14
  187. package/payload/server/public/public.html +13 -13
  188. package/payload/server/public/routines.html +6 -6
  189. package/payload/server/public/skills.html +5 -5
  190. package/payload/server/public/tasks.html +6 -6
  191. package/payload/server/server.js +1006 -606
  192. package/payload/server/public/assets/AdminLoginScreens-Dar_MMJm.js.br +0 -0
  193. package/payload/server/public/assets/AdminLoginScreens-Dar_MMJm.js.gz +0 -0
  194. package/payload/server/public/assets/AdminShell-CpaI2F_p.js.br +0 -0
  195. package/payload/server/public/assets/activity-B1rt4GIy.js.br +0 -0
  196. package/payload/server/public/assets/activity-B1rt4GIy.js.gz +0 -0
  197. package/payload/server/public/assets/admin-DE3lLNje.js +0 -1
  198. package/payload/server/public/assets/admin-DE3lLNje.js.br +0 -0
  199. package/payload/server/public/assets/admin-DE3lLNje.js.gz +0 -0
  200. package/payload/server/public/assets/agents-BXq8woVf.js.br +0 -0
  201. package/payload/server/public/assets/agents-BXq8woVf.js.gz +0 -0
  202. package/payload/server/public/assets/browser-1QSCPl3X.js.br +0 -0
  203. package/payload/server/public/assets/browser-1QSCPl3X.js.gz +0 -0
  204. package/payload/server/public/assets/calendar-D009qWVV.js.br +0 -0
  205. package/payload/server/public/assets/calendar-D009qWVV.js.gz +0 -0
  206. package/payload/server/public/assets/chat-CUg1fTqJ.js +0 -1
  207. package/payload/server/public/assets/chat-CUg1fTqJ.js.br +0 -1
  208. package/payload/server/public/assets/chat-CUg1fTqJ.js.gz +0 -0
  209. package/payload/server/public/assets/chevron-left-C2JEy7uU.js +0 -1
  210. package/payload/server/public/assets/chevron-left-C2JEy7uU.js.br +0 -0
  211. package/payload/server/public/assets/chevron-right-DWa047Ys.js +0 -1
  212. package/payload/server/public/assets/chevron-right-DWa047Ys.js.br +0 -0
  213. package/payload/server/public/assets/clock-C3OqfCnn.js +0 -1
  214. package/payload/server/public/assets/clock-C3OqfCnn.js.br +0 -0
  215. package/payload/server/public/assets/clock-C3OqfCnn.js.gz +0 -0
  216. package/payload/server/public/assets/data-Bu_yCScC.js +0 -1
  217. package/payload/server/public/assets/data-Bu_yCScC.js.br +0 -0
  218. package/payload/server/public/assets/data-Bu_yCScC.js.gz +0 -0
  219. package/payload/server/public/assets/file-text-DwGAfCsd.js.br +0 -0
  220. package/payload/server/public/assets/file-text-DwGAfCsd.js.gz +0 -0
  221. package/payload/server/public/assets/graph-D-DGlfhW.js.br +0 -0
  222. package/payload/server/public/assets/graph-D-DGlfhW.js.gz +0 -0
  223. package/payload/server/public/assets/graph-labels-BbX3fXzl.js.br +0 -0
  224. package/payload/server/public/assets/graph-labels-BbX3fXzl.js.gz +0 -0
  225. package/payload/server/public/assets/maximize-2-C_-KapxH.js.br +0 -0
  226. package/payload/server/public/assets/maximize-2-C_-KapxH.js.gz +0 -0
  227. package/payload/server/public/assets/operator-CFrZVcv6.js.br +0 -0
  228. package/payload/server/public/assets/operator-CFrZVcv6.js.gz +0 -0
  229. package/payload/server/public/assets/page-CHt62f1_.js.br +0 -0
  230. package/payload/server/public/assets/page-CHt62f1_.js.gz +0 -0
  231. package/payload/server/public/assets/page-E74MYB18.js.br +0 -0
  232. package/payload/server/public/assets/page-E74MYB18.js.gz +0 -0
  233. package/payload/server/public/assets/public-CI6K1sNW.js.br +0 -0
  234. package/payload/server/public/assets/public-CI6K1sNW.js.gz +0 -0
  235. package/payload/server/public/assets/rotate-ccw-PWu_QGrD.js.br +0 -0
  236. package/payload/server/public/assets/rotate-ccw-PWu_QGrD.js.gz +0 -0
  237. package/payload/server/public/assets/routines-Cp3_XS7S.js.br +0 -0
  238. package/payload/server/public/assets/routines-Cp3_XS7S.js.gz +0 -0
  239. package/payload/server/public/assets/skills-g8HvunPA.js.br +0 -0
  240. package/payload/server/public/assets/skills-g8HvunPA.js.gz +0 -0
  241. package/payload/server/public/assets/tasks-CMC_jDVm.js +0 -1
  242. package/payload/server/public/assets/tasks-CMC_jDVm.js.br +0 -0
  243. package/payload/server/public/assets/tasks-CMC_jDVm.js.gz +0 -0
  244. package/payload/server/public/assets/time-entry-format-BXWuQ6Sw.js.br +0 -2
  245. package/payload/server/public/assets/time-entry-format-BXWuQ6Sw.js.gz +0 -0
  246. package/payload/server/public/assets/triangle-alert-BNshRC13.js.br +0 -0
  247. package/payload/server/public/assets/triangle-alert-BNshRC13.js.gz +0 -0
  248. package/payload/server/public/assets/useCopyFeedback-CwTZ9DqH.js.br +0 -0
  249. package/payload/server/public/assets/useCopyFeedback-CwTZ9DqH.js.gz +0 -0
  250. package/payload/server/public/assets/useSubAccountSwitcher-BuUYMDWl.js.br +0 -0
  251. package/payload/server/public/assets/useSubAccountSwitcher-dzDnmWq9.css.br +0 -0
  252. package/payload/server/public/assets/useVoiceRecorder-BGqV5R6u.js.br +0 -0
  253. package/payload/server/public/assets/useVoiceRecorder-BGqV5R6u.js.gz +0 -0
  254. package/payload/server/public/assets/wrench-DQ045Pyk.js.br +0 -0
  255. package/payload/server/public/assets/wrench-DQ045Pyk.js.gz +0 -0
@@ -332,32 +332,32 @@ function ledgerFilePath(account) {
332
332
  }
333
333
  return join(root, `${account}.jsonl`);
334
334
  }
335
- function appendStanza(entry) {
335
+ function appendStanza(entry2) {
336
336
  try {
337
337
  const row = {
338
- msgId: entry.msgId,
339
- from: entry.from,
340
- type: entry.type,
338
+ msgId: entry2.msgId,
339
+ from: entry2.from,
340
+ type: entry2.type,
341
341
  ts: (/* @__PURE__ */ new Date()).toISOString()
342
342
  };
343
- appendFileSync(ledgerFilePath(entry.account), JSON.stringify(row) + "\n");
343
+ appendFileSync(ledgerFilePath(entry2.account), JSON.stringify(row) + "\n");
344
344
  } catch (err) {
345
345
  console.error(
346
- `${TAG3} FAIL op=append msgId=${entry.msgId} err=${err instanceof Error ? err.message : String(err)}`
346
+ `${TAG3} FAIL op=append msgId=${entry2.msgId} err=${err instanceof Error ? err.message : String(err)}`
347
347
  );
348
348
  }
349
349
  }
350
- function markDeclined(entry) {
350
+ function markDeclined(entry2) {
351
351
  try {
352
352
  const row = {
353
- declined: entry.msgId,
354
- reason: entry.reason,
353
+ declined: entry2.msgId,
354
+ reason: entry2.reason,
355
355
  ts: (/* @__PURE__ */ new Date()).toISOString()
356
356
  };
357
- appendFileSync(ledgerFilePath(entry.account), JSON.stringify(row) + "\n");
357
+ appendFileSync(ledgerFilePath(entry2.account), JSON.stringify(row) + "\n");
358
358
  } catch (err) {
359
359
  console.error(
360
- `${TAG3} FAIL op=decline msgId=${entry.msgId} err=${err instanceof Error ? err.message : String(err)}`
360
+ `${TAG3} FAIL op=decline msgId=${entry2.msgId} err=${err instanceof Error ? err.message : String(err)}`
361
361
  );
362
362
  }
363
363
  }
@@ -375,36 +375,36 @@ function readDeclined(account) {
375
375
  }
376
376
  return out;
377
377
  }
378
- function appendNotifyEligible(entry) {
378
+ function appendNotifyEligible(entry2) {
379
379
  try {
380
380
  const row = {
381
- notifyEligible: entry.msgId,
382
- upsertType: entry.upsertType,
383
- fromMe: entry.fromMe,
384
- allowed: entry.allowed,
385
- reason: entry.reason,
386
- passive: entry.passive,
387
- persistAccount: entry.persistAccount,
381
+ notifyEligible: entry2.msgId,
382
+ upsertType: entry2.upsertType,
383
+ fromMe: entry2.fromMe,
384
+ allowed: entry2.allowed,
385
+ reason: entry2.reason,
386
+ passive: entry2.passive,
387
+ persistAccount: entry2.persistAccount,
388
388
  ts: (/* @__PURE__ */ new Date()).toISOString()
389
389
  };
390
- appendFileSync(ledgerFilePath(entry.account), JSON.stringify(row) + "\n");
390
+ appendFileSync(ledgerFilePath(entry2.account), JSON.stringify(row) + "\n");
391
391
  } catch (err) {
392
392
  console.error(
393
- `${TAG3} FAIL op=append-notify-eligible msgId=${entry.msgId} err=${err instanceof Error ? err.message : String(err)}`
393
+ `${TAG3} FAIL op=append-notify-eligible msgId=${entry2.msgId} err=${err instanceof Error ? err.message : String(err)}`
394
394
  );
395
395
  }
396
396
  }
397
- function appendNotifyPublished(entry) {
397
+ function appendNotifyPublished(entry2) {
398
398
  try {
399
399
  const row = {
400
- notifyPublished: entry.msgId,
401
- subscribers: entry.subscribers,
400
+ notifyPublished: entry2.msgId,
401
+ subscribers: entry2.subscribers,
402
402
  ts: (/* @__PURE__ */ new Date()).toISOString()
403
403
  };
404
- appendFileSync(ledgerFilePath(entry.account), JSON.stringify(row) + "\n");
404
+ appendFileSync(ledgerFilePath(entry2.account), JSON.stringify(row) + "\n");
405
405
  } catch (err) {
406
406
  console.error(
407
- `${TAG3} FAIL op=append-notify-published msgId=${entry.msgId} err=${err instanceof Error ? err.message : String(err)}`
407
+ `${TAG3} FAIL op=append-notify-published msgId=${entry2.msgId} err=${err instanceof Error ? err.message : String(err)}`
408
408
  );
409
409
  }
410
410
  }
@@ -1218,16 +1218,16 @@ function toMillis(v) {
1218
1218
  if (typeof v.low === "number") return (v.low >>> 0) + (v.high ?? 0) * 4294967296;
1219
1219
  return null;
1220
1220
  }
1221
- function readReactionEntry(entry) {
1222
- const targetMsgKeyId = entry.key?.id ?? void 0;
1221
+ function readReactionEntry(entry2) {
1222
+ const targetMsgKeyId = entry2.key?.id ?? void 0;
1223
1223
  if (!targetMsgKeyId) return null;
1224
- const chatJid = entry.key?.remoteJid ?? entry.reaction?.key?.remoteJid ?? void 0;
1224
+ const chatJid = entry2.key?.remoteJid ?? entry2.reaction?.key?.remoteJid ?? void 0;
1225
1225
  if (!chatJid) return null;
1226
1226
  const isGroup = isGroupJid(chatJid);
1227
- const reactorKey = entry.reaction?.key;
1227
+ const reactorKey = entry2.reaction?.key;
1228
1228
  const reactorJid = isGroup ? reactorKey?.participant ?? void 0 : reactorKey?.remoteJid ?? chatJid;
1229
1229
  if (!reactorJid) return null;
1230
- const emoji = entry.reaction?.text ?? "";
1230
+ const emoji = entry2.reaction?.text ?? "";
1231
1231
  return {
1232
1232
  targetMsgKeyId,
1233
1233
  chatJid,
@@ -1236,7 +1236,7 @@ function readReactionEntry(entry) {
1236
1236
  emoji,
1237
1237
  removed: !emoji,
1238
1238
  fromMe: !!reactorKey?.fromMe,
1239
- timestampMs: toMillis(entry.reaction?.senderTimestampMs)
1239
+ timestampMs: toMillis(entry2.reaction?.senderTimestampMs)
1240
1240
  };
1241
1241
  }
1242
1242
 
@@ -1381,7 +1381,7 @@ function summariseRecords(records) {
1381
1381
  return {
1382
1382
  first: sorted[0],
1383
1383
  last: sorted[sorted.length - 1],
1384
- firstNamedSender: sorted.find((r) => r.senderName)?.senderName ?? null
1384
+ firstNamedSender: sorted.find((r) => !r.fromMe && r.senderName)?.senderName ?? null
1385
1385
  };
1386
1386
  }
1387
1387
  function readConversationSummaries(platformAccountId) {
@@ -1393,10 +1393,10 @@ function readConversationSummaries(platformAccountId) {
1393
1393
  let bytesRead = 0;
1394
1394
  try {
1395
1395
  if (!existsSync3(dir)) return out;
1396
- for (const entry of readdirSync2(dir)) {
1397
- if (!entry.endsWith(".jsonl")) continue;
1398
- const remoteJid = entry.slice(0, -".jsonl".length);
1399
- const file = join2(dir, entry);
1396
+ for (const entry2 of readdirSync2(dir)) {
1397
+ if (!entry2.endsWith(".jsonl")) continue;
1398
+ const remoteJid = entry2.slice(0, -".jsonl".length);
1399
+ const file = join2(dir, entry2);
1400
1400
  seen.add(file);
1401
1401
  let size;
1402
1402
  let mtimeMs;
@@ -1445,9 +1445,9 @@ function readAllConversations(platformAccountId) {
1445
1445
  const out = /* @__PURE__ */ new Map();
1446
1446
  try {
1447
1447
  if (!existsSync3(dir)) return out;
1448
- for (const entry of readdirSync2(dir)) {
1449
- if (!entry.endsWith(".jsonl")) continue;
1450
- const remoteJid = entry.slice(0, -".jsonl".length);
1448
+ for (const entry2 of readdirSync2(dir)) {
1449
+ if (!entry2.endsWith(".jsonl")) continue;
1450
+ const remoteJid = entry2.slice(0, -".jsonl".length);
1451
1451
  out.set(remoteJid, readConversation(platformAccountId, remoteJid));
1452
1452
  }
1453
1453
  } catch (err) {
@@ -1468,16 +1468,16 @@ function normalizeEntry(v) {
1468
1468
  return typeof v === "string" ? { account: v, mode: "active" } : { account: v.managesAccount, mode: v.mode ?? "active" };
1469
1469
  }
1470
1470
  function managedAccountFor(accountManagers, phone) {
1471
- for (const [managerPhone, entry] of Object.entries(accountManagers)) {
1472
- const { account, mode } = normalizeEntry(entry);
1471
+ for (const [managerPhone, entry2] of Object.entries(accountManagers)) {
1472
+ const { account, mode } = normalizeEntry(entry2);
1473
1473
  if (account && phonesMatch(managerPhone, phone)) return { account, mode };
1474
1474
  }
1475
1475
  return null;
1476
1476
  }
1477
1477
  function managerPhonesForAccount(accountManagers, subAccountId) {
1478
1478
  const phones = [];
1479
- for (const [managerPhone, entry] of Object.entries(accountManagers)) {
1480
- const { account } = normalizeEntry(entry);
1479
+ for (const [managerPhone, entry2] of Object.entries(accountManagers)) {
1480
+ const { account } = normalizeEntry(entry2);
1481
1481
  if (account && account === subAccountId) phones.push(managerPhone);
1482
1482
  }
1483
1483
  return phones;
@@ -1498,7 +1498,7 @@ function resolveAccountConfig(config, accountConfig) {
1498
1498
  function isAdminPhone(phone, adminPhones) {
1499
1499
  const normalized = normalizeE164(phone);
1500
1500
  if (!normalized) return false;
1501
- return adminPhones.some((entry) => phonesMatch(entry, normalized));
1501
+ return adminPhones.some((entry2) => phonesMatch(entry2, normalized));
1502
1502
  }
1503
1503
  function checkDmAccess(params) {
1504
1504
  const { senderPhone, selfPhone, accountId } = params;
@@ -1520,9 +1520,9 @@ function checkDmAccess(params) {
1520
1520
  case "open":
1521
1521
  return { allowed: true, reason: "dm-policy-open", agentType: "public", effectiveAccountId: accountId };
1522
1522
  case "allowlist": {
1523
- const inList = cfg.allowFrom.some((entry) => {
1524
- if (entry === "*") return true;
1525
- return phonesMatch(entry, senderPhone);
1523
+ const inList = cfg.allowFrom.some((entry2) => {
1524
+ if (entry2 === "*") return true;
1525
+ return phonesMatch(entry2, senderPhone);
1526
1526
  });
1527
1527
  if (inList) {
1528
1528
  return { allowed: true, reason: "allowlist-match", agentType: "public", effectiveAccountId: accountId };
@@ -1597,8 +1597,8 @@ var NOTIFY_MAX = 5e3;
1597
1597
  var notifyCache = /* @__PURE__ */ new Map();
1598
1598
  function isNotifyDuplicate(msgKeyId) {
1599
1599
  const now = Date.now();
1600
- const entry = notifyCache.get(msgKeyId);
1601
- if (entry && now - entry.ts <= NOTIFY_TTL_MS) return true;
1600
+ const entry2 = notifyCache.get(msgKeyId);
1601
+ if (entry2 && now - entry2.ts <= NOTIFY_TTL_MS) return true;
1602
1602
  for (const [key, e] of notifyCache) {
1603
1603
  if (now - e.ts > NOTIFY_TTL_MS) notifyCache.delete(key);
1604
1604
  }
@@ -1675,15 +1675,15 @@ var ACCESS_LOCKOUT_MS = 15 * 60 * 1e3;
1675
1675
  var ACCESS_WINDOW_MS = 15 * 60 * 1e3;
1676
1676
  function checkAccessRateLimit(ip, agentSlug) {
1677
1677
  const key = `${ip}:${agentSlug}`;
1678
- const entry = rateLimitMap.get(key);
1679
- if (!entry) return null;
1678
+ const entry2 = rateLimitMap.get(key);
1679
+ if (!entry2) return null;
1680
1680
  const now = Date.now();
1681
- if (entry.lockedUntil && now < entry.lockedUntil) {
1682
- const remainingMs = entry.lockedUntil - now;
1681
+ if (entry2.lockedUntil && now < entry2.lockedUntil) {
1682
+ const remainingMs = entry2.lockedUntil - now;
1683
1683
  const remainingS = Math.ceil(remainingMs / 1e3);
1684
1684
  return `Too many attempts. Try again in ${remainingS}s`;
1685
1685
  }
1686
- if (now - entry.firstAttempt > ACCESS_WINDOW_MS) {
1686
+ if (now - entry2.firstAttempt > ACCESS_WINDOW_MS) {
1687
1687
  rateLimitMap.delete(key);
1688
1688
  return null;
1689
1689
  }
@@ -1692,14 +1692,14 @@ function checkAccessRateLimit(ip, agentSlug) {
1692
1692
  function recordAccessFailedAttempt(ip, agentSlug) {
1693
1693
  const key = `${ip}:${agentSlug}`;
1694
1694
  const now = Date.now();
1695
- const entry = rateLimitMap.get(key);
1696
- if (!entry || now - entry.firstAttempt > ACCESS_WINDOW_MS) {
1695
+ const entry2 = rateLimitMap.get(key);
1696
+ if (!entry2 || now - entry2.firstAttempt > ACCESS_WINDOW_MS) {
1697
1697
  rateLimitMap.set(key, { attempts: 1, firstAttempt: now });
1698
1698
  return;
1699
1699
  }
1700
- entry.attempts++;
1701
- if (entry.attempts >= ACCESS_MAX_ATTEMPTS) {
1702
- entry.lockedUntil = now + ACCESS_LOCKOUT_MS;
1700
+ entry2.attempts++;
1701
+ if (entry2.attempts >= ACCESS_MAX_ATTEMPTS) {
1702
+ entry2.lockedUntil = now + ACCESS_LOCKOUT_MS;
1703
1703
  }
1704
1704
  }
1705
1705
  function clearAccessRateLimit(ip, agentSlug) {
@@ -1709,15 +1709,15 @@ var contactRateMap = /* @__PURE__ */ new Map();
1709
1709
  var REQUEST_LINK_MAX = 3;
1710
1710
  var REQUEST_LINK_WINDOW_MS = 60 * 60 * 1e3;
1711
1711
  function checkRequestLinkRateLimit(contactValue) {
1712
- const entry = contactRateMap.get(contactValue);
1713
- if (!entry) return null;
1712
+ const entry2 = contactRateMap.get(contactValue);
1713
+ if (!entry2) return null;
1714
1714
  const now = Date.now();
1715
- if (now - entry.windowStart > REQUEST_LINK_WINDOW_MS) {
1715
+ if (now - entry2.windowStart > REQUEST_LINK_WINDOW_MS) {
1716
1716
  contactRateMap.delete(contactValue);
1717
1717
  return null;
1718
1718
  }
1719
- if (entry.count >= REQUEST_LINK_MAX) {
1720
- const remainingMs = REQUEST_LINK_WINDOW_MS - (now - entry.windowStart);
1719
+ if (entry2.count >= REQUEST_LINK_MAX) {
1720
+ const remainingMs = REQUEST_LINK_WINDOW_MS - (now - entry2.windowStart);
1721
1721
  const remainingM = Math.ceil(remainingMs / 6e4);
1722
1722
  return `Too many requests. Try again in ${remainingM} minute(s)`;
1723
1723
  }
@@ -1725,12 +1725,12 @@ function checkRequestLinkRateLimit(contactValue) {
1725
1725
  }
1726
1726
  function recordRequestLinkAttempt(contactValue) {
1727
1727
  const now = Date.now();
1728
- const entry = contactRateMap.get(contactValue);
1729
- if (!entry || now - entry.windowStart > REQUEST_LINK_WINDOW_MS) {
1728
+ const entry2 = contactRateMap.get(contactValue);
1729
+ if (!entry2 || now - entry2.windowStart > REQUEST_LINK_WINDOW_MS) {
1730
1730
  contactRateMap.set(contactValue, { count: 1, windowStart: now });
1731
1731
  return;
1732
1732
  }
1733
- entry.count++;
1733
+ entry2.count++;
1734
1734
  }
1735
1735
  function maskContact(value) {
1736
1736
  if (value.includes("@")) {
@@ -1919,8 +1919,8 @@ var agentSentCache = /* @__PURE__ */ new Map();
1919
1919
  var inboundCache = /* @__PURE__ */ new Map();
1920
1920
  function pruneCache(cache3, ttl, max) {
1921
1921
  const now = Date.now();
1922
- for (const [key, entry] of cache3) {
1923
- if (now - entry.ts > ttl) cache3.delete(key);
1922
+ for (const [key, entry2] of cache3) {
1923
+ if (now - entry2.ts > ttl) cache3.delete(key);
1924
1924
  }
1925
1925
  if (cache3.size > max) {
1926
1926
  const excess = cache3.size - max;
@@ -1937,22 +1937,22 @@ function trackAgentSentMessage(messageId) {
1937
1937
  agentSentCache.set(messageId, { ts: Date.now() });
1938
1938
  }
1939
1939
  function isAgentSentMessage(messageId) {
1940
- const entry = agentSentCache.get(messageId);
1941
- if (!entry) return false;
1942
- if (Date.now() - entry.ts > AGENT_SENT_TTL_MS) {
1940
+ const entry2 = agentSentCache.get(messageId);
1941
+ if (!entry2) return false;
1942
+ if (Date.now() - entry2.ts > AGENT_SENT_TTL_MS) {
1943
1943
  agentSentCache.delete(messageId);
1944
1944
  return false;
1945
1945
  }
1946
1946
  return true;
1947
1947
  }
1948
1948
  function isDuplicateInbound(key) {
1949
- const entry = inboundCache.get(key);
1950
- if (!entry) {
1949
+ const entry2 = inboundCache.get(key);
1950
+ if (!entry2) {
1951
1951
  pruneCache(inboundCache, INBOUND_TTL_MS, INBOUND_MAX);
1952
1952
  inboundCache.set(key, { ts: Date.now() });
1953
1953
  return false;
1954
1954
  }
1955
- if (Date.now() - entry.ts > INBOUND_TTL_MS) {
1955
+ if (Date.now() - entry2.ts > INBOUND_TTL_MS) {
1956
1956
  inboundCache.delete(key);
1957
1957
  inboundCache.set(key, { ts: Date.now() });
1958
1958
  return false;
@@ -2013,7 +2013,7 @@ function recordActivity(event) {
2013
2013
  }
2014
2014
  acct[direction]++;
2015
2015
  acct.lastEventAt = now;
2016
- const entry = {
2016
+ const entry2 = {
2017
2017
  channel: "whatsapp",
2018
2018
  accountId,
2019
2019
  direction,
@@ -2021,7 +2021,7 @@ function recordActivity(event) {
2021
2021
  timestamp: now,
2022
2022
  messageType
2023
2023
  };
2024
- recentEvents.push(entry);
2024
+ recentEvents.push(entry2);
2025
2025
  if (recentEvents.length > RECENT_EVENTS_MAX) {
2026
2026
  recentEvents.splice(0, recentEvents.length - RECENT_EVENTS_MAX);
2027
2027
  }
@@ -2295,6 +2295,216 @@ function sanitizeReason(err) {
2295
2295
  return `${err.name}:${msg}`;
2296
2296
  }
2297
2297
 
2298
+ // app/lib/whatsapp/chat-metadata-store.ts
2299
+ import { existsSync as existsSync4, mkdirSync as mkdirSync3, readFileSync as readFileSync5, writeFileSync as writeFileSync3, renameSync, statSync as statSync2 } from "fs";
2300
+ import { dirname as dirname2, join as join4 } from "path";
2301
+
2302
+ // app/lib/data-path.ts
2303
+ import { realpathSync } from "fs";
2304
+ import { resolve as resolve2, normalize, sep, relative, basename, join as join3 } from "path";
2305
+ var PLATFORM_ROOT2 = process.env.MAXY_PLATFORM_ROOT ?? resolve2(process.cwd(), "../platform");
2306
+ var DATA_ROOT = resolve2(PLATFORM_ROOT2, "..", "data");
2307
+ var CLAUDE_UPLOADS_ROOT = process.env.CLAUDE_CONFIG_DIR ? resolve2(process.env.CLAUDE_CONFIG_DIR, "uploads") : null;
2308
+ var ACCOUNT_PARTITION_DIRS = /* @__PURE__ */ new Set(["accounts"]);
2309
+ var ACCOUNT_UUID_RE = /^[0-9a-f]{8}-[0-9a-f]{4}-[0-9a-f]{4}-[0-9a-f]{4}-[0-9a-f]{12}$/i;
2310
+ function crossesForeignAccountPartition(relPath, accountId) {
2311
+ const segs = relPath.split("/").filter(Boolean);
2312
+ if (segs.length < 2) return false;
2313
+ if (!ACCOUNT_PARTITION_DIRS.has(segs[0])) return false;
2314
+ const owner = segs[1];
2315
+ if (!ACCOUNT_UUID_RE.test(owner)) return false;
2316
+ return owner !== accountId;
2317
+ }
2318
+ function isWithinOwnAccountPartition(relPath, accountId) {
2319
+ const segs = relPath.split("/").filter(Boolean);
2320
+ return segs.length >= 2 && segs[0] === "accounts" && segs[1] === accountId;
2321
+ }
2322
+ function resolveUnderRoot(raw, rootAbs, rootLabel) {
2323
+ const cleaned = normalize("/" + (raw ?? "").replace(/\\/g, "/")).replace(/^\/+/, "");
2324
+ const absolute = resolve2(rootAbs, cleaned);
2325
+ let rootReal;
2326
+ try {
2327
+ rootReal = realpathSync(rootAbs);
2328
+ } catch (err) {
2329
+ return {
2330
+ ok: false,
2331
+ status: 500,
2332
+ error: `${rootLabel} not accessible: ${err instanceof Error ? err.message : String(err)}`
2333
+ };
2334
+ }
2335
+ let resolvedReal;
2336
+ try {
2337
+ resolvedReal = realpathSync(absolute);
2338
+ } catch (err) {
2339
+ const code = err.code;
2340
+ if (code === "ENOENT") {
2341
+ if (absolute !== rootReal && !absolute.startsWith(rootReal + sep)) {
2342
+ return { ok: false, status: 403, error: `Path escapes ${rootLabel}`, resolved: absolute };
2343
+ }
2344
+ return { ok: false, status: 404, error: "Not found" };
2345
+ }
2346
+ return {
2347
+ ok: false,
2348
+ status: 500,
2349
+ error: err instanceof Error ? err.message : String(err)
2350
+ };
2351
+ }
2352
+ if (resolvedReal !== rootReal && !resolvedReal.startsWith(rootReal + sep)) {
2353
+ return { ok: false, status: 403, error: `Path escapes ${rootLabel}`, resolved: resolvedReal };
2354
+ }
2355
+ const relPath = relative(rootReal, resolvedReal) || ".";
2356
+ return { ok: true, absolute: resolvedReal, dataRootReal: rootReal, relative: relPath };
2357
+ }
2358
+ function resolveDataPath(raw) {
2359
+ return resolveUnderRoot(raw, DATA_ROOT, "DATA_ROOT");
2360
+ }
2361
+ function resolveClaudeUploadsPath(raw) {
2362
+ if (!CLAUDE_UPLOADS_ROOT) {
2363
+ return { ok: false, status: 404, error: "Not found" };
2364
+ }
2365
+ return resolveUnderRoot(raw, CLAUDE_UPLOADS_ROOT, "CLAUDE_UPLOADS_ROOT");
2366
+ }
2367
+ function scratchpadTmpBase() {
2368
+ return process.env.MAXY_SCRATCHPAD_BASE ?? "/tmp";
2369
+ }
2370
+ function sessionScratchpadRoot(projectDir, sessionId) {
2371
+ const uid = typeof process.geteuid === "function" ? process.geteuid() : 0;
2372
+ return join3(scratchpadTmpBase(), `claude-${uid}`, basename(projectDir), sessionId, "scratchpad");
2373
+ }
2374
+ function resolveScratchpadPath(raw, scratchpadRootAbs) {
2375
+ return resolveUnderRoot(raw, scratchpadRootAbs, "scratchpad");
2376
+ }
2377
+
2378
+ // app/lib/whatsapp/chat-metadata-store.ts
2379
+ var SOURCE_RANK = { contact: 3, group: 2, chat: 1 };
2380
+ function isSource(v) {
2381
+ return v === "contact" || v === "group" || v === "chat";
2382
+ }
2383
+ function preferEntry(existing, incoming) {
2384
+ if (existing === void 0) return incoming;
2385
+ const a = SOURCE_RANK[existing.source];
2386
+ const b = SOURCE_RANK[incoming.source];
2387
+ if (b > a) return incoming;
2388
+ if (b < a) return existing;
2389
+ return incoming.updatedAt > existing.updatedAt ? incoming : existing;
2390
+ }
2391
+ function parseChatMetadata(raw) {
2392
+ const out = /* @__PURE__ */ new Map();
2393
+ let parsed;
2394
+ try {
2395
+ parsed = JSON.parse(raw);
2396
+ } catch {
2397
+ return out;
2398
+ }
2399
+ if (parsed === null || typeof parsed !== "object" || Array.isArray(parsed)) return out;
2400
+ for (const [jid, value] of Object.entries(parsed)) {
2401
+ if (value === null || typeof value !== "object") continue;
2402
+ const v = value;
2403
+ if (typeof v.name !== "string" || v.name.length === 0) continue;
2404
+ if (!isSource(v.source)) continue;
2405
+ if (typeof v.updatedAt !== "string") continue;
2406
+ out.set(jid, {
2407
+ jid,
2408
+ name: v.name,
2409
+ source: v.source,
2410
+ isGroup: v.isGroup === true,
2411
+ updatedAt: v.updatedAt
2412
+ });
2413
+ }
2414
+ return out;
2415
+ }
2416
+ function serializeChatMetadata(map) {
2417
+ const obj = {};
2418
+ for (const [jid, entry2] of map) obj[jid] = entry2;
2419
+ return JSON.stringify(obj);
2420
+ }
2421
+ function chatMetadataPath(accountId) {
2422
+ return join4(DATA_ROOT, "accounts", accountId, "chat-metadata.json");
2423
+ }
2424
+ var readCache = /* @__PURE__ */ new Map();
2425
+ function readChatMetadata(accountId) {
2426
+ const path3 = chatMetadataPath(accountId);
2427
+ try {
2428
+ if (!existsSync4(path3)) return /* @__PURE__ */ new Map();
2429
+ const st = statSync2(path3);
2430
+ const cached = readCache.get(path3);
2431
+ if (cached && cached.size === st.size && cached.mtimeMs === st.mtimeMs) return cached.map;
2432
+ const map = parseChatMetadata(readFileSync5(path3, "utf8"));
2433
+ readCache.set(path3, { size: st.size, mtimeMs: st.mtimeMs, map });
2434
+ return map;
2435
+ } catch (err) {
2436
+ console.error(
2437
+ `[wa-chatmeta] op=read outcome=fail account=${accountId.slice(0, 8)} reason=${(err instanceof Error ? err.message : String(err)).slice(0, 100)}`
2438
+ );
2439
+ return /* @__PURE__ */ new Map();
2440
+ }
2441
+ }
2442
+ function writeChatMetadataMerged(accountId, updates) {
2443
+ if (updates.length === 0) return -1;
2444
+ const path3 = chatMetadataPath(accountId);
2445
+ try {
2446
+ mkdirSync3(dirname2(path3), { recursive: true });
2447
+ let merged = /* @__PURE__ */ new Map();
2448
+ if (existsSync4(path3)) merged = parseChatMetadata(readFileSync5(path3, "utf8"));
2449
+ for (const entry2 of updates) merged.set(entry2.jid, preferEntry(merged.get(entry2.jid), entry2));
2450
+ const tmp = `${path3}.tmp`;
2451
+ writeFileSync3(tmp, serializeChatMetadata(merged), "utf8");
2452
+ renameSync(tmp, path3);
2453
+ return parseChatMetadata(readFileSync5(path3, "utf8")).size;
2454
+ } catch (err) {
2455
+ console.error(
2456
+ `[wa-chatmeta] op=persist outcome=fail account=${accountId.slice(0, 8)} reason=${(err instanceof Error ? err.message : String(err)).slice(0, 100)}`
2457
+ );
2458
+ return -1;
2459
+ }
2460
+ }
2461
+
2462
+ // app/lib/whatsapp/chat-metadata-events.ts
2463
+ var NON_CHAT_JIDS = /* @__PURE__ */ new Set(["status@broadcast"]);
2464
+ function isGroupJid2(jid) {
2465
+ return jid.endsWith("@g.us");
2466
+ }
2467
+ function entry(jid, name, source, nowIso) {
2468
+ return { jid, name, source, isGroup: isGroupJid2(jid), updatedAt: nowIso };
2469
+ }
2470
+ function conversationKey(jid, phoneNumber) {
2471
+ if (!jid.endsWith("@lid")) return jid;
2472
+ if (typeof phoneNumber !== "string") return jid;
2473
+ const trimmed = phoneNumber.trim();
2474
+ return trimmed.endsWith("@s.whatsapp.net") ? trimmed : jid;
2475
+ }
2476
+ function usable(jid, name, phoneNumber) {
2477
+ if (typeof jid !== "string" || jid.length === 0) return null;
2478
+ if (NON_CHAT_JIDS.has(jid)) return null;
2479
+ const trimmed = typeof name === "string" ? name.trim() : "";
2480
+ if (trimmed.length === 0) return null;
2481
+ return { jid: conversationKey(jid, phoneNumber), name: trimmed };
2482
+ }
2483
+ function chatEntriesFromChats(chats, nowIso) {
2484
+ const out = [];
2485
+ for (const c of chats) {
2486
+ const ok = usable(c.id, c.name, c.phoneNumber);
2487
+ if (ok) out.push(entry(ok.jid, ok.name, "chat", nowIso));
2488
+ }
2489
+ return out;
2490
+ }
2491
+ function chatEntriesFromContacts(contacts, nowIso) {
2492
+ const out = [];
2493
+ for (const c of contacts) {
2494
+ const ok = usable(c.id, c.name, c.phoneNumber);
2495
+ if (ok) out.push(entry(ok.jid, ok.name, isGroupJid2(ok.jid) ? "chat" : "contact", nowIso));
2496
+ }
2497
+ return out;
2498
+ }
2499
+ function groupEntriesFromUpdates(updates, nowIso) {
2500
+ const out = [];
2501
+ for (const g of updates) {
2502
+ const ok = usable(g.id, g.subject);
2503
+ if (ok) out.push(entry(ok.jid, ok.name, "group", nowIso));
2504
+ }
2505
+ return out;
2506
+ }
2507
+
2298
2508
  // app/lib/whatsapp/ensure-conversation.ts
2299
2509
  var TAG10 = "[whatsapp-persist]";
2300
2510
  async function ensureWhatsAppConversation(input) {
@@ -2327,8 +2537,8 @@ async function ensureWhatsAppConversation(input) {
2327
2537
  }
2328
2538
 
2329
2539
  // ../lib/account-enumeration/src/index.ts
2330
- import { readdirSync as readdirSync3, readFileSync as readFileSync5 } from "fs";
2331
- import { resolve as resolve2 } from "path";
2540
+ import { readdirSync as readdirSync3, readFileSync as readFileSync6 } from "fs";
2541
+ import { resolve as resolve3 } from "path";
2332
2542
  var UUID_RE = /^[0-9a-f]{8}-[0-9a-f]{4}-[0-9a-f]{4}-[0-9a-f]{4}-[0-9a-f]{12}$/i;
2333
2543
  var cache2 = /* @__PURE__ */ new Map();
2334
2544
  function enumerateValidAccountIds(accountsDir) {
@@ -2347,9 +2557,9 @@ function enumerateValidAccountIds(accountsDir) {
2347
2557
  const valid = [];
2348
2558
  for (const name of names) {
2349
2559
  if (!UUID_RE.test(name)) continue;
2350
- const configPath = resolve2(accountsDir, name, "account.json");
2560
+ const configPath = resolve3(accountsDir, name, "account.json");
2351
2561
  try {
2352
- JSON.parse(readFileSync5(configPath, "utf-8"));
2562
+ JSON.parse(readFileSync6(configPath, "utf-8"));
2353
2563
  valid.push(name);
2354
2564
  } catch (err) {
2355
2565
  const code = err.code;
@@ -2363,9 +2573,9 @@ function resolveHouseOrSoleAccountId(accountsDir) {
2363
2573
  const valid = enumerateValidAccountIds(accountsDir);
2364
2574
  const houses = [];
2365
2575
  for (const id of valid) {
2366
- const configPath = resolve2(accountsDir, id, "account.json");
2576
+ const configPath = resolve3(accountsDir, id, "account.json");
2367
2577
  try {
2368
- const cfg = JSON.parse(readFileSync5(configPath, "utf-8"));
2578
+ const cfg = JSON.parse(readFileSync6(configPath, "utf-8"));
2369
2579
  if (cfg.role === "house") houses.push(id);
2370
2580
  } catch {
2371
2581
  }
@@ -2383,7 +2593,7 @@ function getAccountsDirFromEnv() {
2383
2593
  "[graph-write] MAXY_PLATFORM_ROOT not set \u2014 cannot enforce accountId gate. Set MAXY_PLATFORM_ROOT in the spawning process or pass `accountsDir` explicitly."
2384
2594
  );
2385
2595
  }
2386
- return resolve2(root, "..", "data/accounts");
2596
+ return resolve3(root, "..", "data/accounts");
2387
2597
  }
2388
2598
  function validateAccountIdEnv(envValue, diskIds) {
2389
2599
  if (!envValue) {
@@ -2399,8 +2609,8 @@ function validateAccountIdEnv(envValue, diskIds) {
2399
2609
  }
2400
2610
 
2401
2611
  // app/lib/whatsapp/platform-account-id.ts
2402
- import { readFileSync as readFileSync6 } from "fs";
2403
- import { resolve as resolve3 } from "path";
2612
+ import { readFileSync as readFileSync7 } from "fs";
2613
+ import { resolve as resolve4 } from "path";
2404
2614
  var cachedHouseId = null;
2405
2615
  var cachedHouseAccountsDir = null;
2406
2616
  function resolveHouseId(accountsDir) {
@@ -2411,10 +2621,10 @@ function resolveHouseId(accountsDir) {
2411
2621
  return cachedHouseId;
2412
2622
  }
2413
2623
  function readChannelRoutingOverride(accountsDir, houseId) {
2414
- const configPath = resolve3(accountsDir, houseId, "account.json");
2624
+ const configPath = resolve4(accountsDir, houseId, "account.json");
2415
2625
  let raw;
2416
2626
  try {
2417
- raw = readFileSync6(configPath, "utf-8");
2627
+ raw = readFileSync7(configPath, "utf-8");
2418
2628
  } catch {
2419
2629
  return null;
2420
2630
  }
@@ -2455,8 +2665,8 @@ function warnNonUuidAccount(caller, accountId) {
2455
2665
  }
2456
2666
 
2457
2667
  // app/lib/managed-service.ts
2458
- import { join as join3 } from "path";
2459
- import { readFileSync as readFileSync7 } from "fs";
2668
+ import { join as join5 } from "path";
2669
+ import { readFileSync as readFileSync8 } from "fs";
2460
2670
  function isHouseManagedService(accountsDir = ACCOUNTS_DIR) {
2461
2671
  let houseId;
2462
2672
  try {
@@ -2466,7 +2676,7 @@ function isHouseManagedService(accountsDir = ACCOUNTS_DIR) {
2466
2676
  }
2467
2677
  try {
2468
2678
  const cfg = JSON.parse(
2469
- readFileSync7(join3(accountsDir, houseId, "account.json"), "utf-8")
2679
+ readFileSync8(join5(accountsDir, houseId, "account.json"), "utf-8")
2470
2680
  );
2471
2681
  return cfg.managedService === true;
2472
2682
  } catch {
@@ -2480,7 +2690,7 @@ function isCustomerTurnSuppressed(role, managedService) {
2480
2690
  // app/lib/whatsapp/inbound/media.ts
2481
2691
  import { randomUUID as randomUUID4, createHash } from "crypto";
2482
2692
  import { writeFile as writeFile2, mkdir as mkdir2 } from "fs/promises";
2483
- import { join as join5 } from "path";
2693
+ import { join as join6 } from "path";
2484
2694
  import {
2485
2695
  downloadMediaMessage,
2486
2696
  downloadContentFromMessage,
@@ -2490,85 +2700,9 @@ import {
2490
2700
  // app/lib/attachments.ts
2491
2701
  import { randomUUID as randomUUID3 } from "crypto";
2492
2702
  import { mkdir, writeFile } from "fs/promises";
2493
- import { realpathSync as realpathSync2, existsSync as existsSync4, readFileSync as readFileSync8, readdirSync as readdirSync4 } from "fs";
2703
+ import { realpathSync as realpathSync2, existsSync as existsSync5, readFileSync as readFileSync9, readdirSync as readdirSync4 } from "fs";
2494
2704
  import { resolve as resolve5, extname } from "path";
2495
2705
 
2496
- // app/lib/data-path.ts
2497
- import { realpathSync } from "fs";
2498
- import { resolve as resolve4, normalize, sep, relative, basename, join as join4 } from "path";
2499
- var PLATFORM_ROOT2 = process.env.MAXY_PLATFORM_ROOT ?? resolve4(process.cwd(), "../platform");
2500
- var DATA_ROOT = resolve4(PLATFORM_ROOT2, "..", "data");
2501
- var CLAUDE_UPLOADS_ROOT = process.env.CLAUDE_CONFIG_DIR ? resolve4(process.env.CLAUDE_CONFIG_DIR, "uploads") : null;
2502
- var ACCOUNT_PARTITION_DIRS = /* @__PURE__ */ new Set(["accounts"]);
2503
- var ACCOUNT_UUID_RE = /^[0-9a-f]{8}-[0-9a-f]{4}-[0-9a-f]{4}-[0-9a-f]{4}-[0-9a-f]{12}$/i;
2504
- function crossesForeignAccountPartition(relPath, accountId) {
2505
- const segs = relPath.split("/").filter(Boolean);
2506
- if (segs.length < 2) return false;
2507
- if (!ACCOUNT_PARTITION_DIRS.has(segs[0])) return false;
2508
- const owner = segs[1];
2509
- if (!ACCOUNT_UUID_RE.test(owner)) return false;
2510
- return owner !== accountId;
2511
- }
2512
- function isWithinOwnAccountPartition(relPath, accountId) {
2513
- const segs = relPath.split("/").filter(Boolean);
2514
- return segs.length >= 2 && segs[0] === "accounts" && segs[1] === accountId;
2515
- }
2516
- function resolveUnderRoot(raw, rootAbs, rootLabel) {
2517
- const cleaned = normalize("/" + (raw ?? "").replace(/\\/g, "/")).replace(/^\/+/, "");
2518
- const absolute = resolve4(rootAbs, cleaned);
2519
- let rootReal;
2520
- try {
2521
- rootReal = realpathSync(rootAbs);
2522
- } catch (err) {
2523
- return {
2524
- ok: false,
2525
- status: 500,
2526
- error: `${rootLabel} not accessible: ${err instanceof Error ? err.message : String(err)}`
2527
- };
2528
- }
2529
- let resolvedReal;
2530
- try {
2531
- resolvedReal = realpathSync(absolute);
2532
- } catch (err) {
2533
- const code = err.code;
2534
- if (code === "ENOENT") {
2535
- if (absolute !== rootReal && !absolute.startsWith(rootReal + sep)) {
2536
- return { ok: false, status: 403, error: `Path escapes ${rootLabel}`, resolved: absolute };
2537
- }
2538
- return { ok: false, status: 404, error: "Not found" };
2539
- }
2540
- return {
2541
- ok: false,
2542
- status: 500,
2543
- error: err instanceof Error ? err.message : String(err)
2544
- };
2545
- }
2546
- if (resolvedReal !== rootReal && !resolvedReal.startsWith(rootReal + sep)) {
2547
- return { ok: false, status: 403, error: `Path escapes ${rootLabel}`, resolved: resolvedReal };
2548
- }
2549
- const relPath = relative(rootReal, resolvedReal) || ".";
2550
- return { ok: true, absolute: resolvedReal, dataRootReal: rootReal, relative: relPath };
2551
- }
2552
- function resolveDataPath(raw) {
2553
- return resolveUnderRoot(raw, DATA_ROOT, "DATA_ROOT");
2554
- }
2555
- function resolveClaudeUploadsPath(raw) {
2556
- if (!CLAUDE_UPLOADS_ROOT) {
2557
- return { ok: false, status: 404, error: "Not found" };
2558
- }
2559
- return resolveUnderRoot(raw, CLAUDE_UPLOADS_ROOT, "CLAUDE_UPLOADS_ROOT");
2560
- }
2561
- function scratchpadTmpBase() {
2562
- return process.env.MAXY_SCRATCHPAD_BASE ?? "/tmp";
2563
- }
2564
- function sessionScratchpadRoot(projectDir, sessionId) {
2565
- const uid = typeof process.geteuid === "function" ? process.geteuid() : 0;
2566
- return join4(scratchpadTmpBase(), `claude-${uid}`, basename(projectDir), sessionId, "scratchpad");
2567
- }
2568
- function resolveScratchpadPath(raw, scratchpadRootAbs) {
2569
- return resolveUnderRoot(raw, scratchpadRootAbs, "scratchpad");
2570
- }
2571
-
2572
2706
  // app/lib/doc-to-text.ts
2573
2707
  import { unzipSync, strFromU8 } from "fflate";
2574
2708
  var DOCX = "application/vnd.openxmlformats-officedocument.wordprocessingml.document";
@@ -2589,10 +2723,10 @@ function bareMime(mimeType) {
2589
2723
  function unescapeXml(s) {
2590
2724
  return s.replace(/&lt;/g, "<").replace(/&gt;/g, ">").replace(/&quot;/g, '"').replace(/&apos;/g, "'").replace(/&amp;/g, "&");
2591
2725
  }
2592
- function unzipEntry(buffer, entry) {
2726
+ function unzipEntry(buffer, entry2) {
2593
2727
  const files = unzipSync(new Uint8Array(buffer));
2594
- const bytes = files[entry];
2595
- if (!bytes) throw new Error(`zip entry not found: ${entry}`);
2728
+ const bytes = files[entry2];
2729
+ if (!bytes) throw new Error(`zip entry not found: ${entry2}`);
2596
2730
  return strFromU8(bytes);
2597
2731
  }
2598
2732
  function docxToText(buffer) {
@@ -2814,14 +2948,14 @@ async function storeMediaBuffer(accountId, attachmentId, filename, mimeType, buf
2814
2948
  return writeAttachment(accountId, "", filename, mimeType, buffer.byteLength, buffer, attachmentId);
2815
2949
  }
2816
2950
  function attachmentExists(accountId, attachmentId) {
2817
- return existsSync4(resolve5(uploadsDirFor(accountId, "", attachmentId), `${attachmentId}.meta.json`));
2951
+ return existsSync5(resolve5(uploadsDirFor(accountId, "", attachmentId), `${attachmentId}.meta.json`));
2818
2952
  }
2819
2953
  function resolveStoredAttachment(accountId, attachmentId) {
2820
2954
  if (!ATTACHMENT_ID_RE.test(attachmentId)) return null;
2821
2955
  const dir = uploadsDirFor(accountId, "", attachmentId);
2822
2956
  let meta;
2823
2957
  try {
2824
- meta = JSON.parse(readFileSync8(resolve5(dir, `${attachmentId}.meta.json`), "utf8"));
2958
+ meta = JSON.parse(readFileSync9(resolve5(dir, `${attachmentId}.meta.json`), "utf8"));
2825
2959
  } catch {
2826
2960
  return null;
2827
2961
  }
@@ -3171,7 +3305,7 @@ async function downloadInboundMedia(msg, sock, opts) {
3171
3305
  if (!res) return void 0;
3172
3306
  await mkdir2(MEDIA_DIR, { recursive: true });
3173
3307
  const ext = mimeToExt(res.mimetype);
3174
- const filePath = join5(MEDIA_DIR, `${randomUUID4()}.${ext}`);
3308
+ const filePath = join6(MEDIA_DIR, `${randomUUID4()}.${ext}`);
3175
3309
  await writeFile2(filePath, res.buffer);
3176
3310
  const sizeKB = (res.buffer.length / 1024).toFixed(0);
3177
3311
  console.error(`${TAG12} media downloaded type=${res.mimetype} size=${sizeKB}KB path=${filePath}`);
@@ -3607,13 +3741,13 @@ var messageStore = /* @__PURE__ */ new Map();
3607
3741
  function messageStoreKey(accountId, remoteJid) {
3608
3742
  return `${accountId}:${remoteJid}`;
3609
3743
  }
3610
- function storeMessage(storeKey, entry) {
3744
+ function storeMessage(storeKey, entry2) {
3611
3745
  let entries = messageStore.get(storeKey);
3612
3746
  if (!entries) {
3613
3747
  entries = [];
3614
3748
  messageStore.set(storeKey, entries);
3615
3749
  }
3616
- entries.push(entry);
3750
+ entries.push(entry2);
3617
3751
  if (entries.length > MESSAGE_STORE_MAX) {
3618
3752
  const trimmed = entries.length - MESSAGE_STORE_MAX;
3619
3753
  entries.splice(0, trimmed);
@@ -3870,6 +4004,7 @@ async function registerLoginSocket(accountId, sock, authDir) {
3870
4004
  applySelfIdentity(conn, sock, "register");
3871
4005
  connections.set(accountId, conn);
3872
4006
  monitorInbound(conn);
4007
+ monitorChatMetadata(conn);
3873
4008
  try {
3874
4009
  await sock.sendPresenceUpdate("available");
3875
4010
  console.error(`${TAG16} presence set to available account=${accountId}`);
@@ -3991,6 +4126,7 @@ async function connectWithReconnect(conn) {
3991
4126
  conn.sock = sock;
3992
4127
  applySelfIdentity(conn, sock, "pre-listener");
3993
4128
  monitorInbound(conn);
4129
+ monitorChatMetadata(conn);
3994
4130
  console.error(`${TAG16} socket created account=${conn.accountId} \u2014 waiting for connection`);
3995
4131
  await waitForConnection(sock);
3996
4132
  connectedAt = Date.now();
@@ -4122,6 +4258,95 @@ function applySelfIdentity(conn, sock, phase) {
4122
4258
  );
4123
4259
  }
4124
4260
  }
4261
+ function monitorChatMetadata(conn) {
4262
+ if (!conn.sock) return;
4263
+ const sock = conn.sock;
4264
+ const account = conn.platformAccountId;
4265
+ const canonicalise = async (entries) => {
4266
+ const out = [];
4267
+ for (const e of entries) {
4268
+ if (!e.jid.endsWith("@lid")) {
4269
+ out.push(e);
4270
+ continue;
4271
+ }
4272
+ const { canonical, resolved } = await resolveCanonicalConversationJid(e.jid, conn.lidMapping);
4273
+ if (resolved === "lid2pn") {
4274
+ console.error(`${TAG16} [wa-chatmeta] op=canonical raw=${e.jid} canonical=${canonical}`);
4275
+ out.push({ ...e, jid: canonical });
4276
+ } else {
4277
+ out.push(e);
4278
+ }
4279
+ }
4280
+ return out;
4281
+ };
4282
+ const persist = (kind, entries, perJid) => {
4283
+ if (entries.length === 0) return;
4284
+ if (perJid) {
4285
+ for (const e of entries) {
4286
+ console.error(
4287
+ `${TAG16} [wa-chatmeta] op=event kind=${kind} jid=${e.jid} name=${e.name.length} source=${e.source}`
4288
+ );
4289
+ }
4290
+ }
4291
+ const total = writeChatMetadataMerged(account, entries);
4292
+ console.error(
4293
+ `${TAG16} [wa-chatmeta] op=persist kind=${kind} account=${account.slice(0, 8)} updates=${entries.length} outcome=${total < 0 ? "fail" : "ok"} entries=${total}`
4294
+ );
4295
+ };
4296
+ sock.ev.on("messaging-history.set", ({ chats, contacts }) => {
4297
+ const nowIso = (/* @__PURE__ */ new Date()).toISOString();
4298
+ const chatEntries = chatEntriesFromChats(chats ?? [], nowIso);
4299
+ const contactEntries = chatEntriesFromContacts(contacts ?? [], nowIso);
4300
+ console.error(
4301
+ `${TAG16} [wa-chatmeta] op=history-set account=${account.slice(0, 8)} chats=${chats?.length ?? 0} contacts=${contacts?.length ?? 0} groups=${chatEntries.filter((e) => e.isGroup).length} named=${chatEntries.length + contactEntries.length}`
4302
+ );
4303
+ void canonicalise([...chatEntries, ...contactEntries]).then((e) => persist("history-set", e, false));
4304
+ });
4305
+ sock.ev.on("chats.upsert", (chats) => {
4306
+ void canonicalise(chatEntriesFromChats(chats ?? [], (/* @__PURE__ */ new Date()).toISOString())).then((e) => persist("chats.upsert", e, true));
4307
+ });
4308
+ sock.ev.on("chats.update", (chats) => {
4309
+ void canonicalise(chatEntriesFromChats(chats ?? [], (/* @__PURE__ */ new Date()).toISOString())).then((e) => persist("chats.update", e, true));
4310
+ });
4311
+ sock.ev.on("contacts.upsert", (contacts) => {
4312
+ void canonicalise(chatEntriesFromContacts(contacts ?? [], (/* @__PURE__ */ new Date()).toISOString())).then((e) => persist("contacts.upsert", e, true));
4313
+ });
4314
+ sock.ev.on("contacts.update", (contacts) => {
4315
+ void canonicalise(chatEntriesFromContacts(contacts ?? [], (/* @__PURE__ */ new Date()).toISOString())).then((e) => persist("contacts.update", e, true));
4316
+ });
4317
+ sock.ev.on("groups.update", (updates) => {
4318
+ persist("groups.update", groupEntriesFromUpdates(updates ?? [], (/* @__PURE__ */ new Date()).toISOString()), true);
4319
+ });
4320
+ const groupFetchAttempted = /* @__PURE__ */ new Set();
4321
+ sock.ev.on("messages.upsert", async (upsert) => {
4322
+ for (const msg of upsert.messages ?? []) {
4323
+ const jid = msg.key?.remoteJid;
4324
+ if (!jid || !jid.endsWith("@g.us")) continue;
4325
+ if (groupFetchAttempted.has(jid)) continue;
4326
+ if (readChatMetadata(account).get(jid)?.source === "group") continue;
4327
+ groupFetchAttempted.add(jid);
4328
+ const startedAt = Date.now();
4329
+ try {
4330
+ const meta = await sock.groupMetadata(jid);
4331
+ console.error(
4332
+ `${TAG16} [wa-chatmeta] op=group-fetch jid=${jid} ms=${Date.now() - startedAt} outcome=ok`
4333
+ );
4334
+ persist(
4335
+ "group-fetch",
4336
+ groupEntriesFromUpdates([{ id: jid, subject: meta.subject }], (/* @__PURE__ */ new Date()).toISOString()),
4337
+ true
4338
+ );
4339
+ } catch (err) {
4340
+ console.error(
4341
+ `${TAG16} [wa-chatmeta] op=group-fetch jid=${jid} ms=${Date.now() - startedAt} outcome=fail reason=${(err instanceof Error ? err.message : String(err)).slice(0, 100)}`
4342
+ );
4343
+ }
4344
+ }
4345
+ });
4346
+ }
4347
+ function listConnections() {
4348
+ return [...connections.values()];
4349
+ }
4125
4350
  function monitorInbound(conn) {
4126
4351
  if (!conn.sock || !onInboundMessage) return;
4127
4352
  const sock = conn.sock;
@@ -4130,8 +4355,8 @@ function monitorInbound(conn) {
4130
4355
  conn.debouncer = createInboundDebouncer({
4131
4356
  debounceMs,
4132
4357
  buildKey: (payload) => {
4133
- const conversationKey = payload.isGroup ? payload.groupJid : payload.senderPhone;
4134
- return `${payload.accountId}:${conversationKey ?? payload.senderPhone}:${payload.senderPhone}`;
4358
+ const conversationKey2 = payload.isGroup ? payload.groupJid : payload.senderPhone;
4359
+ return `${payload.accountId}:${conversationKey2 ?? payload.senderPhone}:${payload.senderPhone}`;
4135
4360
  },
4136
4361
  onFlush: (entries) => {
4137
4362
  if (!onInboundMessage) return;
@@ -4480,9 +4705,9 @@ function monitorInbound(conn) {
4480
4705
  });
4481
4706
  console.error(`[whatsapp-reaction] op=subscribed account=${conn.platformAccountId}`);
4482
4707
  sock.ev.on("messages.reaction", async (reactions) => {
4483
- for (const entry of reactions) {
4708
+ for (const entry2 of reactions) {
4484
4709
  try {
4485
- const sig = readReactionEntry(entry);
4710
+ const sig = readReactionEntry(entry2);
4486
4711
  if (!sig) continue;
4487
4712
  if (sig.fromMe) continue;
4488
4713
  const reactorTelephone = await resolveJidToE164(sig.reactorJid, conn.lidMapping) ?? sig.reactorJid;
@@ -4653,8 +4878,8 @@ async function handleInboundMessage(conn, msg) {
4653
4878
  }
4654
4879
  }
4655
4880
  if (extracted.mediaType === "audio" && mediaResult?.path) {
4656
- const conversationKey = isGroup ? remoteJid : senderPhone;
4657
- const debounceKey = `${conn.accountId}:${conversationKey}:${senderPhone}`;
4881
+ const conversationKey2 = isGroup ? remoteJid : senderPhone;
4882
+ const debounceKey = `${conn.accountId}:${conversationKey2}:${senderPhone}`;
4658
4883
  let resolvePending;
4659
4884
  const sttPending = new Promise((resolve6) => {
4660
4885
  resolvePending = resolve6;
@@ -4795,6 +5020,7 @@ export {
4795
5020
  managerPhonesForAccount,
4796
5021
  isAdminPhone,
4797
5022
  shouldDispatchInbound,
5023
+ formatSenderPhone,
4798
5024
  checkAccessRateLimit,
4799
5025
  recordAccessFailedAttempt,
4800
5026
  clearAccessRateLimit,
@@ -4813,10 +5039,6 @@ export {
4813
5039
  sendComposing,
4814
5040
  sendPaused,
4815
5041
  sendMediaMessage,
4816
- resolvePlatformAccountId,
4817
- warnNonUuidAccount,
4818
- isHouseManagedService,
4819
- isCustomerTurnSuppressed,
4820
5042
  DATA_ROOT,
4821
5043
  crossesForeignAccountPartition,
4822
5044
  isWithinOwnAccountPartition,
@@ -4824,6 +5046,13 @@ export {
4824
5046
  resolveClaudeUploadsPath,
4825
5047
  sessionScratchpadRoot,
4826
5048
  resolveScratchpadPath,
5049
+ readChatMetadata,
5050
+ writeChatMetadataMerged,
5051
+ groupEntriesFromUpdates,
5052
+ resolvePlatformAccountId,
5053
+ warnNonUuidAccount,
5054
+ isHouseManagedService,
5055
+ isCustomerTurnSuppressed,
4827
5056
  SUPPORTED_MIME_TYPES,
4828
5057
  MAX_FILE_SIZE_BYTES,
4829
5058
  MAX_FILES_PER_MESSAGE,
@@ -4866,5 +5095,6 @@ export {
4866
5095
  getMessages,
4867
5096
  listConversationJids,
4868
5097
  listStoreAccountKeys,
4869
- shutdown
5098
+ shutdown,
5099
+ listConnections
4870
5100
  };