@openclaw/nextcloud-talk 2026.9.5 → 2026.9.7

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 (367) hide show
  1. package/assets/icon.png +0 -0
  2. package/dist/.setup/api-hlcmleZc.mjs +3 -0
  3. package/dist/.setup/{channel-COfyxLDp.mjs → channel-CeJpOTiY.mjs} +486 -354
  4. package/dist/.setup/doctor-contract-BVJcDIeU.mjs +213 -0
  5. package/dist/api.js +1 -1
  6. package/dist/channel-plugin-api.js +1 -1
  7. package/dist/doctor-contract-api.js +1 -1
  8. package/dist/setup-entry.js +1 -1
  9. package/node_modules/zod/README.md +2 -2
  10. package/node_modules/zod/compile.cjs +19 -0
  11. package/node_modules/zod/index.cjs +19 -0
  12. package/node_modules/zod/locales/index.cjs +19 -0
  13. package/node_modules/zod/mini/index.cjs +19 -0
  14. package/node_modules/zod/package.json +8 -7
  15. package/node_modules/zod/src/v3/helpers/errorUtil.ts +1 -1
  16. package/node_modules/zod/src/v4/classic/external.ts +2 -0
  17. package/node_modules/zod/src/v4/classic/from-json-schema.ts +248 -25
  18. package/node_modules/zod/src/v4/classic/schemas.ts +243 -168
  19. package/node_modules/zod/src/v4/classic/tests/assignability.test.ts +60 -9
  20. package/node_modules/zod/src/v4/classic/tests/bigint.test.ts +6 -0
  21. package/node_modules/zod/src/v4/classic/tests/continuability.test.ts +2 -2
  22. package/node_modules/zod/src/v4/classic/tests/cyclic-data.test.ts +265 -0
  23. package/node_modules/zod/src/v4/classic/tests/discriminated-unions.test.ts +112 -6
  24. package/node_modules/zod/src/v4/classic/tests/enum.test.ts +9 -0
  25. package/node_modules/zod/src/v4/classic/tests/error.test.ts +130 -1
  26. package/node_modules/zod/src/v4/classic/tests/from-json-schema.test.ts +157 -0
  27. package/node_modules/zod/src/v4/classic/tests/iban.test.ts +81 -0
  28. package/node_modules/zod/src/v4/classic/tests/instance-footprint.test.ts +40 -2
  29. package/node_modules/zod/src/v4/classic/tests/instanceof.test.ts +27 -7
  30. package/node_modules/zod/src/v4/classic/tests/issue-schema.test.ts +88 -56
  31. package/node_modules/zod/src/v4/classic/tests/number.test.ts +39 -0
  32. package/node_modules/zod/src/v4/classic/tests/object.test.ts +56 -0
  33. package/node_modules/zod/src/v4/classic/tests/optin-ladder.test.ts +3 -2
  34. package/node_modules/zod/src/v4/classic/tests/prefault.test.ts +70 -0
  35. package/node_modules/zod/src/v4/classic/tests/properties.test.ts +141 -0
  36. package/node_modules/zod/src/v4/classic/tests/recursive-types.test.ts +46 -1
  37. package/node_modules/zod/src/v4/classic/tests/standard-schema.test.ts +19 -0
  38. package/node_modules/zod/src/v4/classic/tests/string.test.ts +95 -1
  39. package/node_modules/zod/src/v4/classic/tests/template-literal.test.ts +33 -1
  40. package/node_modules/zod/src/v4/classic/tests/to-json-schema.test.ts +234 -38
  41. package/node_modules/zod/src/v4/classic/tests/validate.test.ts +569 -0
  42. package/node_modules/zod/src/v4/core/api.ts +44 -28
  43. package/node_modules/zod/src/v4/core/checks.ts +62 -102
  44. package/node_modules/zod/src/v4/core/compile.ts +218 -93
  45. package/node_modules/zod/src/v4/core/core.ts +1 -3
  46. package/node_modules/zod/src/v4/core/doc.ts +6 -2
  47. package/node_modules/zod/src/v4/core/errors.ts +3 -6
  48. package/node_modules/zod/src/v4/core/json-schema-generator.ts +2 -2
  49. package/node_modules/zod/src/v4/core/json-schema-processors.ts +185 -81
  50. package/node_modules/zod/src/v4/core/memoizer.ts +75 -28
  51. package/node_modules/zod/src/v4/core/parse.ts +37 -16
  52. package/node_modules/zod/src/v4/core/regexes.ts +14 -4
  53. package/node_modules/zod/src/v4/core/schemas.ts +296 -132
  54. package/node_modules/zod/src/v4/core/tests/cached.test.ts +54 -0
  55. package/node_modules/zod/src/v4/core/tests/compile-differential.test.ts +35 -0
  56. package/node_modules/zod/src/v4/core/tests/compile-generative.test.ts +445 -0
  57. package/node_modules/zod/src/v4/core/tests/compile.test.ts +399 -2
  58. package/node_modules/zod/src/v4/core/tests/email-regex.test.ts +140 -0
  59. package/node_modules/zod/src/v4/core/tests/locales/tg.test.ts +85 -0
  60. package/node_modules/zod/src/v4/core/tests/polyfill-collision.test.ts +46 -0
  61. package/node_modules/zod/src/v4/core/tests/url-no-canparse.test.ts +118 -16
  62. package/node_modules/zod/src/v4/core/to-json-schema.ts +9 -7
  63. package/node_modules/zod/src/v4/core/util.ts +218 -147
  64. package/node_modules/zod/src/v4/core/versions.ts +2 -2
  65. package/node_modules/zod/src/v4/locales/ar.ts +2 -0
  66. package/node_modules/zod/src/v4/locales/az.ts +2 -0
  67. package/node_modules/zod/src/v4/locales/be.ts +2 -0
  68. package/node_modules/zod/src/v4/locales/bg.ts +2 -0
  69. package/node_modules/zod/src/v4/locales/bn.ts +2 -0
  70. package/node_modules/zod/src/v4/locales/ca.ts +2 -0
  71. package/node_modules/zod/src/v4/locales/ckb.ts +2 -0
  72. package/node_modules/zod/src/v4/locales/cs.ts +2 -0
  73. package/node_modules/zod/src/v4/locales/da.ts +2 -0
  74. package/node_modules/zod/src/v4/locales/de.ts +2 -0
  75. package/node_modules/zod/src/v4/locales/el.ts +2 -0
  76. package/node_modules/zod/src/v4/locales/en.ts +2 -0
  77. package/node_modules/zod/src/v4/locales/eo.ts +2 -0
  78. package/node_modules/zod/src/v4/locales/es.ts +2 -0
  79. package/node_modules/zod/src/v4/locales/fa.ts +2 -0
  80. package/node_modules/zod/src/v4/locales/fi.ts +2 -0
  81. package/node_modules/zod/src/v4/locales/fr-CA.ts +2 -0
  82. package/node_modules/zod/src/v4/locales/fr.ts +2 -0
  83. package/node_modules/zod/src/v4/locales/gu.ts +2 -0
  84. package/node_modules/zod/src/v4/locales/he.ts +2 -0
  85. package/node_modules/zod/src/v4/locales/hi.ts +2 -0
  86. package/node_modules/zod/src/v4/locales/hr.ts +2 -0
  87. package/node_modules/zod/src/v4/locales/hu.ts +2 -0
  88. package/node_modules/zod/src/v4/locales/hy.ts +2 -0
  89. package/node_modules/zod/src/v4/locales/id.ts +2 -0
  90. package/node_modules/zod/src/v4/locales/index.ts +1 -0
  91. package/node_modules/zod/src/v4/locales/is.ts +2 -0
  92. package/node_modules/zod/src/v4/locales/it.ts +2 -0
  93. package/node_modules/zod/src/v4/locales/ja.ts +2 -0
  94. package/node_modules/zod/src/v4/locales/ka.ts +2 -0
  95. package/node_modules/zod/src/v4/locales/km.ts +2 -0
  96. package/node_modules/zod/src/v4/locales/kn.ts +2 -0
  97. package/node_modules/zod/src/v4/locales/ko.ts +2 -0
  98. package/node_modules/zod/src/v4/locales/lt.ts +2 -0
  99. package/node_modules/zod/src/v4/locales/mk.ts +2 -0
  100. package/node_modules/zod/src/v4/locales/ms.ts +2 -0
  101. package/node_modules/zod/src/v4/locales/ne.ts +2 -0
  102. package/node_modules/zod/src/v4/locales/nl.ts +2 -0
  103. package/node_modules/zod/src/v4/locales/nn.ts +2 -0
  104. package/node_modules/zod/src/v4/locales/no.ts +2 -0
  105. package/node_modules/zod/src/v4/locales/ota.ts +2 -0
  106. package/node_modules/zod/src/v4/locales/pl.ts +2 -0
  107. package/node_modules/zod/src/v4/locales/ps.ts +2 -0
  108. package/node_modules/zod/src/v4/locales/pt-BR.ts +2 -0
  109. package/node_modules/zod/src/v4/locales/pt.ts +2 -0
  110. package/node_modules/zod/src/v4/locales/ro.ts +2 -0
  111. package/node_modules/zod/src/v4/locales/ru.ts +2 -0
  112. package/node_modules/zod/src/v4/locales/sk.ts +2 -0
  113. package/node_modules/zod/src/v4/locales/sl.ts +2 -0
  114. package/node_modules/zod/src/v4/locales/sv.ts +2 -0
  115. package/node_modules/zod/src/v4/locales/ta.ts +2 -0
  116. package/node_modules/zod/src/v4/locales/tg.ts +135 -0
  117. package/node_modules/zod/src/v4/locales/th.ts +2 -0
  118. package/node_modules/zod/src/v4/locales/tk.ts +2 -0
  119. package/node_modules/zod/src/v4/locales/tr.ts +2 -0
  120. package/node_modules/zod/src/v4/locales/uk.ts +2 -0
  121. package/node_modules/zod/src/v4/locales/ur.ts +2 -0
  122. package/node_modules/zod/src/v4/locales/uz.ts +2 -0
  123. package/node_modules/zod/src/v4/locales/vi.ts +2 -0
  124. package/node_modules/zod/src/v4/locales/yo.ts +2 -0
  125. package/node_modules/zod/src/v4/locales/zh-CN.ts +2 -0
  126. package/node_modules/zod/src/v4/locales/zh-TW.ts +2 -0
  127. package/node_modules/zod/src/v4/mini/external.ts +2 -0
  128. package/node_modules/zod/src/v4/mini/schemas.ts +32 -7
  129. package/node_modules/zod/src/v4/mini/tests/checks.test.ts +1 -1
  130. package/node_modules/zod/src/v4/mini/tests/computed.test.ts +11 -17
  131. package/node_modules/zod/src/v4/mini/tests/index.test.ts +86 -0
  132. package/node_modules/zod/src/v4/mini/tests/recursive-types.test.ts +16 -0
  133. package/node_modules/zod/src/v4/mini/tests/string.test.ts +23 -0
  134. package/node_modules/zod/v3/ZodError.cjs +19 -0
  135. package/node_modules/zod/v3/errors.cjs +19 -0
  136. package/node_modules/zod/v3/external.cjs +19 -0
  137. package/node_modules/zod/v3/helpers/enumUtil.cjs +19 -0
  138. package/node_modules/zod/v3/helpers/errorUtil.cjs +20 -1
  139. package/node_modules/zod/v3/helpers/errorUtil.js +1 -1
  140. package/node_modules/zod/v3/helpers/parseUtil.cjs +19 -0
  141. package/node_modules/zod/v3/helpers/partialUtil.cjs +19 -0
  142. package/node_modules/zod/v3/helpers/typeAliases.cjs +19 -0
  143. package/node_modules/zod/v3/helpers/util.cjs +19 -0
  144. package/node_modules/zod/v3/index.cjs +19 -0
  145. package/node_modules/zod/v3/standard-schema.cjs +19 -0
  146. package/node_modules/zod/v3/types.cjs +19 -0
  147. package/node_modules/zod/v4/classic/checks.cjs +19 -0
  148. package/node_modules/zod/v4/classic/coerce.cjs +19 -0
  149. package/node_modules/zod/v4/classic/compat.cjs +19 -0
  150. package/node_modules/zod/v4/classic/deep-partial.cjs +19 -0
  151. package/node_modules/zod/v4/classic/errors.cjs +19 -0
  152. package/node_modules/zod/v4/classic/external.cjs +22 -1
  153. package/node_modules/zod/v4/classic/external.d.cts +1 -1
  154. package/node_modules/zod/v4/classic/external.d.ts +1 -1
  155. package/node_modules/zod/v4/classic/external.js +1 -1
  156. package/node_modules/zod/v4/classic/from-json-schema.cjs +264 -24
  157. package/node_modules/zod/v4/classic/from-json-schema.js +245 -24
  158. package/node_modules/zod/v4/classic/in-out.cjs +19 -0
  159. package/node_modules/zod/v4/classic/index.cjs +19 -0
  160. package/node_modules/zod/v4/classic/iso.cjs +19 -0
  161. package/node_modules/zod/v4/classic/parse.cjs +19 -0
  162. package/node_modules/zod/v4/classic/schemas.cjs +100 -35
  163. package/node_modules/zod/v4/classic/schemas.d.cts +15 -1
  164. package/node_modules/zod/v4/classic/schemas.d.ts +15 -1
  165. package/node_modules/zod/v4/classic/schemas.js +77 -33
  166. package/node_modules/zod/v4/core/api.cjs +45 -22
  167. package/node_modules/zod/v4/core/api.d.cts +12 -6
  168. package/node_modules/zod/v4/core/api.d.ts +12 -6
  169. package/node_modules/zod/v4/core/api.js +25 -22
  170. package/node_modules/zod/v4/core/checks.cjs +51 -97
  171. package/node_modules/zod/v4/core/checks.d.cts +17 -1
  172. package/node_modules/zod/v4/core/checks.d.ts +17 -1
  173. package/node_modules/zod/v4/core/checks.js +31 -96
  174. package/node_modules/zod/v4/core/compile.cjs +173 -78
  175. package/node_modules/zod/v4/core/compile.d.cts +18 -4
  176. package/node_modules/zod/v4/core/compile.d.ts +18 -4
  177. package/node_modules/zod/v4/core/compile.js +154 -79
  178. package/node_modules/zod/v4/core/core.cjs +20 -1
  179. package/node_modules/zod/v4/core/core.js +1 -1
  180. package/node_modules/zod/v4/core/doc.cjs +26 -2
  181. package/node_modules/zod/v4/core/doc.js +7 -2
  182. package/node_modules/zod/v4/core/errors.cjs +21 -5
  183. package/node_modules/zod/v4/core/errors.js +2 -5
  184. package/node_modules/zod/v4/core/index.cjs +19 -0
  185. package/node_modules/zod/v4/core/json-schema-generator.cjs +20 -1
  186. package/node_modules/zod/v4/core/json-schema-generator.js +2 -2
  187. package/node_modules/zod/v4/core/json-schema-processors.cjs +188 -72
  188. package/node_modules/zod/v4/core/json-schema-processors.d.cts +16 -0
  189. package/node_modules/zod/v4/core/json-schema-processors.d.ts +16 -0
  190. package/node_modules/zod/v4/core/json-schema-processors.js +170 -74
  191. package/node_modules/zod/v4/core/json-schema.cjs +19 -0
  192. package/node_modules/zod/v4/core/memoizer.cjs +111 -23
  193. package/node_modules/zod/v4/core/memoizer.js +69 -23
  194. package/node_modules/zod/v4/core/parse.cjs +56 -16
  195. package/node_modules/zod/v4/core/parse.js +37 -16
  196. package/node_modules/zod/v4/core/regexes.cjs +31 -6
  197. package/node_modules/zod/v4/core/regexes.d.cts +3 -0
  198. package/node_modules/zod/v4/core/regexes.d.ts +3 -0
  199. package/node_modules/zod/v4/core/regexes.js +10 -4
  200. package/node_modules/zod/v4/core/registries.cjs +19 -0
  201. package/node_modules/zod/v4/core/schemas.cjs +302 -114
  202. package/node_modules/zod/v4/core/schemas.d.cts +28 -8
  203. package/node_modules/zod/v4/core/schemas.d.ts +28 -8
  204. package/node_modules/zod/v4/core/schemas.js +279 -113
  205. package/node_modules/zod/v4/core/standard-schema.cjs +19 -0
  206. package/node_modules/zod/v4/core/to-json-schema.cjs +28 -7
  207. package/node_modules/zod/v4/core/to-json-schema.d.cts +4 -3
  208. package/node_modules/zod/v4/core/to-json-schema.d.ts +4 -3
  209. package/node_modules/zod/v4/core/to-json-schema.js +7 -6
  210. package/node_modules/zod/v4/core/util.cjs +177 -143
  211. package/node_modules/zod/v4/core/util.d.cts +25 -4
  212. package/node_modules/zod/v4/core/util.d.ts +25 -4
  213. package/node_modules/zod/v4/core/util.js +156 -143
  214. package/node_modules/zod/v4/core/versions.cjs +21 -2
  215. package/node_modules/zod/v4/core/versions.d.cts +1 -1
  216. package/node_modules/zod/v4/core/versions.d.ts +1 -1
  217. package/node_modules/zod/v4/core/versions.js +2 -2
  218. package/node_modules/zod/v4/core/visit.cjs +19 -0
  219. package/node_modules/zod/v4/index.cjs +19 -0
  220. package/node_modules/zod/v4/locales/ar.cjs +2 -0
  221. package/node_modules/zod/v4/locales/ar.js +2 -0
  222. package/node_modules/zod/v4/locales/az.cjs +2 -0
  223. package/node_modules/zod/v4/locales/az.js +2 -0
  224. package/node_modules/zod/v4/locales/be.cjs +2 -0
  225. package/node_modules/zod/v4/locales/be.js +2 -0
  226. package/node_modules/zod/v4/locales/bg.cjs +2 -0
  227. package/node_modules/zod/v4/locales/bg.js +2 -0
  228. package/node_modules/zod/v4/locales/bn.cjs +2 -0
  229. package/node_modules/zod/v4/locales/bn.js +2 -0
  230. package/node_modules/zod/v4/locales/ca.cjs +2 -0
  231. package/node_modules/zod/v4/locales/ca.js +2 -0
  232. package/node_modules/zod/v4/locales/ckb.cjs +2 -0
  233. package/node_modules/zod/v4/locales/ckb.js +2 -0
  234. package/node_modules/zod/v4/locales/cs.cjs +2 -0
  235. package/node_modules/zod/v4/locales/cs.js +2 -0
  236. package/node_modules/zod/v4/locales/da.cjs +2 -0
  237. package/node_modules/zod/v4/locales/da.js +2 -0
  238. package/node_modules/zod/v4/locales/de.cjs +2 -0
  239. package/node_modules/zod/v4/locales/de.js +2 -0
  240. package/node_modules/zod/v4/locales/el.cjs +2 -0
  241. package/node_modules/zod/v4/locales/el.js +2 -0
  242. package/node_modules/zod/v4/locales/en.cjs +2 -0
  243. package/node_modules/zod/v4/locales/en.js +2 -0
  244. package/node_modules/zod/v4/locales/eo.cjs +2 -0
  245. package/node_modules/zod/v4/locales/eo.js +2 -0
  246. package/node_modules/zod/v4/locales/es.cjs +2 -0
  247. package/node_modules/zod/v4/locales/es.js +2 -0
  248. package/node_modules/zod/v4/locales/fa.cjs +2 -0
  249. package/node_modules/zod/v4/locales/fa.js +2 -0
  250. package/node_modules/zod/v4/locales/fi.cjs +2 -0
  251. package/node_modules/zod/v4/locales/fi.js +2 -0
  252. package/node_modules/zod/v4/locales/fr-CA.cjs +2 -0
  253. package/node_modules/zod/v4/locales/fr-CA.js +2 -0
  254. package/node_modules/zod/v4/locales/fr.cjs +2 -0
  255. package/node_modules/zod/v4/locales/fr.js +2 -0
  256. package/node_modules/zod/v4/locales/gu.cjs +2 -0
  257. package/node_modules/zod/v4/locales/gu.js +2 -0
  258. package/node_modules/zod/v4/locales/he.cjs +2 -0
  259. package/node_modules/zod/v4/locales/he.js +2 -0
  260. package/node_modules/zod/v4/locales/hi.cjs +2 -0
  261. package/node_modules/zod/v4/locales/hi.js +2 -0
  262. package/node_modules/zod/v4/locales/hr.cjs +2 -0
  263. package/node_modules/zod/v4/locales/hr.js +2 -0
  264. package/node_modules/zod/v4/locales/hu.cjs +2 -0
  265. package/node_modules/zod/v4/locales/hu.js +2 -0
  266. package/node_modules/zod/v4/locales/hy.cjs +2 -0
  267. package/node_modules/zod/v4/locales/hy.js +2 -0
  268. package/node_modules/zod/v4/locales/id.cjs +2 -0
  269. package/node_modules/zod/v4/locales/id.js +2 -0
  270. package/node_modules/zod/v4/locales/index.cjs +22 -1
  271. package/node_modules/zod/v4/locales/index.d.cts +1 -0
  272. package/node_modules/zod/v4/locales/index.d.ts +1 -0
  273. package/node_modules/zod/v4/locales/index.js +1 -0
  274. package/node_modules/zod/v4/locales/is.cjs +2 -0
  275. package/node_modules/zod/v4/locales/is.js +2 -0
  276. package/node_modules/zod/v4/locales/it.cjs +2 -0
  277. package/node_modules/zod/v4/locales/it.js +2 -0
  278. package/node_modules/zod/v4/locales/ja.cjs +2 -0
  279. package/node_modules/zod/v4/locales/ja.js +2 -0
  280. package/node_modules/zod/v4/locales/ka.cjs +2 -0
  281. package/node_modules/zod/v4/locales/ka.js +2 -0
  282. package/node_modules/zod/v4/locales/km.cjs +2 -0
  283. package/node_modules/zod/v4/locales/km.js +2 -0
  284. package/node_modules/zod/v4/locales/kn.cjs +2 -0
  285. package/node_modules/zod/v4/locales/kn.js +2 -0
  286. package/node_modules/zod/v4/locales/ko.cjs +2 -0
  287. package/node_modules/zod/v4/locales/ko.js +2 -0
  288. package/node_modules/zod/v4/locales/lt.cjs +2 -0
  289. package/node_modules/zod/v4/locales/lt.js +2 -0
  290. package/node_modules/zod/v4/locales/mk.cjs +2 -0
  291. package/node_modules/zod/v4/locales/mk.js +2 -0
  292. package/node_modules/zod/v4/locales/ms.cjs +2 -0
  293. package/node_modules/zod/v4/locales/ms.js +2 -0
  294. package/node_modules/zod/v4/locales/ne.cjs +2 -0
  295. package/node_modules/zod/v4/locales/ne.js +2 -0
  296. package/node_modules/zod/v4/locales/nl.cjs +2 -0
  297. package/node_modules/zod/v4/locales/nl.js +2 -0
  298. package/node_modules/zod/v4/locales/nn.cjs +2 -0
  299. package/node_modules/zod/v4/locales/nn.js +2 -0
  300. package/node_modules/zod/v4/locales/no.cjs +2 -0
  301. package/node_modules/zod/v4/locales/no.js +2 -0
  302. package/node_modules/zod/v4/locales/ota.cjs +2 -0
  303. package/node_modules/zod/v4/locales/ota.js +2 -0
  304. package/node_modules/zod/v4/locales/pl.cjs +2 -0
  305. package/node_modules/zod/v4/locales/pl.js +2 -0
  306. package/node_modules/zod/v4/locales/ps.cjs +2 -0
  307. package/node_modules/zod/v4/locales/ps.js +2 -0
  308. package/node_modules/zod/v4/locales/pt-BR.cjs +2 -0
  309. package/node_modules/zod/v4/locales/pt-BR.js +2 -0
  310. package/node_modules/zod/v4/locales/pt.cjs +2 -0
  311. package/node_modules/zod/v4/locales/pt.js +2 -0
  312. package/node_modules/zod/v4/locales/ro.cjs +2 -0
  313. package/node_modules/zod/v4/locales/ro.js +2 -0
  314. package/node_modules/zod/v4/locales/ru.cjs +2 -0
  315. package/node_modules/zod/v4/locales/ru.js +2 -0
  316. package/node_modules/zod/v4/locales/sk.cjs +2 -0
  317. package/node_modules/zod/v4/locales/sk.js +2 -0
  318. package/node_modules/zod/v4/locales/sl.cjs +2 -0
  319. package/node_modules/zod/v4/locales/sl.js +2 -0
  320. package/node_modules/zod/v4/locales/sv.cjs +2 -0
  321. package/node_modules/zod/v4/locales/sv.js +2 -0
  322. package/node_modules/zod/v4/locales/ta.cjs +2 -0
  323. package/node_modules/zod/v4/locales/ta.js +2 -0
  324. package/node_modules/zod/v4/locales/tg.cjs +144 -0
  325. package/node_modules/zod/v4/locales/tg.d.cts +5 -0
  326. package/node_modules/zod/v4/locales/tg.d.ts +4 -0
  327. package/node_modules/zod/v4/locales/tg.js +117 -0
  328. package/node_modules/zod/v4/locales/th.cjs +2 -0
  329. package/node_modules/zod/v4/locales/th.js +2 -0
  330. package/node_modules/zod/v4/locales/tk.cjs +2 -0
  331. package/node_modules/zod/v4/locales/tk.js +2 -0
  332. package/node_modules/zod/v4/locales/tr.cjs +2 -0
  333. package/node_modules/zod/v4/locales/tr.js +2 -0
  334. package/node_modules/zod/v4/locales/uk.cjs +2 -0
  335. package/node_modules/zod/v4/locales/uk.js +2 -0
  336. package/node_modules/zod/v4/locales/ur.cjs +2 -0
  337. package/node_modules/zod/v4/locales/ur.js +2 -0
  338. package/node_modules/zod/v4/locales/uz.cjs +2 -0
  339. package/node_modules/zod/v4/locales/uz.js +2 -0
  340. package/node_modules/zod/v4/locales/vi.cjs +2 -0
  341. package/node_modules/zod/v4/locales/vi.js +2 -0
  342. package/node_modules/zod/v4/locales/yo.cjs +2 -0
  343. package/node_modules/zod/v4/locales/yo.js +2 -0
  344. package/node_modules/zod/v4/locales/zh-CN.cjs +2 -0
  345. package/node_modules/zod/v4/locales/zh-CN.js +2 -0
  346. package/node_modules/zod/v4/locales/zh-TW.cjs +2 -0
  347. package/node_modules/zod/v4/locales/zh-TW.js +2 -0
  348. package/node_modules/zod/v4/mini/checks.cjs +19 -0
  349. package/node_modules/zod/v4/mini/coerce.cjs +19 -0
  350. package/node_modules/zod/v4/mini/deep-partial.cjs +19 -0
  351. package/node_modules/zod/v4/mini/external.cjs +22 -1
  352. package/node_modules/zod/v4/mini/external.d.cts +1 -1
  353. package/node_modules/zod/v4/mini/external.d.ts +1 -1
  354. package/node_modules/zod/v4/mini/external.js +1 -1
  355. package/node_modules/zod/v4/mini/in-out.cjs +19 -0
  356. package/node_modules/zod/v4/mini/index.cjs +19 -0
  357. package/node_modules/zod/v4/mini/iso.cjs +19 -0
  358. package/node_modules/zod/v4/mini/parse.cjs +19 -0
  359. package/node_modules/zod/v4/mini/schemas.cjs +44 -8
  360. package/node_modules/zod/v4/mini/schemas.d.cts +6 -1
  361. package/node_modules/zod/v4/mini/schemas.d.ts +6 -1
  362. package/node_modules/zod/v4/mini/schemas.js +21 -6
  363. package/node_modules/zod/v4-mini/index.cjs +19 -0
  364. package/openclaw.plugin.json +48 -14
  365. package/package.json +5 -5
  366. package/dist/.setup/api-C8hJa49T.mjs +0 -3
  367. package/dist/.setup/doctor-contract-Bda_xc6V.mjs +0 -21
