@sonde/packs 0.0.0 → 0.1.1

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 (359) hide show
  1. package/.turbo/turbo-build.log +6 -0
  2. package/.turbo/turbo-test.log +814 -0
  3. package/.turbo/turbo-typecheck.log +4 -0
  4. package/CHANGELOG.md +10 -0
  5. package/dist/index.d.ts +16 -1
  6. package/dist/index.d.ts.map +1 -1
  7. package/dist/index.js +40 -2
  8. package/dist/index.js.map +1 -1
  9. package/dist/integrations/citrix.d.ts +13 -0
  10. package/dist/integrations/citrix.d.ts.map +1 -0
  11. package/dist/integrations/citrix.js +420 -0
  12. package/dist/integrations/citrix.js.map +1 -0
  13. package/dist/integrations/citrix.test.d.ts +2 -0
  14. package/dist/integrations/citrix.test.d.ts.map +1 -0
  15. package/dist/integrations/citrix.test.js +464 -0
  16. package/dist/integrations/citrix.test.js.map +1 -0
  17. package/dist/integrations/graph.d.ts +9 -0
  18. package/dist/integrations/graph.d.ts.map +1 -0
  19. package/dist/integrations/graph.js +290 -0
  20. package/dist/integrations/graph.js.map +1 -0
  21. package/dist/integrations/graph.test.d.ts +2 -0
  22. package/dist/integrations/graph.test.d.ts.map +1 -0
  23. package/dist/integrations/graph.test.js +356 -0
  24. package/dist/integrations/graph.test.js.map +1 -0
  25. package/dist/integrations/httpbin.d.ts +3 -0
  26. package/dist/integrations/httpbin.d.ts.map +1 -0
  27. package/dist/integrations/httpbin.js +70 -0
  28. package/dist/integrations/httpbin.js.map +1 -0
  29. package/dist/integrations/nutanix.d.ts +18 -0
  30. package/dist/integrations/nutanix.d.ts.map +1 -0
  31. package/dist/integrations/nutanix.js +1121 -0
  32. package/dist/integrations/nutanix.js.map +1 -0
  33. package/dist/integrations/nutanix.test.d.ts +2 -0
  34. package/dist/integrations/nutanix.test.d.ts.map +1 -0
  35. package/dist/integrations/nutanix.test.js +978 -0
  36. package/dist/integrations/nutanix.test.js.map +1 -0
  37. package/dist/integrations/proxmox.d.ts +12 -0
  38. package/dist/integrations/proxmox.d.ts.map +1 -0
  39. package/dist/integrations/proxmox.js +733 -0
  40. package/dist/integrations/proxmox.js.map +1 -0
  41. package/dist/integrations/proxmox.test.d.ts +2 -0
  42. package/dist/integrations/proxmox.test.d.ts.map +1 -0
  43. package/dist/integrations/proxmox.test.js +697 -0
  44. package/dist/integrations/proxmox.test.js.map +1 -0
  45. package/dist/integrations/servicenow.d.ts +3 -0
  46. package/dist/integrations/servicenow.d.ts.map +1 -0
  47. package/dist/integrations/servicenow.js +257 -0
  48. package/dist/integrations/servicenow.js.map +1 -0
  49. package/dist/integrations/servicenow.test.d.ts +2 -0
  50. package/dist/integrations/servicenow.test.d.ts.map +1 -0
  51. package/dist/integrations/servicenow.test.js +217 -0
  52. package/dist/integrations/servicenow.test.js.map +1 -0
  53. package/dist/integrations/splunk.d.ts +9 -0
  54. package/dist/integrations/splunk.d.ts.map +1 -0
  55. package/dist/integrations/splunk.js +242 -0
  56. package/dist/integrations/splunk.js.map +1 -0
  57. package/dist/integrations/splunk.test.d.ts +2 -0
  58. package/dist/integrations/splunk.test.d.ts.map +1 -0
  59. package/dist/integrations/splunk.test.js +323 -0
  60. package/dist/integrations/splunk.test.js.map +1 -0
  61. package/dist/mysql/index.d.ts +3 -0
  62. package/dist/mysql/index.d.ts.map +1 -0
  63. package/dist/mysql/index.js +13 -0
  64. package/dist/mysql/index.js.map +1 -0
  65. package/dist/mysql/manifest.d.ts +3 -0
  66. package/dist/mysql/manifest.d.ts.map +1 -0
  67. package/dist/mysql/manifest.js +69 -0
  68. package/dist/mysql/manifest.js.map +1 -0
  69. package/dist/mysql/probes/databases-list.d.ts +13 -0
  70. package/dist/mysql/probes/databases-list.d.ts.map +1 -0
  71. package/dist/mysql/probes/databases-list.js +31 -0
  72. package/dist/mysql/probes/databases-list.js.map +1 -0
  73. package/dist/mysql/probes/databases-list.test.d.ts +2 -0
  74. package/dist/mysql/probes/databases-list.test.d.ts.map +1 -0
  75. package/dist/mysql/probes/databases-list.test.js +54 -0
  76. package/dist/mysql/probes/databases-list.test.js.map +1 -0
  77. package/dist/mysql/probes/processlist.d.ts +18 -0
  78. package/dist/mysql/probes/processlist.d.ts.map +1 -0
  79. package/dist/mysql/probes/processlist.js +36 -0
  80. package/dist/mysql/probes/processlist.js.map +1 -0
  81. package/dist/mysql/probes/processlist.test.d.ts +2 -0
  82. package/dist/mysql/probes/processlist.test.d.ts.map +1 -0
  83. package/dist/mysql/probes/processlist.test.js +41 -0
  84. package/dist/mysql/probes/processlist.test.js.map +1 -0
  85. package/dist/mysql/probes/status.d.ts +14 -0
  86. package/dist/mysql/probes/status.d.ts.map +1 -0
  87. package/dist/mysql/probes/status.js +40 -0
  88. package/dist/mysql/probes/status.js.map +1 -0
  89. package/dist/mysql/probes/status.test.d.ts +2 -0
  90. package/dist/mysql/probes/status.test.d.ts.map +1 -0
  91. package/dist/mysql/probes/status.test.js +43 -0
  92. package/dist/mysql/probes/status.test.js.map +1 -0
  93. package/dist/nginx/index.d.ts +3 -0
  94. package/dist/nginx/index.d.ts.map +1 -0
  95. package/dist/nginx/index.js +13 -0
  96. package/dist/nginx/index.js.map +1 -0
  97. package/dist/nginx/manifest.d.ts +3 -0
  98. package/dist/nginx/manifest.d.ts.map +1 -0
  99. package/dist/nginx/manifest.js +68 -0
  100. package/dist/nginx/manifest.js.map +1 -0
  101. package/dist/nginx/probes/access-log-tail.d.ts +9 -0
  102. package/dist/nginx/probes/access-log-tail.d.ts.map +1 -0
  103. package/dist/nginx/probes/access-log-tail.js +14 -0
  104. package/dist/nginx/probes/access-log-tail.js.map +1 -0
  105. package/dist/nginx/probes/access-log-tail.test.d.ts +2 -0
  106. package/dist/nginx/probes/access-log-tail.test.d.ts.map +1 -0
  107. package/dist/nginx/probes/access-log-tail.test.js +40 -0
  108. package/dist/nginx/probes/access-log-tail.test.js.map +1 -0
  109. package/dist/nginx/probes/config-test.d.ts +8 -0
  110. package/dist/nginx/probes/config-test.d.ts.map +1 -0
  111. package/dist/nginx/probes/config-test.js +18 -0
  112. package/dist/nginx/probes/config-test.js.map +1 -0
  113. package/dist/nginx/probes/config-test.test.d.ts +2 -0
  114. package/dist/nginx/probes/config-test.test.d.ts.map +1 -0
  115. package/dist/nginx/probes/config-test.test.js +35 -0
  116. package/dist/nginx/probes/config-test.test.js.map +1 -0
  117. package/dist/nginx/probes/error-log-tail.d.ts +9 -0
  118. package/dist/nginx/probes/error-log-tail.d.ts.map +1 -0
  119. package/dist/nginx/probes/error-log-tail.js +14 -0
  120. package/dist/nginx/probes/error-log-tail.js.map +1 -0
  121. package/dist/nginx/probes/error-log-tail.test.d.ts +2 -0
  122. package/dist/nginx/probes/error-log-tail.test.d.ts.map +1 -0
  123. package/dist/nginx/probes/error-log-tail.test.js +34 -0
  124. package/dist/nginx/probes/error-log-tail.test.js.map +1 -0
  125. package/dist/postgres/index.d.ts +3 -0
  126. package/dist/postgres/index.d.ts.map +1 -0
  127. package/dist/postgres/index.js +13 -0
  128. package/dist/postgres/index.js.map +1 -0
  129. package/dist/postgres/manifest.d.ts +3 -0
  130. package/dist/postgres/manifest.d.ts.map +1 -0
  131. package/dist/postgres/manifest.js +90 -0
  132. package/dist/postgres/manifest.js.map +1 -0
  133. package/dist/postgres/probes/connections-active.d.ts +17 -0
  134. package/dist/postgres/probes/connections-active.d.ts.map +1 -0
  135. package/dist/postgres/probes/connections-active.js +37 -0
  136. package/dist/postgres/probes/connections-active.js.map +1 -0
  137. package/dist/postgres/probes/connections-active.test.d.ts +2 -0
  138. package/dist/postgres/probes/connections-active.test.d.ts.map +1 -0
  139. package/dist/postgres/probes/connections-active.test.js +36 -0
  140. package/dist/postgres/probes/connections-active.test.js.map +1 -0
  141. package/dist/postgres/probes/databases-list.d.ts +14 -0
  142. package/dist/postgres/probes/databases-list.d.ts.map +1 -0
  143. package/dist/postgres/probes/databases-list.js +34 -0
  144. package/dist/postgres/probes/databases-list.js.map +1 -0
  145. package/dist/postgres/probes/databases-list.test.d.ts +2 -0
  146. package/dist/postgres/probes/databases-list.test.d.ts.map +1 -0
  147. package/dist/postgres/probes/databases-list.test.js +49 -0
  148. package/dist/postgres/probes/databases-list.test.js.map +1 -0
  149. package/dist/postgres/probes/query-slow.d.ts +17 -0
  150. package/dist/postgres/probes/query-slow.d.ts.map +1 -0
  151. package/dist/postgres/probes/query-slow.js +37 -0
  152. package/dist/postgres/probes/query-slow.js.map +1 -0
  153. package/dist/postgres/probes/query-slow.test.d.ts +2 -0
  154. package/dist/postgres/probes/query-slow.test.d.ts.map +1 -0
  155. package/dist/postgres/probes/query-slow.test.js +30 -0
  156. package/dist/postgres/probes/query-slow.test.js.map +1 -0
  157. package/dist/proxmox/index.d.ts +3 -0
  158. package/dist/proxmox/index.d.ts.map +1 -0
  159. package/dist/proxmox/index.js +23 -0
  160. package/dist/proxmox/index.js.map +1 -0
  161. package/dist/proxmox/manifest.d.ts +3 -0
  162. package/dist/proxmox/manifest.d.ts.map +1 -0
  163. package/dist/proxmox/manifest.js +75 -0
  164. package/dist/proxmox/manifest.js.map +1 -0
  165. package/dist/proxmox/probes/ceph-status.d.ts +36 -0
  166. package/dist/proxmox/probes/ceph-status.d.ts.map +1 -0
  167. package/dist/proxmox/probes/ceph-status.js +71 -0
  168. package/dist/proxmox/probes/ceph-status.js.map +1 -0
  169. package/dist/proxmox/probes/ceph-status.test.d.ts +2 -0
  170. package/dist/proxmox/probes/ceph-status.test.d.ts.map +1 -0
  171. package/dist/proxmox/probes/ceph-status.test.js +115 -0
  172. package/dist/proxmox/probes/ceph-status.test.js.map +1 -0
  173. package/dist/proxmox/probes/cluster-config.d.ts +31 -0
  174. package/dist/proxmox/probes/cluster-config.d.ts.map +1 -0
  175. package/dist/proxmox/probes/cluster-config.js +72 -0
  176. package/dist/proxmox/probes/cluster-config.js.map +1 -0
  177. package/dist/proxmox/probes/cluster-config.test.d.ts +2 -0
  178. package/dist/proxmox/probes/cluster-config.test.d.ts.map +1 -0
  179. package/dist/proxmox/probes/cluster-config.test.js +107 -0
  180. package/dist/proxmox/probes/cluster-config.test.js.map +1 -0
  181. package/dist/proxmox/probes/ha-status.d.ts +18 -0
  182. package/dist/proxmox/probes/ha-status.d.ts.map +1 -0
  183. package/dist/proxmox/probes/ha-status.js +38 -0
  184. package/dist/proxmox/probes/ha-status.js.map +1 -0
  185. package/dist/proxmox/probes/ha-status.test.d.ts +2 -0
  186. package/dist/proxmox/probes/ha-status.test.d.ts.map +1 -0
  187. package/dist/proxmox/probes/ha-status.test.js +66 -0
  188. package/dist/proxmox/probes/ha-status.test.js.map +1 -0
  189. package/dist/proxmox/probes/lvm.d.ts +35 -0
  190. package/dist/proxmox/probes/lvm.d.ts.map +1 -0
  191. package/dist/proxmox/probes/lvm.js +75 -0
  192. package/dist/proxmox/probes/lvm.js.map +1 -0
  193. package/dist/proxmox/probes/lvm.test.d.ts +2 -0
  194. package/dist/proxmox/probes/lvm.test.d.ts.map +1 -0
  195. package/dist/proxmox/probes/lvm.test.js +128 -0
  196. package/dist/proxmox/probes/lvm.test.js.map +1 -0
  197. package/dist/proxmox/probes/lxc-config.d.ts +29 -0
  198. package/dist/proxmox/probes/lxc-config.d.ts.map +1 -0
  199. package/dist/proxmox/probes/lxc-config.js +67 -0
  200. package/dist/proxmox/probes/lxc-config.js.map +1 -0
  201. package/dist/proxmox/probes/lxc-config.test.d.ts +2 -0
  202. package/dist/proxmox/probes/lxc-config.test.d.ts.map +1 -0
  203. package/dist/proxmox/probes/lxc-config.test.js +77 -0
  204. package/dist/proxmox/probes/lxc-config.test.js.map +1 -0
  205. package/dist/proxmox/probes/lxc-list.d.ts +20 -0
  206. package/dist/proxmox/probes/lxc-list.d.ts.map +1 -0
  207. package/dist/proxmox/probes/lxc-list.js +49 -0
  208. package/dist/proxmox/probes/lxc-list.js.map +1 -0
  209. package/dist/proxmox/probes/lxc-list.test.d.ts +2 -0
  210. package/dist/proxmox/probes/lxc-list.test.d.ts.map +1 -0
  211. package/dist/proxmox/probes/lxc-list.test.js +51 -0
  212. package/dist/proxmox/probes/lxc-list.test.js.map +1 -0
  213. package/dist/proxmox/probes/vm-config.d.ts +21 -0
  214. package/dist/proxmox/probes/vm-config.d.ts.map +1 -0
  215. package/dist/proxmox/probes/vm-config.js +58 -0
  216. package/dist/proxmox/probes/vm-config.js.map +1 -0
  217. package/dist/proxmox/probes/vm-config.test.d.ts +2 -0
  218. package/dist/proxmox/probes/vm-config.test.d.ts.map +1 -0
  219. package/dist/proxmox/probes/vm-config.test.js +80 -0
  220. package/dist/proxmox/probes/vm-config.test.js.map +1 -0
  221. package/dist/proxmox/probes/vm-locks.d.ts +16 -0
  222. package/dist/proxmox/probes/vm-locks.d.ts.map +1 -0
  223. package/dist/proxmox/probes/vm-locks.js +35 -0
  224. package/dist/proxmox/probes/vm-locks.js.map +1 -0
  225. package/dist/proxmox/probes/vm-locks.test.d.ts +2 -0
  226. package/dist/proxmox/probes/vm-locks.test.d.ts.map +1 -0
  227. package/dist/proxmox/probes/vm-locks.test.js +54 -0
  228. package/dist/proxmox/probes/vm-locks.test.js.map +1 -0
  229. package/dist/redis/index.d.ts +3 -0
  230. package/dist/redis/index.d.ts.map +1 -0
  231. package/dist/redis/index.js +13 -0
  232. package/dist/redis/index.js.map +1 -0
  233. package/dist/redis/manifest.d.ts +3 -0
  234. package/dist/redis/manifest.d.ts.map +1 -0
  235. package/dist/redis/manifest.js +51 -0
  236. package/dist/redis/manifest.js.map +1 -0
  237. package/dist/redis/probes/info.d.ts +15 -0
  238. package/dist/redis/probes/info.d.ts.map +1 -0
  239. package/dist/redis/probes/info.js +32 -0
  240. package/dist/redis/probes/info.js.map +1 -0
  241. package/dist/redis/probes/info.test.d.ts +2 -0
  242. package/dist/redis/probes/info.test.d.ts.map +1 -0
  243. package/dist/redis/probes/info.test.js +64 -0
  244. package/dist/redis/probes/info.test.js.map +1 -0
  245. package/dist/redis/probes/keys-count.d.ts +13 -0
  246. package/dist/redis/probes/keys-count.d.ts.map +1 -0
  247. package/dist/redis/probes/keys-count.js +24 -0
  248. package/dist/redis/probes/keys-count.js.map +1 -0
  249. package/dist/redis/probes/keys-count.test.d.ts +2 -0
  250. package/dist/redis/probes/keys-count.test.d.ts.map +1 -0
  251. package/dist/redis/probes/keys-count.test.js +37 -0
  252. package/dist/redis/probes/keys-count.test.js.map +1 -0
  253. package/dist/redis/probes/memory-usage.d.ts +16 -0
  254. package/dist/redis/probes/memory-usage.d.ts.map +1 -0
  255. package/dist/redis/probes/memory-usage.js +31 -0
  256. package/dist/redis/probes/memory-usage.js.map +1 -0
  257. package/dist/redis/probes/memory-usage.test.d.ts +2 -0
  258. package/dist/redis/probes/memory-usage.test.d.ts.map +1 -0
  259. package/dist/redis/probes/memory-usage.test.js +48 -0
  260. package/dist/redis/probes/memory-usage.test.js.map +1 -0
  261. package/dist/runbooks/nutanix.d.ts +3 -0
  262. package/dist/runbooks/nutanix.d.ts.map +1 -0
  263. package/dist/runbooks/nutanix.js +619 -0
  264. package/dist/runbooks/nutanix.js.map +1 -0
  265. package/dist/runbooks/nutanix.test.d.ts +2 -0
  266. package/dist/runbooks/nutanix.test.d.ts.map +1 -0
  267. package/dist/runbooks/nutanix.test.js +971 -0
  268. package/dist/runbooks/nutanix.test.js.map +1 -0
  269. package/dist/runbooks/proxmox.d.ts +3 -0
  270. package/dist/runbooks/proxmox.d.ts.map +1 -0
  271. package/dist/runbooks/proxmox.js +451 -0
  272. package/dist/runbooks/proxmox.js.map +1 -0
  273. package/dist/runbooks/proxmox.test.d.ts +2 -0
  274. package/dist/runbooks/proxmox.test.d.ts.map +1 -0
  275. package/dist/runbooks/proxmox.test.js +700 -0
  276. package/dist/runbooks/proxmox.test.js.map +1 -0
  277. package/dist/signatures.d.ts +2 -0
  278. package/dist/signatures.d.ts.map +1 -0
  279. package/dist/signatures.js +2 -0
  280. package/dist/signatures.js.map +1 -0
  281. package/dist/types.d.ts +53 -0
  282. package/dist/types.d.ts.map +1 -1
  283. package/dist/validation.d.ts +6 -1
  284. package/dist/validation.d.ts.map +1 -1
  285. package/dist/validation.js +10 -1
  286. package/dist/validation.js.map +1 -1
  287. package/package.json +1 -1
  288. package/src/index.ts +60 -6
  289. package/src/integrations/citrix.test.ts +592 -0
  290. package/src/integrations/citrix.ts +557 -0
  291. package/src/integrations/graph.test.ts +478 -0
  292. package/src/integrations/graph.ts +413 -0
  293. package/src/integrations/httpbin.ts +72 -0
  294. package/src/integrations/nutanix.test.ts +1508 -0
  295. package/src/integrations/nutanix.ts +1460 -0
  296. package/src/integrations/proxmox.test.ts +1020 -0
  297. package/src/integrations/proxmox.ts +989 -0
  298. package/src/integrations/servicenow.test.ts +314 -0
  299. package/src/integrations/servicenow.ts +285 -0
  300. package/src/integrations/splunk.test.ts +440 -0
  301. package/src/integrations/splunk.ts +356 -0
  302. package/src/mysql/index.ts +14 -0
  303. package/src/mysql/manifest.ts +70 -0
  304. package/src/mysql/probes/databases-list.test.ts +62 -0
  305. package/src/mysql/probes/databases-list.ts +45 -0
  306. package/src/mysql/probes/processlist.test.ts +47 -0
  307. package/src/mysql/probes/processlist.ts +55 -0
  308. package/src/mysql/probes/status.test.ts +50 -0
  309. package/src/mysql/probes/status.ts +56 -0
  310. package/src/nginx/index.ts +14 -0
  311. package/src/nginx/manifest.ts +69 -0
  312. package/src/nginx/probes/access-log-tail.test.ts +51 -0
  313. package/src/nginx/probes/access-log-tail.ts +23 -0
  314. package/src/nginx/probes/config-test.test.ts +47 -0
  315. package/src/nginx/probes/config-test.ts +24 -0
  316. package/src/nginx/probes/error-log-tail.test.ts +44 -0
  317. package/src/nginx/probes/error-log-tail.ts +23 -0
  318. package/src/postgres/index.ts +14 -0
  319. package/src/postgres/manifest.ts +91 -0
  320. package/src/postgres/probes/connections-active.test.ts +42 -0
  321. package/src/postgres/probes/connections-active.ts +55 -0
  322. package/src/postgres/probes/databases-list.test.ts +57 -0
  323. package/src/postgres/probes/databases-list.ts +49 -0
  324. package/src/postgres/probes/query-slow.test.ts +37 -0
  325. package/src/postgres/probes/query-slow.ts +55 -0
  326. package/src/proxmox/index.ts +24 -0
  327. package/src/proxmox/manifest.ts +76 -0
  328. package/src/proxmox/probes/ceph-status.test.ts +126 -0
  329. package/src/proxmox/probes/ceph-status.ts +116 -0
  330. package/src/proxmox/probes/cluster-config.test.ts +118 -0
  331. package/src/proxmox/probes/cluster-config.ts +97 -0
  332. package/src/proxmox/probes/ha-status.test.ts +76 -0
  333. package/src/proxmox/probes/ha-status.ts +56 -0
  334. package/src/proxmox/probes/lvm.test.ts +140 -0
  335. package/src/proxmox/probes/lvm.ts +121 -0
  336. package/src/proxmox/probes/lxc-config.test.ts +89 -0
  337. package/src/proxmox/probes/lxc-config.ts +90 -0
  338. package/src/proxmox/probes/lxc-list.test.ts +60 -0
  339. package/src/proxmox/probes/lxc-list.ts +67 -0
  340. package/src/proxmox/probes/vm-config.test.ts +93 -0
  341. package/src/proxmox/probes/vm-config.ts +77 -0
  342. package/src/proxmox/probes/vm-locks.test.ts +63 -0
  343. package/src/proxmox/probes/vm-locks.ts +49 -0
  344. package/src/redis/index.ts +14 -0
  345. package/src/redis/manifest.ts +52 -0
  346. package/src/redis/probes/info.test.ts +73 -0
  347. package/src/redis/probes/info.ts +46 -0
  348. package/src/redis/probes/keys-count.test.ts +44 -0
  349. package/src/redis/probes/keys-count.ts +38 -0
  350. package/src/redis/probes/memory-usage.test.ts +54 -0
  351. package/src/redis/probes/memory-usage.ts +46 -0
  352. package/src/runbooks/nutanix.test.ts +1138 -0
  353. package/src/runbooks/nutanix.ts +941 -0
  354. package/src/runbooks/proxmox.test.ts +838 -0
  355. package/src/runbooks/proxmox.ts +626 -0
  356. package/src/signatures.ts +1 -0
  357. package/src/types.ts +62 -0
  358. package/src/validation.ts +21 -1
  359. package/tsconfig.tsbuildinfo +1 -0
