@lhremote/core 0.7.0 → 0.8.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/db/index.d.ts +1 -1
- package/dist/db/index.d.ts.map +1 -1
- package/dist/db/index.js +1 -1
- package/dist/db/index.js.map +1 -1
- package/dist/db/repositories/action-budget.d.ts +29 -0
- package/dist/db/repositories/action-budget.d.ts.map +1 -0
- package/dist/db/repositories/action-budget.js +100 -0
- package/dist/db/repositories/action-budget.js.map +1 -0
- package/dist/db/repositories/action-budget.test.d.ts +2 -0
- package/dist/db/repositories/action-budget.test.d.ts.map +1 -0
- package/dist/db/repositories/action-budget.test.js +181 -0
- package/dist/db/repositories/action-budget.test.js.map +1 -0
- package/dist/db/repositories/campaign-hard-delete.integration.test.d.ts +2 -0
- package/dist/db/repositories/campaign-hard-delete.integration.test.d.ts.map +1 -0
- package/dist/db/repositories/campaign-hard-delete.integration.test.js +78 -0
- package/dist/db/repositories/campaign-hard-delete.integration.test.js.map +1 -0
- package/dist/db/repositories/campaign.d.ts +14 -0
- package/dist/db/repositories/campaign.d.ts.map +1 -1
- package/dist/db/repositories/campaign.js +125 -0
- package/dist/db/repositories/campaign.js.map +1 -1
- package/dist/db/repositories/index.d.ts +1 -0
- package/dist/db/repositories/index.d.ts.map +1 -1
- package/dist/db/repositories/index.js +1 -0
- package/dist/db/repositories/index.js.map +1 -1
- package/dist/index.d.ts +5 -4
- package/dist/index.d.ts.map +1 -1
- package/dist/index.js +24 -4
- package/dist/index.js.map +1 -1
- package/dist/linkedin/__tests__/dom-automation.integration.test.d.ts +2 -0
- package/dist/linkedin/__tests__/dom-automation.integration.test.d.ts.map +1 -0
- package/dist/linkedin/__tests__/dom-automation.integration.test.js +160 -0
- package/dist/linkedin/__tests__/dom-automation.integration.test.js.map +1 -0
- package/dist/linkedin/__tests__/selectors.integration.test.d.ts +2 -0
- package/dist/linkedin/__tests__/selectors.integration.test.d.ts.map +1 -0
- package/dist/linkedin/__tests__/selectors.integration.test.js +258 -0
- package/dist/linkedin/__tests__/selectors.integration.test.js.map +1 -0
- package/dist/linkedin/dom-automation.d.ts +67 -0
- package/dist/linkedin/dom-automation.d.ts.map +1 -0
- package/dist/linkedin/dom-automation.js +139 -0
- package/dist/linkedin/dom-automation.js.map +1 -0
- package/dist/linkedin/index.d.ts +3 -0
- package/dist/linkedin/index.d.ts.map +1 -0
- package/dist/linkedin/index.js +5 -0
- package/dist/linkedin/index.js.map +1 -0
- package/dist/linkedin/selectors.d.ts +67 -0
- package/dist/linkedin/selectors.d.ts.map +1 -0
- package/dist/linkedin/selectors.js +74 -0
- package/dist/linkedin/selectors.js.map +1 -0
- package/dist/operations/campaign-delete.d.ts +6 -2
- package/dist/operations/campaign-delete.d.ts.map +1 -1
- package/dist/operations/campaign-delete.js +9 -2
- package/dist/operations/campaign-delete.js.map +1 -1
- package/dist/operations/campaign-delete.test.js +41 -1
- package/dist/operations/campaign-delete.test.js.map +1 -1
- package/dist/operations/campaign-erase.d.ts +19 -0
- package/dist/operations/campaign-erase.d.ts.map +1 -0
- package/dist/operations/campaign-erase.js +22 -0
- package/dist/operations/campaign-erase.js.map +1 -0
- package/dist/operations/campaign-erase.test.d.ts +2 -0
- package/dist/operations/campaign-erase.test.d.ts.map +1 -0
- package/dist/operations/campaign-erase.test.js +101 -0
- package/dist/operations/campaign-erase.test.js.map +1 -0
- package/dist/operations/comment-on-post.d.ts +34 -0
- package/dist/operations/comment-on-post.d.ts.map +1 -0
- package/dist/operations/comment-on-post.js +108 -0
- package/dist/operations/comment-on-post.js.map +1 -0
- package/dist/operations/comment-on-post.test.d.ts +2 -0
- package/dist/operations/comment-on-post.test.d.ts.map +1 -0
- package/dist/operations/comment-on-post.test.js +240 -0
- package/dist/operations/comment-on-post.test.js.map +1 -0
- package/dist/operations/dismiss-errors.d.ts +22 -0
- package/dist/operations/dismiss-errors.d.ts.map +1 -0
- package/dist/operations/dismiss-errors.js +55 -0
- package/dist/operations/dismiss-errors.js.map +1 -0
- package/dist/operations/dismiss-errors.test.d.ts +2 -0
- package/dist/operations/dismiss-errors.test.d.ts.map +1 -0
- package/dist/operations/dismiss-errors.test.js +136 -0
- package/dist/operations/dismiss-errors.test.js.map +1 -0
- package/dist/operations/endorse-skills.d.ts +10 -0
- package/dist/operations/endorse-skills.d.ts.map +1 -0
- package/dist/operations/endorse-skills.js +12 -0
- package/dist/operations/endorse-skills.js.map +1 -0
- package/dist/operations/enrich-profile.d.ts +18 -0
- package/dist/operations/enrich-profile.d.ts.map +1 -0
- package/dist/operations/enrich-profile.js +15 -0
- package/dist/operations/enrich-profile.js.map +1 -0
- package/dist/operations/ephemeral-action.d.ts +22 -0
- package/dist/operations/ephemeral-action.d.ts.map +1 -0
- package/dist/operations/ephemeral-action.js +31 -0
- package/dist/operations/ephemeral-action.js.map +1 -0
- package/dist/operations/follow-person.d.ts +9 -0
- package/dist/operations/follow-person.d.ts.map +1 -0
- package/dist/operations/follow-person.js +11 -0
- package/dist/operations/follow-person.js.map +1 -0
- package/dist/operations/get-action-budget.d.ts +6 -0
- package/dist/operations/get-action-budget.d.ts.map +1 -0
- package/dist/operations/get-action-budget.js +22 -0
- package/dist/operations/get-action-budget.js.map +1 -0
- package/dist/operations/get-action-budget.test.d.ts +2 -0
- package/dist/operations/get-action-budget.test.d.ts.map +1 -0
- package/dist/operations/get-action-budget.test.js +79 -0
- package/dist/operations/get-action-budget.test.js.map +1 -0
- package/dist/operations/get-errors.d.ts +9 -3
- package/dist/operations/get-errors.d.ts.map +1 -1
- package/dist/operations/get-errors.js +41 -4
- package/dist/operations/get-errors.js.map +1 -1
- package/dist/operations/get-errors.test.js +108 -42
- package/dist/operations/get-errors.test.js.map +1 -1
- package/dist/operations/get-feed.d.ts +33 -0
- package/dist/operations/get-feed.d.ts.map +1 -0
- package/dist/operations/get-feed.js +220 -0
- package/dist/operations/get-feed.js.map +1 -0
- package/dist/operations/get-feed.test.d.ts +2 -0
- package/dist/operations/get-feed.test.d.ts.map +1 -0
- package/dist/operations/get-feed.test.js +276 -0
- package/dist/operations/get-feed.test.js.map +1 -0
- package/dist/operations/get-post-engagers.d.ts +40 -0
- package/dist/operations/get-post-engagers.d.ts.map +1 -0
- package/dist/operations/get-post-engagers.js +128 -0
- package/dist/operations/get-post-engagers.js.map +1 -0
- package/dist/operations/get-post-engagers.test.d.ts +2 -0
- package/dist/operations/get-post-engagers.test.d.ts.map +1 -0
- package/dist/operations/get-post-engagers.test.js +19 -0
- package/dist/operations/get-post-engagers.test.js.map +1 -0
- package/dist/operations/get-post-stats.d.ts +38 -0
- package/dist/operations/get-post-stats.d.ts.map +1 -0
- package/dist/operations/get-post-stats.js +100 -0
- package/dist/operations/get-post-stats.js.map +1 -0
- package/dist/operations/get-post-stats.test.d.ts +2 -0
- package/dist/operations/get-post-stats.test.d.ts.map +1 -0
- package/dist/operations/get-post-stats.test.js +34 -0
- package/dist/operations/get-post-stats.test.js.map +1 -0
- package/dist/operations/get-post.d.ts +183 -0
- package/dist/operations/get-post.d.ts.map +1 -0
- package/dist/operations/get-post.js +270 -0
- package/dist/operations/get-post.js.map +1 -0
- package/dist/operations/get-post.test.d.ts +2 -0
- package/dist/operations/get-post.test.d.ts.map +1 -0
- package/dist/operations/get-post.test.js +449 -0
- package/dist/operations/get-post.test.js.map +1 -0
- package/dist/operations/get-profile-activity.d.ts +129 -0
- package/dist/operations/get-profile-activity.d.ts.map +1 -0
- package/dist/operations/get-profile-activity.js +181 -0
- package/dist/operations/get-profile-activity.js.map +1 -0
- package/dist/operations/get-profile-activity.test.d.ts +2 -0
- package/dist/operations/get-profile-activity.test.d.ts.map +1 -0
- package/dist/operations/get-profile-activity.test.js +205 -0
- package/dist/operations/get-profile-activity.test.js.map +1 -0
- package/dist/operations/get-throttle-status.d.ts +6 -0
- package/dist/operations/get-throttle-status.d.ts.map +1 -0
- package/dist/operations/get-throttle-status.js +30 -0
- package/dist/operations/get-throttle-status.js.map +1 -0
- package/dist/operations/get-throttle-status.test.d.ts +2 -0
- package/dist/operations/get-throttle-status.test.d.ts.map +1 -0
- package/dist/operations/get-throttle-status.test.js +62 -0
- package/dist/operations/get-throttle-status.test.js.map +1 -0
- package/dist/operations/index.d.ts +22 -0
- package/dist/operations/index.d.ts.map +1 -1
- package/dist/operations/index.js +32 -0
- package/dist/operations/index.js.map +1 -1
- package/dist/operations/like-person-posts.d.ts +14 -0
- package/dist/operations/like-person-posts.d.ts.map +1 -0
- package/dist/operations/like-person-posts.js +28 -0
- package/dist/operations/like-person-posts.js.map +1 -0
- package/dist/operations/message-person.d.ts +11 -0
- package/dist/operations/message-person.d.ts.map +1 -0
- package/dist/operations/message-person.js +19 -0
- package/dist/operations/message-person.js.map +1 -0
- package/dist/operations/react-to-post.d.ts +38 -0
- package/dist/operations/react-to-post.d.ts.map +1 -0
- package/dist/operations/react-to-post.js +82 -0
- package/dist/operations/react-to-post.js.map +1 -0
- package/dist/operations/react-to-post.test.d.ts +2 -0
- package/dist/operations/react-to-post.test.d.ts.map +1 -0
- package/dist/operations/react-to-post.test.js +154 -0
- package/dist/operations/react-to-post.test.js.map +1 -0
- package/dist/operations/remove-connection.d.ts +6 -0
- package/dist/operations/remove-connection.d.ts.map +1 -0
- package/dist/operations/remove-connection.js +7 -0
- package/dist/operations/remove-connection.js.map +1 -0
- package/dist/operations/search-posts.d.ts +143 -0
- package/dist/operations/search-posts.d.ts.map +1 -0
- package/dist/operations/search-posts.js +220 -0
- package/dist/operations/search-posts.js.map +1 -0
- package/dist/operations/search-posts.test.d.ts +2 -0
- package/dist/operations/search-posts.test.d.ts.map +1 -0
- package/dist/operations/search-posts.test.js +261 -0
- package/dist/operations/search-posts.test.js.map +1 -0
- package/dist/operations/send-inmail.d.ts +11 -0
- package/dist/operations/send-inmail.d.ts.map +1 -0
- package/dist/operations/send-inmail.js +19 -0
- package/dist/operations/send-inmail.js.map +1 -0
- package/dist/operations/send-invite.d.ts +9 -0
- package/dist/operations/send-invite.d.ts.map +1 -0
- package/dist/operations/send-invite.js +14 -0
- package/dist/operations/send-invite.js.map +1 -0
- package/dist/operations/visit-profile.d.ts +14 -0
- package/dist/operations/visit-profile.d.ts.map +1 -0
- package/dist/operations/visit-profile.js +49 -0
- package/dist/operations/visit-profile.js.map +1 -0
- package/dist/operations/visit-profile.test.d.ts +2 -0
- package/dist/operations/visit-profile.test.d.ts.map +1 -0
- package/dist/operations/visit-profile.test.js +193 -0
- package/dist/operations/visit-profile.test.js.map +1 -0
- package/dist/services/campaign.d.ts +10 -0
- package/dist/services/campaign.d.ts.map +1 -1
- package/dist/services/campaign.js +16 -0
- package/dist/services/campaign.js.map +1 -1
- package/dist/services/collection.d.ts +5 -2
- package/dist/services/collection.d.ts.map +1 -1
- package/dist/services/collection.js +24 -5
- package/dist/services/collection.js.map +1 -1
- package/dist/services/collection.test.js +51 -9
- package/dist/services/collection.test.js.map +1 -1
- package/dist/services/ephemeral-campaign.d.ts +64 -0
- package/dist/services/ephemeral-campaign.d.ts.map +1 -0
- package/dist/services/ephemeral-campaign.js +210 -0
- package/dist/services/ephemeral-campaign.js.map +1 -0
- package/dist/services/ephemeral-campaign.test.d.ts +2 -0
- package/dist/services/ephemeral-campaign.test.d.ts.map +1 -0
- package/dist/services/ephemeral-campaign.test.js +333 -0
- package/dist/services/ephemeral-campaign.test.js.map +1 -0
- package/dist/services/errors.d.ts +10 -0
- package/dist/services/errors.d.ts.map +1 -1
- package/dist/services/errors.js +20 -0
- package/dist/services/errors.js.map +1 -1
- package/dist/services/index.d.ts +3 -1
- package/dist/services/index.d.ts.map +1 -1
- package/dist/services/index.js +3 -1
- package/dist/services/index.js.map +1 -1
- package/dist/services/instance-context.d.ts.map +1 -1
- package/dist/services/instance-context.js +9 -1
- package/dist/services/instance-context.js.map +1 -1
- package/dist/services/instance-context.test.js +77 -1
- package/dist/services/instance-context.test.js.map +1 -1
- package/dist/services/instance.d.ts +31 -0
- package/dist/services/instance.d.ts.map +1 -1
- package/dist/services/instance.js +123 -0
- package/dist/services/instance.js.map +1 -1
- package/dist/services/instance.test.js +70 -0
- package/dist/services/instance.test.js.map +1 -1
- package/dist/services/launcher.d.ts +7 -0
- package/dist/services/launcher.d.ts.map +1 -1
- package/dist/services/launcher.js +18 -1
- package/dist/services/launcher.js.map +1 -1
- package/dist/types/action-budget.d.ts +52 -0
- package/dist/types/action-budget.d.ts.map +1 -0
- package/dist/types/action-budget.js +4 -0
- package/dist/types/action-budget.js.map +1 -0
- package/dist/types/campaign.d.ts +24 -0
- package/dist/types/campaign.d.ts.map +1 -1
- package/dist/types/feed.d.ts +32 -0
- package/dist/types/feed.d.ts.map +1 -0
- package/dist/types/feed.js +4 -0
- package/dist/types/feed.js.map +1 -0
- package/dist/types/index.d.ts +7 -2
- package/dist/types/index.d.ts.map +1 -1
- package/dist/types/post-analytics.d.ts +40 -0
- package/dist/types/post-analytics.d.ts.map +1 -0
- package/dist/types/post-analytics.js +4 -0
- package/dist/types/post-analytics.js.map +1 -0
- package/dist/types/post.d.ts +43 -0
- package/dist/types/post.d.ts.map +1 -0
- package/dist/types/post.js +4 -0
- package/dist/types/post.js.map +1 -0
- package/dist/types/search-posts.d.ts +22 -0
- package/dist/types/search-posts.d.ts.map +1 -0
- package/dist/types/search-posts.js +4 -0
- package/dist/types/search-posts.js.map +1 -0
- package/dist/types/ui-health.d.ts +16 -0
- package/dist/types/ui-health.d.ts.map +1 -1
- package/dist/voyager/index.d.ts +2 -0
- package/dist/voyager/index.d.ts.map +1 -0
- package/dist/voyager/index.js +4 -0
- package/dist/voyager/index.js.map +1 -0
- package/dist/voyager/interceptor.d.ts +100 -0
- package/dist/voyager/interceptor.d.ts.map +1 -0
- package/dist/voyager/interceptor.integration.test.d.ts +2 -0
- package/dist/voyager/interceptor.integration.test.d.ts.map +1 -0
- package/dist/voyager/interceptor.integration.test.js +89 -0
- package/dist/voyager/interceptor.integration.test.js.map +1 -0
- package/dist/voyager/interceptor.js +235 -0
- package/dist/voyager/interceptor.js.map +1 -0
- package/dist/voyager/interceptor.test.d.ts +2 -0
- package/dist/voyager/interceptor.test.d.ts.map +1 -0
- package/dist/voyager/interceptor.test.js +372 -0
- package/dist/voyager/interceptor.test.js.map +1 -0
- package/package.json +1 -1
|
@@ -0,0 +1,100 @@
|
|
|
1
|
+
import type { CDPClient } from "../cdp/client.js";
|
|
2
|
+
/** URL pattern matching LinkedIn Voyager API endpoints. */
|
|
3
|
+
export declare const VOYAGER_URL_PATTERN: RegExp;
|
|
4
|
+
/**
|
|
5
|
+
* A captured Voyager API response.
|
|
6
|
+
*/
|
|
7
|
+
export interface VoyagerResponse {
|
|
8
|
+
/** The full request URL. */
|
|
9
|
+
readonly url: string;
|
|
10
|
+
/** HTTP status code. */
|
|
11
|
+
readonly status: number;
|
|
12
|
+
/** Parsed JSON response body, or raw string if JSON parsing failed. */
|
|
13
|
+
readonly body: unknown;
|
|
14
|
+
}
|
|
15
|
+
/**
|
|
16
|
+
* Callback for intercepted Voyager API responses.
|
|
17
|
+
*/
|
|
18
|
+
export type VoyagerResponseHandler = (response: VoyagerResponse) => void;
|
|
19
|
+
/**
|
|
20
|
+
* Options for active Voyager API fetching.
|
|
21
|
+
*/
|
|
22
|
+
export interface VoyagerFetchOptions {
|
|
23
|
+
/** Additional HTTP headers to include in the request. */
|
|
24
|
+
readonly headers?: Readonly<Record<string, string>>;
|
|
25
|
+
}
|
|
26
|
+
/**
|
|
27
|
+
* CDP Network domain listener for LinkedIn Voyager API responses.
|
|
28
|
+
*
|
|
29
|
+
* Intercepts HTTP responses matching the Voyager API URL pattern
|
|
30
|
+
* (`/voyager/api/`) via the Chrome DevTools Protocol Network domain.
|
|
31
|
+
*
|
|
32
|
+
* Two modes of operation:
|
|
33
|
+
* - **Passive**: Enable the interceptor and register handlers to capture
|
|
34
|
+
* Voyager responses triggered by page navigation, scrolling, or user
|
|
35
|
+
* interaction within the LinkedIn WebView.
|
|
36
|
+
* - **Active**: Use {@link fetch} to execute Voyager API requests directly
|
|
37
|
+
* in the page context (which has the LinkedIn session cookies).
|
|
38
|
+
*
|
|
39
|
+
* The interceptor is read-only — it does not modify requests or responses,
|
|
40
|
+
* so it coexists safely with LinkedHelper's mockttp proxy.
|
|
41
|
+
*/
|
|
42
|
+
export declare class VoyagerInterceptor {
|
|
43
|
+
private readonly client;
|
|
44
|
+
private readonly handlers;
|
|
45
|
+
private readonly pendingRequests;
|
|
46
|
+
private interceptEnabled;
|
|
47
|
+
constructor(client: CDPClient);
|
|
48
|
+
/** Whether passive interception is currently enabled. */
|
|
49
|
+
get isEnabled(): boolean;
|
|
50
|
+
/**
|
|
51
|
+
* Enable the CDP Network domain and start intercepting Voyager responses.
|
|
52
|
+
*
|
|
53
|
+
* Subscribes to `Network.responseReceived`, `Network.loadingFinished`,
|
|
54
|
+
* and `Network.loadingFailed` events. Responses matching the Voyager
|
|
55
|
+
* URL pattern are captured and emitted to registered handlers.
|
|
56
|
+
*/
|
|
57
|
+
enable(): Promise<void>;
|
|
58
|
+
/**
|
|
59
|
+
* Disable the CDP Network domain and stop intercepting.
|
|
60
|
+
*
|
|
61
|
+
* Cleans up event listeners and pending request state.
|
|
62
|
+
*/
|
|
63
|
+
disable(): Promise<void>;
|
|
64
|
+
/**
|
|
65
|
+
* Register a handler for passively intercepted Voyager responses.
|
|
66
|
+
*/
|
|
67
|
+
onResponse(handler: VoyagerResponseHandler): void;
|
|
68
|
+
/**
|
|
69
|
+
* Remove a previously registered response handler.
|
|
70
|
+
*/
|
|
71
|
+
offResponse(handler: VoyagerResponseHandler): void;
|
|
72
|
+
/**
|
|
73
|
+
* Wait for the next Voyager response matching an optional URL filter.
|
|
74
|
+
*
|
|
75
|
+
* Requires the interceptor to be {@link enable}d.
|
|
76
|
+
*
|
|
77
|
+
* @param filter - Optional predicate applied to the response URL.
|
|
78
|
+
* @param timeout - Maximum wait time in ms (default: 30 000).
|
|
79
|
+
*/
|
|
80
|
+
waitForResponse(filter?: (url: string) => boolean, timeout?: number): Promise<VoyagerResponse>;
|
|
81
|
+
/**
|
|
82
|
+
* Execute a Voyager API request in the LinkedIn page context.
|
|
83
|
+
*
|
|
84
|
+
* Runs `fetch()` inside the WebView where LinkedIn session cookies are
|
|
85
|
+
* available, automatically extracting the CSRF token from cookies.
|
|
86
|
+
*
|
|
87
|
+
* Does not require the interceptor to be {@link enable}d — works
|
|
88
|
+
* independently of the Network domain.
|
|
89
|
+
*
|
|
90
|
+
* @param path - Voyager API path (e.g. `/voyager/api/feed/dash/feedUpdates`).
|
|
91
|
+
* Full URLs starting with `https://` are also accepted.
|
|
92
|
+
* @param options - Optional fetch configuration.
|
|
93
|
+
*/
|
|
94
|
+
fetch(path: string, options?: VoyagerFetchOptions): Promise<VoyagerResponse>;
|
|
95
|
+
private handleResponseReceived;
|
|
96
|
+
private handleLoadingFinished;
|
|
97
|
+
private handleLoadingFailed;
|
|
98
|
+
private fetchAndEmitBody;
|
|
99
|
+
}
|
|
100
|
+
//# sourceMappingURL=interceptor.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"interceptor.d.ts","sourceRoot":"","sources":["../../src/voyager/interceptor.ts"],"names":[],"mappings":"AAGA,OAAO,KAAK,EAAE,SAAS,EAAE,MAAM,kBAAkB,CAAC;AAGlD,2DAA2D;AAC3D,eAAO,MAAM,mBAAmB,QAAqB,CAAC;AAKtD;;GAEG;AACH,MAAM,WAAW,eAAe;IAC9B,4BAA4B;IAC5B,QAAQ,CAAC,GAAG,EAAE,MAAM,CAAC;IACrB,wBAAwB;IACxB,QAAQ,CAAC,MAAM,EAAE,MAAM,CAAC;IACxB,uEAAuE;IACvE,QAAQ,CAAC,IAAI,EAAE,OAAO,CAAC;CACxB;AAED;;GAEG;AACH,MAAM,MAAM,sBAAsB,GAAG,CAAC,QAAQ,EAAE,eAAe,KAAK,IAAI,CAAC;AAEzE;;GAEG;AACH,MAAM,WAAW,mBAAmB;IAClC,yDAAyD;IACzD,QAAQ,CAAC,OAAO,CAAC,EAAE,QAAQ,CAAC,MAAM,CAAC,MAAM,EAAE,MAAM,CAAC,CAAC,CAAC;CACrD;AAUD;;;;;;;;;;;;;;;GAeG;AACH,qBAAa,kBAAkB;IAC7B,OAAO,CAAC,QAAQ,CAAC,MAAM,CAAY;IACnC,OAAO,CAAC,QAAQ,CAAC,QAAQ,CAAqC;IAC9D,OAAO,CAAC,QAAQ,CAAC,eAAe,CAG5B;IACJ,OAAO,CAAC,gBAAgB,CAAS;gBAErB,MAAM,EAAE,SAAS;IAI7B,yDAAyD;IACzD,IAAI,SAAS,IAAI,OAAO,CAEvB;IAED;;;;;;OAMG;IACG,MAAM,IAAI,OAAO,CAAC,IAAI,CAAC;IAS7B;;;;OAIG;IACG,OAAO,IAAI,OAAO,CAAC,IAAI,CAAC;IAU9B;;OAEG;IACH,UAAU,CAAC,OAAO,EAAE,sBAAsB,GAAG,IAAI;IAIjD;;OAEG;IACH,WAAW,CAAC,OAAO,EAAE,sBAAsB,GAAG,IAAI;IAIlD;;;;;;;OAOG;IACG,eAAe,CACnB,MAAM,CAAC,EAAE,CAAC,GAAG,EAAE,MAAM,KAAK,OAAO,EACjC,OAAO,CAAC,EAAE,MAAM,GACf,OAAO,CAAC,eAAe,CAAC;IA2B3B;;;;;;;;;;;;OAYG;IACG,KAAK,CACT,IAAI,EAAE,MAAM,EACZ,OAAO,CAAC,EAAE,mBAAmB,GAC5B,OAAO,CAAC,eAAe,CAAC;IAyE3B,OAAO,CAAC,sBAAsB,CAY5B;IAEF,OAAO,CAAC,qBAAqB,CAO3B;IAEF,OAAO,CAAC,mBAAmB,CAGzB;YAEY,gBAAgB;CAqC/B"}
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"interceptor.integration.test.d.ts","sourceRoot":"","sources":["../../src/voyager/interceptor.integration.test.ts"],"names":[],"mappings":""}
|
|
@@ -0,0 +1,89 @@
|
|
|
1
|
+
// SPDX-License-Identifier: AGPL-3.0-only
|
|
2
|
+
// Copyright (C) 2026 Oleksii PELYKH
|
|
3
|
+
import { createServer } from "node:http";
|
|
4
|
+
import { afterAll, afterEach, beforeAll, describe, expect, it } from "vitest";
|
|
5
|
+
import { CDPClient } from "../cdp/client.js";
|
|
6
|
+
import { launchChromium, } from "../cdp/testing/launch-chromium.js";
|
|
7
|
+
import { VoyagerInterceptor } from "./interceptor.js";
|
|
8
|
+
describe("VoyagerInterceptor (integration)", () => {
|
|
9
|
+
let chromium;
|
|
10
|
+
let server;
|
|
11
|
+
let serverPort;
|
|
12
|
+
let client;
|
|
13
|
+
let interceptor;
|
|
14
|
+
beforeAll(async () => {
|
|
15
|
+
chromium = await launchChromium();
|
|
16
|
+
// Start a minimal local HTTP server to avoid external network dependency
|
|
17
|
+
// (http://example.com caused Windows CI timeouts)
|
|
18
|
+
server = createServer((_req, res) => {
|
|
19
|
+
res.writeHead(200, { "Content-Type": "text/html" });
|
|
20
|
+
res.end("<html></html>");
|
|
21
|
+
});
|
|
22
|
+
await new Promise((resolve) => server.listen(0, resolve));
|
|
23
|
+
serverPort = server.address().port;
|
|
24
|
+
}, 30_000);
|
|
25
|
+
afterAll(async () => {
|
|
26
|
+
await chromium.close();
|
|
27
|
+
server.close();
|
|
28
|
+
});
|
|
29
|
+
afterEach(async () => {
|
|
30
|
+
if (interceptor?.isEnabled) {
|
|
31
|
+
await interceptor.disable();
|
|
32
|
+
}
|
|
33
|
+
client?.disconnect();
|
|
34
|
+
});
|
|
35
|
+
describe("enable / disable", () => {
|
|
36
|
+
it("should enable and disable without error on a real browser", async () => {
|
|
37
|
+
client = new CDPClient(chromium.port);
|
|
38
|
+
await client.connect();
|
|
39
|
+
interceptor = new VoyagerInterceptor(client);
|
|
40
|
+
await interceptor.enable();
|
|
41
|
+
expect(interceptor.isEnabled).toBe(true);
|
|
42
|
+
await interceptor.disable();
|
|
43
|
+
expect(interceptor.isEnabled).toBe(false);
|
|
44
|
+
});
|
|
45
|
+
});
|
|
46
|
+
describe("passive interception", () => {
|
|
47
|
+
it("should capture responses matching Voyager URL pattern", async () => {
|
|
48
|
+
client = new CDPClient(chromium.port);
|
|
49
|
+
await client.connect();
|
|
50
|
+
interceptor = new VoyagerInterceptor(client);
|
|
51
|
+
// Navigate to the local HTTP server so we have an origin for fetch
|
|
52
|
+
await client.send("Page.enable");
|
|
53
|
+
const loadPromise = client.waitForEvent("Page.loadEventFired");
|
|
54
|
+
await client.navigate(`http://localhost:${serverPort.toString()}`);
|
|
55
|
+
await loadPromise;
|
|
56
|
+
await client.send("Page.disable").catch(() => { });
|
|
57
|
+
await interceptor.enable();
|
|
58
|
+
// Use waitForResponse for deterministic waiting instead of setTimeout
|
|
59
|
+
const responsePromise = interceptor.waitForResponse(undefined, 5000);
|
|
60
|
+
// Trigger a fetch from within the page to a URL containing /voyager/api/
|
|
61
|
+
// The local server responds with 200 to any path
|
|
62
|
+
await client.evaluate(`fetch("/voyager/api/test-endpoint").catch(() => {})`, true);
|
|
63
|
+
const captured = await responsePromise;
|
|
64
|
+
expect(captured.url).toContain("/voyager/api/");
|
|
65
|
+
});
|
|
66
|
+
});
|
|
67
|
+
describe("waitForResponse", () => {
|
|
68
|
+
it("should resolve when a matching response arrives", async () => {
|
|
69
|
+
client = new CDPClient(chromium.port);
|
|
70
|
+
await client.connect();
|
|
71
|
+
interceptor = new VoyagerInterceptor(client);
|
|
72
|
+
// Navigate to the local HTTP server so we have an origin for fetch
|
|
73
|
+
await client.send("Page.enable");
|
|
74
|
+
const loadPromise = client.waitForEvent("Page.loadEventFired");
|
|
75
|
+
await client.navigate(`http://localhost:${serverPort.toString()}`);
|
|
76
|
+
await loadPromise;
|
|
77
|
+
await client.send("Page.disable").catch(() => { });
|
|
78
|
+
await interceptor.enable();
|
|
79
|
+
// Start waiting before triggering the fetch
|
|
80
|
+
const responsePromise = interceptor.waitForResponse(undefined, 5000);
|
|
81
|
+
// Trigger a fetch matching the voyager pattern
|
|
82
|
+
await client.evaluate(`fetch("/voyager/api/integration-test").catch(() => {})`, true);
|
|
83
|
+
const response = await responsePromise;
|
|
84
|
+
expect(response.url).toContain("/voyager/api/");
|
|
85
|
+
expect(response.status).toEqual(expect.any(Number));
|
|
86
|
+
});
|
|
87
|
+
});
|
|
88
|
+
});
|
|
89
|
+
//# sourceMappingURL=interceptor.integration.test.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"interceptor.integration.test.js","sourceRoot":"","sources":["../../src/voyager/interceptor.integration.test.ts"],"names":[],"mappings":"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"}
|
|
@@ -0,0 +1,235 @@
|
|
|
1
|
+
// SPDX-License-Identifier: AGPL-3.0-only
|
|
2
|
+
// Copyright (C) 2026 Oleksii PELYKH
|
|
3
|
+
import { CDPEvaluationError, CDPTimeoutError } from "../cdp/errors.js";
|
|
4
|
+
/** URL pattern matching LinkedIn Voyager API endpoints. */
|
|
5
|
+
export const VOYAGER_URL_PATTERN = /\/voyager\/api\//;
|
|
6
|
+
/** Default timeout for response wait operations (ms). */
|
|
7
|
+
const DEFAULT_TIMEOUT = 30_000;
|
|
8
|
+
/**
|
|
9
|
+
* CDP Network domain listener for LinkedIn Voyager API responses.
|
|
10
|
+
*
|
|
11
|
+
* Intercepts HTTP responses matching the Voyager API URL pattern
|
|
12
|
+
* (`/voyager/api/`) via the Chrome DevTools Protocol Network domain.
|
|
13
|
+
*
|
|
14
|
+
* Two modes of operation:
|
|
15
|
+
* - **Passive**: Enable the interceptor and register handlers to capture
|
|
16
|
+
* Voyager responses triggered by page navigation, scrolling, or user
|
|
17
|
+
* interaction within the LinkedIn WebView.
|
|
18
|
+
* - **Active**: Use {@link fetch} to execute Voyager API requests directly
|
|
19
|
+
* in the page context (which has the LinkedIn session cookies).
|
|
20
|
+
*
|
|
21
|
+
* The interceptor is read-only — it does not modify requests or responses,
|
|
22
|
+
* so it coexists safely with LinkedHelper's mockttp proxy.
|
|
23
|
+
*/
|
|
24
|
+
export class VoyagerInterceptor {
|
|
25
|
+
client;
|
|
26
|
+
handlers = new Set();
|
|
27
|
+
pendingRequests = new Map();
|
|
28
|
+
interceptEnabled = false;
|
|
29
|
+
constructor(client) {
|
|
30
|
+
this.client = client;
|
|
31
|
+
}
|
|
32
|
+
/** Whether passive interception is currently enabled. */
|
|
33
|
+
get isEnabled() {
|
|
34
|
+
return this.interceptEnabled;
|
|
35
|
+
}
|
|
36
|
+
/**
|
|
37
|
+
* Enable the CDP Network domain and start intercepting Voyager responses.
|
|
38
|
+
*
|
|
39
|
+
* Subscribes to `Network.responseReceived`, `Network.loadingFinished`,
|
|
40
|
+
* and `Network.loadingFailed` events. Responses matching the Voyager
|
|
41
|
+
* URL pattern are captured and emitted to registered handlers.
|
|
42
|
+
*/
|
|
43
|
+
async enable() {
|
|
44
|
+
if (this.interceptEnabled)
|
|
45
|
+
return;
|
|
46
|
+
await this.client.send("Network.enable");
|
|
47
|
+
this.client.on("Network.responseReceived", this.handleResponseReceived);
|
|
48
|
+
this.client.on("Network.loadingFinished", this.handleLoadingFinished);
|
|
49
|
+
this.client.on("Network.loadingFailed", this.handleLoadingFailed);
|
|
50
|
+
this.interceptEnabled = true;
|
|
51
|
+
}
|
|
52
|
+
/**
|
|
53
|
+
* Disable the CDP Network domain and stop intercepting.
|
|
54
|
+
*
|
|
55
|
+
* Cleans up event listeners and pending request state.
|
|
56
|
+
*/
|
|
57
|
+
async disable() {
|
|
58
|
+
if (!this.interceptEnabled)
|
|
59
|
+
return;
|
|
60
|
+
this.interceptEnabled = false;
|
|
61
|
+
this.client.off("Network.responseReceived", this.handleResponseReceived);
|
|
62
|
+
this.client.off("Network.loadingFinished", this.handleLoadingFinished);
|
|
63
|
+
this.client.off("Network.loadingFailed", this.handleLoadingFailed);
|
|
64
|
+
this.pendingRequests.clear();
|
|
65
|
+
await this.client.send("Network.disable").catch(() => { });
|
|
66
|
+
}
|
|
67
|
+
/**
|
|
68
|
+
* Register a handler for passively intercepted Voyager responses.
|
|
69
|
+
*/
|
|
70
|
+
onResponse(handler) {
|
|
71
|
+
this.handlers.add(handler);
|
|
72
|
+
}
|
|
73
|
+
/**
|
|
74
|
+
* Remove a previously registered response handler.
|
|
75
|
+
*/
|
|
76
|
+
offResponse(handler) {
|
|
77
|
+
this.handlers.delete(handler);
|
|
78
|
+
}
|
|
79
|
+
/**
|
|
80
|
+
* Wait for the next Voyager response matching an optional URL filter.
|
|
81
|
+
*
|
|
82
|
+
* Requires the interceptor to be {@link enable}d.
|
|
83
|
+
*
|
|
84
|
+
* @param filter - Optional predicate applied to the response URL.
|
|
85
|
+
* @param timeout - Maximum wait time in ms (default: 30 000).
|
|
86
|
+
*/
|
|
87
|
+
async waitForResponse(filter, timeout) {
|
|
88
|
+
if (!this.interceptEnabled) {
|
|
89
|
+
throw new Error("VoyagerInterceptor is not enabled — call enable() before waitForResponse()");
|
|
90
|
+
}
|
|
91
|
+
const ms = timeout ?? DEFAULT_TIMEOUT;
|
|
92
|
+
return new Promise((resolve, reject) => {
|
|
93
|
+
const timer = setTimeout(() => {
|
|
94
|
+
this.offResponse(handler);
|
|
95
|
+
reject(new CDPTimeoutError("Timed out waiting for Voyager response"));
|
|
96
|
+
}, ms);
|
|
97
|
+
const handler = (response) => {
|
|
98
|
+
if (!filter || filter(response.url)) {
|
|
99
|
+
clearTimeout(timer);
|
|
100
|
+
this.offResponse(handler);
|
|
101
|
+
resolve(response);
|
|
102
|
+
}
|
|
103
|
+
};
|
|
104
|
+
this.onResponse(handler);
|
|
105
|
+
});
|
|
106
|
+
}
|
|
107
|
+
/**
|
|
108
|
+
* Execute a Voyager API request in the LinkedIn page context.
|
|
109
|
+
*
|
|
110
|
+
* Runs `fetch()` inside the WebView where LinkedIn session cookies are
|
|
111
|
+
* available, automatically extracting the CSRF token from cookies.
|
|
112
|
+
*
|
|
113
|
+
* Does not require the interceptor to be {@link enable}d — works
|
|
114
|
+
* independently of the Network domain.
|
|
115
|
+
*
|
|
116
|
+
* @param path - Voyager API path (e.g. `/voyager/api/feed/dash/feedUpdates`).
|
|
117
|
+
* Full URLs starting with `https://` are also accepted.
|
|
118
|
+
* @param options - Optional fetch configuration.
|
|
119
|
+
*/
|
|
120
|
+
async fetch(path, options) {
|
|
121
|
+
const fullUrl = path.startsWith("https://")
|
|
122
|
+
? path
|
|
123
|
+
: `https://www.linkedin.com${path.startsWith("/") ? "" : "/"}${path}`;
|
|
124
|
+
// Guard: only send credentials to LinkedIn origins
|
|
125
|
+
const parsed = new URL(fullUrl);
|
|
126
|
+
if (parsed.hostname !== "www.linkedin.com" &&
|
|
127
|
+
parsed.hostname !== "linkedin.com" &&
|
|
128
|
+
!parsed.hostname.endsWith(".linkedin.com")) {
|
|
129
|
+
throw new Error(`Voyager fetch restricted to linkedin.com origins, got: ${parsed.hostname}`);
|
|
130
|
+
}
|
|
131
|
+
const extraHeaders = JSON.stringify(options?.headers ?? {});
|
|
132
|
+
const result = await this.client.evaluate(`(async () => {
|
|
133
|
+
try {
|
|
134
|
+
const jsessionid = document.cookie
|
|
135
|
+
.split(";")
|
|
136
|
+
.map(c => c.trim())
|
|
137
|
+
.find(c => c.startsWith("JSESSIONID="));
|
|
138
|
+
let csrfToken = jsessionid
|
|
139
|
+
? jsessionid.substring(jsessionid.indexOf("=") + 1).replace(/"/g, "")
|
|
140
|
+
: "";
|
|
141
|
+
if (!csrfToken.startsWith("ajax:")) {
|
|
142
|
+
csrfToken = "ajax:" + csrfToken;
|
|
143
|
+
}
|
|
144
|
+
|
|
145
|
+
const response = await fetch(${JSON.stringify(fullUrl)}, {
|
|
146
|
+
headers: {
|
|
147
|
+
"Csrf-Token": csrfToken,
|
|
148
|
+
"X-RestLi-Protocol-Version": "2.0.0",
|
|
149
|
+
...${extraHeaders},
|
|
150
|
+
},
|
|
151
|
+
credentials: "include",
|
|
152
|
+
});
|
|
153
|
+
|
|
154
|
+
const text = await response.text();
|
|
155
|
+
let body;
|
|
156
|
+
try {
|
|
157
|
+
body = JSON.parse(text);
|
|
158
|
+
} catch {
|
|
159
|
+
body = text;
|
|
160
|
+
}
|
|
161
|
+
|
|
162
|
+
return { url: response.url, status: response.status, body };
|
|
163
|
+
} catch (e) {
|
|
164
|
+
return { url: ${JSON.stringify(fullUrl)}, status: 0, body: null, error: String(e) };
|
|
165
|
+
}
|
|
166
|
+
})()`, true);
|
|
167
|
+
if (result.error) {
|
|
168
|
+
throw new CDPEvaluationError(`Voyager fetch failed: ${result.error}`);
|
|
169
|
+
}
|
|
170
|
+
return {
|
|
171
|
+
url: result.url,
|
|
172
|
+
status: result.status,
|
|
173
|
+
body: result.body,
|
|
174
|
+
};
|
|
175
|
+
}
|
|
176
|
+
// ---------------------------------------------------------------------------
|
|
177
|
+
// Private — CDP event handlers
|
|
178
|
+
// ---------------------------------------------------------------------------
|
|
179
|
+
handleResponseReceived = (params) => {
|
|
180
|
+
const { requestId, response } = params;
|
|
181
|
+
if (VOYAGER_URL_PATTERN.test(response.url)) {
|
|
182
|
+
this.pendingRequests.set(requestId, {
|
|
183
|
+
url: response.url,
|
|
184
|
+
status: response.status,
|
|
185
|
+
});
|
|
186
|
+
}
|
|
187
|
+
};
|
|
188
|
+
handleLoadingFinished = (params) => {
|
|
189
|
+
const { requestId } = params;
|
|
190
|
+
const pending = this.pendingRequests.get(requestId);
|
|
191
|
+
if (!pending)
|
|
192
|
+
return;
|
|
193
|
+
this.pendingRequests.delete(requestId);
|
|
194
|
+
void this.fetchAndEmitBody(requestId, pending);
|
|
195
|
+
};
|
|
196
|
+
handleLoadingFailed = (params) => {
|
|
197
|
+
const { requestId } = params;
|
|
198
|
+
this.pendingRequests.delete(requestId);
|
|
199
|
+
};
|
|
200
|
+
async fetchAndEmitBody(requestId, meta) {
|
|
201
|
+
let body;
|
|
202
|
+
try {
|
|
203
|
+
const result = (await this.client.send("Network.getResponseBody", {
|
|
204
|
+
requestId,
|
|
205
|
+
}));
|
|
206
|
+
const raw = result.base64Encoded
|
|
207
|
+
? Buffer.from(result.body, "base64").toString("utf8")
|
|
208
|
+
: result.body;
|
|
209
|
+
try {
|
|
210
|
+
body = JSON.parse(raw);
|
|
211
|
+
}
|
|
212
|
+
catch {
|
|
213
|
+
body = raw;
|
|
214
|
+
}
|
|
215
|
+
}
|
|
216
|
+
catch {
|
|
217
|
+
// Body retrieval can fail for cached or evicted responses — skip silently
|
|
218
|
+
return;
|
|
219
|
+
}
|
|
220
|
+
const response = {
|
|
221
|
+
url: meta.url,
|
|
222
|
+
status: meta.status,
|
|
223
|
+
body,
|
|
224
|
+
};
|
|
225
|
+
for (const handler of this.handlers) {
|
|
226
|
+
try {
|
|
227
|
+
handler(response);
|
|
228
|
+
}
|
|
229
|
+
catch {
|
|
230
|
+
// Isolate handler errors so one failing handler doesn't block others
|
|
231
|
+
}
|
|
232
|
+
}
|
|
233
|
+
}
|
|
234
|
+
}
|
|
235
|
+
//# sourceMappingURL=interceptor.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"interceptor.js","sourceRoot":"","sources":["../../src/voyager/interceptor.ts"],"names":[],"mappings":"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"}
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"interceptor.test.d.ts","sourceRoot":"","sources":["../../src/voyager/interceptor.test.ts"],"names":[],"mappings":""}
|