surfsky 0.0.6 → 0.0.9
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/index.d.ts +88 -5
- package/dist/index.js +78 -41
- package/package.json +1 -1
package/dist/index.d.ts
CHANGED
|
@@ -45,6 +45,20 @@ declare const regionalPool: z.ZodEnum<{
|
|
|
45
45
|
western: "western";
|
|
46
46
|
westeurope: "westeurope";
|
|
47
47
|
}>;
|
|
48
|
+
declare const captchaType: z.ZodEnum<{
|
|
49
|
+
bls: "bls";
|
|
50
|
+
click: "click";
|
|
51
|
+
datadome: "datadome";
|
|
52
|
+
datadome_audio: "datadome_audio";
|
|
53
|
+
datadome_click: "datadome_click";
|
|
54
|
+
funcaptcha: "funcaptcha";
|
|
55
|
+
geetest: "geetest";
|
|
56
|
+
hcaptcha: "hcaptcha";
|
|
57
|
+
image: "image";
|
|
58
|
+
perimeterx: "perimeterx";
|
|
59
|
+
recaptcha: "recaptcha";
|
|
60
|
+
turnstile: "turnstile";
|
|
61
|
+
}>;
|
|
48
62
|
type OS = z.infer<typeof os>;
|
|
49
63
|
type Arch = z.infer<typeof arch>;
|
|
50
64
|
type DeviceType = z.infer<typeof deviceType>;
|
|
@@ -52,6 +66,7 @@ type WaitUntil = z.infer<typeof waitUntil>;
|
|
|
52
66
|
type ProxyType = z.infer<typeof proxyType>;
|
|
53
67
|
type ProfileOrdering = z.infer<typeof profileOrdering>;
|
|
54
68
|
type RegionalPool = z.infer<typeof regionalPool>;
|
|
69
|
+
type CaptchaType = z.infer<typeof captchaType>;
|
|
55
70
|
type ExportFormat = "json" | "netscape";
|
|
56
71
|
type MouseButton = "left" | "right" | "middle";
|
|
57
72
|
type KeyModifier = "Alt" | "Control" | "Meta" | "Shift";
|
|
@@ -178,6 +193,27 @@ declare const browserSettings: z.ZodObject<{
|
|
|
178
193
|
cache_key: z.ZodOptional<z.ZodString>;
|
|
179
194
|
}, z.core.$strict>;
|
|
180
195
|
type BrowserSettings = z.infer<typeof browserSettings>;
|
|
196
|
+
declare const antiCaptcha: z.ZodObject<{
|
|
197
|
+
enabled: z.ZodOptional<z.ZodBoolean>;
|
|
198
|
+
auto_captcha_types: z.ZodOptional<z.ZodArray<z.ZodEnum<{
|
|
199
|
+
bls: "bls";
|
|
200
|
+
click: "click";
|
|
201
|
+
datadome: "datadome";
|
|
202
|
+
datadome_audio: "datadome_audio";
|
|
203
|
+
datadome_click: "datadome_click";
|
|
204
|
+
funcaptcha: "funcaptcha";
|
|
205
|
+
geetest: "geetest";
|
|
206
|
+
hcaptcha: "hcaptcha";
|
|
207
|
+
image: "image";
|
|
208
|
+
perimeterx: "perimeterx";
|
|
209
|
+
recaptcha: "recaptcha";
|
|
210
|
+
turnstile: "turnstile";
|
|
211
|
+
}>>>;
|
|
212
|
+
gemini_api_key: z.ZodOptional<z.ZodString>;
|
|
213
|
+
disable_external_providers: z.ZodOptional<z.ZodBoolean>;
|
|
214
|
+
external_providers_initially_enabled: z.ZodOptional<z.ZodBoolean>;
|
|
215
|
+
}, z.core.$strict>;
|
|
216
|
+
type AntiCaptcha = z.infer<typeof antiCaptcha>;
|
|
181
217
|
declare const shared: z.ZodObject<{
|
|
182
218
|
tier: z.ZodLiteral<"shared">;
|
|
183
219
|
country: z.ZodOptional<z.ZodString>;
|
|
@@ -371,6 +407,26 @@ declare const oneTimeStartRequest: z.ZodObject<{
|
|
|
371
407
|
cache_enabled: z.ZodOptional<z.ZodBoolean>;
|
|
372
408
|
cache_key: z.ZodOptional<z.ZodString>;
|
|
373
409
|
}, z.core.$strict>>;
|
|
410
|
+
anti_captcha: z.ZodOptional<z.ZodObject<{
|
|
411
|
+
enabled: z.ZodOptional<z.ZodBoolean>;
|
|
412
|
+
auto_captcha_types: z.ZodOptional<z.ZodArray<z.ZodEnum<{
|
|
413
|
+
bls: "bls";
|
|
414
|
+
click: "click";
|
|
415
|
+
datadome: "datadome";
|
|
416
|
+
datadome_audio: "datadome_audio";
|
|
417
|
+
datadome_click: "datadome_click";
|
|
418
|
+
funcaptcha: "funcaptcha";
|
|
419
|
+
geetest: "geetest";
|
|
420
|
+
hcaptcha: "hcaptcha";
|
|
421
|
+
image: "image";
|
|
422
|
+
perimeterx: "perimeterx";
|
|
423
|
+
recaptcha: "recaptcha";
|
|
424
|
+
turnstile: "turnstile";
|
|
425
|
+
}>>>;
|
|
426
|
+
gemini_api_key: z.ZodOptional<z.ZodString>;
|
|
427
|
+
disable_external_providers: z.ZodOptional<z.ZodBoolean>;
|
|
428
|
+
external_providers_initially_enabled: z.ZodOptional<z.ZodBoolean>;
|
|
429
|
+
}, z.core.$strict>>;
|
|
374
430
|
enable_chromedriver: z.ZodOptional<z.ZodBoolean>;
|
|
375
431
|
extensions: z.ZodOptional<z.ZodArray<z.ZodString>>;
|
|
376
432
|
proxy_blacklist: z.ZodOptional<z.ZodArray<z.ZodString>>;
|
|
@@ -390,6 +446,26 @@ declare const profileStartRequest: z.ZodObject<{
|
|
|
390
446
|
cache_enabled: z.ZodOptional<z.ZodBoolean>;
|
|
391
447
|
cache_key: z.ZodOptional<z.ZodString>;
|
|
392
448
|
}, z.core.$strict>>;
|
|
449
|
+
anti_captcha: z.ZodOptional<z.ZodObject<{
|
|
450
|
+
enabled: z.ZodOptional<z.ZodBoolean>;
|
|
451
|
+
auto_captcha_types: z.ZodOptional<z.ZodArray<z.ZodEnum<{
|
|
452
|
+
bls: "bls";
|
|
453
|
+
click: "click";
|
|
454
|
+
datadome: "datadome";
|
|
455
|
+
datadome_audio: "datadome_audio";
|
|
456
|
+
datadome_click: "datadome_click";
|
|
457
|
+
funcaptcha: "funcaptcha";
|
|
458
|
+
geetest: "geetest";
|
|
459
|
+
hcaptcha: "hcaptcha";
|
|
460
|
+
image: "image";
|
|
461
|
+
perimeterx: "perimeterx";
|
|
462
|
+
recaptcha: "recaptcha";
|
|
463
|
+
turnstile: "turnstile";
|
|
464
|
+
}>>>;
|
|
465
|
+
gemini_api_key: z.ZodOptional<z.ZodString>;
|
|
466
|
+
disable_external_providers: z.ZodOptional<z.ZodBoolean>;
|
|
467
|
+
external_providers_initially_enabled: z.ZodOptional<z.ZodBoolean>;
|
|
468
|
+
}, z.core.$strict>>;
|
|
393
469
|
enable_chromedriver: z.ZodOptional<z.ZodBoolean>;
|
|
394
470
|
extensions: z.ZodOptional<z.ZodArray<z.ZodString>>;
|
|
395
471
|
proxy_blacklist: z.ZodOptional<z.ZodArray<z.ZodString>>;
|
|
@@ -1266,7 +1342,6 @@ declare class Deadline {
|
|
|
1266
1342
|
readonly until: number;
|
|
1267
1343
|
constructor(timeout: number | null | undefined, message: string);
|
|
1268
1344
|
error(): BrowserTimeoutError;
|
|
1269
|
-
check(): void;
|
|
1270
1345
|
race<T>(promise: Promise<T>): Promise<T>;
|
|
1271
1346
|
}
|
|
1272
1347
|
declare class CapturedResponse {
|
|
@@ -1330,6 +1405,7 @@ declare class Page extends Actions {
|
|
|
1330
1405
|
/** @internal */
|
|
1331
1406
|
_send(method: string, params?: Record<string, unknown>): Promise<any>;
|
|
1332
1407
|
/** @internal */
|
|
1408
|
+
_change(): Promise<void>;
|
|
1333
1409
|
_waitReady(): Promise<void>;
|
|
1334
1410
|
/** @internal */
|
|
1335
1411
|
_setup(waiting: boolean): Promise<void>;
|
|
@@ -1428,6 +1504,7 @@ declare class Browser extends Page implements AsyncDisposable {
|
|
|
1428
1504
|
/** @internal */ _pages: Map<string, Page>;
|
|
1429
1505
|
/** @internal aborts on close: background sleeps end early */
|
|
1430
1506
|
_signal: AbortSignal;
|
|
1507
|
+
_changed: PromiseWithResolvers<void>;
|
|
1431
1508
|
constructor(session: Session, options?: BrowserOptions);
|
|
1432
1509
|
get internalUuid(): string;
|
|
1433
1510
|
get cdp(): CDPClient;
|
|
@@ -1466,6 +1543,8 @@ declare class Browser extends Page implements AsyncDisposable {
|
|
|
1466
1543
|
/** @internal */
|
|
1467
1544
|
_onAttached(event: Record<string, any>): void;
|
|
1468
1545
|
/** @internal */
|
|
1546
|
+
_notify(): void;
|
|
1547
|
+
/** @internal */
|
|
1469
1548
|
_onDetached(event: Record<string, any>): void;
|
|
1470
1549
|
/** @internal */
|
|
1471
1550
|
_drop(page: Page): void;
|
|
@@ -1628,6 +1707,7 @@ interface RequestOptions {
|
|
|
1628
1707
|
interface SessionStartOptions extends SessionOptions {
|
|
1629
1708
|
/** A saved profile to start; a one-time session when absent. */
|
|
1630
1709
|
profileUuid?: string;
|
|
1710
|
+
signal?: AbortSignal;
|
|
1631
1711
|
}
|
|
1632
1712
|
interface BrowserStartOptions extends SessionStartOptions {
|
|
1633
1713
|
/** CDP resource types to drop: `["image", "font", "media"]` saves proxy traffic. */
|
|
@@ -1674,7 +1754,7 @@ declare class Surfsky implements AsyncDisposable {
|
|
|
1674
1754
|
/** An open `BrowserPool`. `close()` stops every browser in it. */
|
|
1675
1755
|
browsers(options?: PoolOptions): Promise<BrowserPool>;
|
|
1676
1756
|
/** `browsers()` and `pool.map()` in 1 call. */
|
|
1677
|
-
map<I, R>(handler: PoolHandler<I, R>, items: Iterable<I>, options?: PoolOptions): Promise<PoolOutcome<I, R>[]>;
|
|
1757
|
+
map<I, R>(handler: PoolHandler<I, R>, items: Iterable<I>, options?: PoolOptions & LeaseOptions): Promise<PoolOutcome<I, R>[]>;
|
|
1678
1758
|
/** Nothing to release with fetch; here for `await using` symmetry. */
|
|
1679
1759
|
close(): Promise<void>;
|
|
1680
1760
|
[Symbol.asyncDispose](): Promise<void>;
|
|
@@ -1704,6 +1784,9 @@ type PoolOutcome<I, R> = {
|
|
|
1704
1784
|
index: number;
|
|
1705
1785
|
error: unknown;
|
|
1706
1786
|
};
|
|
1787
|
+
interface LeaseOptions {
|
|
1788
|
+
signal?: AbortSignal;
|
|
1789
|
+
}
|
|
1707
1790
|
declare class BrowserPool implements AsyncDisposable {
|
|
1708
1791
|
#private;
|
|
1709
1792
|
readonly sessionOptions: SessionOptions;
|
|
@@ -1717,12 +1800,12 @@ declare class BrowserPool implements AsyncDisposable {
|
|
|
1717
1800
|
close(): Promise<void>;
|
|
1718
1801
|
[Symbol.asyncDispose](): Promise<void>;
|
|
1719
1802
|
/** Run `fn` on a live browser, then hand the browser back. Waits while all are busy. */
|
|
1720
|
-
lease<R>(fn: (browser: Browser) => Promise<R
|
|
1803
|
+
lease<R>(fn: (browser: Browser) => Promise<R>, { signal }?: LeaseOptions): Promise<R>;
|
|
1721
1804
|
/** Run every item through `handler` on a leased browser, `capacity` at a time. */
|
|
1722
|
-
map<I, R>(handler: PoolHandler<I, R>, items: Iterable<I
|
|
1805
|
+
map<I, R>(handler: PoolHandler<I, R>, items: Iterable<I>, { signal }?: LeaseOptions): Promise<PoolOutcome<I, R>[]>;
|
|
1723
1806
|
}
|
|
1724
1807
|
//#endregion
|
|
1725
1808
|
//#region src/version.d.ts
|
|
1726
1809
|
declare const VERSION: string;
|
|
1727
1810
|
//#endregion
|
|
1728
|
-
export { APIConnectionError, APIError, APIErrorOptions, APITimeoutError, Account, Actions, type ActiveProfile, type Arch, AuthenticationError, BadRequestError, type BatchDeleteResult, Browser, type BrowserLimits, type BrowserOptions, BrowserPool, type BrowserSettings, type BrowserStartOptions, BrowserTimeoutError, CDPClient, type CDPClientOptions, CDPError, CapturedResponse, type ClickOptions, ConfigurationError, ConflictError, type Cookie, type CookieInput, type CreateWebSocket, type DblclickOptions, type DeviceModel, type DeviceModelsOptions, type DeviceType, type DialogHandler, type DomainRoute, type DragOptions, type EvaluateOptions, type EventHandler, type ExportFormat, type Extension, type ExtensionFile, Extensions, type Fingerprint, Fingerprints, ForbiddenError, type Geolocation, type GotoOptions, type HoverOptions, type Inspector, type InspectorPage, type KeyModifier, Keyboard, type ListPageOptions, type ListPageRequest, type Logger, type Loose, type ManagedSession, type MediaDevices, MonthlySessionLimitError, Mouse, type MouseButton, type MouseClickOptions, type Noise, NotFoundError, type OS, type OneTimeStartRequest, Page, PageClosedError, PaymentRequiredError, type PoolHandler, type PoolOptions, type PoolOutcome, type PremiumProxy, PremiumTrafficLimitError, type PressOptions, type Profile, type ProfileCreate, type ProfileCreateRequest, type ProfileOrdering, type ProfileRef, type ProfileStartRequest, type ProfileSummary, type ProfileUpdate, type ProfileUpdateRequest, Profiles, Proxies, type ProxyCity, type ProxyCountry, ProxyCycle, type ProxyFactory, type ProxyInput, type ProxyLike, type ProxyQuota, ProxyRandom, type ProxyRegion, type ProxySource, ProxyTemplate, type ProxyType, RESOURCE_TYPES, RateLimitError, type RegionalPool, type Renderer, type RequestOptions, type ScrapeOptions, type ScrapeRequest, type ScrapeResult, type Screen, type ScreenshotOptions, type ScrollBehavior, type ScrollOptions, type ScrollToOptions, ServerError, type Session, type SessionLimits, type SessionOptions, type SessionStartOptions, type SharedProxy, type SharedProxyQuota, SharedTrafficLimitError, type Spec, type StopAllResult, StopRun, type StorageOptions, Surfsky, SurfskyError, type SurfskyOptions, type TrafficStats, type TrafficVolume, VERSION, ValidationError, type WaitOptions, type WaitUntil, type WebSocketLike, type isRecord, type parseListPageRequest, type parseOneTimeStartRequest, type parseProfileCreateRequest, type parseProfileStartRequest, type parseProfileUpdateRequest, type parseProxyLike, type parseScrapeRequest };
|
|
1811
|
+
export { APIConnectionError, APIError, APIErrorOptions, APITimeoutError, Account, Actions, type ActiveProfile, type AntiCaptcha, type Arch, AuthenticationError, BadRequestError, type BatchDeleteResult, Browser, type BrowserLimits, type BrowserOptions, BrowserPool, type BrowserSettings, type BrowserStartOptions, BrowserTimeoutError, CDPClient, type CDPClientOptions, CDPError, type CaptchaType, CapturedResponse, type ClickOptions, ConfigurationError, ConflictError, type Cookie, type CookieInput, type CreateWebSocket, type DblclickOptions, type DeviceModel, type DeviceModelsOptions, type DeviceType, type DialogHandler, type DomainRoute, type DragOptions, type EvaluateOptions, type EventHandler, type ExportFormat, type Extension, type ExtensionFile, Extensions, type Fingerprint, Fingerprints, ForbiddenError, type Geolocation, type GotoOptions, type HoverOptions, type Inspector, type InspectorPage, type KeyModifier, Keyboard, type ListPageOptions, type ListPageRequest, type Logger, type Loose, type ManagedSession, type MediaDevices, MonthlySessionLimitError, Mouse, type MouseButton, type MouseClickOptions, type Noise, NotFoundError, type OS, type OneTimeStartRequest, Page, PageClosedError, PaymentRequiredError, type PoolHandler, type PoolOptions, type PoolOutcome, type PremiumProxy, PremiumTrafficLimitError, type PressOptions, type Profile, type ProfileCreate, type ProfileCreateRequest, type ProfileOrdering, type ProfileRef, type ProfileStartRequest, type ProfileSummary, type ProfileUpdate, type ProfileUpdateRequest, Profiles, Proxies, type ProxyCity, type ProxyCountry, ProxyCycle, type ProxyFactory, type ProxyInput, type ProxyLike, type ProxyQuota, ProxyRandom, type ProxyRegion, type ProxySource, ProxyTemplate, type ProxyType, RESOURCE_TYPES, RateLimitError, type RegionalPool, type Renderer, type RequestOptions, type ScrapeOptions, type ScrapeRequest, type ScrapeResult, type Screen, type ScreenshotOptions, type ScrollBehavior, type ScrollOptions, type ScrollToOptions, ServerError, type Session, type SessionLimits, type SessionOptions, type SessionStartOptions, type SharedProxy, type SharedProxyQuota, SharedTrafficLimitError, type Spec, type StopAllResult, StopRun, type StorageOptions, Surfsky, SurfskyError, type SurfskyOptions, type TrafficStats, type TrafficVolume, VERSION, ValidationError, type WaitOptions, type WaitUntil, type WebSocketLike, type isRecord, type parseListPageRequest, type parseOneTimeStartRequest, type parseProfileCreateRequest, type parseProfileStartRequest, type parseProfileUpdateRequest, type parseProxyLike, type parseScrapeRequest };
|
package/dist/index.js
CHANGED
|
@@ -277,6 +277,20 @@ const regionalPool = z.enum([
|
|
|
277
277
|
"oceania",
|
|
278
278
|
"mena"
|
|
279
279
|
]);
|
|
280
|
+
const captchaType = z.enum([
|
|
281
|
+
"recaptcha",
|
|
282
|
+
"hcaptcha",
|
|
283
|
+
"turnstile",
|
|
284
|
+
"perimeterx",
|
|
285
|
+
"geetest",
|
|
286
|
+
"bls",
|
|
287
|
+
"datadome",
|
|
288
|
+
"datadome_audio",
|
|
289
|
+
"datadome_click",
|
|
290
|
+
"click",
|
|
291
|
+
"image",
|
|
292
|
+
"funcaptcha"
|
|
293
|
+
]);
|
|
280
294
|
const loose = () => z.string();
|
|
281
295
|
function isRecord(value) {
|
|
282
296
|
return typeof value === "object" && value !== null && !Array.isArray(value);
|
|
@@ -329,6 +343,13 @@ const browserSettings = z.strictObject({
|
|
|
329
343
|
cache_enabled: z.boolean().optional(),
|
|
330
344
|
cache_key: z.string().optional()
|
|
331
345
|
});
|
|
346
|
+
const antiCaptcha = z.strictObject({
|
|
347
|
+
enabled: z.boolean().optional(),
|
|
348
|
+
auto_captcha_types: z.array(captchaType).optional(),
|
|
349
|
+
gemini_api_key: z.string().optional(),
|
|
350
|
+
disable_external_providers: z.boolean().optional(),
|
|
351
|
+
external_providers_initially_enabled: z.boolean().optional()
|
|
352
|
+
});
|
|
332
353
|
const shared = z.strictObject({
|
|
333
354
|
tier: z.literal("shared"),
|
|
334
355
|
country: z.string().min(1).optional()
|
|
@@ -383,6 +404,7 @@ const oneTimeStartRequest = z.strictObject({
|
|
|
383
404
|
fingerprint: fingerprint.optional(),
|
|
384
405
|
proxy: proxyLike.nullish(),
|
|
385
406
|
browser_settings: browserSettings.optional(),
|
|
407
|
+
anti_captcha: antiCaptcha.optional(),
|
|
386
408
|
enable_chromedriver: z.boolean().optional(),
|
|
387
409
|
extensions: z.array(z.string()).max(5).optional(),
|
|
388
410
|
proxy_blacklist: z.array(z.string()).optional(),
|
|
@@ -920,9 +942,6 @@ var Deadline = class {
|
|
|
920
942
|
error() {
|
|
921
943
|
return new BrowserTimeoutError(`${this.message} within ${this.timeout}ms`);
|
|
922
944
|
}
|
|
923
|
-
check() {
|
|
924
|
-
if (Date.now() >= this.until) throw this.error();
|
|
925
|
-
}
|
|
926
945
|
race(promise) {
|
|
927
946
|
if (this.timeout === null) return promise;
|
|
928
947
|
return withTimeout(promise, Math.max(0, this.until - Date.now()), () => this.error());
|
|
@@ -1064,6 +1083,9 @@ var Page = class extends Actions {
|
|
|
1064
1083
|
}
|
|
1065
1084
|
}
|
|
1066
1085
|
/** @internal */
|
|
1086
|
+
_change() {
|
|
1087
|
+
return Promise.race([this._browser._changed.promise, sleep(100)]);
|
|
1088
|
+
}
|
|
1067
1089
|
async _waitReady() {
|
|
1068
1090
|
await this._ready.wait();
|
|
1069
1091
|
if (this._setupError !== void 0) throw this._setupError;
|
|
@@ -1113,8 +1135,7 @@ var Page = class extends Actions {
|
|
|
1113
1135
|
const deadline = new Deadline(options.timeout ?? 3e4, `the page did not reach '${state}'`);
|
|
1114
1136
|
while (!this._milestones.has(milestone)) {
|
|
1115
1137
|
this._requireOpen();
|
|
1116
|
-
deadline.
|
|
1117
|
-
await sleep(100);
|
|
1138
|
+
await deadline.race(this._change());
|
|
1118
1139
|
}
|
|
1119
1140
|
}
|
|
1120
1141
|
async goto(url, options = {}) {
|
|
@@ -1166,8 +1187,7 @@ var Page = class extends Actions {
|
|
|
1166
1187
|
const deadline = new Deadline(timeout, "history did not move");
|
|
1167
1188
|
while (true) {
|
|
1168
1189
|
if ((await deadline.race(this.send("Page.getNavigationHistory"))).currentIndex === index) break;
|
|
1169
|
-
deadline.
|
|
1170
|
-
await sleep(100);
|
|
1190
|
+
await deadline.race(sleep(100));
|
|
1171
1191
|
}
|
|
1172
1192
|
return this.url();
|
|
1173
1193
|
}
|
|
@@ -1192,8 +1212,7 @@ var Page = class extends Actions {
|
|
|
1192
1212
|
const found = this._responses.find((response) => response.url.includes(fragment));
|
|
1193
1213
|
if (found !== void 0) return found;
|
|
1194
1214
|
this._requireOpen();
|
|
1195
|
-
deadline.
|
|
1196
|
-
await sleep(100);
|
|
1215
|
+
await deadline.race(this._change());
|
|
1197
1216
|
}
|
|
1198
1217
|
}
|
|
1199
1218
|
/** @internal */
|
|
@@ -1221,6 +1240,7 @@ var Page = class extends Actions {
|
|
|
1221
1240
|
this._browser.logger.debug(`no body for ${String(response.url)}: ${String(err)}`);
|
|
1222
1241
|
}
|
|
1223
1242
|
into.push(new CapturedResponse(typeof response.url === "string" ? response.url : "", typeof response.status === "number" ? response.status : 0, isRecord(response.headers) ? response.headers : {}, body));
|
|
1243
|
+
this._browser._notify();
|
|
1224
1244
|
}
|
|
1225
1245
|
localStorage() {
|
|
1226
1246
|
return this.#storage(true);
|
|
@@ -1338,8 +1358,7 @@ var Page = class extends Actions {
|
|
|
1338
1358
|
while (true) {
|
|
1339
1359
|
const value = await deadline.race(this.evaluate(expression, rest));
|
|
1340
1360
|
if (value) return value;
|
|
1341
|
-
deadline.
|
|
1342
|
-
await sleep(100);
|
|
1361
|
+
await deadline.race(sleep(100));
|
|
1343
1362
|
}
|
|
1344
1363
|
}
|
|
1345
1364
|
async innerText(selector) {
|
|
@@ -1413,10 +1432,7 @@ var Page = class extends Actions {
|
|
|
1413
1432
|
const visible = options.visible ?? true;
|
|
1414
1433
|
const state = visible ? "visible" : "in the document";
|
|
1415
1434
|
const deadline = new Deadline(options.timeout ?? 3e4, `'${selector}' was not ${state}`);
|
|
1416
|
-
while (!await deadline.race(this.#matches(selector, visible)))
|
|
1417
|
-
deadline.check();
|
|
1418
|
-
await sleep(100);
|
|
1419
|
-
}
|
|
1435
|
+
while (!await deadline.race(this.#matches(selector, visible))) await deadline.race(sleep(100));
|
|
1420
1436
|
}
|
|
1421
1437
|
async #matches(selector, visible) {
|
|
1422
1438
|
let box;
|
|
@@ -1472,8 +1488,7 @@ var Page = class extends Actions {
|
|
|
1472
1488
|
while (true) {
|
|
1473
1489
|
const url = await deadline.race(this.url());
|
|
1474
1490
|
if (url.includes(fragment)) return url;
|
|
1475
|
-
deadline.
|
|
1476
|
-
await sleep(100);
|
|
1491
|
+
await deadline.race(sleep(100));
|
|
1477
1492
|
}
|
|
1478
1493
|
}
|
|
1479
1494
|
/** The first match has a bounding box. */
|
|
@@ -1551,6 +1566,7 @@ var Page = class extends Actions {
|
|
|
1551
1566
|
this._loaderId = loaderId;
|
|
1552
1567
|
this._milestones = /* @__PURE__ */ new Set([name]);
|
|
1553
1568
|
}
|
|
1569
|
+
this._browser._notify();
|
|
1554
1570
|
this._waiter?.observe(name, loaderId);
|
|
1555
1571
|
}
|
|
1556
1572
|
/** @internal */
|
|
@@ -1663,6 +1679,7 @@ var Browser = class extends Page {
|
|
|
1663
1679
|
#client;
|
|
1664
1680
|
#abort = new AbortController();
|
|
1665
1681
|
#pending = /* @__PURE__ */ new Set();
|
|
1682
|
+
_changed = Promise.withResolvers();
|
|
1666
1683
|
#closing;
|
|
1667
1684
|
#retired = false;
|
|
1668
1685
|
#useCount = 0;
|
|
@@ -1744,8 +1761,7 @@ var Browser = class extends Page {
|
|
|
1744
1761
|
const last = opened[opened.length - 1];
|
|
1745
1762
|
if (last !== void 0) return last;
|
|
1746
1763
|
this._requireOpen();
|
|
1747
|
-
deadline.
|
|
1748
|
-
await sleep(100);
|
|
1764
|
+
await deadline.race(this._change());
|
|
1749
1765
|
}
|
|
1750
1766
|
}
|
|
1751
1767
|
async connect() {
|
|
@@ -1817,8 +1833,7 @@ var Browser = class extends Page {
|
|
|
1817
1833
|
let page = this.#pageFor(targetId);
|
|
1818
1834
|
while (page === void 0) {
|
|
1819
1835
|
this._requireOpen();
|
|
1820
|
-
deadline.
|
|
1821
|
-
await sleep(100);
|
|
1836
|
+
await deadline.race(this._change());
|
|
1822
1837
|
page = this.#pageFor(targetId);
|
|
1823
1838
|
}
|
|
1824
1839
|
await deadline.race(page._waitReady());
|
|
@@ -1848,8 +1863,14 @@ var Browser = class extends Page {
|
|
|
1848
1863
|
page._frameId = page._targetId;
|
|
1849
1864
|
page._ready = new Flag();
|
|
1850
1865
|
this._pages.set(sessionId, page);
|
|
1866
|
+
this._notify();
|
|
1851
1867
|
this._spawn(page._setup(waiting));
|
|
1852
1868
|
}
|
|
1869
|
+
/** @internal */
|
|
1870
|
+
_notify() {
|
|
1871
|
+
this._changed.resolve();
|
|
1872
|
+
this._changed = Promise.withResolvers();
|
|
1873
|
+
}
|
|
1853
1874
|
async #letGo(sessionId, waiting) {
|
|
1854
1875
|
const timeout = this.commandTimeout;
|
|
1855
1876
|
const detach = async () => {
|
|
@@ -1867,6 +1888,7 @@ var Browser = class extends Page {
|
|
|
1867
1888
|
_drop(page) {
|
|
1868
1889
|
this._pages.delete(page._sessionId);
|
|
1869
1890
|
page._closed = true;
|
|
1891
|
+
this._notify();
|
|
1870
1892
|
page._waiter?.fail("page closed");
|
|
1871
1893
|
if (page === this) {
|
|
1872
1894
|
this.logger.warn(`page target gone for ${this.internalUuid}`);
|
|
@@ -1885,6 +1907,7 @@ var Browser = class extends Page {
|
|
|
1885
1907
|
page._closed = true;
|
|
1886
1908
|
page._waiter?.fail("CDP connection closed");
|
|
1887
1909
|
}
|
|
1910
|
+
this._notify();
|
|
1888
1911
|
}
|
|
1889
1912
|
/** @internal track a background task; its failure is logged at debug level */
|
|
1890
1913
|
_spawn(task) {
|
|
@@ -2230,7 +2253,6 @@ var BrowserPool = class {
|
|
|
2230
2253
|
#idle = [];
|
|
2231
2254
|
#owned = 0;
|
|
2232
2255
|
#planFull = false;
|
|
2233
|
-
#planFullError;
|
|
2234
2256
|
#waiters = [];
|
|
2235
2257
|
#capacity = 0;
|
|
2236
2258
|
#slots;
|
|
@@ -2263,7 +2285,6 @@ var BrowserPool = class {
|
|
|
2263
2285
|
this.#capacity = Math.max(1, total);
|
|
2264
2286
|
this.#slots = new Semaphore(this.#capacity);
|
|
2265
2287
|
this.#planFull = false;
|
|
2266
|
-
this.#planFullError = void 0;
|
|
2267
2288
|
this.#owned = 0;
|
|
2268
2289
|
return this;
|
|
2269
2290
|
}
|
|
@@ -2279,14 +2300,17 @@ var BrowserPool = class {
|
|
|
2279
2300
|
return this.close();
|
|
2280
2301
|
}
|
|
2281
2302
|
/** Run `fn` on a live browser, then hand the browser back. Waits while all are busy. */
|
|
2282
|
-
async lease(fn) {
|
|
2303
|
+
async lease(fn, { signal } = {}) {
|
|
2304
|
+
signal?.throwIfAborted();
|
|
2283
2305
|
const slots = this.#requireOpen();
|
|
2284
2306
|
await slots.acquire();
|
|
2285
2307
|
try {
|
|
2286
2308
|
if (this.#slots !== slots) throw new Error("the pool was closed while waiting for a slot");
|
|
2309
|
+
signal?.throwIfAborted();
|
|
2287
2310
|
const browser = await this.#acquire();
|
|
2288
2311
|
browser._lease();
|
|
2289
2312
|
try {
|
|
2313
|
+
signal?.throwIfAborted();
|
|
2290
2314
|
return await fn(browser);
|
|
2291
2315
|
} finally {
|
|
2292
2316
|
await this.#release(browser);
|
|
@@ -2317,7 +2341,6 @@ var BrowserPool = class {
|
|
|
2317
2341
|
const idle = this.#idle.pop();
|
|
2318
2342
|
if (idle !== void 0) return idle;
|
|
2319
2343
|
if (this.#planFull) {
|
|
2320
|
-
if (this.#owned === 0) throw this.#planFullError ?? new RateLimitError("parallel browser limit reached", { statusCode: 429 });
|
|
2321
2344
|
await this.#wait();
|
|
2322
2345
|
continue;
|
|
2323
2346
|
}
|
|
@@ -2326,15 +2349,10 @@ var BrowserPool = class {
|
|
|
2326
2349
|
try {
|
|
2327
2350
|
browser = await this.#startBrowser();
|
|
2328
2351
|
} catch (err) {
|
|
2329
|
-
const full = planIsFull(err);
|
|
2330
2352
|
this.#owned -= 1;
|
|
2331
|
-
|
|
2332
|
-
this.#planFull = true;
|
|
2333
|
-
this.#planFullError = err;
|
|
2334
|
-
}
|
|
2335
|
-
const nothingLeft = this.#owned === 0;
|
|
2353
|
+
this.#planFull = planIsFull(err) && this.#owned > 0;
|
|
2336
2354
|
this.#notifyAll();
|
|
2337
|
-
if (!
|
|
2355
|
+
if (!this.#planFull) throw err;
|
|
2338
2356
|
this.#client.logger.info("plan is full, waiting for a browser of ours");
|
|
2339
2357
|
continue;
|
|
2340
2358
|
}
|
|
@@ -2358,20 +2376,20 @@ var BrowserPool = class {
|
|
|
2358
2376
|
this.#notifyAll();
|
|
2359
2377
|
}
|
|
2360
2378
|
/** Run every item through `handler` on a leased browser, `capacity` at a time. */
|
|
2361
|
-
async map(handler, items) {
|
|
2379
|
+
async map(handler, items, { signal } = {}) {
|
|
2362
2380
|
const work = items[Symbol.iterator]();
|
|
2363
2381
|
const outcomes = [];
|
|
2364
2382
|
let index = 0;
|
|
2365
2383
|
let stopped = false;
|
|
2366
2384
|
const worker = async () => {
|
|
2367
|
-
while (!stopped) {
|
|
2385
|
+
while (!stopped && !signal?.aborted) {
|
|
2368
2386
|
const next = work.next();
|
|
2369
2387
|
if (next.done) return;
|
|
2370
2388
|
const item = next.value;
|
|
2371
2389
|
const at = index;
|
|
2372
2390
|
index += 1;
|
|
2373
2391
|
try {
|
|
2374
|
-
const value = await this.lease((browser) => handler(browser, item));
|
|
2392
|
+
const value = await this.lease((browser) => handler(browser, item), { signal });
|
|
2375
2393
|
outcomes.push({
|
|
2376
2394
|
ok: true,
|
|
2377
2395
|
item,
|
|
@@ -2678,7 +2696,7 @@ var Proxies = class {
|
|
|
2678
2696
|
};
|
|
2679
2697
|
//#endregion
|
|
2680
2698
|
//#region src/version.ts
|
|
2681
|
-
const VERSION = "0.0.
|
|
2699
|
+
const VERSION = "0.0.9";
|
|
2682
2700
|
//#endregion
|
|
2683
2701
|
//#region src/client.ts
|
|
2684
2702
|
function userAgent() {
|
|
@@ -2777,13 +2795,18 @@ var Surfsky = class Surfsky {
|
|
|
2777
2795
|
}
|
|
2778
2796
|
/** Start a session; `stop()` it (or `await using`) so it does not keep billing. */
|
|
2779
2797
|
async session(options = {}) {
|
|
2780
|
-
const { profileUuid, ...rest } = options;
|
|
2798
|
+
const { profileUuid, signal, ...rest } = options;
|
|
2799
|
+
signal?.throwIfAborted();
|
|
2781
2800
|
const session = profileUuid === void 0 ? await this.profiles.startOneTime(rest) : await this.profiles.start(profileUuid, rest);
|
|
2782
2801
|
let stopping;
|
|
2783
2802
|
const stop = () => {
|
|
2784
2803
|
stopping ??= stopSession(this, session.internal_uuid);
|
|
2785
2804
|
return stopping;
|
|
2786
2805
|
};
|
|
2806
|
+
if (signal?.aborted) {
|
|
2807
|
+
await stop();
|
|
2808
|
+
throw signal.reason;
|
|
2809
|
+
}
|
|
2787
2810
|
return {
|
|
2788
2811
|
...session,
|
|
2789
2812
|
stop,
|
|
@@ -2792,11 +2815,12 @@ var Surfsky = class Surfsky {
|
|
|
2792
2815
|
}
|
|
2793
2816
|
/** Start a session and connect a `Browser` to it. `close()` stops the session. */
|
|
2794
2817
|
async browser(options = {}) {
|
|
2795
|
-
const { profileUuid, blockResources, blockUrls, connectTimeout, commandTimeout, createWebSocket, ...sessionOptions } = options;
|
|
2818
|
+
const { profileUuid, signal, blockResources, blockUrls, connectTimeout, commandTimeout, createWebSocket, ...sessionOptions } = options;
|
|
2796
2819
|
const blocked = normalizeBlocked(blockResources);
|
|
2797
2820
|
const urls = normalizeUrls(blockUrls);
|
|
2798
2821
|
const session = await this.session({
|
|
2799
2822
|
profileUuid,
|
|
2823
|
+
signal,
|
|
2800
2824
|
...sessionOptions
|
|
2801
2825
|
});
|
|
2802
2826
|
const browser = new Browser(session, {
|
|
@@ -2808,7 +2832,19 @@ var Surfsky = class Surfsky {
|
|
|
2808
2832
|
logger: this.logger,
|
|
2809
2833
|
onClose: () => session.stop()
|
|
2810
2834
|
});
|
|
2811
|
-
|
|
2835
|
+
const onAbort = () => void browser.close();
|
|
2836
|
+
signal?.addEventListener("abort", onAbort, { once: true });
|
|
2837
|
+
try {
|
|
2838
|
+
await browser.connect();
|
|
2839
|
+
} catch (err) {
|
|
2840
|
+
throw signal?.aborted ? signal.reason : err;
|
|
2841
|
+
} finally {
|
|
2842
|
+
signal?.removeEventListener("abort", onAbort);
|
|
2843
|
+
}
|
|
2844
|
+
if (signal?.aborted) {
|
|
2845
|
+
await browser.close();
|
|
2846
|
+
throw signal.reason;
|
|
2847
|
+
}
|
|
2812
2848
|
return browser;
|
|
2813
2849
|
}
|
|
2814
2850
|
/** An open `BrowserPool`. `close()` stops every browser in it. */
|
|
@@ -2817,9 +2853,10 @@ var Surfsky = class Surfsky {
|
|
|
2817
2853
|
}
|
|
2818
2854
|
/** `browsers()` and `pool.map()` in 1 call. */
|
|
2819
2855
|
async map(handler, items, options = {}) {
|
|
2820
|
-
const
|
|
2856
|
+
const { signal, ...poolOptions } = options;
|
|
2857
|
+
const pool = await this.browsers(poolOptions);
|
|
2821
2858
|
try {
|
|
2822
|
-
return await pool.map(handler, items);
|
|
2859
|
+
return await pool.map(handler, items, { signal });
|
|
2823
2860
|
} finally {
|
|
2824
2861
|
await pool.close();
|
|
2825
2862
|
}
|