@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,176 +1,278 @@
|
|
|
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 {
|
|
6
|
+
import { navigateAwayIf } from "./navigate-away.js";
|
|
7
|
+
import { gaussianDelay, gaussianBetween, maybeHesitate, maybeBreak, simulateReadingTime } from "../utils/delay.js";
|
|
8
|
+
import { humanizedScrollToByIndex, retryInteraction } from "../linkedin/dom-automation.js";
|
|
9
|
+
import { mapRawPosts, scrollFeed, delay, } from "./get-feed.js";
|
|
10
|
+
// ---------------------------------------------------------------------------
|
|
11
|
+
// Search-specific DOM scraping script
|
|
12
|
+
// ---------------------------------------------------------------------------
|
|
7
13
|
/**
|
|
8
|
-
*
|
|
14
|
+
* JavaScript evaluated inside the LinkedIn search results page. Returns
|
|
15
|
+
* an array of {@link RawDomPost} objects.
|
|
9
16
|
*
|
|
10
|
-
*
|
|
11
|
-
* -
|
|
12
|
-
*
|
|
17
|
+
* Search result items are `div[role="listitem"]` elements (NOT wrapped
|
|
18
|
+
* in `data-testid="mainFeed"` like the feed page). URNs/URLs are NOT
|
|
19
|
+
* exposed inline — they are extracted in a subsequent phase by opening
|
|
20
|
+
* each post's three-dot menu and clicking "Copy link to post", which
|
|
21
|
+
* writes the URL to `navigator.clipboard.writeText`.
|
|
13
22
|
*/
|
|
14
|
-
|
|
15
|
-
|
|
16
|
-
|
|
17
|
-
|
|
18
|
-
|
|
19
|
-
|
|
20
|
-
|
|
21
|
-
|
|
22
|
-
|
|
23
|
-
|
|
24
|
-
|
|
25
|
-
|
|
26
|
-
|
|
27
|
-
|
|
28
|
-
|
|
29
|
-
|
|
23
|
+
const SCRAPE_SEARCH_RESULTS_SCRIPT = `(() => {
|
|
24
|
+
const posts = [];
|
|
25
|
+
|
|
26
|
+
// --- Strategy 1: div[role="listitem"] search results (no mainFeed wrapper) ---
|
|
27
|
+
const searchItems = document.querySelectorAll('div[role="listitem"]');
|
|
28
|
+
const isSearchPage = searchItems.length > 0
|
|
29
|
+
&& !document.querySelector('[data-testid="mainFeed"]');
|
|
30
|
+
if (isSearchPage) {
|
|
31
|
+
for (const card of searchItems) {
|
|
32
|
+
if (card.offsetHeight < 100) continue;
|
|
33
|
+
const menuBtn = card.querySelector('button[aria-label^="Open control menu for post"]');
|
|
34
|
+
if (!menuBtn) continue;
|
|
35
|
+
|
|
36
|
+
// URL extracted via three-dot menu
|
|
37
|
+
|
|
38
|
+
let authorName = null;
|
|
39
|
+
let authorHeadline = null;
|
|
40
|
+
let authorProfileUrl = null;
|
|
41
|
+
|
|
42
|
+
const authorLink = card.querySelector('a[href*="/in/"], a[href*="/company/"]');
|
|
43
|
+
if (authorLink) {
|
|
44
|
+
authorProfileUrl = authorLink.href.split('?')[0] || null;
|
|
45
|
+
const nameEl = authorLink.querySelector('span[dir="ltr"], span[aria-hidden="true"]')
|
|
46
|
+
|| authorLink;
|
|
47
|
+
const rawName = (nameEl.textContent || '').trim();
|
|
48
|
+
authorName = rawName || null;
|
|
49
|
+
}
|
|
50
|
+
|
|
51
|
+
const allSpans = card.querySelectorAll('span');
|
|
52
|
+
for (const span of allSpans) {
|
|
53
|
+
const txt = (span.textContent || '').trim();
|
|
54
|
+
if (
|
|
55
|
+
txt &&
|
|
56
|
+
txt.length > 5 &&
|
|
57
|
+
txt.length < 200 &&
|
|
58
|
+
txt !== authorName &&
|
|
59
|
+
!txt.match(/^\\d+[smhdw]$/) &&
|
|
60
|
+
!txt.match(/^\\d[\\d,]*\\s+(reactions?|comments?|reposts?|likes?)$/i) &&
|
|
61
|
+
!txt.match(/^Follow$|^Promoted$/i)
|
|
62
|
+
) {
|
|
63
|
+
authorHeadline = txt;
|
|
64
|
+
break;
|
|
65
|
+
}
|
|
66
|
+
}
|
|
67
|
+
|
|
68
|
+
let text = null;
|
|
69
|
+
const ltrSpans = card.querySelectorAll('span[dir="ltr"]');
|
|
70
|
+
let longestText = '';
|
|
71
|
+
for (const span of ltrSpans) {
|
|
72
|
+
const txt = (span.textContent || '').trim();
|
|
73
|
+
if (txt.length > longestText.length && txt !== authorName && txt !== authorHeadline) {
|
|
74
|
+
longestText = txt;
|
|
75
|
+
}
|
|
76
|
+
}
|
|
77
|
+
if (longestText.length > 20) text = longestText;
|
|
78
|
+
|
|
79
|
+
let mediaType = null;
|
|
80
|
+
if (card.querySelector('video')) {
|
|
81
|
+
mediaType = 'video';
|
|
82
|
+
} else if (card.querySelector('img[src*="media.licdn.com"]')) {
|
|
83
|
+
const imgs = card.querySelectorAll('img[src*="media.licdn.com"]');
|
|
84
|
+
for (const img of imgs) {
|
|
85
|
+
if (img.offsetHeight > 100) { mediaType = 'image'; break; }
|
|
86
|
+
}
|
|
87
|
+
}
|
|
88
|
+
|
|
89
|
+
const cardText = card.textContent || '';
|
|
90
|
+
function parseCount(pattern) {
|
|
91
|
+
const m = cardText.match(pattern);
|
|
92
|
+
if (!m) return 0;
|
|
93
|
+
const raw = m[1].replace(/,/g, '');
|
|
94
|
+
const num = parseInt(raw, 10);
|
|
95
|
+
return isNaN(num) ? 0 : num;
|
|
96
|
+
}
|
|
97
|
+
|
|
98
|
+
const reactionCount = parseCount(/(\\d[\\d,]*)\\s+reactions?/i);
|
|
99
|
+
const commentCount = parseCount(/(\\d[\\d,]*)\\s+comments?/i);
|
|
100
|
+
const shareCount = parseCount(/(\\d[\\d,]*)\\s+reposts?/i);
|
|
101
|
+
|
|
102
|
+
let timestamp = null;
|
|
103
|
+
const timeEl = card.querySelector('time');
|
|
104
|
+
if (timeEl) {
|
|
105
|
+
const dt = timeEl.getAttribute('datetime');
|
|
106
|
+
if (dt) timestamp = dt;
|
|
107
|
+
}
|
|
108
|
+
if (!timestamp) {
|
|
109
|
+
const timeMatch = cardText.match(/(?:^|\\s)(\\d+[smhdw])(?:\\s|$|\\u00B7|\\xB7)/);
|
|
110
|
+
if (timeMatch) timestamp = timeMatch[1];
|
|
111
|
+
}
|
|
112
|
+
|
|
113
|
+
posts.push({
|
|
114
|
+
url: null,
|
|
115
|
+
authorName,
|
|
116
|
+
authorHeadline,
|
|
117
|
+
authorProfileUrl,
|
|
118
|
+
text,
|
|
119
|
+
mediaType,
|
|
120
|
+
reactionCount,
|
|
121
|
+
commentCount,
|
|
122
|
+
shareCount,
|
|
123
|
+
timestamp,
|
|
124
|
+
});
|
|
125
|
+
}
|
|
126
|
+
return posts;
|
|
127
|
+
}
|
|
128
|
+
|
|
129
|
+
// --- Strategy 2: mainFeed fallback (older LinkedIn renders) ---
|
|
130
|
+
const feedList = document.querySelector('[data-testid="mainFeed"]');
|
|
131
|
+
if (!feedList) return posts;
|
|
132
|
+
|
|
133
|
+
const items = feedList.querySelectorAll('div[role="listitem"]');
|
|
134
|
+
for (const item of items) {
|
|
135
|
+
if (item.offsetHeight < 100) continue;
|
|
136
|
+
const menuBtn = item.querySelector('button[aria-label^="Open control menu for post"]');
|
|
137
|
+
if (!menuBtn) continue;
|
|
138
|
+
|
|
139
|
+
let authorName = null;
|
|
140
|
+
let authorHeadline = null;
|
|
141
|
+
let authorProfileUrl = null;
|
|
142
|
+
|
|
143
|
+
const authorLink = item.querySelector('a[href*="/in/"], a[href*="/company/"]');
|
|
144
|
+
if (authorLink) {
|
|
145
|
+
authorProfileUrl = authorLink.href.split('?')[0] || null;
|
|
146
|
+
const nameEl = authorLink.querySelector('span[dir="ltr"], span[aria-hidden="true"]')
|
|
147
|
+
|| authorLink;
|
|
148
|
+
authorName = (nameEl.textContent || '').trim() || null;
|
|
149
|
+
}
|
|
150
|
+
|
|
151
|
+
const allSpans = item.querySelectorAll('span');
|
|
152
|
+
for (const span of allSpans) {
|
|
153
|
+
const txt = (span.textContent || '').trim();
|
|
154
|
+
if (
|
|
155
|
+
txt && txt.length > 5 && txt.length < 200 &&
|
|
156
|
+
txt !== authorName &&
|
|
157
|
+
!txt.match(/^\\d+[smhdw]$/) &&
|
|
158
|
+
!txt.match(/^\\d[\\d,]*\\s+(reactions?|comments?|reposts?|likes?)$/i) &&
|
|
159
|
+
!txt.match(/^Follow$|^Promoted$/i)
|
|
160
|
+
) {
|
|
161
|
+
authorHeadline = txt;
|
|
162
|
+
break;
|
|
163
|
+
}
|
|
164
|
+
}
|
|
165
|
+
|
|
166
|
+
let text = null;
|
|
167
|
+
const ltrSpans = item.querySelectorAll('span[dir="ltr"]');
|
|
168
|
+
let longestText = '';
|
|
169
|
+
for (const span of ltrSpans) {
|
|
170
|
+
const txt = (span.textContent || '').trim();
|
|
171
|
+
if (txt.length > longestText.length && txt !== authorName && txt !== authorHeadline) {
|
|
172
|
+
longestText = txt;
|
|
173
|
+
}
|
|
174
|
+
}
|
|
175
|
+
if (longestText.length > 20) text = longestText;
|
|
176
|
+
|
|
177
|
+
let mediaType = null;
|
|
178
|
+
if (item.querySelector('video')) {
|
|
179
|
+
mediaType = 'video';
|
|
180
|
+
} else if (item.querySelector('img[src*="media.licdn.com"]')) {
|
|
181
|
+
const imgs = item.querySelectorAll('img[src*="media.licdn.com"]');
|
|
182
|
+
for (const img of imgs) {
|
|
183
|
+
if (img.offsetHeight > 100) { mediaType = 'image'; break; }
|
|
184
|
+
}
|
|
185
|
+
}
|
|
186
|
+
|
|
187
|
+
const itemText = item.textContent || '';
|
|
188
|
+
function parseCount2(pattern) {
|
|
189
|
+
const m = itemText.match(pattern);
|
|
190
|
+
if (!m) return 0;
|
|
191
|
+
const raw = m[1].replace(/,/g, '');
|
|
192
|
+
const num = parseInt(raw, 10);
|
|
193
|
+
return isNaN(num) ? 0 : num;
|
|
194
|
+
}
|
|
195
|
+
|
|
196
|
+
const reactionCount = parseCount2(/(\\d[\\d,]*)\\s+reactions?/i);
|
|
197
|
+
const commentCount = parseCount2(/(\\d[\\d,]*)\\s+comments?/i);
|
|
198
|
+
const shareCount = parseCount2(/(\\d[\\d,]*)\\s+reposts?/i);
|
|
199
|
+
|
|
200
|
+
let timestamp = null;
|
|
201
|
+
const timeEl = item.querySelector('time');
|
|
202
|
+
if (timeEl) {
|
|
203
|
+
const dt = timeEl.getAttribute('datetime');
|
|
204
|
+
if (dt) timestamp = dt;
|
|
205
|
+
}
|
|
206
|
+
if (!timestamp) {
|
|
207
|
+
const timeMatch = itemText.match(/(?:^|\\s)(\\d+[smhdw])(?:\\s|$|\\u00B7|\\xB7)/);
|
|
208
|
+
if (timeMatch) timestamp = timeMatch[1];
|
|
209
|
+
}
|
|
210
|
+
|
|
211
|
+
posts.push({
|
|
212
|
+
url: null,
|
|
213
|
+
authorName,
|
|
214
|
+
authorHeadline,
|
|
215
|
+
authorProfileUrl,
|
|
216
|
+
text,
|
|
217
|
+
mediaType,
|
|
218
|
+
reactionCount,
|
|
219
|
+
commentCount,
|
|
220
|
+
shareCount,
|
|
221
|
+
timestamp,
|
|
222
|
+
});
|
|
223
|
+
}
|
|
224
|
+
|
|
225
|
+
return posts;
|
|
226
|
+
})()`;
|
|
227
|
+
// ---------------------------------------------------------------------------
|
|
228
|
+
// Search-specific readiness check
|
|
229
|
+
// ---------------------------------------------------------------------------
|
|
30
230
|
/**
|
|
31
|
-
*
|
|
231
|
+
* Wait until search results are visible in the DOM.
|
|
32
232
|
*
|
|
33
|
-
*
|
|
34
|
-
*
|
|
35
|
-
*
|
|
36
|
-
*
|
|
37
|
-
*/
|
|
38
|
-
export function extractActivityUrn(urn) {
|
|
39
|
-
if (!urn)
|
|
40
|
-
return null;
|
|
41
|
-
// Extract nested activity URN from fs_updateV2 wrapper
|
|
42
|
-
// e.g. urn:li:fs_updateV2:(urn:li:activity:123,FEED_DETAIL)
|
|
43
|
-
const nestedMatch = /\((urn:li:(?:activity|ugcPost):\d+)[,)]/.exec(urn);
|
|
44
|
-
if (nestedMatch?.[1])
|
|
45
|
-
return nestedMatch[1];
|
|
46
|
-
// Direct activity/ugcPost URN
|
|
47
|
-
if (/^urn:li:(?:activity|ugcPost):\d+$/.test(urn))
|
|
48
|
-
return urn;
|
|
49
|
-
return urn;
|
|
50
|
-
}
|
|
51
|
-
/**
|
|
52
|
-
* Parse the Voyager content search response into normalised search results.
|
|
233
|
+
* Checks for two possible page structures:
|
|
234
|
+
* 1. `[data-chameleon-result-urn]` — modern search results with inline URNs.
|
|
235
|
+
* 2. `[data-testid="mainFeed"]` with menu buttons — older layout sharing
|
|
236
|
+
* the feed container.
|
|
53
237
|
*
|
|
54
|
-
*
|
|
55
|
-
* entities referenced via URN in the `included` array. This parser
|
|
56
|
-
* handles both inline and reference-based entity resolution.
|
|
238
|
+
* @internal Exported for testing.
|
|
57
239
|
*/
|
|
58
|
-
export function
|
|
59
|
-
const
|
|
60
|
-
|
|
61
|
-
|
|
62
|
-
|
|
63
|
-
|
|
64
|
-
|
|
65
|
-
|
|
66
|
-
|
|
67
|
-
|
|
68
|
-
}
|
|
69
|
-
const posts = [];
|
|
70
|
-
for (const cluster of clusters) {
|
|
71
|
-
for (const searchItem of cluster.items ?? []) {
|
|
72
|
-
const entityResult = searchItem.item?.entityResult;
|
|
73
|
-
if (!entityResult)
|
|
74
|
-
continue;
|
|
75
|
-
const postUrn = extractActivityUrn(entityResult.entityUrn);
|
|
76
|
-
if (!postUrn)
|
|
77
|
-
continue;
|
|
78
|
-
// Try to find the update entity in included
|
|
79
|
-
const entityRef = entityResult["*entity"] ?? entityResult.entityUrn;
|
|
80
|
-
const updateEntity = entityRef
|
|
81
|
-
? entitiesByUrn.get(entityRef)
|
|
82
|
-
: undefined;
|
|
83
|
-
// Extract post text from entity result summary or update commentary
|
|
84
|
-
const text = entityResult.summary?.text ??
|
|
85
|
-
updateEntity?.commentary?.text ??
|
|
86
|
-
null;
|
|
87
|
-
// Extract author info from entity result or included actor
|
|
88
|
-
let authorFirstName = null;
|
|
89
|
-
let authorLastName = null;
|
|
90
|
-
let authorPublicId = null;
|
|
91
|
-
let authorHeadline = null;
|
|
92
|
-
// Try entity result title (author name in search results)
|
|
93
|
-
const authorName = entityResult.title?.text ?? null;
|
|
94
|
-
if (authorName) {
|
|
95
|
-
const nameParts = authorName.split(" ");
|
|
96
|
-
authorFirstName = nameParts[0] ?? null;
|
|
97
|
-
authorLastName = nameParts.slice(1).join(" ") || null;
|
|
98
|
-
}
|
|
99
|
-
authorHeadline =
|
|
100
|
-
entityResult.primarySubtitle?.text ?? null;
|
|
101
|
-
// Try to resolve from included actor profile
|
|
102
|
-
if (updateEntity?.["*actor"]) {
|
|
103
|
-
const actorProfile = entitiesByUrn.get(updateEntity["*actor"]);
|
|
104
|
-
if (actorProfile) {
|
|
105
|
-
if (!authorFirstName) {
|
|
106
|
-
authorFirstName = actorProfile.firstName ?? null;
|
|
107
|
-
}
|
|
108
|
-
if (!authorLastName) {
|
|
109
|
-
authorLastName = actorProfile.lastName ?? null;
|
|
110
|
-
}
|
|
111
|
-
if (!authorPublicId) {
|
|
112
|
-
authorPublicId = actorProfile.publicIdentifier ?? null;
|
|
113
|
-
}
|
|
114
|
-
if (!authorHeadline) {
|
|
115
|
-
authorHeadline = resolveTextOrWrapper(actorProfile.headline) ??
|
|
116
|
-
actorProfile.occupation ?? null;
|
|
117
|
-
}
|
|
118
|
-
}
|
|
119
|
-
}
|
|
120
|
-
// Try to extract publicId from actor navigation URL
|
|
121
|
-
if (!authorPublicId && updateEntity?.actor?.navigationUrl) {
|
|
122
|
-
authorPublicId = extractPublicId(updateEntity.actor.navigationUrl);
|
|
123
|
-
}
|
|
124
|
-
// Extract engagement counts
|
|
125
|
-
let reactionCount = 0;
|
|
126
|
-
let commentCount = 0;
|
|
127
|
-
if (updateEntity?.socialDetail && typeof updateEntity.socialDetail === "object") {
|
|
128
|
-
reactionCount =
|
|
129
|
-
updateEntity.socialDetail.totalSocialActivityCounts?.numLikes ?? 0;
|
|
130
|
-
commentCount =
|
|
131
|
-
updateEntity.socialDetail.totalSocialActivityCounts?.numComments ?? 0;
|
|
132
|
-
}
|
|
133
|
-
else {
|
|
134
|
-
reactionCount = updateEntity?.numLikes ?? 0;
|
|
135
|
-
commentCount = updateEntity?.numComments ?? 0;
|
|
136
|
-
}
|
|
137
|
-
posts.push({
|
|
138
|
-
postUrn,
|
|
139
|
-
text,
|
|
140
|
-
authorFirstName,
|
|
141
|
-
authorLastName,
|
|
142
|
-
authorPublicId,
|
|
143
|
-
authorHeadline,
|
|
144
|
-
reactionCount,
|
|
145
|
-
commentCount,
|
|
146
|
-
});
|
|
240
|
+
export async function waitForSearchResults(client, timeoutMs = 15_000) {
|
|
241
|
+
const deadline = Date.now() + timeoutMs;
|
|
242
|
+
while (Date.now() < deadline) {
|
|
243
|
+
const ready = await client.evaluate(`(() => {
|
|
244
|
+
// Search results render as div[role="listitem"] with post menu buttons.
|
|
245
|
+
// Unlike the feed page they are NOT wrapped in data-testid="mainFeed".
|
|
246
|
+
const items = document.querySelectorAll('div[role="listitem"]');
|
|
247
|
+
for (const item of items) {
|
|
248
|
+
if (item.querySelector('button[aria-label^="Open control menu for post"]')) {
|
|
249
|
+
return true;
|
|
147
250
|
}
|
|
251
|
+
}
|
|
252
|
+
return false;
|
|
253
|
+
})()`);
|
|
254
|
+
if (ready)
|
|
255
|
+
return;
|
|
256
|
+
await delay(500);
|
|
148
257
|
}
|
|
149
|
-
|
|
150
|
-
posts,
|
|
151
|
-
paging: {
|
|
152
|
-
start: paging?.start ?? 0,
|
|
153
|
-
count: paging?.count ?? posts.length,
|
|
154
|
-
total: paging?.total ?? posts.length,
|
|
155
|
-
},
|
|
156
|
-
};
|
|
258
|
+
throw new Error("Timed out waiting for search results to appear in the DOM");
|
|
157
259
|
}
|
|
158
260
|
/**
|
|
159
261
|
* Search LinkedIn for posts matching a keyword query.
|
|
160
262
|
*
|
|
161
|
-
* Connects to the LinkedIn webview in LinkedHelper
|
|
162
|
-
*
|
|
263
|
+
* Connects to the LinkedIn webview in LinkedHelper, navigates to the
|
|
264
|
+
* content search page, and extracts posts from the rendered DOM.
|
|
163
265
|
* Supports keyword search, hashtag search, and cursor-based pagination.
|
|
164
266
|
*
|
|
165
267
|
* @param input - Search query, pagination parameters, and CDP connection options.
|
|
166
|
-
* @returns List of matching posts with
|
|
268
|
+
* @returns List of matching posts with cursor for the next page.
|
|
167
269
|
*/
|
|
168
270
|
export async function searchPosts(input) {
|
|
169
|
-
const cdpPort = input.cdpPort
|
|
271
|
+
const cdpPort = await resolveInstancePort(input.cdpPort, input.cdpHost);
|
|
170
272
|
const cdpHost = input.cdpHost ?? "127.0.0.1";
|
|
171
273
|
const allowRemote = input.allowRemote ?? false;
|
|
172
274
|
const count = input.count ?? 10;
|
|
173
|
-
const
|
|
275
|
+
const cursor = input.cursor ?? null;
|
|
174
276
|
if (!input.query.trim()) {
|
|
175
277
|
throw new Error("Search query must not be empty");
|
|
176
278
|
}
|
|
@@ -188,30 +290,127 @@ export async function searchPosts(input) {
|
|
|
188
290
|
const client = new CDPClient(cdpPort, { host: cdpHost, allowRemote });
|
|
189
291
|
await client.connect(linkedInTarget.id);
|
|
190
292
|
try {
|
|
191
|
-
|
|
192
|
-
|
|
193
|
-
|
|
194
|
-
const
|
|
195
|
-
|
|
196
|
-
|
|
197
|
-
|
|
198
|
-
|
|
199
|
-
|
|
200
|
-
|
|
201
|
-
|
|
202
|
-
|
|
203
|
-
|
|
293
|
+
// Navigate away if already on the search page to force a fresh load
|
|
294
|
+
await navigateAwayIf(client, "/search/results/");
|
|
295
|
+
// Navigate to LinkedIn content search
|
|
296
|
+
const searchUrl = new URL("https://www.linkedin.com/search/results/content/");
|
|
297
|
+
searchUrl.searchParams.set("keywords", input.query);
|
|
298
|
+
searchUrl.searchParams.set("origin", "GLOBAL_SEARCH_HEADER");
|
|
299
|
+
await client.navigate(searchUrl.toString());
|
|
300
|
+
// Wait for the search results to render
|
|
301
|
+
await waitForSearchResults(client);
|
|
302
|
+
const mouse = input.mouse ?? null;
|
|
303
|
+
// Collect posts — scroll to load more if needed.
|
|
304
|
+
//
|
|
305
|
+
// Cursor is an index-based offset (e.g. "10" means start from post
|
|
306
|
+
// at index 10). URN-based cursors are not possible because search
|
|
307
|
+
// result posts don't expose URNs in the DOM.
|
|
308
|
+
const maxScrollAttempts = 10;
|
|
309
|
+
let allPosts = [];
|
|
310
|
+
let previousCount = 0;
|
|
311
|
+
const startIdx = cursor ?? 0;
|
|
312
|
+
if (startIdx < 0) {
|
|
313
|
+
throw new Error(`Invalid cursor ${String(cursor)} — must be a non-negative integer offset`);
|
|
314
|
+
}
|
|
315
|
+
for (let scroll = 0; scroll <= maxScrollAttempts; scroll++) {
|
|
316
|
+
const countBeforeScroll = previousCount;
|
|
317
|
+
const scraped = await client.evaluate(SCRAPE_SEARCH_RESULTS_SCRIPT);
|
|
318
|
+
allPosts = scraped ?? [];
|
|
319
|
+
const available = allPosts.length - startIdx;
|
|
320
|
+
if (available >= count)
|
|
321
|
+
break;
|
|
322
|
+
// No new posts appeared after scroll — stop
|
|
323
|
+
if (allPosts.length === previousCount && scroll > 0)
|
|
324
|
+
break;
|
|
325
|
+
previousCount = allPosts.length;
|
|
326
|
+
// Scroll to load more
|
|
327
|
+
if (scroll < maxScrollAttempts) {
|
|
328
|
+
await scrollFeed(client, mouse);
|
|
329
|
+
// Progressive session fatigue: delays increase with each scroll
|
|
330
|
+
const fatigueMultiplier = 1 + scroll * 0.1;
|
|
331
|
+
// Scale delay by newly visible content volume
|
|
332
|
+
const newPostCount = allPosts.length - countBeforeScroll;
|
|
333
|
+
const contentBonus = Math.min(newPostCount * gaussianBetween(350, 75, 200, 500), 3_000);
|
|
334
|
+
await gaussianDelay(1_500 * fatigueMultiplier + contentBonus, 150 * fatigueMultiplier, 1_200 * fatigueMultiplier + contentBonus, 1_800 * fatigueMultiplier + contentBonus);
|
|
335
|
+
// Reading simulation: pause proportional to visible content volume.
|
|
336
|
+
// Estimate ~300 chars per newly visible post (headline + snippet).
|
|
337
|
+
if (newPostCount > 0) {
|
|
338
|
+
await simulateReadingTime(newPostCount * 300);
|
|
339
|
+
}
|
|
340
|
+
await maybeBreak();
|
|
341
|
+
}
|
|
204
342
|
}
|
|
205
|
-
|
|
206
|
-
|
|
207
|
-
|
|
343
|
+
// --- URL extraction via three-dot menu → "Copy link to post" ---
|
|
344
|
+
// Search result posts don't expose URLs in the DOM. For each post
|
|
345
|
+
// with urn === null, open the three-dot menu, click "Copy link to
|
|
346
|
+
// post" which writes the URL to the clipboard.
|
|
347
|
+
//
|
|
348
|
+
// Note: URNs are NOT extractable from search results — only the URL
|
|
349
|
+
// is captured here. Do not attempt to reconstruct URNs from URLs.
|
|
350
|
+
//
|
|
351
|
+
// Electron's clipboard API is broken (readText returns {}) so we
|
|
352
|
+
// monkey-patch navigator.clipboard.writeText to capture into a
|
|
353
|
+
// window global instead.
|
|
354
|
+
const needsUrlExtraction = allPosts.some((p) => p.url === null);
|
|
355
|
+
if (needsUrlExtraction) {
|
|
356
|
+
// Install clipboard interceptor once
|
|
357
|
+
await client.evaluate(`navigator.clipboard.writeText = function(text) {
|
|
358
|
+
window.__capturedClipboard = text;
|
|
359
|
+
return Promise.resolve();
|
|
360
|
+
};`);
|
|
361
|
+
const SEARCH_MENU_BUTTON_SELECTOR = 'div[role="listitem"] button[aria-label^="Open control menu for post"]';
|
|
362
|
+
for (let i = 0; i < allPosts.length; i++) {
|
|
363
|
+
const post = allPosts[i];
|
|
364
|
+
if (!post || post.url)
|
|
365
|
+
continue;
|
|
366
|
+
if (i > 0)
|
|
367
|
+
await gaussianDelay(550, 125, 300, 800); // Inter-post delay
|
|
368
|
+
await maybeBreak();
|
|
369
|
+
const url = await retryInteraction(async () => {
|
|
370
|
+
await maybeHesitate(); // Probabilistic pause before menu interaction
|
|
371
|
+
// Reset capture
|
|
372
|
+
await client.evaluate(`window.__capturedClipboard = null;`);
|
|
373
|
+
// Scroll the menu button into view (humanized when mouse available)
|
|
374
|
+
await humanizedScrollToByIndex(client, SEARCH_MENU_BUTTON_SELECTOR, i, mouse);
|
|
375
|
+
// Click the i-th menu button
|
|
376
|
+
const clicked = await client.evaluate(`(() => {
|
|
377
|
+
const btns = document.querySelectorAll(
|
|
378
|
+
${JSON.stringify(SEARCH_MENU_BUTTON_SELECTOR)}
|
|
379
|
+
);
|
|
380
|
+
const btn = btns[${String(i)}];
|
|
381
|
+
if (!btn) return false;
|
|
382
|
+
btn.click();
|
|
383
|
+
return true;
|
|
384
|
+
})()`);
|
|
385
|
+
if (!clicked)
|
|
386
|
+
return null;
|
|
387
|
+
await gaussianDelay(700, 100, 500, 900);
|
|
388
|
+
// Click "Copy link to post" menu item
|
|
389
|
+
await client.evaluate(`(() => {
|
|
390
|
+
for (const el of document.querySelectorAll('[role="menuitem"]')) {
|
|
391
|
+
if (el.textContent.trim() === 'Copy link to post') {
|
|
392
|
+
el.click();
|
|
393
|
+
return;
|
|
394
|
+
}
|
|
395
|
+
}
|
|
396
|
+
})()`);
|
|
397
|
+
await gaussianDelay(550, 75, 400, 700);
|
|
398
|
+
// Read captured URL
|
|
399
|
+
return client.evaluate(`window.__capturedClipboard`);
|
|
400
|
+
});
|
|
401
|
+
if (url) {
|
|
402
|
+
post.url = url.split("?")[0] ?? url;
|
|
403
|
+
}
|
|
404
|
+
}
|
|
208
405
|
}
|
|
209
|
-
|
|
210
|
-
|
|
211
|
-
|
|
212
|
-
|
|
213
|
-
|
|
214
|
-
|
|
406
|
+
// Slice the result window
|
|
407
|
+
const window = allPosts.slice(startIdx, startIdx + count);
|
|
408
|
+
const posts = mapRawPosts(window);
|
|
409
|
+
// Determine next cursor (index-based offset)
|
|
410
|
+
const hasMore = startIdx + count < allPosts.length;
|
|
411
|
+
const nextCursor = hasMore ? startIdx + count : null;
|
|
412
|
+
await gaussianDelay(800, 300, 300, 1_800); // Post-action dwell
|
|
413
|
+
return { query: input.query, posts, nextCursor };
|
|
215
414
|
}
|
|
216
415
|
finally {
|
|
217
416
|
client.disconnect();
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"search-posts.js","sourceRoot":"","sources":["../../src/operations/search-posts.ts"],"names":[],"mappings":"AAAA,yCAAyC;AACzC,oCAAoC;
|
|
1
|
+
{"version":3,"file":"search-posts.js","sourceRoot":"","sources":["../../src/operations/search-posts.ts"],"names":[],"mappings":"AAAA,yCAAyC;AACzC,oCAAoC;AAEpC,OAAO,EAAE,mBAAmB,EAAE,MAAM,iBAAiB,CAAC;AAEtD,OAAO,EAAE,SAAS,EAAE,MAAM,kBAAkB,CAAC;AAC7C,OAAO,EAAE,eAAe,EAAE,MAAM,qBAAqB,CAAC;AAEtD,OAAO,EAAE,cAAc,EAAE,MAAM,oBAAoB,CAAC;AACpD,OAAO,EAAE,aAAa,EAAE,eAAe,EAAE,aAAa,EAAE,UAAU,EAAE,mBAAmB,EAAE,MAAM,mBAAmB,CAAC;AACnH,OAAO,EAAE,wBAAwB,EAAE,gBAAgB,EAAE,MAAM,+BAA+B,CAAC;AAE3F,OAAO,EAEL,WAAW,EACX,UAAU,EACV,KAAK,GACN,MAAM,eAAe,CAAC;AA4BvB,8EAA8E;AAC9E,sCAAsC;AACtC,8EAA8E;AAE9E;;;;;;;;;GASG;AACH,MAAM,4BAA4B,GAAG;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;KA2MhC,CAAC;AAEN,8EAA8E;AAC9E,kCAAkC;AAClC,8EAA8E;AAE9E;;;;;;;;;GASG;AACH,MAAM,CAAC,KAAK,UAAU,oBAAoB,CACxC,MAAiB,EACjB,SAAS,GAAG,MAAM;IAElB,MAAM,QAAQ,GAAG,IAAI,CAAC,GAAG,EAAE,GAAG,SAAS,CAAC;IACxC,OAAO,IAAI,CAAC,GAAG,EAAE,GAAG,QAAQ,EAAE,CAAC;QAC7B,MAAM,KAAK,GAAG,MAAM,MAAM,CAAC,QAAQ,CAAU;;;;;;;;;;SAUxC,CAAC,CAAC;QACP,IAAI,KAAK;YAAE,OAAO;QAClB,MAAM,KAAK,CAAC,GAAG,CAAC,CAAC;IACnB,CAAC;IACD,MAAM,IAAI,KAAK,CACb,2DAA2D,CAC5D,CAAC;AACJ,CAAC;AAED;;;;;;;;;GASG;AACH,MAAM,CAAC,KAAK,UAAU,WAAW,CAC/B,KAAuB;IAEvB,MAAM,OAAO,GAAG,MAAM,mBAAmB,CAAC,KAAK,CAAC,OAAO,EAAE,KAAK,CAAC,OAAO,CAAC,CAAC;IACxE,MAAM,OAAO,GAAG,KAAK,CAAC,OAAO,IAAI,WAAW,CAAC;IAC7C,MAAM,WAAW,GAAG,KAAK,CAAC,WAAW,IAAI,KAAK,CAAC;IAC/C,MAAM,KAAK,GAAG,KAAK,CAAC,KAAK,IAAI,EAAE,CAAC;IAChC,MAAM,MAAM,GAAG,KAAK,CAAC,MAAM,IAAI,IAAI,CAAC;IAEpC,IAAI,CAAC,KAAK,CAAC,KAAK,CAAC,IAAI,EAAE,EAAE,CAAC;QACxB,MAAM,IAAI,KAAK,CAAC,gCAAgC,CAAC,CAAC;IACpD,CAAC;IAED,yBAAyB;IACzB,IAAI,CAAC,WAAW,IAAI,OAAO,KAAK,WAAW,IAAI,OAAO,KAAK,WAAW,EAAE,CAAC;QACvE,MAAM,IAAI,KAAK,CACb,0BAA0B,OAAO,6BAA6B;YAC5D,8DAA8D,CACjE,CAAC;IACJ,CAAC;IAED,MAAM,OAAO,GAAG,MAAM,eAAe,CAAC,OAAO,EAAE,OAAO,CAAC,CAAC;IACxD,MAAM,cAAc,GAAG,OAAO,CAAC,IAAI,CACjC,CAAC,CAAC,EAAE,EAAE,CAAC,CAAC,CAAC,IAAI,KAAK,MAAM,IAAI,CAAC,CAAC,GAAG,EAAE,QAAQ,CAAC,cAAc,CAAC,CAC5D,CAAC;IAEF,IAAI,CAAC,cAAc,EAAE,CAAC;QACpB,MAAM,IAAI,KAAK,CACb,0CAA0C;YACxC,iEAAiE,CACpE,CAAC;IACJ,CAAC;IAED,MAAM,MAAM,GAAG,IAAI,SAAS,CAAC,OAAO,EAAE,EAAE,IAAI,EAAE,OAAO,EAAE,WAAW,EAAE,CAAC,CAAC;IACtE,MAAM,MAAM,CAAC,OAAO,CAAC,cAAc,CAAC,EAAE,CAAC,CAAC;IAExC,IAAI,CAAC;QACH,oEAAoE;QACpE,MAAM,cAAc,CAAC,MAAM,EAAE,kBAAkB,CAAC,CAAC;QAEjD,sCAAsC;QACtC,MAAM,SAAS,GAAG,IAAI,GAAG,CACvB,kDAAkD,CACnD,CAAC;QACF,SAAS,CAAC,YAAY,CAAC,GAAG,CAAC,UAAU,EAAE,KAAK,CAAC,KAAK,CAAC,CAAC;QACpD,SAAS,CAAC,YAAY,CAAC,GAAG,CAAC,QAAQ,EAAE,sBAAsB,CAAC,CAAC;QAC7D,MAAM,MAAM,CAAC,QAAQ,CAAC,SAAS,CAAC,QAAQ,EAAE,CAAC,CAAC;QAE5C,wCAAwC;QACxC,MAAM,oBAAoB,CAAC,MAAM,CAAC,CAAC;QAEnC,MAAM,KAAK,GAAG,KAAK,CAAC,KAAK,IAAI,IAAI,CAAC;QAElC,iDAAiD;QACjD,EAAE;QACF,mEAAmE;QACnE,mEAAmE;QACnE,6CAA6C;QAC7C,MAAM,iBAAiB,GAAG,EAAE,CAAC;QAC7B,IAAI,QAAQ,GAAiB,EAAE,CAAC;QAChC,IAAI,aAAa,GAAG,CAAC,CAAC;QAEtB,MAAM,QAAQ,GAAG,MAAM,IAAI,CAAC,CAAC;QAC7B,IAAI,QAAQ,GAAG,CAAC,EAAE,CAAC;YACjB,MAAM,IAAI,KAAK,CAAC,kBAAkB,MAAM,CAAC,MAAM,CAAC,0CAA0C,CAAC,CAAC;QAC9F,CAAC;QAED,KAAK,IAAI,MAAM,GAAG,CAAC,EAAE,MAAM,IAAI,iBAAiB,EAAE,MAAM,EAAE,EAAE,CAAC;YAC3D,MAAM,iBAAiB,GAAG,aAAa,CAAC;YACxC,MAAM,OAAO,GACX,MAAM,MAAM,CAAC,QAAQ,CAAe,4BAA4B,CAAC,CAAC;YACpE,QAAQ,GAAG,OAAO,IAAI,EAAE,CAAC;YAEzB,MAAM,SAAS,GAAG,QAAQ,CAAC,MAAM,GAAG,QAAQ,CAAC;YAC7C,IAAI,SAAS,IAAI,KAAK;gBAAE,MAAM;YAE9B,4CAA4C;YAC5C,IAAI,QAAQ,CAAC,MAAM,KAAK,aAAa,IAAI,MAAM,GAAG,CAAC;gBAAE,MAAM;YAC3D,aAAa,GAAG,QAAQ,CAAC,MAAM,CAAC;YAEhC,sBAAsB;YACtB,IAAI,MAAM,GAAG,iBAAiB,EAAE,CAAC;gBAC/B,MAAM,UAAU,CAAC,MAAM,EAAE,KAAK,CAAC,CAAC;gBAEhC,gEAAgE;gBAChE,MAAM,iBAAiB,GAAG,CAAC,GAAG,MAAM,GAAG,GAAG,CAAC;gBAC3C,8CAA8C;gBAC9C,MAAM,YAAY,GAAG,QAAQ,CAAC,MAAM,GAAG,iBAAiB,CAAC;gBACzD,MAAM,YAAY,GAAG,IAAI,CAAC,GAAG,CAC3B,YAAY,GAAG,eAAe,CAAC,GAAG,EAAE,EAAE,EAAE,GAAG,EAAE,GAAG,CAAC,EACjD,KAAK,CACN,CAAC;gBACF,MAAM,aAAa,CACjB,KAAK,GAAG,iBAAiB,GAAG,YAAY,EACxC,GAAG,GAAG,iBAAiB,EACvB,KAAK,GAAG,iBAAiB,GAAG,YAAY,EACxC,KAAK,GAAG,iBAAiB,GAAG,YAAY,CACzC,CAAC;gBAEF,oEAAoE;gBACpE,mEAAmE;gBACnE,IAAI,YAAY,GAAG,CAAC,EAAE,CAAC;oBACrB,MAAM,mBAAmB,CAAC,YAAY,GAAG,GAAG,CAAC,CAAC;gBAChD,CAAC;gBAED,MAAM,UAAU,EAAE,CAAC;YACrB,CAAC;QACH,CAAC;QAED,kEAAkE;QAClE,mEAAmE;QACnE,kEAAkE;QAClE,+CAA+C;QAC/C,EAAE;QACF,oEAAoE;QACpE,mEAAmE;QACnE,EAAE;QACF,iEAAiE;QACjE,+DAA+D;QAC/D,yBAAyB;QACzB,MAAM,kBAAkB,GAAG,QAAQ,CAAC,IAAI,CAAC,CAAC,CAAC,EAAE,EAAE,CAAC,CAAC,CAAC,GAAG,KAAK,IAAI,CAAC,CAAC;QAChE,IAAI,kBAAkB,EAAE,CAAC;YACvB,qCAAqC;YACrC,MAAM,MAAM,CAAC,QAAQ,CACnB;;;WAGG,CACJ,CAAC;YAEF,MAAM,2BAA2B,GAC/B,uEAAuE,CAAC;YAE1E,KAAK,IAAI,CAAC,GAAG,CAAC,EAAE,CAAC,GAAG,QAAQ,CAAC,MAAM,EAAE,CAAC,EAAE,EAAE,CAAC;gBACzC,MAAM,IAAI,GAAG,QAAQ,CAAC,CAAC,CAAC,CAAC;gBACzB,IAAI,CAAC,IAAI,IAAI,IAAI,CAAC,GAAG;oBAAE,SAAS;gBAEhC,IAAI,CAAC,GAAG,CAAC;oBAAE,MAAM,aAAa,CAAC,GAAG,EAAE,GAAG,EAAE,GAAG,EAAE,GAAG,CAAC,CAAC,CAAC,mBAAmB;gBACvE,MAAM,UAAU,EAAE,CAAC;gBAEnB,MAAM,GAAG,GAAG,MAAM,gBAAgB,CAAC,KAAK,IAAI,EAAE;oBAC5C,MAAM,aAAa,EAAE,CAAC,CAAC,8CAA8C;oBAErE,gBAAgB;oBAChB,MAAM,MAAM,CAAC,QAAQ,CAAC,oCAAoC,CAAC,CAAC;oBAE5D,oEAAoE;oBACpE,MAAM,wBAAwB,CAAC,MAAM,EAAE,2BAA2B,EAAE,CAAC,EAAE,KAAK,CAAC,CAAC;oBAE9E,6BAA6B;oBAC7B,MAAM,OAAO,GAAG,MAAM,MAAM,CAAC,QAAQ,CAAU;;gBAEzC,IAAI,CAAC,SAAS,CAAC,2BAA2B,CAAC;;+BAE5B,MAAM,CAAC,CAAC,CAAC;;;;eAIzB,CAAC,CAAC;oBACP,IAAI,CAAC,OAAO;wBAAE,OAAO,IAAI,CAAC;oBAE1B,MAAM,aAAa,CAAC,GAAG,EAAE,GAAG,EAAE,GAAG,EAAE,GAAG,CAAC,CAAC;oBAExC,sCAAsC;oBACtC,MAAM,MAAM,CAAC,QAAQ,CAAC;;;;;;;eAOjB,CAAC,CAAC;oBAEP,MAAM,aAAa,CAAC,GAAG,EAAE,EAAE,EAAE,GAAG,EAAE,GAAG,CAAC,CAAC;oBAEvC,oBAAoB;oBACpB,OAAO,MAAM,CAAC,QAAQ,CAAgB,4BAA4B,CAAC,CAAC;gBACtE,CAAC,CAAC,CAAC;gBAEH,IAAI,GAAG,EAAE,CAAC;oBACR,IAAI,CAAC,GAAG,GAAG,GAAG,CAAC,KAAK,CAAC,GAAG,CAAC,CAAC,CAAC,CAAC,IAAI,GAAG,CAAC;gBACtC,CAAC;YACH,CAAC;QACH,CAAC;QAED,0BAA0B;QAC1B,MAAM,MAAM,GAAG,QAAQ,CAAC,KAAK,CAAC,QAAQ,EAAE,QAAQ,GAAG,KAAK,CAAC,CAAC;QAC1D,MAAM,KAAK,GAAG,WAAW,CAAC,MAAM,CAAC,CAAC;QAElC,6CAA6C;QAC7C,MAAM,OAAO,GAAG,QAAQ,GAAG,KAAK,GAAG,QAAQ,CAAC,MAAM,CAAC;QACnD,MAAM,UAAU,GAAG,OAAO,CAAC,CAAC,CAAC,QAAQ,GAAG,KAAK,CAAC,CAAC,CAAC,IAAI,CAAC;QAErD,MAAM,aAAa,CAAC,GAAG,EAAE,GAAG,EAAE,GAAG,EAAE,KAAK,CAAC,CAAC,CAAC,oBAAoB;QAC/D,OAAO,EAAE,KAAK,EAAE,KAAK,CAAC,KAAK,EAAE,KAAK,EAAE,UAAU,EAAE,CAAC;IACnD,CAAC;YAAS,CAAC;QACT,MAAM,CAAC,UAAU,EAAE,CAAC;IACtB,CAAC;AACH,CAAC"}
|