@spinabot/brigade 1.6.1 → 1.8.0

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 (339) hide show
  1. package/dist/agents/agent-loop.d.ts +13 -0
  2. package/dist/agents/agent-loop.d.ts.map +1 -1
  3. package/dist/agents/agent-loop.js +5 -0
  4. package/dist/agents/agent-loop.js.map +1 -1
  5. package/dist/agents/channels/access-control/group-tool-policy.d.ts +73 -0
  6. package/dist/agents/channels/access-control/group-tool-policy.d.ts.map +1 -0
  7. package/dist/agents/channels/access-control/group-tool-policy.js +193 -0
  8. package/dist/agents/channels/access-control/group-tool-policy.js.map +1 -0
  9. package/dist/agents/channels/access-control/index.d.ts +1 -0
  10. package/dist/agents/channels/access-control/index.d.ts.map +1 -1
  11. package/dist/agents/channels/access-control/index.js +1 -0
  12. package/dist/agents/channels/access-control/index.js.map +1 -1
  13. package/dist/agents/channels/bluebubbles/account-config.d.ts +253 -0
  14. package/dist/agents/channels/bluebubbles/account-config.d.ts.map +1 -0
  15. package/dist/agents/channels/bluebubbles/account-config.js +486 -0
  16. package/dist/agents/channels/bluebubbles/account-config.js.map +1 -0
  17. package/dist/agents/channels/bluebubbles/account-registry.d.ts +33 -0
  18. package/dist/agents/channels/bluebubbles/account-registry.d.ts.map +1 -0
  19. package/dist/agents/channels/bluebubbles/account-registry.js +46 -0
  20. package/dist/agents/channels/bluebubbles/account-registry.js.map +1 -0
  21. package/dist/agents/channels/bluebubbles/adapter.d.ts +45 -0
  22. package/dist/agents/channels/bluebubbles/adapter.d.ts.map +1 -0
  23. package/dist/agents/channels/bluebubbles/adapter.js +366 -0
  24. package/dist/agents/channels/bluebubbles/adapter.js.map +1 -0
  25. package/dist/agents/channels/bluebubbles/catchup-cursor.d.ts +52 -0
  26. package/dist/agents/channels/bluebubbles/catchup-cursor.d.ts.map +1 -0
  27. package/dist/agents/channels/bluebubbles/catchup-cursor.js +118 -0
  28. package/dist/agents/channels/bluebubbles/catchup-cursor.js.map +1 -0
  29. package/dist/agents/channels/bluebubbles/catchup.d.ts +114 -0
  30. package/dist/agents/channels/bluebubbles/catchup.d.ts.map +1 -0
  31. package/dist/agents/channels/bluebubbles/catchup.js +220 -0
  32. package/dist/agents/channels/bluebubbles/catchup.js.map +1 -0
  33. package/dist/agents/channels/bluebubbles/chat.d.ts +75 -0
  34. package/dist/agents/channels/bluebubbles/chat.d.ts.map +1 -0
  35. package/dist/agents/channels/bluebubbles/chat.js +182 -0
  36. package/dist/agents/channels/bluebubbles/chat.js.map +1 -0
  37. package/dist/agents/channels/bluebubbles/connection.d.ts +95 -0
  38. package/dist/agents/channels/bluebubbles/connection.d.ts.map +1 -0
  39. package/dist/agents/channels/bluebubbles/connection.js +413 -0
  40. package/dist/agents/channels/bluebubbles/connection.js.map +1 -0
  41. package/dist/agents/channels/bluebubbles/contact-names.d.ts +79 -0
  42. package/dist/agents/channels/bluebubbles/contact-names.d.ts.map +1 -0
  43. package/dist/agents/channels/bluebubbles/contact-names.js +188 -0
  44. package/dist/agents/channels/bluebubbles/contact-names.js.map +1 -0
  45. package/dist/agents/channels/bluebubbles/debounce.d.ts +78 -0
  46. package/dist/agents/channels/bluebubbles/debounce.d.ts.map +1 -0
  47. package/dist/agents/channels/bluebubbles/debounce.js +173 -0
  48. package/dist/agents/channels/bluebubbles/debounce.js.map +1 -0
  49. package/dist/agents/channels/bluebubbles/dedupe.d.ts +25 -0
  50. package/dist/agents/channels/bluebubbles/dedupe.d.ts.map +1 -0
  51. package/dist/agents/channels/bluebubbles/dedupe.js +35 -0
  52. package/dist/agents/channels/bluebubbles/dedupe.js.map +1 -0
  53. package/dist/agents/channels/bluebubbles/effects.d.ts +17 -0
  54. package/dist/agents/channels/bluebubbles/effects.d.ts.map +1 -0
  55. package/dist/agents/channels/bluebubbles/effects.js +57 -0
  56. package/dist/agents/channels/bluebubbles/effects.js.map +1 -0
  57. package/dist/agents/channels/bluebubbles/history.d.ts +56 -0
  58. package/dist/agents/channels/bluebubbles/history.d.ts.map +1 -0
  59. package/dist/agents/channels/bluebubbles/history.js +140 -0
  60. package/dist/agents/channels/bluebubbles/history.js.map +1 -0
  61. package/dist/agents/channels/bluebubbles/index.d.ts +18 -0
  62. package/dist/agents/channels/bluebubbles/index.d.ts.map +1 -0
  63. package/dist/agents/channels/bluebubbles/index.js +18 -0
  64. package/dist/agents/channels/bluebubbles/index.js.map +1 -0
  65. package/dist/agents/channels/bluebubbles/media.d.ts +104 -0
  66. package/dist/agents/channels/bluebubbles/media.d.ts.map +1 -0
  67. package/dist/agents/channels/bluebubbles/media.js +222 -0
  68. package/dist/agents/channels/bluebubbles/media.js.map +1 -0
  69. package/dist/agents/channels/bluebubbles/messaging.d.ts +13 -0
  70. package/dist/agents/channels/bluebubbles/messaging.d.ts.map +1 -0
  71. package/dist/agents/channels/bluebubbles/messaging.js +36 -0
  72. package/dist/agents/channels/bluebubbles/messaging.js.map +1 -0
  73. package/dist/agents/channels/bluebubbles/module.d.ts +24 -0
  74. package/dist/agents/channels/bluebubbles/module.d.ts.map +1 -0
  75. package/dist/agents/channels/bluebubbles/module.js +52 -0
  76. package/dist/agents/channels/bluebubbles/module.js.map +1 -0
  77. package/dist/agents/channels/bluebubbles/normalize.d.ts +111 -0
  78. package/dist/agents/channels/bluebubbles/normalize.d.ts.map +1 -0
  79. package/dist/agents/channels/bluebubbles/normalize.js +239 -0
  80. package/dist/agents/channels/bluebubbles/normalize.js.map +1 -0
  81. package/dist/agents/channels/bluebubbles/plugin.d.ts +46 -0
  82. package/dist/agents/channels/bluebubbles/plugin.d.ts.map +1 -0
  83. package/dist/agents/channels/bluebubbles/plugin.js +242 -0
  84. package/dist/agents/channels/bluebubbles/plugin.js.map +1 -0
  85. package/dist/agents/channels/bluebubbles/probe.d.ts +79 -0
  86. package/dist/agents/channels/bluebubbles/probe.d.ts.map +1 -0
  87. package/dist/agents/channels/bluebubbles/probe.js +138 -0
  88. package/dist/agents/channels/bluebubbles/probe.js.map +1 -0
  89. package/dist/agents/channels/bluebubbles/reactions.d.ts +46 -0
  90. package/dist/agents/channels/bluebubbles/reactions.d.ts.map +1 -0
  91. package/dist/agents/channels/bluebubbles/reactions.js +207 -0
  92. package/dist/agents/channels/bluebubbles/reactions.js.map +1 -0
  93. package/dist/agents/channels/bluebubbles/send.d.ts +132 -0
  94. package/dist/agents/channels/bluebubbles/send.d.ts.map +1 -0
  95. package/dist/agents/channels/bluebubbles/send.js +327 -0
  96. package/dist/agents/channels/bluebubbles/send.js.map +1 -0
  97. package/dist/agents/channels/bluebubbles/status-issues.d.ts +57 -0
  98. package/dist/agents/channels/bluebubbles/status-issues.d.ts.map +1 -0
  99. package/dist/agents/channels/bluebubbles/status-issues.js +93 -0
  100. package/dist/agents/channels/bluebubbles/status-issues.js.map +1 -0
  101. package/dist/agents/channels/bluebubbles/types.d.ts +69 -0
  102. package/dist/agents/channels/bluebubbles/types.d.ts.map +1 -0
  103. package/dist/agents/channels/bluebubbles/types.js +118 -0
  104. package/dist/agents/channels/bluebubbles/types.js.map +1 -0
  105. package/dist/agents/channels/bluebubbles/webhook.d.ts +97 -0
  106. package/dist/agents/channels/bluebubbles/webhook.d.ts.map +1 -0
  107. package/dist/agents/channels/bluebubbles/webhook.js +249 -0
  108. package/dist/agents/channels/bluebubbles/webhook.js.map +1 -0
  109. package/dist/agents/channels/bundled-channel-metas.d.ts +13 -0
  110. package/dist/agents/channels/bundled-channel-metas.d.ts.map +1 -1
  111. package/dist/agents/channels/bundled-channel-metas.js +33 -0
  112. package/dist/agents/channels/bundled-channel-metas.js.map +1 -1
  113. package/dist/agents/channels/discord/account-config.d.ts +60 -0
  114. package/dist/agents/channels/discord/account-config.d.ts.map +1 -1
  115. package/dist/agents/channels/discord/account-config.js +89 -0
  116. package/dist/agents/channels/discord/account-config.js.map +1 -1
  117. package/dist/agents/channels/discord/adapter.d.ts +24 -1
  118. package/dist/agents/channels/discord/adapter.d.ts.map +1 -1
  119. package/dist/agents/channels/discord/adapter.js +208 -41
  120. package/dist/agents/channels/discord/adapter.js.map +1 -1
  121. package/dist/agents/channels/discord/component-blocks.d.ts +108 -0
  122. package/dist/agents/channels/discord/component-blocks.d.ts.map +1 -0
  123. package/dist/agents/channels/discord/component-blocks.js +113 -0
  124. package/dist/agents/channels/discord/component-blocks.js.map +1 -0
  125. package/dist/agents/channels/discord/components.d.ts +78 -0
  126. package/dist/agents/channels/discord/components.d.ts.map +1 -1
  127. package/dist/agents/channels/discord/components.js +89 -0
  128. package/dist/agents/channels/discord/components.js.map +1 -1
  129. package/dist/agents/channels/discord/connection.d.ts +195 -12
  130. package/dist/agents/channels/discord/connection.d.ts.map +1 -1
  131. package/dist/agents/channels/discord/connection.js +852 -38
  132. package/dist/agents/channels/discord/connection.js.map +1 -1
  133. package/dist/agents/channels/discord/directory-cache.d.ts +47 -0
  134. package/dist/agents/channels/discord/directory-cache.d.ts.map +1 -0
  135. package/dist/agents/channels/discord/directory-cache.js +131 -0
  136. package/dist/agents/channels/discord/directory-cache.js.map +1 -0
  137. package/dist/agents/channels/discord/directory-live.d.ts +61 -0
  138. package/dist/agents/channels/discord/directory-live.d.ts.map +1 -0
  139. package/dist/agents/channels/discord/directory-live.js +140 -0
  140. package/dist/agents/channels/discord/directory-live.js.map +1 -0
  141. package/dist/agents/channels/discord/format.d.ts +15 -0
  142. package/dist/agents/channels/discord/format.d.ts.map +1 -1
  143. package/dist/agents/channels/discord/format.js +56 -0
  144. package/dist/agents/channels/discord/format.js.map +1 -1
  145. package/dist/agents/channels/discord/guilds.d.ts +25 -0
  146. package/dist/agents/channels/discord/guilds.d.ts.map +1 -0
  147. package/dist/agents/channels/discord/guilds.js +46 -0
  148. package/dist/agents/channels/discord/guilds.js.map +1 -0
  149. package/dist/agents/channels/discord/inbound-extras.d.ts +166 -9
  150. package/dist/agents/channels/discord/inbound-extras.d.ts.map +1 -1
  151. package/dist/agents/channels/discord/inbound-extras.js +246 -8
  152. package/dist/agents/channels/discord/inbound-extras.js.map +1 -1
  153. package/dist/agents/channels/discord/index.d.ts +10 -3
  154. package/dist/agents/channels/discord/index.d.ts.map +1 -1
  155. package/dist/agents/channels/discord/index.js +10 -3
  156. package/dist/agents/channels/discord/index.js.map +1 -1
  157. package/dist/agents/channels/discord/modal-registry.d.ts +89 -0
  158. package/dist/agents/channels/discord/modal-registry.d.ts.map +1 -0
  159. package/dist/agents/channels/discord/modal-registry.js +104 -0
  160. package/dist/agents/channels/discord/modal-registry.js.map +1 -0
  161. package/dist/agents/channels/discord/modals.d.ts +100 -0
  162. package/dist/agents/channels/discord/modals.d.ts.map +1 -0
  163. package/dist/agents/channels/discord/modals.js +124 -0
  164. package/dist/agents/channels/discord/modals.js.map +1 -0
  165. package/dist/agents/channels/discord/permission-audit.d.ts +43 -0
  166. package/dist/agents/channels/discord/permission-audit.d.ts.map +1 -0
  167. package/dist/agents/channels/discord/permission-audit.js +192 -0
  168. package/dist/agents/channels/discord/permission-audit.js.map +1 -0
  169. package/dist/agents/channels/discord/plugin.d.ts +18 -2
  170. package/dist/agents/channels/discord/plugin.d.ts.map +1 -1
  171. package/dist/agents/channels/discord/plugin.js +73 -4
  172. package/dist/agents/channels/discord/plugin.js.map +1 -1
  173. package/dist/agents/channels/discord/probe.d.ts +23 -1
  174. package/dist/agents/channels/discord/probe.d.ts.map +1 -1
  175. package/dist/agents/channels/discord/probe.js +40 -5
  176. package/dist/agents/channels/discord/probe.js.map +1 -1
  177. package/dist/agents/channels/discord/rest-actions.d.ts +346 -0
  178. package/dist/agents/channels/discord/rest-actions.d.ts.map +1 -0
  179. package/dist/agents/channels/discord/rest-actions.js +559 -0
  180. package/dist/agents/channels/discord/rest-actions.js.map +1 -0
  181. package/dist/agents/channels/discord/rest-components.d.ts +122 -0
  182. package/dist/agents/channels/discord/rest-components.d.ts.map +1 -0
  183. package/dist/agents/channels/discord/rest-components.js +243 -0
  184. package/dist/agents/channels/discord/rest-components.js.map +1 -0
  185. package/dist/agents/channels/discord/security-audit.d.ts +29 -0
  186. package/dist/agents/channels/discord/security-audit.d.ts.map +1 -0
  187. package/dist/agents/channels/discord/security-audit.js +94 -0
  188. package/dist/agents/channels/discord/security-audit.js.map +1 -0
  189. package/dist/agents/channels/discord/security-doctor.d.ts +43 -0
  190. package/dist/agents/channels/discord/security-doctor.d.ts.map +1 -0
  191. package/dist/agents/channels/discord/security-doctor.js +83 -0
  192. package/dist/agents/channels/discord/security-doctor.js.map +1 -0
  193. package/dist/agents/channels/discord/status-issues.d.ts +37 -0
  194. package/dist/agents/channels/discord/status-issues.d.ts.map +1 -0
  195. package/dist/agents/channels/discord/status-issues.js +66 -0
  196. package/dist/agents/channels/discord/status-issues.js.map +1 -0
  197. package/dist/agents/channels/discord/subagent-thread-binding-store.d.ts +57 -0
  198. package/dist/agents/channels/discord/subagent-thread-binding-store.d.ts.map +1 -0
  199. package/dist/agents/channels/discord/subagent-thread-binding-store.js +98 -0
  200. package/dist/agents/channels/discord/subagent-thread-binding-store.js.map +1 -0
  201. package/dist/agents/channels/discord/subagent-thread-binding.d.ts +95 -0
  202. package/dist/agents/channels/discord/subagent-thread-binding.d.ts.map +1 -0
  203. package/dist/agents/channels/discord/subagent-thread-binding.js +208 -0
  204. package/dist/agents/channels/discord/subagent-thread-binding.js.map +1 -0
  205. package/dist/agents/channels/discord/system-events.d.ts +31 -0
  206. package/dist/agents/channels/discord/system-events.d.ts.map +1 -0
  207. package/dist/agents/channels/discord/system-events.js +74 -0
  208. package/dist/agents/channels/discord/system-events.js.map +1 -0
  209. package/dist/agents/channels/general-callback.d.ts +12 -0
  210. package/dist/agents/channels/general-callback.d.ts.map +1 -1
  211. package/dist/agents/channels/general-callback.js +18 -0
  212. package/dist/agents/channels/general-callback.js.map +1 -1
  213. package/dist/agents/channels/imessage/account-config.d.ts +178 -0
  214. package/dist/agents/channels/imessage/account-config.d.ts.map +1 -0
  215. package/dist/agents/channels/imessage/account-config.js +371 -0
  216. package/dist/agents/channels/imessage/account-config.js.map +1 -0
  217. package/dist/agents/channels/imessage/adapter.d.ts +36 -0
  218. package/dist/agents/channels/imessage/adapter.d.ts.map +1 -0
  219. package/dist/agents/channels/imessage/adapter.js +286 -0
  220. package/dist/agents/channels/imessage/adapter.js.map +1 -0
  221. package/dist/agents/channels/imessage/client.d.ts +99 -0
  222. package/dist/agents/channels/imessage/client.d.ts.map +1 -0
  223. package/dist/agents/channels/imessage/client.js +231 -0
  224. package/dist/agents/channels/imessage/client.js.map +1 -0
  225. package/dist/agents/channels/imessage/connection.d.ts +101 -0
  226. package/dist/agents/channels/imessage/connection.d.ts.map +1 -0
  227. package/dist/agents/channels/imessage/connection.js +367 -0
  228. package/dist/agents/channels/imessage/connection.js.map +1 -0
  229. package/dist/agents/channels/imessage/format.d.ts +45 -0
  230. package/dist/agents/channels/imessage/format.d.ts.map +1 -0
  231. package/dist/agents/channels/imessage/format.js +170 -0
  232. package/dist/agents/channels/imessage/format.js.map +1 -0
  233. package/dist/agents/channels/imessage/history.d.ts +49 -0
  234. package/dist/agents/channels/imessage/history.d.ts.map +1 -0
  235. package/dist/agents/channels/imessage/history.js +74 -0
  236. package/dist/agents/channels/imessage/history.js.map +1 -0
  237. package/dist/agents/channels/imessage/index.d.ts +25 -0
  238. package/dist/agents/channels/imessage/index.d.ts.map +1 -0
  239. package/dist/agents/channels/imessage/index.js +25 -0
  240. package/dist/agents/channels/imessage/index.js.map +1 -0
  241. package/dist/agents/channels/imessage/media.d.ts +92 -0
  242. package/dist/agents/channels/imessage/media.d.ts.map +1 -0
  243. package/dist/agents/channels/imessage/media.js +196 -0
  244. package/dist/agents/channels/imessage/media.js.map +1 -0
  245. package/dist/agents/channels/imessage/messaging.d.ts +14 -0
  246. package/dist/agents/channels/imessage/messaging.d.ts.map +1 -0
  247. package/dist/agents/channels/imessage/messaging.js +37 -0
  248. package/dist/agents/channels/imessage/messaging.js.map +1 -0
  249. package/dist/agents/channels/imessage/module.d.ts +16 -0
  250. package/dist/agents/channels/imessage/module.d.ts.map +1 -0
  251. package/dist/agents/channels/imessage/module.js +23 -0
  252. package/dist/agents/channels/imessage/module.js.map +1 -0
  253. package/dist/agents/channels/imessage/monitor.d.ts +207 -0
  254. package/dist/agents/channels/imessage/monitor.d.ts.map +1 -0
  255. package/dist/agents/channels/imessage/monitor.js +504 -0
  256. package/dist/agents/channels/imessage/monitor.js.map +1 -0
  257. package/dist/agents/channels/imessage/plugin.d.ts +53 -0
  258. package/dist/agents/channels/imessage/plugin.d.ts.map +1 -0
  259. package/dist/agents/channels/imessage/plugin.js +215 -0
  260. package/dist/agents/channels/imessage/plugin.js.map +1 -0
  261. package/dist/agents/channels/imessage/probe.d.ts +68 -0
  262. package/dist/agents/channels/imessage/probe.d.ts.map +1 -0
  263. package/dist/agents/channels/imessage/probe.js +134 -0
  264. package/dist/agents/channels/imessage/probe.js.map +1 -0
  265. package/dist/agents/channels/imessage/remote-attachments.d.ts +61 -0
  266. package/dist/agents/channels/imessage/remote-attachments.d.ts.map +1 -0
  267. package/dist/agents/channels/imessage/remote-attachments.js +131 -0
  268. package/dist/agents/channels/imessage/remote-attachments.js.map +1 -0
  269. package/dist/agents/channels/imessage/send.d.ts +61 -0
  270. package/dist/agents/channels/imessage/send.d.ts.map +1 -0
  271. package/dist/agents/channels/imessage/send.js +108 -0
  272. package/dist/agents/channels/imessage/send.js.map +1 -0
  273. package/dist/agents/channels/imessage/targets.d.ts +91 -0
  274. package/dist/agents/channels/imessage/targets.d.ts.map +1 -0
  275. package/dist/agents/channels/imessage/targets.js +245 -0
  276. package/dist/agents/channels/imessage/targets.js.map +1 -0
  277. package/dist/agents/channels/imessage/watch-error.d.ts +23 -0
  278. package/dist/agents/channels/imessage/watch-error.d.ts.map +1 -0
  279. package/dist/agents/channels/imessage/watch-error.js +69 -0
  280. package/dist/agents/channels/imessage/watch-error.js.map +1 -0
  281. package/dist/agents/channels/inbound-pipeline.d.ts +11 -0
  282. package/dist/agents/channels/inbound-pipeline.d.ts.map +1 -1
  283. package/dist/agents/channels/inbound-pipeline.js +25 -4
  284. package/dist/agents/channels/inbound-pipeline.js.map +1 -1
  285. package/dist/agents/channels/manager.d.ts +9 -0
  286. package/dist/agents/channels/manager.d.ts.map +1 -1
  287. package/dist/agents/channels/manager.js.map +1 -1
  288. package/dist/agents/channels/sdk.d.ts +4 -0
  289. package/dist/agents/channels/sdk.d.ts.map +1 -1
  290. package/dist/agents/channels/sdk.js +4 -0
  291. package/dist/agents/channels/sdk.js.map +1 -1
  292. package/dist/agents/extensions/modules/index.d.ts.map +1 -1
  293. package/dist/agents/extensions/modules/index.js +12 -0
  294. package/dist/agents/extensions/modules/index.js.map +1 -1
  295. package/dist/agents/extensions/types.d.ts +7 -0
  296. package/dist/agents/extensions/types.d.ts.map +1 -1
  297. package/dist/agents/extensions/types.js.map +1 -1
  298. package/dist/agents/session-wiring.d.ts +31 -0
  299. package/dist/agents/session-wiring.d.ts.map +1 -1
  300. package/dist/agents/session-wiring.js +45 -2
  301. package/dist/agents/session-wiring.js.map +1 -1
  302. package/dist/agents/subagent-announce-delivery.d.ts +10 -0
  303. package/dist/agents/subagent-announce-delivery.d.ts.map +1 -1
  304. package/dist/agents/subagent-announce-delivery.js +1 -0
  305. package/dist/agents/subagent-announce-delivery.js.map +1 -1
  306. package/dist/agents/subagent-completion-bridge.d.ts.map +1 -1
  307. package/dist/agents/subagent-completion-bridge.js +81 -0
  308. package/dist/agents/subagent-completion-bridge.js.map +1 -1
  309. package/dist/agents/subagent-spawn.d.ts.map +1 -1
  310. package/dist/agents/subagent-spawn.js +57 -4
  311. package/dist/agents/subagent-spawn.js.map +1 -1
  312. package/dist/agents/tools/bluebubbles-action-tool.d.ts +66 -0
  313. package/dist/agents/tools/bluebubbles-action-tool.d.ts.map +1 -0
  314. package/dist/agents/tools/bluebubbles-action-tool.js +234 -0
  315. package/dist/agents/tools/bluebubbles-action-tool.js.map +1 -0
  316. package/dist/agents/tools/discord-action-tool.d.ts +224 -0
  317. package/dist/agents/tools/discord-action-tool.d.ts.map +1 -0
  318. package/dist/agents/tools/discord-action-tool.js +848 -0
  319. package/dist/agents/tools/discord-action-tool.js.map +1 -0
  320. package/dist/agents/tools/registry.d.ts.map +1 -1
  321. package/dist/agents/tools/registry.js +39 -0
  322. package/dist/agents/tools/registry.js.map +1 -1
  323. package/dist/agents/tools/sessions/index.d.ts +8 -0
  324. package/dist/agents/tools/sessions/index.d.ts.map +1 -1
  325. package/dist/agents/tools/sessions/index.js +15 -3
  326. package/dist/agents/tools/sessions/index.js.map +1 -1
  327. package/dist/buildstamp.json +1 -1
  328. package/dist/cli/commands/channels.d.ts +2 -0
  329. package/dist/cli/commands/channels.d.ts.map +1 -1
  330. package/dist/cli/commands/channels.js +58 -1
  331. package/dist/cli/commands/channels.js.map +1 -1
  332. package/dist/core/server.d.ts.map +1 -1
  333. package/dist/core/server.js +48 -2
  334. package/dist/core/server.js.map +1 -1
  335. package/dist/infra/net/fetch-guard.d.ts +24 -2
  336. package/dist/infra/net/fetch-guard.d.ts.map +1 -1
  337. package/dist/infra/net/fetch-guard.js +78 -31
  338. package/dist/infra/net/fetch-guard.js.map +1 -1
  339. package/package.json +1 -1
