@intuned/runtime 1.3.15 → 1.3.16

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.
@@ -1,16 +1,16 @@
1
1
  import { Command } from "commander";
2
2
  export declare const baseRunAuthSessionCommandOptionsSchema: import("zod").ZodObject<{
3
3
  proxy: import("zod").ZodOptional<import("zod").ZodString>;
4
- trace: import("zod").ZodDefault<import("zod").ZodBoolean>;
5
4
  timeout: import("zod").ZodEffects<import("zod").ZodEffects<import("zod").ZodDefault<import("zod").ZodString>, import("ms").StringValue, string | undefined>, number, string | undefined>;
5
+ trace: import("zod").ZodDefault<import("zod").ZodBoolean>;
6
6
  headless: import("zod").ZodDefault<import("zod").ZodBoolean>;
7
7
  keepBrowserOpen: import("zod").ZodDefault<import("zod").ZodBoolean>;
8
8
  cdpUrl: import("zod").ZodOptional<import("zod").ZodString>;
9
9
  checkAttempts: import("zod").ZodDefault<import("zod").ZodNumber>;
10
10
  createAttempts: import("zod").ZodDefault<import("zod").ZodNumber>;
11
11
  }, "strip", import("zod").ZodTypeAny, {
12
- trace: boolean;
13
12
  timeout: number;
13
+ trace: boolean;
14
14
  headless: boolean;
15
15
  keepBrowserOpen: boolean;
16
16
  checkAttempts: number;
@@ -19,8 +19,8 @@ export declare const baseRunAuthSessionCommandOptionsSchema: import("zod").ZodOb
19
19
  cdpUrl?: string | undefined;
20
20
  }, {
21
21
  proxy?: string | undefined;
22
- trace?: boolean | undefined;
23
22
  timeout?: string | undefined;
23
+ trace?: boolean | undefined;
24
24
  headless?: boolean | undefined;
25
25
  keepBrowserOpen?: boolean | undefined;
26
26
  cdpUrl?: string | undefined;
@@ -17,8 +17,8 @@ export declare const baseCommandOptionsSchema: z.ZodObject<{
17
17
  keepBrowserOpen: z.ZodDefault<z.ZodBoolean>;
18
18
  cdpUrl: z.ZodOptional<z.ZodString>;
19
19
  }, "strip", z.ZodTypeAny, {
20
- trace: boolean;
21
20
  timeout: number;
21
+ trace: boolean;
22
22
  headless: boolean;
23
23
  keepBrowserOpen: boolean;
24
24
  proxy?: string | undefined;
@@ -1,8 +1,11 @@
1
1
  import * as playwright from "playwright";
2
- import { CaptchaSolverSettingsWithRunContext } from "../settingsSchema";
2
+ import { CaptchaSolverSettings, CaptchaSolverSettingsWithRunContext } from "../settingsSchema";
3
+ export declare function resolveCaptchaSolverSettings(input?: unknown): Promise<CaptchaSolverSettings>;
4
+ export declare function isIntunedExtensionLoaded(): boolean;
3
5
  export declare function buildExtensionsList(): string[];
4
6
  export declare function getIntunedExtensionPath(): string;
5
- export declare function isIntunedExtensionEnabled(): boolean;
7
+ export declare function isIntunedExtensionEnabled(): Promise<boolean>;
6
8
  export declare function getIntunedExtensionWorker(context: playwright.BrowserContext): Promise<playwright.Worker | null>;
7
- export declare function getIntunedExtensionSettings(): Promise<CaptchaSolverSettingsWithRunContext>;
9
+ export declare function getIntunedExtensionSettings(captchaSolverSettings: CaptchaSolverSettings): Promise<CaptchaSolverSettingsWithRunContext>;
10
+ export declare function getIntunedCaptchaSolverSettings(): Promise<CaptchaSolverSettings>;
8
11
  export declare function setupIntunedExtension(): Promise<void>;
@@ -4,10 +4,13 @@ Object.defineProperty(exports, "__esModule", {
4
4
  value: true
5
5
  });
6
6
  exports.buildExtensionsList = buildExtensionsList;
7
+ exports.getIntunedCaptchaSolverSettings = getIntunedCaptchaSolverSettings;
7
8
  exports.getIntunedExtensionPath = getIntunedExtensionPath;
8
9
  exports.getIntunedExtensionSettings = getIntunedExtensionSettings;
9
10
  exports.getIntunedExtensionWorker = getIntunedExtensionWorker;
10
11
  exports.isIntunedExtensionEnabled = isIntunedExtensionEnabled;
12
+ exports.isIntunedExtensionLoaded = isIntunedExtensionLoaded;
13
+ exports.resolveCaptchaSolverSettings = resolveCaptchaSolverSettings;
11
14
  exports.setupIntunedExtension = setupIntunedExtension;
12
15
  var _settings = require("../../commands/common/utils/settings");
13
16
  var _settingsSchema = require("../settingsSchema");
@@ -21,6 +24,20 @@ function _interopRequireDefault(e) { return e && e.__esModule ? e : { default: e
21
24
  const INTUNED_WORKER = "intunedWorker.js";
22
25
  const INTUNED_EXTENSION_SETTINGS_FILE_NAME = "intunedSettings.json";
23
26
  const INTUNED_CAPTCHA_EXTENSION_PORT_ENV_VAR = "INTUNED_CAPTCHA_EXTENSION_PORT";
27
+ let captchaSolverSettings = null;
28
+ async function getIntunedCaptchaExtensionPort() {
29
+ if (process.env.INTUNED_CAPTCHA_EXTENSION_PORT) {
30
+ return parseInt(process.env.INTUNED_CAPTCHA_EXTENSION_PORT, 10);
31
+ }
32
+ return await (0, _portfinder.getPort)({});
33
+ }
34
+ async function resolveCaptchaSolverSettings(input) {
35
+ const parsed = _settingsSchema.captchaSolverSettingsSchema.parse(input || {});
36
+ if (!parsed.port) {
37
+ parsed.port = await getIntunedCaptchaExtensionPort();
38
+ }
39
+ return parsed;
40
+ }
24
41
  function getIntunedCaptchaExtensionPortFromEnv() {
25
42
  const raw = process.env[INTUNED_CAPTCHA_EXTENSION_PORT_ENV_VAR];
26
43
  if (!raw) return null;
@@ -30,9 +47,12 @@ function getIntunedCaptchaExtensionPortFromEnv() {
30
47
  }
31
48
  return parsed;
32
49
  }
50
+ function isIntunedExtensionLoaded() {
51
+ return !!getIntunedExtensionPath();
52
+ }
33
53
  function buildExtensionsList() {
34
54
  const extensionsList = [];
35
- if (isIntunedExtensionEnabled()) {
55
+ if (isIntunedExtensionLoaded()) {
36
56
  const intunedExtensionPath = getIntunedExtensionPath();
37
57
  extensionsList.push(intunedExtensionPath);
38
58
  }
@@ -41,11 +61,16 @@ function buildExtensionsList() {
41
61
  function getIntunedExtensionPath() {
42
62
  return process.env.INTUNED_EXTENSION_PATH;
43
63
  }
44
- function isIntunedExtensionEnabled() {
45
- return !!getIntunedExtensionPath();
64
+ async function isIntunedExtensionEnabled() {
65
+ const path = getIntunedExtensionPath();
66
+ if (!path) {
67
+ return false;
68
+ }
69
+ const captchaSolverSettings = await getIntunedCaptchaSolverSettings();
70
+ return captchaSolverSettings.enabled;
46
71
  }
47
72
  async function getIntunedExtensionWorker(context) {
48
- if (!isIntunedExtensionEnabled()) {
73
+ if (!(await isIntunedExtensionEnabled())) {
49
74
  return null;
50
75
  }
51
76
  let attemptCount = 0;
@@ -66,8 +91,7 @@ async function getIntunedExtensionWorker(context) {
66
91
  console.error("Failed to get intuned worker after 5 attmepts");
67
92
  return null;
68
93
  }
69
- async function getIntunedExtensionSettings() {
70
- const settings = await (0, _settings.getSettings)();
94
+ async function getIntunedExtensionSettings(captchaSolverSettings) {
71
95
  const [domain, workspaceId, projectId] = [process.env.FUNCTIONS_DOMAIN, process.env[_constants.WORKSPACE_ID_ENV_VAR_KEY], process.env.INTUNED_INTEGRATION_ID ?? process.env[_constants.PROJECT_ID_ENV_VAR_KEY]];
72
96
  if (!domain || !workspaceId || !projectId) {
73
97
  const missingEnvVars = [domain && "FUNCTIONS_DOMAIN", workspaceId && _constants.WORKSPACE_ID_ENV_VAR_KEY, projectId && `INTUNED_INTEGRATION_ID OR ${_constants.PROJECT_ID_ENV_VAR_KEY}`];
@@ -94,28 +118,30 @@ async function getIntunedExtensionSettings() {
94
118
  };
95
119
  })();
96
120
  const baseUrl = process.env.INTUNED_API_BASE_URL ?? domain;
97
- const port = getIntunedCaptchaExtensionPortFromEnv() ?? (await (0, _portfinder.getPort)({}));
98
121
  return {
99
- ...(settings.captchaSolver ?? _settingsSchema.captchaSolverSettingsSchema.parse({})),
122
+ ...captchaSolverSettings,
100
123
  workspaceId,
101
124
  projectId,
102
125
  baseUrl,
103
- authentication,
104
- port
126
+ authentication
105
127
  };
106
128
  }
129
+ async function getIntunedCaptchaSolverSettings() {
130
+ if (captchaSolverSettings) {
131
+ return captchaSolverSettings;
132
+ }
133
+ const settings = await (0, _settings.getSettings)();
134
+ captchaSolverSettings = await resolveCaptchaSolverSettings(settings.captchaSolver);
135
+ return captchaSolverSettings;
136
+ }
107
137
  async function setupIntunedExtension() {
108
- if (!isIntunedExtensionEnabled()) {
138
+ if (!(await isIntunedExtensionEnabled())) {
109
139
  return;
110
140
  }
111
141
  const intunedExtensionPath = getIntunedExtensionPath();
112
142
  const intunedExtensionSettingsPath = _path.default.join(intunedExtensionPath, INTUNED_EXTENSION_SETTINGS_FILE_NAME);
113
- const settings = await getIntunedExtensionSettings();
114
- if (!settings.enabled) {
115
- return;
116
- }
117
- await (0, _intunedExtensionServer.setupIntunedExtensionServer)({
118
- port: settings.port ?? 9000
119
- });
120
- await (0, _promises.writeFile)(intunedExtensionSettingsPath, JSON.stringify(settings));
143
+ const captchaSolverSettings = await getIntunedCaptchaSolverSettings();
144
+ await (0, _intunedExtensionServer.setupIntunedExtensionServer)(captchaSolverSettings);
145
+ const captchaSolverSettingsWithRunContext = await getIntunedExtensionSettings(captchaSolverSettings);
146
+ await (0, _promises.writeFile)(intunedExtensionSettingsPath, JSON.stringify(captchaSolverSettingsWithRunContext));
121
147
  }
@@ -1,9 +1,9 @@
1
1
  import type * as playwright from "playwright";
2
2
  import { Captcha, CaptchaCallback, CaptchaStatus } from "./types";
3
+ import { CaptchaSolverSettings } from "../settingsSchema";
3
4
  export declare class ExtensionServer {
4
5
  private tabs;
5
6
  private app;
6
- isHealthy: boolean;
7
7
  constructor();
8
8
  private getOrCreateTab;
9
9
  handleUpsertCaptcha(captcha: Captcha): Promise<void>;
@@ -19,9 +19,6 @@ export declare class ExtensionServer {
19
19
  getTabId(page: playwright.Page): Promise<number>;
20
20
  }
21
21
  export declare function getIntunedExtensionServer(): ExtensionServer;
22
- export declare function setupIntunedExtensionServer({ port, host, }: {
23
- port: number;
24
- host?: string;
25
- }): Promise<void>;
22
+ export declare function setupIntunedExtensionServer(captchaSolverSettings?: CaptchaSolverSettings): Promise<void>;
26
23
  export declare function cleanIntunedExtensionServer(): Promise<void>;
27
24
  export declare function getTabId(page: playwright.Page): Promise<number>;
@@ -10,6 +10,7 @@ exports.getTabId = getTabId;
10
10
  exports.setupIntunedExtensionServer = setupIntunedExtensionServer;
11
11
  var _fastify = _interopRequireDefault(require("fastify"));
12
12
  var _types = require("./types");
13
+ var _extensionsHelpers = require("./extensionsHelpers");
13
14
  function _interopRequireDefault(e) { return e && e.__esModule ? e : { default: e }; }
14
15
  class TabCaptchaState {
15
16
  constructor(tabId) {
@@ -40,7 +41,6 @@ class TabCaptchaState {
40
41
  }
41
42
  class ExtensionServer {
42
43
  app = null;
43
- isHealthy = false;
44
44
  constructor() {
45
45
  this.tabs = new Map();
46
46
  }
@@ -94,13 +94,11 @@ class ExtensionServer {
94
94
  port,
95
95
  host
96
96
  });
97
- this.isHealthy = true;
98
97
  }
99
98
  async stop() {
100
99
  if (!this.app) return;
101
100
  const toClose = this.app;
102
101
  this.app = null;
103
- this.isHealthy = false;
104
102
  await toClose.close();
105
103
  }
106
104
  async getCaptchas(page, status) {
@@ -140,16 +138,15 @@ function getIntunedExtensionServer() {
140
138
  }
141
139
  return extensionServerSingleton;
142
140
  }
143
- async function setupIntunedExtensionServer({
144
- port,
145
- host
146
- }) {
141
+ async function setupIntunedExtensionServer(captchaSolverSettings) {
142
+ if (!captchaSolverSettings) {
143
+ captchaSolverSettings = await (0, _extensionsHelpers.resolveCaptchaSolverSettings)();
144
+ }
147
145
  if (!extensionServerSingleton) {
148
146
  extensionServerSingleton = new ExtensionServer();
149
147
  }
150
148
  await extensionServerSingleton.start({
151
- port,
152
- host
149
+ port: captchaSolverSettings.port ?? 9000
153
150
  });
154
151
  }
155
152
  async function cleanIntunedExtensionServer() {
@@ -38,6 +38,9 @@ async function createUserDirWithPreferences() {
38
38
  }
39
39
  async function launchChromium(options) {
40
40
  if ("cdpAddress" in options) {
41
+ if (await (0, _extensionsHelpers.isIntunedExtensionEnabled)()) {
42
+ await (0, _intunedExtensionServer.setupIntunedExtensionServer)();
43
+ }
41
44
  const browser = await playwright.chromium.connectOverCDP(options.cdpAddress);
42
45
  if (browser.contexts().length === 0) {
43
46
  throw new Error("No browser contexts found in the connected browser");
@@ -65,12 +68,17 @@ async function launchChromium(options) {
65
68
  const defaultArgsToIgnore = ["--disable-extensions", "--disable-component-extensions-with-background-pages", "--disable-background-networking", "--disable-backgrounding-occluded-windows", "--disable-background-timer-throttling"];
66
69
  const extraArgs = [];
67
70
  const userDataDir = await createUserDirWithPreferences();
68
- if ((0, _extensionsHelpers.isIntunedExtensionEnabled)()) {
71
+ if ((0, _extensionsHelpers.isIntunedExtensionLoaded)()) {
69
72
  const extensionsList = (0, _extensionsHelpers.buildExtensionsList)();
70
73
  const extensions = extensionsList.join(",");
71
74
  extraArgs.push(`--disable-extensions-except=${extensions}`);
72
75
  extraArgs.push(`--load-extension=${extensions}`);
76
+ }
77
+ if (await (0, _extensionsHelpers.isIntunedExtensionEnabled)()) {
73
78
  await (0, _extensionsHelpers.setupIntunedExtension)();
79
+ if (proxy) {
80
+ extraArgs.push('--proxy-bypass-list="<-loopback>"');
81
+ }
74
82
  }
75
83
  if (cdpPort) {
76
84
  extraArgs.push(`--remote-debugging-port=${cdpPort}`);
@@ -105,13 +113,15 @@ async function launchChromium(options) {
105
113
  });
106
114
  context.once("close", async () => {
107
115
  try {
108
- await (0, _intunedExtensionServer.cleanIntunedExtensionServer)();
109
116
  await (0, _fsExtra.rm)(userDataDir, {
110
117
  recursive: true,
111
118
  force: true,
112
119
  retryDelay: 1000,
113
120
  maxRetries: 5
114
121
  });
122
+ if (await (0, _extensionsHelpers.isIntunedExtensionEnabled)()) {
123
+ await (0, _intunedExtensionServer.cleanIntunedExtensionServer)();
124
+ }
115
125
  } catch (error) {
116
126
  console.error("Failed to remove user data dir", error);
117
127
  }
@@ -121,7 +131,7 @@ async function launchChromium(options) {
121
131
  await waitOnCdpAddress(createdCdpAddress);
122
132
  }
123
133
  const page = context.pages().at(0) ?? (await context.newPage());
124
- if ((0, _extensionsHelpers.isIntunedExtensionEnabled)()) {
134
+ if (await (0, _extensionsHelpers.isIntunedExtensionEnabled)()) {
125
135
  await (0, _extensionsHelpers.getIntunedExtensionWorker)(context);
126
136
  }
127
137
  return {
@@ -197,7 +197,8 @@ export declare const captchaSolverSettingsSchema: z.ZodDefault<z.ZodObject<{
197
197
  timeout?: number | undefined;
198
198
  } | undefined;
199
199
  }>>;
200
- export type CaptchaSolverSettingsWithRunContext = z.infer<typeof captchaSolverSettingsSchema> & {
200
+ export type CaptchaSolverSettings = z.infer<typeof captchaSolverSettingsSchema>;
201
+ export type CaptchaSolverSettingsWithRunContext = CaptchaSolverSettings & {
201
202
  workspaceId: string;
202
203
  projectId: string;
203
204
  baseUrl: string;
@@ -20,6 +20,7 @@ async function withWaitForCaptchaSolve(callback, options) {
20
20
  settleDurationMs = 5_000,
21
21
  waitForNetworkSettled = true
22
22
  } = options;
23
+ console.error(`Starting captcha solve wait (timeout=${timeoutInMs}ms, settleDuration=${settleDurationMs}ms, waitForNetworkSettled=${waitForNetworkSettled})`);
23
24
  const extensionServer = (0, _intunedExtensionServer.getIntunedExtensionServer)();
24
25
  let settledResolve = null;
25
26
  let settledPromise = new Promise(resolve => {
@@ -39,21 +40,35 @@ async function withWaitForCaptchaSolve(callback, options) {
39
40
  const onCaptchaUpdate = async _captcha => {
40
41
  const solvingCaptchas = await extensionServer.getCaptchas(page, "solving");
41
42
  const errorCaptchas = await extensionServer.getCaptchas(page, "error");
43
+ console.error(`Captcha update received: solving=${solvingCaptchas.length}, errors=${errorCaptchas.length}`);
42
44
  if (solvingCaptchas.length > 0) {
43
45
  captchasAppeared = true;
46
+ console.error(`Captchas detected: ${solvingCaptchas.map(c => c.id).join(", ")}`);
44
47
  }
45
48
  if (errorCaptchas.length > 0) {
46
49
  error = errorCaptchas[0].error;
50
+ console.error(`Captcha error detected: ${error?.code}`);
47
51
  await maybeSettle();
48
52
  return;
49
53
  }
50
54
  if (solvingCaptchas.length === 0) {
55
+ console.error("No pending captchas, settling");
51
56
  await maybeSettle();
52
57
  }
53
58
  };
59
+ const result = await callback(page);
60
+ actionDone = true;
61
+ if (waitForNetworkSettled) {
62
+ try {
63
+ await page.waitForLoadState("networkidle");
64
+ } catch (err) {
65
+ console.error(`Failed to wait for networkidle. Error: ${err}`);
66
+ }
67
+ }
54
68
  const timeoutPromise = new Promise(resolve => {
55
69
  setTimeout(() => {
56
70
  isTimeout = true;
71
+ console.error("Captcha solve timeout reached");
57
72
  settledResolve?.();
58
73
  resolve();
59
74
  }, timeoutInMs);
@@ -61,33 +76,32 @@ async function withWaitForCaptchaSolve(callback, options) {
61
76
  await extensionServer.subscribe(page, onCaptchaUpdate);
62
77
  try {
63
78
  const initialPending = await getPendingCaptchas();
79
+ console.error(`Found ${initialPending.length} ongoing captchas`);
64
80
  if (initialPending.length > 0) {
65
81
  captchasAppeared = true;
66
82
  }
67
- const result = await callback(page);
68
- actionDone = true;
69
- if (waitForNetworkSettled) {
70
- try {
71
- await page.waitForLoadState("networkidle");
72
- } catch (err) {
73
- console.error(`Failed to wait for networkidle. Error: ${err}`);
74
- }
75
- }
76
83
  await maybeSettle();
77
84
  let shouldContinue = true;
78
85
  while (shouldContinue) {
79
86
  await Promise.race([settledPromise, timeoutPromise]);
87
+ console.error(`Settled event received, waiting ${settleDurationMs}ms before checking`);
80
88
  await new Promise(r => setTimeout(r, settleDurationMs));
81
89
  if (error) {
90
+ console.error(`Raising captcha error: ${error.code}`);
82
91
  throw new _types.CaptchaSolveError(`CAPTCHA Solve Error: ${error.code}`, error);
83
92
  }
84
93
  const noPendingCaptchas = await hasNoPendingCaptchas();
94
+ const pending = await getPendingCaptchas();
95
+ console.error(`Check point: actionDone=${actionDone}, noPendingCaptchas=${noPendingCaptchas}, isTimeout=${isTimeout}, pendingCount=${pending.length}`);
85
96
  if (actionDone && noPendingCaptchas || isTimeout) {
86
97
  if (isTimeout && !noPendingCaptchas) {
98
+ console.error(`Timeout with ${pending.length} pending captchas`);
87
99
  throw new _types.TimeoutError("CAPTCHA Solve timed out with pending captchas.");
88
100
  }
101
+ console.error("Captcha solve completed successfully");
89
102
  shouldContinue = false;
90
103
  } else {
104
+ console.error(`Still have ${pending.length} pending captchas, waiting for more updates`);
91
105
  settledPromise = new Promise(resolve => {
92
106
  settledResolve = resolve;
93
107
  });
@@ -164,13 +178,13 @@ async function setAutoSolve(context, enabled) {
164
178
  `, enabled);
165
179
  }
166
180
  async function pauseCaptchaSolver(context) {
167
- if (!(0, _extensionsHelpers.isIntunedExtensionEnabled)()) {
181
+ if (!(await (0, _extensionsHelpers.isIntunedExtensionEnabled)())) {
168
182
  throw new Error("Intuned extension is not enabled. Cannot pause captcha solver.");
169
183
  }
170
184
  await setAutoSolve(context, false);
171
185
  }
172
186
  async function resumeCaptchaSolver(context) {
173
- if (!(0, _extensionsHelpers.isIntunedExtensionEnabled)()) {
187
+ if (!(await (0, _extensionsHelpers.isIntunedExtensionEnabled)())) {
174
188
  throw new Error("Intuned extension is not enabled. Cannot resume captcha solver.");
175
189
  }
176
190
  await setAutoSolve(context, true);
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@intuned/runtime",
3
- "version": "1.3.15",
3
+ "version": "1.3.16",
4
4
  "description": "Intuned runtime",
5
5
  "exports": {
6
6
  ".": "./dist/index.js",
@@ -70,7 +70,7 @@
70
70
  "commander": "14.0.0",
71
71
  "cross-fetch": "^4.0.0",
72
72
  "dotenv": "^16.3.1",
73
- "fastify": "4.29.0",
73
+ "fastify": "4.29.1",
74
74
  "fs-extra": "^11.3.0",
75
75
  "image-size": "^1.1.1",
76
76
  "jsonc-parser": "^3.3.1",