@@ -1,8 +1,8 @@
1
+ import { i as __reExport, n as normalizeCompatibilityConfig, r as __exportAll, t as legacyConfigRules } from "./doctor-contract-BVJcDIeU.mjs";
1
2
  import { a as fetchWithSsrFGuard, c as resolveDefaultGroupPolicy, i as deliverFormattedTextWithAttachments, l as warnMissingProviderGroupPolicyFallbackOnce, o as logInboundDrop, r as createChannelPairingController, s as resolveAllowlistProviderRuntimeGroupPolicy, t as GROUP_POLICY_BLOCKED_LABEL, u as getNextcloudTalkRuntime } from "./runtime-api-BKsxTw4J.mjs";
2
- import { n as normalizeCompatibilityConfig, t as legacyConfigRules } from "./doctor-contract-Bda_xc6V.mjs";
3
3
  import { n as collectRuntimeConfigAssignments, r as secretTargetRegistryEntries } from "./secret-contract-Bvm0PmP3.mjs";
4
4
  import { createAccountListHelpers, describeWebhookAccountSnapshot } from "openclaw/plugin-sdk/account-helpers";
5
- import { createChatChannelPlugin } from "openclaw/plugin-sdk/channel-core";
5
+ import { buildChannelOutboundSessionRoute, createChatChannelPlugin } from "openclaw/plugin-sdk/channel-core";
6
6
  import { createLoggedPairingApprovalNotifier, createPairingPrefixStripper } from "openclaw/plugin-sdk/channel-pairing";
