scrapely 1.2.3 → 1.2.5

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.
Files changed (86) hide show
  1. package/README.md +119 -1
  2. package/dist/actor.d.ts +703 -0
  3. package/dist/actor.js +1441 -0
  4. package/dist/browser-configuration.d.ts +58 -0
  5. package/dist/browser-configuration.js +128 -0
  6. package/dist/browser-locations.d.ts +5 -0
  7. package/dist/browser-locations.js +5469 -0
  8. package/dist/charging.d.ts +153 -0
  9. package/dist/charging.js +782 -0
  10. package/dist/charging_client.d.ts +18 -0
  11. package/dist/charging_client.js +49 -0
  12. package/dist/configuration.d.ts +121 -0
  13. package/dist/configuration.js +128 -0
  14. package/dist/crypto/secrets.d.ts +44 -0
  15. package/dist/crypto/secrets.js +164 -0
  16. package/dist/events/events-client.d.ts +59 -0
  17. package/dist/events/events-client.js +120 -0
  18. package/dist/events/scrapely-event-manager.d.ts +13 -0
  19. package/dist/events/scrapely-event-manager.js +61 -0
  20. package/dist/index.d.ts +29 -0
  21. package/dist/index.js +95 -0
  22. package/dist/log-env.d.ts +1 -0
  23. package/dist/log-env.js +12 -0
  24. package/dist/manifest.d.ts +30 -0
  25. package/dist/manifest.js +47 -0
  26. package/dist/patch-browser-pool.d.ts +66 -0
  27. package/dist/patch-browser-pool.js +827 -0
  28. package/dist/proxy-configuration.d.ts +118 -0
  29. package/dist/proxy-configuration.js +88 -0
  30. package/dist/request-list.d.ts +57 -0
  31. package/dist/request-list.js +79 -0
  32. package/dist/runner/docker-manager.d.ts +88 -0
  33. package/dist/runner/docker-manager.js +283 -0
  34. package/dist/runner/index.d.ts +2 -0
  35. package/dist/runner/index.js +7 -0
  36. package/dist/runner/timeout-manager.d.ts +43 -0
  37. package/dist/runner/timeout-manager.js +90 -0
  38. package/dist/scrapely-proxy-configuration.d.ts +99 -0
  39. package/dist/scrapely-proxy-configuration.js +559 -0
  40. package/dist/storage/api-storage-client.d.ts +199 -0
  41. package/dist/storage/api-storage-client.js +910 -0
  42. package/dist/storage/billing-tracker.d.ts +163 -0
  43. package/dist/storage/billing-tracker.js +260 -0
  44. package/dist/storage/dataset-client.d.ts +43 -0
  45. package/dist/storage/dataset-client.js +232 -0
  46. package/dist/storage/dataset-collection-client.d.ts +8 -0
  47. package/dist/storage/dataset-collection-client.js +75 -0
  48. package/dist/storage/dataset-push-script.d.ts +18 -0
  49. package/dist/storage/dataset-push-script.js +38 -0
  50. package/dist/storage/dragonfly-client.d.ts +94 -0
  51. package/dist/storage/dragonfly-client.js +167 -0
  52. package/dist/storage/index.d.ts +11 -0
  53. package/dist/storage/index.js +25 -0
  54. package/dist/storage/key-value-store-client.d.ts +61 -0
  55. package/dist/storage/key-value-store-client.js +306 -0
  56. package/dist/storage/kv-store-collection-client.d.ts +8 -0
  57. package/dist/storage/kv-store-collection-client.js +76 -0
  58. package/dist/storage/kvs-iteration.d.ts +17 -0
  59. package/dist/storage/kvs-iteration.js +126 -0
  60. package/dist/storage/log-manager.d.ts +114 -0
  61. package/dist/storage/log-manager.js +244 -0
  62. package/dist/storage/patch-storage.d.ts +11 -0
  63. package/dist/storage/patch-storage.js +177 -0
  64. package/dist/storage/request-queue-client.d.ts +93 -0
  65. package/dist/storage/request-queue-client.js +522 -0
  66. package/dist/storage/rq-collection-client.d.ts +8 -0
  67. package/dist/storage/rq-collection-client.js +89 -0
  68. package/dist/storage/rq-list-requests.d.ts +59 -0
  69. package/dist/storage/rq-list-requests.js +114 -0
  70. package/dist/storage/rq-lock-script.d.ts +56 -0
  71. package/dist/storage/rq-lock-script.js +127 -0
  72. package/dist/storage/run-metadata.d.ts +98 -0
  73. package/dist/storage/run-metadata.js +256 -0
  74. package/dist/storage/s3-client.d.ts +103 -0
  75. package/dist/storage/s3-client.js +302 -0
  76. package/dist/storage/ttl-manager.d.ts +70 -0
  77. package/dist/storage/ttl-manager.js +115 -0
  78. package/dist/storage/utils.d.ts +3 -0
  79. package/dist/storage/utils.js +19 -0
  80. package/dist/storage-identifiers.d.ts +20 -0
  81. package/dist/storage-identifiers.js +6 -0
  82. package/dist/utils.d.ts +54 -0
  83. package/dist/utils.js +63 -0
  84. package/dist/validator.d.ts +24 -0
  85. package/dist/validator.js +158 -0
  86. package/package.json +90 -9
