@agenticmail/enterprise 0.5.430 → 0.5.431

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.
@@ -0,0 +1,359 @@
1
+ import {
2
+ DEFAULT_AGENTICMAIL_BROWSER_COLOR,
3
+ DEFAULT_AGENTICMAIL_BROWSER_ENABLED,
4
+ DEFAULT_AGENTICMAIL_BROWSER_PROFILE_NAME,
5
+ DEFAULT_BROWSER_DEFAULT_PROFILE_NAME,
6
+ DEFAULT_BROWSER_EVALUATE_ENABLED
7
+ } from "./chunk-MCZNCJQ2.js";
8
+ import {
9
+ DEFAULT_BROWSER_CONTROL_PORT,
10
+ deriveDefaultBrowserCdpPortRange,
11
+ deriveDefaultBrowserControlPort,
12
+ extractErrorCode,
13
+ formatErrorMessage,
14
+ isLoopbackHost,
15
+ resolveGatewayPort,
16
+ runExec
17
+ } from "./chunk-A3PUJDNH.js";
18
+
19
+ // src/browser/profiles.ts
20
+ var CDP_PORT_RANGE_START = 18800;
21
+ var CDP_PORT_RANGE_END = 18899;
22
+ var PROFILE_NAME_REGEX = /^[a-z0-9][a-z0-9-]*$/;
23
+ function isValidProfileName(name) {
24
+ if (!name || name.length > 64) {
25
+ return false;
26
+ }
27
+ return PROFILE_NAME_REGEX.test(name);
28
+ }
29
+ function allocateCdpPort(usedPorts, range) {
30
+ const start = range?.start ?? CDP_PORT_RANGE_START;
31
+ const end = range?.end ?? CDP_PORT_RANGE_END;
32
+ if (!Number.isFinite(start) || !Number.isFinite(end) || start <= 0 || end <= 0) {
33
+ return null;
34
+ }
35
+ if (start > end) {
36
+ return null;
37
+ }
38
+ for (let port = start; port <= end; port++) {
39
+ if (!usedPorts.has(port)) {
40
+ return port;
41
+ }
42
+ }
43
+ return null;
44
+ }
45
+ function getUsedPorts(profiles) {
46
+ if (!profiles) {
47
+ return /* @__PURE__ */ new Set();
48
+ }
49
+ const used = /* @__PURE__ */ new Set();
50
+ for (const profile of Object.values(profiles)) {
51
+ if (typeof profile.cdpPort === "number") {
52
+ used.add(profile.cdpPort);
53
+ continue;
54
+ }
55
+ const rawUrl = profile.cdpUrl?.trim();
56
+ if (!rawUrl) {
57
+ continue;
58
+ }
59
+ try {
60
+ const parsed = new URL(rawUrl);
61
+ const port = parsed.port && Number.parseInt(parsed.port, 10) > 0 ? Number.parseInt(parsed.port, 10) : parsed.protocol === "https:" ? 443 : 80;
62
+ if (!Number.isNaN(port) && port > 0 && port <= 65535) {
63
+ used.add(port);
64
+ }
65
+ } catch {
66
+ }
67
+ }
68
+ return used;
69
+ }
70
+ var PROFILE_COLORS = [
71
+ "#FF4500",
72
+ // Orange-red (agenticmail default)
73
+ "#0066CC",
74
+ // Blue
75
+ "#00AA00",
76
+ // Green
77
+ "#9933FF",
78
+ // Purple
79
+ "#FF6699",
80
+ // Pink
81
+ "#00CCCC",
82
+ // Cyan
83
+ "#FF9900",
84
+ // Orange
85
+ "#6666FF",
86
+ // Indigo
87
+ "#CC3366",
88
+ // Magenta
89
+ "#339966"
90
+ // Teal
91
+ ];
92
+ function allocateColor(usedColors) {
93
+ for (const color of PROFILE_COLORS) {
94
+ if (!usedColors.has(color.toUpperCase())) {
95
+ return color;
96
+ }
97
+ }
98
+ const index = usedColors.size % PROFILE_COLORS.length;
99
+ return PROFILE_COLORS[index] ?? PROFILE_COLORS[0];
100
+ }
101
+ function getUsedColors(profiles) {
102
+ if (!profiles) {
103
+ return /* @__PURE__ */ new Set();
104
+ }
105
+ return new Set(Object.values(profiles).map((p) => (p.color || "").toUpperCase()));
106
+ }
107
+
108
+ // src/browser/config.ts
109
+ function normalizeHexColor(raw) {
110
+ const value = (raw ?? "").trim();
111
+ if (!value) {
112
+ return DEFAULT_AGENTICMAIL_BROWSER_COLOR;
113
+ }
114
+ const normalized = value.startsWith("#") ? value : `#${value}`;
115
+ if (!/^#[0-9a-fA-F]{6}$/.test(normalized)) {
116
+ return DEFAULT_AGENTICMAIL_BROWSER_COLOR;
117
+ }
118
+ return normalized.toUpperCase();
119
+ }
120
+ function normalizeTimeoutMs(raw, fallback) {
121
+ const value = typeof raw === "number" && Number.isFinite(raw) ? Math.floor(raw) : fallback;
122
+ return value < 0 ? fallback : value;
123
+ }
124
+ function normalizeStringList(raw) {
125
+ if (!Array.isArray(raw) || raw.length === 0) {
126
+ return void 0;
127
+ }
128
+ const values = raw.map((value) => value.trim()).filter((value) => value.length > 0);
129
+ return values.length > 0 ? values : void 0;
130
+ }
131
+ function resolveBrowserSsrFPolicy(cfg) {
132
+ const allowPrivateNetwork = cfg?.ssrfPolicy?.allowPrivateNetwork;
133
+ const allowedHostnames = normalizeStringList(cfg?.ssrfPolicy?.allowedHostnames);
134
+ const hostnameAllowlist = normalizeStringList(cfg?.ssrfPolicy?.hostnameAllowlist);
135
+ if (allowPrivateNetwork === void 0 && allowedHostnames === void 0 && hostnameAllowlist === void 0) {
136
+ return void 0;
137
+ }
138
+ return {
139
+ mode: "permissive",
140
+ allowedPatterns: [],
141
+ blockedPatterns: [],
142
+ allowFileUrls: false,
143
+ allowPrivateIps: allowPrivateNetwork || false,
144
+ ...allowPrivateNetwork === true ? { allowPrivateNetwork: true } : {},
145
+ ...allowedHostnames ? { allowedHostnames } : {},
146
+ ...hostnameAllowlist ? { hostnameAllowlist } : {}
147
+ };
148
+ }
149
+ function parseHttpUrl(raw, label) {
150
+ const trimmed = raw.trim();
151
+ const parsed = new URL(trimmed);
152
+ if (parsed.protocol !== "http:" && parsed.protocol !== "https:") {
153
+ throw new Error(`${label} must be http(s), got: ${parsed.protocol.replace(":", "")}`);
154
+ }
155
+ const port = parsed.port && Number.parseInt(parsed.port, 10) > 0 ? Number.parseInt(parsed.port, 10) : parsed.protocol === "https:" ? 443 : 80;
156
+ if (Number.isNaN(port) || port <= 0 || port > 65535) {
157
+ throw new Error(`${label} has invalid port: ${parsed.port}`);
158
+ }
159
+ return {
160
+ parsed,
161
+ port,
162
+ normalized: parsed.toString().replace(/\/$/, "")
163
+ };
164
+ }
165
+ function ensureDefaultProfile(profiles, defaultColor, legacyCdpPort, derivedDefaultCdpPort) {
166
+ const result = { ...profiles };
167
+ if (!result[DEFAULT_AGENTICMAIL_BROWSER_PROFILE_NAME]) {
168
+ result[DEFAULT_AGENTICMAIL_BROWSER_PROFILE_NAME] = {
169
+ cdpPort: legacyCdpPort ?? derivedDefaultCdpPort ?? CDP_PORT_RANGE_START,
170
+ color: defaultColor
171
+ };
172
+ }
173
+ return result;
174
+ }
175
+ function ensureDefaultChromeExtensionProfile(profiles, controlPort) {
176
+ const result = { ...profiles };
177
+ if (result.chrome) {
178
+ return result;
179
+ }
180
+ const relayPort = controlPort + 1;
181
+ if (!Number.isFinite(relayPort) || relayPort <= 0 || relayPort > 65535) {
182
+ return result;
183
+ }
184
+ if (getUsedPorts(result).has(relayPort)) {
185
+ return result;
186
+ }
187
+ result.chrome = {
188
+ driver: "extension",
189
+ cdpUrl: `http://127.0.0.1:${relayPort}`,
190
+ color: "#00AA00"
191
+ };
192
+ return result;
193
+ }
194
+ function resolveBrowserConfig(cfg, rootConfig) {
195
+ const enabled = cfg?.enabled ?? DEFAULT_AGENTICMAIL_BROWSER_ENABLED;
196
+ const evaluateEnabled = cfg?.evaluateEnabled ?? DEFAULT_BROWSER_EVALUATE_ENABLED;
197
+ const gatewayPort = resolveGatewayPort(rootConfig);
198
+ const controlPort = deriveDefaultBrowserControlPort(gatewayPort ?? DEFAULT_BROWSER_CONTROL_PORT);
199
+ const defaultColor = normalizeHexColor(cfg?.color);
200
+ const remoteCdpTimeoutMs = normalizeTimeoutMs(cfg?.remoteCdpTimeoutMs, 1500);
201
+ const remoteCdpHandshakeTimeoutMs = normalizeTimeoutMs(
202
+ cfg?.remoteCdpHandshakeTimeoutMs,
203
+ Math.max(2e3, remoteCdpTimeoutMs * 2)
204
+ );
205
+ const derivedCdpRange = deriveDefaultBrowserCdpPortRange(controlPort);
206
+ const rawCdpUrl = (cfg?.cdpUrl ?? "").trim();
207
+ let cdpInfo;
208
+ if (rawCdpUrl) {
209
+ cdpInfo = parseHttpUrl(rawCdpUrl, "browser.cdpUrl");
210
+ } else {
211
+ const derivedPort = controlPort + 1;
212
+ if (derivedPort > 65535) {
213
+ throw new Error(
214
+ `Derived CDP port (${derivedPort}) is too high; check gateway port configuration.`
215
+ );
216
+ }
217
+ const derived = new URL(`http://127.0.0.1:${derivedPort}`);
218
+ cdpInfo = {
219
+ parsed: derived,
220
+ port: derivedPort,
221
+ normalized: derived.toString().replace(/\/$/, "")
222
+ };
223
+ }
224
+ const headless = cfg?.headless === true;
225
+ const noSandbox = cfg?.noSandbox === true;
226
+ const attachOnly = cfg?.attachOnly === true;
227
+ const executablePath = cfg?.executablePath?.trim() || void 0;
228
+ const defaultProfileFromConfig = cfg?.defaultProfile?.trim() || void 0;
229
+ const legacyCdpPort = rawCdpUrl ? cdpInfo.port : void 0;
230
+ const profiles = ensureDefaultChromeExtensionProfile(
231
+ ensureDefaultProfile(cfg?.profiles, defaultColor, legacyCdpPort, derivedCdpRange.start),
232
+ controlPort
233
+ );
234
+ const cdpProtocol = cdpInfo.parsed.protocol === "https:" ? "https" : "http";
235
+ const defaultProfile = defaultProfileFromConfig ?? (profiles[DEFAULT_BROWSER_DEFAULT_PROFILE_NAME] ? DEFAULT_BROWSER_DEFAULT_PROFILE_NAME : DEFAULT_AGENTICMAIL_BROWSER_PROFILE_NAME);
236
+ const extraArgs = Array.isArray(cfg?.extraArgs) ? cfg.extraArgs.filter((a) => typeof a === "string" && a.trim().length > 0) : [];
237
+ const ssrfPolicy = resolveBrowserSsrFPolicy(cfg);
238
+ return {
239
+ enabled,
240
+ evaluateEnabled,
241
+ controlPort,
242
+ cdpProtocol,
243
+ cdpHost: cdpInfo.parsed.hostname,
244
+ cdpIsLoopback: isLoopbackHost(cdpInfo.parsed.hostname),
245
+ remoteCdpTimeoutMs,
246
+ remoteCdpHandshakeTimeoutMs,
247
+ color: defaultColor,
248
+ executablePath,
249
+ headless,
250
+ noSandbox,
251
+ attachOnly,
252
+ defaultProfile,
253
+ profiles,
254
+ ssrfPolicy,
255
+ extraArgs
256
+ };
257
+ }
258
+ function resolveProfile(resolved, profileName) {
259
+ const profile = resolved.profiles[profileName];
260
+ if (!profile) {
261
+ return null;
262
+ }
263
+ const rawProfileUrl = profile.cdpUrl?.trim() ?? "";
264
+ let cdpHost = resolved.cdpHost;
265
+ let cdpPort = profile.cdpPort ?? 0;
266
+ let cdpUrl = "";
267
+ const driver = profile.driver === "extension" ? "extension" : "agenticmail";
268
+ if (rawProfileUrl) {
269
+ const parsed = parseHttpUrl(rawProfileUrl, `browser.profiles.${profileName}.cdpUrl`);
270
+ cdpHost = parsed.parsed.hostname;
271
+ cdpPort = parsed.port;
272
+ cdpUrl = parsed.normalized;
273
+ } else if (cdpPort) {
274
+ cdpUrl = `${resolved.cdpProtocol}://${resolved.cdpHost}:${cdpPort}`;
275
+ } else {
276
+ throw new Error(`Profile "${profileName}" must define cdpPort or cdpUrl.`);
277
+ }
278
+ return {
279
+ name: profileName,
280
+ cdpPort,
281
+ cdpUrl,
282
+ cdpHost,
283
+ cdpIsLoopback: isLoopbackHost(cdpHost),
284
+ color: profile.color || "#666",
285
+ driver
286
+ };
287
+ }
288
+
289
+ // src/browser/pw-ai-module.ts
290
+ var pwAiModuleSoft = null;
291
+ var pwAiModuleStrict = null;
292
+ function isModuleNotFoundError(err) {
293
+ const code = extractErrorCode(err);
294
+ if (code === "ERR_MODULE_NOT_FOUND") {
295
+ return true;
296
+ }
297
+ const msg = formatErrorMessage(err);
298
+ return msg.includes("Cannot find module") || msg.includes("Cannot find package") || msg.includes("Failed to resolve import") || msg.includes("Failed to resolve entry for package") || msg.includes("Failed to load url");
299
+ }
300
+ async function loadPwAiModule(mode) {
301
+ try {
302
+ return await import("./pw-ai-UQSZWCVQ.js");
303
+ } catch (err) {
304
+ if (mode === "soft") {
305
+ return null;
306
+ }
307
+ if (isModuleNotFoundError(err)) {
308
+ return null;
309
+ }
310
+ throw err;
311
+ }
312
+ }
313
+ async function getPwAiModule(opts) {
314
+ const mode = opts?.mode ?? "soft";
315
+ if (mode === "soft") {
316
+ if (!pwAiModuleSoft) {
317
+ pwAiModuleSoft = loadPwAiModule("soft");
318
+ }
319
+ return await pwAiModuleSoft;
320
+ }
321
+ if (!pwAiModuleStrict) {
322
+ pwAiModuleStrict = loadPwAiModule("strict");
323
+ }
324
+ return await pwAiModuleStrict;
325
+ }
326
+
327
+ // src/browser/trash.ts
328
+ import fs from "fs";
329
+ import os from "os";
330
+ import path from "path";
331
+ async function movePathToTrash(targetPath) {
332
+ try {
333
+ await runExec("trash", [targetPath], { timeoutMs: 1e4 });
334
+ return targetPath;
335
+ } catch {
336
+ const trashDir = path.join(os.homedir(), ".Trash");
337
+ fs.mkdirSync(trashDir, { recursive: true });
338
+ const base = path.basename(targetPath);
339
+ let dest = path.join(trashDir, `${base}-${Date.now()}`);
340
+ if (fs.existsSync(dest)) {
341
+ dest = path.join(trashDir, `${base}-${Date.now()}-${Math.random()}`);
342
+ }
343
+ fs.renameSync(targetPath, dest);
344
+ return dest;
345
+ }
346
+ }
347
+
348
+ export {
349
+ isValidProfileName,
350
+ allocateCdpPort,
351
+ getUsedPorts,
352
+ allocateColor,
353
+ getUsedColors,
354
+ parseHttpUrl,
355
+ resolveBrowserConfig,
356
+ resolveProfile,
357
+ getPwAiModule,
358
+ movePathToTrash
359
+ };