7
7
  import { createAllowlistProviderRouteAllowlistWarningCollector, createConditionalWarningCollector, resolveScopeRequireMention, resolveScopeToolsPolicy } from "openclaw/plugin-sdk/channel-policy";
8
8
  import { buildWebhookChannelStatusSummary, createComputedAccountStatusAdapter, createDefaultChannelRuntimeState } from "openclaw/plugin-sdk/status-helpers";
@@ -19,6 +19,7 @@ import { readProviderJsonResponse, readProviderTextResponse } from "openclaw/plu
19
19
  import { resolveChannelInboundRouteEnvelope } from "openclaw/plugin-sdk/channel-inbound";
20
20
  import { bindIngressLifecycleToReplyOptions, createAccountStatusSink, createChannelIngressMonitor, createMessageReceiptFromOutboundResults, defineChannelMessageAdapter, resolveChannelStreamingBlockEnabled, runPassiveAccountLifecycle } from "openclaw/plugin-sdk/channel-outbound";
21
21
  import { SsrFBlockedError, ssrfPolicyFromPrivateNetworkOptIn, ssrfPolicyFromPrivateNetworkOptIn as ssrfPolicyFromPrivateNetworkOptIn$1 } from "openclaw/plugin-sdk/ssrf-runtime";
22
+ import { createPluginRuntimeStore } from "openclaw/plugin-sdk/runtime-store";
22
23
  import { redactToolPayloadText } from "openclaw/plugin-sdk/logging-core";
23
24
  import { requireRuntimeConfig } from "openclaw/plugin-sdk/plugin-config-runtime";
24
25
  import { resolveMarkdownTableMode } from "openclaw/plugin-sdk/markdown-table-runtime";
@@ -28,7 +29,7 @@ import { DEFAULT_ACCOUNT_ID as DEFAULT_ACCOUNT_ID$2 } from "openclaw/plugin-sdk/
28
29
  import { DmPolicySchema, GroupPolicySchema, MarkdownConfigSchema, ReplyRuntimeConfigSchemaShape, ReplyToModeSchema, buildChannelConfigSchema, buildGroupEntrySchema, buildMultiAccountChannelSchema, requireOpenAllowFrom } from "openclaw/plugin-sdk/channel-config-schema";
29
30
  import { formatAllowFromLowercase, resolveAllowlistMatchByCandidates } from "openclaw/plugin-sdk/allow-from";
30
31
  import { adaptScopedAccountAccessor, clearAccountFieldsFromConfigSection, createScopedChannelConfigAdapter, createScopedDmSecurityResolver } from "openclaw/plugin-sdk/channel-config-helpers";
31
- import { requireChannelOpenAllowFrom, resolveLoggerBackedRuntime } from "openclaw/plugin-sdk/extension-shared";
32
+ import { createDeferred, requireChannelOpenAllowFrom, resolveLoggerBackedRuntime } from "openclaw/plugin-sdk/extension-shared";
32
33
  import { z } from "zod";
33
34
  import os from "node:os";
34
35
  import path from "node:path";
@@ -36,20 +37,20 @@ import { fileExists } from "openclaw/plugin-sdk/file-access-runtime";
36
37
  import { migratePersistentDedupeLegacyJsonFile, resolvePersistentDedupePluginStateNamespace } from "openclaw/plugin-sdk/persistent-dedupe";
37
38
  import { resolveStateDir } from "openclaw/plugin-sdk/state-paths";
38
39
  import { channelReadyPatch } from "openclaw/plugin-sdk/gateway-runtime";
39
- import { channelIngressRoutes, resolveStableChannelMessageIngress } from "openclaw/plugin-sdk/channel-ingress-runtime";
40
+ import { channelIngressRoutes } from "openclaw/plugin-sdk/channel-ingress-runtime";
40
41
  import { safeParseJson, truncateUtf16Safe } from "openclaw/plugin-sdk/text-utility-runtime";
41
42
  import { buildChannelKeyCandidates, normalizeChannelSlug, resolveChannelEntryMatchWithFallback } from "openclaw/plugin-sdk/channel-targets";
42
43
  import { pruneMapToMaxSize } from "openclaw/plugin-sdk/collection-runtime";
43
- import { createServer } from "node:http";
44
- import { WEBHOOK_RATE_LIMIT_DEFAULTS, createAuthRateLimiter, createWebhookInFlightLimiter, isRequestBodyLimitError, readRequestBodyWithLimit, requestBodyErrorToText, resolveRequestClientIp } from "openclaw/plugin-sdk/webhook-ingress";
45
- import { runHttpConnectionRequest, sendHttpRequestRejection } from "openclaw/plugin-sdk/webhook-request-guards";
44
+ import { WEBHOOK_RATE_LIMIT_DEFAULTS, createAuthRateLimiter, createWebhookInFlightLimiter, getWebhookLegacyListener, isRequestBodyLimitError, readRequestBodyWithLimit, requestBodyErrorToText, resolveRequestClientIp } from "openclaw/plugin-sdk/webhook-ingress";
45
+ import { sendHttpRequestRejection } from "openclaw/plugin-sdk/webhook-request-guards";
46
+ import { canonicalizeWebhookRouteKey, registerPluginHttpRoute, registerWebhookTarget, resolveSingleWebhookTarget } from "openclaw/plugin-sdk/webhook-targets";
46
47
  import { isRecord as isRecord$1 } from "openclaw/plugin-sdk/channel-secret-basic-runtime";
47
48
  import { jsonResult, readStringParam, resolveReactionMessageId } from "openclaw/plugin-sdk/channel-actions";
48
- import { DEFAULT_ACCOUNT_ID as DEFAULT_ACCOUNT_ID$1, buildOutboundBaseSessionKey, normalizeAccountId as normalizeAccountId$1 } from "openclaw/plugin-sdk/routing";
49
49
  import { createChannelDmPolicy } from "openclaw/plugin-sdk/channel-dm-policy";
50
50
  import { defineChannelSetupContract } from "openclaw/plugin-sdk/channel-setup";
51
- import { applyAccountNameToChannelSection, baseUrlTextInput, createSetupTranslator, createStandardChannelSetupStatus, defineTokenCredential, formatDocsLink, patchScopedAccountConfig, setSetupChannelEnabled } from "openclaw/plugin-sdk/setup";
52
- import { createSetupInputPresenceValidator, createSetupTranslator as createSetupTranslator$1, mergeAllowFromEntries, promptParsedAllowFromForAccount, resolveSetupAccountId } from "openclaw/plugin-sdk/setup-runtime";
51
+ import { DEFAULT_ACCOUNT_ID as DEFAULT_ACCOUNT_ID$1, normalizeAccountId as normalizeAccountId$1 } from "openclaw/plugin-sdk/routing";
52
+ import { applyAccountNameToChannelSection, baseUrlTextInput, createPromptParsedAllowFromForAccount, createSetupTranslator, createStandardChannelSetupStatus, defineTokenCredential, formatDocsLink, patchScopedAccountConfig, setSetupChannelEnabled } from "openclaw/plugin-sdk/setup";
53
+ import { createSetupInputPresenceValidator, createSetupTranslator as createSetupTranslator$1, mergeAllowFromEntries } from "openclaw/plugin-sdk/setup-runtime";
53
54
  import { formatDocsLink as formatDocsLink$1 } from "openclaw/plugin-sdk/setup-tools";
54
55
  //#region extensions/nextcloud-talk/src/api-credentials.ts
