@lhremote/core 0.8.0 → 0.10.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (480) hide show
  1. package/dist/cdp/app-discovery.d.ts +57 -0
  2. package/dist/cdp/app-discovery.d.ts.map +1 -1
  3. package/dist/cdp/app-discovery.js +90 -7
  4. package/dist/cdp/app-discovery.js.map +1 -1
  5. package/dist/cdp/app-discovery.test.js +180 -9
  6. package/dist/cdp/app-discovery.test.js.map +1 -1
  7. package/dist/cdp/client.d.ts +8 -1
  8. package/dist/cdp/client.d.ts.map +1 -1
  9. package/dist/cdp/client.js +8 -1
  10. package/dist/cdp/client.js.map +1 -1
  11. package/dist/cdp/discovery.d.ts.map +1 -1
  12. package/dist/cdp/discovery.js +5 -1
  13. package/dist/cdp/discovery.js.map +1 -1
  14. package/dist/cdp/discovery.test.js +7 -0
  15. package/dist/cdp/discovery.test.js.map +1 -1
  16. package/dist/cdp/index.d.ts +1 -1
  17. package/dist/cdp/index.d.ts.map +1 -1
  18. package/dist/cdp/index.js +1 -1
  19. package/dist/cdp/index.js.map +1 -1
  20. package/dist/cdp/instance-discovery.d.ts.map +1 -1
  21. package/dist/cdp/instance-discovery.js +25 -10
  22. package/dist/cdp/instance-discovery.js.map +1 -1
  23. package/dist/cdp/instance-discovery.test.js +17 -0
  24. package/dist/cdp/instance-discovery.test.js.map +1 -1
  25. package/dist/cdp/testing/launch-chromium.d.ts +1 -1
  26. package/dist/cdp/testing/launch-chromium.js +2 -2
  27. package/dist/db/client.d.ts.map +1 -1
  28. package/dist/db/client.js +3 -0
  29. package/dist/db/client.js.map +1 -1
  30. package/dist/db/repositories/campaign-hard-delete.integration.test.js +4 -1
  31. package/dist/db/repositories/campaign-hard-delete.integration.test.js.map +1 -1
  32. package/dist/db/repositories/campaign.d.ts.map +1 -1
  33. package/dist/db/repositories/campaign.js +81 -33
  34. package/dist/db/repositories/campaign.js.map +1 -1
  35. package/dist/db/repositories/campaign.test.js +2 -2
  36. package/dist/db/repositories/collection-list.d.ts +11 -0
  37. package/dist/db/repositories/collection-list.d.ts.map +1 -1
  38. package/dist/db/repositories/collection-list.integration.test.js +6 -4
  39. package/dist/db/repositories/collection-list.integration.test.js.map +1 -1
  40. package/dist/db/repositories/collection-list.js +92 -2
  41. package/dist/db/repositories/collection-list.js.map +1 -1
  42. package/dist/db/testing/create-fixture.js +36 -2
  43. package/dist/db/testing/create-fixture.js.map +1 -1
  44. package/dist/index.d.ts +6 -6
  45. package/dist/index.d.ts.map +1 -1
  46. package/dist/index.js +6 -6
  47. package/dist/index.js.map +1 -1
  48. package/dist/linkedin/dom-automation-retry.test.d.ts +2 -0
  49. package/dist/linkedin/dom-automation-retry.test.d.ts.map +1 -0
  50. package/dist/linkedin/dom-automation-retry.test.js +51 -0
  51. package/dist/linkedin/dom-automation-retry.test.js.map +1 -0
  52. package/dist/linkedin/dom-automation.d.ts +166 -6
  53. package/dist/linkedin/dom-automation.d.ts.map +1 -1
  54. package/dist/linkedin/dom-automation.js +496 -21
  55. package/dist/linkedin/dom-automation.js.map +1 -1
  56. package/dist/linkedin/humanized-mouse.d.ts +69 -0
  57. package/dist/linkedin/humanized-mouse.d.ts.map +1 -0
  58. package/dist/linkedin/humanized-mouse.js +109 -0
  59. package/dist/linkedin/humanized-mouse.js.map +1 -0
  60. package/dist/linkedin/index.d.ts +3 -2
  61. package/dist/linkedin/index.d.ts.map +1 -1
  62. package/dist/linkedin/index.js +3 -2
  63. package/dist/linkedin/index.js.map +1 -1
  64. package/dist/linkedin/selectors.d.ts +74 -48
  65. package/dist/linkedin/selectors.d.ts.map +1 -1
  66. package/dist/linkedin/selectors.js +64 -41
  67. package/dist/linkedin/selectors.js.map +1 -1
  68. package/dist/operations/add-people-to-collection.d.ts +1 -1
  69. package/dist/operations/add-people-to-collection.d.ts.map +1 -1
  70. package/dist/operations/add-people-to-collection.js +3 -6
  71. package/dist/operations/add-people-to-collection.js.map +1 -1
  72. package/dist/operations/build-linkedin-url.test.d.ts +2 -0
  73. package/dist/operations/build-linkedin-url.test.d.ts.map +1 -0
  74. package/dist/operations/build-linkedin-url.test.js +158 -0
  75. package/dist/operations/build-linkedin-url.test.js.map +1 -0
  76. package/dist/operations/campaign-add-action.d.ts +1 -1
  77. package/dist/operations/campaign-add-action.d.ts.map +1 -1
  78. package/dist/operations/campaign-add-action.js +3 -6
  79. package/dist/operations/campaign-add-action.js.map +1 -1
  80. package/dist/operations/campaign-create.d.ts +1 -1
  81. package/dist/operations/campaign-create.d.ts.map +1 -1
  82. package/dist/operations/campaign-create.js +3 -6
  83. package/dist/operations/campaign-create.js.map +1 -1
  84. package/dist/operations/campaign-delete.d.ts +1 -1
  85. package/dist/operations/campaign-delete.d.ts.map +1 -1
  86. package/dist/operations/campaign-delete.js +3 -6
  87. package/dist/operations/campaign-delete.js.map +1 -1
  88. package/dist/operations/campaign-erase.d.ts +1 -1
  89. package/dist/operations/campaign-erase.d.ts.map +1 -1
  90. package/dist/operations/campaign-erase.js +3 -6
  91. package/dist/operations/campaign-erase.js.map +1 -1
  92. package/dist/operations/campaign-exclude-add.d.ts +1 -1
  93. package/dist/operations/campaign-exclude-add.d.ts.map +1 -1
  94. package/dist/operations/campaign-exclude-add.js +3 -6
  95. package/dist/operations/campaign-exclude-add.js.map +1 -1
  96. package/dist/operations/campaign-exclude-list.d.ts +1 -1
  97. package/dist/operations/campaign-exclude-list.d.ts.map +1 -1
  98. package/dist/operations/campaign-exclude-list.js +3 -6
  99. package/dist/operations/campaign-exclude-list.js.map +1 -1
  100. package/dist/operations/campaign-exclude-remove.d.ts +1 -1
  101. package/dist/operations/campaign-exclude-remove.d.ts.map +1 -1
  102. package/dist/operations/campaign-exclude-remove.js +3 -6
  103. package/dist/operations/campaign-exclude-remove.js.map +1 -1
  104. package/dist/operations/campaign-export.d.ts +1 -1
  105. package/dist/operations/campaign-export.d.ts.map +1 -1
  106. package/dist/operations/campaign-export.js +3 -6
  107. package/dist/operations/campaign-export.js.map +1 -1
  108. package/dist/operations/campaign-get.d.ts +1 -1
  109. package/dist/operations/campaign-get.d.ts.map +1 -1
  110. package/dist/operations/campaign-get.js +3 -6
  111. package/dist/operations/campaign-get.js.map +1 -1
  112. package/dist/operations/campaign-list-people.d.ts +1 -1
  113. package/dist/operations/campaign-list-people.d.ts.map +1 -1
  114. package/dist/operations/campaign-list-people.js +3 -6
  115. package/dist/operations/campaign-list-people.js.map +1 -1
  116. package/dist/operations/campaign-list.d.ts +1 -1
  117. package/dist/operations/campaign-list.d.ts.map +1 -1
  118. package/dist/operations/campaign-list.js +3 -6
  119. package/dist/operations/campaign-list.js.map +1 -1
  120. package/dist/operations/campaign-move-next.d.ts +1 -1
  121. package/dist/operations/campaign-move-next.d.ts.map +1 -1
  122. package/dist/operations/campaign-move-next.js +3 -6
  123. package/dist/operations/campaign-move-next.js.map +1 -1
  124. package/dist/operations/campaign-remove-action.d.ts +1 -1
  125. package/dist/operations/campaign-remove-action.d.ts.map +1 -1
  126. package/dist/operations/campaign-remove-action.js +3 -6
  127. package/dist/operations/campaign-remove-action.js.map +1 -1
  128. package/dist/operations/campaign-remove-people.d.ts +1 -1
  129. package/dist/operations/campaign-remove-people.d.ts.map +1 -1
  130. package/dist/operations/campaign-remove-people.js +3 -6
  131. package/dist/operations/campaign-remove-people.js.map +1 -1
  132. package/dist/operations/campaign-reorder-actions.d.ts +1 -1
  133. package/dist/operations/campaign-reorder-actions.d.ts.map +1 -1
  134. package/dist/operations/campaign-reorder-actions.js +3 -6
  135. package/dist/operations/campaign-reorder-actions.js.map +1 -1
  136. package/dist/operations/campaign-retry.d.ts +1 -1
  137. package/dist/operations/campaign-retry.d.ts.map +1 -1
  138. package/dist/operations/campaign-retry.js +3 -6
  139. package/dist/operations/campaign-retry.js.map +1 -1
  140. package/dist/operations/campaign-start.d.ts +1 -1
  141. package/dist/operations/campaign-start.d.ts.map +1 -1
  142. package/dist/operations/campaign-start.js +3 -6
  143. package/dist/operations/campaign-start.js.map +1 -1
  144. package/dist/operations/campaign-statistics.d.ts +1 -1
  145. package/dist/operations/campaign-statistics.d.ts.map +1 -1
  146. package/dist/operations/campaign-statistics.js +3 -6
  147. package/dist/operations/campaign-statistics.js.map +1 -1
  148. package/dist/operations/campaign-status.d.ts +1 -1
  149. package/dist/operations/campaign-status.d.ts.map +1 -1
  150. package/dist/operations/campaign-status.js +3 -6
  151. package/dist/operations/campaign-status.js.map +1 -1
  152. package/dist/operations/campaign-stop.d.ts +1 -1
  153. package/dist/operations/campaign-stop.d.ts.map +1 -1
  154. package/dist/operations/campaign-stop.js +3 -6
  155. package/dist/operations/campaign-stop.js.map +1 -1
  156. package/dist/operations/campaign-update-action.d.ts +1 -1
  157. package/dist/operations/campaign-update-action.d.ts.map +1 -1
  158. package/dist/operations/campaign-update-action.js +3 -6
  159. package/dist/operations/campaign-update-action.js.map +1 -1
  160. package/dist/operations/campaign-update.d.ts +1 -1
  161. package/dist/operations/campaign-update.d.ts.map +1 -1
  162. package/dist/operations/campaign-update.js +3 -6
  163. package/dist/operations/campaign-update.js.map +1 -1
  164. package/dist/operations/check-replies.d.ts +3 -1
  165. package/dist/operations/check-replies.d.ts.map +1 -1
  166. package/dist/operations/check-replies.js +124 -17
  167. package/dist/operations/check-replies.js.map +1 -1
  168. package/dist/operations/check-replies.test.js +152 -17
  169. package/dist/operations/check-replies.test.js.map +1 -1
  170. package/dist/operations/collect-people.d.ts +1 -1
  171. package/dist/operations/collect-people.d.ts.map +1 -1
  172. package/dist/operations/collect-people.js +18 -12
  173. package/dist/operations/collect-people.js.map +1 -1
  174. package/dist/operations/collect-people.test.js +21 -5
  175. package/dist/operations/collect-people.test.js.map +1 -1
  176. package/dist/operations/comment-on-post.d.ts +4 -1
  177. package/dist/operations/comment-on-post.d.ts.map +1 -1
  178. package/dist/operations/comment-on-post.js +15 -19
  179. package/dist/operations/comment-on-post.js.map +1 -1
  180. package/dist/operations/comment-on-post.test.js +8 -6
  181. package/dist/operations/comment-on-post.test.js.map +1 -1
  182. package/dist/operations/create-collection.d.ts +1 -1
  183. package/dist/operations/create-collection.d.ts.map +1 -1
  184. package/dist/operations/create-collection.js +5 -7
  185. package/dist/operations/create-collection.js.map +1 -1
  186. package/dist/operations/create-collection.test.js +3 -1
  187. package/dist/operations/create-collection.test.js.map +1 -1
  188. package/dist/operations/delete-collection.d.ts +1 -1
  189. package/dist/operations/delete-collection.d.ts.map +1 -1
  190. package/dist/operations/delete-collection.js +3 -6
  191. package/dist/operations/delete-collection.js.map +1 -1
  192. package/dist/operations/dismiss-errors.d.ts +11 -5
  193. package/dist/operations/dismiss-errors.d.ts.map +1 -1
  194. package/dist/operations/dismiss-errors.js +68 -34
  195. package/dist/operations/dismiss-errors.js.map +1 -1
  196. package/dist/operations/dismiss-errors.test.js +129 -8
  197. package/dist/operations/dismiss-errors.test.js.map +1 -1
  198. package/dist/operations/endorse-skills.test.d.ts +2 -0
  199. package/dist/operations/endorse-skills.test.d.ts.map +1 -0
  200. package/dist/operations/endorse-skills.test.js +70 -0
  201. package/dist/operations/endorse-skills.test.js.map +1 -0
  202. package/dist/operations/enrich-profile.test.d.ts +2 -0
  203. package/dist/operations/enrich-profile.test.d.ts.map +1 -0
  204. package/dist/operations/enrich-profile.test.js +73 -0
  205. package/dist/operations/enrich-profile.test.js.map +1 -0
  206. package/dist/operations/ephemeral-action.d.ts +2 -1
  207. package/dist/operations/ephemeral-action.d.ts.map +1 -1
  208. package/dist/operations/ephemeral-action.js +5 -7
  209. package/dist/operations/ephemeral-action.js.map +1 -1
  210. package/dist/operations/ephemeral-action.test.d.ts +2 -0
  211. package/dist/operations/ephemeral-action.test.d.ts.map +1 -0
  212. package/dist/operations/ephemeral-action.test.js +159 -0
  213. package/dist/operations/ephemeral-action.test.js.map +1 -0
  214. package/dist/operations/follow-person.test.d.ts +2 -0
  215. package/dist/operations/follow-person.test.d.ts.map +1 -0
  216. package/dist/operations/follow-person.test.js +57 -0
  217. package/dist/operations/follow-person.test.js.map +1 -0
  218. package/dist/operations/get-action-budget.d.ts +1 -1
  219. package/dist/operations/get-action-budget.d.ts.map +1 -1
  220. package/dist/operations/get-action-budget.js +3 -6
  221. package/dist/operations/get-action-budget.js.map +1 -1
  222. package/dist/operations/get-errors.d.ts +5 -1
  223. package/dist/operations/get-errors.d.ts.map +1 -1
  224. package/dist/operations/get-errors.js +55 -33
  225. package/dist/operations/get-errors.js.map +1 -1
  226. package/dist/operations/get-errors.test.js +54 -55
  227. package/dist/operations/get-errors.test.js.map +1 -1
  228. package/dist/operations/get-feed.d.ts +83 -4
  229. package/dist/operations/get-feed.d.ts.map +1 -1
  230. package/dist/operations/get-feed.js +400 -153
  231. package/dist/operations/get-feed.js.map +1 -1
  232. package/dist/operations/get-feed.test.js +416 -190
  233. package/dist/operations/get-feed.test.js.map +1 -1
  234. package/dist/operations/get-post-engagers.d.ts +6 -3
  235. package/dist/operations/get-post-engagers.d.ts.map +1 -1
  236. package/dist/operations/get-post-engagers.js +278 -78
  237. package/dist/operations/get-post-engagers.js.map +1 -1
  238. package/dist/operations/get-post-engagers.test.js +292 -14
  239. package/dist/operations/get-post-engagers.test.js.map +1 -1
  240. package/dist/operations/get-post-stats.d.ts +8 -3
  241. package/dist/operations/get-post-stats.d.ts.map +1 -1
  242. package/dist/operations/get-post-stats.js +101 -37
  243. package/dist/operations/get-post-stats.js.map +1 -1
  244. package/dist/operations/get-post-stats.test.js +137 -2
  245. package/dist/operations/get-post-stats.test.js.map +1 -1
  246. package/dist/operations/get-post.d.ts +9 -150
  247. package/dist/operations/get-post.d.ts.map +1 -1
  248. package/dist/operations/get-post.js +356 -210
  249. package/dist/operations/get-post.js.map +1 -1
  250. package/dist/operations/get-post.test.js +210 -387
  251. package/dist/operations/get-post.test.js.map +1 -1
  252. package/dist/operations/get-profile-activity.d.ts +13 -92
  253. package/dist/operations/get-profile-activity.d.ts.map +1 -1
  254. package/dist/operations/get-profile-activity.js +305 -105
  255. package/dist/operations/get-profile-activity.js.map +1 -1
  256. package/dist/operations/get-profile-activity.test.js +277 -158
  257. package/dist/operations/get-profile-activity.test.js.map +1 -1
  258. package/dist/operations/get-throttle-status.d.ts +1 -1
  259. package/dist/operations/get-throttle-status.d.ts.map +1 -1
  260. package/dist/operations/get-throttle-status.js +4 -10
  261. package/dist/operations/get-throttle-status.js.map +1 -1
  262. package/dist/operations/import-people-from-collection.d.ts +1 -1
  263. package/dist/operations/import-people-from-collection.d.ts.map +1 -1
  264. package/dist/operations/import-people-from-collection.js +3 -6
  265. package/dist/operations/import-people-from-collection.js.map +1 -1
  266. package/dist/operations/import-people-from-urls.d.ts +1 -1
  267. package/dist/operations/import-people-from-urls.d.ts.map +1 -1
  268. package/dist/operations/import-people-from-urls.js +3 -6
  269. package/dist/operations/import-people-from-urls.js.map +1 -1
  270. package/dist/operations/index.d.ts +2 -2
  271. package/dist/operations/index.d.ts.map +1 -1
  272. package/dist/operations/index.js +2 -1
  273. package/dist/operations/index.js.map +1 -1
  274. package/dist/operations/like-person-posts.test.d.ts +2 -0
  275. package/dist/operations/like-person-posts.test.d.ts.map +1 -0
  276. package/dist/operations/like-person-posts.test.js +103 -0
  277. package/dist/operations/like-person-posts.test.js.map +1 -0
  278. package/dist/operations/list-collections.d.ts +1 -1
  279. package/dist/operations/list-collections.d.ts.map +1 -1
  280. package/dist/operations/list-collections.js +3 -6
  281. package/dist/operations/list-collections.js.map +1 -1
  282. package/dist/operations/message-person.test.d.ts +2 -0
  283. package/dist/operations/message-person.test.d.ts.map +1 -0
  284. package/dist/operations/message-person.test.js +108 -0
  285. package/dist/operations/message-person.test.js.map +1 -0
  286. package/dist/operations/navigate-away.d.ts +14 -0
  287. package/dist/operations/navigate-away.d.ts.map +1 -0
  288. package/dist/operations/navigate-away.js +24 -0
  289. package/dist/operations/navigate-away.js.map +1 -0
  290. package/dist/operations/navigate-away.test.d.ts +2 -0
  291. package/dist/operations/navigate-away.test.d.ts.map +1 -0
  292. package/dist/operations/navigate-away.test.js +51 -0
  293. package/dist/operations/navigate-away.test.js.map +1 -0
  294. package/dist/operations/query-messages.d.ts +1 -1
  295. package/dist/operations/query-messages.d.ts.map +1 -1
  296. package/dist/operations/query-messages.js +3 -6
  297. package/dist/operations/query-messages.js.map +1 -1
  298. package/dist/operations/react-to-post.d.ts +16 -4
  299. package/dist/operations/react-to-post.d.ts.map +1 -1
  300. package/dist/operations/react-to-post.js +86 -24
  301. package/dist/operations/react-to-post.js.map +1 -1
  302. package/dist/operations/react-to-post.test.js +55 -5
  303. package/dist/operations/react-to-post.test.js.map +1 -1
  304. package/dist/operations/remove-connection.test.d.ts +2 -0
  305. package/dist/operations/remove-connection.test.d.ts.map +1 -0
  306. package/dist/operations/remove-connection.test.js +45 -0
  307. package/dist/operations/remove-connection.test.js.map +1 -0
  308. package/dist/operations/remove-people-from-collection.d.ts +1 -1
  309. package/dist/operations/remove-people-from-collection.d.ts.map +1 -1
  310. package/dist/operations/remove-people-from-collection.js +3 -6
  311. package/dist/operations/remove-people-from-collection.js.map +1 -1
  312. package/dist/operations/resolve-linkedin-entity.d.ts.map +1 -1
  313. package/dist/operations/resolve-linkedin-entity.js +2 -2
  314. package/dist/operations/resolve-linkedin-entity.js.map +1 -1
  315. package/dist/operations/resolve-linkedin-entity.test.d.ts +2 -0
  316. package/dist/operations/resolve-linkedin-entity.test.d.ts.map +1 -0
  317. package/dist/operations/resolve-linkedin-entity.test.js +343 -0
  318. package/dist/operations/resolve-linkedin-entity.test.js.map +1 -0
  319. package/dist/operations/scrape-messaging-history.d.ts +2 -1
  320. package/dist/operations/scrape-messaging-history.d.ts.map +1 -1
  321. package/dist/operations/scrape-messaging-history.js +113 -18
  322. package/dist/operations/scrape-messaging-history.js.map +1 -1
  323. package/dist/operations/scrape-messaging-history.test.js +109 -12
  324. package/dist/operations/scrape-messaging-history.test.js.map +1 -1
  325. package/dist/operations/search-posts.d.ts +20 -112
  326. package/dist/operations/search-posts.d.ts.map +1 -1
  327. package/dist/operations/search-posts.js +369 -170
  328. package/dist/operations/search-posts.js.map +1 -1
  329. package/dist/operations/search-posts.test.js +273 -234
  330. package/dist/operations/search-posts.test.js.map +1 -1
  331. package/dist/operations/send-inmail.test.d.ts +2 -0
  332. package/dist/operations/send-inmail.test.d.ts.map +1 -0
  333. package/dist/operations/send-inmail.test.js +108 -0
  334. package/dist/operations/send-inmail.test.js.map +1 -0
  335. package/dist/operations/send-invite.test.d.ts +2 -0
  336. package/dist/operations/send-invite.test.d.ts.map +1 -0
  337. package/dist/operations/send-invite.test.js +59 -0
  338. package/dist/operations/send-invite.test.js.map +1 -0
  339. package/dist/operations/types.d.ts +27 -1
  340. package/dist/operations/types.d.ts.map +1 -1
  341. package/dist/operations/types.js +14 -1
  342. package/dist/operations/types.js.map +1 -1
  343. package/dist/operations/visit-profile.d.ts +1 -1
  344. package/dist/operations/visit-profile.d.ts.map +1 -1
  345. package/dist/operations/visit-profile.js +3 -6
  346. package/dist/operations/visit-profile.js.map +1 -1
  347. package/dist/services/account-resolution.d.ts +10 -4
  348. package/dist/services/account-resolution.d.ts.map +1 -1
  349. package/dist/services/account-resolution.js +63 -5
  350. package/dist/services/account-resolution.js.map +1 -1
  351. package/dist/services/app.d.ts +6 -2
  352. package/dist/services/app.d.ts.map +1 -1
  353. package/dist/services/app.js +18 -6
  354. package/dist/services/app.js.map +1 -1
  355. package/dist/services/app.test.js +41 -7
  356. package/dist/services/app.test.js.map +1 -1
  357. package/dist/services/campaign.d.ts +40 -4
  358. package/dist/services/campaign.d.ts.map +1 -1
  359. package/dist/services/campaign.js +176 -10
  360. package/dist/services/campaign.js.map +1 -1
  361. package/dist/services/campaign.test.js +53 -15
  362. package/dist/services/campaign.test.js.map +1 -1
  363. package/dist/services/collection.d.ts +16 -21
  364. package/dist/services/collection.d.ts.map +1 -1
  365. package/dist/services/collection.js +34 -47
  366. package/dist/services/collection.js.map +1 -1
  367. package/dist/services/collection.test.js +30 -91
  368. package/dist/services/collection.test.js.map +1 -1
  369. package/dist/services/ephemeral-campaign.d.ts +6 -0
  370. package/dist/services/ephemeral-campaign.d.ts.map +1 -1
  371. package/dist/services/ephemeral-campaign.js +54 -10
  372. package/dist/services/ephemeral-campaign.js.map +1 -1
  373. package/dist/services/ephemeral-campaign.test.js +23 -10
  374. package/dist/services/ephemeral-campaign.test.js.map +1 -1
  375. package/dist/services/errors.d.ts +2 -1
  376. package/dist/services/errors.d.ts.map +1 -1
  377. package/dist/services/errors.js +6 -3
  378. package/dist/services/errors.js.map +1 -1
  379. package/dist/services/index.d.ts +1 -2
  380. package/dist/services/index.d.ts.map +1 -1
  381. package/dist/services/index.js +1 -2
  382. package/dist/services/index.js.map +1 -1
  383. package/dist/services/instance-context.d.ts +5 -1
  384. package/dist/services/instance-context.d.ts.map +1 -1
  385. package/dist/services/instance-context.js +87 -28
  386. package/dist/services/instance-context.js.map +1 -1
  387. package/dist/services/instance-context.test.js +5 -1
  388. package/dist/services/instance-context.test.js.map +1 -1
  389. package/dist/services/instance-lifecycle.d.ts.map +1 -1
  390. package/dist/services/instance-lifecycle.js +32 -1
  391. package/dist/services/instance-lifecycle.js.map +1 -1
  392. package/dist/services/instance-lifecycle.test.js +52 -1
  393. package/dist/services/instance-lifecycle.test.js.map +1 -1
  394. package/dist/services/instance.d.ts +37 -9
  395. package/dist/services/instance.d.ts.map +1 -1
  396. package/dist/services/instance.js +100 -25
  397. package/dist/services/instance.js.map +1 -1
  398. package/dist/services/instance.test.js +157 -0
  399. package/dist/services/instance.test.js.map +1 -1
  400. package/dist/services/launcher.d.ts +47 -3
  401. package/dist/services/launcher.d.ts.map +1 -1
  402. package/dist/services/launcher.js +205 -33
  403. package/dist/services/launcher.js.map +1 -1
  404. package/dist/services/launcher.test.js +133 -6
  405. package/dist/services/launcher.test.js.map +1 -1
  406. package/dist/services/source-type-registry.d.ts +8 -0
  407. package/dist/services/source-type-registry.d.ts.map +1 -1
  408. package/dist/services/source-type-registry.js +39 -0
  409. package/dist/services/source-type-registry.js.map +1 -1
  410. package/dist/services/source-type-registry.test.js +31 -1
  411. package/dist/services/source-type-registry.test.js.map +1 -1
  412. package/dist/services/status.d.ts +6 -2
  413. package/dist/services/status.d.ts.map +1 -1
  414. package/dist/services/status.js +67 -34
  415. package/dist/services/status.js.map +1 -1
  416. package/dist/services/status.test.js +9 -2
  417. package/dist/services/status.test.js.map +1 -1
  418. package/dist/testing/e2e-helpers.d.ts +47 -1
  419. package/dist/testing/e2e-helpers.d.ts.map +1 -1
  420. package/dist/testing/e2e-helpers.js +244 -7
  421. package/dist/testing/e2e-helpers.js.map +1 -1
  422. package/dist/testing/index.d.ts +1 -1
  423. package/dist/testing/index.d.ts.map +1 -1
  424. package/dist/testing/index.js +1 -1
  425. package/dist/testing/index.js.map +1 -1
  426. package/dist/types/account.d.ts +1 -1
  427. package/dist/types/campaign.d.ts +1 -1
  428. package/dist/types/campaign.d.ts.map +1 -1
  429. package/dist/types/feed.d.ts +1 -3
  430. package/dist/types/feed.d.ts.map +1 -1
  431. package/dist/types/index.d.ts +0 -1
  432. package/dist/types/index.d.ts.map +1 -1
  433. package/dist/utils/cdp-port.d.ts.map +1 -1
  434. package/dist/utils/cdp-port.js +3 -1
  435. package/dist/utils/cdp-port.js.map +1 -1
  436. package/dist/utils/cdp-port.test.js +1 -1
  437. package/dist/utils/cdp-port.test.js.map +1 -1
  438. package/dist/utils/delay.d.ts +79 -0
  439. package/dist/utils/delay.d.ts.map +1 -1
  440. package/dist/utils/delay.js +118 -0
  441. package/dist/utils/delay.js.map +1 -1
  442. package/dist/utils/delay.test.js +111 -1
  443. package/dist/utils/delay.test.js.map +1 -1
  444. package/dist/utils/index.d.ts +2 -1
  445. package/dist/utils/index.d.ts.map +1 -1
  446. package/dist/utils/index.js +2 -1
  447. package/dist/utils/index.js.map +1 -1
  448. package/dist/utils/session-pacer.d.ts +27 -0
  449. package/dist/utils/session-pacer.d.ts.map +1 -0
  450. package/dist/utils/session-pacer.js +55 -0
  451. package/dist/utils/session-pacer.js.map +1 -0
  452. package/dist/utils/session-pacer.test.d.ts +2 -0
  453. package/dist/utils/session-pacer.test.d.ts.map +1 -0
  454. package/dist/utils/session-pacer.test.js +111 -0
  455. package/dist/utils/session-pacer.test.js.map +1 -0
  456. package/package.json +1 -1
  457. package/dist/linkedin/__tests__/selectors.integration.test.d.ts +0 -2
  458. package/dist/linkedin/__tests__/selectors.integration.test.d.ts.map +0 -1
  459. package/dist/linkedin/__tests__/selectors.integration.test.js +0 -258
  460. package/dist/linkedin/__tests__/selectors.integration.test.js.map +0 -1
  461. package/dist/types/search-posts.d.ts +0 -22
  462. package/dist/types/search-posts.d.ts.map +0 -1
  463. package/dist/types/search-posts.js +0 -4
  464. package/dist/types/search-posts.js.map +0 -1
  465. package/dist/voyager/index.d.ts +0 -2
  466. package/dist/voyager/index.d.ts.map +0 -1
  467. package/dist/voyager/index.js +0 -4
  468. package/dist/voyager/index.js.map +0 -1
  469. package/dist/voyager/interceptor.d.ts +0 -100
  470. package/dist/voyager/interceptor.d.ts.map +0 -1
  471. package/dist/voyager/interceptor.integration.test.d.ts +0 -2
  472. package/dist/voyager/interceptor.integration.test.d.ts.map +0 -1
  473. package/dist/voyager/interceptor.integration.test.js +0 -89
  474. package/dist/voyager/interceptor.integration.test.js.map +0 -1
  475. package/dist/voyager/interceptor.js +0 -235
  476. package/dist/voyager/interceptor.js.map +0 -1
  477. package/dist/voyager/interceptor.test.d.ts +0 -2
  478. package/dist/voyager/interceptor.test.d.ts.map +0 -1
  479. package/dist/voyager/interceptor.test.js +0 -372
  480. package/dist/voyager/interceptor.test.js.map +0 -1
