@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.
- package/dist/cdp/app-discovery.d.ts +57 -0
- package/dist/cdp/app-discovery.d.ts.map +1 -1
- package/dist/cdp/app-discovery.js +90 -7
- package/dist/cdp/app-discovery.js.map +1 -1
- package/dist/cdp/app-discovery.test.js +180 -9
- package/dist/cdp/app-discovery.test.js.map +1 -1
- package/dist/cdp/client.d.ts +8 -1
- package/dist/cdp/client.d.ts.map +1 -1
- package/dist/cdp/client.js +8 -1
- package/dist/cdp/client.js.map +1 -1
- package/dist/cdp/discovery.d.ts.map +1 -1
- package/dist/cdp/discovery.js +5 -1
- package/dist/cdp/discovery.js.map +1 -1
- package/dist/cdp/discovery.test.js +7 -0
- package/dist/cdp/discovery.test.js.map +1 -1
- package/dist/cdp/index.d.ts +1 -1
- package/dist/cdp/index.d.ts.map +1 -1
- package/dist/cdp/index.js +1 -1
- package/dist/cdp/index.js.map +1 -1
- package/dist/cdp/instance-discovery.d.ts.map +1 -1
- package/dist/cdp/instance-discovery.js +25 -10
- package/dist/cdp/instance-discovery.js.map +1 -1
- package/dist/cdp/instance-discovery.test.js +17 -0
- package/dist/cdp/instance-discovery.test.js.map +1 -1
- package/dist/cdp/testing/launch-chromium.d.ts +1 -1
- package/dist/cdp/testing/launch-chromium.js +2 -2
- package/dist/db/client.d.ts.map +1 -1
- package/dist/db/client.js +3 -0
- package/dist/db/client.js.map +1 -1
- package/dist/db/repositories/campaign-hard-delete.integration.test.js +4 -1
- package/dist/db/repositories/campaign-hard-delete.integration.test.js.map +1 -1
- package/dist/db/repositories/campaign.d.ts.map +1 -1
- package/dist/db/repositories/campaign.js +81 -33
- package/dist/db/repositories/campaign.js.map +1 -1
- package/dist/db/repositories/campaign.test.js +2 -2
- package/dist/db/repositories/collection-list.d.ts +11 -0
- package/dist/db/repositories/collection-list.d.ts.map +1 -1
- package/dist/db/repositories/collection-list.integration.test.js +6 -4
- package/dist/db/repositories/collection-list.integration.test.js.map +1 -1
- package/dist/db/repositories/collection-list.js +92 -2
- package/dist/db/repositories/collection-list.js.map +1 -1
- package/dist/db/testing/create-fixture.js +36 -2
- package/dist/db/testing/create-fixture.js.map +1 -1
- package/dist/index.d.ts +6 -6
- package/dist/index.d.ts.map +1 -1
- package/dist/index.js +6 -6
- package/dist/index.js.map +1 -1
- package/dist/linkedin/dom-automation-retry.test.d.ts +2 -0
- package/dist/linkedin/dom-automation-retry.test.d.ts.map +1 -0
- package/dist/linkedin/dom-automation-retry.test.js +51 -0
- package/dist/linkedin/dom-automation-retry.test.js.map +1 -0
- package/dist/linkedin/dom-automation.d.ts +166 -6
- package/dist/linkedin/dom-automation.d.ts.map +1 -1
- package/dist/linkedin/dom-automation.js +496 -21
- package/dist/linkedin/dom-automation.js.map +1 -1
- package/dist/linkedin/humanized-mouse.d.ts +69 -0
- package/dist/linkedin/humanized-mouse.d.ts.map +1 -0
- package/dist/linkedin/humanized-mouse.js +109 -0
- package/dist/linkedin/humanized-mouse.js.map +1 -0
- package/dist/linkedin/index.d.ts +3 -2
- package/dist/linkedin/index.d.ts.map +1 -1
- package/dist/linkedin/index.js +3 -2
- package/dist/linkedin/index.js.map +1 -1
- package/dist/linkedin/selectors.d.ts +74 -48
- package/dist/linkedin/selectors.d.ts.map +1 -1
- package/dist/linkedin/selectors.js +64 -41
- package/dist/linkedin/selectors.js.map +1 -1
- package/dist/operations/add-people-to-collection.d.ts +1 -1
- package/dist/operations/add-people-to-collection.d.ts.map +1 -1
- package/dist/operations/add-people-to-collection.js +3 -6
- package/dist/operations/add-people-to-collection.js.map +1 -1
- package/dist/operations/build-linkedin-url.test.d.ts +2 -0
- package/dist/operations/build-linkedin-url.test.d.ts.map +1 -0
- package/dist/operations/build-linkedin-url.test.js +158 -0
- package/dist/operations/build-linkedin-url.test.js.map +1 -0
- package/dist/operations/campaign-add-action.d.ts +1 -1
- package/dist/operations/campaign-add-action.d.ts.map +1 -1
- package/dist/operations/campaign-add-action.js +3 -6
- package/dist/operations/campaign-add-action.js.map +1 -1
- package/dist/operations/campaign-create.d.ts +1 -1
- package/dist/operations/campaign-create.d.ts.map +1 -1
- package/dist/operations/campaign-create.js +3 -6
- package/dist/operations/campaign-create.js.map +1 -1
- package/dist/operations/campaign-delete.d.ts +1 -1
- package/dist/operations/campaign-delete.d.ts.map +1 -1
- package/dist/operations/campaign-delete.js +3 -6
- package/dist/operations/campaign-delete.js.map +1 -1
- package/dist/operations/campaign-erase.d.ts +1 -1
- package/dist/operations/campaign-erase.d.ts.map +1 -1
- package/dist/operations/campaign-erase.js +3 -6
- package/dist/operations/campaign-erase.js.map +1 -1
- package/dist/operations/campaign-exclude-add.d.ts +1 -1
- package/dist/operations/campaign-exclude-add.d.ts.map +1 -1
- package/dist/operations/campaign-exclude-add.js +3 -6
- package/dist/operations/campaign-exclude-add.js.map +1 -1
- package/dist/operations/campaign-exclude-list.d.ts +1 -1
- package/dist/operations/campaign-exclude-list.d.ts.map +1 -1
- package/dist/operations/campaign-exclude-list.js +3 -6
- package/dist/operations/campaign-exclude-list.js.map +1 -1
- package/dist/operations/campaign-exclude-remove.d.ts +1 -1
- package/dist/operations/campaign-exclude-remove.d.ts.map +1 -1
- package/dist/operations/campaign-exclude-remove.js +3 -6
- package/dist/operations/campaign-exclude-remove.js.map +1 -1
- package/dist/operations/campaign-export.d.ts +1 -1
- package/dist/operations/campaign-export.d.ts.map +1 -1
- package/dist/operations/campaign-export.js +3 -6
- package/dist/operations/campaign-export.js.map +1 -1
- package/dist/operations/campaign-get.d.ts +1 -1
- package/dist/operations/campaign-get.d.ts.map +1 -1
- package/dist/operations/campaign-get.js +3 -6
- package/dist/operations/campaign-get.js.map +1 -1
- package/dist/operations/campaign-list-people.d.ts +1 -1
- package/dist/operations/campaign-list-people.d.ts.map +1 -1
- package/dist/operations/campaign-list-people.js +3 -6
- package/dist/operations/campaign-list-people.js.map +1 -1
- package/dist/operations/campaign-list.d.ts +1 -1
- package/dist/operations/campaign-list.d.ts.map +1 -1
- package/dist/operations/campaign-list.js +3 -6
- package/dist/operations/campaign-list.js.map +1 -1
- package/dist/operations/campaign-move-next.d.ts +1 -1
- package/dist/operations/campaign-move-next.d.ts.map +1 -1
- package/dist/operations/campaign-move-next.js +3 -6
- package/dist/operations/campaign-move-next.js.map +1 -1
- package/dist/operations/campaign-remove-action.d.ts +1 -1
- package/dist/operations/campaign-remove-action.d.ts.map +1 -1
- package/dist/operations/campaign-remove-action.js +3 -6
- package/dist/operations/campaign-remove-action.js.map +1 -1
- package/dist/operations/campaign-remove-people.d.ts +1 -1
- package/dist/operations/campaign-remove-people.d.ts.map +1 -1
- package/dist/operations/campaign-remove-people.js +3 -6
- package/dist/operations/campaign-remove-people.js.map +1 -1
- package/dist/operations/campaign-reorder-actions.d.ts +1 -1
- package/dist/operations/campaign-reorder-actions.d.ts.map +1 -1
- package/dist/operations/campaign-reorder-actions.js +3 -6
- package/dist/operations/campaign-reorder-actions.js.map +1 -1
- package/dist/operations/campaign-retry.d.ts +1 -1
- package/dist/operations/campaign-retry.d.ts.map +1 -1
- package/dist/operations/campaign-retry.js +3 -6
- package/dist/operations/campaign-retry.js.map +1 -1
- package/dist/operations/campaign-start.d.ts +1 -1
- package/dist/operations/campaign-start.d.ts.map +1 -1
- package/dist/operations/campaign-start.js +3 -6
- package/dist/operations/campaign-start.js.map +1 -1
- package/dist/operations/campaign-statistics.d.ts +1 -1
- package/dist/operations/campaign-statistics.d.ts.map +1 -1
- package/dist/operations/campaign-statistics.js +3 -6
- package/dist/operations/campaign-statistics.js.map +1 -1
- package/dist/operations/campaign-status.d.ts +1 -1
- package/dist/operations/campaign-status.d.ts.map +1 -1
- package/dist/operations/campaign-status.js +3 -6
- package/dist/operations/campaign-status.js.map +1 -1
- package/dist/operations/campaign-stop.d.ts +1 -1
- package/dist/operations/campaign-stop.d.ts.map +1 -1
- package/dist/operations/campaign-stop.js +3 -6
- package/dist/operations/campaign-stop.js.map +1 -1
- package/dist/operations/campaign-update-action.d.ts +1 -1
- package/dist/operations/campaign-update-action.d.ts.map +1 -1
- package/dist/operations/campaign-update-action.js +3 -6
- package/dist/operations/campaign-update-action.js.map +1 -1
- package/dist/operations/campaign-update.d.ts +1 -1
- package/dist/operations/campaign-update.d.ts.map +1 -1
- package/dist/operations/campaign-update.js +3 -6
- package/dist/operations/campaign-update.js.map +1 -1
- package/dist/operations/check-replies.d.ts +3 -1
- package/dist/operations/check-replies.d.ts.map +1 -1
- package/dist/operations/check-replies.js +124 -17
- package/dist/operations/check-replies.js.map +1 -1
- package/dist/operations/check-replies.test.js +152 -17
- package/dist/operations/check-replies.test.js.map +1 -1
- package/dist/operations/collect-people.d.ts +1 -1
- package/dist/operations/collect-people.d.ts.map +1 -1
- package/dist/operations/collect-people.js +18 -12
- package/dist/operations/collect-people.js.map +1 -1
- package/dist/operations/collect-people.test.js +21 -5
- package/dist/operations/collect-people.test.js.map +1 -1
- package/dist/operations/comment-on-post.d.ts +4 -1
- package/dist/operations/comment-on-post.d.ts.map +1 -1
- package/dist/operations/comment-on-post.js +15 -19
- package/dist/operations/comment-on-post.js.map +1 -1
- package/dist/operations/comment-on-post.test.js +8 -6
- package/dist/operations/comment-on-post.test.js.map +1 -1
- package/dist/operations/create-collection.d.ts +1 -1
- package/dist/operations/create-collection.d.ts.map +1 -1
- package/dist/operations/create-collection.js +5 -7
- package/dist/operations/create-collection.js.map +1 -1
- package/dist/operations/create-collection.test.js +3 -1
- package/dist/operations/create-collection.test.js.map +1 -1
- package/dist/operations/delete-collection.d.ts +1 -1
- package/dist/operations/delete-collection.d.ts.map +1 -1
- package/dist/operations/delete-collection.js +3 -6
- package/dist/operations/delete-collection.js.map +1 -1
- package/dist/operations/dismiss-errors.d.ts +11 -5
- package/dist/operations/dismiss-errors.d.ts.map +1 -1
- package/dist/operations/dismiss-errors.js +68 -34
- package/dist/operations/dismiss-errors.js.map +1 -1
- package/dist/operations/dismiss-errors.test.js +129 -8
- package/dist/operations/dismiss-errors.test.js.map +1 -1
- package/dist/operations/endorse-skills.test.d.ts +2 -0
- package/dist/operations/endorse-skills.test.d.ts.map +1 -0
- package/dist/operations/endorse-skills.test.js +70 -0
- package/dist/operations/endorse-skills.test.js.map +1 -0
- package/dist/operations/enrich-profile.test.d.ts +2 -0
- package/dist/operations/enrich-profile.test.d.ts.map +1 -0
- package/dist/operations/enrich-profile.test.js +73 -0
- package/dist/operations/enrich-profile.test.js.map +1 -0
- package/dist/operations/ephemeral-action.d.ts +2 -1
- package/dist/operations/ephemeral-action.d.ts.map +1 -1
- package/dist/operations/ephemeral-action.js +5 -7
- package/dist/operations/ephemeral-action.js.map +1 -1
- package/dist/operations/ephemeral-action.test.d.ts +2 -0
- package/dist/operations/ephemeral-action.test.d.ts.map +1 -0
- package/dist/operations/ephemeral-action.test.js +159 -0
- package/dist/operations/ephemeral-action.test.js.map +1 -0
- package/dist/operations/follow-person.test.d.ts +2 -0
- package/dist/operations/follow-person.test.d.ts.map +1 -0
- package/dist/operations/follow-person.test.js +57 -0
- package/dist/operations/follow-person.test.js.map +1 -0
- package/dist/operations/get-action-budget.d.ts +1 -1
- package/dist/operations/get-action-budget.d.ts.map +1 -1
- package/dist/operations/get-action-budget.js +3 -6
- package/dist/operations/get-action-budget.js.map +1 -1
- package/dist/operations/get-errors.d.ts +5 -1
- package/dist/operations/get-errors.d.ts.map +1 -1
- package/dist/operations/get-errors.js +55 -33
- package/dist/operations/get-errors.js.map +1 -1
- package/dist/operations/get-errors.test.js +54 -55
- package/dist/operations/get-errors.test.js.map +1 -1
- package/dist/operations/get-feed.d.ts +83 -4
- package/dist/operations/get-feed.d.ts.map +1 -1
- package/dist/operations/get-feed.js +400 -153
- package/dist/operations/get-feed.js.map +1 -1
- package/dist/operations/get-feed.test.js +416 -190
- package/dist/operations/get-feed.test.js.map +1 -1
- package/dist/operations/get-post-engagers.d.ts +6 -3
- package/dist/operations/get-post-engagers.d.ts.map +1 -1
- package/dist/operations/get-post-engagers.js +278 -78
- package/dist/operations/get-post-engagers.js.map +1 -1
- package/dist/operations/get-post-engagers.test.js +292 -14
- package/dist/operations/get-post-engagers.test.js.map +1 -1
- package/dist/operations/get-post-stats.d.ts +8 -3
- package/dist/operations/get-post-stats.d.ts.map +1 -1
- package/dist/operations/get-post-stats.js +101 -37
- package/dist/operations/get-post-stats.js.map +1 -1
- package/dist/operations/get-post-stats.test.js +137 -2
- package/dist/operations/get-post-stats.test.js.map +1 -1
- package/dist/operations/get-post.d.ts +9 -150
- package/dist/operations/get-post.d.ts.map +1 -1
- package/dist/operations/get-post.js +356 -210
- package/dist/operations/get-post.js.map +1 -1
- package/dist/operations/get-post.test.js +210 -387
- package/dist/operations/get-post.test.js.map +1 -1
- package/dist/operations/get-profile-activity.d.ts +13 -92
- package/dist/operations/get-profile-activity.d.ts.map +1 -1
- package/dist/operations/get-profile-activity.js +305 -105
- package/dist/operations/get-profile-activity.js.map +1 -1
- package/dist/operations/get-profile-activity.test.js +277 -158
- package/dist/operations/get-profile-activity.test.js.map +1 -1
- package/dist/operations/get-throttle-status.d.ts +1 -1
- package/dist/operations/get-throttle-status.d.ts.map +1 -1
- package/dist/operations/get-throttle-status.js +4 -10
- package/dist/operations/get-throttle-status.js.map +1 -1
- package/dist/operations/import-people-from-collection.d.ts +1 -1
- package/dist/operations/import-people-from-collection.d.ts.map +1 -1
- package/dist/operations/import-people-from-collection.js +3 -6
- package/dist/operations/import-people-from-collection.js.map +1 -1
- package/dist/operations/import-people-from-urls.d.ts +1 -1
- package/dist/operations/import-people-from-urls.d.ts.map +1 -1
- package/dist/operations/import-people-from-urls.js +3 -6
- package/dist/operations/import-people-from-urls.js.map +1 -1
- package/dist/operations/index.d.ts +2 -2
- package/dist/operations/index.d.ts.map +1 -1
- package/dist/operations/index.js +2 -1
- package/dist/operations/index.js.map +1 -1
- package/dist/operations/like-person-posts.test.d.ts +2 -0
- package/dist/operations/like-person-posts.test.d.ts.map +1 -0
- package/dist/operations/like-person-posts.test.js +103 -0
- package/dist/operations/like-person-posts.test.js.map +1 -0
- package/dist/operations/list-collections.d.ts +1 -1
- package/dist/operations/list-collections.d.ts.map +1 -1
- package/dist/operations/list-collections.js +3 -6
- package/dist/operations/list-collections.js.map +1 -1
- package/dist/operations/message-person.test.d.ts +2 -0
- package/dist/operations/message-person.test.d.ts.map +1 -0
- package/dist/operations/message-person.test.js +108 -0
- package/dist/operations/message-person.test.js.map +1 -0
- package/dist/operations/navigate-away.d.ts +14 -0
- package/dist/operations/navigate-away.d.ts.map +1 -0
- package/dist/operations/navigate-away.js +24 -0
- package/dist/operations/navigate-away.js.map +1 -0
- package/dist/operations/navigate-away.test.d.ts +2 -0
- package/dist/operations/navigate-away.test.d.ts.map +1 -0
- package/dist/operations/navigate-away.test.js +51 -0
- package/dist/operations/navigate-away.test.js.map +1 -0
- package/dist/operations/query-messages.d.ts +1 -1
- package/dist/operations/query-messages.d.ts.map +1 -1
- package/dist/operations/query-messages.js +3 -6
- package/dist/operations/query-messages.js.map +1 -1
- package/dist/operations/react-to-post.d.ts +16 -4
- package/dist/operations/react-to-post.d.ts.map +1 -1
- package/dist/operations/react-to-post.js +86 -24
- package/dist/operations/react-to-post.js.map +1 -1
- package/dist/operations/react-to-post.test.js +55 -5
- package/dist/operations/react-to-post.test.js.map +1 -1
- package/dist/operations/remove-connection.test.d.ts +2 -0
- package/dist/operations/remove-connection.test.d.ts.map +1 -0
- package/dist/operations/remove-connection.test.js +45 -0
- package/dist/operations/remove-connection.test.js.map +1 -0
- package/dist/operations/remove-people-from-collection.d.ts +1 -1
- package/dist/operations/remove-people-from-collection.d.ts.map +1 -1
- package/dist/operations/remove-people-from-collection.js +3 -6
- package/dist/operations/remove-people-from-collection.js.map +1 -1
- package/dist/operations/resolve-linkedin-entity.d.ts.map +1 -1
- package/dist/operations/resolve-linkedin-entity.js +2 -2
- package/dist/operations/resolve-linkedin-entity.js.map +1 -1
- package/dist/operations/resolve-linkedin-entity.test.d.ts +2 -0
- package/dist/operations/resolve-linkedin-entity.test.d.ts.map +1 -0
- package/dist/operations/resolve-linkedin-entity.test.js +343 -0
- package/dist/operations/resolve-linkedin-entity.test.js.map +1 -0
- package/dist/operations/scrape-messaging-history.d.ts +2 -1
- package/dist/operations/scrape-messaging-history.d.ts.map +1 -1
- package/dist/operations/scrape-messaging-history.js +113 -18
- package/dist/operations/scrape-messaging-history.js.map +1 -1
- package/dist/operations/scrape-messaging-history.test.js +109 -12
- package/dist/operations/scrape-messaging-history.test.js.map +1 -1
- package/dist/operations/search-posts.d.ts +20 -112
- package/dist/operations/search-posts.d.ts.map +1 -1
- package/dist/operations/search-posts.js +369 -170
- package/dist/operations/search-posts.js.map +1 -1
- package/dist/operations/search-posts.test.js +273 -234
- package/dist/operations/search-posts.test.js.map +1 -1
- package/dist/operations/send-inmail.test.d.ts +2 -0
- package/dist/operations/send-inmail.test.d.ts.map +1 -0
- package/dist/operations/send-inmail.test.js +108 -0
- package/dist/operations/send-inmail.test.js.map +1 -0
- package/dist/operations/send-invite.test.d.ts +2 -0
- package/dist/operations/send-invite.test.d.ts.map +1 -0
- package/dist/operations/send-invite.test.js +59 -0
- package/dist/operations/send-invite.test.js.map +1 -0
- package/dist/operations/types.d.ts +27 -1
- package/dist/operations/types.d.ts.map +1 -1
- package/dist/operations/types.js +14 -1
- package/dist/operations/types.js.map +1 -1
- package/dist/operations/visit-profile.d.ts +1 -1
- package/dist/operations/visit-profile.d.ts.map +1 -1
- package/dist/operations/visit-profile.js +3 -6
- package/dist/operations/visit-profile.js.map +1 -1
- package/dist/services/account-resolution.d.ts +10 -4
- package/dist/services/account-resolution.d.ts.map +1 -1
- package/dist/services/account-resolution.js +63 -5
- package/dist/services/account-resolution.js.map +1 -1
- package/dist/services/app.d.ts +6 -2
- package/dist/services/app.d.ts.map +1 -1
- package/dist/services/app.js +18 -6
- package/dist/services/app.js.map +1 -1
- package/dist/services/app.test.js +41 -7
- package/dist/services/app.test.js.map +1 -1
- package/dist/services/campaign.d.ts +40 -4
- package/dist/services/campaign.d.ts.map +1 -1
- package/dist/services/campaign.js +176 -10
- package/dist/services/campaign.js.map +1 -1
- package/dist/services/campaign.test.js +53 -15
- package/dist/services/campaign.test.js.map +1 -1
- package/dist/services/collection.d.ts +16 -21
- package/dist/services/collection.d.ts.map +1 -1
- package/dist/services/collection.js +34 -47
- package/dist/services/collection.js.map +1 -1
- package/dist/services/collection.test.js +30 -91
- package/dist/services/collection.test.js.map +1 -1
- package/dist/services/ephemeral-campaign.d.ts +6 -0
- package/dist/services/ephemeral-campaign.d.ts.map +1 -1
- package/dist/services/ephemeral-campaign.js +54 -10
- package/dist/services/ephemeral-campaign.js.map +1 -1
- package/dist/services/ephemeral-campaign.test.js +23 -10
- package/dist/services/ephemeral-campaign.test.js.map +1 -1
- package/dist/services/errors.d.ts +2 -1
- package/dist/services/errors.d.ts.map +1 -1
- package/dist/services/errors.js +6 -3
- package/dist/services/errors.js.map +1 -1
- package/dist/services/index.d.ts +1 -2
- package/dist/services/index.d.ts.map +1 -1
- package/dist/services/index.js +1 -2
- package/dist/services/index.js.map +1 -1
- package/dist/services/instance-context.d.ts +5 -1
- package/dist/services/instance-context.d.ts.map +1 -1
- package/dist/services/instance-context.js +87 -28
- package/dist/services/instance-context.js.map +1 -1
- package/dist/services/instance-context.test.js +5 -1
- package/dist/services/instance-context.test.js.map +1 -1
- package/dist/services/instance-lifecycle.d.ts.map +1 -1
- package/dist/services/instance-lifecycle.js +32 -1
- package/dist/services/instance-lifecycle.js.map +1 -1
- package/dist/services/instance-lifecycle.test.js +52 -1
- package/dist/services/instance-lifecycle.test.js.map +1 -1
- package/dist/services/instance.d.ts +37 -9
- package/dist/services/instance.d.ts.map +1 -1
- package/dist/services/instance.js +100 -25
- package/dist/services/instance.js.map +1 -1
- package/dist/services/instance.test.js +157 -0
- package/dist/services/instance.test.js.map +1 -1
- package/dist/services/launcher.d.ts +47 -3
- package/dist/services/launcher.d.ts.map +1 -1
- package/dist/services/launcher.js +205 -33
- package/dist/services/launcher.js.map +1 -1
- package/dist/services/launcher.test.js +133 -6
- package/dist/services/launcher.test.js.map +1 -1
- package/dist/services/source-type-registry.d.ts +8 -0
- package/dist/services/source-type-registry.d.ts.map +1 -1
- package/dist/services/source-type-registry.js +39 -0
- package/dist/services/source-type-registry.js.map +1 -1
- package/dist/services/source-type-registry.test.js +31 -1
- package/dist/services/source-type-registry.test.js.map +1 -1
- package/dist/services/status.d.ts +6 -2
- package/dist/services/status.d.ts.map +1 -1
- package/dist/services/status.js +67 -34
- package/dist/services/status.js.map +1 -1
- package/dist/services/status.test.js +9 -2
- package/dist/services/status.test.js.map +1 -1
- package/dist/testing/e2e-helpers.d.ts +47 -1
- package/dist/testing/e2e-helpers.d.ts.map +1 -1
- package/dist/testing/e2e-helpers.js +244 -7
- package/dist/testing/e2e-helpers.js.map +1 -1
- package/dist/testing/index.d.ts +1 -1
- package/dist/testing/index.d.ts.map +1 -1
- package/dist/testing/index.js +1 -1
- package/dist/testing/index.js.map +1 -1
- package/dist/types/account.d.ts +1 -1
- package/dist/types/campaign.d.ts +1 -1
- package/dist/types/campaign.d.ts.map +1 -1
- package/dist/types/feed.d.ts +1 -3
- package/dist/types/feed.d.ts.map +1 -1
- package/dist/types/index.d.ts +0 -1
- package/dist/types/index.d.ts.map +1 -1
- package/dist/utils/cdp-port.d.ts.map +1 -1
- package/dist/utils/cdp-port.js +3 -1
- package/dist/utils/cdp-port.js.map +1 -1
- package/dist/utils/cdp-port.test.js +1 -1
- package/dist/utils/cdp-port.test.js.map +1 -1
- package/dist/utils/delay.d.ts +79 -0
- package/dist/utils/delay.d.ts.map +1 -1
- package/dist/utils/delay.js +118 -0
- package/dist/utils/delay.js.map +1 -1
- package/dist/utils/delay.test.js +111 -1
- package/dist/utils/delay.test.js.map +1 -1
- package/dist/utils/index.d.ts +2 -1
- package/dist/utils/index.d.ts.map +1 -1
- package/dist/utils/index.js +2 -1
- package/dist/utils/index.js.map +1 -1
- package/dist/utils/session-pacer.d.ts +27 -0
- package/dist/utils/session-pacer.d.ts.map +1 -0
- package/dist/utils/session-pacer.js +55 -0
- package/dist/utils/session-pacer.js.map +1 -0
- package/dist/utils/session-pacer.test.d.ts +2 -0
- package/dist/utils/session-pacer.test.d.ts.map +1 -0
- package/dist/utils/session-pacer.test.js +111 -0
- package/dist/utils/session-pacer.test.js.map +1 -0
- package/package.json +1 -1
- package/dist/linkedin/__tests__/selectors.integration.test.d.ts +0 -2
- package/dist/linkedin/__tests__/selectors.integration.test.d.ts.map +0 -1
- package/dist/linkedin/__tests__/selectors.integration.test.js +0 -258
- package/dist/linkedin/__tests__/selectors.integration.test.js.map +0 -1
- package/dist/types/search-posts.d.ts +0 -22
- package/dist/types/search-posts.d.ts.map +0 -1
- package/dist/types/search-posts.js +0 -4
- package/dist/types/search-posts.js.map +0 -1
- package/dist/voyager/index.d.ts +0 -2
- package/dist/voyager/index.d.ts.map +0 -1
- package/dist/voyager/index.js +0 -4
- package/dist/voyager/index.js.map +0 -1
- package/dist/voyager/interceptor.d.ts +0 -100
- package/dist/voyager/interceptor.d.ts.map +0 -1
- package/dist/voyager/interceptor.integration.test.d.ts +0 -2
- package/dist/voyager/interceptor.integration.test.d.ts.map +0 -1
- package/dist/voyager/interceptor.integration.test.js +0 -89
- package/dist/voyager/interceptor.integration.test.js.map +0 -1
- package/dist/voyager/interceptor.js +0 -235
- package/dist/voyager/interceptor.js.map +0 -1
- package/dist/voyager/interceptor.test.d.ts +0 -2
- package/dist/voyager/interceptor.test.d.ts.map +0 -1
- package/dist/voyager/interceptor.test.js +0 -372
- 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 {
|
|
6
|
-
import {
|
|
7
|
-
import {
|
|
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
|
-
//
|
|
11
|
+
// In-page DOM scraping scripts
|
|
10
12
|
// ---------------------------------------------------------------------------
|
|
11
13
|
/**
|
|
12
|
-
*
|
|
13
|
-
|
|
14
|
-
|
|
15
|
-
|
|
16
|
-
|
|
17
|
-
|
|
18
|
-
|
|
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
|
-
|
|
25
|
-
|
|
26
|
-
|
|
27
|
-
|
|
28
|
-
|
|
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
|
-
*
|
|
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
|
-
|
|
34
|
-
|
|
35
|
-
|
|
36
|
-
|
|
37
|
-
|
|
38
|
-
|
|
39
|
-
|
|
40
|
-
|
|
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
|
|
48
|
-
|
|
49
|
-
|
|
50
|
-
|
|
51
|
-
|
|
52
|
-
|
|
53
|
-
|
|
54
|
-
|
|
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
|
-
|
|
58
|
-
|
|
59
|
-
|
|
60
|
-
|
|
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
|
-
|
|
63
|
-
|
|
64
|
-
|
|
65
|
-
|
|
66
|
-
|
|
67
|
-
|
|
68
|
-
|
|
69
|
-
|
|
70
|
-
|
|
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
|
-
|
|
75
|
-
|
|
76
|
-
|
|
77
|
-
|
|
78
|
-
|
|
79
|
-
|
|
80
|
-
const
|
|
81
|
-
|
|
82
|
-
|
|
83
|
-
|
|
84
|
-
|
|
85
|
-
|
|
86
|
-
|
|
87
|
-
|
|
88
|
-
|
|
89
|
-
|
|
90
|
-
|
|
91
|
-
|
|
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
|
-
*
|
|
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
|
-
|
|
98
|
-
|
|
99
|
-
|
|
100
|
-
|
|
101
|
-
|
|
102
|
-
|
|
103
|
-
|
|
104
|
-
|
|
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
|
-
|
|
107
|
-
|
|
272
|
+
}
|
|
273
|
+
return false;
|
|
274
|
+
})()`;
|
|
275
|
+
// ---------------------------------------------------------------------------
|
|
276
|
+
// Wait for post detail to load
|
|
277
|
+
// ---------------------------------------------------------------------------
|
|
108
278
|
/**
|
|
109
|
-
*
|
|
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
|
-
|
|
112
|
-
const
|
|
113
|
-
|
|
114
|
-
|
|
115
|
-
|
|
116
|
-
|
|
117
|
-
|
|
118
|
-
|
|
119
|
-
|
|
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
|
-
|
|
123
|
-
|
|
124
|
-
|
|
125
|
-
|
|
126
|
-
|
|
127
|
-
|
|
128
|
-
|
|
129
|
-
|
|
130
|
-
|
|
131
|
-
|
|
132
|
-
|
|
133
|
-
|
|
134
|
-
|
|
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
|
|
207
|
-
*
|
|
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,
|
|
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
|
|
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
|
|
217
|
-
const
|
|
218
|
-
|
|
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
|
-
|
|
234
|
-
|
|
235
|
-
|
|
236
|
-
|
|
237
|
-
|
|
238
|
-
|
|
239
|
-
|
|
240
|
-
|
|
241
|
-
|
|
242
|
-
|
|
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
|
|
246
|
-
|
|
247
|
-
|
|
248
|
-
|
|
249
|
-
|
|
250
|
-
|
|
251
|
-
|
|
252
|
-
|
|
253
|
-
|
|
254
|
-
|
|
255
|
-
|
|
256
|
-
|
|
257
|
-
|
|
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
|
-
|
|
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
|
|
263
|
-
commentsPaging:
|
|
404
|
+
comments,
|
|
405
|
+
commentsPaging: {
|
|
406
|
+
start: 0,
|
|
407
|
+
count: comments.length,
|
|
408
|
+
total: comments.length,
|
|
409
|
+
},
|
|
264
410
|
};
|
|
265
411
|
}
|
|
266
412
|
finally {
|