@@ -0,0 +1,207 @@
1
+ /**
2
+ * BlueBubbles tapback / reaction maps.
3
+ *
4
+ * iMessage "tapbacks" are the six canonical reactions. They cross the wire two
5
+ * different ways:
6
+ *
7
+ * OUTBOUND — the Private-API `message/react` endpoint takes a TYPE NAME string
8
+ * (`"love"`, `"like"`, …), with a leading `-` to REMOVE
9
+ * (`"-love"`). `normalizeBlueBubblesReaction` resolves any input — a type name,
10
+ * a common alias, or an emoji glyph — to that wire string.
11
+ *
12
+ * INBOUND — a tapback arrives as a MESSAGE whose `associatedMessageType` is a
13
+ * numeric code: `2000-2005` = ADD, `3000-3005` = REMOVE, in the canonical order
14
+ * love/like/dislike/laugh/emphasize/question. `decodeTapbackType` maps that
15
+ * code to `{ emoji, action }` so the inbound path can DROP the tapback as a
16
+ * normal message and (optionally) surface it as a reaction note.
17
+ */
18
+ /** Ordered tapback types — index N maps to the `200N` (add) / `300N` (remove) code. */
19
+ const REACTION_ORDER = [
20
+ "love",
21
+ "like",
22
+ "dislike",
23
+ "laugh",
24
+ "emphasize",
25
+ "question",
26
+ ];
27
+ /** Tapback type → its representative emoji (for inbound surfacing). */
28
+ const REACTION_EMOJI = {
29
+ love: "❤️",
30
+ like: "👍",
31
+ dislike: "👎",
32
+ laugh: "😂",
33
+ emphasize: "‼️",
34
+ question: "❓",
35
+ };
36
+ /**
37
+ * Text/name aliases → canonical type. Covers the canonical names, the
38
+ * Apple/Messages past-tense forms, and a broad colloquial set (`fire`, `wow`,
39
+ * `lmao`, `xd`, `ok`, `boo`, `heart_eyes`, `important`, `bang`, `ask`, …) so the
40
+ * agent can name a tapback however it likes.
41
+ */
42
+ const REACTION_ALIASES = {
43
+ // love
44
+ love: "love",
45
+ heart: "love",
46
+ loved: "love",
47
+ red_heart: "love",
48
+ heart_eyes: "love",
49
+ fire: "love",
50
+ // like
51
+ like: "like",
52
+ liked: "like",
53
+ thumbsup: "like",
54
+ thumb: "like",
55
+ "thumbs-up": "like",
56
+ "thumbs up": "like",
57
+ thumbs_up: "like",
58
+ ok: "like",
59
+ // dislike
60
+ dislike: "dislike",
61
+ disliked: "dislike",
62
+ thumbsdown: "dislike",
63
+ "thumbs-down": "dislike",
64
+ "thumbs down": "dislike",
65
+ thumbs_down: "dislike",
66
+ boo: "dislike",
67
+ no: "dislike",
68
+ // laugh
69
+ laugh: "laugh",
70
+ laughed: "laugh",
71
+ haha: "laugh",
72
+ lol: "laugh",
73
+ lmao: "laugh",
74
+ rofl: "laugh",
75
+ xd: "laugh",
76
+ smile: "laugh",
77
+ smiley: "laugh",
78
+ happy: "laugh",
79
+ joy: "laugh",
80
+ // emphasize / exclaim
81
+ emphasize: "emphasize",
82
+ emphasized: "emphasize",
83
+ emphasis: "emphasize",
84
+ exclaim: "emphasize",
85
+ important: "emphasize",
86
+ bang: "emphasize",
87
+ wow: "emphasize",
88
+ "!!": "emphasize",
89
+ "!": "emphasize",
90
+ // question
91
+ question: "question",
92
+ questioned: "question",
93
+ ask: "question",
94
+ "?": "question",
95
+ };
96
+ /** Emoji glyph → canonical type (resolves the common variants + the broadened set). */
97
+ const REACTION_EMOJIS = {
98
+ // love
99
+ "❤️": "love",
100
+ "❤": "love",
101
+ "♥️": "love",
102
+ "♥": "love",
103
+ "🩷": "love",
104
+ "😍": "love",
105
+ "💕": "love",
106
+ "🔥": "love",
107
+ // like
108
+ "👍": "like",
109
+ "👍🏻": "like",
110
+ "👌": "like",
111
+ // dislike
112
+ "👎": "dislike",
113
+ "👎🏻": "dislike",
114
+ "🙅": "dislike",
115
+ // laugh
116
+ "😂": "laugh",
117
+ "🤣": "laugh",
118
+ "😆": "laugh",
119
+ "😁": "laugh",
120
+ "😹": "laugh",
121
+ // emphasize
122
+ "‼️": "emphasize",
123
+ "‼": "emphasize",
124
+ "❗": "emphasize",
125
+ "❕": "emphasize",
126
+ // question
127
+ "❓": "question",
128
+ "❔": "question",
129
+ };
130
+ /**
131
+ * Resolve any reaction input to the BlueBubbles wire string for `message/react`.
132
+ * A leading `-` (e.g. `"-love"`) or the words `remove`/`removed` mark a REMOVAL.
133
+ * Returns null when the input doesn't map to a known tapback.
134
+ */
135
+ export function normalizeBlueBubblesReaction(raw) {
136
+ const trimmed = (raw ?? "").trim();
137
+ if (!trimmed)
138
+ return null;
139
+ let remove = false;
140
+ let body = trimmed;
141
+ if (body.startsWith("-")) {
142
+ remove = true;
143
+ body = body.slice(1).trim();
144
+ }
145
+ const lower = body.toLowerCase();
146
+ if (lower.startsWith("remove ") || lower.startsWith("removed ")) {
147
+ remove = true;
148
+ body = body.replace(/^removed?\s+/i, "").trim();
149
+ }
150
+ const type = resolveReactionType(body);
151
+ if (!type)
152
+ return null;
153
+ return remove ? `-${type}` : type;
154
+ }
155
+ /** Resolve a name/alias/emoji to a canonical reaction type (null when unknown). */
156
+ export function resolveReactionType(raw) {
157
+ const trimmed = (raw ?? "").trim();
158
+ if (!trimmed)
159
+ return null;
160
+ const lower = trimmed.toLowerCase();
161
+ if (REACTION_ALIASES[lower])
162
+ return REACTION_ALIASES[lower];
163
+ if (REACTION_EMOJIS[trimmed])
164
+ return REACTION_EMOJIS[trimmed];
165
+ // Bare canonical type passes through.
166
+ if (REACTION_ORDER.includes(lower))
167
+ return lower;
168
+ return null;
169
+ }
170
+ /**
171
+ * Decode an inbound `associatedMessageType` numeric code into a tapback. Codes
172
+ * `2000-2005` are ADD; `3000-3005` are REMOVE; the low digit selects the type in
173
+ * canonical order. Returns null for any non-tapback type.
174
+ */
175
+ export function decodeTapbackType(associatedMessageType) {
176
+ if (typeof associatedMessageType !== "number" || !Number.isFinite(associatedMessageType))
177
+ return null;
178
+ let action;
179
+ let index;
180
+ if (associatedMessageType >= 2000 && associatedMessageType <= 2005) {
181
+ action = "added";
182
+ index = associatedMessageType - 2000;
183
+ }
184
+ else if (associatedMessageType >= 3000 && associatedMessageType <= 3005) {
185
+ action = "removed";
186
+ index = associatedMessageType - 3000;
187
+ }
188
+ else {
189
+ return null;
190
+ }
191
+ const type = REACTION_ORDER[index];
192
+ if (!type)
193
+ return null;
194
+ return { type, emoji: REACTION_EMOJI[type], action };
195
+ }
196
+ /**
197
+ * True iff an `associatedMessageType` is in the tapback range at all (2000-3999).
198
+ * Used to DROP a tapback-as-message so it isn't replied to as normal text and so
199
+ * a reaction-association isn't mistaken for a reply target.
200
+ */
201
+ export function isTapbackAssociatedType(associatedMessageType) {
202
+ return (typeof associatedMessageType === "number" &&
203
+ Number.isFinite(associatedMessageType) &&
204
+ associatedMessageType >= 2000 &&
205
+ associatedMessageType < 4000);
206
+ }
207
+ //# sourceMappingURL=reactions.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"reactions.js","sourceRoot":"","sources":["../../../../src/agents/channels/bluebubbles/reactions.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,132 @@
1
+ /**
2
+ * BlueBubbles REST outbound.
3
+ *
4
+ * Every outbound action is a REST call to the BlueBubbles server, authenticated
5
+ * by the password in the query string (see `types.ts`). `fetch` is INJECTABLE on
6
+ * every function (the test seam) so the whole surface is exercised with no live
7
+ * server.
8
+ *
9
+ * Surface:
10
+ * - `sendBlueBubblesText` POST message/text (Private API adds reply-thread + effect)
11
+ * - `sendBlueBubblesAttachment` POST message/attachment (multipart; caption is a SEPARATE bubble after)
12
+ * - `reactBlueBubbles` POST message/react (Private API)
13
+ * - `editBlueBubblesMessage` POST message/{guid}/edit (Private API)
14
+ * - `unsendBlueBubblesMessage` POST message/{guid}/unsend (Private API)
15
+ * - `createBlueBubblesChat` POST chat/new (start a DM to a fresh handle)
16
+ * - `resolveChatGuid` map a target (handle / chat_id / chat_identifier) → chatGuid
17
+ *
18
+ * iMessage has NO native media caption, so an attachment send with a caption is
19
+ * delivered as the media bubble FOLLOWED BY a separate text bubble (the
20
+ * connection layer orchestrates the second send).
21
+ *
22
+ * `bubbleSplit` splits outbound text on BLANK LINES so multi-paragraph replies
23
+ * land as separate iMessage bubbles (each chunk = a separate text POST).
24
+ */
25
+ import { type FetchLike } from "./types.js";
26
+ /** Shared REST args every send helper takes. */
27
+ export interface BlueBubblesRestBase {
28
+ serverUrl: string;
29
+ password: string;
30
+ timeoutMs?: number;
31
+ /** TEST SEAM — inject a mock fetch. */
32
+ fetchImpl?: FetchLike;
33
+ /** When false, Private-API-only params (reply-thread, effect, react, edit…) are skipped/refused. */
34
+ privateApiEnabled?: boolean;
35
+ /** Allow private/LAN/loopback hosts through the SSRF guard (default TRUE for BlueBubbles). */
36
+ allowPrivateNetwork?: boolean;
37
+ }
38
+ /**
39
+ * Split outbound text into iMessage bubbles on BLANK lines. A run of text with
40
+ * no blank line stays one bubble; an empty result (whitespace only) yields []. A
41
+ * source with no blank line yields a single-element array (one bubble).
42
+ */
43
+ export declare function bubbleSplit(text: string): string[];
44
+ /** Result of an outbound send — the BlueBubbles message GUID when known. */
45
+ export interface BlueBubblesSendResult {
46
+ messageId?: string;
47
+ }
48
+ /**
49
+ * Create a new chat to a fresh handle (DM). Returns the new chat GUID. Requires
50
+ * the Private API for groups; a 1:1 chat may work without it on some servers.
51
+ */
52
+ export declare function createBlueBubblesChat(base: BlueBubblesRestBase, params: {
53
+ address: string;
54
+ message?: string;
55
+ }): Promise<string>;
56
+ /**
57
+ * Resolve an outbound conversation target to a real chatGuid.
58
+ *
59
+ * - `chat_guid:` — passes straight through (the HOT inbound→reply path; the
60
+ * webhook always delivers the chatGuid).
61
+ * - `chat_id:` / `chat_identifier:` — looked up against the server via
62
+ * `chat/query` (paged), matching the numeric id or the GUID's identifier
63
+ * component. Passing these raw produced a silent 400 on a cold send.
64
+ * - `handle` — looked up by participant in existing DM chats; if none exists a
65
+ * fresh `chat/new` is created.
66
+ *
67
+ * Returns the resolved chatGuid. Throws when a `chat_id`/`chat_identifier`
68
+ * target can't be resolved (the server has no such chat) rather than handing the
69
+ * server a bad key.
70
+ */
71
+ export declare function resolveChatGuid(base: BlueBubblesRestBase, target: string): Promise<string>;
72
+ /** Options for a text send. */
73
+ export interface SendTextOptions extends BlueBubblesRestBase {
74
+ /** Native reply-thread target (Private API): the message GUID to reply to. */
75
+ replyToMessageGuid?: string;
76
+ /** Part index of the replied-to message (Private API). */
77
+ replyToPartIndex?: number;
78
+ /** A send effect name (balloons/confetti/slam/…) — Private API. */
79
+ effect?: string;
80
+ }
81
+ /**
82
+ * Send ONE text bubble to a chatGuid. Use `bubbleSplit` + a loop for
83
+ * multi-bubble replies (the connection layer does this). Returns the message
84
+ * GUID when the server reports one.
85
+ */
86
+ export declare function sendBlueBubblesText(chatGuid: string, message: string, opts: SendTextOptions): Promise<BlueBubblesSendResult>;
87
+ /** Options for an attachment send. */
88
+ export interface SendAttachmentOptions extends BlueBubblesRestBase {
89
+ /** Local file path to upload. */
90
+ filePath: string;
91
+ /** Override the multipart filename (e.g. an extension coerced by the voice pre-flight). Defaults to the basename of `filePath`. */
92
+ fileName?: string;
93
+ /** MIME content type, when known. */
94
+ contentType?: string;
95
+ /** Send as a voice memo (BlueBubbles converts mp3→caf when set). */
96
+ asVoice?: boolean;
97
+ /** Native reply-thread target (Private API). */
98
+ replyToMessageGuid?: string;
99
+ replyToPartIndex?: number;
100
+ /** Pre-read bytes (TEST SEAM — bypass disk read). */
101
+ bytes?: Uint8Array;
102
+ }
103
+ /**
104
+ * Send a media attachment via multipart. iMessage has NO native caption, so the
105
+ * caller sends any caption as a SEPARATE text bubble AFTER this (handled by the
106
+ * connection layer). Returns the message GUID when reported.
107
+ */
108
+ export declare function sendBlueBubblesAttachment(chatGuid: string, opts: SendAttachmentOptions): Promise<BlueBubblesSendResult>;
109
+ /**
110
+ * Add or remove a tapback reaction on a message (Private API). `reaction` is any
111
+ * input `normalizeBlueBubblesReaction` accepts (`"love"`, `"👍"`, `"-love"` to
112
+ * remove). Throws when the Private API isn't available or the reaction is unknown.
113
+ */
114
+ export declare function reactBlueBubbles(base: BlueBubblesRestBase, params: {
115
+ chatGuid: string;
116
+ messageGuid: string;
117
+ reaction: string;
118
+ partIndex?: number;
119
+ }): Promise<void>;
120
+ /** Edit a previously-sent message (Private API, macOS 13+ / iMessage edit window). */
121
+ export declare function editBlueBubblesMessage(base: BlueBubblesRestBase, params: {
122
+ messageGuid: string;
123
+ editedMessage: string;
124
+ partIndex?: number;
125
+ backwardsCompatMessage?: string;
126
+ }): Promise<void>;
127
+ /** Unsend (retract) a previously-sent message (Private API, iMessage unsend window). */
128
+ export declare function unsendBlueBubblesMessage(base: BlueBubblesRestBase, params: {
129
+ messageGuid: string;
130
+ partIndex?: number;
131
+ }): Promise<void>;
132
+ //# sourceMappingURL=send.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"send.d.ts","sourceRoot":"","sources":["../../../../src/agents/channels/bluebubbles/send.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,327 @@
1
+ /**
2
+ * BlueBubbles REST outbound.
3
+ *
4
+ * Every outbound action is a REST call to the BlueBubbles server, authenticated
5
+ * by the password in the query string (see `types.ts`). `fetch` is INJECTABLE on
6
+ * every function (the test seam) so the whole surface is exercised with no live
7
+ * server.
8
+ *
9
+ * Surface:
10
+ * - `sendBlueBubblesText` POST message/text (Private API adds reply-thread + effect)
11
+ * - `sendBlueBubblesAttachment` POST message/attachment (multipart; caption is a SEPARATE bubble after)
12
+ * - `reactBlueBubbles` POST message/react (Private API)
13
+ * - `editBlueBubblesMessage` POST message/{guid}/edit (Private API)
14
+ * - `unsendBlueBubblesMessage` POST message/{guid}/unsend (Private API)
15
+ * - `createBlueBubblesChat` POST chat/new (start a DM to a fresh handle)
16
+ * - `resolveChatGuid` map a target (handle / chat_id / chat_identifier) → chatGuid
17
+ *
18
+ * iMessage has NO native media caption, so an attachment send with a caption is
19
+ * delivered as the media bubble FOLLOWED BY a separate text bubble (the
20
+ * connection layer orchestrates the second send).
21
+ *
22
+ * `bubbleSplit` splits outbound text on BLANK LINES so multi-paragraph replies
23
+ * land as separate iMessage bubbles (each chunk = a separate text POST).
24
+ */
25
+ import { randomUUID } from "node:crypto";
26
+ import { readFile } from "node:fs/promises";
27
+ import path from "node:path";
28
+ import { resolveEffectId } from "./effects.js";
29
+ import { normalizeBlueBubblesReaction } from "./reactions.js";
30
+ import { parseIMessageTarget } from "../imessage/targets.js";
31
+ import { blueBubblesFetchWithTimeout, buildBlueBubblesApiUrl, readBlueBubblesJson, } from "./types.js";
32
+ /**
33
+ * Shared fetch-option assembly so every helper threads timeout + fetchImpl +
34
+ * the SSRF private-network knob identically. `allowPrivateNetwork` defaults TRUE
35
+ * (a BlueBubbles server is normally on the operator's LAN); only forwarded as
36
+ * `false` when the operator tightened the knob.
37
+ */
38
+ function fetchOpts(base) {
39
+ return {
40
+ ...(base.timeoutMs !== undefined ? { timeoutMs: base.timeoutMs } : {}),
41
+ ...(base.fetchImpl ? { fetchImpl: base.fetchImpl } : {}),
42
+ ...(base.allowPrivateNetwork === false ? { allowPrivateNetwork: false } : {}),
43
+ };
44
+ }
45
+ /**
46
+ * Split outbound text into iMessage bubbles on BLANK lines. A run of text with
47
+ * no blank line stays one bubble; an empty result (whitespace only) yields []. A
48
+ * source with no blank line yields a single-element array (one bubble).
49
+ */
50
+ export function bubbleSplit(text) {
51
+ const src = (text ?? "").replace(/\r\n/g, "\n");
52
+ if (!src.trim())
53
+ return [];
54
+ return src
55
+ .split(/\n\s*\n/)
56
+ .map((b) => b.trim())
57
+ .filter((b) => b.length > 0);
58
+ }
59
+ /** Dig a message GUID out of a BlueBubbles send response (shape varies by version). */
60
+ function extractMessageGuid(data) {
61
+ if (!data || typeof data !== "object")
62
+ return undefined;
63
+ const rec = data;
64
+ const direct = rec.guid ?? rec.messageGuid ?? rec.tempGuid;
65
+ if (typeof direct === "string" && direct)
66
+ return direct;
67
+ return undefined;
68
+ }
69
+ /** Dig a chat GUID out of a chat/new (or chat/query) response. */
70
+ function extractChatGuid(data) {
71
+ if (!data || typeof data !== "object")
72
+ return undefined;
73
+ const rec = data;
74
+ const direct = rec.chatGuid ?? rec.guid;
75
+ if (typeof direct === "string" && direct)
76
+ return direct;
77
+ const chats = rec.chats;
78
+ if (Array.isArray(chats) && chats[0] && typeof chats[0] === "object") {
79
+ const g = chats[0].guid;
80
+ if (typeof g === "string" && g)
81
+ return g;
82
+ }
83
+ return undefined;
84
+ }
85
+ /**
86
+ * Create a new chat to a fresh handle (DM). Returns the new chat GUID. Requires
87
+ * the Private API for groups; a 1:1 chat may work without it on some servers.
88
+ */
89
+ export async function createBlueBubblesChat(base, params) {
90
+ const url = buildBlueBubblesApiUrl({ serverUrl: base.serverUrl, path: "chat/new", password: base.password });
91
+ const res = await blueBubblesFetchWithTimeout(url, {
92
+ method: "POST",
93
+ headers: { "Content-Type": "application/json" },
94
+ body: JSON.stringify({
95
+ addresses: [params.address],
96
+ message: params.message ?? "",
97
+ tempGuid: `temp-${randomUUID()}`,
98
+ }),
99
+ }, fetchOpts(base));
100
+ const data = await readBlueBubblesJson(res, "chat/new");
101
+ const guid = extractChatGuid(data);
102
+ if (!guid)
103
+ throw new Error("BlueBubbles chat/new returned no chat GUID");
104
+ return guid;
105
+ }
106
+ /** Pull a chat GUID off a query record. */
107
+ function recordChatGuid(chat) {
108
+ const g = chat.guid ?? chat.chatGuid;
109
+ return typeof g === "string" && g ? g : undefined;
110
+ }
111
+ /** Pull the numeric chat id off a query record. */
112
+ function recordChatId(chat) {
113
+ for (const c of [chat.chatId, chat.id, chat.chat_id]) {
114
+ if (typeof c === "number" && Number.isFinite(c))
115
+ return c;
116
+ }
117
+ return null;
118
+ }
119
+ /** The third `;`-delimited component of a chat GUID is the chat identifier. */
120
+ function identifierFromChatGuid(chatGuid) {
121
+ const parts = chatGuid.split(";");
122
+ if (parts.length < 3)
123
+ return null;
124
+ const id = (parts[2] ?? "").trim();
125
+ return id || null;
126
+ }
127
+ /** Page through `chat/query` and return one page of chat records. */
128
+ async function queryBlueBubblesChats(base, params) {
129
+ const url = buildBlueBubblesApiUrl({ serverUrl: base.serverUrl, path: "chat/query", password: base.password });
130
+ const res = await blueBubblesFetchWithTimeout(url, {
131
+ method: "POST",
132
+ headers: { "Content-Type": "application/json" },
133
+ body: JSON.stringify({ limit: params.limit, offset: params.offset, with: ["participants"] }),
134
+ }, fetchOpts(base));
135
+ if (!res.ok)
136
+ return [];
137
+ const data = await readBlueBubblesJson(res, "chat/query").catch(() => null);
138
+ return Array.isArray(data) ? data : [];
139
+ }
140
+ /**
141
+ * Resolve an outbound conversation target to a real chatGuid.
142
+ *
143
+ * - `chat_guid:` — passes straight through (the HOT inbound→reply path; the
144
+ * webhook always delivers the chatGuid).
145
+ * - `chat_id:` / `chat_identifier:` — looked up against the server via
146
+ * `chat/query` (paged), matching the numeric id or the GUID's identifier
147
+ * component. Passing these raw produced a silent 400 on a cold send.
148
+ * - `handle` — looked up by participant in existing DM chats; if none exists a
149
+ * fresh `chat/new` is created.
150
+ *
151
+ * Returns the resolved chatGuid. Throws when a `chat_id`/`chat_identifier`
152
+ * target can't be resolved (the server has no such chat) rather than handing the
153
+ * server a bad key.
154
+ */
155
+ export async function resolveChatGuid(base, target) {
156
+ const parsed = parseIMessageTarget(target);
157
+ // Hot path — a chat GUID is already a server key.
158
+ if (parsed.kind === "chat_guid")
159
+ return parsed.chatGuid;
160
+ const wantChatId = parsed.kind === "chat_id" ? parsed.chatId : null;
161
+ const wantIdentifier = parsed.kind === "chat_identifier" ? parsed.chatIdentifier : null;
162
+ const wantHandle = parsed.kind === "handle" ? parsed.to.trim() : "";
163
+ const limit = 500;
164
+ let participantMatch = null;
165
+ for (let offset = 0; offset < 5000; offset += limit) {
166
+ const chats = await queryBlueBubblesChats(base, { offset, limit });
167
+ if (chats.length === 0)
168
+ break;
169
+ for (const chat of chats) {
170
+ const guid = recordChatGuid(chat);
171
+ if (wantChatId != null && recordChatId(chat) === wantChatId && guid)
172
+ return guid;
173
+ if (wantIdentifier) {
174
+ if (guid && guid === wantIdentifier)
175
+ return guid;
176
+ if (guid && identifierFromChatGuid(guid) === wantIdentifier)
177
+ return guid;
178
+ const id = (typeof chat.identifier === "string" && chat.identifier) ||
179
+ (typeof chat.chatIdentifier === "string" && chat.chatIdentifier) ||
180
+ (typeof chat.chat_identifier === "string" && chat.chat_identifier) ||
181
+ "";
182
+ if (id && id === wantIdentifier && guid)
183
+ return guid;
184
+ }
185
+ if (wantHandle && !participantMatch && guid && guid.includes(";-;")) {
186
+ // Only DM chats (`;-;`) match a bare handle — never route a handle to a group.
187
+ if (identifierFromChatGuid(guid) === wantHandle)
188
+ participantMatch = guid;
189
+ }
190
+ }
191
+ }
192
+ if (wantHandle) {
193
+ if (participantMatch)
194
+ return participantMatch;
195
+ // No existing chat for this handle — create a fresh DM.
196
+ return createBlueBubblesChat(base, { address: wantHandle });
197
+ }
198
+ throw new Error(`BlueBubbles could not resolve a chat for target "${target}" (no matching chat on the server)`);
199
+ }
200
+ /**
201
+ * Send ONE text bubble to a chatGuid. Use `bubbleSplit` + a loop for
202
+ * multi-bubble replies (the connection layer does this). Returns the message
203
+ * GUID when the server reports one.
204
+ */
205
+ export async function sendBlueBubblesText(chatGuid, message, opts) {
206
+ const payload = {
207
+ chatGuid,
208
+ tempGuid: randomUUID(),
209
+ message,
210
+ };
211
+ if (opts.privateApiEnabled) {
212
+ payload.method = "private-api";
213
+ if (opts.replyToMessageGuid) {
214
+ payload.selectedMessageGuid = opts.replyToMessageGuid;
215
+ payload.partIndex = opts.replyToPartIndex ?? 0;
216
+ }
217
+ const effectId = opts.effect ? resolveEffectId(opts.effect) : undefined;
218
+ if (effectId)
219
+ payload.effectId = effectId;
220
+ }
221
+ const url = buildBlueBubblesApiUrl({ serverUrl: opts.serverUrl, path: "message/text", password: opts.password });
222
+ const res = await blueBubblesFetchWithTimeout(url, { method: "POST", headers: { "Content-Type": "application/json" }, body: JSON.stringify(payload) }, fetchOpts(opts));
223
+ const data = await readBlueBubblesJson(res, "message/text");
224
+ const guid = extractMessageGuid(data);
225
+ return guid ? { messageId: guid } : {};
226
+ }
227
+ /** Sanitise a filename for a multipart header (CWE-93 / header injection guard). */
228
+ function sanitizeFilename(name) {
229
+ const base = path.basename(name || "attachment").replace(/[\r\n"\\]/g, "_").trim();
230
+ return base || "attachment";
231
+ }
232
+ /**
233
+ * Send a media attachment via multipart. iMessage has NO native caption, so the
234
+ * caller sends any caption as a SEPARATE text bubble AFTER this (handled by the
235
+ * connection layer). Returns the message GUID when reported.
236
+ */
237
+ export async function sendBlueBubblesAttachment(chatGuid, opts) {
238
+ const bytes = opts.bytes ?? new Uint8Array(await readFile(opts.filePath));
239
+ const filename = sanitizeFilename(opts.fileName ?? opts.filePath);
240
+ const form = new FormData();
241
+ // Copy into a fresh ArrayBuffer so the Blob ctor accepts it across lib targets.
242
+ const ab = bytes.buffer.slice(bytes.byteOffset, bytes.byteOffset + bytes.byteLength);
243
+ const blob = new Blob([ab], opts.contentType ? { type: opts.contentType } : {});
244
+ form.append("attachment", blob, filename);
245
+ form.append("chatGuid", chatGuid);
246
+ form.append("name", filename);
247
+ form.append("tempGuid", `temp-${Date.now()}-${randomUUID().slice(0, 8)}`);
248
+ if (opts.privateApiEnabled)
249
+ form.append("method", "private-api");
250
+ if (opts.asVoice)
251
+ form.append("isAudioMessage", "true");
252
+ if (opts.privateApiEnabled && opts.replyToMessageGuid) {
253
+ form.append("selectedMessageGuid", opts.replyToMessageGuid);
254
+ form.append("partIndex", String(opts.replyToPartIndex ?? 0));
255
+ }
256
+ const url = buildBlueBubblesApiUrl({ serverUrl: opts.serverUrl, path: "message/attachment", password: opts.password });
257
+ const res = await blueBubblesFetchWithTimeout(url, { method: "POST", body: form },
258
+ // Attachments can be large — give a generous default upload timeout.
259
+ { ...fetchOpts(opts), timeoutMs: opts.timeoutMs ?? 60_000 });
260
+ const data = await readBlueBubblesJson(res, "message/attachment");
261
+ const guid = extractMessageGuid(data);
262
+ return guid ? { messageId: guid } : {};
263
+ }
264
+ /**
265
+ * Add or remove a tapback reaction on a message (Private API). `reaction` is any
266
+ * input `normalizeBlueBubblesReaction` accepts (`"love"`, `"👍"`, `"-love"` to
267
+ * remove). Throws when the Private API isn't available or the reaction is unknown.
268
+ */
269
+ export async function reactBlueBubbles(base, params) {
270
+ if (base.privateApiEnabled === false) {
271
+ throw new Error("BlueBubbles reactions require the Private API to be enabled on the server");
272
+ }
273
+ const reaction = normalizeBlueBubblesReaction(params.reaction);
274
+ if (!reaction)
275
+ throw new Error(`Unknown iMessage reaction: ${params.reaction}`);
276
+ const url = buildBlueBubblesApiUrl({ serverUrl: base.serverUrl, path: "message/react", password: base.password });
277
+ const res = await blueBubblesFetchWithTimeout(url, {
278
+ method: "POST",
279
+ headers: { "Content-Type": "application/json" },
280
+ body: JSON.stringify({
281
+ chatGuid: params.chatGuid,
282
+ selectedMessageGuid: params.messageGuid,
283
+ reaction,
284
+ partIndex: params.partIndex ?? 0,
285
+ }),
286
+ }, fetchOpts(base));
287
+ await readBlueBubblesJson(res, "message/react");
288
+ }
289
+ /** Edit a previously-sent message (Private API, macOS 13+ / iMessage edit window). */
290
+ export async function editBlueBubblesMessage(base, params) {
291
+ if (base.privateApiEnabled === false) {
292
+ throw new Error("BlueBubbles message edit requires the Private API to be enabled on the server");
293
+ }
294
+ const url = buildBlueBubblesApiUrl({
295
+ serverUrl: base.serverUrl,
296
+ path: `message/${encodeURIComponent(params.messageGuid)}/edit`,
297
+ password: base.password,
298
+ });
299
+ const res = await blueBubblesFetchWithTimeout(url, {
300
+ method: "POST",
301
+ headers: { "Content-Type": "application/json" },
302
+ body: JSON.stringify({
303
+ editedMessage: params.editedMessage,
304
+ backwardsCompatibilityMessage: params.backwardsCompatMessage ?? `Edited to: ${params.editedMessage}`,
305
+ partIndex: params.partIndex ?? 0,
306
+ }),
307
+ }, fetchOpts(base));
308
+ await readBlueBubblesJson(res, "message/edit");
309
+ }
310
+ /** Unsend (retract) a previously-sent message (Private API, iMessage unsend window). */
311
+ export async function unsendBlueBubblesMessage(base, params) {
312
+ if (base.privateApiEnabled === false) {
313
+ throw new Error("BlueBubbles message unsend requires the Private API to be enabled on the server");
314
+ }
315
+ const url = buildBlueBubblesApiUrl({
316
+ serverUrl: base.serverUrl,
317
+ path: `message/${encodeURIComponent(params.messageGuid)}/unsend`,
318
+ password: base.password,
319
+ });
320
+ const res = await blueBubblesFetchWithTimeout(url, {
321
+ method: "POST",
322
+ headers: { "Content-Type": "application/json" },
323
+ body: JSON.stringify({ partIndex: params.partIndex ?? 0 }),
324
+ }, fetchOpts(base));
325
+ await readBlueBubblesJson(res, "message/unsend");
326
+ }
327
+ //# sourceMappingURL=send.js.map