@@ -1,201 +1,311 @@
1
1
  // SPDX-License-Identifier: AGPL-3.0-only
2
2
  // Copyright (C) 2026 Oleksii PELYKH
3
+ import { resolveInstancePort } from "../cdp/index.js";
3
4
  import { CDPClient } from "../cdp/client.js";
4
5
  import { discoverTargets } from "../cdp/discovery.js";
5
- import { VoyagerInterceptor } from "../voyager/interceptor.js";
6
- import { DEFAULT_CDP_PORT } from "../constants.js";
7
- import { extractPostUrn } from "./get-post-stats.js";
6
+ import { gaussianDelay } from "../utils/delay.js";
7
+ import { extractPostUrn, resolvePostDetailUrl } from "./get-post-stats.js";
8
+ import { delay, parseTimestamp } from "./get-feed.js";
9
+ import { navigateAwayIf } from "./navigate-away.js";
8
10
  // ---------------------------------------------------------------------------
9
- // Parsing helpers
11
+ // In-page DOM scraping scripts
10
12
  // ---------------------------------------------------------------------------
11
13
  /**
12
- * Resolve a text value that may be a string or an object with a `text` field.
13
- */
14
- export function resolveTextValue(value) {
15
- if (value === undefined || value === null)
16
- return "";
17
- if (typeof value === "string")
18
- return value;
19
- return value.text ?? "";
20
- }
21
- /**
22
- * Extract public identifier from a LinkedIn navigation URL.
14
+ * JavaScript source evaluated inside the LinkedIn post detail page to
15
+ * extract post metadata from the rendered DOM.
16
+ *
17
+ * The post detail page (`/feed/update/{urn}/`) renders a single post
18
+ * using the same SSR feed structure as the home feed. The script looks
19
+ * for `[data-testid="mainFeed"]` → `div[role="listitem"]` first, then
20
+ * falls back to the full document.
23
21
  */