55
56
  function resolveNextcloudTalkApiCredentialsResult(params) {
@@ -243,12 +244,9 @@ function verifyNextcloudTalkSignature(params) {
243
244
  const expected = createHmac("sha256", secret).update(random + body).digest("hex");
244
245
  return safeEqualSecret(signature, expected);
245
246
  }
246
- /**
247
- * Extract webhook headers from an incoming request.
248
- */
249
247
  function extractNextcloudTalkHeaders(headers) {
250
248
  const getHeader = (name) => {
251
- const value = headers[name] ?? headers[normalizeLowercaseStringOrEmpty(name)];
249
+ const value = headers[name];
252
250
  return Array.isArray(value) ? value[0] : value;
253
251
  };
254
252
  const signature = getHeader(SIGNATURE_HEADER);
@@ -285,10 +283,6 @@ function normalizeUrlForMatch(value) {
285
283
  return value.trim().replace(/\/$/, "");
286
284
  }
287
285
  }
288
- function coerceFeatureMask(value) {
289
- if (typeof value === "number" && Number.isSafeInteger(value) && value >= 0) return value;
290
- return parseStrictNonNegativeInteger(value);
291
- }
292
286
  function formatMissingResponseFeatureMessage(bot, features) {
293
287
  const id = bot.id == null ? "unknown" : String(bot.id);
294
288
  return `Nextcloud Talk bot "${bot.name?.trim() || "matching bot"}" (${id}) is missing the response feature${typeof features === "number" ? ` (features=${features})` : ""}; outbound replies will fail. Run ./occ talk:bot:state --feature webhook --feature response --feature reaction ${id} 1 or reinstall the bot with --feature response.`;
@@ -354,7 +348,7 @@ async function probeNextcloudTalkBotResponseFeature(params) {
354
348
  code: "bot_not_found",
355
349
  message: `Nextcloud Talk bot response feature probe could not find a bot with webhook URL ${webhookUrl}.`
356
350
  };
357
- const features = coerceFeatureMask(bot.features);
351
+ const features = parseStrictNonNegativeInteger(bot.features);
358
352
  if (features == null || (features & BOT_FEATURE_RESPONSE) !== BOT_FEATURE_RESPONSE) return {
359
353
  ok: false,
360
354
  code: "missing_response_feature",
@@ -442,8 +436,10 @@ const NextcloudTalkAccountSchemaBase = z.object({
442
436
  apiPassword: buildSecretInputSchema().optional(),
443
437
  apiPasswordFile: z.string().optional(),
444
438
  dmPolicy: DmPolicySchema.optional().default("pairing"),
445
- webhookPort: z.number().int().positive().optional(),
446
- webhookHost: z.string().optional(),
439
+ legacyWebhook: z.union([z.literal(false), z.object({
440
+ port: z.number().int().min(1).max(65535),
441
+ host: z.string().optional()
442
+ }).strict()]).optional(),
447
443
  webhookPath: z.string().optional(),
448
444
  webhookPublicUrl: z.string().optional(),
449
445
  allowFrom: z.array(z.string()).optional(),
@@ -467,18 +463,199 @@ const NextcloudTalkConfigSchema = buildMultiAccountChannelSchema(NextcloudTalkAc
467
463
  }
468
464
  });
469
465
  //#endregion
466
+ //#region src/gateway/gateway-http-route-contracts.ts
467
+ const GATEWAY_PROBE_ROUTES = /* @__PURE__ */ new Map([
468
+ ["/health", "live"],
469
+ ["/healthz", "live"],
470
+ ["/ready", "ready"],
471
+ ["/readyz", "ready"],
472
+ ["/startup", "startup"],
473
+ ["/startupz", "startup"]
474
+ ]);
475
+ function classifyGatewayProbePath(pathname) {
476
+ for (const [root, status] of GATEWAY_PROBE_ROUTES) {
477
+ if (pathname === root) return status;
478
+ if (pathname.startsWith(`${root}/`)) return "namespace";
479
+ }
480
+ return "outside";
481
+ }
482
+ //#endregion
483
+ //#region packages/normalization-core/src/string-coerce.ts
484
+ /** Trims string input and returns null for non-strings or empty strings. */
485
+ function normalizeNullableString(value) {
486
+ if (typeof value !== "string") return null;
487
+ const trimmed = value.trim();
488
+ return trimmed ? trimmed : null;
489
+ }
490
+ /** Trims string input and returns undefined for non-strings or empty strings. */
491
+ function normalizeOptionalString$1(value) {
492
+ return normalizeNullableString(value) ?? void 0;
493
+ }
494
+ /** Lowercases a normalized optional string. */
495
+ function normalizeOptionalLowercaseString$1(value) {
496
+ return normalizeOptionalString$1(value)?.toLowerCase();
497
+ }
498
+ /** Lowercases a normalized string or returns an empty string when absent. */
499
+ function normalizeLowercaseStringOrEmpty$1(value) {
500
+ return normalizeOptionalLowercaseString$1(value) ?? "";
501
+ }
502
+ //#endregion
503
+ //#region src/plugins/http-path-prefix.ts
504
+ function prefixMatchPath(pathname, prefix) {
505
+ return pathname === prefix || pathname.startsWith(`${prefix}/`) || pathname.startsWith(`${prefix}%`);
506
+ }
507
+ //#endregion
508
+ //#region src/gateway/security-path.ts
509
+ const MAX_PATH_DECODE_PASSES = 32;
510
+ function normalizePathSeparators(pathname) {
511
+ const collapsed = pathname.replace(/\/{2,}/g, "/");
512
+ if (collapsed.length <= 1) return collapsed;
513
+ return collapsed.replace(/\/+$/, "");
514
+ }
515
+ function resolveDotSegments(pathname) {
516
+ try {
517
+ return new URL(pathname, "http://localhost").pathname;
518
+ } catch {
519
+ return pathname;
520
+ }
521
+ }
522
+ function normalizePathForSecurity(pathname) {
523
+ return normalizePathSeparators(normalizeLowercaseStringOrEmpty$1(resolveDotSegments(pathname))) || "/";
524
+ }
525
+ function buildCanonicalPathCandidates(pathname, maxDecodePasses = MAX_PATH_DECODE_PASSES) {
526
+ const candidates = /* @__PURE__ */ new Set([normalizePathForSecurity(pathname)]);
527
+ let decoded = pathname;
528
+ let malformedEncoding = false;
529
+ let decodePasses = 0;
530
+ for (let pass = 0; pass < maxDecodePasses; pass++) {
531
+ let nextDecoded;
532
+ try {
533
+ nextDecoded = decodeURIComponent(decoded);
534
+ } catch {
535
+ malformedEncoding = true;
536
+ break;
537
+ }
538
+ if (nextDecoded === decoded) break;
539
+ decodePasses += 1;
540
+ decoded = nextDecoded;
541
+ candidates.add(normalizePathForSecurity(decoded));
542
+ }
543
+ let decodePassLimitReached = false;
544
+ if (!malformedEncoding) try {
545
+ decodePassLimitReached = decodeURIComponent(decoded) !== decoded;
546
+ } catch {
547
+ malformedEncoding = true;
548
+ }
549
+ return {
550
+ candidates: [...candidates],
551
+ decodePasses,
552
+ decodePassLimitReached,
553
+ malformedEncoding
554
+ };
555
+ }
556
+ function canonicalizePathForSecurity(pathname) {
557
+ const { candidates, decodePasses, decodePassLimitReached, malformedEncoding } = buildCanonicalPathCandidates(pathname);
558
+ return {
559
+ canonicalPath: candidates[candidates.length - 1] ?? "/",
560
+ candidates,
561
+ decodePasses,
562
+ decodePassLimitReached,
563
+ malformedEncoding,
564
+ rawNormalizedPath: normalizePathSeparators(normalizeLowercaseStringOrEmpty$1(pathname)) || "/"
565
+ };
566
+ }
567
+ const PROTECTED_PLUGIN_ROUTE_PREFIXES = ["/api/channels"];
568
+ //#endregion
569
+ //#region src/gateway/server/plugins-http/path-context.ts
570
+ function normalizeProtectedPrefix(prefix) {
571
+ const collapsed = normalizeLowercaseStringOrEmpty$1(prefix).replace(/\/{2,}/g, "/");
572
+ if (collapsed.length <= 1) return collapsed || "/";
573
+ return collapsed.replace(/\/+$/, "");
574
+ }
575
+ const NORMALIZED_PROTECTED_PLUGIN_ROUTE_PREFIXES = PROTECTED_PLUGIN_ROUTE_PREFIXES.map(normalizeProtectedPrefix);
576
+ /** Returns true when any decoded path candidate targets a protected route. */
577
+ function isProtectedPluginRoutePathFromContext(context) {
578
+ if (context.candidates.some((candidate) => NORMALIZED_PROTECTED_PLUGIN_ROUTE_PREFIXES.some((prefix) => prefixMatchPath(candidate, prefix)))) return true;
579
+ if (context.decodePassLimitReached) return true;
580
+ if (!context.malformedEncoding) return false;
581
+ return NORMALIZED_PROTECTED_PLUGIN_ROUTE_PREFIXES.some((prefix) => prefixMatchPath(context.rawNormalizedPath, prefix));
582
+ }
583
+ /** Builds all security-relevant decoded path candidates for a request path. */
584
+ function resolvePluginRoutePathContext(pathname) {
585
+ const canonical = canonicalizePathForSecurity(pathname);
586
+ return {
587
+ pathname,
588
+ canonicalPath: canonical.canonicalPath,
589
+ candidates: canonical.candidates,
590
+ malformedEncoding: canonical.malformedEncoding,
591
+ decodePassLimitReached: canonical.decodePassLimitReached,
592
+ rawNormalizedPath: canonical.rawNormalizedPath
593
+ };
594
+ }
595
+ //#endregion
596
+ //#region \0openclaw:bundled-sdk:openclaw/plugin-sdk/gateway-config-runtime
597
+ var gateway_config_runtime_exports = /* @__PURE__ */ __exportAll({
598
+ classifyGatewayProbePath: () => classifyGatewayProbePath,
599
+ isProtectedPluginRoutePathFromContext: () => isProtectedPluginRoutePathFromContext,
600
+ resolvePluginRoutePathContext: () => resolvePluginRoutePathContext
601
+ });
602
+ import * as import_openclaw_plugin_sdk_gateway_config_runtime from "openclaw/plugin-sdk/gateway-config-runtime";
603
+ __reExport(gateway_config_runtime_exports, import_openclaw_plugin_sdk_gateway_config_runtime);
604
+ //#endregion
470
605
  //#region extensions/nextcloud-talk/src/replay-migration-contract.ts
471
606
  const NEXTCLOUD_TALK_PLUGIN_ID = "nextcloud-talk";
472
607
  const NEXTCLOUD_TALK_REPLAY_DEDUPE_NAMESPACE_PREFIX = "replay-dedupe";
473
608
  const NEXTCLOUD_TALK_REPLAY_DEDUPE_TTL_MS = 864e5;
474
609
  const NEXTCLOUD_TALK_REPLAY_DEDUPE_MAX_ENTRIES = 1e4;
475
610
  //#endregion
611
+ //#region extensions/nextcloud-talk/src/webhook-route.ts
612
+ const DEFAULT_NEXTCLOUD_TALK_WEBHOOK_PATH = "/nextcloud-talk-webhook";
613
+ function resolveNextcloudTalkLegacyWebhook(config) {
614
+ const listener = config.legacyWebhook;
615
+ if (listener === false) return;
616
+ return {
617
+ port: listener?.port ?? 8788,
618
+ host: listener?.host ?? "0.0.0.0"
619
+ };
620
+ }
621
+ function describeNextcloudTalkWebhookRouteConflict(path, gatewayPort) {
622
+ const pathname = URL.parse(path, "http://localhost")?.pathname ?? path;
623
+ const probe = classifyGatewayProbePath(pathname);
624
+ const reason = probe !== "outside" && probe !== "namespace" ? "is reserved for Gateway probes" : isProtectedPluginRoutePathFromContext(resolvePluginRoutePathContext(pathname)) ? "requires Gateway authentication" : void 0;
625
+ if (!reason) return;
626
+ return `Webhook path "${path}" ${reason} and cannot receive Nextcloud callbacks on the Gateway port. Set webhookPath to "${DEFAULT_NEXTCLOUD_TALK_WEBHOOK_PATH}" and update the Nextcloud bot callback and reverse-proxy upstream to Gateway port ${gatewayPort}${DEFAULT_NEXTCLOUD_TALK_WEBHOOK_PATH}.`;
627
+ }
628
+ //#endregion
476
629
  //#region extensions/nextcloud-talk/src/doctor.ts
477
630
  function sanitizeLegacyReplaySegment(value) {
478
631
  const trimmed = value.trim();
479
632
  if (!trimmed) return "default";
480
633
  return trimmed.replace(/[^a-zA-Z0-9_-]/g, "_");
481
634
  }
635
+ function runNextcloudTalkDoctorSequence(params) {
636
+ const infoNotes = [];
637
+ const warningNotes = [];
638
+ for (const accountId of listNextcloudTalkAccountIds(params.cfg)) {
639
+ const account = resolveNextcloudTalkAccount({
640
+ cfg: params.cfg,
641
+ accountId
642
+ });
643
+ if (!account.enabled || !isNextcloudTalkAccountConfigured(account)) continue;
644
+ const gatewayPort = (0, gateway_config_runtime_exports.resolveGatewayPort)({ gateway: params.cfg.gateway }, params.env);
645
+ const webhookPath = account.config.webhookPath ?? "/nextcloud-talk-webhook";
646
+ const destination = `Gateway port ${gatewayPort}${webhookPath}`;
647
+ const legacyListener = resolveNextcloudTalkLegacyWebhook(account.config);
648
+ const routeConflict = describeNextcloudTalkWebhookRouteConflict(webhookPath, gatewayPort);
649
+ if (routeConflict) warningNotes.push(`- channels.nextcloud-talk.${account.accountId}: ${routeConflict}` + (legacyListener ? ` Legacy webhook listener ${legacyListener.host}:${legacyListener.port} remains available; verify the new route before setting legacyWebhook: false.` : " This account cannot start until the callback path is changed."));
650
+ else if (legacyListener) infoNotes.push(`- channels.nextcloud-talk.${account.accountId}: legacy webhook listener ${legacyListener.host}:${legacyListener.port} forwards to the Gateway route. Point the Nextcloud callback or reverse-proxy upstream to ${destination}, verify delivery, then set legacyWebhook: false to disable this account's legacy forwarding.`);
651
+ else infoNotes.push(`- channels.nextcloud-talk.${account.accountId}: legacyWebhook is false; use ${destination} for the Nextcloud callback or reverse-proxy upstream.`);
652
+ }
653
+ return {
654
+ changeNotes: [],
655
+ warningNotes,
656
+ infoNotes
657
+ };
658
+ }
482
659
  async function collectNextcloudTalkBotResponseWarnings(params) {
483
660
  const warnings = [];
484
661
  for (const accountId of listNextcloudTalkAccountIds(params.cfg)) {
@@ -528,7 +705,8 @@ async function repairNextcloudTalkReplayDedupeState(params) {
528
705
  const nextcloudTalkDoctor = {
529
706
  legacyConfigRules,
530
707
  normalizeCompatibilityConfig,
531
- collectPreviewWarnings: async ({ cfg }) => await collectNextcloudTalkBotResponseWarnings({ cfg }),
708
+ runConfigSequence: runNextcloudTalkDoctorSequence,
709
+ collectPreviewWarnings: collectNextcloudTalkBotResponseWarnings,
532
710
  repairConfig: async ({ cfg, env }) => {
533
711
  const repair = await repairNextcloudTalkReplayDedupeState({
534
712
  cfg,
@@ -703,15 +881,7 @@ async function resolveNextcloudTalkRoomKind(params) {
703
881
  //#endregion
704
882
  //#region extensions/nextcloud-talk/src/normalize.ts
705
883
  function stripNextcloudTalkTargetPrefix(raw) {
706
- const trimmed = raw.trim();
707
- if (!trimmed) return;
708
- let normalized = trimmed;
709
- if (/^nextcloud-talk:/i.test(normalized)) normalized = normalized.slice(15).trim();
710
- else if (/^nc-talk:/i.test(normalized)) normalized = normalized.slice(8).trim();
711
- else if (/^nc:/i.test(normalized)) normalized = normalized.slice(3).trim();
712
- if (/^room:/i.test(normalized)) normalized = normalized.slice(5).trim();
713
- if (!normalized) return;
714
- return normalized;
884
+ return raw.trim().replace(/^(nextcloud-talk|nc-talk|nc):/i, "").trim().replace(/^room:/i, "").trim() || void 0;
715
885
  }
716
886
  function normalizeNextcloudTalkMessagingTarget(raw) {
717
887
  const normalized = stripNextcloudTalkTargetPrefix(raw);
@@ -751,31 +921,16 @@ function collapseErrorSnippet(text) {
751
921
  if (collapsed.length > NEXTCLOUD_TALK_ERROR_SNIPPET_MAX_CHARS) return `${truncateUtf16Safe(collapsed, NEXTCLOUD_TALK_ERROR_SNIPPET_MAX_CHARS)}…`;
752
922
  return collapsed;
753
923
  }
754
- function resolveCredentials(explicit, account) {
755
- const baseUrl = explicit.baseUrl?.trim() ?? account.baseUrl;
756
- const secret = explicit.secret?.trim() ?? account.secret;
757
- if (!baseUrl) throw new Error(`Nextcloud Talk baseUrl missing for account "${account.accountId}" (set channels.nextcloud-talk.baseUrl).`);
758
- if (!secret) throw new Error(`Nextcloud Talk bot secret missing for account "${account.accountId}" (set channels.nextcloud-talk.botSecret/botSecretFile or NEXTCLOUD_TALK_BOT_SECRET for default).`);
759
- return {
760
- baseUrl,
761
- secret
762
- };
763
- }
764
- function normalizeRoomToken(to) {
765
- const normalized = stripNextcloudTalkTargetPrefix(to);
766
- if (!normalized) throw new Error("Room token is required for Nextcloud Talk sends");
767
- return normalized;
768
- }
769
924
  function resolveNextcloudTalkSendContext(opts) {
770
925
  const cfg = requireRuntimeConfig(opts.cfg, "Nextcloud Talk send");
771
926
  const account = resolveNextcloudTalkAccount({
772
927
  cfg,
773
928
  accountId: opts.accountId
774
929
  });
775
- const { baseUrl, secret } = resolveCredentials({
776
- baseUrl: opts.baseUrl,
777
- secret: opts.secret
778
- }, account);
930
+ const baseUrl = opts.baseUrl?.trim() ?? account.baseUrl;
931
+ const secret = opts.secret?.trim() ?? account.secret;
932
+ if (!baseUrl) throw new Error(`Nextcloud Talk baseUrl missing for account "${account.accountId}" (set channels.nextcloud-talk.baseUrl).`);
933
+ if (!secret) throw new Error(account.tokenStatus === "configured_unavailable" ? `Nextcloud Talk bot secret is configured but unavailable for account "${account.accountId}" (check the configured channels.nextcloud-talk.botSecret/botSecretFile).` : `Nextcloud Talk bot secret missing for account "${account.accountId}" (set channels.nextcloud-talk.botSecret/botSecretFile or NEXTCLOUD_TALK_BOT_SECRET for default).`);
779
934
  return {
780
935
  cfg,
781
936
  account,
@@ -783,6 +938,11 @@ function resolveNextcloudTalkSendContext(opts) {
783
938
  secret
784
939
  };
785
940
  }
941
+ function normalizeRoomToken(to) {
942
+ const normalized = stripNextcloudTalkTargetPrefix(to);
943
+ if (!normalized) throw new Error("Room token is required for Nextcloud Talk sends");
944
+ return normalized;
945
+ }
786
946
  function recordNextcloudTalkOutboundActivity(accountId) {
787
947
  try {
788
948
  getNextcloudTalkRuntime().channel.activity.record({
@@ -949,20 +1109,6 @@ function roomRoutes(params) {
949
1109
  }
950
1110
  });
951
1111
  }
952
- async function deliverNextcloudTalkReply(params) {
953
- const { cfg, payload, roomToken, accountId, statusSink } = params;
954
- return { visibleReplySent: await deliverFormattedTextWithAttachments({
955
- payload,
956
- send: async ({ text, replyToId }) => {
957
- await sendMessageNextcloudTalk(roomToken, text, {
958
- cfg,
959
- accountId,
960
- replyTo: replyToId
961
- });
962
- statusSink?.({ lastOutboundAt: Date.now() });
963
- }
964
- }) };
965
- }
966
1112
  async function handleNextcloudTalkInbound(params) {
967
1113
  const { message, account, config, runtime, statusSink } = params;
968
1114
  const core = getNextcloudTalkRuntime();
@@ -1018,7 +1164,7 @@ async function handleNextcloudTalkInbound(params) {
1018
1164
  const allowFrom = normalizeStringEntries(account.config.allowFrom);
1019
1165
  const outerGroupAllowFrom = account.config.groupAllowFrom?.length ? normalizeStringEntries(account.config.groupAllowFrom) : allowFrom;
1020
1166
  const roomAllowFrom = normalizeStringEntries(roomConfig?.allowFrom);
1021
- const resolveAccess = async (wasMentioned, contextBinding) => await resolveStableChannelMessageIngress({
1167
+ const resolveAccess = async (wasMentioned, contextBinding) => await core.channel.inbound.ingress.resolveStable({
1022
1168
  channelId: CHANNEL_ID,
1023
1169
  accountId: account.accountId,
1024
1170
  identity: {
@@ -1209,13 +1355,17 @@ async function handleNextcloudTalkInbound(params) {
1209
1355
  text: sanitizeAssistantVisibleText(payload.text)
1210
1356
  },
1211
1357
  deliver: async (payload) => {
1212
- return await deliverNextcloudTalkReply({
1213
- cfg: config,
1358
+ return { visibleReplySent: await deliverFormattedTextWithAttachments({
1214
1359
  payload,
1215
- roomToken,
1216
- accountId: account.accountId,
1217
- statusSink
1218
- });
1360
+ send: async ({ text, replyToId }) => {
1361
+ await sendMessageNextcloudTalk(roomToken, text, {
1362
+ cfg: config,
1363
+ accountId: account.accountId,
1364
+ replyTo: replyToId
1365
+ });
1366
+ statusSink?.({ lastOutboundAt: Date.now() });
1367
+ }
1368
+ }) };
1219
1369
  },
1220
1370
  onError: (err, info) => {
1221
1371
  runtime.error?.(`nextcloud-talk ${info.kind} reply failed: ${String(err)}`);
@@ -1299,211 +1449,226 @@ async function migrateNextcloudTalkLegacyReplayState(params) {
1299
1449
  }
1300
1450
  //#endregion
1301
1451
  //#region extensions/nextcloud-talk/src/monitor.ts
1302
- const DEFAULT_WEBHOOK_MAX_BODY_BYTES = 1048576;
1303
1452
  const PREAUTH_WEBHOOK_MAX_BODY_BYTES = 65536;
1304
1453
  const NEXTCLOUD_TALK_WEBHOOK_ACCEPTED_HEADER = "x-openclaw-delivery-accepted";
1305
1454
  const NEXTCLOUD_TALK_WEBHOOK_ACCEPTED_VALUE = "durable";
1306
1455
  const PREAUTH_WEBHOOK_BODY_TIMEOUT_MS = 5e3;
1307
1456
  const PREAUTH_WEBHOOK_MAX_IN_FLIGHT = 64;
1308
1457
  const WEBHOOK_IN_FLIGHT_KEY = "nextcloud-talk-webhook";
1309
- const HEALTH_PATH = "/healthz";
1310
1458
  const WEBHOOK_AUTH_RATE_LIMIT_SCOPE = "nextcloud-talk-webhook-auth";
1311
- const WEBHOOK_ERRORS = {
1312
- missingSignatureHeaders: "Missing signature headers",
1313
- invalidBackend: "Invalid backend",
1314
- invalidSignature: "Invalid signature",
1315
- invalidPayloadFormat: "Invalid payload format",
1316
- payloadTooLarge: "Payload too large",
1317
- internalServerError: "Internal server error"
1318
- };
1319
- function writeJsonResponse(res, status, body) {
1320
- if (body) {
1321
- res.writeHead(status, { "Content-Type": "application/json" });
1322
- res.end(JSON.stringify(body));
1323
- return;
1324
- }
1325
- res.writeHead(status);
1326
- res.end();
1327
- }
1328
1459
  function writeWebhookError(res, status, error) {
1329
1460
  if (res.headersSent) return;
1330
- writeJsonResponse(res, status, { error });
1331
- }
1332
- function validateWebhookHeaders(params) {
1333
- const headers = extractNextcloudTalkHeaders(params.req.headers);
1334
- if (!headers) {
1335
- writeWebhookError(params.res, 400, WEBHOOK_ERRORS.missingSignatureHeaders);
1336
- return null;
1337
- }
1338
- if (params.isBackendAllowed && !params.isBackendAllowed(headers.backend)) {
1339
- writeWebhookError(params.res, 401, WEBHOOK_ERRORS.invalidBackend);
1340
- return null;
1341
- }
1342
- return headers;
1343
- }
1344
- function verifyWebhookSignature(params) {
1345
- if (!verifyNextcloudTalkSignature({
1346
- signature: params.headers.signature,
1347
- random: params.headers.random,
1348
- body: params.body,
1349
- secret: params.secret
1350
- })) {
1351
- params.authRateLimiter.recordFailure(params.clientIp, WEBHOOK_AUTH_RATE_LIMIT_SCOPE);
1352
- writeWebhookError(params.res, 401, WEBHOOK_ERRORS.invalidSignature);
1353
- return false;
1354
- }
1355
- params.authRateLimiter.reset(params.clientIp, WEBHOOK_AUTH_RATE_LIMIT_SCOPE);
1356
- return true;
1357
- }
1358
- function readNextcloudTalkWebhookBody(req, maxBodyBytes) {
1359
- return readRequestBodyWithLimit(req, {
1360
- maxBytes: Math.min(maxBodyBytes, PREAUTH_WEBHOOK_MAX_BODY_BYTES),
1361
- timeoutMs: PREAUTH_WEBHOOK_BODY_TIMEOUT_MS,
1362
- destroyOnLimit: false
1363
- });
1461
+ res.writeHead(status, { "Content-Type": "application/json" });
1462
+ res.end(JSON.stringify({ error }));
1364
1463
  }
1365
1464
  async function rejectWebhookRequest(req, res, status, error) {
1366
1465
  if (res.headersSent) return;
1367
1466
  await sendHttpRequestRejection(req, res, status, JSON.stringify({ error }), "application/json");
1368
1467
  }
1369
- function createNextcloudTalkWebhookServer(opts) {
1370
- const { port, host, path, secret, onWebhook, onError, abortSignal } = opts;
1371
- const maxBodyBytes = typeof opts.maxBodyBytes === "number" && Number.isFinite(opts.maxBodyBytes) && opts.maxBodyBytes > 0 ? Math.floor(opts.maxBodyBytes) : DEFAULT_WEBHOOK_MAX_BODY_BYTES;
1372
- const readBody = opts.readBody ?? readNextcloudTalkWebhookBody;
1373
- const isBackendAllowed = opts.isBackendAllowed;
1374
- const authRateLimitMaxRequests = typeof opts.authRateLimit?.maxRequests === "number" ? opts.authRateLimit.maxRequests : WEBHOOK_RATE_LIMIT_DEFAULTS.maxRequests;
1375
- const authRateLimitWindowMs = typeof opts.authRateLimit?.windowMs === "number" ? opts.authRateLimit.windowMs : WEBHOOK_RATE_LIMIT_DEFAULTS.windowMs;
1376
- const webhookAuthRateLimiter = createAuthRateLimiter({
1377
- maxAttempts: authRateLimitMaxRequests,
1378
- windowMs: authRateLimitWindowMs,
1379
- lockoutMs: authRateLimitWindowMs,
1380
- exemptLoopback: false,
1381
- pruneIntervalMs: authRateLimitWindowMs
1382
- });
1383
- const webhookInFlightLimiter = createWebhookInFlightLimiter({
1384
- maxInFlightPerKey: PREAUTH_WEBHOOK_MAX_IN_FLIGHT,
1385
- maxTrackedKeys: 1
1386
- });
1387
- const handleWebhookRequest = async (req, res) => {
1388
- if (req.url === HEALTH_PATH) {
1389
- res.writeHead(200, { "Content-Type": "text/plain" });
1390
- res.end("ok");
1468
+ function createWebhookGuards() {
1469
+ return {
1470
+ authRateLimiter: createAuthRateLimiter({
1471
+ maxAttempts: WEBHOOK_RATE_LIMIT_DEFAULTS.maxRequests,
1472
+ windowMs: WEBHOOK_RATE_LIMIT_DEFAULTS.windowMs,
1473
+ lockoutMs: WEBHOOK_RATE_LIMIT_DEFAULTS.windowMs,
1474
+ exemptLoopback: false,
1475
+ pruneIntervalMs: WEBHOOK_RATE_LIMIT_DEFAULTS.windowMs
1476
+ }),
1477
+ inFlightLimiter: createWebhookInFlightLimiter({
1478
+ maxInFlightPerKey: PREAUTH_WEBHOOK_MAX_IN_FLIGHT,
1479
+ maxTrackedKeys: 1
1480
+ })
1481
+ };
1482
+ }
1483
+ async function handleWebhookRequest(req, res, targetsByPath, path) {
1484
+ const legacyListener = getWebhookLegacyListener(req);
1485
+ const requestTargets = (targetsByPath.get(path) ?? []).filter((entry) => entry.rawPath === req.url && (!legacyListener || entry.legacyListener?.port === legacyListener.port && entry.legacyListener.host === legacyListener.host));
1486
+ if (req.method !== "POST" || requestTargets.length === 0) {
1487
+ res.writeHead(404);
1488
+ res.end();
1489
+ return;
1490
+ }
1491
+ const servingTargets = requestTargets.filter((entry) => !entry.stopping);
1492
+ const firstTarget = servingTargets[0];
1493
+ if (!firstTarget) {
1494
+ res.writeHead(503, { "Retry-After": "1" });
1495
+ res.end();
1496
+ return;
1497
+ }
1498
+ const responseOwners = /* @__PURE__ */ new Map();
1499
+ if (!res.destroyed && !res.writableFinished) {
1500
+ for (const entry of servingTargets) {
1501
+ const responseDone = createDeferred();
1502
+ entry.pendingResponses.add(responseDone.promise);
1503
+ responseOwners.set(entry, () => {
1504
+ entry.pendingResponses.delete(responseDone.promise);
1505
+ responseOwners.delete(entry);
1506
+ responseDone.resolve();
1507
+ });
1508
+ }
1509
+ const complete = () => {
1510
+ res.off("finish", complete);
1511
+ res.off("close", complete);
1512
+ for (const release of responseOwners.values()) release();
1513
+ };
1514
+ res.once("finish", complete);
1515
+ res.once("close", complete);
1516
+ }
1517
+ const guards = legacyListener ? firstTarget.legacyGuards : firstTarget.gatewayGuards;
1518
+ if (!guards) {
1519
+ res.writeHead(503, { "Retry-After": "1" });
1520
+ res.end();
1521
+ return;
1522
+ }
1523
+ const { authRateLimiter: webhookAuthRateLimiter, inFlightLimiter: webhookInFlightLimiter } = guards;
1524
+ const { onError, trustedProxies, allowRealIpFallback } = firstTarget;
1525
+ const clientIp = resolveRequestClientIp(req, trustedProxies, allowRealIpFallback) ?? req.socket.remoteAddress ?? "unknown";
1526
+ if (!webhookAuthRateLimiter.check(clientIp, WEBHOOK_AUTH_RATE_LIMIT_SCOPE).allowed) {
1527
+ res.writeHead(429);
1528
+ res.end("Too Many Requests");
1529
+ return;
1530
+ }
1531
+ if (!webhookInFlightLimiter.tryAcquire(WEBHOOK_IN_FLIGHT_KEY)) {
1532
+ await sendHttpRequestRejection(req, res, 429, "Too Many Requests");
1533
+ return;
1534
+ }
1535
+ let body;
1536
+ let target;
1537
+ try {
1538
+ const headers = extractNextcloudTalkHeaders(req.headers);
1539
+ if (!headers) {
1540
+ writeWebhookError(res, 400, "Missing signature headers");
1541
+ return;
1542
+ }
1543
+ const targets = requestTargets.filter((entry) => !entry.isBackendAllowed || entry.isBackendAllowed(headers.backend));
1544
+ if (targets.length === 0) {
1545
+ writeWebhookError(res, 401, "Invalid backend");
1391
1546
  return;
1392
1547
  }
1393
- if (req.url !== path || req.method !== "POST") {
1394
- res.writeHead(404);
1548
+ body = await readRequestBodyWithLimit(req, {
1549
+ maxBytes: PREAUTH_WEBHOOK_MAX_BODY_BYTES,
1550
+ timeoutMs: PREAUTH_WEBHOOK_BODY_TIMEOUT_MS,
1551
+ destroyOnLimit: false
1552
+ });
1553
+ const matchesSignature = (entry) => verifyNextcloudTalkSignature({
1554
+ ...headers,
1555
+ body,
1556
+ secret: entry.secret
1557
+ });
1558
+ const match = resolveSingleWebhookTarget(targets, (entry) => servingTargets.includes(entry) && matchesSignature(entry));
1559
+ if (match.kind === "none" && targets.some((entry) => !servingTargets.includes(entry) && matchesSignature(entry))) {
1560
+ res.writeHead(503, { "Retry-After": "1" });
1395
1561
  res.end();
1396
1562
  return;
1397
1563
  }
1398
- const clientIp = resolveRequestClientIp(req, opts.trustedProxies, opts.allowRealIpFallback) ?? req.socket.remoteAddress ?? "unknown";
1399
- if (!webhookAuthRateLimiter.check(clientIp, WEBHOOK_AUTH_RATE_LIMIT_SCOPE).allowed) {
1400
- res.writeHead(429);
1401
- res.end("Too Many Requests");
1564
+ if (match.kind !== "single") {
1565
+ webhookAuthRateLimiter.recordFailure(clientIp, WEBHOOK_AUTH_RATE_LIMIT_SCOPE);
1566
+ writeWebhookError(res, 401, "Invalid signature");
1402
1567
  return;
1403
1568
  }
1404
- if (!webhookInFlightLimiter.tryAcquire(WEBHOOK_IN_FLIGHT_KEY)) {
1405
- await sendHttpRequestRejection(req, res, 429, "Too Many Requests");
1569
+ target = match.target;
1570
+ for (const [entry, release] of responseOwners) if (entry !== target) release();
1571
+ if (!targetsByPath.get(path)?.includes(target)) {
1572
+ res.writeHead(503, { "Retry-After": "1" });
1573
+ res.end();
1406
1574
  return;
1407
1575
  }
1408
- let body;
1409
- try {
1410
- const headers = validateWebhookHeaders({
1411
- req,
1412
- res,
1413
- isBackendAllowed
1414
- });
1415
- if (!headers) return;
1416
- body = await readBody(req, maxBodyBytes);
1417
- if (!verifyWebhookSignature({
1418
- headers,
1419
- body,
1420
- secret,
1421
- res,
1422
- clientIp,
1423
- authRateLimiter: webhookAuthRateLimiter
1424
- })) return;
1425
- } catch (err) {
1426
- if (isRequestBodyLimitError(err, "PAYLOAD_TOO_LARGE")) {
1427
- await rejectWebhookRequest(req, res, 413, WEBHOOK_ERRORS.payloadTooLarge);
1428
- return;
1429
- }
1430
- if (isRequestBodyLimitError(err, "REQUEST_BODY_TIMEOUT")) {
1431
- await rejectWebhookRequest(req, res, 408, requestBodyErrorToText("REQUEST_BODY_TIMEOUT"));
1432
- return;
1433
- }
1434
- if (err instanceof NextcloudTalkWebhookPayloadError) {
1435
- writeWebhookError(res, 400, WEBHOOK_ERRORS.invalidPayloadFormat);
1436
- return;
1437
- }
1438
- const error = err instanceof Error ? err : new Error(formatErrorMessage(err));
1439
- onError?.(error);
1440
- writeWebhookError(res, 500, WEBHOOK_ERRORS.internalServerError);
1576
+ webhookAuthRateLimiter.reset(clientIp, WEBHOOK_AUTH_RATE_LIMIT_SCOPE);
1577
+ } catch (err) {
1578
+ if (isRequestBodyLimitError(err, "PAYLOAD_TOO_LARGE")) {
1579
+ await rejectWebhookRequest(req, res, 413, "Payload too large");
1441
1580
  return;
1442
- } finally {
1443
- webhookInFlightLimiter.release(WEBHOOK_IN_FLIGHT_KEY);
1444
1581
  }
1445
- try {
1446
- if (await onWebhook(body) === "accepted") res.setHeader(NEXTCLOUD_TALK_WEBHOOK_ACCEPTED_HEADER, NEXTCLOUD_TALK_WEBHOOK_ACCEPTED_VALUE);
1447
- writeJsonResponse(res, 200);
1448
- } catch (err) {
1449
- if (err instanceof NextcloudTalkWebhookPayloadError) {
1450
- writeWebhookError(res, 400, WEBHOOK_ERRORS.invalidPayloadFormat);
1451
- return;
1452
- }
1453
- const error = err instanceof Error ? err : new Error(formatErrorMessage(err));
1454
- onError?.(error);
1455
- writeWebhookError(res, 500, WEBHOOK_ERRORS.internalServerError);
1582
+ if (isRequestBodyLimitError(err, "REQUEST_BODY_TIMEOUT")) {
1583
+ await rejectWebhookRequest(req, res, 408, requestBodyErrorToText("REQUEST_BODY_TIMEOUT"));
1584
+ return;
1456
1585
  }
1457
- };
1458
- const server = createServer((req, res) => {
1459
- runHttpConnectionRequest(req, () => handleWebhookRequest(req, res), res).catch((error) => {
1460
- onError?.(error instanceof Error ? error : new Error(formatErrorMessage(error)));
1461
- if (!res.destroyed && typeof res.destroy === "function") res.destroy();
1462
- });
1586
+ const error = err instanceof Error ? err : new Error(formatErrorMessage(err));
1587
+ onError?.(error);
1588
+ writeWebhookError(res, 500, "Internal server error");
1589
+ return;
1590
+ } finally {
1591
+ webhookInFlightLimiter.release(WEBHOOK_IN_FLIGHT_KEY);
1592
+ }
1593
+ try {
1594
+ if (await target.onWebhook(body) === "accepted") res.setHeader(NEXTCLOUD_TALK_WEBHOOK_ACCEPTED_HEADER, NEXTCLOUD_TALK_WEBHOOK_ACCEPTED_VALUE);
1595
+ res.writeHead(200);
1596
+ res.end();
1597
+ } catch (err) {
1598
+ if (err instanceof NextcloudTalkWebhookPayloadError) {
1599
+ writeWebhookError(res, 400, "Invalid payload format");
1600
+ return;
1601
+ }
1602
+ const error = err instanceof Error ? err : new Error(formatErrorMessage(err));
1603
+ target.onError?.(error);
1604
+ writeWebhookError(res, 500, "Internal server error");
1605
+ }
1606
+ }
1607
+ const webhookState = createPluginRuntimeStore({
1608
+ key: "nextcloud-talk:webhook-routes",
1609
+ errorMessage: "Nextcloud Talk webhook routes are not registered"
1610
+ });
1611
+ function registerNextcloudTalkWebhook(target) {
1612
+ let targets = webhookState.tryGetRuntime();
1613
+ if (!targets) {
1614
+ targets = /* @__PURE__ */ new Map();
1615
+ webhookState.setRuntime(targets);
1616
+ }
1617
+ const path = canonicalizeWebhookRouteKey(target.path);
1618
+ const gatewayGuards = targets.get(path)?.[0]?.gatewayGuards ?? createWebhookGuards();
1619
+ const endpoint = target.legacyListener;
1620
+ const legacyGuards = endpoint ? [...targets.values()].flat().find((entry) => entry.legacyListener?.port === endpoint.port && entry.legacyListener.host === endpoint.host)?.legacyGuards ?? createWebhookGuards() : void 0;
1621
+ const registration = registerWebhookTarget(targets, {
1622
+ ...target,
1623
+ path,
1624
+ rawPath: target.path,
1625
+ stopping: false,
1626
+ pendingResponses: /* @__PURE__ */ new Set(),
1627
+ gatewayGuards,
1628
+ legacyGuards
1463
1629
  });
1464
- let stopRequested = false;
1465
- let listenerActive = false;
1466
- let closePromise;
1467
- const closeIfListening = () => {
1468
- if (closePromise) return closePromise;
1469
- if (!listenerActive) return Promise.resolve();
1470
- closePromise = new Promise((resolve) => {
1471
- server.close(() => resolve());
1472
- }).finally(() => {
1473
- listenerActive = false;
1474
- closePromise = void 0;
1475
- });
1476
- return closePromise;
1477
- };
1478
- const stop = async () => {
1479
- stopRequested = true;
1480
- await closeIfListening();
1481
- webhookAuthRateLimiter.dispose();
1630
+ const removeTarget = () => {
1631
+ registration.unregister();
1632
+ const remaining = [...targets.values()].flat();
1633
+ for (const guards of [gatewayGuards, legacyGuards]) if (guards && !remaining.some((entry) => entry.gatewayGuards === guards || entry.legacyGuards === guards)) guards.authRateLimiter.dispose();
1482
1634
  };
1483
- const start = () => {
1484
- if (stopRequested) return Promise.resolve();
1485
- return new Promise((resolve, reject) => {
1486
- const onListenError = (error) => reject(error);
1487
- server.once("error", onListenError);
1488
- server.listen(port, host, () => {
1489
- listenerActive = true;
1490
- server.off("error", onListenError);
1491
- (async () => {
1492
- if (stopRequested) await closeIfListening();
1493
- resolve();
1494
- })().catch(reject);
1495
- });
1635
+ try {
1636
+ const unregister = registerPluginHttpRoute({
1637
+ path,
1638
+ auth: "plugin",
1639
+ pluginId: "nextcloud-talk",
1640
+ source: "webhook",
1641
+ accountId: target.accountId,
1642
+ handler: (req, res) => handleWebhookRequest(req, res, targets, path),
1643
+ legacyListener: target.legacyListener ? {
1644
+ ...target.legacyListener,
1645
+ health: {
1646
+ path: "/healthz",
1647
+ contentType: "text/plain"
1648
+ }
1649
+ } : void 0,
1650
+ reuseExistingSameOwner: true,
1651
+ throwOnFailure: true
1496
1652
  });
1497
- };
1498
- if (abortSignal) {
1499
- if (abortSignal.aborted) stop();
1500
- else abortSignal.addEventListener("abort", () => void stop(), { once: true });
1653
+ let stopPromise;
1654
+ return () => {
1655
+ if (stopPromise) return stopPromise;
1656
+ registration.target.stopping = true;
1657
+ const release = () => {
1658
+ removeTarget();
1659
+ unregister();
1660
+ };
1661
+ const pending = registration.target.pendingResponses;
1662
+ if (pending.size === 0) {
1663
+ release();
1664
+ stopPromise = Promise.resolve();
1665
+ } else stopPromise = Promise.all(pending).then(release);
1666
+ return stopPromise;
1667
+ };
1668
+ } catch (error) {
1669
+ removeTarget();
1670
+ throw error;
1501
1671
  }
1502
- return {
1503
- server,
1504
- start,
1505
- stop
1506
- };
1507
1672
  }
1508
1673
  //#endregion
1509
1674
  //#region extensions/nextcloud-talk/src/webhook-spool.ts
@@ -1667,9 +1832,6 @@ function createNextcloudTalkWebhookSpool(options) {
1667
1832
  }
1668
1833
  //#endregion
1669
1834
  //#region extensions/nextcloud-talk/src/monitor-runtime.ts
1670
- const DEFAULT_WEBHOOK_PORT = 8788;
1671
- const DEFAULT_WEBHOOK_HOST = "0.0.0.0";
1672
- const DEFAULT_WEBHOOK_PATH = "/nextcloud-talk-webhook";
1673
1835
  function normalizeOrigin(value) {
1674
1836
  try {
1675
1837
  return normalizeLowercaseStringOrEmpty(new URL(value).origin);
@@ -1686,9 +1848,11 @@ async function monitorNextcloudTalkProvider(opts) {
1686
1848
  });
1687
1849
  const runtime = resolveLoggerBackedRuntime(opts.runtime, core.logging.getChildLogger());
1688
1850
  if (!account.secret) throw new Error(`Nextcloud Talk bot secret not configured for account "${account.accountId}"`);
1689
- const port = account.config.webhookPort ?? DEFAULT_WEBHOOK_PORT;
1690
- const host = account.config.webhookHost ?? DEFAULT_WEBHOOK_HOST;
1691
- const path = account.config.webhookPath ?? DEFAULT_WEBHOOK_PATH;
1851
+ const path = account.config.webhookPath ?? "/nextcloud-talk-webhook";
1852
+ const gatewayPort = (0, gateway_config_runtime_exports.resolveGatewayPort)({ gateway: cfg.gateway });
1853
+ const legacyListener = resolveNextcloudTalkLegacyWebhook(account.config);
1854
+ const routeConflict = describeNextcloudTalkWebhookRouteConflict(path, gatewayPort);
1855
+ if (routeConflict && !legacyListener) throw new Error(`[nextcloud-talk:${account.accountId}] ${routeConflict}`);
1692
1856
  const logger = core.logging.getChildLogger({
1693
1857
  channel: "nextcloud-talk",
1694
1858
  accountId: account.accountId
@@ -1716,27 +1880,12 @@ async function monitorNextcloudTalkProvider(opts) {
1716
1880
  });
1717
1881
  }
1718
1882
  });
1719
- const server = (opts.createServer ?? createNextcloudTalkWebhookServer)({
1720
- port,
1721
- host,
1722
- path,
1723
- secret: account.secret,
1724
- isBackendAllowed: (backend) => {
1725
- if (!expectedBackendOrigin) return true;
1726
- return normalizeOrigin(backend) === expectedBackendOrigin;
1727
- },
1728
- onWebhook: spool.receive,
1729
- onError: (error) => {
1730
- logger.error(`[nextcloud-talk:${account.accountId}] webhook error: ${error.message}`);
1731
- },
1732
- trustedProxies: cfg.gateway?.trustedProxies,
1733
- allowRealIpFallback: cfg.gateway?.allowRealIpFallback,
1734
- abortSignal: opts.abortSignal
1735
- });
1883
+ let unregister;
1736
1884
  let stopPromise;
1737
1885
  const stop = () => {
1738
1886
  stopPromise ??= (async () => {
1739
- await server.stop();
1887
+ await unregister?.();
1888
+ unregister = void 0;
1740
1889
  await spool.stop();
1741
1890
  })();
1742
1891
  return stopPromise;
@@ -1748,7 +1897,26 @@ async function monitorNextcloudTalkProvider(opts) {
1748
1897
  }
1749
1898
  try {
1750
1899
  await spool.ready();
1751
- await server.start();
1900
+ if (opts.abortSignal?.aborted) {
1901
+ await stop();
1902
+ return { stop };
1903
+ }
1904
+ unregister = registerNextcloudTalkWebhook({
1905
+ accountId: account.accountId,
1906
+ legacyListener,
1907
+ path,
1908
+ secret: account.secret,
1909
+ isBackendAllowed: (backend) => {
1910
+ if (!expectedBackendOrigin) return true;
1911
+ return normalizeOrigin(backend) === expectedBackendOrigin;
1912
+ },
1913
+ onWebhook: spool.receive,
1914
+ onError: (error) => {
1915
+ logger.error(`[nextcloud-talk:${account.accountId}] webhook error: ${error.message}`);
1916
+ },
1917
+ trustedProxies: cfg.gateway?.trustedProxies,
1918
+ allowRealIpFallback: cfg.gateway?.allowRealIpFallback
1919
+ });
1752
1920
  } catch (error) {
1753
1921
  await stop();
1754
1922
  throw error;
@@ -1758,8 +1926,12 @@ async function monitorNextcloudTalkProvider(opts) {
1758
1926
  return { stop };
1759
1927
  }
1760
1928
  opts.statusSink?.(channelReadyPatch());
1761
- const publicUrl = account.config.webhookPublicUrl ?? `http://${host === "0.0.0.0" ? "localhost" : host}:${port}${path}`;
1762
- logger.info(`[nextcloud-talk:${account.accountId}] webhook listening on ${publicUrl}`);
1929
+ if (routeConflict && legacyListener) {
1930
+ logger.warn(`[nextcloud-talk:${account.accountId}] ${routeConflict} Legacy webhook listener ${legacyListener.host}:${legacyListener.port} remains available; verify the new route before setting legacyWebhook: false.`);
1931
+ return { stop };
1932
+ }
1933
+ logger.info(`[nextcloud-talk:${account.accountId}] Gateway webhook route ready at port ${gatewayPort}${path}; point the Nextcloud bot callback or reverse-proxy upstream here.`);
1934
+ if (legacyListener) logger.info(`[nextcloud-talk:${account.accountId}] legacy webhook listener ${legacyListener.host}:${legacyListener.port} forwards to the Gateway route. After verifying the callback or proxy upstream uses the Gateway port, set legacyWebhook: false to disable this account's legacy forwarding.`);
1763
1935
  return { stop };
1764
1936
  }
1765
1937
  //#endregion
@@ -1768,7 +1940,7 @@ const nextcloudTalkGatewayAdapter = {
1768
1940
  startAccount: async (ctx) => {
1769
1941
  const account = ctx.account;
1770
1942
  if (!account.secret || !account.baseUrl) throw new Error(`Nextcloud Talk not configured for account "${account.accountId}" (missing secret or baseUrl)`);
1771
- ctx.log?.info(`[${account.accountId}] starting Nextcloud Talk webhook server`);
1943
+ ctx.log?.info(`[${account.accountId}] starting Nextcloud Talk Gateway webhook route`);
1772
1944
  const statusSink = createAccountStatusSink({
1773
1945
  accountId: ctx.accountId,
1774
1946
  setStatus: ctx.setStatus
@@ -1865,6 +2037,15 @@ const nextcloudTalkMessageActions = {
1865
2037
  };
1866
2038
  //#endregion
1867
2039
  //#region extensions/nextcloud-talk/src/message-adapter.ts
2040
+ function sendNextcloudTalkMessage(ctx, text = ctx.text) {
2041
+ return sendMessageNextcloudTalk(ctx.to, text, {
2042
+ accountId: ctx.accountId ?? void 0,
2043
+ replyTo: ctx.replyToId ?? void 0,
2044
+ cfg: ctx.cfg,
2045
+ onPlatformSendDispatch: ctx.onPlatformSendDispatch,
2046
+ assertDirectAdapterHandoff: ctx.assertDirectAdapterHandoff
2047
+ });
2048
+ }
1868
2049
  const nextcloudTalkMessageAdapter = defineChannelMessageAdapter({
1869
2050
  id: "nextcloud-talk",
1870
2051
  durableFinal: { capabilities: {
@@ -1873,20 +2054,8 @@ const nextcloudTalkMessageAdapter = defineChannelMessageAdapter({
1873
2054
  replyTo: true
1874
2055
  } },
1875
2056
  send: {
1876
- text: async (ctx) => await sendMessageNextcloudTalk(ctx.to, ctx.text, {
1877
- accountId: ctx.accountId ?? void 0,
1878
- replyTo: ctx.replyToId ?? void 0,
1879
- cfg: ctx.cfg,
1880
- onPlatformSendDispatch: ctx.onPlatformSendDispatch,
1881
- assertDirectAdapterHandoff: ctx.assertDirectAdapterHandoff
1882
- }),
1883
- media: async (ctx) => await sendMessageNextcloudTalk(ctx.to, ctx.mediaUrl ? `${ctx.text}\n\nAttachment: ${ctx.mediaUrl}` : ctx.text, {
1884
- accountId: ctx.accountId ?? void 0,
1885
- replyTo: ctx.replyToId ?? void 0,
1886
- cfg: ctx.cfg,
1887
- onPlatformSendDispatch: ctx.onPlatformSendDispatch,
1888
- assertDirectAdapterHandoff: ctx.assertDirectAdapterHandoff
1889
- })
2057
+ text: sendNextcloudTalkMessage,
2058
+ media: (ctx) => sendNextcloudTalkMessage(ctx, ctx.mediaUrl ? `${ctx.text}\n\nAttachment: ${ctx.mediaUrl}` : ctx.text)
1890
2059
  }
1891
2060
  });
1892
2061
  //#endregion
@@ -1894,19 +2063,11 @@ const nextcloudTalkMessageAdapter = defineChannelMessageAdapter({
1894
2063
  function resolveNextcloudTalkOutboundSessionRoute(params) {
1895
2064
  const roomId = stripNextcloudTalkTargetPrefix(params.target);
1896
2065
  if (!roomId) return null;
1897
- const baseSessionKey = buildOutboundBaseSessionKey({
2066
+ return buildChannelOutboundSessionRoute({
1898
2067
  cfg: params.cfg,
1899
2068
  agentId: params.agentId,
1900
2069
  channel: "nextcloud-talk",
1901
2070
  accountId: params.accountId,
1902
- peer: {
1903
- kind: "group",
1904
- id: roomId
1905
- }
1906
- });
1907
- return {
1908
- sessionKey: baseSessionKey,
1909
- baseSessionKey,
1910
2071
  recipientSessionExact: false,
1911
2072
  peer: {
1912
2073
  kind: "group",
@@ -1915,7 +2076,7 @@ function resolveNextcloudTalkOutboundSessionRoute(params) {
1915
2076
  chatType: "group",
1916
2077
  from: `nextcloud-talk:room:${roomId}`,
1917
2078
  to: `nextcloud-talk:${roomId}`
1918
- };
2079
+ });
1919
2080
  }
1920
2081
  //#endregion
1921
2082
  //#region extensions/nextcloud-talk/src/setup-core.ts
@@ -1937,44 +2098,28 @@ function setNextcloudTalkAccountConfig(cfg, accountId, updates, clearFields) {
1937
2098
  ...clearFields ? { clearFields } : {}
1938
2099
  });
1939
2100
  }
1940
- async function promptNextcloudTalkAllowFrom(params) {
1941
- return await promptParsedAllowFromForAccount({
1942
- cfg: params.cfg,
1943
- accountId: params.accountId,
1944
- defaultAccountId: params.accountId,
1945
- prompter: params.prompter,
1946
- noteTitle: t$1("wizard.nextcloudTalk.userIdTitle"),
1947
- noteLines: [
1948
- t$1("wizard.nextcloudTalk.userIdHelpAdmin"),
1949
- t$1("wizard.nextcloudTalk.userIdHelpLogs"),
1950
- t$1("wizard.nextcloudTalk.userIdHelpLowercase"),
1951
- t$1("wizard.channels.docs", { link: formatDocsLink$1("/channels/nextcloud-talk", "nextcloud-talk") })
1952
- ],
1953
- message: t$1("wizard.nextcloudTalk.allowFromPrompt"),
1954
- placeholder: "username",
1955
- parseEntries: (raw) => ({ entries: raw.split(/[\n,;]+/g).map(normalizeLowercaseStringOrEmpty).filter(Boolean) }),
1956
- getExistingAllowFrom: ({ cfg, accountId }) => resolveNextcloudTalkAccount({
1957
- cfg,
1958
- accountId
1959
- }).config.allowFrom ?? [],
1960
- mergeEntries: ({ existing, parsed }) => mergeAllowFromEntries(existing.map((value) => normalizeLowercaseStringOrEmpty(String(value))), parsed),
1961
- applyAllowFrom: ({ cfg, accountId, allowFrom }) => setNextcloudTalkAccountConfig(cfg, accountId, {
1962
- dmPolicy: "allowlist",
1963
- allowFrom
1964
- })
1965
- });
1966
- }
1967
- async function promptNextcloudTalkAllowFromForAccount(params) {
1968
- const accountId = resolveSetupAccountId({
1969
- accountId: params.accountId,
1970
- defaultAccountId: resolveDefaultNextcloudTalkAccountId(params.cfg)
1971
- });
1972
- return await promptNextcloudTalkAllowFrom({
1973
- cfg: params.cfg,
1974
- prompter: params.prompter,
2101
+ const promptNextcloudTalkAllowFrom = async (params) => await createPromptParsedAllowFromForAccount({
2102
+ defaultAccountId: resolveDefaultNextcloudTalkAccountId,
2103
+ noteTitle: t$1("wizard.nextcloudTalk.userIdTitle"),
2104
+ noteLines: [
2105
+ t$1("wizard.nextcloudTalk.userIdHelpAdmin"),
2106
+ t$1("wizard.nextcloudTalk.userIdHelpLogs"),
2107
+ t$1("wizard.nextcloudTalk.userIdHelpLowercase"),
2108
+ t$1("wizard.channels.docs", { link: formatDocsLink$1("/channels/nextcloud-talk", "nextcloud-talk") })
2109
+ ],
2110
+ message: t$1("wizard.nextcloudTalk.allowFromPrompt"),
2111
+ placeholder: "username",
2112
+ parseEntries: (raw) => ({ entries: raw.split(/[\n,;]+/g).map(normalizeLowercaseStringOrEmpty).filter(Boolean) }),
2113
+ getExistingAllowFrom: ({ cfg, accountId }) => resolveNextcloudTalkAccount({
2114
+ cfg,
1975
2115
  accountId
1976
- });
1977
- }
2116
+ }).config.allowFrom ?? [],
2117
+ mergeEntries: ({ existing, parsed }) => mergeAllowFromEntries(existing.map((value) => normalizeLowercaseStringOrEmpty(String(value))), parsed),
2118
+ applyAllowFrom: ({ cfg, accountId, allowFrom }) => setNextcloudTalkAccountConfig(cfg, accountId, {
2119
+ dmPolicy: "allowlist",
2120
+ allowFrom
2121
+ })
2122
+ })(params);
1978
2123
  const nextcloudTalkDmPolicy = createChannelDmPolicy({
1979
2124
  label: "Nextcloud Talk",
1980
2125
  channel: channel$1,
@@ -1983,7 +2128,7 @@ const nextcloudTalkDmPolicy = createChannelDmPolicy({
1983
2128
  accountId: accountId ?? resolveDefaultNextcloudTalkAccountId(cfg)
1984
2129
  }),
1985
2130
  applyPatch: ({ cfg, account, patch }) => setNextcloudTalkAccountConfig(cfg, account.accountId, patch),
1986
- promptAllowFrom: promptNextcloudTalkAllowFromForAccount
2131
+ promptAllowFrom: promptNextcloudTalkAllowFrom
1987
2132
  });
1988
2133
  const nextcloudTalkSetupAdapter = {
1989
2134
  singleAccountKeysToMove: ["rooms"],
@@ -2304,7 +2449,7 @@ const nextcloudTalkPlugin = createChatChannelPlugin({
2304
2449
  ],
2305
2450
  normalizeTarget: normalizeNextcloudTalkMessagingTarget,
2306
2451
  inferTargetChatType: ({ to }) => normalizeNextcloudTalkMessagingTarget(to) ? "group" : void 0,
2307
- resolveOutboundSessionRoute: (params) => resolveNextcloudTalkOutboundSessionRoute(params),
2452
+ resolveOutboundSessionRoute: resolveNextcloudTalkOutboundSessionRoute,
2308
2453
  targetResolver: {
2309
2454
  looksLikeId: looksLikeNextcloudTalkTargetId,
2310
2455
  hint: "<roomToken>"
@@ -2369,24 +2514,11 @@ const nextcloudTalkPlugin = createChatChannelPlugin({
2369
2514
  },
2370
2515
  attachedResults: {
2371
2516
  channel: "nextcloud-talk",
2372
- sendText: async (ctx) => await nextcloudTalkMessageAdapter.send.text({
2373
- cfg: ctx.cfg,
2374
- to: ctx.to,
2375
- text: ctx.text,
2376
- accountId: ctx.accountId,
2377
- replyToId: ctx.replyToId,
2378
- onPlatformSendDispatch: ctx.onPlatformSendDispatch,
2379
- assertDirectAdapterHandoff: ctx.assertDirectAdapterHandoff
2380
- }),
2381
- sendMedia: async (ctx) => await nextcloudTalkMessageAdapter.send.media({
2382
- cfg: ctx.cfg,
2383
- to: ctx.to,
2384
- text: ctx.text,
2517
+ sendText: nextcloudTalkMessageAdapter.send.text,
2518
+ sendMedia: (ctx) => nextcloudTalkMessageAdapter.send.media({
2519
+ ...ctx,
2385
2520
  mediaUrl: ctx.mediaUrl ?? "",
2386
- accountId: ctx.accountId,
2387
- replyToId: ctx.replyToId,
2388
- onPlatformSendDispatch: ctx.onPlatformSendDispatch,
2389
- assertDirectAdapterHandoff: ctx.assertDirectAdapterHandoff
2521
+ onDeliveryResult: void 0
2390
2522
  })
2391
2523
  }
2392
2524
  }