@lobu/connector-sdk 6.0.1 → 7.0.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/browser/acquire.d.ts +7 -0
- package/dist/browser/acquire.d.ts.map +1 -1
- package/dist/browser/acquire.js +68 -16
- package/dist/browser/acquire.js.map +1 -1
- package/dist/browser/cdp-page.d.ts.map +1 -1
- package/dist/browser/cdp-page.js +40 -12
- package/dist/browser/cdp-page.js.map +1 -1
- package/dist/browser/launcher.d.ts +1 -2
- package/dist/browser/launcher.d.ts.map +1 -1
- package/dist/browser/launcher.js +1 -1
- package/dist/browser/launcher.js.map +1 -1
- package/dist/browser-network.d.ts +6 -0
- package/dist/browser-network.d.ts.map +1 -1
- package/dist/browser-network.js +78 -31
- package/dist/browser-network.js.map +1 -1
- package/dist/connector-types.d.ts +35 -0
- package/dist/connector-types.d.ts.map +1 -1
- package/dist/connector-types.js +3 -0
- package/dist/connector-types.js.map +1 -1
- package/dist/identity-normalize.d.ts +2 -0
- package/dist/identity-normalize.d.ts.map +1 -1
- package/dist/identity-normalize.js +28 -0
- package/dist/identity-normalize.js.map +1 -1
- package/dist/index.d.ts +3 -11
- package/dist/index.d.ts.map +1 -1
- package/dist/index.js +1 -7
- package/dist/index.js.map +1 -1
- package/dist/logger.d.ts +5 -4
- package/dist/logger.d.ts.map +1 -1
- package/dist/logger.js +5 -7
- package/dist/logger.js.map +1 -1
- package/dist/retry.d.ts +6 -3
- package/dist/retry.d.ts.map +1 -1
- package/dist/retry.js +29 -33
- package/dist/retry.js.map +1 -1
- package/dist/types.d.ts +0 -164
- package/dist/types.d.ts.map +1 -1
- package/package.json +3 -4
- package/dist/api-paginated.d.ts +0 -79
- package/dist/api-paginated.d.ts.map +0 -1
- package/dist/api-paginated.js +0 -120
- package/dist/api-paginated.js.map +0 -1
- package/dist/base.d.ts +0 -66
- package/dist/base.d.ts.map +0 -1
- package/dist/base.js +0 -122
- package/dist/base.js.map +0 -1
- package/dist/browser-paginated.d.ts +0 -141
- package/dist/browser-paginated.d.ts.map +0 -1
- package/dist/browser-paginated.js +0 -269
- package/dist/browser-paginated.js.map +0 -1
- package/dist/http.d.ts +0 -18
- package/dist/http.d.ts.map +0 -1
- package/dist/http.js +0 -74
- package/dist/http.js.map +0 -1
- package/dist/paginated.d.ts +0 -93
- package/dist/paginated.d.ts.map +0 -1
- package/dist/paginated.js +0 -167
- package/dist/paginated.js.map +0 -1
|
@@ -1,269 +0,0 @@
|
|
|
1
|
-
/// <reference lib="dom" />
|
|
2
|
-
/**
|
|
3
|
-
* Browser Paginated Feed Base Class
|
|
4
|
-
*
|
|
5
|
-
* Extends PaginatedFeed for browser-based feeds (Playwright).
|
|
6
|
-
*/
|
|
7
|
-
import { captureErrorArtifacts, launchBrowser } from './browser/launcher.js';
|
|
8
|
-
import { sdkLogger } from './logger.js';
|
|
9
|
-
import { PaginatedFeed } from './paginated.js';
|
|
10
|
-
/**
|
|
11
|
-
* Base class for browser-based feeds with pagination
|
|
12
|
-
*/
|
|
13
|
-
export class BrowserPaginatedFeed extends PaginatedFeed {
|
|
14
|
-
apiType = 'browser';
|
|
15
|
-
_browser = null;
|
|
16
|
-
_page = null;
|
|
17
|
-
_screenshotDir = '';
|
|
18
|
-
_isFirstPage = true;
|
|
19
|
-
_currentPageNumber = 0;
|
|
20
|
-
/**
|
|
21
|
-
* Browser-specific pagination configuration
|
|
22
|
-
*/
|
|
23
|
-
getBrowserPaginationConfig() {
|
|
24
|
-
return {
|
|
25
|
-
...this.getPaginationConfig(),
|
|
26
|
-
pagesPerRun: 1,
|
|
27
|
-
pageDelayMs: 2000,
|
|
28
|
-
};
|
|
29
|
-
}
|
|
30
|
-
/**
|
|
31
|
-
* Override pull() to manage browser lifecycle
|
|
32
|
-
*/
|
|
33
|
-
async pull(options, checkpoint, env, sessionState, updateCheckpointFn) {
|
|
34
|
-
const config = this.getBrowserConfig();
|
|
35
|
-
const browserSessionState = sessionState;
|
|
36
|
-
const { browser, screenshotDir } = await launchBrowser(env, { stealth: config.stealth });
|
|
37
|
-
this._browser = browser;
|
|
38
|
-
this._page = (await browser.newPage());
|
|
39
|
-
this._screenshotDir = screenshotDir;
|
|
40
|
-
this._isFirstPage = true;
|
|
41
|
-
this._currentPageNumber = 0;
|
|
42
|
-
if (config.viewport) {
|
|
43
|
-
await this._page.setViewportSize(config.viewport);
|
|
44
|
-
}
|
|
45
|
-
if (config.userAgent) {
|
|
46
|
-
await this._page.setExtraHTTPHeaders({
|
|
47
|
-
'User-Agent': config.userAgent,
|
|
48
|
-
});
|
|
49
|
-
}
|
|
50
|
-
if (browserSessionState) {
|
|
51
|
-
await this.applySessionState(this._page, browserSessionState);
|
|
52
|
-
}
|
|
53
|
-
try {
|
|
54
|
-
const result = await this.paginate(options, checkpoint, env, updateCheckpointFn);
|
|
55
|
-
let parentMapRecord;
|
|
56
|
-
if (result.parentMap && result.parentMap.size > 0) {
|
|
57
|
-
parentMapRecord = Object.fromEntries(result.parentMap);
|
|
58
|
-
}
|
|
59
|
-
const capturedSessionState = await this.captureSessionState(this._page);
|
|
60
|
-
return {
|
|
61
|
-
contents: result.contents,
|
|
62
|
-
checkpoint: result.checkpoint,
|
|
63
|
-
metadata: {
|
|
64
|
-
items_found: result.contents.length,
|
|
65
|
-
items_skipped: 0,
|
|
66
|
-
parent_map: parentMapRecord,
|
|
67
|
-
next_sync_recommended_at: result.nextSyncRecommendedAt,
|
|
68
|
-
},
|
|
69
|
-
auth_update: capturedSessionState,
|
|
70
|
-
};
|
|
71
|
-
}
|
|
72
|
-
catch (error) {
|
|
73
|
-
if (this._page) {
|
|
74
|
-
await captureErrorArtifacts(this._page, error, this.type, this._screenshotDir);
|
|
75
|
-
}
|
|
76
|
-
throw error;
|
|
77
|
-
}
|
|
78
|
-
finally {
|
|
79
|
-
if (this._browser) {
|
|
80
|
-
await this._browser.close();
|
|
81
|
-
this._browser = null;
|
|
82
|
-
this._page = null;
|
|
83
|
-
}
|
|
84
|
-
}
|
|
85
|
-
}
|
|
86
|
-
/**
|
|
87
|
-
* Apply session state to browser page before navigation
|
|
88
|
-
*/
|
|
89
|
-
async applySessionState(page, sessionState) {
|
|
90
|
-
if (sessionState.cookies && sessionState.cookies.length > 0) {
|
|
91
|
-
try {
|
|
92
|
-
await page.context().addCookies(sessionState.cookies);
|
|
93
|
-
sdkLogger.info({ cookieCount: sessionState.cookies.length }, `[${this.type}] Applied session cookies`);
|
|
94
|
-
}
|
|
95
|
-
catch (error) {
|
|
96
|
-
sdkLogger.warn({ error }, `[${this.type}] Failed to apply session cookies`);
|
|
97
|
-
}
|
|
98
|
-
}
|
|
99
|
-
if (sessionState.headers && Object.keys(sessionState.headers).length > 0) {
|
|
100
|
-
try {
|
|
101
|
-
await page.setExtraHTTPHeaders(sessionState.headers);
|
|
102
|
-
sdkLogger.info({ headerCount: Object.keys(sessionState.headers).length }, `[${this.type}] Applied session headers`);
|
|
103
|
-
}
|
|
104
|
-
catch (error) {
|
|
105
|
-
sdkLogger.warn({ error }, `[${this.type}] Failed to apply session headers`);
|
|
106
|
-
}
|
|
107
|
-
}
|
|
108
|
-
if (sessionState.localStorage && Object.keys(sessionState.localStorage).length > 0) {
|
|
109
|
-
sdkLogger.debug({ keyCount: Object.keys(sessionState.localStorage).length }, `[${this.type}] localStorage will be applied after first navigation`);
|
|
110
|
-
}
|
|
111
|
-
}
|
|
112
|
-
/**
|
|
113
|
-
* Capture browser session state after sync for persistence
|
|
114
|
-
*/
|
|
115
|
-
async captureSessionState(page) {
|
|
116
|
-
const sessionState = {};
|
|
117
|
-
try {
|
|
118
|
-
const cookies = await page.context().cookies();
|
|
119
|
-
if (cookies.length > 0) {
|
|
120
|
-
sessionState.cookies = cookies;
|
|
121
|
-
sdkLogger.debug({ cookieCount: cookies.length }, `[${this.type}] Captured session cookies`);
|
|
122
|
-
}
|
|
123
|
-
}
|
|
124
|
-
catch (error) {
|
|
125
|
-
sdkLogger.warn({ error }, `[${this.type}] Failed to capture session cookies`);
|
|
126
|
-
}
|
|
127
|
-
try {
|
|
128
|
-
const localStorage = await page.evaluate(() => {
|
|
129
|
-
const storage = {};
|
|
130
|
-
for (let i = 0; i < window.localStorage.length; i++) {
|
|
131
|
-
const key = window.localStorage.key(i);
|
|
132
|
-
if (key) {
|
|
133
|
-
storage[key] = window.localStorage.getItem(key) || '';
|
|
134
|
-
}
|
|
135
|
-
}
|
|
136
|
-
return storage;
|
|
137
|
-
});
|
|
138
|
-
if (Object.keys(localStorage).length > 0) {
|
|
139
|
-
sessionState.localStorage = localStorage;
|
|
140
|
-
sdkLogger.debug({ keyCount: Object.keys(localStorage).length }, `[${this.type}] Captured localStorage`);
|
|
141
|
-
}
|
|
142
|
-
}
|
|
143
|
-
catch (error) {
|
|
144
|
-
sdkLogger.debug({ error }, `[${this.type}] Could not capture localStorage (may be expected)`);
|
|
145
|
-
}
|
|
146
|
-
return sessionState;
|
|
147
|
-
}
|
|
148
|
-
/**
|
|
149
|
-
* fetchPage() implementation for browser-based pagination
|
|
150
|
-
*/
|
|
151
|
-
async fetchPage(cursor, options, _env) {
|
|
152
|
-
const pageNumber = cursor ? parseInt(cursor, 10) : 1;
|
|
153
|
-
this._currentPageNumber = pageNumber;
|
|
154
|
-
const baseUrl = this.getBaseUrl(options);
|
|
155
|
-
const pageUrl = this.buildPageUrl(baseUrl, pageNumber);
|
|
156
|
-
const config = this.getBrowserConfig();
|
|
157
|
-
const paginationConfig = this.getBrowserPaginationConfig();
|
|
158
|
-
const page = this._page;
|
|
159
|
-
sdkLogger.info({ pageUrl, pageNumber, maxPages: paginationConfig.pagesPerRun }, `[${this.type}] Fetching page`);
|
|
160
|
-
await page.goto(pageUrl, {
|
|
161
|
-
waitUntil: config.waitUntil,
|
|
162
|
-
timeout: config.navigationTimeout,
|
|
163
|
-
});
|
|
164
|
-
if (this._isFirstPage && config.cookieConsent) {
|
|
165
|
-
await this.handleCookieConsent(page, config.cookieConsent);
|
|
166
|
-
this._isFirstPage = false;
|
|
167
|
-
}
|
|
168
|
-
if (config.captcha?.enabled) {
|
|
169
|
-
await this.checkForCaptcha(page, config.captcha);
|
|
170
|
-
}
|
|
171
|
-
await this.waitForContent(page);
|
|
172
|
-
const items = await this.extractItems(page);
|
|
173
|
-
sdkLogger.info({ itemCount: items.length, pageNumber }, `[${this.type}] Extracted items from page`);
|
|
174
|
-
const hasNext = items.length > 0 &&
|
|
175
|
-
items.length >= paginationConfig.pageSize &&
|
|
176
|
-
pageNumber < paginationConfig.pagesPerRun;
|
|
177
|
-
if (hasNext && paginationConfig.pageDelayMs > 0) {
|
|
178
|
-
await this.sleep(paginationConfig.pageDelayMs);
|
|
179
|
-
}
|
|
180
|
-
return {
|
|
181
|
-
items,
|
|
182
|
-
nextToken: hasNext ? String(pageNumber + 1) : null,
|
|
183
|
-
rawCount: items.length,
|
|
184
|
-
};
|
|
185
|
-
}
|
|
186
|
-
/**
|
|
187
|
-
* Handle cookie consent banner
|
|
188
|
-
*/
|
|
189
|
-
async handleCookieConsent(page, config) {
|
|
190
|
-
try {
|
|
191
|
-
const timeout = config.timeout ?? 2000;
|
|
192
|
-
for (const selector of config.bannerSelectors) {
|
|
193
|
-
try {
|
|
194
|
-
const banner = await page.$(selector);
|
|
195
|
-
if (banner) {
|
|
196
|
-
for (const acceptSelector of config.acceptSelectors) {
|
|
197
|
-
try {
|
|
198
|
-
const acceptButton = await page.$(acceptSelector);
|
|
199
|
-
if (acceptButton) {
|
|
200
|
-
await acceptButton.click();
|
|
201
|
-
await this.sleep(1000);
|
|
202
|
-
sdkLogger.debug(`[${this.type}] Cookie consent accepted`);
|
|
203
|
-
return;
|
|
204
|
-
}
|
|
205
|
-
}
|
|
206
|
-
catch (_e) {
|
|
207
|
-
// Try next accept selector
|
|
208
|
-
}
|
|
209
|
-
}
|
|
210
|
-
}
|
|
211
|
-
}
|
|
212
|
-
catch (_e) {
|
|
213
|
-
// Try next banner selector
|
|
214
|
-
}
|
|
215
|
-
}
|
|
216
|
-
const bannerSelector = config.bannerSelectors.join(', ');
|
|
217
|
-
try {
|
|
218
|
-
await page.waitForSelector(bannerSelector, { timeout });
|
|
219
|
-
const acceptSelector = config.acceptSelectors.join(', ');
|
|
220
|
-
await page.click(acceptSelector);
|
|
221
|
-
await this.sleep(1000);
|
|
222
|
-
sdkLogger.debug(`[${this.type}] Cookie consent accepted (waited)`);
|
|
223
|
-
}
|
|
224
|
-
catch (_e) {
|
|
225
|
-
// No cookie banner or already dismissed
|
|
226
|
-
}
|
|
227
|
-
}
|
|
228
|
-
catch (_e) {
|
|
229
|
-
sdkLogger.debug(`[${this.type}] No cookie banner found or already handled`);
|
|
230
|
-
}
|
|
231
|
-
}
|
|
232
|
-
/**
|
|
233
|
-
* Check for CAPTCHA and throw if detected
|
|
234
|
-
*/
|
|
235
|
-
async checkForCaptcha(page, config) {
|
|
236
|
-
const hasCaptcha = await page.evaluate((cfg) => {
|
|
237
|
-
if (cfg.selectors) {
|
|
238
|
-
for (const selector of cfg.selectors) {
|
|
239
|
-
if (document.querySelector(selector))
|
|
240
|
-
return true;
|
|
241
|
-
}
|
|
242
|
-
}
|
|
243
|
-
if (cfg.textPatterns) {
|
|
244
|
-
const bodyText = document.body.textContent || '';
|
|
245
|
-
for (const pattern of cfg.textPatterns) {
|
|
246
|
-
if (bodyText.includes(pattern))
|
|
247
|
-
return true;
|
|
248
|
-
}
|
|
249
|
-
}
|
|
250
|
-
return false;
|
|
251
|
-
}, { selectors: config.selectors, textPatterns: config.textPatterns });
|
|
252
|
-
if (hasCaptcha) {
|
|
253
|
-
throw new Error(`CAPTCHA detected - ${this.displayName} blocking access`);
|
|
254
|
-
}
|
|
255
|
-
}
|
|
256
|
-
/**
|
|
257
|
-
* Get current page number
|
|
258
|
-
*/
|
|
259
|
-
getCurrentPageNumber() {
|
|
260
|
-
return this._currentPageNumber;
|
|
261
|
-
}
|
|
262
|
-
/**
|
|
263
|
-
* Get the Playwright page instance
|
|
264
|
-
*/
|
|
265
|
-
getPage() {
|
|
266
|
-
return this._page;
|
|
267
|
-
}
|
|
268
|
-
}
|
|
269
|
-
//# sourceMappingURL=browser-paginated.js.map
|
|
@@ -1 +0,0 @@
|
|
|
1
|
-
{"version":3,"file":"browser-paginated.js","sourceRoot":"","sources":["../src/browser-paginated.ts"],"names":[],"mappings":"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"}
|
package/dist/http.d.ts
DELETED
|
@@ -1,18 +0,0 @@
|
|
|
1
|
-
import { type KyInstance, type Options } from 'ky';
|
|
2
|
-
/**
|
|
3
|
-
* Create a configured ky instance with custom options
|
|
4
|
-
*/
|
|
5
|
-
export declare function createHttpClient(options?: Options): KyInstance;
|
|
6
|
-
/**
|
|
7
|
-
* Default HTTP client for feeds with standard User-Agent
|
|
8
|
-
*/
|
|
9
|
-
export declare const httpClient: KyInstance;
|
|
10
|
-
/**
|
|
11
|
-
* Create an HTTP client with authentication headers
|
|
12
|
-
*/
|
|
13
|
-
export declare function createAuthenticatedClient(authHeader: string, additionalHeaders?: Record<string, string>): KyInstance;
|
|
14
|
-
/**
|
|
15
|
-
* HTTP client for JSON APIs
|
|
16
|
-
*/
|
|
17
|
-
export declare const jsonHttpClient: KyInstance;
|
|
18
|
-
//# sourceMappingURL=http.d.ts.map
|
package/dist/http.d.ts.map
DELETED
|
@@ -1 +0,0 @@
|
|
|
1
|
-
{"version":3,"file":"http.d.ts","sourceRoot":"","sources":["../src/http.ts"],"names":[],"mappings":"AAAA,OAAW,EAAE,KAAK,UAAU,EAAE,KAAK,OAAO,EAAE,MAAM,IAAI,CAAC;AA8BvD;;GAEG;AACH,wBAAgB,gBAAgB,CAAC,OAAO,CAAC,EAAE,OAAO,GAAG,UAAU,CAY9D;AAED;;GAEG;AACH,eAAO,MAAM,UAAU,YAIrB,CAAC;AAEH;;GAEG;AACH,wBAAgB,yBAAyB,CACvC,UAAU,EAAE,MAAM,EAClB,iBAAiB,CAAC,EAAE,MAAM,CAAC,MAAM,EAAE,MAAM,CAAC,GACzC,UAAU,CAQZ;AAED;;GAEG;AACH,eAAO,MAAM,cAAc,YAMzB,CAAC"}
|
package/dist/http.js
DELETED
|
@@ -1,74 +0,0 @@
|
|
|
1
|
-
import ky from 'ky';
|
|
2
|
-
/**
|
|
3
|
-
* Shared HTTP client configuration for all feeds
|
|
4
|
-
*/
|
|
5
|
-
/**
|
|
6
|
-
* Default retry configuration
|
|
7
|
-
* - Max 2 retries (3 total attempts)
|
|
8
|
-
* - Only retry transient errors (429, 5xx)
|
|
9
|
-
* - Exponential backoff up to 5 seconds
|
|
10
|
-
* - 30s timeout per request
|
|
11
|
-
*/
|
|
12
|
-
const defaultRetryConfig = {
|
|
13
|
-
retry: {
|
|
14
|
-
limit: 2, // Max 2 retries (3 total attempts)
|
|
15
|
-
methods: ['get', 'post'],
|
|
16
|
-
statusCodes: [
|
|
17
|
-
408, // Request Timeout
|
|
18
|
-
429, // Too Many Requests (rate limit)
|
|
19
|
-
500, // Internal Server Error
|
|
20
|
-
502, // Bad Gateway
|
|
21
|
-
503, // Service Unavailable
|
|
22
|
-
504, // Gateway Timeout
|
|
23
|
-
],
|
|
24
|
-
backoffLimit: 5000, // Max 5 seconds delay between retries
|
|
25
|
-
},
|
|
26
|
-
timeout: 30000, // 30 second timeout per request
|
|
27
|
-
};
|
|
28
|
-
/**
|
|
29
|
-
* Create a configured ky instance with custom options
|
|
30
|
-
*/
|
|
31
|
-
export function createHttpClient(options) {
|
|
32
|
-
return ky.create({
|
|
33
|
-
...defaultRetryConfig,
|
|
34
|
-
...options,
|
|
35
|
-
// Merge retry config if provided
|
|
36
|
-
retry: options?.retry
|
|
37
|
-
? {
|
|
38
|
-
...defaultRetryConfig.retry,
|
|
39
|
-
...(typeof options.retry === 'number' ? { limit: options.retry } : options.retry),
|
|
40
|
-
}
|
|
41
|
-
: defaultRetryConfig.retry,
|
|
42
|
-
});
|
|
43
|
-
}
|
|
44
|
-
/**
|
|
45
|
-
* Default HTTP client for feeds with standard User-Agent
|
|
46
|
-
*/
|
|
47
|
-
export const httpClient = createHttpClient({
|
|
48
|
-
headers: {
|
|
49
|
-
'User-Agent': 'UserResearchBot/1.0',
|
|
50
|
-
},
|
|
51
|
-
});
|
|
52
|
-
/**
|
|
53
|
-
* Create an HTTP client with authentication headers
|
|
54
|
-
*/
|
|
55
|
-
export function createAuthenticatedClient(authHeader, additionalHeaders) {
|
|
56
|
-
return createHttpClient({
|
|
57
|
-
headers: {
|
|
58
|
-
'User-Agent': 'UserResearchBot/1.0',
|
|
59
|
-
Authorization: authHeader,
|
|
60
|
-
...additionalHeaders,
|
|
61
|
-
},
|
|
62
|
-
});
|
|
63
|
-
}
|
|
64
|
-
/**
|
|
65
|
-
* HTTP client for JSON APIs
|
|
66
|
-
*/
|
|
67
|
-
export const jsonHttpClient = createHttpClient({
|
|
68
|
-
headers: {
|
|
69
|
-
'User-Agent': 'UserResearchBot/1.0',
|
|
70
|
-
Accept: 'application/json',
|
|
71
|
-
'Content-Type': 'application/json',
|
|
72
|
-
},
|
|
73
|
-
});
|
|
74
|
-
//# sourceMappingURL=http.js.map
|
package/dist/http.js.map
DELETED
|
@@ -1 +0,0 @@
|
|
|
1
|
-
{"version":3,"file":"http.js","sourceRoot":"","sources":["../src/http.ts"],"names":[],"mappings":"AAAA,OAAO,EAAqC,MAAM,IAAI,CAAC;AAEvD;;GAEG;AAEH;;;;;;GAMG;AACH,MAAM,kBAAkB,GAAG;IACzB,KAAK,EAAE;QACL,KAAK,EAAE,CAAC,EAAE,mCAAmC;QAC7C,OAAO,EAAE,CAAC,KAAK,EAAE,MAAM,CAAC;QACxB,WAAW,EAAE;YACX,GAAG,EAAE,kBAAkB;YACvB,GAAG,EAAE,iCAAiC;YACtC,GAAG,EAAE,wBAAwB;YAC7B,GAAG,EAAE,cAAc;YACnB,GAAG,EAAE,sBAAsB;YAC3B,GAAG,EAAE,kBAAkB;SACxB;QACD,YAAY,EAAE,IAAI,EAAE,sCAAsC;KAC3D;IACD,OAAO,EAAE,KAAK,EAAE,gCAAgC;CACjD,CAAC;AAEF;;GAEG;AACH,MAAM,UAAU,gBAAgB,CAAC,OAAiB;IAChD,OAAO,EAAE,CAAC,MAAM,CAAC;QACf,GAAG,kBAAkB;QACrB,GAAG,OAAO;QACV,iCAAiC;QACjC,KAAK,EAAE,OAAO,EAAE,KAAK;YACnB,CAAC,CAAC;gBACE,GAAG,kBAAkB,CAAC,KAAK;gBAC3B,GAAG,CAAC,OAAO,OAAO,CAAC,KAAK,KAAK,QAAQ,CAAC,CAAC,CAAC,EAAE,KAAK,EAAE,OAAO,CAAC,KAAK,EAAE,CAAC,CAAC,CAAC,OAAO,CAAC,KAAK,CAAC;aAClF;YACH,CAAC,CAAC,kBAAkB,CAAC,KAAK;KAC7B,CAAC,CAAC;AACL,CAAC;AAED;;GAEG;AACH,MAAM,CAAC,MAAM,UAAU,GAAG,gBAAgB,CAAC;IACzC,OAAO,EAAE;QACP,YAAY,EAAE,qBAAqB;KACpC;CACF,CAAC,CAAC;AAEH;;GAEG;AACH,MAAM,UAAU,yBAAyB,CACvC,UAAkB,EAClB,iBAA0C;IAE1C,OAAO,gBAAgB,CAAC;QACtB,OAAO,EAAE;YACP,YAAY,EAAE,qBAAqB;YACnC,aAAa,EAAE,UAAU;YACzB,GAAG,iBAAiB;SACrB;KACF,CAAC,CAAC;AACL,CAAC;AAED;;GAEG;AACH,MAAM,CAAC,MAAM,cAAc,GAAG,gBAAgB,CAAC;IAC7C,OAAO,EAAE;QACP,YAAY,EAAE,qBAAqB;QACnC,MAAM,EAAE,kBAAkB;QAC1B,cAAc,EAAE,kBAAkB;KACnC;CACF,CAAC,CAAC"}
|
package/dist/paginated.d.ts
DELETED
|
@@ -1,93 +0,0 @@
|
|
|
1
|
-
/**
|
|
2
|
-
* Paginated Feed Base Class
|
|
3
|
-
*
|
|
4
|
-
* Provides a reusable pagination pattern for feeds that fetch data in pages.
|
|
5
|
-
* Uses the template method pattern - subclasses implement specific methods while
|
|
6
|
-
* the base class handles the pagination loop, rate limiting, and checkpoint management.
|
|
7
|
-
*/
|
|
8
|
-
import { BaseFeed } from './base.js';
|
|
9
|
-
import type { Checkpoint, Content, Env, FeedOptions } from './types.js';
|
|
10
|
-
/**
|
|
11
|
-
* Configuration for pagination behavior
|
|
12
|
-
*/
|
|
13
|
-
export interface PaginationConfig {
|
|
14
|
-
/** Maximum pages to fetch (safety limit). Default: 50 */
|
|
15
|
-
maxPages: number;
|
|
16
|
-
/** Expected items per page (for partial page detection). Default: 100 */
|
|
17
|
-
pageSize: number;
|
|
18
|
-
/** Milliseconds to wait between page requests. Default: 1000 */
|
|
19
|
-
rateLimitMs: number;
|
|
20
|
-
/** Whether to update checkpoint after each page (for resume). Default: false */
|
|
21
|
-
incrementalCheckpoint: boolean;
|
|
22
|
-
}
|
|
23
|
-
/**
|
|
24
|
-
* Result from fetching a single page
|
|
25
|
-
*/
|
|
26
|
-
export interface PageFetchResult<TItem> {
|
|
27
|
-
/** Items from this page */
|
|
28
|
-
items: TItem[];
|
|
29
|
-
/** Token/cursor for next page (null = no more pages) */
|
|
30
|
-
nextToken: string | null;
|
|
31
|
-
/** Optional: raw item count before any filtering (for logging) */
|
|
32
|
-
rawCount?: number;
|
|
33
|
-
}
|
|
34
|
-
/**
|
|
35
|
-
* Extended checkpoint interface with pagination token
|
|
36
|
-
*/
|
|
37
|
-
export interface PaginatedCheckpoint extends Checkpoint {
|
|
38
|
-
/** Pagination token for resuming sync */
|
|
39
|
-
pagination_token?: string | null;
|
|
40
|
-
/** Whether initial sync completed (used to choose checkpoint boundary) */
|
|
41
|
-
initial_complete?: boolean;
|
|
42
|
-
}
|
|
43
|
-
/**
|
|
44
|
-
* Result from the paginate() method
|
|
45
|
-
*/
|
|
46
|
-
export interface PaginateResult<TCheckpoint extends Checkpoint> {
|
|
47
|
-
contents: Content[];
|
|
48
|
-
checkpoint: TCheckpoint;
|
|
49
|
-
parentMap?: Map<string, string>;
|
|
50
|
-
nextSyncRecommendedAt?: Date;
|
|
51
|
-
}
|
|
52
|
-
/**
|
|
53
|
-
* Base class for feeds with cursor/page-based pagination
|
|
54
|
-
*/
|
|
55
|
-
export declare abstract class PaginatedFeed<TItem, TCheckpoint extends PaginatedCheckpoint = PaginatedCheckpoint> extends BaseFeed {
|
|
56
|
-
/**
|
|
57
|
-
* Default pagination configuration
|
|
58
|
-
*/
|
|
59
|
-
protected getPaginationConfig(): PaginationConfig;
|
|
60
|
-
/**
|
|
61
|
-
* ABSTRACT: Fetch a single page of items from the platform
|
|
62
|
-
*/
|
|
63
|
-
protected abstract fetchPage(cursor: string | null, options: FeedOptions, env: Env): Promise<PageFetchResult<TItem>>;
|
|
64
|
-
/**
|
|
65
|
-
* ABSTRACT: Transform a platform item to Content format
|
|
66
|
-
*/
|
|
67
|
-
protected abstract transformItem(item: TItem, options: FeedOptions): Content;
|
|
68
|
-
/**
|
|
69
|
-
* ABSTRACT: Extract published date from platform item
|
|
70
|
-
*/
|
|
71
|
-
protected abstract getItemDate(item: TItem): Date;
|
|
72
|
-
/**
|
|
73
|
-
* OPTIONAL: Filter items before transformation
|
|
74
|
-
*/
|
|
75
|
-
protected filterItem(_item: TItem, _options: FeedOptions): boolean;
|
|
76
|
-
/**
|
|
77
|
-
* OPTIONAL: Extract parent ID for hierarchical content
|
|
78
|
-
*/
|
|
79
|
-
protected getParentId(_item: TItem): string | null;
|
|
80
|
-
/**
|
|
81
|
-
* OPTIONAL: Extract pagination token from checkpoint
|
|
82
|
-
*/
|
|
83
|
-
protected getPaginationToken(checkpoint: TCheckpoint | null): string | null;
|
|
84
|
-
/**
|
|
85
|
-
* OPTIONAL: Create checkpoint with feed-specific fields
|
|
86
|
-
*/
|
|
87
|
-
protected createCheckpoint(existing: TCheckpoint | null, latestContent: Content | null, nextToken: string | null, itemsProcessed: number): TCheckpoint;
|
|
88
|
-
/**
|
|
89
|
-
* Main pagination loop - handles both initial and incremental syncs
|
|
90
|
-
*/
|
|
91
|
-
protected paginate(options: FeedOptions, checkpoint: TCheckpoint | null, env: Env, updateCheckpointFn?: (checkpoint: Checkpoint) => Promise<void>): Promise<PaginateResult<TCheckpoint>>;
|
|
92
|
-
}
|
|
93
|
-
//# sourceMappingURL=paginated.d.ts.map
|
package/dist/paginated.d.ts.map
DELETED
|
@@ -1 +0,0 @@
|
|
|
1
|
-
{"version":3,"file":"paginated.d.ts","sourceRoot":"","sources":["../src/paginated.ts"],"names":[],"mappings":"AAAA;;;;;;GAMG;AAEH,OAAO,EAAE,QAAQ,EAAkB,MAAM,WAAW,CAAC;AAErD,OAAO,KAAK,EAAE,UAAU,EAAE,OAAO,EAAE,GAAG,EAAE,WAAW,EAAE,MAAM,YAAY,CAAC;AAExE;;GAEG;AACH,MAAM,WAAW,gBAAgB;IAC/B,yDAAyD;IACzD,QAAQ,EAAE,MAAM,CAAC;IACjB,yEAAyE;IACzE,QAAQ,EAAE,MAAM,CAAC;IACjB,gEAAgE;IAChE,WAAW,EAAE,MAAM,CAAC;IACpB,gFAAgF;IAChF,qBAAqB,EAAE,OAAO,CAAC;CAChC;AAED;;GAEG;AACH,MAAM,WAAW,eAAe,CAAC,KAAK;IACpC,2BAA2B;IAC3B,KAAK,EAAE,KAAK,EAAE,CAAC;IACf,wDAAwD;IACxD,SAAS,EAAE,MAAM,GAAG,IAAI,CAAC;IACzB,kEAAkE;IAClE,QAAQ,CAAC,EAAE,MAAM,CAAC;CACnB;AAED;;GAEG;AACH,MAAM,WAAW,mBAAoB,SAAQ,UAAU;IACrD,yCAAyC;IACzC,gBAAgB,CAAC,EAAE,MAAM,GAAG,IAAI,CAAC;IACjC,0EAA0E;IAC1E,gBAAgB,CAAC,EAAE,OAAO,CAAC;CAC5B;AAED;;GAEG;AACH,MAAM,WAAW,cAAc,CAAC,WAAW,SAAS,UAAU;IAC5D,QAAQ,EAAE,OAAO,EAAE,CAAC;IACpB,UAAU,EAAE,WAAW,CAAC;IACxB,SAAS,CAAC,EAAE,GAAG,CAAC,MAAM,EAAE,MAAM,CAAC,CAAC;IAChC,qBAAqB,CAAC,EAAE,IAAI,CAAC;CAC9B;AAED;;GAEG;AACH,8BAAsB,aAAa,CACjC,KAAK,EACL,WAAW,SAAS,mBAAmB,GAAG,mBAAmB,CAC7D,SAAQ,QAAQ;IAChB;;OAEG;IACH,SAAS,CAAC,mBAAmB,IAAI,gBAAgB;IASjD;;OAEG;IACH,SAAS,CAAC,QAAQ,CAAC,SAAS,CAC1B,MAAM,EAAE,MAAM,GAAG,IAAI,EACrB,OAAO,EAAE,WAAW,EACpB,GAAG,EAAE,GAAG,GACP,OAAO,CAAC,eAAe,CAAC,KAAK,CAAC,CAAC;IAElC;;OAEG;IACH,SAAS,CAAC,QAAQ,CAAC,aAAa,CAAC,IAAI,EAAE,KAAK,EAAE,OAAO,EAAE,WAAW,GAAG,OAAO;IAE5E;;OAEG;IACH,SAAS,CAAC,QAAQ,CAAC,WAAW,CAAC,IAAI,EAAE,KAAK,GAAG,IAAI;IAEjD;;OAEG;IACH,SAAS,CAAC,UAAU,CAAC,KAAK,EAAE,KAAK,EAAE,QAAQ,EAAE,WAAW,GAAG,OAAO;IAIlE;;OAEG;IACH,SAAS,CAAC,WAAW,CAAC,KAAK,EAAE,KAAK,GAAG,MAAM,GAAG,IAAI;IAIlD;;OAEG;IACH,SAAS,CAAC,kBAAkB,CAAC,UAAU,EAAE,WAAW,GAAG,IAAI,GAAG,MAAM,GAAG,IAAI;IAI3E;;OAEG;IACH,SAAS,CAAC,gBAAgB,CACxB,QAAQ,EAAE,WAAW,GAAG,IAAI,EAC5B,aAAa,EAAE,OAAO,GAAG,IAAI,EAC7B,SAAS,EAAE,MAAM,GAAG,IAAI,EACxB,cAAc,EAAE,MAAM,GACrB,WAAW;IAUd;;OAEG;cACa,QAAQ,CACtB,OAAO,EAAE,WAAW,EACpB,UAAU,EAAE,WAAW,GAAG,IAAI,EAC9B,GAAG,EAAE,GAAG,EACR,kBAAkB,CAAC,EAAE,CAAC,UAAU,EAAE,UAAU,KAAK,OAAO,CAAC,IAAI,CAAC,GAC7D,OAAO,CAAC,cAAc,CAAC,WAAW,CAAC,CAAC;CA6JxC"}
|
package/dist/paginated.js
DELETED
|
@@ -1,167 +0,0 @@
|
|
|
1
|
-
/**
|
|
2
|
-
* Paginated Feed Base Class
|
|
3
|
-
*
|
|
4
|
-
* Provides a reusable pagination pattern for feeds that fetch data in pages.
|
|
5
|
-
* Uses the template method pattern - subclasses implement specific methods while
|
|
6
|
-
* the base class handles the pagination loop, rate limiting, and checkpoint management.
|
|
7
|
-
*/
|
|
8
|
-
import { BaseFeed, RateLimitError } from './base.js';
|
|
9
|
-
import { sdkLogger } from './logger.js';
|
|
10
|
-
/**
|
|
11
|
-
* Base class for feeds with cursor/page-based pagination
|
|
12
|
-
*/
|
|
13
|
-
export class PaginatedFeed extends BaseFeed {
|
|
14
|
-
/**
|
|
15
|
-
* Default pagination configuration
|
|
16
|
-
*/
|
|
17
|
-
getPaginationConfig() {
|
|
18
|
-
return {
|
|
19
|
-
maxPages: 50,
|
|
20
|
-
pageSize: 100,
|
|
21
|
-
rateLimitMs: 1000,
|
|
22
|
-
incrementalCheckpoint: false,
|
|
23
|
-
};
|
|
24
|
-
}
|
|
25
|
-
/**
|
|
26
|
-
* OPTIONAL: Filter items before transformation
|
|
27
|
-
*/
|
|
28
|
-
filterItem(_item, _options) {
|
|
29
|
-
return true;
|
|
30
|
-
}
|
|
31
|
-
/**
|
|
32
|
-
* OPTIONAL: Extract parent ID for hierarchical content
|
|
33
|
-
*/
|
|
34
|
-
getParentId(_item) {
|
|
35
|
-
return null;
|
|
36
|
-
}
|
|
37
|
-
/**
|
|
38
|
-
* OPTIONAL: Extract pagination token from checkpoint
|
|
39
|
-
*/
|
|
40
|
-
getPaginationToken(checkpoint) {
|
|
41
|
-
return checkpoint?.pagination_token ?? null;
|
|
42
|
-
}
|
|
43
|
-
/**
|
|
44
|
-
* OPTIONAL: Create checkpoint with feed-specific fields
|
|
45
|
-
*/
|
|
46
|
-
createCheckpoint(existing, latestContent, nextToken, itemsProcessed) {
|
|
47
|
-
return {
|
|
48
|
-
updated_at: new Date(),
|
|
49
|
-
last_timestamp: latestContent?.occurred_at ?? existing?.last_timestamp,
|
|
50
|
-
pagination_token: nextToken,
|
|
51
|
-
total_items_processed: (existing?.total_items_processed || 0) + itemsProcessed,
|
|
52
|
-
initial_complete: existing?.initial_complete ?? false,
|
|
53
|
-
};
|
|
54
|
-
}
|
|
55
|
-
/**
|
|
56
|
-
* Main pagination loop - handles both initial and incremental syncs
|
|
57
|
-
*/
|
|
58
|
-
async paginate(options, checkpoint, env, updateCheckpointFn) {
|
|
59
|
-
const config = this.getPaginationConfig();
|
|
60
|
-
const existingToken = this.getPaginationToken(checkpoint);
|
|
61
|
-
const parentMap = new Map();
|
|
62
|
-
const initialComplete = checkpoint?.initial_complete ?? (!!checkpoint?.last_timestamp && !existingToken);
|
|
63
|
-
const isIncremental = initialComplete && !existingToken;
|
|
64
|
-
const lookbackDate = this.getLookbackDate(options);
|
|
65
|
-
const checkpointTimestamp = checkpoint?.last_timestamp ?? null;
|
|
66
|
-
const checkpointDate = checkpointTimestamp
|
|
67
|
-
? checkpointTimestamp instanceof Date
|
|
68
|
-
? checkpointTimestamp
|
|
69
|
-
: new Date(checkpointTimestamp)
|
|
70
|
-
: null;
|
|
71
|
-
const boundaryDate = initialComplete && checkpointDate ? checkpointDate : lookbackDate;
|
|
72
|
-
const allContents = [];
|
|
73
|
-
let cursor = isIncremental ? null : existingToken;
|
|
74
|
-
let pageCount = 0;
|
|
75
|
-
let stopReason = null;
|
|
76
|
-
let rateLimitRetryMs;
|
|
77
|
-
const modeLabel = isIncremental ? 'incremental' : cursor ? 'resumed' : 'initial';
|
|
78
|
-
sdkLogger.info(`[${this.type}] Starting ${modeLabel} sync (max ${config.maxPages} pages)`);
|
|
79
|
-
while (pageCount < config.maxPages) {
|
|
80
|
-
if (pageCount > 0) {
|
|
81
|
-
await this.sleep(config.rateLimitMs);
|
|
82
|
-
}
|
|
83
|
-
let result;
|
|
84
|
-
try {
|
|
85
|
-
result = await this.fetchPage(cursor, options, env);
|
|
86
|
-
}
|
|
87
|
-
catch (error) {
|
|
88
|
-
if (error instanceof RateLimitError) {
|
|
89
|
-
sdkLogger.warn({ error: error.message }, `[${this.type}] Rate limit hit after ${pageCount} pages, pausing`);
|
|
90
|
-
stopReason = 'rate_limited';
|
|
91
|
-
rateLimitRetryMs = error.retryAfterMs;
|
|
92
|
-
break;
|
|
93
|
-
}
|
|
94
|
-
throw error;
|
|
95
|
-
}
|
|
96
|
-
const rawCount = result.rawCount ?? result.items.length;
|
|
97
|
-
if (result.items.length === 0) {
|
|
98
|
-
sdkLogger.info(`[${this.type}] Empty page at ${pageCount + 1}, stopping`);
|
|
99
|
-
stopReason = 'empty_page';
|
|
100
|
-
break;
|
|
101
|
-
}
|
|
102
|
-
const pageContents = [];
|
|
103
|
-
for (const item of result.items) {
|
|
104
|
-
if (!this.filterItem(item, options))
|
|
105
|
-
continue;
|
|
106
|
-
const content = this.transformItem(item, options);
|
|
107
|
-
pageContents.push(content);
|
|
108
|
-
const parentId = this.getParentId(item);
|
|
109
|
-
if (parentId) {
|
|
110
|
-
parentMap.set(content.origin_id, parentId);
|
|
111
|
-
if (!content.origin_parent_id) {
|
|
112
|
-
content.origin_parent_id = parentId;
|
|
113
|
-
}
|
|
114
|
-
}
|
|
115
|
-
}
|
|
116
|
-
const boundaryContents = pageContents.filter((c) => c.occurred_at >= boundaryDate);
|
|
117
|
-
allContents.push(...boundaryContents);
|
|
118
|
-
pageCount++;
|
|
119
|
-
sdkLogger.info(`[${this.type}] Page ${pageCount}: raw=${rawCount}, ` +
|
|
120
|
-
`filtered=${pageContents.length}, recent=${boundaryContents.length}, ` +
|
|
121
|
-
`nextToken=${result.nextToken ? 'yes' : 'no'}`);
|
|
122
|
-
if (config.incrementalCheckpoint && updateCheckpointFn && allContents.length > 0) {
|
|
123
|
-
const incrementalCP = this.createCheckpoint(checkpoint, allContents[0], result.nextToken, boundaryContents.length);
|
|
124
|
-
await updateCheckpointFn(incrementalCP);
|
|
125
|
-
sdkLogger.debug(`[${this.type}] Saved incremental checkpoint after page ${pageCount}`);
|
|
126
|
-
}
|
|
127
|
-
if (boundaryContents.length === 0 && pageContents.length > 0) {
|
|
128
|
-
sdkLogger.info(`[${this.type}] Reached boundary after ${pageCount} pages`);
|
|
129
|
-
stopReason = 'boundary';
|
|
130
|
-
break;
|
|
131
|
-
}
|
|
132
|
-
if (result.items.length < config.pageSize) {
|
|
133
|
-
sdkLogger.info(`[${this.type}] Partial page (${result.items.length}/${config.pageSize}), end reached`);
|
|
134
|
-
stopReason = 'partial_page';
|
|
135
|
-
break;
|
|
136
|
-
}
|
|
137
|
-
if (!result.nextToken) {
|
|
138
|
-
sdkLogger.info(`[${this.type}] No next token after page ${pageCount}, end reached`);
|
|
139
|
-
stopReason = 'no_next_token';
|
|
140
|
-
break;
|
|
141
|
-
}
|
|
142
|
-
cursor = result.nextToken;
|
|
143
|
-
}
|
|
144
|
-
if (!stopReason && pageCount >= config.maxPages) {
|
|
145
|
-
stopReason = 'max_pages';
|
|
146
|
-
}
|
|
147
|
-
if (stopReason === 'max_pages') {
|
|
148
|
-
sdkLogger.warn(`[${this.type}] Hit max page limit (${config.maxPages})`);
|
|
149
|
-
}
|
|
150
|
-
sdkLogger.info(`[${this.type}] Pagination complete: ${allContents.length} items from ${pageCount} pages`);
|
|
151
|
-
const resumeToken = stopReason === 'max_pages' || stopReason === 'rate_limited' ? cursor : null;
|
|
152
|
-
const shouldMarkComplete = initialComplete ||
|
|
153
|
-
(!initialComplete && stopReason !== 'max_pages' && stopReason !== 'rate_limited');
|
|
154
|
-
const nextSyncRecommendedAt = stopReason === 'rate_limited'
|
|
155
|
-
? new Date(Date.now() + (rateLimitRetryMs ?? config.rateLimitMs))
|
|
156
|
-
: undefined;
|
|
157
|
-
const finalCheckpoint = this.createCheckpoint(checkpoint, allContents[0] || null, resumeToken, allContents.length);
|
|
158
|
-
finalCheckpoint.initial_complete = shouldMarkComplete;
|
|
159
|
-
return {
|
|
160
|
-
contents: allContents,
|
|
161
|
-
checkpoint: finalCheckpoint,
|
|
162
|
-
parentMap: parentMap.size > 0 ? parentMap : undefined,
|
|
163
|
-
nextSyncRecommendedAt,
|
|
164
|
-
};
|
|
165
|
-
}
|
|
166
|
-
}
|
|
167
|
-
//# sourceMappingURL=paginated.js.map
|
package/dist/paginated.js.map
DELETED
|
@@ -1 +0,0 @@
|
|
|
1
|
-
{"version":3,"file":"paginated.js","sourceRoot":"","sources":["../src/paginated.ts"],"names":[],"mappings":"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"}
|