24
- function extractPublicId(url) {
25
- if (!url)
26
- return null;
27
- const match = /linkedin\.com\/in\/([^/?]+)/.exec(url);
28
- return match?.[1] ?? null;
29
- }
22
+ const SCRAPE_POST_DETAIL_SCRIPT = `(() => {
23
+ let authorName = null;
24
+ let authorHeadline = null;
25
+ let authorProfileUrl = null;
26
+ let text = null;
27
+ let reactionCount = 0;
28
+ let commentCount = 0;
29
+ let shareCount = 0;
30
+ let timestamp = null;
31
+
32
+ // Narrow scope: try mainFeed listitem, then <main>, then document
33
+ let scope = document.querySelector('main') || document;
34
+ const feedList = document.querySelector('[data-testid="mainFeed"]');
35
+ if (feedList) {
36
+ const items = feedList.querySelectorAll('div[role="listitem"]');
37
+ for (const item of items) {
38
+ if (item.offsetHeight < 100) continue;
39
+ const menuBtn = item.querySelector('button[aria-label^="Open control menu for post"]');
40
+ if (menuBtn) {
41
+ scope = item;
42
+ break;
43
+ }
44
+ }
45
+ }
46
+
47
+ // --- Author info ---
48
+ const authorLink = scope.querySelector('a[href*="/in/"], a[href*="/company/"]');
49
+ if (authorLink) {
50
+ authorProfileUrl = authorLink.href.split('?')[0] || null;
51
+
52
+ // Try name from span inside the link first
53
+ const nameSpan = authorLink.querySelector('span[dir="ltr"], span[aria-hidden="true"]');
54
+ let rawName = nameSpan ? (nameSpan.textContent || '').trim() : '';
55
+
56
+ // Fallback: link's own textContent (trimmed, first line only)
57
+ if (!rawName) {
58
+ rawName = (authorLink.textContent || '').trim().split('\\n')[0].trim();
59
+ }
60
+
61
+ // Fallback: look for a nearby heading or span that contains the name
62
+ // (LinkedIn sometimes renders the name outside the <a> tag)
63
+ if (!rawName) {
64
+ const parent = authorLink.closest('div');
65
+ if (parent) {
66
+ const nearby = parent.querySelector('span[dir="ltr"], span[aria-hidden="true"]');
67
+ if (nearby) rawName = (nearby.textContent || '').trim();
68
+ }
69
+ }
70
+
71
+ authorName = rawName || null;
72
+ }
73
+
74
+ // --- Author headline ---
75
+ // Search within <main> scope, skip navigation text and the author name
76
+ const allSpans = scope.querySelectorAll('span');
77
+ for (const span of allSpans) {
78
+ const txt = (span.textContent || '').trim();
79
+ if (
80
+ txt &&
81
+ txt.length > 5 &&
82
+ txt.length < 200 &&
83
+ txt !== authorName &&
84
+ !txt.match(/^\\d+[smhdw]$/) &&
85
+ !txt.match(/^\\d[\\d,]*\\s+(reactions?|comments?|reposts?|likes?)$/i) &&
86
+ !txt.match(/^Follow$|^Promoted$/i) &&
87
+ !txt.match(/^Skip to|^Keyboard shortcuts$|^Close jump menu$/i) &&
88
+ !txt.match(/^Feed detail update$|^Feed post$/i)
89
+ ) {
90
+ authorHeadline = txt;
91
+ break;
92
+ }
93
+ }
94
+
95
+ // --- Post text ---
96
+ const ltrSpans = scope.querySelectorAll('span[dir="ltr"]');
97
+ let longestText = '';
98
+ for (const span of ltrSpans) {
99
+ const txt = (span.textContent || '').trim();
100
+ if (txt.length > longestText.length && txt !== authorName && txt !== authorHeadline) {
101
+ longestText = txt;
102
+ }
103
+ }
104
+ if (longestText.length > 20) {
105
+ text = longestText;
106
+ }
107
+
108
+ // --- Engagement counts ---
109
+ const countText = document.body.textContent || '';
110
+
111
+ function parseCount(pattern) {
112
+ const m = countText.match(pattern);
113
+ if (!m) return 0;
114
+ const raw = m[1].replace(/,/g, '');
115
+ const num = parseInt(raw, 10);
116
+ return isNaN(num) ? 0 : num;
117
+ }
118
+
119
+ reactionCount = parseCount(/(\\d[\\d,]*)\\s+reactions?/i);
120
+ commentCount = parseCount(/(\\d[\\d,]*)\\s+comments?/i);
121
+ shareCount = parseCount(/(\\d[\\d,]*)\\s+reposts?/i);
122
+
123
+ // --- Timestamp ---
124
+ const timeEl = scope.querySelector('time');
125
+ if (timeEl) {
126
+ const dt = timeEl.getAttribute('datetime');
127
+ if (dt) timestamp = dt;
128
+ }
129
+ if (!timestamp) {
130
+ const scopeText = scope.textContent || '';
131
+ const timeMatch = scopeText.match(/(?:^|\\s)(\\d+[smhdw])(?:\\s|$|\\u00B7|\\xB7)/);
132
+ if (timeMatch) timestamp = timeMatch[1];
133
+ }
134
+
135
+ return {
136
+ authorName,
137
+ authorHeadline,
138
+ authorProfileUrl,
139
+ text,
140
+ reactionCount,
141
+ commentCount,
142
+ shareCount,
143
+ timestamp,
144
+ };
145
+ })()`;
30
146
  /**
31
- * Parse the Voyager feed update response into a normalised PostDetail.
147
+ * JavaScript source evaluated inside the LinkedIn post detail page to
148
+ * extract visible comments from the DOM.
149
+ *
150
+ * Comments are rendered as `article` elements containing an author link
151
+ * and text content. Only first-page (visible) comments are extracted;
152
+ * "Load more" is not clicked.
32
153
  */
