@open-wa/wa-automate 5.3.0 → 5.5.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/cli-runtime-BGz4DzHq.d.cts.map +1 -1
- package/dist/{cli-runtime-BHx1nVhT.cjs → cli-runtime-BRj_LUIT.cjs} +503 -115
- package/dist/cli-runtime-BRj_LUIT.cjs.map +1 -0
- package/dist/cli.cjs +1 -1
- package/dist/index.cjs +86 -305
- package/dist/index.cjs.map +1 -1
- package/dist/index.d.cts +9 -7
- package/dist/index.d.cts.map +1 -1
- package/dist/{init-CTh6gc8w.cjs → init-CUhC5Wkq.cjs} +4 -4
- package/dist/{init-CTh6gc8w.cjs.map → init-CUhC5Wkq.cjs.map} +1 -1
- package/package.json +21 -12
- package/dist/cli-runtime-BHx1nVhT.cjs.map +0 -1
|
@@ -21,16 +21,17 @@ var __toESM = (mod, isNodeMode, target) => (target = mod != null ? __create(__ge
|
|
|
21
21
|
}) : target, mod));
|
|
22
22
|
//#endregion
|
|
23
23
|
let _open_wa_api = require("@open-wa/api");
|
|
24
|
-
let node_path = require("node:path");
|
|
25
24
|
let qrcode_terminal = require("qrcode-terminal");
|
|
26
25
|
qrcode_terminal = __toESM(qrcode_terminal, 1);
|
|
26
|
+
let node_path = require("node:path");
|
|
27
27
|
let _open_wa_core = require("@open-wa/core");
|
|
28
28
|
let _open_wa_client = require("@open-wa/client");
|
|
29
|
-
let _open_wa_driver_lightpanda = require("@open-wa/driver-lightpanda");
|
|
30
|
-
let _open_wa_driver_puppeteer = require("@open-wa/driver-puppeteer");
|
|
31
|
-
let _open_wa_schema = require("@open-wa/schema");
|
|
32
29
|
let _open_wa_config = require("@open-wa/config");
|
|
33
30
|
let node_fs = require("node:fs");
|
|
31
|
+
let node_fs_promises = require("node:fs/promises");
|
|
32
|
+
let node_os = require("node:os");
|
|
33
|
+
let _open_wa_driver_interface = require("@open-wa/driver-interface");
|
|
34
|
+
let _open_wa_schema = require("@open-wa/schema");
|
|
34
35
|
let node_url = require("node:url");
|
|
35
36
|
let _open_wa_runtime_core = require("@open-wa/runtime-core");
|
|
36
37
|
let _open_wa_runtime_node = require("@open-wa/runtime-node");
|
|
@@ -42,6 +43,30 @@ var WAServer = class extends _open_wa_api.ApiServer {
|
|
|
42
43
|
};
|
|
43
44
|
//#endregion
|
|
44
45
|
//#region src/cli/output-sink.ts
|
|
46
|
+
async function promptChoice(question, choices) {
|
|
47
|
+
if (!process.stdin.isTTY || !process.stderr.isTTY) throw new Error("No browser is installed. Choose --use-chrome, --use-chromium or --use-lightpanda to download one without a prompt.");
|
|
48
|
+
const { createInterface } = await import("node:readline/promises");
|
|
49
|
+
const readline = createInterface({
|
|
50
|
+
input: process.stdin,
|
|
51
|
+
output: process.stderr
|
|
52
|
+
});
|
|
53
|
+
const abort = new AbortController();
|
|
54
|
+
readline.on("SIGINT", () => abort.abort());
|
|
55
|
+
readline.on("close", () => abort.abort());
|
|
56
|
+
try {
|
|
57
|
+
process.stderr.write(`\n${question}\n${choices.map((choice, index) => ` ${index + 1}. ${choice}`).join("\n")}\n`);
|
|
58
|
+
while (true) {
|
|
59
|
+
const answer = (await readline.question("Choose a browser [1]: ", { signal: abort.signal })).trim();
|
|
60
|
+
const choice = answer === "" ? 0 : Number(answer) - 1;
|
|
61
|
+
if (Number.isInteger(choice) && choice >= 0 && choice < choices.length) return choice;
|
|
62
|
+
process.stderr.write(`Enter a number from 1 to ${choices.length}.\n`);
|
|
63
|
+
}
|
|
64
|
+
} catch (cause) {
|
|
65
|
+
throw new Error("Browser selection cancelled.", { cause });
|
|
66
|
+
} finally {
|
|
67
|
+
readline.close();
|
|
68
|
+
}
|
|
69
|
+
}
|
|
45
70
|
function writeToConsole(level, message) {
|
|
46
71
|
if (level === "warn") {
|
|
47
72
|
console.warn(message);
|
|
@@ -55,6 +80,7 @@ function writeToConsole(level, message) {
|
|
|
55
80
|
}
|
|
56
81
|
function createConsoleOutputSink() {
|
|
57
82
|
return {
|
|
83
|
+
promptChoice,
|
|
58
84
|
write(entry) {
|
|
59
85
|
writeToConsole(entry.level, entry.message);
|
|
60
86
|
},
|
|
@@ -77,6 +103,430 @@ function resetCliOutputSink() {
|
|
|
77
103
|
activeSink = createConsoleOutputSink();
|
|
78
104
|
}
|
|
79
105
|
//#endregion
|
|
106
|
+
//#region src/browser-choice.ts
|
|
107
|
+
const choiceFile = (0, node_path.join)((0, node_os.homedir)(), ".cache", "open-wa", "browser-choice.json");
|
|
108
|
+
async function findSystemBrowser(kind) {
|
|
109
|
+
const app = kind === "chrome" ? "Google Chrome" : "Chromium";
|
|
110
|
+
const names = process.platform === "win32" ? ["chrome.exe"] : kind === "chrome" ? [
|
|
111
|
+
"google-chrome-stable",
|
|
112
|
+
"google-chrome",
|
|
113
|
+
"chrome"
|
|
114
|
+
] : ["chromium", "chromium-browser"];
|
|
115
|
+
const candidates = process.platform === "darwin" ? ["/Applications", (0, node_path.join)((0, node_os.homedir)(), "Applications")].map((root) => (0, node_path.join)(root, `${app}.app`, "Contents", "MacOS", app)) : process.platform === "win32" ? [
|
|
116
|
+
process.env.LOCALAPPDATA,
|
|
117
|
+
process.env.PROGRAMFILES,
|
|
118
|
+
process.env["PROGRAMFILES(X86)"]
|
|
119
|
+
].filter((root) => !!root).map((root) => kind === "chrome" ? (0, node_path.join)(root, "Google", "Chrome", "Application", "chrome.exe") : (0, node_path.join)(root, "Chromium", "Application", "chrome.exe")) : kind === "chrome" ? ["/opt/google/chrome/chrome"] : [];
|
|
120
|
+
candidates.push(...(process.env.PATH ?? "").split(node_path.delimiter).filter(Boolean).flatMap((root) => names.map((name) => (0, node_path.join)(root, name))));
|
|
121
|
+
for (const candidate of candidates) try {
|
|
122
|
+
if (!(await (0, node_fs_promises.stat)(candidate)).isFile()) continue;
|
|
123
|
+
await (0, node_fs_promises.access)(candidate, node_fs.constants.X_OK);
|
|
124
|
+
return candidate;
|
|
125
|
+
} catch {}
|
|
126
|
+
}
|
|
127
|
+
async function readBrowserChoice() {
|
|
128
|
+
const { Effect, Schema } = await import("effect");
|
|
129
|
+
const recordSchema = Schema.fromJsonString(Schema.Struct({
|
|
130
|
+
kind: Schema.Literals([
|
|
131
|
+
"chrome",
|
|
132
|
+
"chromium",
|
|
133
|
+
"lightpanda"
|
|
134
|
+
]),
|
|
135
|
+
executablePath: Schema.String
|
|
136
|
+
}));
|
|
137
|
+
const io = (operation) => Effect.tryPromise({
|
|
138
|
+
try: operation,
|
|
139
|
+
catch: _open_wa_driver_interface.toPublicError
|
|
140
|
+
});
|
|
141
|
+
return Effect.runPromise(Effect.gen(function* () {
|
|
142
|
+
const record = yield* Schema.decodeUnknownEffect(recordSchema)(yield* io(() => (0, node_fs_promises.readFile)(choiceFile, "utf8")));
|
|
143
|
+
if (!(yield* io(() => (0, node_fs_promises.stat)(record.executablePath))).isFile()) return void 0;
|
|
144
|
+
yield* io(() => (0, node_fs_promises.access)(record.executablePath, node_fs.constants.X_OK));
|
|
145
|
+
return record;
|
|
146
|
+
}).pipe(Effect.catch(() => Effect.succeed(void 0))));
|
|
147
|
+
}
|
|
148
|
+
async function writeBrowserChoice(kind, executablePath) {
|
|
149
|
+
const { Effect } = await import("effect");
|
|
150
|
+
const io = (operation) => Effect.tryPromise({
|
|
151
|
+
try: operation,
|
|
152
|
+
catch: _open_wa_driver_interface.toPublicError
|
|
153
|
+
});
|
|
154
|
+
const program = Effect.gen(function* () {
|
|
155
|
+
const directory = (0, node_path.dirname)(choiceFile);
|
|
156
|
+
yield* io(() => (0, node_fs_promises.mkdir)(directory, { recursive: true }));
|
|
157
|
+
const staging = yield* Effect.acquireRelease(io(() => (0, node_fs_promises.mkdtemp)((0, node_path.join)(directory, ".browser-choice-"))), (path) => io(() => (0, node_fs_promises.rm)(path, {
|
|
158
|
+
recursive: true,
|
|
159
|
+
force: true
|
|
160
|
+
})).pipe(Effect.orDie));
|
|
161
|
+
const temporary = (0, node_path.join)(staging, "browser-choice.json");
|
|
162
|
+
yield* io(() => (0, node_fs_promises.writeFile)(temporary, JSON.stringify({
|
|
163
|
+
kind,
|
|
164
|
+
executablePath
|
|
165
|
+
}), {
|
|
166
|
+
encoding: "utf8",
|
|
167
|
+
flag: "wx"
|
|
168
|
+
}));
|
|
169
|
+
yield* io(() => (0, node_fs_promises.rename)(temporary, choiceFile));
|
|
170
|
+
});
|
|
171
|
+
await Effect.runPromise(Effect.scoped(Effect.uninterruptible(program))).catch((cause) => {
|
|
172
|
+
throw (0, _open_wa_driver_interface.toPublicError)(cause);
|
|
173
|
+
});
|
|
174
|
+
}
|
|
175
|
+
async function chooseBrowser() {
|
|
176
|
+
return [
|
|
177
|
+
"chrome",
|
|
178
|
+
"chromium",
|
|
179
|
+
"lightpanda"
|
|
180
|
+
][await (getCliOutputSink().promptChoice ?? promptChoice)("Google Chrome was not found. Which browser would you like to download?", [
|
|
181
|
+
"Chrome for Testing — recommended; highest compatibility, including video and media.",
|
|
182
|
+
"Chromium — middle ground; proprietary video/audio codecs may be unavailable.",
|
|
183
|
+
"Lightpanda — lightweight basic automation; low compatibility, experimental WhatsApp support, no video or rendering."
|
|
184
|
+
])];
|
|
185
|
+
}
|
|
186
|
+
//#endregion
|
|
187
|
+
//#region src/runtime-client.ts
|
|
188
|
+
function readChromePathCache(cacheFilePath) {
|
|
189
|
+
try {
|
|
190
|
+
if (!(0, node_fs.existsSync)(cacheFilePath)) return;
|
|
191
|
+
const raw = JSON.parse((0, node_fs.readFileSync)(cacheFilePath, "utf8"));
|
|
192
|
+
if (!raw || typeof raw !== "object") return;
|
|
193
|
+
return { executablePath: typeof raw.executablePath === "string" ? raw.executablePath : void 0 };
|
|
194
|
+
} catch {
|
|
195
|
+
return;
|
|
196
|
+
}
|
|
197
|
+
}
|
|
198
|
+
function writeChromePathCache(executablePath, cacheFilePath) {
|
|
199
|
+
(0, node_fs.mkdirSync)((0, node_path.dirname)(cacheFilePath), { recursive: true });
|
|
200
|
+
(0, node_fs.writeFileSync)(cacheFilePath, JSON.stringify({
|
|
201
|
+
executablePath,
|
|
202
|
+
updatedAt: (/* @__PURE__ */ new Date()).toISOString()
|
|
203
|
+
}, null, 2), "utf8");
|
|
204
|
+
}
|
|
205
|
+
function clearChromePathCache(cacheFilePath) {
|
|
206
|
+
if ((0, node_fs.existsSync)(cacheFilePath)) (0, node_fs.rmSync)(cacheFilePath, { force: true });
|
|
207
|
+
}
|
|
208
|
+
function isUsableExecutablePath(executablePath) {
|
|
209
|
+
if (!executablePath) return false;
|
|
210
|
+
try {
|
|
211
|
+
if (!(0, node_fs.statSync)(executablePath).isFile()) return false;
|
|
212
|
+
(0, node_fs.accessSync)(executablePath, node_fs.constants.X_OK);
|
|
213
|
+
return true;
|
|
214
|
+
} catch {
|
|
215
|
+
return false;
|
|
216
|
+
}
|
|
217
|
+
}
|
|
218
|
+
function getExplicitUseChromePreference(rawConfigs) {
|
|
219
|
+
const explicitConfigSources = [
|
|
220
|
+
rawConfigs?.file,
|
|
221
|
+
rawConfigs?.env,
|
|
222
|
+
rawConfigs?.cli,
|
|
223
|
+
rawConfigs?.programmatic
|
|
224
|
+
];
|
|
225
|
+
for (let index = explicitConfigSources.length - 1; index >= 0; index -= 1) {
|
|
226
|
+
const source = explicitConfigSources[index];
|
|
227
|
+
if (source?.useChrome !== void 0) return source.useChrome;
|
|
228
|
+
}
|
|
229
|
+
}
|
|
230
|
+
function shouldPreferLocalChrome(config, rawConfigs, defaultPreference = true) {
|
|
231
|
+
if (config.useLightpanda || config.useChromium || config.browser?.kind === "chromium") return false;
|
|
232
|
+
if (config.executablePath || process.env.PUPPETEER_EXECUTABLE_PATH !== void 0) return false;
|
|
233
|
+
const explicitUseChrome = getExplicitUseChromePreference(rawConfigs);
|
|
234
|
+
if (explicitUseChrome !== void 0) return explicitUseChrome;
|
|
235
|
+
return defaultPreference;
|
|
236
|
+
}
|
|
237
|
+
async function resolveExecutablePath(config, options) {
|
|
238
|
+
const configuredPath = config.executablePath ?? process.env.PUPPETEER_EXECUTABLE_PATH;
|
|
239
|
+
if (configuredPath !== void 0) return {
|
|
240
|
+
executablePath: configuredPath,
|
|
241
|
+
source: "config"
|
|
242
|
+
};
|
|
243
|
+
if (!(options.preferLocalChrome ?? config.useChrome)) return { source: "driver_default" };
|
|
244
|
+
const matchesKind = (path) => options.kind === "chromium" ? /chromium/i.test(path) : !/chromium/i.test(path);
|
|
245
|
+
const cachedPath = readChromePathCache(options.cacheFilePath)?.executablePath;
|
|
246
|
+
if (isUsableExecutablePath(cachedPath) && matchesKind(cachedPath)) return {
|
|
247
|
+
executablePath: cachedPath,
|
|
248
|
+
source: "cache"
|
|
249
|
+
};
|
|
250
|
+
if (cachedPath) clearChromePathCache(options.cacheFilePath);
|
|
251
|
+
const detectedPath = await findSystemBrowser(options.kind ?? "chrome");
|
|
252
|
+
if (detectedPath) {
|
|
253
|
+
writeChromePathCache(detectedPath, options.cacheFilePath);
|
|
254
|
+
return {
|
|
255
|
+
executablePath: detectedPath,
|
|
256
|
+
source: "chrome_installation"
|
|
257
|
+
};
|
|
258
|
+
}
|
|
259
|
+
clearChromePathCache(options.cacheFilePath);
|
|
260
|
+
return { source: "driver_default" };
|
|
261
|
+
}
|
|
262
|
+
function resolveLightpandaExecutablePath(config) {
|
|
263
|
+
const executablePath = config.lightpanda?.executablePath ?? config.executablePath ?? process.env.LIGHTPANDA_EXECUTABLE_PATH;
|
|
264
|
+
if (executablePath) return {
|
|
265
|
+
executablePath,
|
|
266
|
+
source: "lightpanda_config"
|
|
267
|
+
};
|
|
268
|
+
return { source: "lightpanda_managed" };
|
|
269
|
+
}
|
|
270
|
+
async function selectRuntimeDriver$1(config, options) {
|
|
271
|
+
if ([
|
|
272
|
+
config.useChrome,
|
|
273
|
+
config.useChromium,
|
|
274
|
+
config.useLightpanda
|
|
275
|
+
].filter(Boolean).length > 1) throw new Error("Choose only one browser: useChrome, useChromium or useLightpanda.");
|
|
276
|
+
let kind = config.useLightpanda ? "lightpanda" : config.useChromium ? "chromium" : config.useChrome ? "chrome" : config.browser?.kind;
|
|
277
|
+
const explicitChoice = kind !== void 0 || getExplicitUseChromePreference(options.rawConfigs) !== void 0 || config.browser?.download === "auto";
|
|
278
|
+
const preferLocalChrome = shouldPreferLocalChrome(config, options.rawConfigs, options.defaultPreferLocalChrome ?? true);
|
|
279
|
+
let executableResolution = { source: "driver_default" };
|
|
280
|
+
if (kind !== "lightpanda") executableResolution = await resolveExecutablePath(config, {
|
|
281
|
+
preferLocalChrome: kind === "chromium" || preferLocalChrome,
|
|
282
|
+
cacheFilePath: kind === "chromium" ? `${options.cacheFilePath}.chromium` : options.cacheFilePath,
|
|
283
|
+
kind: kind === "chromium" ? "chromium" : "chrome"
|
|
284
|
+
});
|
|
285
|
+
else {
|
|
286
|
+
executableResolution = resolveLightpandaExecutablePath(config);
|
|
287
|
+
executableResolution.executablePath ??= config.executablePath;
|
|
288
|
+
}
|
|
289
|
+
if (!executableResolution.executablePath && (kind !== void 0 || options.promptForMissingBrowser) && !(kind === "lightpanda" && config.lightpanda?.experimentalWhatsApp !== false)) {
|
|
290
|
+
const remembered = await readBrowserChoice();
|
|
291
|
+
if (remembered && (kind === void 0 || remembered.kind === kind)) {
|
|
292
|
+
kind = remembered.kind;
|
|
293
|
+
executableResolution = {
|
|
294
|
+
source: "cache",
|
|
295
|
+
executablePath: remembered.executablePath
|
|
296
|
+
};
|
|
297
|
+
}
|
|
298
|
+
}
|
|
299
|
+
if (!kind && executableResolution.executablePath === void 0 && options.promptForMissingBrowser) {
|
|
300
|
+
const { ensureBrowser } = await import("@open-wa/driver-puppeteer");
|
|
301
|
+
try {
|
|
302
|
+
executableResolution = {
|
|
303
|
+
source: "managed_browser",
|
|
304
|
+
executablePath: await ensureBrowser({ browser: {
|
|
305
|
+
...config.browser,
|
|
306
|
+
kind: "chrome",
|
|
307
|
+
download: "never"
|
|
308
|
+
} })
|
|
309
|
+
};
|
|
310
|
+
} catch (error) {
|
|
311
|
+
if (!(error instanceof Error) || !/missing from .* and browser downloads are disabled/.test(error.message)) throw error;
|
|
312
|
+
}
|
|
313
|
+
}
|
|
314
|
+
if (!kind && !executableResolution.executablePath && !explicitChoice && options.promptForMissingBrowser) {
|
|
315
|
+
if (config.browser?.download === "never") throw new Error("No browser is available and browser downloads are disabled. Configure executablePath or pre-provision a browser cache.");
|
|
316
|
+
if (options.nonInteractive || process.env.CI || process.env.NONINTERACTIVE) throw new Error("No browser is installed. Choose --use-chrome, --use-chromium or --use-lightpanda to download one without a prompt.");
|
|
317
|
+
kind = await chooseBrowser();
|
|
318
|
+
}
|
|
319
|
+
kind ??= "chrome";
|
|
320
|
+
const sink = getCliOutputSink();
|
|
321
|
+
const ctx = { logger: {
|
|
322
|
+
debug: (message) => sink.write({
|
|
323
|
+
level: "debug",
|
|
324
|
+
message
|
|
325
|
+
}),
|
|
326
|
+
info: (message) => sink.write({
|
|
327
|
+
level: "info",
|
|
328
|
+
message
|
|
329
|
+
}),
|
|
330
|
+
warn: (message) => sink.write({
|
|
331
|
+
level: "warn",
|
|
332
|
+
message
|
|
333
|
+
}),
|
|
334
|
+
error: (message) => sink.write({
|
|
335
|
+
level: "error",
|
|
336
|
+
message
|
|
337
|
+
})
|
|
338
|
+
} };
|
|
339
|
+
const browser = {
|
|
340
|
+
...config.browser,
|
|
341
|
+
...explicitChoice || options.promptForMissingBrowser ? { download: config.browser?.download ?? "auto" } : {},
|
|
342
|
+
...kind !== "lightpanda" ? { kind } : {}
|
|
343
|
+
};
|
|
344
|
+
if (kind === "lightpanda") {
|
|
345
|
+
const { LightpandaDriver, ensureLightpanda } = await import("@open-wa/driver-lightpanda");
|
|
346
|
+
config.lightpanda = _open_wa_config.ConfigSchema.shape.lightpanda.parse({
|
|
347
|
+
...config.lightpanda,
|
|
348
|
+
experimentalWhatsApp: config.lightpanda?.experimentalWhatsApp ?? true
|
|
349
|
+
});
|
|
350
|
+
config.browser = browser;
|
|
351
|
+
const executablePath = await ensureLightpanda({
|
|
352
|
+
executablePath: executableResolution.executablePath,
|
|
353
|
+
browser,
|
|
354
|
+
preferPinnedRelease: config.lightpanda?.experimentalWhatsApp ?? true
|
|
355
|
+
}, ctx);
|
|
356
|
+
config.useLightpanda = true;
|
|
357
|
+
config.useChrome = false;
|
|
358
|
+
config.useChromium = false;
|
|
359
|
+
sink.write({
|
|
360
|
+
level: "warn",
|
|
361
|
+
message: "Lightpanda has low compatibility and experimental WhatsApp support; video, screenshots and rendering are unavailable."
|
|
362
|
+
});
|
|
363
|
+
if (options.promptForMissingBrowser) await writeBrowserChoice(kind, executablePath).catch((error) => sink.write({
|
|
364
|
+
level: "warn",
|
|
365
|
+
message: `Could not remember the browser choice: ${error instanceof Error ? error.message : String(error)}`
|
|
366
|
+
}));
|
|
367
|
+
return {
|
|
368
|
+
driver: new LightpandaDriver(),
|
|
369
|
+
engineLabel: "Lightpanda",
|
|
370
|
+
executableResolution: {
|
|
371
|
+
source: "lightpanda_managed",
|
|
372
|
+
executablePath
|
|
373
|
+
},
|
|
374
|
+
preferLocalChrome: false
|
|
375
|
+
};
|
|
376
|
+
}
|
|
377
|
+
config.browser = browser;
|
|
378
|
+
const { PuppeteerDriver, ensureBrowser } = await import("@open-wa/driver-puppeteer");
|
|
379
|
+
const executablePath = await ensureBrowser({
|
|
380
|
+
executablePath: executableResolution.executablePath,
|
|
381
|
+
browser
|
|
382
|
+
}, ctx);
|
|
383
|
+
if (!executableResolution.executablePath) executableResolution = {
|
|
384
|
+
source: "managed_browser",
|
|
385
|
+
executablePath
|
|
386
|
+
};
|
|
387
|
+
if (options.promptForMissingBrowser) await writeBrowserChoice(kind, executablePath).catch((error) => sink.write({
|
|
388
|
+
level: "warn",
|
|
389
|
+
message: `Could not remember the browser choice: ${error instanceof Error ? error.message : String(error)}`
|
|
390
|
+
}));
|
|
391
|
+
return {
|
|
392
|
+
driver: new PuppeteerDriver(),
|
|
393
|
+
engineLabel: "Puppeteer",
|
|
394
|
+
executableResolution,
|
|
395
|
+
preferLocalChrome
|
|
396
|
+
};
|
|
397
|
+
}
|
|
398
|
+
/** Load the Node media runtime only when a call needs a source or sink. */
|
|
399
|
+
function makeDefaultCallMediaHost() {
|
|
400
|
+
return { async prepare(...args) {
|
|
401
|
+
const { makeNodeCallMediaHost } = await import("@open-wa/runtime-node");
|
|
402
|
+
return makeNodeCallMediaHost({ log: (message) => getCliOutputSink().write({
|
|
403
|
+
level: "info",
|
|
404
|
+
message
|
|
405
|
+
}) }).prepare(...args);
|
|
406
|
+
} };
|
|
407
|
+
}
|
|
408
|
+
function toCreateClientOptions(config, driverSelection, options = {}) {
|
|
409
|
+
return {
|
|
410
|
+
sessionId: config.sessionId,
|
|
411
|
+
eventMode: config.eventMode,
|
|
412
|
+
driver: driverSelection.driver,
|
|
413
|
+
deleteSessionDataOnLogout: config.deleteSessionDataOnLogout,
|
|
414
|
+
killClientOnLogout: config.killClientOnLogout,
|
|
415
|
+
sessionDataPath: config.sessionDataPath,
|
|
416
|
+
sessionData: config.sessionData,
|
|
417
|
+
skipSessionSave: config.skipSessionSave,
|
|
418
|
+
sessionDataBucketAuth: config.sessionDataBucketAuth,
|
|
419
|
+
sessionDataEncryptionKey: config.sessionDataEncryptionKey,
|
|
420
|
+
sessionDataEncryptionKeyFile: config.sessionDataEncryptionKeyFile,
|
|
421
|
+
s3Sync: config.s3Sync,
|
|
422
|
+
debug: options.debug ?? (config.logLevel === "debug" || config.logConsole),
|
|
423
|
+
headless: config.headless,
|
|
424
|
+
qrTimeoutMs: typeof config.qrTimeout === "number" ? config.qrTimeout * 1e3 : void 0,
|
|
425
|
+
authTimeoutMs: typeof config.authTimeout === "number" ? config.authTimeout * 1e3 : void 0,
|
|
426
|
+
executablePath: driverSelection.executableResolution.executablePath,
|
|
427
|
+
browserArgs: config.chromiumArgs,
|
|
428
|
+
browser: config.browser,
|
|
429
|
+
allowDangerousBrowserArgs: config.allowDangerousBrowserArgs,
|
|
430
|
+
userDataDir: config.userDataDir,
|
|
431
|
+
ephemeral: config.ephemeral,
|
|
432
|
+
linkCode: config.linkCode,
|
|
433
|
+
qrMax: config.qrMax,
|
|
434
|
+
oorTimeoutMs: config.oorTimeout * 1e3,
|
|
435
|
+
logConsole: config.logConsole,
|
|
436
|
+
logConsoleErrors: config.logConsoleErrors,
|
|
437
|
+
blockCrashLogs: config.blockCrashLogs,
|
|
438
|
+
blockAssets: config.blockAssets,
|
|
439
|
+
safeMode: config.safeMode,
|
|
440
|
+
lightpanda: config.useLightpanda ? {
|
|
441
|
+
experimentalWhatsApp: true,
|
|
442
|
+
...config.lightpanda
|
|
443
|
+
} : void 0,
|
|
444
|
+
licenseKey: config.licenseKey,
|
|
445
|
+
calling: config.calling,
|
|
446
|
+
callMediaHost: makeDefaultCallMediaHost(),
|
|
447
|
+
licenseConfig: config.licenseConfig,
|
|
448
|
+
patchConfig: {
|
|
449
|
+
ghPatch: config.ghPatch,
|
|
450
|
+
cachedPatch: config.cachedPatch
|
|
451
|
+
}
|
|
452
|
+
};
|
|
453
|
+
}
|
|
454
|
+
/** Start WhatsApp, display QR login when needed, and return a ready messaging client. */
|
|
455
|
+
async function create(options = {}) {
|
|
456
|
+
const { createClient: createCoreClient } = await import("@open-wa/core");
|
|
457
|
+
const { Client } = await import("@open-wa/client");
|
|
458
|
+
const { driver, sessionData, sessionDataBucketAuth, s3Sync, calling, sessionDataEncryptionKey, sessionDataEncryptionKeyFile, ...configOverrides } = options;
|
|
459
|
+
const { config, rawConfigs } = await (0, _open_wa_config.resolveConfig)({
|
|
460
|
+
programmaticOverrides: {
|
|
461
|
+
qrTimeout: 0,
|
|
462
|
+
...configOverrides
|
|
463
|
+
},
|
|
464
|
+
skipConfigFile: true,
|
|
465
|
+
skipEnv: true,
|
|
466
|
+
includeRawConfigs: true
|
|
467
|
+
});
|
|
468
|
+
const coreOptions = toCreateClientOptions(config, driver ? {
|
|
469
|
+
driver,
|
|
470
|
+
engineLabel: driver.name === "lightpanda" ? "Lightpanda" : "Puppeteer",
|
|
471
|
+
executableResolution: {
|
|
472
|
+
source: "config",
|
|
473
|
+
executablePath: config.executablePath
|
|
474
|
+
},
|
|
475
|
+
preferLocalChrome: false
|
|
476
|
+
} : await selectRuntimeDriver$1(config, {
|
|
477
|
+
rawConfigs,
|
|
478
|
+
cacheFilePath: (0, node_path.resolve)(process.cwd(), ".open-wa", "chrome-executable-path.json"),
|
|
479
|
+
defaultPreferLocalChrome: false
|
|
480
|
+
}));
|
|
481
|
+
if (calling) coreOptions.calling = calling;
|
|
482
|
+
if (driver) coreOptions.driver = driver;
|
|
483
|
+
coreOptions.sessionData = sessionData;
|
|
484
|
+
coreOptions.sessionDataBucketAuth = sessionDataBucketAuth;
|
|
485
|
+
coreOptions.sessionDataEncryptionKey = sessionDataEncryptionKey;
|
|
486
|
+
coreOptions.sessionDataEncryptionKeyFile = sessionDataEncryptionKeyFile;
|
|
487
|
+
coreOptions.s3Sync = s3Sync;
|
|
488
|
+
const core = await createCoreClient(coreOptions);
|
|
489
|
+
const sink = getCliOutputSink();
|
|
490
|
+
const onQr = (event) => {
|
|
491
|
+
if (config.qrLogSkip || !event.details?.qr) return;
|
|
492
|
+
sink.write({
|
|
493
|
+
level: "info",
|
|
494
|
+
message: "Open WhatsApp on your sending phone: Linked Devices → Link a Device, then scan this QR code."
|
|
495
|
+
});
|
|
496
|
+
sink.qr({
|
|
497
|
+
qr: event.details.qr,
|
|
498
|
+
sessionId: config.sessionId
|
|
499
|
+
});
|
|
500
|
+
};
|
|
501
|
+
const onLinkCode = (event) => {
|
|
502
|
+
if (event.details?.linkCode && !config.qrLogSkip) sink.write({
|
|
503
|
+
level: "info",
|
|
504
|
+
message: `Enter this link code on your sending phone: ${event.details.linkCode}`
|
|
505
|
+
});
|
|
506
|
+
};
|
|
507
|
+
core.events.on("launch.auth.qr.generated", onQr);
|
|
508
|
+
core.events.on("launch.auth.linkCode.generated", onLinkCode);
|
|
509
|
+
let client;
|
|
510
|
+
try {
|
|
511
|
+
client = new Client({
|
|
512
|
+
client: core,
|
|
513
|
+
transport: core.getTransport()
|
|
514
|
+
});
|
|
515
|
+
await client.start();
|
|
516
|
+
if (core.getState() !== "READY" || !core.getReadiness().exposureSafe) throw new Error("WhatsApp startup finished without a messaging-ready session.");
|
|
517
|
+
return client;
|
|
518
|
+
} catch (error) {
|
|
519
|
+
try {
|
|
520
|
+
if (client) await client.stop("startup-failure");
|
|
521
|
+
else await core.stop("startup-failure");
|
|
522
|
+
} catch {}
|
|
523
|
+
throw error;
|
|
524
|
+
} finally {
|
|
525
|
+
core.events.off("launch.auth.qr.generated", onQr);
|
|
526
|
+
core.events.off("launch.auth.linkCode.generated", onLinkCode);
|
|
527
|
+
}
|
|
528
|
+
}
|
|
529
|
+
//#endregion
|
|
80
530
|
//#region src/cli-runtime.ts
|
|
81
531
|
function bridgeRuntimeEvents(openwaClient, publishRuntimeEvent) {
|
|
82
532
|
if (typeof openwaClient.events.onAny === "function" && typeof openwaClient.events.offAny === "function") {
|
|
@@ -84,7 +534,9 @@ function bridgeRuntimeEvents(openwaClient, publishRuntimeEvent) {
|
|
|
84
534
|
return () => openwaClient.events.offAny(publishRuntimeEvent);
|
|
85
535
|
}
|
|
86
536
|
const unsubscribers = [];
|
|
87
|
-
new Set(_open_wa_schema.eventRegistry.getAll().map((def) => def.meta.eventName))
|
|
537
|
+
const bridgedEvents = new Set(_open_wa_schema.eventRegistry.getAll().map((def) => def.meta.eventName));
|
|
538
|
+
bridgedEvents.add("session.refresh.progress");
|
|
539
|
+
bridgedEvents.forEach((eventName) => {
|
|
88
540
|
const handler = (payload) => publishRuntimeEvent(eventName, payload);
|
|
89
541
|
openwaClient.events.on(eventName, handler);
|
|
90
542
|
unsubscribers.push(() => openwaClient.events.off(eventName, handler));
|
|
@@ -271,51 +723,6 @@ const CHROME_CACHE_FILE = (0, node_path.resolve)(process.cwd(), ".open-wa", "chr
|
|
|
271
723
|
function getChromeCacheFilePath() {
|
|
272
724
|
return CHROME_CACHE_FILE;
|
|
273
725
|
}
|
|
274
|
-
function readChromePathCache(cacheFilePath = getChromeCacheFilePath()) {
|
|
275
|
-
if (!(0, node_fs.existsSync)(cacheFilePath)) return;
|
|
276
|
-
try {
|
|
277
|
-
const raw = JSON.parse((0, node_fs.readFileSync)(cacheFilePath, "utf8"));
|
|
278
|
-
if (!raw || typeof raw !== "object") return;
|
|
279
|
-
return {
|
|
280
|
-
executablePath: typeof raw.executablePath === "string" ? raw.executablePath : void 0,
|
|
281
|
-
updatedAt: typeof raw.updatedAt === "string" ? raw.updatedAt : void 0
|
|
282
|
-
};
|
|
283
|
-
} catch {
|
|
284
|
-
return;
|
|
285
|
-
}
|
|
286
|
-
}
|
|
287
|
-
function writeChromePathCache(executablePath, cacheFilePath = getChromeCacheFilePath()) {
|
|
288
|
-
(0, node_fs.mkdirSync)((0, node_path.dirname)(cacheFilePath), { recursive: true });
|
|
289
|
-
(0, node_fs.writeFileSync)(cacheFilePath, JSON.stringify({
|
|
290
|
-
executablePath,
|
|
291
|
-
updatedAt: (/* @__PURE__ */ new Date()).toISOString()
|
|
292
|
-
}, null, 2), "utf8");
|
|
293
|
-
}
|
|
294
|
-
function clearChromePathCache(cacheFilePath = getChromeCacheFilePath()) {
|
|
295
|
-
if ((0, node_fs.existsSync)(cacheFilePath)) (0, node_fs.rmSync)(cacheFilePath, { force: true });
|
|
296
|
-
}
|
|
297
|
-
function isUsableExecutablePath(executablePath) {
|
|
298
|
-
return !!executablePath && (0, node_fs.existsSync)(executablePath);
|
|
299
|
-
}
|
|
300
|
-
function getExplicitUseChromePreference(rawConfigs) {
|
|
301
|
-
const explicitConfigSources = [
|
|
302
|
-
rawConfigs?.file,
|
|
303
|
-
rawConfigs?.env,
|
|
304
|
-
rawConfigs?.cli,
|
|
305
|
-
rawConfigs?.programmatic
|
|
306
|
-
];
|
|
307
|
-
for (let index = explicitConfigSources.length - 1; index >= 0; index -= 1) {
|
|
308
|
-
const source = explicitConfigSources[index];
|
|
309
|
-
if (source?.useChrome !== void 0) return source.useChrome;
|
|
310
|
-
}
|
|
311
|
-
}
|
|
312
|
-
function shouldPreferLocalChrome(config, rawConfigs) {
|
|
313
|
-
if (config.useLightpanda) return false;
|
|
314
|
-
if (config.executablePath) return false;
|
|
315
|
-
const explicitUseChrome = getExplicitUseChromePreference(rawConfigs);
|
|
316
|
-
if (explicitUseChrome !== void 0) return explicitUseChrome;
|
|
317
|
-
return true;
|
|
318
|
-
}
|
|
319
726
|
function getVal(argv, flag) {
|
|
320
727
|
const index = argv.findIndex((arg) => arg === flag);
|
|
321
728
|
return index !== -1 ? argv[index + 1] : void 0;
|
|
@@ -358,13 +765,21 @@ function parseCliArgs(argv = process.argv.slice(2)) {
|
|
|
358
765
|
if (argv.includes("--no-ezqr")) cliOverrides.ezqr = false;
|
|
359
766
|
if (argv.includes("--headful")) cliOverrides.headless = false;
|
|
360
767
|
if (argv.includes("--headless")) cliOverrides.headless = true;
|
|
361
|
-
|
|
362
|
-
|
|
768
|
+
const browserFlags = [
|
|
769
|
+
"--use-chrome",
|
|
770
|
+
"--use-chromium",
|
|
771
|
+
"--use-lightpanda"
|
|
772
|
+
].filter((flag) => argv.includes(flag) || flag === "--use-lightpanda" && argv.includes("--lightpanda"));
|
|
773
|
+
if (browserFlags.length > 1) throw new Error("Choose only one of --use-chrome, --use-chromium or --use-lightpanda.");
|
|
774
|
+
if (browserFlags.length) {
|
|
775
|
+
cliOverrides.useChrome = browserFlags[0] === "--use-chrome";
|
|
776
|
+
cliOverrides.useChromium = browserFlags[0] === "--use-chromium";
|
|
777
|
+
cliOverrides.useLightpanda = browserFlags[0] === "--use-lightpanda";
|
|
778
|
+
}
|
|
363
779
|
if (argv.includes("--log-console")) cliOverrides.logConsole = true;
|
|
364
780
|
if (argv.includes("--aggressive-garbage-collection")) cliOverrides.aggressiveGarbageCollection = true;
|
|
365
781
|
if (argv.includes("--no-dashboard")) cliOverrides.dashboard = false;
|
|
366
782
|
if (argv.includes("--ephemeral")) cliOverrides.ephemeral = true;
|
|
367
|
-
if (argv.includes("--legacy-data-dir-auth")) cliOverrides.legacyDataDirAuth = true;
|
|
368
783
|
if (argv.includes("--sandbox-chats")) cliOverrides.sandboxChats = true;
|
|
369
784
|
const sandboxIsolation = getVal(argv, "--sandbox-isolation");
|
|
370
785
|
if (sandboxIsolation) {
|
|
@@ -413,57 +828,13 @@ function parseCliArgs(argv = process.argv.slice(2)) {
|
|
|
413
828
|
unsupportedWarnings
|
|
414
829
|
};
|
|
415
830
|
}
|
|
416
|
-
async function
|
|
417
|
-
|
|
418
|
-
|
|
419
|
-
|
|
420
|
-
|
|
421
|
-
|
|
422
|
-
|
|
423
|
-
const cachedPath = readChromePathCache(cacheFilePath)?.executablePath;
|
|
424
|
-
if (isUsableExecutablePath(cachedPath)) return {
|
|
425
|
-
executablePath: cachedPath,
|
|
426
|
-
source: "cache"
|
|
427
|
-
};
|
|
428
|
-
if (cachedPath) clearChromePathCache(cacheFilePath);
|
|
429
|
-
const { Launcher } = await import("chrome-launcher");
|
|
430
|
-
const detectedPath = Launcher.getInstallations().find((installationPath) => isUsableExecutablePath(installationPath));
|
|
431
|
-
if (detectedPath) {
|
|
432
|
-
writeChromePathCache(detectedPath, cacheFilePath);
|
|
433
|
-
return {
|
|
434
|
-
executablePath: detectedPath,
|
|
435
|
-
source: "chrome_installation"
|
|
436
|
-
};
|
|
437
|
-
}
|
|
438
|
-
clearChromePathCache(cacheFilePath);
|
|
439
|
-
return {
|
|
440
|
-
source: "driver_default",
|
|
441
|
-
warning: "Chrome resolution warning: no valid local Chrome installation was found. Falling back to Puppeteer/default driver browser resolution."
|
|
442
|
-
};
|
|
443
|
-
}
|
|
444
|
-
function resolveLightpandaExecutablePath(config) {
|
|
445
|
-
const executablePath = config.lightpanda?.executablePath;
|
|
446
|
-
if (executablePath) return {
|
|
447
|
-
executablePath,
|
|
448
|
-
source: "lightpanda_config"
|
|
449
|
-
};
|
|
450
|
-
return { source: "lightpanda_sdk_default" };
|
|
451
|
-
}
|
|
452
|
-
async function selectRuntimeDriver(config, rawConfigs) {
|
|
453
|
-
if (config.useLightpanda) return {
|
|
454
|
-
driver: new _open_wa_driver_lightpanda.LightpandaDriver(),
|
|
455
|
-
engineLabel: "Lightpanda",
|
|
456
|
-
executableResolution: resolveLightpandaExecutablePath(config),
|
|
457
|
-
preferLocalChrome: false
|
|
458
|
-
};
|
|
459
|
-
const preferLocalChrome = shouldPreferLocalChrome(config, rawConfigs);
|
|
460
|
-
const executableResolution = await resolveExecutablePath(config, { preferLocalChrome });
|
|
461
|
-
return {
|
|
462
|
-
driver: new _open_wa_driver_puppeteer.PuppeteerDriver(),
|
|
463
|
-
engineLabel: "Puppeteer",
|
|
464
|
-
executableResolution,
|
|
465
|
-
preferLocalChrome
|
|
466
|
-
};
|
|
831
|
+
async function selectRuntimeDriver(config, rawConfigs, nonInteractive = false) {
|
|
832
|
+
return selectRuntimeDriver$1(config, {
|
|
833
|
+
rawConfigs,
|
|
834
|
+
cacheFilePath: getChromeCacheFilePath(),
|
|
835
|
+
promptForMissingBrowser: true,
|
|
836
|
+
nonInteractive
|
|
837
|
+
});
|
|
467
838
|
}
|
|
468
839
|
function printStartupSummary(config, resolution, preferLocalChrome, engineLabel) {
|
|
469
840
|
const host = config.host.includes("http") ? config.host : `http://${config.host}`;
|
|
@@ -508,9 +879,9 @@ function printStartupSummary(config, resolution, preferLocalChrome, engineLabel)
|
|
|
508
879
|
level: "info",
|
|
509
880
|
message: `Browser executable: explicit Lightpanda override (${resolution.executablePath})`
|
|
510
881
|
});
|
|
511
|
-
else if (resolution.source === "
|
|
882
|
+
else if (resolution.source === "lightpanda_managed") sink.write({
|
|
512
883
|
level: "info",
|
|
513
|
-
message:
|
|
884
|
+
message: `Browser executable: Lightpanda with experimental WhatsApp setup (${resolution.executablePath})`
|
|
514
885
|
});
|
|
515
886
|
else if (resolution.source === "config" && config.executablePath) sink.write({
|
|
516
887
|
level: "info",
|
|
@@ -518,15 +889,15 @@ function printStartupSummary(config, resolution, preferLocalChrome, engineLabel)
|
|
|
518
889
|
});
|
|
519
890
|
else if (resolution.source === "cache") sink.write({
|
|
520
891
|
level: "info",
|
|
521
|
-
message: `Browser executable:
|
|
892
|
+
message: `Browser executable: cached browser (${resolution.executablePath})`
|
|
522
893
|
});
|
|
523
894
|
else if (resolution.source === "chrome_installation") sink.write({
|
|
524
895
|
level: "info",
|
|
525
|
-
message: `Browser executable:
|
|
896
|
+
message: `Browser executable: installed ${config.browser?.kind === "chromium" ? "Chromium" : "Chrome"} (${resolution.executablePath})`
|
|
526
897
|
});
|
|
527
|
-
else if (
|
|
898
|
+
else if (resolution.source === "managed_browser") sink.write({
|
|
528
899
|
level: "info",
|
|
529
|
-
message:
|
|
900
|
+
message: `Browser executable: managed ${config.browser?.kind === "chromium" ? "Chromium" : "Chrome"} (${resolution.executablePath})`
|
|
530
901
|
});
|
|
531
902
|
if (config.webhook) sink.write({
|
|
532
903
|
level: "warn",
|
|
@@ -565,7 +936,7 @@ async function start(parsedArgs = parseCliArgs()) {
|
|
|
565
936
|
level: "warn",
|
|
566
937
|
message: `Compatibility warning: ${warning}`
|
|
567
938
|
}));
|
|
568
|
-
const { driver, engineLabel, executableResolution, preferLocalChrome } = await selectRuntimeDriver(config, rawConfigs);
|
|
939
|
+
const { driver, engineLabel, executableResolution, preferLocalChrome } = await selectRuntimeDriver(config, rawConfigs, parsedArgs.forwardedArgs.includes("--non-interactive"));
|
|
569
940
|
if (executableResolution.warning) sink.write({
|
|
570
941
|
level: "warn",
|
|
571
942
|
message: executableResolution.warning
|
|
@@ -593,14 +964,16 @@ async function start(parsedArgs = parseCliArgs()) {
|
|
|
593
964
|
const executionSandbox = sandboxPolicy ? (0, _open_wa_runtime_node.makeNodeExecutionSandbox)({ workspacePath: process.cwd() }) : void 0;
|
|
594
965
|
const openwaClient = await (0, _open_wa_core.createClient)({
|
|
595
966
|
sessionId: config.sessionId,
|
|
967
|
+
eventMode: config.eventMode,
|
|
596
968
|
driver,
|
|
597
969
|
deleteSessionDataOnLogout: config.deleteSessionDataOnLogout,
|
|
598
970
|
killClientOnLogout: config.killClientOnLogout,
|
|
599
|
-
legacyDataDirAuth: config.legacyDataDirAuth,
|
|
600
971
|
sessionDataPath: config.sessionDataPath,
|
|
601
972
|
sessionData: config.sessionData,
|
|
602
973
|
skipSessionSave: config.skipSessionSave,
|
|
603
974
|
sessionDataBucketAuth: config.sessionDataBucketAuth,
|
|
975
|
+
sessionDataEncryptionKey: config.sessionDataEncryptionKey,
|
|
976
|
+
sessionDataEncryptionKeyFile: config.sessionDataEncryptionKeyFile,
|
|
604
977
|
s3Sync: config.s3Sync,
|
|
605
978
|
debug: config.logLevel === "debug" || verbose || config.logConsole,
|
|
606
979
|
headless: config.headless,
|
|
@@ -618,7 +991,14 @@ async function start(parsedArgs = parseCliArgs()) {
|
|
|
618
991
|
blockCrashLogs: config.blockCrashLogs,
|
|
619
992
|
blockAssets: config.blockAssets,
|
|
620
993
|
safeMode: config.safeMode,
|
|
994
|
+
lightpanda: config.useLightpanda ? {
|
|
995
|
+
experimentalWhatsApp: true,
|
|
996
|
+
...config.lightpanda
|
|
997
|
+
} : void 0,
|
|
621
998
|
licenseKey: config.licenseKey,
|
|
999
|
+
licenseConfig: config.licenseConfig,
|
|
1000
|
+
calling: config.calling,
|
|
1001
|
+
callMediaHost: makeDefaultCallMediaHost(),
|
|
622
1002
|
sandboxPolicy,
|
|
623
1003
|
executionSandbox,
|
|
624
1004
|
memoryObservation: (observability, getBrowserProcessId) => (0, _open_wa_runtime_node.observeBrowserProcessMemory)(observability, getBrowserProcessId, { attributes: { session: config.sessionId } })
|
|
@@ -628,6 +1008,8 @@ async function start(parsedArgs = parseCliArgs()) {
|
|
|
628
1008
|
state: openwaClient.getState()
|
|
629
1009
|
}));
|
|
630
1010
|
const detachLaunchNarration = attachLaunchNarration(openwaClient, sink, config.sessionId);
|
|
1011
|
+
openwaClient.events.on("launch.auth.qr.expired", () => server.setQR(null));
|
|
1012
|
+
openwaClient.events.on("launch.auth.qr.scanned", () => server.setQR(null));
|
|
631
1013
|
openwaClient.events.on("launch.auth.qr.generated", (event) => {
|
|
632
1014
|
const qr = event.details?.qr;
|
|
633
1015
|
if (!qr) return;
|
|
@@ -709,7 +1091,7 @@ async function start(parsedArgs = parseCliArgs()) {
|
|
|
709
1091
|
});
|
|
710
1092
|
sink.write({
|
|
711
1093
|
level: "warn",
|
|
712
|
-
message: "
|
|
1094
|
+
message: "The API server is still running for inspection; the client failed to start."
|
|
713
1095
|
});
|
|
714
1096
|
sink.write({
|
|
715
1097
|
level: "warn",
|
|
@@ -745,7 +1127,7 @@ async function start(parsedArgs = parseCliArgs()) {
|
|
|
745
1127
|
}
|
|
746
1128
|
async function main(argv = process.argv.slice(2)) {
|
|
747
1129
|
if (argv[0] === "init") {
|
|
748
|
-
const { initProject } = await Promise.resolve().then(() => require("./init-
|
|
1130
|
+
const { initProject } = await Promise.resolve().then(() => require("./init-CUhC5Wkq.cjs"));
|
|
749
1131
|
await initProject(argv.slice(1));
|
|
750
1132
|
return;
|
|
751
1133
|
}
|
|
@@ -815,6 +1197,12 @@ Object.defineProperty(exports, "WAServer", {
|
|
|
815
1197
|
return WAServer;
|
|
816
1198
|
}
|
|
817
1199
|
});
|
|
1200
|
+
Object.defineProperty(exports, "create", {
|
|
1201
|
+
enumerable: true,
|
|
1202
|
+
get: function() {
|
|
1203
|
+
return create;
|
|
1204
|
+
}
|
|
1205
|
+
});
|
|
818
1206
|
Object.defineProperty(exports, "createConsoleOutputSink", {
|
|
819
1207
|
enumerable: true,
|
|
820
1208
|
get: function() {
|
|
@@ -858,4 +1246,4 @@ Object.defineProperty(exports, "start", {
|
|
|
858
1246
|
}
|
|
859
1247
|
});
|
|
860
1248
|
|
|
861
|
-
//# sourceMappingURL=cli-runtime-
|
|
1249
|
+
//# sourceMappingURL=cli-runtime-BRj_LUIT.cjs.map
|