@@ -0,0 +1,118 @@
1
+ import type { ProxyConfigurationOptions as CoreProxyConfigurationOptions, ProxyInfo as CoreProxyInfo } from '@crawlee/core';
2
+ import { ProxyConfiguration } from './scrapely-proxy-configuration.js';
3
+ /**
4
+ * Proxy info enriched with the platform-proxy (Apify-compatible) username
5
+ * fields. Mirrors the Apify SDK's `ProxyInfo` extension of Crawlee's type.
6
+ */
7
+ export interface ProxyInfo extends CoreProxyInfo {
8
+ /** Proxy groups used by the platform proxy (e.g. `['RESIDENTIAL']`). */
9
+ groups?: string[];
10
+ /** Two-letter ISO country code requested from the platform proxy. */
11
+ countryCode?: string;
12
+ /** ISO 3166-2 subdivision code requested from the platform proxy. */
13
+ subdivisionCode?: string;
14
+ }
15
+ /**
16
+ * Options for creating a proxy configuration.
17
+ *
18
+ * Modes supported:
19
+ * - Platform proxy (default on Scrapely runs): when the server injects
20
+ * APIFY_PROXY_* or SCRAPELY_PROXY_* credentials, groups/countryCode/password
21
+ * build Apify-style gateway usernames automatically.
22
+ * - Bring-your-own-proxy (BYOP): custom proxyUrls / newUrlFunction /
23
+ * tieredProxyUrls always win over the platform proxy.
24
+ * - Mixed: the 'auto' (or 'http://auto') sentinel inside proxyUrls /
25
+ * tieredProxyUrls / tieredProxyConfig[].proxyUrls reserves a slot for the
26
+ * platform proxy alongside BYOP entries (Apify-compatible).
27
+ */
28
+ export interface ProxyConfigurationOptions extends CoreProxyConfigurationOptions {
29
+ /**
30
+ * Multiple different ProxyConfigurationOptions stratified into tiers (Apify-compatible).
31
+ * Tiers with `proxyUrls` map directly to tieredProxyUrls; tiers without
32
+ * URLs expand their platform options (groups/countryCode/password) to a
33
+ * concrete platform proxy URL, mirroring Apify's `_generateTieredProxyUrls`.
34
+ */
35
+ tieredProxyConfig?: Omit<ProxyConfigurationOptions, 'tieredProxyConfig' | 'tieredProxyUrls'>[];
36
+ /**
37
+ * Platform proxy groups (Apify-compatible). Effective in platform proxy
38
+ * mode; ignored for BYOP configurations.
39
+ */
40
+ groups?: string[];
41
+ /**
42
+ * Platform proxy country code (Apify-compatible). Effective in platform
43
+ * proxy mode; ignored for BYOP configurations.
44
+ */
45
+ countryCode?: string;
46
+ /**
47
+ * Platform proxy subdivision code, e.g. US state (Apify-compatible).
48
+ * Requires `countryCode`. Effective in platform proxy mode; ignored for
49
+ * BYOP configurations. Emitted as a merged `country-XX_YY` username
50
+ * fragment (ISO 3166-2).
51
+ */
52
+ subdivisionCode?: string;
53
+ /**
54
+ * Input-schema alias for groups. Normalized to groups.
55
+ */
56
+ apifyProxyGroups?: string[];
57
+ /**
58
+ * Input-schema alias for subdivisionCode. Normalized to subdivisionCode.
59
+ */
60
+ apifyProxySubdivision?: string;
61
+ /**
62
+ * Input-schema alias for countryCode. Normalized to countryCode.
63
+ */
64
+ apifyProxyCountry?: string;
65
+ /**
66
+ * Platform proxy password. Defaults to the password injected by the
67
+ * server (APIFY_PROXY_PASSWORD / SCRAPELY_PROXY_PASSWORD).
68
+ */
69
+ password?: string;
70
+ }
71
+ /**
72
+ * Options for Actor.createProxyConfiguration().
73
+ */
74
+ export interface CreateProxyConfigurationOptions extends ProxyConfigurationOptions {
75
+ /**
76
+ * For compatibility with existing Actor Input UI (Input Schema).
77
+ * When set to `false`, this method returns `undefined`.
78
+ */
79
+ useApifyProxy?: boolean;
80
+ /**
81
+ * Whether to verify the proxy configuration by testing a connection.
82
+ * @default true
83
+ */
84
+ checkAccess?: boolean;
85
+ }
86
+ /**
87
+ * Platform proxy connection details injected into run containers by the
88
+ * Scrapely server (backed by Evomi). SCRAPELY_* vars take precedence over the
89
+ * Apify-compatible aliases so Scrapely-first deployments stay unambiguous.
90
+ */
91
+ export interface PlatformProxyEnv {
92
+ hostname: string;
93
+ port: number;
94
+ password: string;
95
+ /**
96
+ * Subaccount username injected by the server. When present it is prefixed
97
+ * to every generated gateway username (groups/country/session fragments
98
+ * are appended after it) so the gateway attributes traffic to the right
99
+ * Scrapely tenant.
100
+ */
101
+ username?: string;
102
+ statusUrl?: string;
103
+ }
104
+ /**
105
+ * Read platform proxy credentials from the environment.
106
+ * Returns null when the run has no platform proxy (BYOP / no-proxy mode).
107
+ */
108
+ export declare function getPlatformProxyEnv(): PlatformProxyEnv | null;
109
+ /**
110
+ * Creates a proxy configuration for use with crawlers.
111
+ *
112
+ * The platform proxy (Evomi-backed) is injected into runs via the SCRAPELY_PROXY
113
+ * and APIFY_PROXY environment variables. Apify Proxy options (groups, countryCode, ...)
114
+ * build gateway usernames in platform mode; proxyUrls, newUrlFunction and
115
+ * tieredProxyUrls configure bring-your-own proxies instead.
116
+ */
117
+ export declare function createProxyConfiguration(options?: CreateProxyConfigurationOptions): Promise<ProxyConfiguration | undefined>;
118
+ export type { ProxyConfigurationFunction } from '@crawlee/core';
@@ -0,0 +1,88 @@
1
+ "use strict";
2
+ Object.defineProperty(exports, "__esModule", { value: true });
3
+ exports.getPlatformProxyEnv = getPlatformProxyEnv;
4
+ exports.createProxyConfiguration = createProxyConfiguration;
5
+ const scrapely_proxy_configuration_js_1 = require("./scrapely-proxy-configuration.js");
6
+ /**
7
+ * Read platform proxy credentials from the environment.
8
+ * Returns null when the run has no platform proxy (BYOP / no-proxy mode).
9
+ */
10
+ function getPlatformProxyEnv() {
11
+ const hostname = process.env.SCRAPELY_PROXY_HOSTNAME || process.env.APIFY_PROXY_HOSTNAME;
12
+ const portStr = process.env.SCRAPELY_PROXY_PORT || process.env.APIFY_PROXY_PORT;
13
+ const password = process.env.SCRAPELY_PROXY_PASSWORD || process.env.APIFY_PROXY_PASSWORD;
14
+ if (!hostname || !password)
15
+ return null;
16
+ const parsedPort = parseInt(portStr || '', 10);
17
+ const username = process.env.SCRAPELY_PROXY_USERNAME || process.env.APIFY_PROXY_USERNAME;
18
+ return {
19
+ hostname,
20
+ // Same bounds as the Python SDK (_platform_env): invalid/out-of-range
21
+ // ports fall back to the default gateway port instead of producing a
22
+ // broken URL.
23
+ port: Number.isFinite(parsedPort) && parsedPort > 0 && parsedPort < 65536 ? parsedPort : 8000,
24
+ password,
25
+ username: username || undefined,
26
+ statusUrl: process.env.SCRAPELY_PROXY_STATUS_URL || process.env.APIFY_PROXY_STATUS_URL || undefined,
27
+ };
28
+ }
29
+ const BYOP_WARNING = '[Scrapely] No proxy configured. Scrapely injects platform proxy credentials (APIFY_PROXY_*/SCRAPELY_PROXY_*) into runs when your account has proxy access. ' +
30
+ 'Locally, either add proxyUrls to your actor input, or copy your proxy credentials from the Scrapely console (Proxy page) into the ' +
31
+ 'SCRAPELY_PROXY_HOSTNAME, SCRAPELY_PROXY_PORT, SCRAPELY_PROXY_USERNAME and SCRAPELY_PROXY_PASSWORD environment variables. ' +
32
+ 'Using the platform proxy from outside Scrapely requires an active plan or a prepaid (PAYG) balance of at least $1; ' +
33
+ 'free accounts get run-scoped credentials injected into their on-platform runs only.';
34
+ function hasCustomProxyOptions(options) {
35
+ return !!((options.proxyUrls && options.proxyUrls.length > 0) ||
36
+ typeof options.newUrlFunction === 'function' ||
37
+ (options.tieredProxyUrls && options.tieredProxyUrls.length > 0) ||
38
+ (options.tieredProxyConfig && options.tieredProxyConfig.length > 0));
39
+ }
40
+ function normalizeProxyInput(options) {
41
+ const normalized = { ...options };
42
+ if (normalized.apifyProxyGroups && !normalized.groups) {
43
+ normalized.groups = normalized.apifyProxyGroups;
44
+ }
45
+ if (normalized.apifyProxyCountry && !normalized.countryCode) {
46
+ normalized.countryCode = normalized.apifyProxyCountry;
47
+ }
48
+ if (normalized.apifyProxySubdivision && !normalized.subdivisionCode) {
49
+ normalized.subdivisionCode = normalized.apifyProxySubdivision;
50
+ }
51
+ return normalized;
52
+ }
53
+ /**
54
+ * Creates a proxy configuration for use with crawlers.
55
+ *
56
+ * The platform proxy (Evomi-backed) is injected into runs via the SCRAPELY_PROXY
57
+ * and APIFY_PROXY environment variables. Apify Proxy options (groups, countryCode, ...)
58
+ * build gateway usernames in platform mode; proxyUrls, newUrlFunction and
59
+ * tieredProxyUrls configure bring-your-own proxies instead.
60
+ */
61
+ async function createProxyConfiguration(options = {}) {
62
+ const normalized = normalizeProxyInput(options);
63
+ const { useApifyProxy, checkAccess = true, ...proxyOptions } = normalized;
64
+ // Apify parity: `useApifyProxy: false` explicitly disables the PLATFORM proxy
65
+ // only — custom proxies from the same input must still be used. The standard
66
+ // "Custom proxy URLs" input shape is `{ useApifyProxy: false, proxyUrls: [...] }`;
67
+ // returning undefined for it would silently drop the user's own proxies and
68
+ // crawl on their real IPs. We only bail when NO custom proxy mode is given —
69
+ // proxyUrls, tieredProxyUrls, tieredProxyConfig and newUrlFunction all count
70
+ // (Python SDK Actor.create_proxy_configuration parity).
71
+ const dontUseApifyProxy = useApifyProxy === false;
72
+ const dontUseCustomProxies = !hasCustomProxyOptions(proxyOptions);
73
+ if (dontUseApifyProxy && dontUseCustomProxies) {
74
+ return undefined;
75
+ }
76
+ if (!hasCustomProxyOptions(proxyOptions)) {
77
+ // Platform proxy mode: credentials were injected into the environment
78
+ // by the Scrapely server (Evomi-backed). groups/countryCode become
79
+ // meaningful gateway username fragments instead of being ignored.
80
+ if (!getPlatformProxyEnv()) {
81
+ console.warn(BYOP_WARNING);
82
+ return undefined;
83
+ }
84
+ }
85
+ const proxyConfiguration = new scrapely_proxy_configuration_js_1.ProxyConfiguration(proxyOptions);
86
+ await proxyConfiguration.initialize({ checkAccess });
87
+ return proxyConfiguration;
88
+ }
@@ -0,0 +1,57 @@
1
+ /**
2
+ * ScrapelyRequestList - parses the standard Scrapely/Apify `requestListSources` input format.
3
+ *
4
+ * Parity port of the Python SDK's `scrapely.request_loaders.ScrapelyRequestList`.
5
+ * It supports two kinds of entries:
6
+ *
7
+ * - **Direct URLs** - entries with a `url` key are converted to requests directly.
8
+ * - **Remote URL lists** - entries with a `requestsFromUrl` key point to a remote resource
9
+ * (e.g. a plain-text file). The resource is fetched and all URLs found in the response
10
+ * body are extracted and converted to requests.
11
+ *
12
+ * Both kinds of entries can optionally specify `method`, `payload`, `headers`, and
13
+ * `userData` fields that will be applied to every request created from that entry.
14
+ *
15
+ * Usage:
16
+ * ```javascript
17
+ * import { Actor, ScrapelyRequestList } from 'scrapely';
18
+ *
19
+ * const input = await Actor.getInput() ?? {};
20
+ * const requestList = await ScrapelyRequestList.open(input.requestListSources ?? []);
21
+ * // requestList.requests -> crawlee Request[]
22
+ * ```
23
+ */
24
+ import { Request } from '@crawlee/core';
25
+ /**
26
+ * A single entry of the `requestListSources` input format.
27
+ * Accepts both camelCase (Apify/Scrapely UI) and snake_case keys.
28
+ */
29
+ export interface RequestListSource {
30
+ /** Direct URL to crawl (mutually exclusive with `requestsFromUrl`). */
31
+ url?: string;
32
+ /** Remote resource whose body is scanned for URLs to crawl. */
33
+ requestsFromUrl?: string;
34
+ requests_from_url?: string;
35
+ /** HTTP method applied to all requests from this entry (default: GET). */
36
+ method?: string;
37
+ /** HTTP payload applied to all requests from this entry. */
38
+ payload?: string;
39
+ /** HTTP headers applied to all requests from this entry. */
40
+ headers?: Record<string, string>;
41
+ /** Custom user data applied to all requests from this entry. */
42
+ userData?: Record<string, any>;
43
+ user_data?: Record<string, any>;
44
+ }
45
+ export declare class ScrapelyRequestList {
46
+ /** Resolved requests, ready to be added to a RequestQueue or crawler. */
47
+ readonly requests: Request[];
48
+ private constructor();
49
+ /**
50
+ * Create a new `ScrapelyRequestList` from the standard Scrapely request list sources input.
51
+ *
52
+ * @param requestListSourcesInput List of entries with either a `url` key (direct URL) or a
53
+ * `requestsFromUrl` key (remote resource scanned for URLs). When not provided or empty,
54
+ * an empty request list is returned.
55
+ */
56
+ static open(requestListSourcesInput?: RequestListSource[]): Promise<ScrapelyRequestList>;
57
+ }
@@ -0,0 +1,79 @@
1
+ "use strict";
2
+ /**
3
+ * ScrapelyRequestList - parses the standard Scrapely/Apify `requestListSources` input format.
4
+ *
5
+ * Parity port of the Python SDK's `scrapely.request_loaders.ScrapelyRequestList`.
6
+ * It supports two kinds of entries:
7
+ *
8
+ * - **Direct URLs** - entries with a `url` key are converted to requests directly.
9
+ * - **Remote URL lists** - entries with a `requestsFromUrl` key point to a remote resource
10
+ * (e.g. a plain-text file). The resource is fetched and all URLs found in the response
11
+ * body are extracted and converted to requests.
12
+ *
13
+ * Both kinds of entries can optionally specify `method`, `payload`, `headers`, and
14
+ * `userData` fields that will be applied to every request created from that entry.
15
+ *
16
+ * Usage:
17
+ * ```javascript
18
+ * import { Actor, ScrapelyRequestList } from 'scrapely';
19
+ *
20
+ * const input = await Actor.getInput() ?? {};
21
+ * const requestList = await ScrapelyRequestList.open(input.requestListSources ?? []);
22
+ * // requestList.requests -> crawlee Request[]
23
+ * ```
24
+ */
25
+ Object.defineProperty(exports, "__esModule", { value: true });
26
+ exports.ScrapelyRequestList = void 0;
27
+ const core_1 = require("@crawlee/core");
28
+ /** Regex for extracting URLs from remote text files (matches URLs without commas). */
29
+ const URL_NO_COMMAS_REGEX = /https?:\/\/(www\.)?([^\W_]|[^\W_][-\w0-9@:%._+~#=]{0,254}[^\W_])\.[a-z]{2,63}(:\d{1,5})?(\/[-\w@:%+.~#?&/=()]*)?/g;
30
+ function createRequest(source, url) {
31
+ return new core_1.Request({
32
+ url,
33
+ method: source.method,
34
+ payload: source.payload,
35
+ headers: source.headers,
36
+ // Deep-copy so Request's constructor (which writes __crawlee into the
37
+ // dict) cannot corrupt the shared input, and nested values are not
38
+ // aliased across requests (Python SDK parity: deepcopy).
39
+ userData: structuredClone(source.userData ?? source.user_data ?? {}),
40
+ });
41
+ }
42
+ async function fetchRequestsFromUrl(source) {
43
+ const remoteUrl = source.requestsFromUrl ?? source.requests_from_url;
44
+ if (!remoteUrl)
45
+ return [];
46
+ const response = await fetch(remoteUrl);
47
+ if (!response.ok) {
48
+ throw new Error(`Failed to fetch requestsFromUrl "${remoteUrl}": ${response.status} ${response.statusText}`);
49
+ }
50
+ const body = await response.text();
51
+ const requests = [];
52
+ for (const match of body.matchAll(URL_NO_COMMAS_REGEX)) {
53
+ requests.push(createRequest(source, match[0]));
54
+ }
55
+ return requests;
56
+ }
57
+ class ScrapelyRequestList {
58
+ /** Resolved requests, ready to be added to a RequestQueue or crawler. */
59
+ requests;
60
+ constructor(requests) {
61
+ this.requests = requests;
62
+ }
63
+ /**
64
+ * Create a new `ScrapelyRequestList` from the standard Scrapely request list sources input.
65
+ *
66
+ * @param requestListSourcesInput List of entries with either a `url` key (direct URL) or a
67
+ * `requestsFromUrl` key (remote resource scanned for URLs). When not provided or empty,
68
+ * an empty request list is returned.
69
+ */
70
+ static async open(requestListSourcesInput) {
71
+ const sources = requestListSourcesInput ?? [];
72
+ const simpleUrlSources = sources.filter((source) => source.url);
73
+ const remoteUrlSources = sources.filter((source) => !source.url && (source.requestsFromUrl ?? source.requests_from_url));
74
+ const simpleUrlRequests = simpleUrlSources.map((source) => createRequest(source, source.url));
75
+ const remoteUrlRequests = (await Promise.all(remoteUrlSources.map(fetchRequestsFromUrl))).flat();
76
+ return new ScrapelyRequestList([...simpleUrlRequests, ...remoteUrlRequests]);
77
+ }
78
+ }
79
+ exports.ScrapelyRequestList = ScrapelyRequestList;
@@ -0,0 +1,88 @@
1
+ import Docker from 'dockerode';
2
+ import { TimeoutManager } from './timeout-manager.js';
3
+ import { DragonflyClient } from '../storage/dragonfly-client.js';
4
+ import type { UserPlan } from '../storage/ttl-manager.js';
5
+ export interface RunOptions {
6
+ /** Path to the actor package directory */
7
+ packagePath: string;
8
+ /** Path to the .env file */
9
+ envPath?: string;
10
+ /** Environment variables to pass to container */
11
+ env?: Record<string, string>;
12
+ /** Maximum memory in MB (default: from manifest or 512) */
13
+ memoryMb?: number;
14
+ /** Maximum timeout in seconds (default: from manifest or 1800) */
15
+ timeout?: number;
16
+ /** Run ID for tracking */
17
+ runId?: string;
18
+ /** User ID */
19
+ userId?: string;
20
+ /** User plan for TTL */
21
+ userPlan?: UserPlan;
22
+ /** Dragonfly client for storage cleanup */
23
+ dragonflyClient?: DragonflyClient;
24
+ }
25
+ export interface RunResult {
26
+ containerId: string;
27
+ exitCode: number;
28
+ logs: string;
29
+ status: 'success' | 'failed' | 'timed_out' | 'killed';
30
+ duration: number;
31
+ /** Storage IDs that were cleaned up */
32
+ cleanedUp?: {
33
+ requestQueueDeleted: boolean;
34
+ logsUploadedToS3: boolean;
35
+ };
36
+ }
37
+ export declare class DockerManager {
38
+ private docker;
39
+ private timeoutManager;
40
+ private imageName;
41
+ constructor(options?: {
42
+ socketPath?: string;
43
+ imageName?: string;
44
+ });
45
+ /**
46
+ * Run an actor package in a container
47
+ */
48
+ run(options: RunOptions): Promise<RunResult>;
49
+ /**
50
+ * Cleanup storage after run completes.
51
+ * - Deletes request queue immediately (no longer needed)
52
+ * - Uploads logs to S3 for long-term storage
53
+ * - Updates run metadata with final status
54
+ */
55
+ private cleanupAfterRun;
56
+ /**
57
+ * Stop a container (SIGTERM)
58
+ */
59
+ stop(containerId: string, timeoutSeconds?: number): Promise<void>;
60
+ /**
61
+ * Kill a container (SIGKILL)
62
+ */
63
+ kill(containerId: string): Promise<void>;
64
+ /**
65
+ * Get logs from a container
66
+ */
67
+ getLogs(containerId: string): Promise<string>;
68
+ /**
69
+ * Get container status
70
+ */
71
+ getStatus(containerId: string): Promise<string | null>;
72
+ /**
73
+ * List all scrapely containers
74
+ */
75
+ listContainers(): Promise<Docker.ContainerInfo[]>;
76
+ /**
77
+ * Get the timeout manager
78
+ */
79
+ getTimeoutManager(): TimeoutManager;
80
+ /**
81
+ * Track internal data transfer from container network stats.
82
+ * Following Apify's model:
83
+ * - Ingress (rx_bytes) is FREE - scraped content coming in
84
+ * - Internal transfer is tracked separately in storage clients
85
+ * - External egress is tracked in API layer when users fetch results
86
+ */
87
+ private trackDataTransfer;
88
+ }