@@ -0,0 +1,478 @@
1
+ import type { IntegrationConfig, IntegrationCredentials } from '@sonde/shared';
2
+ import { afterEach, describe, expect, it, vi } from 'vitest';
3
+ import { clearTokenCache, ensureGraphToken, graphFetch, graphPack } from './graph.js';
4
+
5
+ const graphConfig: IntegrationConfig = {
6
+ endpoint: 'https://graph.microsoft.com/v1.0',
7
+ };
8
+
9
+ const graphCreds: IntegrationCredentials = {
10
+ packName: 'graph',
11
+ authMethod: 'oauth2',
12
+ credentials: {
13
+ tenantId: 'tenant-123',
14
+ clientId: 'client-id',
15
+ clientSecret: 'client-secret',
16
+ },
17
+ };
18
+
19
+ const handler = (name: string) => {
20
+ const h = graphPack.handlers[name];
21
+ if (!h) throw new Error(`Handler ${name} not found`);
22
+ return h;
23
+ };
24
+
25
+ function callArgs(fn: ReturnType<typeof vi.fn>, index: number): unknown[] {
26
+ const args = fn.mock.calls[index];
27
+ if (!args) throw new Error(`No call at index ${index}`);
28
+ return args;
29
+ }
30
+
31
+ /** Mock fetch that returns a token response on first call, then Graph API responses */
32
+ function mockGraphFetch(graphValue: unknown[] = [], nextLink?: string) {
33
+ let callCount = 0;
34
+ return vi.fn().mockImplementation(() => {
35
+ callCount++;
36
+ if (callCount === 1) {
37
+ return Promise.resolve(
38
+ new Response(JSON.stringify({ access_token: 'graph-token-123', expires_in: 3600 }), {
39
+ status: 200,
40
+ headers: { 'Content-Type': 'application/json' },
41
+ }),
42
+ );
43
+ }
44
+ const body: Record<string, unknown> = { value: graphValue };
45
+ if (nextLink) body['@odata.nextLink'] = nextLink;
46
+ return Promise.resolve(
47
+ new Response(JSON.stringify(body), {
48
+ status: 200,
49
+ headers: { 'Content-Type': 'application/json' },
50
+ }),
51
+ );
52
+ });
53
+ }
54
+
55
+ /** Mock fetch returning paginated Graph responses (token first, then pages) */
56
+ function mockGraphPaginated(pages: unknown[][]) {
57
+ let callCount = 0;
58
+ return vi.fn().mockImplementation(() => {
59
+ callCount++;
60
+ if (callCount === 1) {
61
+ return Promise.resolve(
62
+ new Response(JSON.stringify({ access_token: 'graph-token-123', expires_in: 3600 }), {
63
+ status: 200,
64
+ headers: { 'Content-Type': 'application/json' },
65
+ }),
66
+ );
67
+ }
68
+ const pageIdx = callCount - 2;
69
+ const value = pages[pageIdx] ?? [];
70
+ const nextLink =
71
+ pageIdx < pages.length - 1
72
+ ? `https://graph.microsoft.com/v1.0/next?$skip=${(pageIdx + 1) * 100}`
73
+ : undefined;
74
+ const body: Record<string, unknown> = { value };
75
+ if (nextLink) body['@odata.nextLink'] = nextLink;
76
+ return Promise.resolve(
77
+ new Response(JSON.stringify(body), {
78
+ status: 200,
79
+ headers: { 'Content-Type': 'application/json' },
80
+ }),
81
+ );
82
+ });
83
+ }
84
+
85
+ function mockFetchError(status: number) {
86
+ return vi.fn().mockResolvedValue(new Response('Error', { status, statusText: 'Error' }));
87
+ }
88
+
89
+ /** Mock fetch: token first, then specific status for API call */
90
+ function mockGraphWithApiStatus(apiStatus: number) {
91
+ let callCount = 0;
92
+ return vi.fn().mockImplementation(() => {
93
+ callCount++;
94
+ if (callCount === 1) {
95
+ return Promise.resolve(
96
+ new Response(JSON.stringify({ access_token: 'graph-token-123', expires_in: 3600 }), {
97
+ status: 200,
98
+ headers: { 'Content-Type': 'application/json' },
99
+ }),
100
+ );
101
+ }
102
+ return Promise.resolve(new Response('Error', { status: apiStatus, statusText: 'Forbidden' }));
103
+ });
104
+ }
105
+
106
+ afterEach(() => {
107
+ clearTokenCache();
108
+ });
109
+
110
+ describe('graph pack', () => {
111
+ describe('token acquisition', () => {
112
+ it('acquires token via client_credentials grant', async () => {
113
+ const fetchFn = vi.fn().mockResolvedValue(
114
+ new Response(JSON.stringify({ access_token: 'tok-abc', expires_in: 3600 }), {
115
+ status: 200,
116
+ headers: { 'Content-Type': 'application/json' },
117
+ }),
118
+ );
119
+
120
+ const token = await ensureGraphToken(graphCreds, fetchFn);
121
+ expect(token).toBe('tok-abc');
122
+
123
+ const [url, init] = callArgs(fetchFn, 0);
124
+ expect(url).toContain('login.microsoftonline.com/tenant-123/oauth2/v2.0/token');
125
+ expect((init as { method: string }).method).toBe('POST');
126
+ const body = (init as { body: string }).body;
127
+ expect(body).toContain('grant_type=client_credentials');
128
+ expect(body).toContain('scope=https%3A%2F%2Fgraph.microsoft.com%2F.default');
129
+ expect(body).toContain('client_id=client-id');
130
+ });
131
+
132
+ it('caches token and reuses on subsequent calls', async () => {
133
+ const fetchFn = vi.fn().mockResolvedValue(
134
+ new Response(JSON.stringify({ access_token: 'tok-cached', expires_in: 3600 }), {
135
+ status: 200,
136
+ headers: { 'Content-Type': 'application/json' },
137
+ }),
138
+ );
139
+
140
+ const t1 = await ensureGraphToken(graphCreds, fetchFn);
141
+ const t2 = await ensureGraphToken(graphCreds, fetchFn);
142
+ expect(t1).toBe('tok-cached');
143
+ expect(t2).toBe('tok-cached');
144
+ expect(fetchFn).toHaveBeenCalledTimes(1);
145
+ });
146
+
147
+ it('throws on token request failure', async () => {
148
+ const fetchFn = mockFetchError(401);
149
+ await expect(ensureGraphToken(graphCreds, fetchFn)).rejects.toThrow(
150
+ 'Graph token request failed: 401',
151
+ );
152
+ });
153
+ });
154
+
155
+ describe('pagination', () => {
156
+ it('fetches a single page when no nextLink', async () => {
157
+ const fetchFn = mockGraphFetch([{ id: '1' }, { id: '2' }]);
158
+ const results = await graphFetch('/users', graphConfig, graphCreds, fetchFn);
159
+ expect(results).toEqual([{ id: '1' }, { id: '2' }]);
160
+ });
161
+
162
+ it('follows nextLink across multiple pages', async () => {
163
+ const fetchFn = mockGraphPaginated([[{ id: '1' }], [{ id: '2' }], [{ id: '3' }]]);
164
+ const results = await graphFetch('/users', graphConfig, graphCreds, fetchFn);
165
+ expect(results).toEqual([{ id: '1' }, { id: '2' }, { id: '3' }]);
166
+ });
167
+
168
+ it('caps at maxPages', async () => {
169
+ const fetchFn = mockGraphPaginated([[{ id: '1' }], [{ id: '2' }], [{ id: '3' }]]);
170
+ const results = await graphFetch('/users', graphConfig, graphCreds, fetchFn, undefined, 2);
171
+ expect(results).toEqual([{ id: '1' }, { id: '2' }]);
172
+ });
173
+ });
174
+
175
+ describe('testConnection', () => {
176
+ it('returns true on 200', async () => {
177
+ const fetchFn = mockGraphFetch([{ id: 'org-1' }]);
178
+ const result = await graphPack.testConnection(graphConfig, graphCreds, fetchFn);
179
+ expect(result).toBe(true);
180
+
181
+ const [url] = callArgs(fetchFn, 1);
182
+ expect(url).toContain('/organization');
183
+ expect(url).toContain('$select=id');
184
+ });
185
+
186
+ it('returns false on non-200', async () => {
187
+ const fetchFn = mockGraphWithApiStatus(403);
188
+ const result = await graphPack.testConnection(graphConfig, graphCreds, fetchFn);
189
+ expect(result).toBe(false);
190
+ });
191
+
192
+ it('returns false on network error', async () => {
193
+ const fetchFn = vi.fn().mockRejectedValue(new Error('ECONNREFUSED'));
194
+ const result = await graphPack.testConnection(graphConfig, graphCreds, fetchFn);
195
+ expect(result).toBe(false);
196
+ });
197
+ });
198
+
199
+ describe('user.lookup', () => {
200
+ it('searches users by query with correct filter', async () => {
201
+ const users = [
202
+ { id: 'u1', displayName: 'Alice', mail: 'alice@corp.com', accountEnabled: true },
203
+ ];
204
+ const fetchFn = mockGraphFetch(users);
205
+ const result = (await handler('user.lookup')(
206
+ { q: 'alice@corp.com' },
207
+ graphConfig,
208
+ graphCreds,
209
+ fetchFn,
210
+ )) as { users: unknown[]; count: number };
211
+
212
+ expect(result.count).toBe(1);
213
+ expect(result.users).toEqual(users);
214
+
215
+ const [url] = callArgs(fetchFn, 1);
216
+ expect(url).toContain('/users');
217
+ expect(url).toContain('alice%40corp.com');
218
+ });
219
+
220
+ it('throws when q is missing', async () => {
221
+ const fetchFn = mockGraphFetch([]);
222
+ await expect(handler('user.lookup')({}, graphConfig, graphCreds, fetchFn)).rejects.toThrow(
223
+ 'q parameter is required',
224
+ );
225
+ });
226
+ });
227
+
228
+ describe('user.groups', () => {
229
+ it('returns group memberships filtered to groups', async () => {
230
+ const memberOf = [
231
+ {
232
+ '@odata.type': '#microsoft.graph.group',
233
+ id: 'g1',
234
+ displayName: 'SG-Sonde-Users',
235
+ },
236
+ {
237
+ '@odata.type': '#microsoft.graph.directoryRole',
238
+ id: 'r1',
239
+ displayName: 'Global Admin',
240
+ },
241
+ ];
242
+ const fetchFn = mockGraphFetch(memberOf);
243
+ const result = (await handler('user.groups')(
244
+ { id: 'u1' },
245
+ graphConfig,
246
+ graphCreds,
247
+ fetchFn,
248
+ )) as { groups: Array<{ id: string; displayName: string }>; count: number };
249
+
250
+ expect(result.count).toBe(1);
251
+ expect(result.groups[0]?.displayName).toBe('SG-Sonde-Users');
252
+
253
+ const [url] = callArgs(fetchFn, 1);
254
+ expect(url).toContain('/users/u1/memberOf');
255
+ });
256
+
257
+ it('throws when id is missing', async () => {
258
+ const fetchFn = mockGraphFetch([]);
259
+ await expect(handler('user.groups')({}, graphConfig, graphCreds, fetchFn)).rejects.toThrow(
260
+ 'id parameter is required',
261
+ );
262
+ });
263
+ });
264
+
265
+ describe('signin.recent', () => {
266
+ it('fetches sign-in logs for a user', async () => {
267
+ const signIns = [
268
+ {
269
+ createdDateTime: '2026-01-01T12:00:00Z',
270
+ appDisplayName: 'Outlook',
271
+ ipAddress: '10.0.0.1',
272
+ },
273
+ ];
274
+ const fetchFn = mockGraphFetch(signIns);
275
+ const result = (await handler('signin.recent')(
276
+ { user: 'alice@corp.com', hours: 12 },
277
+ graphConfig,
278
+ graphCreds,
279
+ fetchFn,
280
+ )) as { signIns: unknown[]; count: number; periodHours: number };
281
+
282
+ expect(result.count).toBe(1);
283
+ expect(result.periodHours).toBe(12);
284
+
285
+ const [url] = callArgs(fetchFn, 1);
286
+ expect(url).toContain('/auditLogs/signIns');
287
+ expect(url).toContain('alice%40corp.com');
288
+ });
289
+
290
+ it('throws when user is missing', async () => {
291
+ const fetchFn = mockGraphFetch([]);
292
+ await expect(handler('signin.recent')({}, graphConfig, graphCreds, fetchFn)).rejects.toThrow(
293
+ 'user parameter is required',
294
+ );
295
+ });
296
+ });
297
+
298
+ describe('users.risky', () => {
299
+ it('fetches risky users at specified level', async () => {
300
+ const risky = [{ id: 'u1', userDisplayName: 'Bob', riskLevel: 'high', riskState: 'atRisk' }];
301
+ const fetchFn = mockGraphFetch(risky);
302
+ const result = (await handler('users.risky')(
303
+ { level: 'medium' },
304
+ graphConfig,
305
+ graphCreds,
306
+ fetchFn,
307
+ )) as { riskyUsers: unknown[]; count: number; riskLevel: string };
308
+
309
+ expect(result.count).toBe(1);
310
+ expect(result.riskLevel).toBe('medium');
311
+
312
+ const [url] = callArgs(fetchFn, 1);
313
+ expect(url).toContain('/identityProtection/riskyUsers');
314
+ expect(url).toContain('medium');
315
+ });
316
+
317
+ it('defaults to high risk level', async () => {
318
+ const fetchFn = mockGraphFetch([]);
319
+ const result = (await handler('users.risky')({}, graphConfig, graphCreds, fetchFn)) as {
320
+ riskLevel: string;
321
+ };
322
+
323
+ expect(result.riskLevel).toBe('high');
324
+ const [url] = callArgs(fetchFn, 1);
325
+ expect(url).toContain('high');
326
+ });
327
+ });
328
+
329
+ describe('intune.devices.compliance', () => {
330
+ it('fetches managed devices with optional user filter', async () => {
331
+ const devices = [
332
+ {
333
+ id: 'd1',
334
+ deviceName: 'LAPTOP-01',
335
+ complianceState: 'compliant',
336
+ userPrincipalName: 'alice@corp.com',
337
+ },
338
+ ];
339
+ const fetchFn = mockGraphFetch(devices);
340
+ const result = (await handler('intune.devices.compliance')(
341
+ { user: 'alice@corp.com' },
342
+ graphConfig,
343
+ graphCreds,
344
+ fetchFn,
345
+ )) as { devices: unknown[]; count: number };
346
+
347
+ expect(result.count).toBe(1);
348
+ const [url] = callArgs(fetchFn, 1);
349
+ expect(url).toContain('/deviceManagement/managedDevices');
350
+ expect(url).toContain('alice%40corp.com');
351
+ });
352
+
353
+ it('fetches all devices when no user filter', async () => {
354
+ const fetchFn = mockGraphFetch([]);
355
+ await handler('intune.devices.compliance')({}, graphConfig, graphCreds, fetchFn);
356
+ const [url] = callArgs(fetchFn, 1);
357
+ expect(url).toContain('/deviceManagement/managedDevices');
358
+ expect(url).not.toContain('%24filter');
359
+ });
360
+ });
361
+
362
+ describe('intune.devices.noncompliant', () => {
363
+ it('fetches only noncompliant devices', async () => {
364
+ const devices = [{ id: 'd2', deviceName: 'LAPTOP-02', complianceState: 'noncompliant' }];
365
+ const fetchFn = mockGraphFetch(devices);
366
+ const result = (await handler('intune.devices.noncompliant')(
367
+ {},
368
+ graphConfig,
369
+ graphCreds,
370
+ fetchFn,
371
+ )) as { devices: unknown[]; count: number };
372
+
373
+ expect(result.count).toBe(1);
374
+ const [url] = callArgs(fetchFn, 1);
375
+ expect(url).toContain('noncompliant');
376
+ });
377
+ });
378
+
379
+ describe('Intune 403 handling', () => {
380
+ it('throws friendly error on 403 for Intune endpoints', async () => {
381
+ const fetchFn = mockGraphWithApiStatus(403);
382
+ await expect(
383
+ handler('intune.devices.compliance')({}, graphConfig, graphCreds, fetchFn),
384
+ ).rejects.toThrow('Intune license or permissions required');
385
+ });
386
+ });
387
+
388
+ describe('intune.apps.status', () => {
389
+ it('fetches apps with install summaries', async () => {
390
+ // Call 1: token, Call 2: mobileApps list, Call 3: token (cached), Call 4: installSummary
391
+ let callCount = 0;
392
+ const fetchFn = vi.fn().mockImplementation((url: string) => {
393
+ callCount++;
394
+ if (callCount === 1) {
395
+ return Promise.resolve(
396
+ new Response(JSON.stringify({ access_token: 'graph-token-123', expires_in: 3600 }), {
397
+ status: 200,
398
+ headers: { 'Content-Type': 'application/json' },
399
+ }),
400
+ );
401
+ }
402
+ if (callCount === 2) {
403
+ return Promise.resolve(
404
+ new Response(
405
+ JSON.stringify({ value: [{ id: 'app1', displayName: 'Teams', publisher: 'MS' }] }),
406
+ { status: 200, headers: { 'Content-Type': 'application/json' } },
407
+ ),
408
+ );
409
+ }
410
+ // installSummary call
411
+ if (typeof url === 'string' && url.includes('installSummary')) {
412
+ return Promise.resolve(
413
+ new Response(JSON.stringify({ installedDeviceCount: 10, failedDeviceCount: 2 }), {
414
+ status: 200,
415
+ headers: { 'Content-Type': 'application/json' },
416
+ }),
417
+ );
418
+ }
419
+ return Promise.resolve(new Response('{}', { status: 200 }));
420
+ });
421
+
422
+ const result = (await handler('intune.apps.status')(
423
+ {},
424
+ graphConfig,
425
+ graphCreds,
426
+ fetchFn,
427
+ )) as { apps: Array<Record<string, unknown>>; count: number };
428
+
429
+ expect(result.count).toBe(1);
430
+ expect(result.apps[0]?.displayName).toBe('Teams');
431
+ expect(result.apps[0]?.installSummary).toEqual({
432
+ installedDeviceCount: 10,
433
+ failedDeviceCount: 2,
434
+ });
435
+ });
436
+ });
437
+
438
+ describe('manifest', () => {
439
+ it('has correct name and probe count', () => {
440
+ expect(graphPack.manifest.name).toBe('graph');
441
+ expect(graphPack.manifest.probes).toHaveLength(7);
442
+ });
443
+
444
+ it('all handlers match manifest probes', () => {
445
+ const probeNames = graphPack.manifest.probes.map((p) => p.name);
446
+ const handlerNames = Object.keys(graphPack.handlers);
447
+ expect(handlerNames.sort()).toEqual(probeNames.sort());
448
+ });
449
+
450
+ it('has correct timeouts (15s for user probes, 30s for sign-in/Intune)', () => {
451
+ const probeMap = new Map(graphPack.manifest.probes.map((p) => [p.name, p.timeout]));
452
+ expect(probeMap.get('user.lookup')).toBe(15000);
453
+ expect(probeMap.get('user.groups')).toBe(15000);
454
+ expect(probeMap.get('users.risky')).toBe(15000);
455
+ expect(probeMap.get('signin.recent')).toBe(30000);
456
+ expect(probeMap.get('intune.devices.compliance')).toBe(30000);
457
+ expect(probeMap.get('intune.devices.noncompliant')).toBe(30000);
458
+ expect(probeMap.get('intune.apps.status')).toBe(30000);
459
+ });
460
+
461
+ it('has identity runbook', () => {
462
+ expect(graphPack.manifest.runbook).toEqual({
463
+ category: 'identity',
464
+ probes: ['user.lookup', 'users.risky', 'intune.devices.noncompliant'],
465
+ parallel: true,
466
+ });
467
+ });
468
+ });
469
+
470
+ describe('error handling', () => {
471
+ it('throws on non-200 API response', async () => {
472
+ const fetchFn = mockGraphWithApiStatus(500);
473
+ await expect(
474
+ handler('user.lookup')({ q: 'test' }, graphConfig, graphCreds, fetchFn),
475
+ ).rejects.toThrow('Graph API returned 500');
476
+ });
477
+ });
478
+ });