33
- export function parseFeedUpdateResponse(raw, postUrn, included) {
34
- // Resolve the feed update element — try nested data, data.elements, or flat
35
- const element = raw.data?.elements?.[0] ?? raw.data ?? raw;
36
- // Build included entity lookup
37
- const profilesByUrn = new Map();
38
- for (const entity of included) {
39
- if (entity.entityUrn) {
40
- profilesByUrn.set(entity.entityUrn, entity);
41
- }
42
- }
43
- // Resolve actor — may be inline object, URN reference, or in included
44
- let authorName = "";
154
+ const SCRAPE_COMMENTS_SCRIPT = `(() => {
155
+ const comments = [];
156
+ const articles = document.querySelectorAll('article');
157
+
158
+ for (const article of articles) {
159
+ if (article.offsetHeight < 30) continue;
160
+
161
+ // --- Author ---
162
+ let authorName = '';
45
163
  let authorHeadline = null;
46
164
  let authorPublicId = null;
47
- const actorValue = element.actor;
48
- if (typeof actorValue === "string") {
49
- // URN reference — look up in included
50
- const profile = profilesByUrn.get(actorValue);
51
- if (profile) {
52
- authorName = resolveActorName(profile);
53
- authorHeadline = resolveTextValue(profile.description ?? profile.headline) || null;
54
- authorPublicId = profile.publicIdentifier ?? extractPublicId(profile.navigationUrl ?? undefined);
165
+ const authorLink = article.querySelector('a[href*="/in/"]');
166
+
167
+ if (authorLink) {
168
+ const nameSpan = authorLink.querySelector('span[dir="ltr"], span[aria-hidden="true"]');
169
+ authorName = nameSpan ? (nameSpan.textContent || '').trim() : '';
170
+ if (!authorName) {
171
+ authorName = (authorLink.textContent || '').trim().split('\\n')[0].trim();
172
+ }
173
+ if (!authorName) {
174
+ const parent = authorLink.closest('div');
175
+ if (parent) {
176
+ const nearby = parent.querySelector('span[dir="ltr"], span[aria-hidden="true"]');
177
+ if (nearby) authorName = (nearby.textContent || '').trim();
55
178
  }
179
+ }
180
+
181
+ const href = authorLink.href.split('?')[0] || '';
182
+ const idMatch = href.match(/\\/in\\/([^/?]+)/);
183
+ if (idMatch) authorPublicId = idMatch[1];
56
184
  }
57
- else if (actorValue) {
58
- authorName = resolveActorName(actorValue);
59
- authorHeadline = resolveTextValue(actorValue.description ?? actorValue.headline) || null;
60
- authorPublicId = actorValue.publicIdentifier ?? extractPublicId(actorValue.navigationUrl);
185
+
186
+ // --- Author headline ---
187
+ const spans = article.querySelectorAll('span');
188
+ for (const span of spans) {
189
+ const txt = (span.textContent || '').trim();
190
+ if (
191
+ txt &&
192
+ txt.length > 5 &&
193
+ txt.length < 200 &&
194
+ txt !== authorName &&
195
+ !txt.match(/^\\d+[smhdw]$/) &&
196
+ !txt.match(/^\\d[\\d,]*\\s+(reactions?|comments?|reposts?|likes?)$/i) &&
197
+ !txt.match(/^Reply$|^Like$/i)
198
+ ) {
199
+ authorHeadline = txt;
200
+ break;
201
+ }
61
202
  }
62
- else {
63
- // Try *actor URN reference
64
- const actorUrn = element["*actor"] ?? raw.data?.["*actor"];
65
- if (actorUrn) {
66
- const profile = profilesByUrn.get(actorUrn);
67
- if (profile) {
68
- authorName = resolveActorName(profile);
69
- authorHeadline = resolveTextValue(profile.description ?? profile.headline) || null;
70
- authorPublicId = profile.publicIdentifier ?? extractPublicId(profile.navigationUrl ?? undefined);
71
- }
72
- }
203
+
204
+ // --- Comment text ---
205
+ let text = '';
206
+ const ltrSpans = article.querySelectorAll('span[dir="ltr"]');
207
+ for (const span of ltrSpans) {
208
+ const txt = (span.textContent || '').trim();
209
+ if (txt.length > text.length && txt !== authorName && txt !== authorHeadline) {
210
+ text = txt;
211
+ }
73
212
  }
74
- // Resolve commentary text
75
- const commentary = element.commentary ?? raw.data?.commentary;
76
- const text = resolveTextValue(commentary?.text);
77
- // Resolve timestamps
78
- const publishedAt = element.publishedAt ?? raw.data?.publishedAt ?? null;
79
- // Resolve social counts
80
- const social = element.socialDetail ?? raw.data?.socialDetail ?? raw.socialDetail;
81
- const counts = social?.totalSocialActivityCounts;
82
- return {
83
- postUrn,
84
- authorName,
85
- authorHeadline,
86
- authorPublicId,
87
- text,
88
- publishedAt,
89
- reactionCount: counts?.numLikes ?? 0,
90
- commentCount: counts?.numComments ?? 0,
91
- shareCount: counts?.numShares ?? 0,
92
- };
93
- }
213
+
214
+ // Skip if no meaningful content
215
+ if (!text && !authorName) continue;
216
+
217
+ // --- Timestamp ---
218
+ let createdAt = null;
219
+ const timeEl = article.querySelector('time');
220
+ if (timeEl) {
221
+ const dt = timeEl.getAttribute('datetime');
222
+ if (dt) createdAt = dt;
223
+ }
224
+
225
+ // --- Reaction count ---
226
+ let reactionCount = 0;
227
+ const articleText = article.textContent || '';
228
+ const likesMatch = articleText.match(/(\\d[\\d,]*)\\s+reactions?/i);
229
+ if (likesMatch) {
230
+ reactionCount = parseInt(likesMatch[1].replace(/,/g, ''), 10) || 0;
231
+ }
232
+
233
+ comments.push({
234
+ authorName,
235
+ authorHeadline,
236
+ authorPublicId,
237
+ text,
238
+ createdAt,
239
+ reactionCount,
240
+ });
241
+ }
242
+
243
+ return comments;
244
+ })()`;
94
245
  /**
95
- * Resolve actor display name from various response shapes.
246
+ * JavaScript source that finds and clicks the "Load more comments" button.
247
+ * Returns `true` if a button was clicked, `false` otherwise.
248
+ *
249
+ * LinkedIn renders the load-more trigger as a `button` or `span` whose
250
+ * text content includes "Load more comments" (or locale equivalents).
251
+ * The script also recognises "Load previous replies" for nested threads.
96
252
  */
97
- function resolveActorName(actor) {
98
- // Try name.text pattern (actor object from feed updates)
99
- const nameText = resolveTextValue(actor.name);
100
- if (nameText)
101
- return nameText;
102
- // Try firstName + lastName pattern (mini-profile)
103
- if (actor.firstName || actor.lastName) {
104
- return [actor.firstName, actor.lastName].filter(Boolean).join(" ");
253
+ const CLICK_LOAD_MORE_COMMENTS_SCRIPT = `(() => {
254
+ const loadMoreTexts = [
255
+ 'load more comments', 'show more comments', 'show previous replies',
256
+ 'load previous replies', 'view more comments',
257
+ ];
258
+
259
+ // Try buttons first, then spans and anchors
260
+ const candidates = [
261
+ ...document.querySelectorAll('button'),
262
+ ...document.querySelectorAll('span[role="button"]'),
263
+ ];
264
+
265
+ for (const el of candidates) {
266
+ const txt = (el.textContent || '').trim().toLowerCase();
267
+ if (loadMoreTexts.some(t => txt.includes(t))) {
268
+ el.scrollIntoView({ block: 'center' });
269
+ el.click();
270
+ return true;
105
271
  }
106
- return "";
107
- }
272
+ }
273
+ return false;
274
+ })()`;
275
+ // ---------------------------------------------------------------------------
276
+ // Wait for post detail to load
277
+ // ---------------------------------------------------------------------------
108
278
  /**
109
- * Parse the Voyager comments response into normalised PostComment entries.
279
+ * Poll the DOM until the post detail page has rendered. The page is
280
+ * considered ready when an author link and at least one `span[dir="ltr"]`
281
+ * are present.
110
282
  */
111
- export function parseCommentsResponse(raw) {
112
- const elements = raw.data?.elements ?? raw.elements ?? [];
113
- const paging = raw.data?.paging ?? raw.paging;
114
- const included = raw.included ?? [];
115
- // Build a lookup for included mini-profile entities
116
- const profilesByUrn = new Map();
117
- for (const entity of included) {
118
- if (entity.entityUrn) {
119
- profilesByUrn.set(entity.entityUrn, entity);
120
- }
283
+ async function waitForPostLoad(client, timeoutMs = 15_000) {
284
+ const deadline = Date.now() + timeoutMs;
285
+ while (Date.now() < deadline) {
286
+ const ready = await client.evaluate(`(() => {
287
+ const authorLink = document.querySelector('a[href*="/in/"], a[href*="/company/"]');
288
+ if (!authorLink) return false;
289
+ const ltrSpans = document.querySelectorAll('span[dir="ltr"]');
290
+ return ltrSpans.length > 0;
291
+ })()`);
292
+ if (ready)
293
+ return;
294
+ await delay(500);
121
295
  }
122
- const comments = [];
123
- for (const el of elements) {
124
- const commentUrn = el.urn ?? el.entityUrn ?? null;
125
- // Resolve commenter
126
- let authorName = "";
127
- let authorHeadline = null;
128
- let authorPublicId = null;
129
- if (el.commenter) {
130
- authorName = [el.commenter.firstName, el.commenter.lastName]
131
- .filter(Boolean)
132
- .join(" ");
133
- authorHeadline =
134
- resolveTextValue(el.commenter.headline) ||
135
- el.commenter.occupation ||
136
- null;
137
- authorPublicId = el.commenter.publicIdentifier ?? null;
138
- }
139
- else {
140
- // Try URN reference lookup
141
- const commenterUrn = el.commenterUrn ?? el["*commenter"];
142
- if (commenterUrn) {
143
- const profile = profilesByUrn.get(commenterUrn);
144
- if (profile) {
145
- authorName = [profile.firstName, profile.lastName]
146
- .filter(Boolean)
147
- .join(" ");
148
- authorHeadline =
149
- resolveTextValue(profile.headline) ||
150
- profile.occupation ||
151
- null;
152
- authorPublicId = profile.publicIdentifier ?? null;
153
- }
154
- }
155
- }
156
- // Resolve comment text — multiple possible shapes
157
- let text = "";
158
- if (el.commentV2) {
159
- text = resolveTextValue(el.commentV2.text);
160
- }
161
- else if (el.commentary) {
162
- text = resolveTextValue(el.commentary.text);
163
- }
164
- else if (el.comment) {
165
- if (typeof el.comment === "string") {
166
- text = el.comment;
167
- }
168
- else if ("text" in el.comment) {
169
- text = resolveTextValue(el.comment.text);
170
- }
171
- else if ("values" in el.comment) {
172
- const vals = el.comment
173
- .values;
174
- text = vals?.map((v) => v.value ?? "").join("") ?? "";
175
- }
176
- }
177
- // Resolve timestamp
178
- const createdAt = el.createdTime ?? el.created?.time ?? null;
179
- // Resolve reaction count
180
- const reactionCount = el.socialDetail?.totalSocialActivityCounts?.numLikes ?? 0;
181
- comments.push({
182
- commentUrn,
183
- authorName,
184
- authorHeadline,
185
- authorPublicId,
186
- text,
187
- createdAt,
188
- reactionCount,
189
- });
190
- }
191
- return {
192
- comments,
193
- paging: {
194
- start: paging?.start ?? 0,
195
- count: paging?.count ?? comments.length,
196
- total: paging?.total ?? comments.length,
197
- },
198
- };
296
+ throw new Error("Timed out waiting for post detail to appear in the DOM");
297
+ }
298
+ // ---------------------------------------------------------------------------
299
+ // Parsing helpers
300
+ // ---------------------------------------------------------------------------
301
+ /**
302
+ * Extract public identifier from a LinkedIn profile URL.
303
+ */
304
+ function extractPublicId(url) {
305
+ if (!url)
306
+ return null;
307
+ const match = /\/in\/([^/?]+)/.exec(url);
308
+ return match?.[1] ?? null;
199
309
  }
200
310
  // ---------------------------------------------------------------------------
201
311
  // Main operation
@@ -203,19 +313,27 @@ export function parseCommentsResponse(raw) {
203
313
  /**
204
314
  * Retrieve detailed data for a single LinkedIn post with its comment thread.
205
315
  *
206
- * Connects to the LinkedIn webview in LinkedHelper and calls the
207
- * Voyager API to fetch the post entity and its comments.
316
+ * Connects to the LinkedIn webview in LinkedHelper, navigates to the
317
+ * post detail page, and extracts post data and comments from the
318
+ * rendered DOM.
208
319
  *
209
- * @param input - Post URL or URN, comment pagination parameters, and CDP connection options.
320
+ * @param input - Post URL or URN, and CDP connection options.
210
321
  * @returns Post detail with comments and pagination metadata.
211
322
  */
212
323
  export async function getPost(input) {
213
- const cdpPort = input.cdpPort ?? DEFAULT_CDP_PORT;
324
+ const cdpPort = await resolveInstancePort(input.cdpPort, input.cdpHost);
214
325
  const cdpHost = input.cdpHost ?? "127.0.0.1";
215
326
  const allowRemote = input.allowRemote ?? false;
216
- const commentCount = input.commentCount ?? 10;
217
- const commentStart = input.commentStart ?? 0;
218
- const postUrn = extractPostUrn(input.postUrl);
327
+ const maxComments = input.commentCount ?? 100;
328
+ const postDetailUrl = resolvePostDetailUrl(input.postUrl);
329
+ // Try to extract URN for the output postUrn field
330
+ let postUrn;
331
+ try {
332
+ postUrn = extractPostUrn(input.postUrl);
333
+ }
334
+ catch {
335
+ postUrn = input.postUrl;
336
+ }
219
337
  // Enforce loopback guard
220
338
  if (!allowRemote && cdpHost !== "127.0.0.1" && cdpHost !== "localhost") {
221
339
  throw new Error(`Non-loopback CDP host "${cdpHost}" requires --allow-remote. ` +
@@ -230,37 +348,65 @@ export async function getPost(input) {
230
348
  const client = new CDPClient(cdpPort, { host: cdpHost, allowRemote });
231
349
  await client.connect(linkedInTarget.id);
232
350
  try {
233
- const voyager = new VoyagerInterceptor(client);
234
- // Fetch post detail
235
- const encodedUrn = encodeURIComponent(postUrn);
236
- const postPath = `/voyager/api/feed/updates/${encodedUrn}`;
237
- const postResponse = await voyager.fetch(postPath);
238
- if (postResponse.status !== 200) {
239
- throw new Error(`Voyager API returned HTTP ${String(postResponse.status)} for post detail`);
240
- }
241
- const postBody = postResponse.body;
242
- if (postBody === null || typeof postBody !== "object") {
243
- throw new Error("Voyager API returned an unexpected response format for post detail");
351
+ // Navigate away if already on the post detail page to force a fresh load
352
+ await navigateAwayIf(client, "/feed/update/");
353
+ // Navigate to the post detail page
354
+ await client.navigate(postDetailUrl);
355
+ // Wait for the post content to render
356
+ await waitForPostLoad(client);
357
+ // Extract post metadata from the DOM
358
+ const rawPost = await client.evaluate(SCRAPE_POST_DETAIL_SCRIPT);
359
+ if (!rawPost) {
360
+ throw new Error("Failed to extract post detail from the DOM");
244
361
  }
245
- const rawPost = postBody;
246
- const post = parseFeedUpdateResponse(rawPost, postUrn, rawPost.included ?? []);
247
- // Fetch comments
248
- const commentsPath = `/voyager/api/feed/dash/feedComments` +
249
- `?q=commentsUnderFeedUpdate&updateUrn=${encodedUrn}` +
250
- `&start=${String(commentStart)}&count=${String(commentCount)}`;
251
- const commentsResponse = await voyager.fetch(commentsPath);
252
- if (commentsResponse.status !== 200) {
253
- throw new Error(`Voyager API returned HTTP ${String(commentsResponse.status)} for post comments`);
254
- }
255
- const commentsBody = commentsResponse.body;
256
- if (commentsBody === null || typeof commentsBody !== "object") {
257
- throw new Error("Voyager API returned an unexpected response format for post comments");
362
+ const post = {
363
+ postUrn,
364
+ authorName: rawPost.authorName ?? "",
365
+ authorHeadline: rawPost.authorHeadline ?? null,
366
+ authorPublicId: extractPublicId(rawPost.authorProfileUrl),
367
+ text: rawPost.text ?? "",
368
+ publishedAt: parseTimestamp(rawPost.timestamp),
369
+ reactionCount: rawPost.reactionCount,
370
+ commentCount: rawPost.commentCount,
371
+ shareCount: rawPost.shareCount,
372
+ };
373
+ // --- Comment loading ---
374
+ // Click "Load more comments" repeatedly until we have enough or no more
375
+ // are available. Each click loads an additional batch of comments.
376
+ const maxLoadMoreAttempts = 20;
377
+ if (maxComments > 0) {
378
+ for (let attempt = 0; attempt < maxLoadMoreAttempts; attempt++) {
379
+ const currentCount = await client.evaluate(`document.querySelectorAll('article').length`);
380
+ if (currentCount >= maxComments)
381
+ break;
382
+ const clicked = await client.evaluate(CLICK_LOAD_MORE_COMMENTS_SCRIPT);
383
+ if (!clicked)
384
+ break;
385
+ await delay(1500);
386
+ }
258
387
  }
259
- const parsed = parseCommentsResponse(commentsBody);
388
+ // Extract all visible comments from the DOM
389
+ const rawComments = await client.evaluate(SCRAPE_COMMENTS_SCRIPT);
390
+ const allRaw = rawComments ?? [];
391
+ const limited = maxComments > 0 ? allRaw.slice(0, maxComments) : [];
392
+ const comments = limited.map((c) => ({
393
+ commentUrn: null,
394
+ authorName: c.authorName,
395
+ authorHeadline: c.authorHeadline,
396
+ authorPublicId: c.authorPublicId,
397
+ text: c.text,
398
+ createdAt: parseTimestamp(c.createdAt),
399
+ reactionCount: c.reactionCount,
400
+ }));
401
+ await gaussianDelay(800, 300, 300, 1_800); // Post-action dwell
260
402
  return {
261
403
  post,
262
- comments: parsed.comments,
263
- commentsPaging: parsed.paging,
404
+ comments,
405
+ commentsPaging: {
406
+ start: 0,
407
+ count: comments.length,
408
+ total: comments.length,
409
+ },
264
410
  };
265
411
  }
266
412
  finally {