@lobu/connector-sdk 6.0.1
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/dist/api-paginated.d.ts +79 -0
- package/dist/api-paginated.d.ts.map +1 -0
- package/dist/api-paginated.js +120 -0
- package/dist/api-paginated.js.map +1 -0
- package/dist/base.d.ts +66 -0
- package/dist/base.d.ts.map +1 -0
- package/dist/base.js +122 -0
- package/dist/base.js.map +1 -0
- package/dist/browser/acquire.d.ts +66 -0
- package/dist/browser/acquire.d.ts.map +1 -0
- package/dist/browser/acquire.js +109 -0
- package/dist/browser/acquire.js.map +1 -0
- package/dist/browser/cdp-page.d.ts +48 -0
- package/dist/browser/cdp-page.d.ts.map +1 -0
- package/dist/browser/cdp-page.js +165 -0
- package/dist/browser/cdp-page.js.map +1 -0
- package/dist/browser/cdp.d.ts +44 -0
- package/dist/browser/cdp.d.ts.map +1 -0
- package/dist/browser/cdp.js +252 -0
- package/dist/browser/cdp.js.map +1 -0
- package/dist/browser/launcher.d.ts +29 -0
- package/dist/browser/launcher.d.ts.map +1 -0
- package/dist/browser/launcher.js +157 -0
- package/dist/browser/launcher.js.map +1 -0
- package/dist/browser/stealth.d.ts +55 -0
- package/dist/browser/stealth.d.ts.map +1 -0
- package/dist/browser/stealth.js +170 -0
- package/dist/browser/stealth.js.map +1 -0
- package/dist/browser-network.d.ts +51 -0
- package/dist/browser-network.d.ts.map +1 -0
- package/dist/browser-network.js +175 -0
- package/dist/browser-network.js.map +1 -0
- package/dist/browser-paginated.d.ts +141 -0
- package/dist/browser-paginated.d.ts.map +1 -0
- package/dist/browser-paginated.js +269 -0
- package/dist/browser-paginated.js.map +1 -0
- package/dist/connector-runtime.d.ts +70 -0
- package/dist/connector-runtime.d.ts.map +1 -0
- package/dist/connector-runtime.js +48 -0
- package/dist/connector-runtime.js.map +1 -0
- package/dist/connector-types.d.ts +613 -0
- package/dist/connector-types.d.ts.map +1 -0
- package/dist/connector-types.js +27 -0
- package/dist/connector-types.js.map +1 -0
- package/dist/event-taxonomy.d.ts +3 -0
- package/dist/event-taxonomy.d.ts.map +1 -0
- package/dist/event-taxonomy.js +30 -0
- package/dist/event-taxonomy.js.map +1 -0
- package/dist/http.d.ts +18 -0
- package/dist/http.d.ts.map +1 -0
- package/dist/http.js +74 -0
- package/dist/http.js.map +1 -0
- package/dist/identity-normalize.d.ts +53 -0
- package/dist/identity-normalize.d.ts.map +1 -0
- package/dist/identity-normalize.js +146 -0
- package/dist/identity-normalize.js.map +1 -0
- package/dist/identity-types.d.ts +214 -0
- package/dist/identity-types.d.ts.map +1 -0
- package/dist/identity-types.js +217 -0
- package/dist/identity-types.js.map +1 -0
- package/dist/index.d.ts +37 -0
- package/dist/index.d.ts.map +1 -0
- package/dist/index.js +33 -0
- package/dist/index.js.map +1 -0
- package/dist/logger.d.ts +7 -0
- package/dist/logger.d.ts.map +1 -0
- package/dist/logger.js +10 -0
- package/dist/logger.js.map +1 -0
- package/dist/paginated.d.ts +93 -0
- package/dist/paginated.d.ts.map +1 -0
- package/dist/paginated.js +167 -0
- package/dist/paginated.js.map +1 -0
- package/dist/reaction-sdk.d.ts +43 -0
- package/dist/reaction-sdk.d.ts.map +1 -0
- package/dist/reaction-sdk.js +9 -0
- package/dist/reaction-sdk.js.map +1 -0
- package/dist/retry.d.ts +19 -0
- package/dist/retry.d.ts.map +1 -0
- package/dist/retry.js +131 -0
- package/dist/retry.js.map +1 -0
- package/dist/scoring.d.ts +17 -0
- package/dist/scoring.d.ts.map +1 -0
- package/dist/scoring.js +28 -0
- package/dist/scoring.js.map +1 -0
- package/dist/types.d.ts +280 -0
- package/dist/types.d.ts.map +1 -0
- package/dist/types.js +2 -0
- package/dist/types.js.map +1 -0
- package/dist/watcher-time.d.ts +14 -0
- package/dist/watcher-time.d.ts.map +1 -0
- package/dist/watcher-time.js +112 -0
- package/dist/watcher-time.js.map +1 -0
- package/package.json +59 -0
|
@@ -0,0 +1,79 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* API Paginated Feed Base Class
|
|
3
|
+
*
|
|
4
|
+
* Extends PaginatedFeed for HTTP/REST API-based feeds.
|
|
5
|
+
* Provides HTTP client setup and common API patterns.
|
|
6
|
+
*/
|
|
7
|
+
import type { KyInstance } from 'ky';
|
|
8
|
+
import { HTTPError } from 'ky';
|
|
9
|
+
import type { PageFetchResult, PaginatedCheckpoint } from './paginated.js';
|
|
10
|
+
import { PaginatedFeed } from './paginated.js';
|
|
11
|
+
import type { Env, FeedOptions, SessionState } from './types.js';
|
|
12
|
+
/**
|
|
13
|
+
* API session state for OAuth/token-based feeds
|
|
14
|
+
*/
|
|
15
|
+
export interface ApiSessionState extends SessionState {
|
|
16
|
+
/** OAuth/API access token */
|
|
17
|
+
access_token?: string;
|
|
18
|
+
/** OAuth refresh token (for token refresh flows) */
|
|
19
|
+
refresh_token?: string;
|
|
20
|
+
/** Token type (e.g., 'Bearer') */
|
|
21
|
+
token_type?: string;
|
|
22
|
+
/** Token expiration time (ISO string) */
|
|
23
|
+
expires_at?: string;
|
|
24
|
+
/** Additional headers to include in requests */
|
|
25
|
+
headers?: Record<string, string>;
|
|
26
|
+
/** API key (alternative to OAuth tokens) */
|
|
27
|
+
api_key?: string;
|
|
28
|
+
}
|
|
29
|
+
/**
|
|
30
|
+
* Base class for API-based feeds with HTTP pagination
|
|
31
|
+
*/
|
|
32
|
+
export declare abstract class ApiPaginatedFeed<TItem, TResponse = unknown, TCheckpoint extends PaginatedCheckpoint = PaginatedCheckpoint> extends PaginatedFeed<TItem, TCheckpoint> {
|
|
33
|
+
readonly apiType: "api";
|
|
34
|
+
/**
|
|
35
|
+
* Session state for this sync session
|
|
36
|
+
*/
|
|
37
|
+
protected _sessionState: ApiSessionState | null;
|
|
38
|
+
/**
|
|
39
|
+
* Set session state for this sync session
|
|
40
|
+
*/
|
|
41
|
+
protected setSessionState(sessionState: SessionState | null | undefined): void;
|
|
42
|
+
/**
|
|
43
|
+
* Get current session state
|
|
44
|
+
*/
|
|
45
|
+
protected getSessionState(): ApiSessionState | null;
|
|
46
|
+
/**
|
|
47
|
+
* ABSTRACT: Build URL for fetching a specific page
|
|
48
|
+
*/
|
|
49
|
+
protected abstract buildPageUrl(cursor: string | null, options: FeedOptions): string;
|
|
50
|
+
/**
|
|
51
|
+
* ABSTRACT: Parse API response into items and next token
|
|
52
|
+
*/
|
|
53
|
+
protected abstract parseResponse(response: TResponse, options: FeedOptions): PageFetchResult<TItem>;
|
|
54
|
+
/**
|
|
55
|
+
* Get configured HTTP client for this feed
|
|
56
|
+
*/
|
|
57
|
+
protected getHttpClient(_env: Env): KyInstance;
|
|
58
|
+
/**
|
|
59
|
+
* Create HTTP client with Bearer token authentication
|
|
60
|
+
*/
|
|
61
|
+
protected createBearerClient(token: string, additionalHeaders?: Record<string, string>): KyInstance;
|
|
62
|
+
/**
|
|
63
|
+
* Create HTTP client with custom headers
|
|
64
|
+
*/
|
|
65
|
+
protected createClientWithHeaders(headers: Record<string, string>): KyInstance;
|
|
66
|
+
/**
|
|
67
|
+
* Create HTTP client from session state
|
|
68
|
+
*/
|
|
69
|
+
protected createClientFromSessionState(additionalHeaders?: Record<string, string>): KyInstance;
|
|
70
|
+
/**
|
|
71
|
+
* Handle HTTP errors with platform-specific messages
|
|
72
|
+
*/
|
|
73
|
+
protected handleHttpError(error: HTTPError, url: string): never;
|
|
74
|
+
/**
|
|
75
|
+
* Default fetchPage implementation using HTTP client with retry
|
|
76
|
+
*/
|
|
77
|
+
protected fetchPage(cursor: string | null, options: FeedOptions, env: Env): Promise<PageFetchResult<TItem>>;
|
|
78
|
+
}
|
|
79
|
+
//# sourceMappingURL=api-paginated.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"api-paginated.d.ts","sourceRoot":"","sources":["../src/api-paginated.ts"],"names":[],"mappings":"AAAA;;;;;GAKG;AAEH,OAAO,KAAK,EAAE,UAAU,EAAE,MAAM,IAAI,CAAC;AACrC,OAAO,EAAE,SAAS,EAAE,MAAM,IAAI,CAAC;AAI/B,OAAO,KAAK,EAAE,eAAe,EAAE,mBAAmB,EAAE,MAAM,gBAAgB,CAAC;AAC3E,OAAO,EAAE,aAAa,EAAE,MAAM,gBAAgB,CAAC;AAE/C,OAAO,KAAK,EAAE,GAAG,EAAE,WAAW,EAAE,YAAY,EAAE,MAAM,YAAY,CAAC;AAEjE;;GAEG;AACH,MAAM,WAAW,eAAgB,SAAQ,YAAY;IACnD,6BAA6B;IAC7B,YAAY,CAAC,EAAE,MAAM,CAAC;IACtB,oDAAoD;IACpD,aAAa,CAAC,EAAE,MAAM,CAAC;IACvB,kCAAkC;IAClC,UAAU,CAAC,EAAE,MAAM,CAAC;IACpB,yCAAyC;IACzC,UAAU,CAAC,EAAE,MAAM,CAAC;IACpB,gDAAgD;IAChD,OAAO,CAAC,EAAE,MAAM,CAAC,MAAM,EAAE,MAAM,CAAC,CAAC;IACjC,4CAA4C;IAC5C,OAAO,CAAC,EAAE,MAAM,CAAC;CAClB;AAED;;GAEG;AACH,8BAAsB,gBAAgB,CACpC,KAAK,EACL,SAAS,GAAG,OAAO,EACnB,WAAW,SAAS,mBAAmB,GAAG,mBAAmB,CAC7D,SAAQ,aAAa,CAAC,KAAK,EAAE,WAAW,CAAC;IACzC,QAAQ,CAAC,OAAO,EAAG,KAAK,CAAU;IAElC;;OAEG;IACH,SAAS,CAAC,aAAa,EAAE,eAAe,GAAG,IAAI,CAAQ;IAEvD;;OAEG;IACH,SAAS,CAAC,eAAe,CAAC,YAAY,EAAE,YAAY,GAAG,IAAI,GAAG,SAAS,GAAG,IAAI;IAU9E;;OAEG;IACH,SAAS,CAAC,eAAe,IAAI,eAAe,GAAG,IAAI;IAInD;;OAEG;IACH,SAAS,CAAC,QAAQ,CAAC,YAAY,CAAC,MAAM,EAAE,MAAM,GAAG,IAAI,EAAE,OAAO,EAAE,WAAW,GAAG,MAAM;IAEpF;;OAEG;IACH,SAAS,CAAC,QAAQ,CAAC,aAAa,CAC9B,QAAQ,EAAE,SAAS,EACnB,OAAO,EAAE,WAAW,GACnB,eAAe,CAAC,KAAK,CAAC;IAEzB;;OAEG;IACH,SAAS,CAAC,aAAa,CAAC,IAAI,EAAE,GAAG,GAAG,UAAU;IAI9C;;OAEG;IACH,SAAS,CAAC,kBAAkB,CAC1B,KAAK,EAAE,MAAM,EACb,iBAAiB,CAAC,EAAE,MAAM,CAAC,MAAM,EAAE,MAAM,CAAC,GACzC,UAAU;IAIb;;OAEG;IACH,SAAS,CAAC,uBAAuB,CAAC,OAAO,EAAE,MAAM,CAAC,MAAM,EAAE,MAAM,CAAC,GAAG,UAAU;IAI9E;;OAEG;IACH,SAAS,CAAC,4BAA4B,CAAC,iBAAiB,CAAC,EAAE,MAAM,CAAC,MAAM,EAAE,MAAM,CAAC,GAAG,UAAU;IAsB9F;;OAEG;IACH,SAAS,CAAC,eAAe,CAAC,KAAK,EAAE,SAAS,EAAE,GAAG,EAAE,MAAM,GAAG,KAAK;IAI/D;;OAEG;cACa,SAAS,CACvB,MAAM,EAAE,MAAM,GAAG,IAAI,EACrB,OAAO,EAAE,WAAW,EACpB,GAAG,EAAE,GAAG,GACP,OAAO,CAAC,eAAe,CAAC,KAAK,CAAC,CAAC;CAsCnC"}
|
|
@@ -0,0 +1,120 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* API Paginated Feed Base Class
|
|
3
|
+
*
|
|
4
|
+
* Extends PaginatedFeed for HTTP/REST API-based feeds.
|
|
5
|
+
* Provides HTTP client setup and common API patterns.
|
|
6
|
+
*/
|
|
7
|
+
import { HTTPError } from 'ky';
|
|
8
|
+
import { RateLimitError } from './base.js';
|
|
9
|
+
import { createAuthenticatedClient, createHttpClient, httpClient } from './http.js';
|
|
10
|
+
import { sdkLogger } from './logger.js';
|
|
11
|
+
import { PaginatedFeed } from './paginated.js';
|
|
12
|
+
import { withHttpRetry } from './retry.js';
|
|
13
|
+
/**
|
|
14
|
+
* Base class for API-based feeds with HTTP pagination
|
|
15
|
+
*/
|
|
16
|
+
export class ApiPaginatedFeed extends PaginatedFeed {
|
|
17
|
+
apiType = 'api';
|
|
18
|
+
/**
|
|
19
|
+
* Session state for this sync session
|
|
20
|
+
*/
|
|
21
|
+
_sessionState = null;
|
|
22
|
+
/**
|
|
23
|
+
* Set session state for this sync session
|
|
24
|
+
*/
|
|
25
|
+
setSessionState(sessionState) {
|
|
26
|
+
this._sessionState = sessionState || null;
|
|
27
|
+
if (this._sessionState) {
|
|
28
|
+
sdkLogger.debug({ hasToken: !!this._sessionState.access_token, hasApiKey: !!this._sessionState.api_key }, `[${this.type}] Session state set`);
|
|
29
|
+
}
|
|
30
|
+
}
|
|
31
|
+
/**
|
|
32
|
+
* Get current session state
|
|
33
|
+
*/
|
|
34
|
+
getSessionState() {
|
|
35
|
+
return this._sessionState;
|
|
36
|
+
}
|
|
37
|
+
/**
|
|
38
|
+
* Get configured HTTP client for this feed
|
|
39
|
+
*/
|
|
40
|
+
getHttpClient(_env) {
|
|
41
|
+
return httpClient;
|
|
42
|
+
}
|
|
43
|
+
/**
|
|
44
|
+
* Create HTTP client with Bearer token authentication
|
|
45
|
+
*/
|
|
46
|
+
createBearerClient(token, additionalHeaders) {
|
|
47
|
+
return createAuthenticatedClient(`Bearer ${token}`, additionalHeaders);
|
|
48
|
+
}
|
|
49
|
+
/**
|
|
50
|
+
* Create HTTP client with custom headers
|
|
51
|
+
*/
|
|
52
|
+
createClientWithHeaders(headers) {
|
|
53
|
+
return createHttpClient({ headers });
|
|
54
|
+
}
|
|
55
|
+
/**
|
|
56
|
+
* Create HTTP client from session state
|
|
57
|
+
*/
|
|
58
|
+
createClientFromSessionState(additionalHeaders) {
|
|
59
|
+
if (!this._sessionState) {
|
|
60
|
+
return additionalHeaders ? createHttpClient({ headers: additionalHeaders }) : httpClient;
|
|
61
|
+
}
|
|
62
|
+
const headers = {
|
|
63
|
+
...this._sessionState.headers,
|
|
64
|
+
...additionalHeaders,
|
|
65
|
+
};
|
|
66
|
+
if (this._sessionState.access_token) {
|
|
67
|
+
const tokenType = this._sessionState.token_type || 'Bearer';
|
|
68
|
+
return createAuthenticatedClient(`${tokenType} ${this._sessionState.access_token}`, headers);
|
|
69
|
+
}
|
|
70
|
+
if (this._sessionState.api_key) {
|
|
71
|
+
return createAuthenticatedClient(this._sessionState.api_key, headers);
|
|
72
|
+
}
|
|
73
|
+
return Object.keys(headers).length > 0 ? createHttpClient({ headers }) : httpClient;
|
|
74
|
+
}
|
|
75
|
+
/**
|
|
76
|
+
* Handle HTTP errors with platform-specific messages
|
|
77
|
+
*/
|
|
78
|
+
handleHttpError(error, url) {
|
|
79
|
+
this.handleHTTPError(error.response.status, url);
|
|
80
|
+
}
|
|
81
|
+
/**
|
|
82
|
+
* Default fetchPage implementation using HTTP client with retry
|
|
83
|
+
*/
|
|
84
|
+
async fetchPage(cursor, options, env) {
|
|
85
|
+
const client = this.getHttpClient(env);
|
|
86
|
+
const url = this.buildPageUrl(cursor, options);
|
|
87
|
+
try {
|
|
88
|
+
const response = await withHttpRetry(async () => client.get(url).json(), {
|
|
89
|
+
operation: `${this.type} API fetch`,
|
|
90
|
+
context: { url, cursor },
|
|
91
|
+
});
|
|
92
|
+
return this.parseResponse(response, options);
|
|
93
|
+
}
|
|
94
|
+
catch (error) {
|
|
95
|
+
if (error instanceof HTTPError) {
|
|
96
|
+
if (error.response.status === 429) {
|
|
97
|
+
const retryAfter = error.response.headers.get('retry-after');
|
|
98
|
+
let retryAfterMs;
|
|
99
|
+
if (retryAfter) {
|
|
100
|
+
const numericRetry = Number(retryAfter);
|
|
101
|
+
if (!Number.isNaN(numericRetry)) {
|
|
102
|
+
retryAfterMs = numericRetry * 1000;
|
|
103
|
+
}
|
|
104
|
+
else {
|
|
105
|
+
const retryDate = Date.parse(retryAfter);
|
|
106
|
+
if (!Number.isNaN(retryDate)) {
|
|
107
|
+
retryAfterMs = retryDate - Date.now();
|
|
108
|
+
}
|
|
109
|
+
}
|
|
110
|
+
}
|
|
111
|
+
throw new RateLimitError(`${this.displayName} rate limit exceeded. Please wait before retrying.`, retryAfterMs && retryAfterMs > 0 ? retryAfterMs : undefined);
|
|
112
|
+
}
|
|
113
|
+
this.handleHttpError(error, url);
|
|
114
|
+
}
|
|
115
|
+
sdkLogger.error({ error, url }, `[${this.type}] API fetch failed`);
|
|
116
|
+
throw error;
|
|
117
|
+
}
|
|
118
|
+
}
|
|
119
|
+
}
|
|
120
|
+
//# sourceMappingURL=api-paginated.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"api-paginated.js","sourceRoot":"","sources":["../src/api-paginated.ts"],"names":[],"mappings":"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"}
|
package/dist/base.d.ts
ADDED
|
@@ -0,0 +1,66 @@
|
|
|
1
|
+
import type { TObject } from '@sinclair/typebox';
|
|
2
|
+
import type { Checkpoint, Content, Env, FeedAuthSchema, FeedOptions, FeedSyncResult, IFeed, ParentFeedDefinition, ScoringConfig, SessionState } from './types.js';
|
|
3
|
+
export declare class RateLimitError extends Error {
|
|
4
|
+
readonly retryAfterMs?: number;
|
|
5
|
+
constructor(message: string, retryAfterMs?: number);
|
|
6
|
+
}
|
|
7
|
+
/**
|
|
8
|
+
* Base feed implementation with common functionality
|
|
9
|
+
* All platform-specific feeds should extend this class
|
|
10
|
+
*/
|
|
11
|
+
export declare abstract class BaseFeed implements IFeed {
|
|
12
|
+
abstract readonly type: string;
|
|
13
|
+
abstract readonly displayName: string;
|
|
14
|
+
abstract readonly apiType: 'api' | 'browser';
|
|
15
|
+
abstract readonly feedMode: 'entity' | 'search';
|
|
16
|
+
abstract readonly optionsSchema: TObject;
|
|
17
|
+
abstract readonly defaultScoringConfig: ScoringConfig;
|
|
18
|
+
abstract readonly defaultScoringFormula: string;
|
|
19
|
+
readonly authSchema: FeedAuthSchema;
|
|
20
|
+
abstract pull(options: FeedOptions, checkpoint: Checkpoint | null, env: Env, sessionState?: SessionState | null, updateCheckpointFn?: (checkpoint: Checkpoint) => Promise<void>): Promise<FeedSyncResult>;
|
|
21
|
+
abstract urlFromOptions(options: FeedOptions): string;
|
|
22
|
+
abstract displayLabelFromOptions(options: FeedOptions): string;
|
|
23
|
+
abstract validateOptions(options: FeedOptions): string | null;
|
|
24
|
+
getParentFeedDefinitions(_options: FeedOptions): ParentFeedDefinition[];
|
|
25
|
+
/**
|
|
26
|
+
* Validate options using TypeBox schema
|
|
27
|
+
* Subclasses can call this for schema validation before adding custom business logic
|
|
28
|
+
*/
|
|
29
|
+
protected validateWithSchema(options: FeedOptions): string | null;
|
|
30
|
+
/**
|
|
31
|
+
* Get rate limit information for this platform
|
|
32
|
+
* Override this method in platform-specific feeds
|
|
33
|
+
* Default is conservative: 10 requests per minute
|
|
34
|
+
*/
|
|
35
|
+
getRateLimit(): {
|
|
36
|
+
requests_per_minute: number;
|
|
37
|
+
recommended_interval_ms: number;
|
|
38
|
+
};
|
|
39
|
+
/**
|
|
40
|
+
* Helper to check if content is newer than checkpoint
|
|
41
|
+
*/
|
|
42
|
+
protected isNewerThan(contentDate: Date, checkpoint: Checkpoint | null): boolean;
|
|
43
|
+
/**
|
|
44
|
+
* Calculate lookback date from options
|
|
45
|
+
* @param options - Feed options with optional lookback_days
|
|
46
|
+
* @param defaultDays - Default lookback period (default: 365)
|
|
47
|
+
*/
|
|
48
|
+
protected getLookbackDate(options: FeedOptions, defaultDays?: number): Date;
|
|
49
|
+
/**
|
|
50
|
+
* Sleep for specified milliseconds (for rate limiting)
|
|
51
|
+
*/
|
|
52
|
+
protected sleep(ms: number): Promise<void>;
|
|
53
|
+
/**
|
|
54
|
+
* Check if feed is in incremental mode
|
|
55
|
+
*/
|
|
56
|
+
protected isIncrementalMode(checkpoint: Checkpoint | null, paginationToken?: string | null): boolean;
|
|
57
|
+
/**
|
|
58
|
+
* Helper to deduplicate content by origin_id
|
|
59
|
+
*/
|
|
60
|
+
protected deduplicate(contents: Content[], seenIds: Set<string>): Content[];
|
|
61
|
+
/**
|
|
62
|
+
* Handle HTTP errors with structured logging and platform-specific messages
|
|
63
|
+
*/
|
|
64
|
+
protected handleHTTPError(status: number, context: string, platformName?: string): never;
|
|
65
|
+
}
|
|
66
|
+
//# sourceMappingURL=base.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"base.d.ts","sourceRoot":"","sources":["../src/base.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,OAAO,EAAE,MAAM,mBAAmB,CAAC;AAGjD,OAAO,KAAK,EACV,UAAU,EACV,OAAO,EACP,GAAG,EACH,cAAc,EACd,WAAW,EACX,cAAc,EACd,KAAK,EACL,oBAAoB,EACpB,aAAa,EACb,YAAY,EACb,MAAM,YAAY,CAAC;AAEpB,qBAAa,cAAe,SAAQ,KAAK;IACvC,QAAQ,CAAC,YAAY,CAAC,EAAE,MAAM,CAAC;gBAEnB,OAAO,EAAE,MAAM,EAAE,YAAY,CAAC,EAAE,MAAM;CAKnD;AAED;;;GAGG;AACH,8BAAsB,QAAS,YAAW,KAAK;IAC7C,QAAQ,CAAC,QAAQ,CAAC,IAAI,EAAE,MAAM,CAAC;IAC/B,QAAQ,CAAC,QAAQ,CAAC,WAAW,EAAE,MAAM,CAAC;IACtC,QAAQ,CAAC,QAAQ,CAAC,OAAO,EAAE,KAAK,GAAG,SAAS,CAAC;IAC7C,QAAQ,CAAC,QAAQ,CAAC,QAAQ,EAAE,QAAQ,GAAG,QAAQ,CAAC;IAChD,QAAQ,CAAC,QAAQ,CAAC,aAAa,EAAE,OAAO,CAAC;IACzC,QAAQ,CAAC,QAAQ,CAAC,oBAAoB,EAAE,aAAa,CAAC;IACtD,QAAQ,CAAC,QAAQ,CAAC,qBAAqB,EAAE,MAAM,CAAC;IAEhD,QAAQ,CAAC,UAAU,EAAE,cAAc,CAAmC;IAEtE,QAAQ,CAAC,IAAI,CACX,OAAO,EAAE,WAAW,EACpB,UAAU,EAAE,UAAU,GAAG,IAAI,EAC7B,GAAG,EAAE,GAAG,EACR,YAAY,CAAC,EAAE,YAAY,GAAG,IAAI,EAClC,kBAAkB,CAAC,EAAE,CAAC,UAAU,EAAE,UAAU,KAAK,OAAO,CAAC,IAAI,CAAC,GAC7D,OAAO,CAAC,cAAc,CAAC;IAE1B,QAAQ,CAAC,cAAc,CAAC,OAAO,EAAE,WAAW,GAAG,MAAM;IAErD,QAAQ,CAAC,uBAAuB,CAAC,OAAO,EAAE,WAAW,GAAG,MAAM;IAE9D,QAAQ,CAAC,eAAe,CAAC,OAAO,EAAE,WAAW,GAAG,MAAM,GAAG,IAAI;IAE7D,wBAAwB,CAAC,QAAQ,EAAE,WAAW,GAAG,oBAAoB,EAAE;IAIvE;;;OAGG;IACH,SAAS,CAAC,kBAAkB,CAAC,OAAO,EAAE,WAAW,GAAG,MAAM,GAAG,IAAI;IAgBjE;;;;OAIG;IACH,YAAY;;;;IAOZ;;OAEG;IACH,SAAS,CAAC,WAAW,CAAC,WAAW,EAAE,IAAI,EAAE,UAAU,EAAE,UAAU,GAAG,IAAI,GAAG,OAAO;IAKhF;;;;OAIG;IACH,SAAS,CAAC,eAAe,CAAC,OAAO,EAAE,WAAW,EAAE,WAAW,GAAE,MAAY,GAAG,IAAI;IAKhF;;OAEG;IACH,SAAS,CAAC,KAAK,CAAC,EAAE,EAAE,MAAM,GAAG,OAAO,CAAC,IAAI,CAAC;IAI1C;;OAEG;IACH,SAAS,CAAC,iBAAiB,CACzB,UAAU,EAAE,UAAU,GAAG,IAAI,EAC7B,eAAe,CAAC,EAAE,MAAM,GAAG,IAAI,GAC9B,OAAO;IAIV;;OAEG;IACH,SAAS,CAAC,WAAW,CAAC,QAAQ,EAAE,OAAO,EAAE,EAAE,OAAO,EAAE,GAAG,CAAC,MAAM,CAAC,GAAG,OAAO,EAAE;IAS3E;;OAEG;IACH,SAAS,CAAC,eAAe,CAAC,MAAM,EAAE,MAAM,EAAE,OAAO,EAAE,MAAM,EAAE,YAAY,CAAC,EAAE,MAAM,GAAG,KAAK;CA+BzF"}
|
package/dist/base.js
ADDED
|
@@ -0,0 +1,122 @@
|
|
|
1
|
+
import { Value } from '@sinclair/typebox/value';
|
|
2
|
+
import { sdkLogger } from './logger.js';
|
|
3
|
+
export class RateLimitError extends Error {
|
|
4
|
+
retryAfterMs;
|
|
5
|
+
constructor(message, retryAfterMs) {
|
|
6
|
+
super(message);
|
|
7
|
+
this.name = 'RateLimitError';
|
|
8
|
+
this.retryAfterMs = retryAfterMs;
|
|
9
|
+
}
|
|
10
|
+
}
|
|
11
|
+
/**
|
|
12
|
+
* Base feed implementation with common functionality
|
|
13
|
+
* All platform-specific feeds should extend this class
|
|
14
|
+
*/
|
|
15
|
+
export class BaseFeed {
|
|
16
|
+
authSchema = { methods: [{ type: 'none' }] };
|
|
17
|
+
getParentFeedDefinitions(_options) {
|
|
18
|
+
return [];
|
|
19
|
+
}
|
|
20
|
+
/**
|
|
21
|
+
* Validate options using TypeBox schema
|
|
22
|
+
* Subclasses can call this for schema validation before adding custom business logic
|
|
23
|
+
*/
|
|
24
|
+
validateWithSchema(options) {
|
|
25
|
+
try {
|
|
26
|
+
const errors = [...Value.Errors(this.optionsSchema, options)];
|
|
27
|
+
if (errors.length > 0) {
|
|
28
|
+
// Format first error for user-friendly message
|
|
29
|
+
const firstError = errors[0];
|
|
30
|
+
const field = firstError.path.replace(/^\//, '');
|
|
31
|
+
return `Invalid option ${field ? `"${field}"` : ''}: ${firstError.message}`;
|
|
32
|
+
}
|
|
33
|
+
return null;
|
|
34
|
+
}
|
|
35
|
+
catch (error) {
|
|
36
|
+
sdkLogger.error({ error }, '[BaseFeed] Schema validation error:');
|
|
37
|
+
return 'Invalid feed options format';
|
|
38
|
+
}
|
|
39
|
+
}
|
|
40
|
+
/**
|
|
41
|
+
* Get rate limit information for this platform
|
|
42
|
+
* Override this method in platform-specific feeds
|
|
43
|
+
* Default is conservative: 10 requests per minute
|
|
44
|
+
*/
|
|
45
|
+
getRateLimit() {
|
|
46
|
+
return {
|
|
47
|
+
requests_per_minute: 10,
|
|
48
|
+
recommended_interval_ms: 6000, // 6 seconds
|
|
49
|
+
};
|
|
50
|
+
}
|
|
51
|
+
/**
|
|
52
|
+
* Helper to check if content is newer than checkpoint
|
|
53
|
+
*/
|
|
54
|
+
isNewerThan(contentDate, checkpoint) {
|
|
55
|
+
if (!checkpoint || !checkpoint.last_timestamp)
|
|
56
|
+
return true;
|
|
57
|
+
return contentDate > checkpoint.last_timestamp;
|
|
58
|
+
}
|
|
59
|
+
/**
|
|
60
|
+
* Calculate lookback date from options
|
|
61
|
+
* @param options - Feed options with optional lookback_days
|
|
62
|
+
* @param defaultDays - Default lookback period (default: 365)
|
|
63
|
+
*/
|
|
64
|
+
getLookbackDate(options, defaultDays = 365) {
|
|
65
|
+
const lookbackDays = options.lookback_days || defaultDays;
|
|
66
|
+
return new Date(Date.now() - lookbackDays * 24 * 60 * 60 * 1000);
|
|
67
|
+
}
|
|
68
|
+
/**
|
|
69
|
+
* Sleep for specified milliseconds (for rate limiting)
|
|
70
|
+
*/
|
|
71
|
+
sleep(ms) {
|
|
72
|
+
return new Promise((resolve) => setTimeout(resolve, ms));
|
|
73
|
+
}
|
|
74
|
+
/**
|
|
75
|
+
* Check if feed is in incremental mode
|
|
76
|
+
*/
|
|
77
|
+
isIncrementalMode(checkpoint, paginationToken) {
|
|
78
|
+
return !!checkpoint?.last_timestamp && !paginationToken;
|
|
79
|
+
}
|
|
80
|
+
/**
|
|
81
|
+
* Helper to deduplicate content by origin_id
|
|
82
|
+
*/
|
|
83
|
+
deduplicate(contents, seenIds) {
|
|
84
|
+
return contents.filter((c) => {
|
|
85
|
+
if (!c.origin_id)
|
|
86
|
+
return false;
|
|
87
|
+
if (seenIds.has(c.origin_id))
|
|
88
|
+
return false;
|
|
89
|
+
seenIds.add(c.origin_id);
|
|
90
|
+
return true;
|
|
91
|
+
});
|
|
92
|
+
}
|
|
93
|
+
/**
|
|
94
|
+
* Handle HTTP errors with structured logging and platform-specific messages
|
|
95
|
+
*/
|
|
96
|
+
handleHTTPError(status, context, platformName) {
|
|
97
|
+
const platform = platformName || this.displayName;
|
|
98
|
+
sdkLogger.error({
|
|
99
|
+
status,
|
|
100
|
+
context,
|
|
101
|
+
platform: this.type,
|
|
102
|
+
timestamp: new Date().toISOString(),
|
|
103
|
+
}, `[${platform}Feed] HTTP ${status} error:`);
|
|
104
|
+
const errorMessages = {
|
|
105
|
+
400: `Bad request to ${platform}: ${context}. Check your feed options.`,
|
|
106
|
+
401: `Authentication failed for ${platform}. Check your API credentials.`,
|
|
107
|
+
403: `Access forbidden to ${platform} resource: ${context}. The resource may be private or require authentication.`,
|
|
108
|
+
404: `Resource not found on ${platform}: ${context}. Verify the resource exists.`,
|
|
109
|
+
422: `Invalid request to ${platform}: ${context}. Check your parameters.`,
|
|
110
|
+
429: `${platform} rate limit exceeded. Please wait before retrying.`,
|
|
111
|
+
500: `${platform} server error (${status}). This is temporary, please retry later.`,
|
|
112
|
+
502: `${platform} bad gateway (${status}). This is temporary, please retry later.`,
|
|
113
|
+
503: `${platform} service unavailable (${status}). This is temporary, please retry later.`,
|
|
114
|
+
};
|
|
115
|
+
const message = errorMessages[status] || `${platform} API error: ${status}`;
|
|
116
|
+
if (status === 429) {
|
|
117
|
+
throw new RateLimitError(message);
|
|
118
|
+
}
|
|
119
|
+
throw new Error(message);
|
|
120
|
+
}
|
|
121
|
+
}
|
|
122
|
+
//# sourceMappingURL=base.js.map
|
package/dist/base.js.map
ADDED
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"base.js","sourceRoot":"","sources":["../src/base.ts"],"names":[],"mappings":"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"}
|
|
@@ -0,0 +1,66 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Browser Acquisition
|
|
3
|
+
*
|
|
4
|
+
* Single entry point for all browser-based connectors. Implements a two-layer
|
|
5
|
+
* cascade:
|
|
6
|
+
*
|
|
7
|
+
* 1. CDP — connect to user's real Chrome via raw CDP protocol.
|
|
8
|
+
* Uses CdpPage for DOM scraping (avoids Playwright's connectOverCDP crash
|
|
9
|
+
* on browsers with many tabs). For network interception, callers use
|
|
10
|
+
* Playwright's connectOverCDP on the resolved wsUrl directly.
|
|
11
|
+
*
|
|
12
|
+
* 2. Playwright — launch headless browser, inject stored cookies.
|
|
13
|
+
* Cookies may come from a previous CDP session (freshest) or CLI capture.
|
|
14
|
+
*
|
|
15
|
+
* Both paths share the same caller API. Fresh cookies are always captured
|
|
16
|
+
* from the resulting context so the caller can persist them for future fallback.
|
|
17
|
+
*/
|
|
18
|
+
import type { Browser, BrowserContext, Cookie, Page } from 'playwright';
|
|
19
|
+
import { CdpPage } from './cdp-page.js';
|
|
20
|
+
export interface AcquireBrowserOptions {
|
|
21
|
+
/** CDP endpoint URL, 'auto' to auto-discover, or null to skip CDP entirely. */
|
|
22
|
+
cdpUrl?: string | 'auto' | null;
|
|
23
|
+
/** Stored cookies for Playwright fallback. May be empty. */
|
|
24
|
+
cookies: Cookie[];
|
|
25
|
+
/** Cookie domains to capture after sync (e.g., ['x.com', '.x.com']). */
|
|
26
|
+
authDomains: string[];
|
|
27
|
+
/** Use stealth/anti-detection mode for Playwright launch (default: false). */
|
|
28
|
+
stealth?: boolean;
|
|
29
|
+
}
|
|
30
|
+
export interface AcquiredBrowser {
|
|
31
|
+
/** Playwright Browser (null when using raw CDP). */
|
|
32
|
+
browser: Browser | null;
|
|
33
|
+
/** Playwright BrowserContext (null when using raw CDP). */
|
|
34
|
+
context: BrowserContext | null;
|
|
35
|
+
/** Playwright Page (null when using raw CDP — use cdpPage instead). */
|
|
36
|
+
page: Page | null;
|
|
37
|
+
/** Raw CDP page handle (null when using Playwright). */
|
|
38
|
+
cdpPage: CdpPage | null;
|
|
39
|
+
/** Resolved CDP WebSocket URL (available when backend is 'cdp'). */
|
|
40
|
+
cdpWsUrl: string | null;
|
|
41
|
+
/** Which backend was used. */
|
|
42
|
+
backend: 'cdp' | 'playwright';
|
|
43
|
+
/** If false, don't close the browser on cleanup (CDP — it's the user's Chrome). */
|
|
44
|
+
ownsBrowser: boolean;
|
|
45
|
+
screenshotDir: string;
|
|
46
|
+
}
|
|
47
|
+
/**
|
|
48
|
+
* Thrown when all cascade layers fail. Includes diagnostic info about each
|
|
49
|
+
* attempted layer so the user gets an actionable error message.
|
|
50
|
+
*/
|
|
51
|
+
export declare class BrowserAuthCascadeError extends Error {
|
|
52
|
+
readonly attempts: Array<{
|
|
53
|
+
layer: string;
|
|
54
|
+
error: string;
|
|
55
|
+
}>;
|
|
56
|
+
constructor(attempts: Array<{
|
|
57
|
+
layer: string;
|
|
58
|
+
error: string;
|
|
59
|
+
}>);
|
|
60
|
+
}
|
|
61
|
+
/**
|
|
62
|
+
* Acquire a browser session using a two-layer cascade:
|
|
63
|
+
* CDP first (if available), then Playwright with stored cookies.
|
|
64
|
+
*/
|
|
65
|
+
export declare function acquireBrowser(opts: AcquireBrowserOptions): Promise<AcquiredBrowser>;
|
|
66
|
+
//# sourceMappingURL=acquire.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"acquire.d.ts","sourceRoot":"","sources":["../../src/browser/acquire.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;;;GAgBG;AAEH,OAAO,KAAK,EAAE,OAAO,EAAE,cAAc,EAAE,MAAM,EAAE,IAAI,EAAE,MAAM,YAAY,CAAC;AAGxE,OAAO,EAAE,OAAO,EAAE,MAAM,eAAe,CAAC;AAOxC,MAAM,WAAW,qBAAqB;IACpC,+EAA+E;IAC/E,MAAM,CAAC,EAAE,MAAM,GAAG,MAAM,GAAG,IAAI,CAAC;IAChC,4DAA4D;IAC5D,OAAO,EAAE,MAAM,EAAE,CAAC;IAClB,wEAAwE;IACxE,WAAW,EAAE,MAAM,EAAE,CAAC;IACtB,8EAA8E;IAC9E,OAAO,CAAC,EAAE,OAAO,CAAC;CACnB;AAED,MAAM,WAAW,eAAe;IAC9B,oDAAoD;IACpD,OAAO,EAAE,OAAO,GAAG,IAAI,CAAC;IACxB,2DAA2D;IAC3D,OAAO,EAAE,cAAc,GAAG,IAAI,CAAC;IAC/B,uEAAuE;IACvE,IAAI,EAAE,IAAI,GAAG,IAAI,CAAC;IAClB,wDAAwD;IACxD,OAAO,EAAE,OAAO,GAAG,IAAI,CAAC;IACxB,oEAAoE;IACpE,QAAQ,EAAE,MAAM,GAAG,IAAI,CAAC;IACxB,8BAA8B;IAC9B,OAAO,EAAE,KAAK,GAAG,YAAY,CAAC;IAC9B,mFAAmF;IACnF,WAAW,EAAE,OAAO,CAAC;IACrB,aAAa,EAAE,MAAM,CAAC;CACvB;AAED;;;GAGG;AACH,qBAAa,uBAAwB,SAAQ,KAAK;IAChD,QAAQ,CAAC,QAAQ,EAAE,KAAK,CAAC;QAAE,KAAK,EAAE,MAAM,CAAC;QAAC,KAAK,EAAE,MAAM,CAAA;KAAE,CAAC,CAAC;gBAE/C,QAAQ,EAAE,KAAK,CAAC;QAAE,KAAK,EAAE,MAAM,CAAC;QAAC,KAAK,EAAE,MAAM,CAAA;KAAE,CAAC;CAW9D;AAMD;;;GAGG;AACH,wBAAsB,cAAc,CAAC,IAAI,EAAE,qBAAqB,GAAG,OAAO,CAAC,eAAe,CAAC,CAyB1F"}
|
|
@@ -0,0 +1,109 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Browser Acquisition
|
|
3
|
+
*
|
|
4
|
+
* Single entry point for all browser-based connectors. Implements a two-layer
|
|
5
|
+
* cascade:
|
|
6
|
+
*
|
|
7
|
+
* 1. CDP — connect to user's real Chrome via raw CDP protocol.
|
|
8
|
+
* Uses CdpPage for DOM scraping (avoids Playwright's connectOverCDP crash
|
|
9
|
+
* on browsers with many tabs). For network interception, callers use
|
|
10
|
+
* Playwright's connectOverCDP on the resolved wsUrl directly.
|
|
11
|
+
*
|
|
12
|
+
* 2. Playwright — launch headless browser, inject stored cookies.
|
|
13
|
+
* Cookies may come from a previous CDP session (freshest) or CLI capture.
|
|
14
|
+
*
|
|
15
|
+
* Both paths share the same caller API. Fresh cookies are always captured
|
|
16
|
+
* from the resulting context so the caller can persist them for future fallback.
|
|
17
|
+
*/
|
|
18
|
+
import { sdkLogger } from '../logger.js';
|
|
19
|
+
import { resolveCdpUrl } from './cdp.js';
|
|
20
|
+
import { CdpPage } from './cdp-page.js';
|
|
21
|
+
import { launchBrowser } from './launcher.js';
|
|
22
|
+
/**
|
|
23
|
+
* Thrown when all cascade layers fail. Includes diagnostic info about each
|
|
24
|
+
* attempted layer so the user gets an actionable error message.
|
|
25
|
+
*/
|
|
26
|
+
export class BrowserAuthCascadeError extends Error {
|
|
27
|
+
attempts;
|
|
28
|
+
constructor(attempts) {
|
|
29
|
+
const lines = attempts.map((a, i) => ` ${i + 1}. ${a.layer}: ${a.error}`);
|
|
30
|
+
super('Browser authentication failed. Tried:\n' +
|
|
31
|
+
lines.join('\n') +
|
|
32
|
+
'\n\nFix: Enable remote debugging in Chrome (chrome://inspect/#remote-debugging)\n' +
|
|
33
|
+
'Or run: lobu memory browser-auth --connector <key> --auth-profile-slug <slug>');
|
|
34
|
+
this.name = 'BrowserAuthCascadeError';
|
|
35
|
+
this.attempts = attempts;
|
|
36
|
+
}
|
|
37
|
+
}
|
|
38
|
+
// ---------------------------------------------------------------------------
|
|
39
|
+
// Cascade
|
|
40
|
+
// ---------------------------------------------------------------------------
|
|
41
|
+
/**
|
|
42
|
+
* Acquire a browser session using a two-layer cascade:
|
|
43
|
+
* CDP first (if available), then Playwright with stored cookies.
|
|
44
|
+
*/
|
|
45
|
+
export async function acquireBrowser(opts) {
|
|
46
|
+
const attempts = [];
|
|
47
|
+
// --- Layer 1: CDP ---
|
|
48
|
+
if (opts.cdpUrl !== null && opts.cdpUrl !== undefined) {
|
|
49
|
+
try {
|
|
50
|
+
return await acquireViaCdp(opts);
|
|
51
|
+
}
|
|
52
|
+
catch (err) {
|
|
53
|
+
attempts.push({ layer: 'CDP', error: err.message });
|
|
54
|
+
sdkLogger.info({ error: err.message }, '[BrowserAcquire] CDP not available, trying Playwright');
|
|
55
|
+
}
|
|
56
|
+
}
|
|
57
|
+
// --- Layer 2: Playwright (with stored cookies if available) ---
|
|
58
|
+
try {
|
|
59
|
+
return await acquireViaPlaywright(opts);
|
|
60
|
+
}
|
|
61
|
+
catch (err) {
|
|
62
|
+
attempts.push({ layer: 'Playwright', error: err.message });
|
|
63
|
+
}
|
|
64
|
+
// --- All layers failed ---
|
|
65
|
+
throw new BrowserAuthCascadeError(attempts);
|
|
66
|
+
}
|
|
67
|
+
// ---------------------------------------------------------------------------
|
|
68
|
+
// Layer implementations
|
|
69
|
+
// ---------------------------------------------------------------------------
|
|
70
|
+
async function acquireViaCdp(opts) {
|
|
71
|
+
const wsUrl = await resolveCdpUrl(opts.cdpUrl === 'auto' ? 'auto' : opts.cdpUrl, {
|
|
72
|
+
loggerLabel: 'BrowserAcquire',
|
|
73
|
+
preferRealBrowser: true,
|
|
74
|
+
});
|
|
75
|
+
const cdpPage = await CdpPage.create(wsUrl);
|
|
76
|
+
sdkLogger.info({ wsUrl }, '[BrowserAcquire] Connected via raw CDP');
|
|
77
|
+
return {
|
|
78
|
+
browser: null,
|
|
79
|
+
context: null,
|
|
80
|
+
page: null,
|
|
81
|
+
cdpPage,
|
|
82
|
+
cdpWsUrl: wsUrl,
|
|
83
|
+
backend: 'cdp',
|
|
84
|
+
ownsBrowser: false,
|
|
85
|
+
screenshotDir: '/tmp/feed-screenshots',
|
|
86
|
+
};
|
|
87
|
+
}
|
|
88
|
+
async function acquireViaPlaywright(opts) {
|
|
89
|
+
const { browser, screenshotDir } = await launchBrowser({}, {
|
|
90
|
+
stealth: opts.stealth ?? false,
|
|
91
|
+
});
|
|
92
|
+
const context = (await browser.newContext());
|
|
93
|
+
if (opts.cookies.length > 0) {
|
|
94
|
+
await context.addCookies(opts.cookies);
|
|
95
|
+
}
|
|
96
|
+
sdkLogger.info({ cookies: opts.cookies.length }, '[BrowserAcquire] Launched Playwright with stored cookies');
|
|
97
|
+
const page = await context.newPage();
|
|
98
|
+
return {
|
|
99
|
+
browser: browser,
|
|
100
|
+
context,
|
|
101
|
+
page,
|
|
102
|
+
cdpPage: null,
|
|
103
|
+
cdpWsUrl: null,
|
|
104
|
+
backend: 'playwright',
|
|
105
|
+
ownsBrowser: true,
|
|
106
|
+
screenshotDir,
|
|
107
|
+
};
|
|
108
|
+
}
|
|
109
|
+
//# sourceMappingURL=acquire.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"acquire.js","sourceRoot":"","sources":["../../src/browser/acquire.ts"],"names":[],"mappings":"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"}
|
|
@@ -0,0 +1,48 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Lightweight CDP Page
|
|
3
|
+
*
|
|
4
|
+
* A minimal Page-like interface over raw Chrome DevTools Protocol.
|
|
5
|
+
* Used when Playwright's connectOverCDP crashes on browsers with many tabs
|
|
6
|
+
* (it tries to enumerate all targets, which fails on real user browsers).
|
|
7
|
+
*
|
|
8
|
+
* Supports the subset of Playwright's Page API used by DOM scraper connectors:
|
|
9
|
+
* goto, evaluate, waitForSelector, waitForTimeout, click, close.
|
|
10
|
+
*/
|
|
11
|
+
export declare class CdpPage {
|
|
12
|
+
private ws;
|
|
13
|
+
private sessionId;
|
|
14
|
+
private targetId;
|
|
15
|
+
private msgId;
|
|
16
|
+
private constructor();
|
|
17
|
+
/**
|
|
18
|
+
* Create a new tab in the browser and return a CdpPage handle.
|
|
19
|
+
* Does NOT enumerate existing tabs — avoids the Playwright crash.
|
|
20
|
+
*/
|
|
21
|
+
static create(browserWsUrl: string): Promise<CdpPage>;
|
|
22
|
+
private send;
|
|
23
|
+
/** Navigate to a URL and wait for the page to load. */
|
|
24
|
+
goto(url: string, options?: {
|
|
25
|
+
waitUntil?: string;
|
|
26
|
+
timeout?: number;
|
|
27
|
+
}): Promise<void>;
|
|
28
|
+
/** Evaluate a JavaScript expression in the page and return the result. */
|
|
29
|
+
evaluate<T = unknown>(expression: string | (() => T)): Promise<T>;
|
|
30
|
+
/**
|
|
31
|
+
* Wait for a CSS selector to appear in the DOM.
|
|
32
|
+
* Returns true if found, false on timeout.
|
|
33
|
+
*/
|
|
34
|
+
waitForSelector(selector: string, options?: {
|
|
35
|
+
timeout?: number;
|
|
36
|
+
}): Promise<boolean>;
|
|
37
|
+
/** Click the first element matching a CSS selector. */
|
|
38
|
+
click(selector: string): Promise<void>;
|
|
39
|
+
/** Wait for a fixed duration. */
|
|
40
|
+
waitForTimeout(ms: number): Promise<void>;
|
|
41
|
+
/** Get the current page URL. */
|
|
42
|
+
url(): Promise<string>;
|
|
43
|
+
/** Get the page title. */
|
|
44
|
+
title(): Promise<string>;
|
|
45
|
+
/** Close the tab and disconnect. */
|
|
46
|
+
close(): Promise<void>;
|
|
47
|
+
}
|
|
48
|
+
//# sourceMappingURL=cdp-page.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"cdp-page.d.ts","sourceRoot":"","sources":["../../src/browser/cdp-page.ts"],"names":[],"mappings":"AAAA;;;;;;;;;GASG;AAIH,qBAAa,OAAO;IAClB,OAAO,CAAC,EAAE,CAAY;IACtB,OAAO,CAAC,SAAS,CAAS;IAC1B,OAAO,CAAC,QAAQ,CAAS;IACzB,OAAO,CAAC,KAAK,CAAK;IAElB,OAAO;IAMP;;;OAGG;WACU,MAAM,CAAC,YAAY,EAAE,MAAM,GAAG,OAAO,CAAC,OAAO,CAAC;IA8C3D,OAAO,CAAC,IAAI;IAiBZ,uDAAuD;IACjD,IAAI,CAAC,GAAG,EAAE,MAAM,EAAE,OAAO,CAAC,EAAE;QAAE,SAAS,CAAC,EAAE,MAAM,CAAC;QAAC,OAAO,CAAC,EAAE,MAAM,CAAA;KAAE,GAAG,OAAO,CAAC,IAAI,CAAC;IAmB1F,0EAA0E;IACpE,QAAQ,CAAC,CAAC,GAAG,OAAO,EAAE,UAAU,EAAE,MAAM,GAAG,CAAC,MAAM,CAAC,CAAC,GAAG,OAAO,CAAC,CAAC,CAAC;IAevE;;;OAGG;IACG,eAAe,CAAC,QAAQ,EAAE,MAAM,EAAE,OAAO,CAAC,EAAE;QAAE,OAAO,CAAC,EAAE,MAAM,CAAA;KAAE,GAAG,OAAO,CAAC,OAAO,CAAC;IAazF,uDAAuD;IACjD,KAAK,CAAC,QAAQ,EAAE,MAAM,GAAG,OAAO,CAAC,IAAI,CAAC;IAI5C,iCAAiC;IAC3B,cAAc,CAAC,EAAE,EAAE,MAAM,GAAG,OAAO,CAAC,IAAI,CAAC;IAI/C,gCAAgC;IAC1B,GAAG,IAAI,OAAO,CAAC,MAAM,CAAC;IAI5B,0BAA0B;IACpB,KAAK,IAAI,OAAO,CAAC,MAAM,CAAC;IAI9B,oCAAoC;IAC9B,KAAK,IAAI,OAAO,CAAC,IAAI,CAAC;CAmB7B"}
|