sweetlink 0.1.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/CHANGELOG.md +12 -0
- package/LICENSE +21 -0
- package/README.md +237 -0
- package/dist/daemon/src/codename.d.ts +8 -0
- package/dist/daemon/src/codename.d.ts.map +1 -0
- package/dist/daemon/src/codename.js +42 -0
- package/dist/daemon/src/codename.js.map +1 -0
- package/dist/daemon/src/index.d.ts +3 -0
- package/dist/daemon/src/index.d.ts.map +1 -0
- package/dist/daemon/src/index.js +675 -0
- package/dist/daemon/src/index.js.map +1 -0
- package/dist/shared/src/env.d.ts +24 -0
- package/dist/shared/src/env.d.ts.map +1 -0
- package/dist/shared/src/env.js +39 -0
- package/dist/shared/src/env.js.map +1 -0
- package/dist/shared/src/index.d.ts +211 -0
- package/dist/shared/src/index.d.ts.map +1 -0
- package/dist/shared/src/index.js +73 -0
- package/dist/shared/src/index.js.map +1 -0
- package/dist/shared/src/node.d.ts +12 -0
- package/dist/shared/src/node.d.ts.map +1 -0
- package/dist/shared/src/node.js +67 -0
- package/dist/shared/src/node.js.map +1 -0
- package/dist/src/codex.d.ts +11 -0
- package/dist/src/codex.d.ts.map +1 -0
- package/dist/src/codex.js +67 -0
- package/dist/src/codex.js.map +1 -0
- package/dist/src/commands/click.d.ts +3 -0
- package/dist/src/commands/click.d.ts.map +1 -0
- package/dist/src/commands/click.js +93 -0
- package/dist/src/commands/click.js.map +1 -0
- package/dist/src/commands/run-js.d.ts +4 -0
- package/dist/src/commands/run-js.d.ts.map +1 -0
- package/dist/src/commands/run-js.js +28 -0
- package/dist/src/commands/run-js.js.map +1 -0
- package/dist/src/commands/trust-ca.d.ts +3 -0
- package/dist/src/commands/trust-ca.d.ts.map +1 -0
- package/dist/src/commands/trust-ca.js +43 -0
- package/dist/src/commands/trust-ca.js.map +1 -0
- package/dist/src/core/config-file.d.ts +41 -0
- package/dist/src/core/config-file.d.ts.map +1 -0
- package/dist/src/core/config-file.js +284 -0
- package/dist/src/core/config-file.js.map +1 -0
- package/dist/src/core/config.d.ts +23 -0
- package/dist/src/core/config.d.ts.map +1 -0
- package/dist/src/core/config.js +132 -0
- package/dist/src/core/config.js.map +1 -0
- package/dist/src/core/env.d.ts +11 -0
- package/dist/src/core/env.d.ts.map +1 -0
- package/dist/src/core/env.js +30 -0
- package/dist/src/core/env.js.map +1 -0
- package/dist/src/devtools-registry.d.ts +3 -0
- package/dist/src/devtools-registry.d.ts.map +1 -0
- package/dist/src/devtools-registry.js +294 -0
- package/dist/src/devtools-registry.js.map +1 -0
- package/dist/src/env.d.ts +16 -0
- package/dist/src/env.d.ts.map +1 -0
- package/dist/src/env.js +17 -0
- package/dist/src/env.js.map +1 -0
- package/dist/src/http.d.ts +2 -0
- package/dist/src/http.d.ts.map +1 -0
- package/dist/src/http.js +53 -0
- package/dist/src/http.js.map +1 -0
- package/dist/src/index.d.ts +19 -0
- package/dist/src/index.d.ts.map +1 -0
- package/dist/src/index.js +1941 -0
- package/dist/src/index.js.map +1 -0
- package/dist/src/runtime/browser/client.d.ts +10 -0
- package/dist/src/runtime/browser/client.d.ts.map +1 -0
- package/dist/src/runtime/browser/client.js +497 -0
- package/dist/src/runtime/browser/client.js.map +1 -0
- package/dist/src/runtime/browser/commands/index.d.ts +10 -0
- package/dist/src/runtime/browser/commands/index.d.ts.map +1 -0
- package/dist/src/runtime/browser/commands/index.js +219 -0
- package/dist/src/runtime/browser/commands/index.js.map +1 -0
- package/dist/src/runtime/browser/dom-to-image-loader.d.ts +6 -0
- package/dist/src/runtime/browser/dom-to-image-loader.d.ts.map +1 -0
- package/dist/src/runtime/browser/dom-to-image-loader.js +50 -0
- package/dist/src/runtime/browser/dom-to-image-loader.js.map +1 -0
- package/dist/src/runtime/browser/index.d.ts +4 -0
- package/dist/src/runtime/browser/index.d.ts.map +1 -0
- package/dist/src/runtime/browser/index.js +4 -0
- package/dist/src/runtime/browser/index.js.map +1 -0
- package/dist/src/runtime/browser/module-loader.d.ts +6 -0
- package/dist/src/runtime/browser/module-loader.d.ts.map +1 -0
- package/dist/src/runtime/browser/module-loader.js +26 -0
- package/dist/src/runtime/browser/module-loader.js.map +1 -0
- package/dist/src/runtime/browser/screenshot/hooks.d.ts +71 -0
- package/dist/src/runtime/browser/screenshot/hooks.d.ts.map +1 -0
- package/dist/src/runtime/browser/screenshot/hooks.js +219 -0
- package/dist/src/runtime/browser/screenshot/hooks.js.map +1 -0
- package/dist/src/runtime/browser/screenshot/index.d.ts +9 -0
- package/dist/src/runtime/browser/screenshot/index.d.ts.map +1 -0
- package/dist/src/runtime/browser/screenshot/index.js +90 -0
- package/dist/src/runtime/browser/screenshot/index.js.map +1 -0
- package/dist/src/runtime/browser/screenshot/renderers/dom-to-image.d.ts +13 -0
- package/dist/src/runtime/browser/screenshot/renderers/dom-to-image.d.ts.map +1 -0
- package/dist/src/runtime/browser/screenshot/renderers/dom-to-image.js +51 -0
- package/dist/src/runtime/browser/screenshot/renderers/dom-to-image.js.map +1 -0
- package/dist/src/runtime/browser/screenshot/renderers/html2canvas.d.ts +12 -0
- package/dist/src/runtime/browser/screenshot/renderers/html2canvas.d.ts.map +1 -0
- package/dist/src/runtime/browser/screenshot/renderers/html2canvas.js +136 -0
- package/dist/src/runtime/browser/screenshot/renderers/html2canvas.js.map +1 -0
- package/dist/src/runtime/browser/screenshot/targets.d.ts +6 -0
- package/dist/src/runtime/browser/screenshot/targets.d.ts.map +1 -0
- package/dist/src/runtime/browser/screenshot/targets.js +53 -0
- package/dist/src/runtime/browser/screenshot/targets.js.map +1 -0
- package/dist/src/runtime/browser/screenshot/utils.d.ts +9 -0
- package/dist/src/runtime/browser/screenshot/utils.d.ts.map +1 -0
- package/dist/src/runtime/browser/screenshot/utils.js +471 -0
- package/dist/src/runtime/browser/screenshot/utils.js.map +1 -0
- package/dist/src/runtime/browser/selector-discovery.d.ts +9 -0
- package/dist/src/runtime/browser/selector-discovery.d.ts.map +1 -0
- package/dist/src/runtime/browser/selector-discovery.js +218 -0
- package/dist/src/runtime/browser/selector-discovery.js.map +1 -0
- package/dist/src/runtime/browser/storage/session-storage.d.ts +13 -0
- package/dist/src/runtime/browser/storage/session-storage.d.ts.map +1 -0
- package/dist/src/runtime/browser/storage/session-storage.js +119 -0
- package/dist/src/runtime/browser/storage/session-storage.js.map +1 -0
- package/dist/src/runtime/browser/types.d.ts +96 -0
- package/dist/src/runtime/browser/types.d.ts.map +1 -0
- package/dist/src/runtime/browser/types.js +6 -0
- package/dist/src/runtime/browser/types.js.map +1 -0
- package/dist/src/runtime/browser/utils/console.d.ts +5 -0
- package/dist/src/runtime/browser/utils/console.d.ts.map +1 -0
- package/dist/src/runtime/browser/utils/console.js +54 -0
- package/dist/src/runtime/browser/utils/console.js.map +1 -0
- package/dist/src/runtime/browser/utils/environment.d.ts +3 -0
- package/dist/src/runtime/browser/utils/environment.d.ts.map +1 -0
- package/dist/src/runtime/browser/utils/environment.js +13 -0
- package/dist/src/runtime/browser/utils/environment.js.map +1 -0
- package/dist/src/runtime/browser/utils/errors.d.ts +3 -0
- package/dist/src/runtime/browser/utils/errors.d.ts.map +1 -0
- package/dist/src/runtime/browser/utils/errors.js +42 -0
- package/dist/src/runtime/browser/utils/errors.js.map +1 -0
- package/dist/src/runtime/browser/utils/number.d.ts +2 -0
- package/dist/src/runtime/browser/utils/number.d.ts.map +1 -0
- package/dist/src/runtime/browser/utils/number.js +2 -0
- package/dist/src/runtime/browser/utils/number.js.map +1 -0
- package/dist/src/runtime/browser/utils/object.d.ts +3 -0
- package/dist/src/runtime/browser/utils/object.d.ts.map +1 -0
- package/dist/src/runtime/browser/utils/object.js +9 -0
- package/dist/src/runtime/browser/utils/object.js.map +1 -0
- package/dist/src/runtime/browser/utils/sanitize.d.ts +2 -0
- package/dist/src/runtime/browser/utils/sanitize.d.ts.map +1 -0
- package/dist/src/runtime/browser/utils/sanitize.js +28 -0
- package/dist/src/runtime/browser/utils/sanitize.js.map +1 -0
- package/dist/src/runtime/browser/utils/time.d.ts +2 -0
- package/dist/src/runtime/browser/utils/time.d.ts.map +1 -0
- package/dist/src/runtime/browser/utils/time.js +7 -0
- package/dist/src/runtime/browser/utils/time.js.map +1 -0
- package/dist/src/runtime/chrome/constants.d.ts +5 -0
- package/dist/src/runtime/chrome/constants.d.ts.map +1 -0
- package/dist/src/runtime/chrome/constants.js +5 -0
- package/dist/src/runtime/chrome/constants.js.map +1 -0
- package/dist/src/runtime/chrome/cookies.d.ts +20 -0
- package/dist/src/runtime/chrome/cookies.d.ts.map +1 -0
- package/dist/src/runtime/chrome/cookies.js +139 -0
- package/dist/src/runtime/chrome/cookies.js.map +1 -0
- package/dist/src/runtime/chrome/diagnostics.d.ts +6 -0
- package/dist/src/runtime/chrome/diagnostics.d.ts.map +1 -0
- package/dist/src/runtime/chrome/diagnostics.js +49 -0
- package/dist/src/runtime/chrome/diagnostics.js.map +1 -0
- package/dist/src/runtime/chrome/focus.d.ts +2 -0
- package/dist/src/runtime/chrome/focus.d.ts.map +1 -0
- package/dist/src/runtime/chrome/focus.js +41 -0
- package/dist/src/runtime/chrome/focus.js.map +1 -0
- package/dist/src/runtime/chrome/launch.d.ts +23 -0
- package/dist/src/runtime/chrome/launch.d.ts.map +1 -0
- package/dist/src/runtime/chrome/launch.js +102 -0
- package/dist/src/runtime/chrome/launch.js.map +1 -0
- package/dist/src/runtime/chrome/puppeteer.d.ts +7 -0
- package/dist/src/runtime/chrome/puppeteer.d.ts.map +1 -0
- package/dist/src/runtime/chrome/puppeteer.js +87 -0
- package/dist/src/runtime/chrome/puppeteer.js.map +1 -0
- package/dist/src/runtime/chrome/reuse/constants.d.ts +4 -0
- package/dist/src/runtime/chrome/reuse/constants.d.ts.map +1 -0
- package/dist/src/runtime/chrome/reuse/constants.js +4 -0
- package/dist/src/runtime/chrome/reuse/constants.js.map +1 -0
- package/dist/src/runtime/chrome/reuse.d.ts +13 -0
- package/dist/src/runtime/chrome/reuse.d.ts.map +1 -0
- package/dist/src/runtime/chrome/reuse.js +183 -0
- package/dist/src/runtime/chrome/reuse.js.map +1 -0
- package/dist/src/runtime/chrome/session.d.ts +13 -0
- package/dist/src/runtime/chrome/session.d.ts.map +1 -0
- package/dist/src/runtime/chrome/session.js +47 -0
- package/dist/src/runtime/chrome/session.js.map +1 -0
- package/dist/src/runtime/chrome.d.ts +9 -0
- package/dist/src/runtime/chrome.d.ts.map +1 -0
- package/dist/src/runtime/chrome.js +10 -0
- package/dist/src/runtime/chrome.js.map +1 -0
- package/dist/src/runtime/cookies.d.ts +37 -0
- package/dist/src/runtime/cookies.d.ts.map +1 -0
- package/dist/src/runtime/cookies.js +592 -0
- package/dist/src/runtime/cookies.js.map +1 -0
- package/dist/src/runtime/devstack.d.ts +14 -0
- package/dist/src/runtime/devstack.d.ts.map +1 -0
- package/dist/src/runtime/devstack.js +174 -0
- package/dist/src/runtime/devstack.js.map +1 -0
- package/dist/src/runtime/devtools/background.d.ts +5 -0
- package/dist/src/runtime/devtools/background.d.ts.map +1 -0
- package/dist/src/runtime/devtools/background.js +109 -0
- package/dist/src/runtime/devtools/background.js.map +1 -0
- package/dist/src/runtime/devtools/cdp.d.ts +16 -0
- package/dist/src/runtime/devtools/cdp.d.ts.map +1 -0
- package/dist/src/runtime/devtools/cdp.js +392 -0
- package/dist/src/runtime/devtools/cdp.js.map +1 -0
- package/dist/src/runtime/devtools/config.d.ts +12 -0
- package/dist/src/runtime/devtools/config.d.ts.map +1 -0
- package/dist/src/runtime/devtools/config.js +78 -0
- package/dist/src/runtime/devtools/config.js.map +1 -0
- package/dist/src/runtime/devtools/constants.d.ts +10 -0
- package/dist/src/runtime/devtools/constants.d.ts.map +1 -0
- package/dist/src/runtime/devtools/constants.js +18 -0
- package/dist/src/runtime/devtools/constants.js.map +1 -0
- package/dist/src/runtime/devtools/diagnostics.d.ts +8 -0
- package/dist/src/runtime/devtools/diagnostics.d.ts.map +1 -0
- package/dist/src/runtime/devtools/diagnostics.js +189 -0
- package/dist/src/runtime/devtools/diagnostics.js.map +1 -0
- package/dist/src/runtime/devtools/oauth.d.ts +9 -0
- package/dist/src/runtime/devtools/oauth.d.ts.map +1 -0
- package/dist/src/runtime/devtools/oauth.js +130 -0
- package/dist/src/runtime/devtools/oauth.js.map +1 -0
- package/dist/src/runtime/devtools/types.d.ts +108 -0
- package/dist/src/runtime/devtools/types.d.ts.map +1 -0
- package/dist/src/runtime/devtools/types.js +2 -0
- package/dist/src/runtime/devtools/types.js.map +1 -0
- package/dist/src/runtime/devtools.d.ts +8 -0
- package/dist/src/runtime/devtools.d.ts.map +1 -0
- package/dist/src/runtime/devtools.js +9 -0
- package/dist/src/runtime/devtools.js.map +1 -0
- package/dist/src/runtime/next-devtools.d.ts +2 -0
- package/dist/src/runtime/next-devtools.d.ts.map +1 -0
- package/dist/src/runtime/next-devtools.js +72 -0
- package/dist/src/runtime/next-devtools.js.map +1 -0
- package/dist/src/runtime/screenshot.d.ts +78 -0
- package/dist/src/runtime/screenshot.d.ts.map +1 -0
- package/dist/src/runtime/screenshot.js +232 -0
- package/dist/src/runtime/screenshot.js.map +1 -0
- package/dist/src/runtime/scripts.d.ts +16 -0
- package/dist/src/runtime/scripts.d.ts.map +1 -0
- package/dist/src/runtime/scripts.js +110 -0
- package/dist/src/runtime/scripts.js.map +1 -0
- package/dist/src/runtime/session.d.ts +64 -0
- package/dist/src/runtime/session.d.ts.map +1 -0
- package/dist/src/runtime/session.js +205 -0
- package/dist/src/runtime/session.js.map +1 -0
- package/dist/src/runtime/smoke.d.ts +36 -0
- package/dist/src/runtime/smoke.d.ts.map +1 -0
- package/dist/src/runtime/smoke.js +417 -0
- package/dist/src/runtime/smoke.js.map +1 -0
- package/dist/src/runtime/url.d.ts +10 -0
- package/dist/src/runtime/url.d.ts.map +1 -0
- package/dist/src/runtime/url.js +147 -0
- package/dist/src/runtime/url.js.map +1 -0
- package/dist/src/screenshot-hooks.d.ts +13 -0
- package/dist/src/screenshot-hooks.d.ts.map +1 -0
- package/dist/src/screenshot-hooks.js +56 -0
- package/dist/src/screenshot-hooks.js.map +1 -0
- package/dist/src/shared/env.d.ts +23 -0
- package/dist/src/shared/env.d.ts.map +1 -0
- package/dist/src/shared/env.js +38 -0
- package/dist/src/shared/env.js.map +1 -0
- package/dist/src/shared/index.d.ts +211 -0
- package/dist/src/shared/index.d.ts.map +1 -0
- package/dist/src/shared/index.js +73 -0
- package/dist/src/shared/index.js.map +1 -0
- package/dist/src/shared/node.d.ts +12 -0
- package/dist/src/shared/node.d.ts.map +1 -0
- package/dist/src/shared/node.js +67 -0
- package/dist/src/shared/node.js.map +1 -0
- package/dist/src/token.d.ts +4 -0
- package/dist/src/token.d.ts.map +1 -0
- package/dist/src/token.js +58 -0
- package/dist/src/token.js.map +1 -0
- package/dist/src/types.d.ts +17 -0
- package/dist/src/types.d.ts.map +1 -0
- package/dist/src/types.js +2 -0
- package/dist/src/types.js.map +1 -0
- package/dist/src/util/app-label.d.ts +5 -0
- package/dist/src/util/app-label.d.ts.map +1 -0
- package/dist/src/util/app-label.js +21 -0
- package/dist/src/util/app-label.js.map +1 -0
- package/dist/src/util/errors.d.ts +9 -0
- package/dist/src/util/errors.d.ts.map +1 -0
- package/dist/src/util/errors.js +56 -0
- package/dist/src/util/errors.js.map +1 -0
- package/dist/src/util/path.d.ts +3 -0
- package/dist/src/util/path.d.ts.map +1 -0
- package/dist/src/util/path.js +6 -0
- package/dist/src/util/path.js.map +1 -0
- package/dist/src/util/regex.d.ts +4 -0
- package/dist/src/util/regex.d.ts.map +1 -0
- package/dist/src/util/regex.js +5 -0
- package/dist/src/util/regex.js.map +1 -0
- package/dist/src/util/time.d.ts +3 -0
- package/dist/src/util/time.d.ts.map +1 -0
- package/dist/src/util/time.js +7 -0
- package/dist/src/util/time.js.map +1 -0
- package/package.json +86 -0
|
@@ -0,0 +1,205 @@
|
|
|
1
|
+
import { mkdir, readFile, writeFile } from 'node:fs/promises';
|
|
2
|
+
import os from 'node:os';
|
|
3
|
+
import path from 'node:path';
|
|
4
|
+
import { createSweetLinkCommandId } from '../../shared/src/index.js';
|
|
5
|
+
import { fetchJson } from '../http.js';
|
|
6
|
+
import { fetchCliToken } from '../token.js';
|
|
7
|
+
const VALID_SELECTOR_HOOKS = new Set(['data-target', 'id', 'aria', 'role', 'structure', 'testid']);
|
|
8
|
+
const SESSION_ID_PATTERN = /^[0-9a-f]{8}-[0-9a-f]{4}-[0-9a-f]{4}-[0-9a-f]{4}-[0-9a-f]{12}$/i;
|
|
9
|
+
const CODENAME_CACHE_PATH = path.join(os.homedir(), '.sweetlink', 'session-codenames.json');
|
|
10
|
+
async function loadCodenameCache() {
|
|
11
|
+
try {
|
|
12
|
+
const raw = await readFile(CODENAME_CACHE_PATH, 'utf8');
|
|
13
|
+
const parsed = JSON.parse(raw);
|
|
14
|
+
if (parsed && typeof parsed === 'object') {
|
|
15
|
+
return parsed;
|
|
16
|
+
}
|
|
17
|
+
}
|
|
18
|
+
catch {
|
|
19
|
+
/* ignore cache read issues */
|
|
20
|
+
}
|
|
21
|
+
return {};
|
|
22
|
+
}
|
|
23
|
+
async function saveCodenameCache(cache) {
|
|
24
|
+
try {
|
|
25
|
+
const directory = path.dirname(CODENAME_CACHE_PATH);
|
|
26
|
+
await mkdir(directory, { recursive: true });
|
|
27
|
+
await writeFile(CODENAME_CACHE_PATH, JSON.stringify(cache, null, 2), 'utf8');
|
|
28
|
+
}
|
|
29
|
+
catch {
|
|
30
|
+
/* ignore cache write issues */
|
|
31
|
+
}
|
|
32
|
+
}
|
|
33
|
+
async function stabilizeSessionCodenames(sessions) {
|
|
34
|
+
if (sessions.length === 0) {
|
|
35
|
+
return sessions;
|
|
36
|
+
}
|
|
37
|
+
const cache = await loadCodenameCache();
|
|
38
|
+
let cacheMutations = 0;
|
|
39
|
+
const stabilized = [];
|
|
40
|
+
for (const session of sessions) {
|
|
41
|
+
const cachedCodename = cache[session.sessionId];
|
|
42
|
+
if (cachedCodename) {
|
|
43
|
+
if (session.codename === cachedCodename) {
|
|
44
|
+
stabilized.push(session);
|
|
45
|
+
}
|
|
46
|
+
else {
|
|
47
|
+
cacheMutations += 1;
|
|
48
|
+
stabilized.push({ ...session, codename: cachedCodename });
|
|
49
|
+
}
|
|
50
|
+
continue;
|
|
51
|
+
}
|
|
52
|
+
if (session.codename && session.codename.trim().length > 0) {
|
|
53
|
+
cache[session.sessionId] = session.codename;
|
|
54
|
+
cacheMutations += 1;
|
|
55
|
+
}
|
|
56
|
+
stabilized.push(session);
|
|
57
|
+
}
|
|
58
|
+
if (cacheMutations > 0) {
|
|
59
|
+
await saveCodenameCache(cache);
|
|
60
|
+
}
|
|
61
|
+
return stabilized;
|
|
62
|
+
}
|
|
63
|
+
export async function fetchSessionSummaries(config, existingToken) {
|
|
64
|
+
const token = existingToken ?? (await fetchCliToken(config));
|
|
65
|
+
const response = await fetchJson(`${config.daemonBaseUrl}/sessions`, {
|
|
66
|
+
headers: { Authorization: `Bearer ${token}` },
|
|
67
|
+
});
|
|
68
|
+
return await stabilizeSessionCodenames(response.sessions);
|
|
69
|
+
}
|
|
70
|
+
/** Formats a session id + codename pair for CLI display. */
|
|
71
|
+
export function formatSessionHeadline(session) {
|
|
72
|
+
return session.codename ? `${session.codename} (${session.sessionId})` : session.sessionId;
|
|
73
|
+
}
|
|
74
|
+
/** Resolves a human codename or short id to an active SweetLink session. */
|
|
75
|
+
export async function resolveSessionIdFromHint(sessionHint, config) {
|
|
76
|
+
const input = sessionHint.trim();
|
|
77
|
+
if (input.length === 0) {
|
|
78
|
+
throw new Error('A SweetLink session identifier is required.');
|
|
79
|
+
}
|
|
80
|
+
if (SESSION_ID_PATTERN.test(input)) {
|
|
81
|
+
return input;
|
|
82
|
+
}
|
|
83
|
+
const sessions = await fetchSessionSummaries(config);
|
|
84
|
+
const normalized = input.toLowerCase();
|
|
85
|
+
const matches = sessions.filter((session) => {
|
|
86
|
+
if (session.sessionId === input || session.sessionId.toLowerCase() === normalized) {
|
|
87
|
+
return true;
|
|
88
|
+
}
|
|
89
|
+
if (session.codename && session.codename.toLowerCase() === normalized) {
|
|
90
|
+
return true;
|
|
91
|
+
}
|
|
92
|
+
return false;
|
|
93
|
+
});
|
|
94
|
+
if (matches.length === 0) {
|
|
95
|
+
throw new Error(`No active SweetLink session matches "${sessionHint}". Run \`pnpm sweetlink sessions\` to list active sessions.`);
|
|
96
|
+
}
|
|
97
|
+
if (matches.length > 1) {
|
|
98
|
+
const headlines = matches.map((session) => formatSessionHeadline(session)).join(', ');
|
|
99
|
+
throw new Error(`Multiple SweetLink sessions match "${sessionHint}". Refine using one of: ${headlines}.`);
|
|
100
|
+
}
|
|
101
|
+
const match = matches[0];
|
|
102
|
+
if (!match) {
|
|
103
|
+
throw new Error('Unexpected missing SweetLink session match.');
|
|
104
|
+
}
|
|
105
|
+
return match.sessionId;
|
|
106
|
+
}
|
|
107
|
+
/** Sends a SweetLink runScript command and returns the raw command result. */
|
|
108
|
+
export async function executeRunScriptCommand(config, options) {
|
|
109
|
+
const token = await fetchCliToken(config);
|
|
110
|
+
const payload = {
|
|
111
|
+
type: 'runScript',
|
|
112
|
+
id: createSweetLinkCommandId(),
|
|
113
|
+
code: options.code,
|
|
114
|
+
timeoutMs: options.timeoutMs,
|
|
115
|
+
captureConsole: Boolean(options.captureConsole),
|
|
116
|
+
};
|
|
117
|
+
const result = await fetchJson(`${config.daemonBaseUrl}/sessions/${encodeURIComponent(options.sessionId)}/command`, {
|
|
118
|
+
method: 'POST',
|
|
119
|
+
headers: {
|
|
120
|
+
Authorization: `Bearer ${token}`,
|
|
121
|
+
'Content-Type': 'application/json',
|
|
122
|
+
},
|
|
123
|
+
body: JSON.stringify(payload),
|
|
124
|
+
});
|
|
125
|
+
return result.result;
|
|
126
|
+
}
|
|
127
|
+
/** Returns recent console events captured for a SweetLink session. */
|
|
128
|
+
export async function fetchConsoleEvents(config, sessionId) {
|
|
129
|
+
const token = await fetchCliToken(config);
|
|
130
|
+
const response = await fetchJson(`${config.daemonBaseUrl}/sessions/${encodeURIComponent(sessionId)}/console`, {
|
|
131
|
+
headers: { Authorization: `Bearer ${token}` },
|
|
132
|
+
});
|
|
133
|
+
return Array.isArray(response.events) ? response.events : [];
|
|
134
|
+
}
|
|
135
|
+
export async function getSessionSummaryById(config, token, sessionId) {
|
|
136
|
+
const sessions = await fetchSessionSummaries(config, token);
|
|
137
|
+
return sessions.find((session) => session.sessionId === sessionId);
|
|
138
|
+
}
|
|
139
|
+
/** Returns the resolved prompt string for CLI commands. */
|
|
140
|
+
export function resolvePromptOption(options) {
|
|
141
|
+
const trimmedPrompt = options.prompt?.trim();
|
|
142
|
+
if (trimmedPrompt) {
|
|
143
|
+
return trimmedPrompt;
|
|
144
|
+
}
|
|
145
|
+
const trimmedQuestion = options.question?.trim();
|
|
146
|
+
if (trimmedQuestion) {
|
|
147
|
+
return trimmedQuestion;
|
|
148
|
+
}
|
|
149
|
+
return;
|
|
150
|
+
}
|
|
151
|
+
/** Builds a DOM click script scoped to the provided selector. */
|
|
152
|
+
export function buildClickScript({ selector, scrollIntoView, bubbles }) {
|
|
153
|
+
const safeSelector = JSON.stringify(selector);
|
|
154
|
+
const notFoundMessage = `SweetLink click: selector ${selector} not found`;
|
|
155
|
+
const lines = [
|
|
156
|
+
'(() => {',
|
|
157
|
+
` const target = document.querySelector(${safeSelector});`,
|
|
158
|
+
' if (!target) {',
|
|
159
|
+
` throw new Error(${JSON.stringify(notFoundMessage)});`,
|
|
160
|
+
' }',
|
|
161
|
+
];
|
|
162
|
+
if (scrollIntoView) {
|
|
163
|
+
lines.push(' if (typeof target.scrollIntoView === "function") {', ' try {', ' target.scrollIntoView({ block: "center", inline: "center", behavior: "smooth" });', ' } catch {', ' target.scrollIntoView();', ' }', ' }');
|
|
164
|
+
}
|
|
165
|
+
lines.push(' const event = new MouseEvent("click", {', ' view: window,', ` bubbles: ${bubbles},`, ' cancelable: true,', ' composed: true', ' });', ' target.dispatchEvent(event);', ' if (typeof target.click === "function") {', ' target.click();', ' }', ' return "clicked";', '})()');
|
|
166
|
+
return lines.join('\n');
|
|
167
|
+
}
|
|
168
|
+
/** Shared guard ensuring candidates from selector discovery are valid. */
|
|
169
|
+
export const isSweetLinkSelectorCandidate = (value) => {
|
|
170
|
+
if (typeof value !== 'object' || value === null) {
|
|
171
|
+
return false;
|
|
172
|
+
}
|
|
173
|
+
const candidate = value;
|
|
174
|
+
if (typeof candidate.selector !== 'string' ||
|
|
175
|
+
typeof candidate.tagName !== 'string' ||
|
|
176
|
+
typeof candidate.hook !== 'string' ||
|
|
177
|
+
!VALID_SELECTOR_HOOKS.has(candidate.hook) ||
|
|
178
|
+
typeof candidate.textSnippet !== 'string' ||
|
|
179
|
+
typeof candidate.score !== 'number' ||
|
|
180
|
+
typeof candidate.visible !== 'boolean' ||
|
|
181
|
+
typeof candidate.path !== 'string') {
|
|
182
|
+
return false;
|
|
183
|
+
}
|
|
184
|
+
const size = candidate.size;
|
|
185
|
+
const position = candidate.position;
|
|
186
|
+
if (!size || typeof size.width !== 'number' || typeof size.height !== 'number') {
|
|
187
|
+
return false;
|
|
188
|
+
}
|
|
189
|
+
if (!position || typeof position.top !== 'number' || typeof position.left !== 'number') {
|
|
190
|
+
return false;
|
|
191
|
+
}
|
|
192
|
+
return true;
|
|
193
|
+
};
|
|
194
|
+
/** Wrapper guards selector discovery responses. */
|
|
195
|
+
export const isSweetLinkSelectorDiscoveryResult = (value) => {
|
|
196
|
+
if (typeof value !== 'object' || value === null) {
|
|
197
|
+
return false;
|
|
198
|
+
}
|
|
199
|
+
const record = value;
|
|
200
|
+
if (!Array.isArray(record.candidates)) {
|
|
201
|
+
return false;
|
|
202
|
+
}
|
|
203
|
+
return record.candidates.every((candidate) => isSweetLinkSelectorCandidate(candidate));
|
|
204
|
+
};
|
|
205
|
+
//# sourceMappingURL=session.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"session.js","sourceRoot":"","sources":["../../../src/runtime/session.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,KAAK,EAAE,QAAQ,EAAE,SAAS,EAAE,MAAM,kBAAkB,CAAC;AAC9D,OAAO,EAAE,MAAM,SAAS,CAAC;AACzB,OAAO,IAAI,MAAM,WAAW,CAAC;AAE7B,OAAO,EAAE,wBAAwB,EAA+B,MAAM,2BAA2B,CAAC;AAClG,OAAO,EAAE,SAAS,EAAE,MAAM,YAAY,CAAC;AACvC,OAAO,EAAE,aAAa,EAAE,MAAM,aAAa,CAAC;AA4C5C,MAAM,oBAAoB,GAAG,IAAI,GAAG,CAAC,CAAC,aAAa,EAAE,IAAI,EAAE,MAAM,EAAE,MAAM,EAAE,WAAW,EAAE,QAAQ,CAAC,CAAC,CAAC;AACnG,MAAM,kBAAkB,GAAG,iEAAiE,CAAC;AAC7F,MAAM,mBAAmB,GAAG,IAAI,CAAC,IAAI,CAAC,EAAE,CAAC,OAAO,EAAE,EAAE,YAAY,EAAE,wBAAwB,CAAC,CAAC;AAI5F,KAAK,UAAU,iBAAiB;IAC9B,IAAI,CAAC;QACH,MAAM,GAAG,GAAG,MAAM,QAAQ,CAAC,mBAAmB,EAAE,MAAM,CAAC,CAAC;QACxD,MAAM,MAAM,GAAG,IAAI,CAAC,KAAK,CAAC,GAAG,CAAkB,CAAC;QAChD,IAAI,MAAM,IAAI,OAAO,MAAM,KAAK,QAAQ,EAAE,CAAC;YACzC,OAAO,MAAM,CAAC;QAChB,CAAC;IACH,CAAC;IAAC,MAAM,CAAC;QACP,8BAA8B;IAChC,CAAC;IACD,OAAO,EAAE,CAAC;AACZ,CAAC;AAED,KAAK,UAAU,iBAAiB,CAAC,KAAoB;IACnD,IAAI,CAAC;QACH,MAAM,SAAS,GAAG,IAAI,CAAC,OAAO,CAAC,mBAAmB,CAAC,CAAC;QACpD,MAAM,KAAK,CAAC,SAAS,EAAE,EAAE,SAAS,EAAE,IAAI,EAAE,CAAC,CAAC;QAC5C,MAAM,SAAS,CAAC,mBAAmB,EAAE,IAAI,CAAC,SAAS,CAAC,KAAK,EAAE,IAAI,EAAE,CAAC,CAAC,EAAE,MAAM,CAAC,CAAC;IAC/E,CAAC;IAAC,MAAM,CAAC;QACP,+BAA+B;IACjC,CAAC;AACH,CAAC;AAED,KAAK,UAAU,yBAAyB,CAAC,QAAmC;IAC1E,IAAI,QAAQ,CAAC,MAAM,KAAK,CAAC,EAAE,CAAC;QAC1B,OAAO,QAAQ,CAAC;IAClB,CAAC;IAED,MAAM,KAAK,GAAG,MAAM,iBAAiB,EAAE,CAAC;IACxC,IAAI,cAAc,GAAG,CAAC,CAAC;IAEvB,MAAM,UAAU,GAA8B,EAAE,CAAC;IACjD,KAAK,MAAM,OAAO,IAAI,QAAQ,EAAE,CAAC;QAC/B,MAAM,cAAc,GAAG,KAAK,CAAC,OAAO,CAAC,SAAS,CAAC,CAAC;QAChD,IAAI,cAAc,EAAE,CAAC;YACnB,IAAI,OAAO,CAAC,QAAQ,KAAK,cAAc,EAAE,CAAC;gBACxC,UAAU,CAAC,IAAI,CAAC,OAAO,CAAC,CAAC;YAC3B,CAAC;iBAAM,CAAC;gBACN,cAAc,IAAI,CAAC,CAAC;gBACpB,UAAU,CAAC,IAAI,CAAC,EAAE,GAAG,OAAO,EAAE,QAAQ,EAAE,cAAc,EAAE,CAAC,CAAC;YAC5D,CAAC;YACD,SAAS;QACX,CAAC;QACD,IAAI,OAAO,CAAC,QAAQ,IAAI,OAAO,CAAC,QAAQ,CAAC,IAAI,EAAE,CAAC,MAAM,GAAG,CAAC,EAAE,CAAC;YAC3D,KAAK,CAAC,OAAO,CAAC,SAAS,CAAC,GAAG,OAAO,CAAC,QAAQ,CAAC;YAC5C,cAAc,IAAI,CAAC,CAAC;QACtB,CAAC;QACD,UAAU,CAAC,IAAI,CAAC,OAAO,CAAC,CAAC;IAC3B,CAAC;IAED,IAAI,cAAc,GAAG,CAAC,EAAE,CAAC;QACvB,MAAM,iBAAiB,CAAC,KAAK,CAAC,CAAC;IACjC,CAAC;IAED,OAAO,UAAU,CAAC;AACpB,CAAC;AAED,MAAM,CAAC,KAAK,UAAU,qBAAqB,CACzC,MAAiB,EACjB,aAAsB;IAEtB,MAAM,KAAK,GAAG,aAAa,IAAI,CAAC,MAAM,aAAa,CAAC,MAAM,CAAC,CAAC,CAAC;IAC7D,MAAM,QAAQ,GAAG,MAAM,SAAS,CAAkC,GAAG,MAAM,CAAC,aAAa,WAAW,EAAE;QACpG,OAAO,EAAE,EAAE,aAAa,EAAE,UAAU,KAAK,EAAE,EAAE;KAC9C,CAAC,CAAC;IACH,OAAO,MAAM,yBAAyB,CAAC,QAAQ,CAAC,QAAQ,CAAC,CAAC;AAC5D,CAAC;AAED,4DAA4D;AAC5D,MAAM,UAAU,qBAAqB,CAAC,OAAiD;IACrF,OAAO,OAAO,CAAC,QAAQ,CAAC,CAAC,CAAC,GAAG,OAAO,CAAC,QAAQ,KAAK,OAAO,CAAC,SAAS,GAAG,CAAC,CAAC,CAAC,OAAO,CAAC,SAAS,CAAC;AAC7F,CAAC;AAED,4EAA4E;AAC5E,MAAM,CAAC,KAAK,UAAU,wBAAwB,CAAC,WAAmB,EAAE,MAAiB;IACnF,MAAM,KAAK,GAAG,WAAW,CAAC,IAAI,EAAE,CAAC;IACjC,IAAI,KAAK,CAAC,MAAM,KAAK,CAAC,EAAE,CAAC;QACvB,MAAM,IAAI,KAAK,CAAC,6CAA6C,CAAC,CAAC;IACjE,CAAC;IACD,IAAI,kBAAkB,CAAC,IAAI,CAAC,KAAK,CAAC,EAAE,CAAC;QACnC,OAAO,KAAK,CAAC;IACf,CAAC;IAED,MAAM,QAAQ,GAAG,MAAM,qBAAqB,CAAC,MAAM,CAAC,CAAC;IAErD,MAAM,UAAU,GAAG,KAAK,CAAC,WAAW,EAAE,CAAC;IACvC,MAAM,OAAO,GAAG,QAAQ,CAAC,MAAM,CAAC,CAAC,OAAO,EAAE,EAAE;QAC1C,IAAI,OAAO,CAAC,SAAS,KAAK,KAAK,IAAI,OAAO,CAAC,SAAS,CAAC,WAAW,EAAE,KAAK,UAAU,EAAE,CAAC;YAClF,OAAO,IAAI,CAAC;QACd,CAAC;QACD,IAAI,OAAO,CAAC,QAAQ,IAAI,OAAO,CAAC,QAAQ,CAAC,WAAW,EAAE,KAAK,UAAU,EAAE,CAAC;YACtE,OAAO,IAAI,CAAC;QACd,CAAC;QACD,OAAO,KAAK,CAAC;IACf,CAAC,CAAC,CAAC;IAEH,IAAI,OAAO,CAAC,MAAM,KAAK,CAAC,EAAE,CAAC;QACzB,MAAM,IAAI,KAAK,CACb,wCAAwC,WAAW,6DAA6D,CACjH,CAAC;IACJ,CAAC;IAED,IAAI,OAAO,CAAC,MAAM,GAAG,CAAC,EAAE,CAAC;QACvB,MAAM,SAAS,GAAG,OAAO,CAAC,GAAG,CAAC,CAAC,OAAO,EAAE,EAAE,CAAC,qBAAqB,CAAC,OAAO,CAAC,CAAC,CAAC,IAAI,CAAC,IAAI,CAAC,CAAC;QACtF,MAAM,IAAI,KAAK,CAAC,sCAAsC,WAAW,2BAA2B,SAAS,GAAG,CAAC,CAAC;IAC5G,CAAC;IAED,MAAM,KAAK,GAAG,OAAO,CAAC,CAAC,CAAC,CAAC;IACzB,IAAI,CAAC,KAAK,EAAE,CAAC;QACX,MAAM,IAAI,KAAK,CAAC,6CAA6C,CAAC,CAAC;IACjE,CAAC;IACD,OAAO,KAAK,CAAC,SAAS,CAAC;AACzB,CAAC;AAED,8EAA8E;AAC9E,MAAM,CAAC,KAAK,UAAU,uBAAuB,CAC3C,MAAiB,EACjB,OAAgC;IAEhC,MAAM,KAAK,GAAG,MAAM,aAAa,CAAC,MAAM,CAAC,CAAC;IAC1C,MAAM,OAAO,GAAG;QACd,IAAI,EAAE,WAAoB;QAC1B,EAAE,EAAE,wBAAwB,EAAE;QAC9B,IAAI,EAAE,OAAO,CAAC,IAAI;QAClB,SAAS,EAAE,OAAO,CAAC,SAAS;QAC5B,cAAc,EAAE,OAAO,CAAC,OAAO,CAAC,cAAc,CAAC;KAChD,CAAC;IAEF,MAAM,MAAM,GAAG,MAAM,SAAS,CAC5B,GAAG,MAAM,CAAC,aAAa,aAAa,kBAAkB,CAAC,OAAO,CAAC,SAAS,CAAC,UAAU,EACnF;QACE,MAAM,EAAE,MAAM;QACd,OAAO,EAAE;YACP,aAAa,EAAE,UAAU,KAAK,EAAE;YAChC,cAAc,EAAE,kBAAkB;SACnC;QACD,IAAI,EAAE,IAAI,CAAC,SAAS,CAAC,OAAO,CAAC;KAC9B,CACF,CAAC;IAEF,OAAO,MAAM,CAAC,MAAM,CAAC;AACvB,CAAC;AAED,sEAAsE;AACtE,MAAM,CAAC,KAAK,UAAU,kBAAkB,CAAC,MAAiB,EAAE,SAAiB;IAC3E,MAAM,KAAK,GAAG,MAAM,aAAa,CAAC,MAAM,CAAC,CAAC;IAC1C,MAAM,QAAQ,GAAG,MAAM,SAAS,CAC9B,GAAG,MAAM,CAAC,aAAa,aAAa,kBAAkB,CAAC,SAAS,CAAC,UAAU,EAC3E;QACE,OAAO,EAAE,EAAE,aAAa,EAAE,UAAU,KAAK,EAAE,EAAE;KAC9C,CACF,CAAC;IACF,OAAO,KAAK,CAAC,OAAO,CAAC,QAAQ,CAAC,MAAM,CAAC,CAAC,CAAC,CAAC,QAAQ,CAAC,MAAM,CAAC,CAAC,CAAC,EAAE,CAAC;AAC/D,CAAC;AAED,MAAM,CAAC,KAAK,UAAU,qBAAqB,CACzC,MAAiB,EACjB,KAAa,EACb,SAAiB;IAEjB,MAAM,QAAQ,GAAG,MAAM,qBAAqB,CAAC,MAAM,EAAE,KAAK,CAAC,CAAC;IAC5D,OAAO,QAAQ,CAAC,IAAI,CAAC,CAAC,OAAO,EAAE,EAAE,CAAC,OAAO,CAAC,SAAS,KAAK,SAAS,CAAC,CAAC;AACrE,CAAC;AAED,2DAA2D;AAC3D,MAAM,UAAU,mBAAmB,CAAC,OAA+C;IACjF,MAAM,aAAa,GAAG,OAAO,CAAC,MAAM,EAAE,IAAI,EAAE,CAAC;IAC7C,IAAI,aAAa,EAAE,CAAC;QAClB,OAAO,aAAa,CAAC;IACvB,CAAC;IAED,MAAM,eAAe,GAAG,OAAO,CAAC,QAAQ,EAAE,IAAI,EAAE,CAAC;IACjD,IAAI,eAAe,EAAE,CAAC;QACpB,OAAO,eAAe,CAAC;IACzB,CAAC;IAED,OAAQ;AACV,CAAC;AAED,iEAAiE;AACjE,MAAM,UAAU,gBAAgB,CAAC,EAAE,QAAQ,EAAE,cAAc,EAAE,OAAO,EAA2B;IAC7F,MAAM,YAAY,GAAG,IAAI,CAAC,SAAS,CAAC,QAAQ,CAAC,CAAC;IAC9C,MAAM,eAAe,GAAG,6BAA6B,QAAQ,YAAY,CAAC;IAE1E,MAAM,KAAK,GAAa;QACtB,UAAU;QACV,2CAA2C,YAAY,IAAI;QAC3D,kBAAkB;QAClB,uBAAuB,IAAI,CAAC,SAAS,CAAC,eAAe,CAAC,IAAI;QAC1D,KAAK;KACN,CAAC;IAEF,IAAI,cAAc,EAAE,CAAC;QACnB,KAAK,CAAC,IAAI,CACR,sDAAsD,EACtD,WAAW,EACX,yFAAyF,EACzF,eAAe,EACf,gCAAgC,EAChC,OAAO,EACP,KAAK,CACN,CAAC;IACJ,CAAC;IAED,KAAK,CAAC,IAAI,CACR,2CAA2C,EAC3C,mBAAmB,EACnB,gBAAgB,OAAO,GAAG,EAC1B,uBAAuB,EACvB,oBAAoB,EACpB,OAAO,EACP,gCAAgC,EAChC,6CAA6C,EAC7C,qBAAqB,EACrB,KAAK,EACL,qBAAqB,EACrB,MAAM,CACP,CAAC;IAEF,OAAO,KAAK,CAAC,IAAI,CAAC,IAAI,CAAC,CAAC;AAC1B,CAAC;AAED,0EAA0E;AAC1E,MAAM,CAAC,MAAM,4BAA4B,GAAG,CAAC,KAAc,EAAuC,EAAE;IAClG,IAAI,OAAO,KAAK,KAAK,QAAQ,IAAI,KAAK,KAAK,IAAI,EAAE,CAAC;QAChD,OAAO,KAAK,CAAC;IACf,CAAC;IACD,MAAM,SAAS,GAAG,KAAgC,CAAC;IACnD,IACE,OAAO,SAAS,CAAC,QAAQ,KAAK,QAAQ;QACtC,OAAO,SAAS,CAAC,OAAO,KAAK,QAAQ;QACrC,OAAO,SAAS,CAAC,IAAI,KAAK,QAAQ;QAClC,CAAC,oBAAoB,CAAC,GAAG,CAAC,SAAS,CAAC,IAAI,CAAC;QACzC,OAAO,SAAS,CAAC,WAAW,KAAK,QAAQ;QACzC,OAAO,SAAS,CAAC,KAAK,KAAK,QAAQ;QACnC,OAAO,SAAS,CAAC,OAAO,KAAK,SAAS;QACtC,OAAO,SAAS,CAAC,IAAI,KAAK,QAAQ,EAClC,CAAC;QACD,OAAO,KAAK,CAAC;IACf,CAAC;IACD,MAAM,IAAI,GAAG,SAAS,CAAC,IAA2C,CAAC;IACnE,MAAM,QAAQ,GAAG,SAAS,CAAC,QAA+C,CAAC;IAC3E,IAAI,CAAC,IAAI,IAAI,OAAO,IAAI,CAAC,KAAK,KAAK,QAAQ,IAAI,OAAO,IAAI,CAAC,MAAM,KAAK,QAAQ,EAAE,CAAC;QAC/E,OAAO,KAAK,CAAC;IACf,CAAC;IACD,IAAI,CAAC,QAAQ,IAAI,OAAO,QAAQ,CAAC,GAAG,KAAK,QAAQ,IAAI,OAAO,QAAQ,CAAC,IAAI,KAAK,QAAQ,EAAE,CAAC;QACvF,OAAO,KAAK,CAAC;IACf,CAAC;IACD,OAAO,IAAI,CAAC;AACd,CAAC,CAAC;AAEF,mDAAmD;AACnD,MAAM,CAAC,MAAM,kCAAkC,GAAG,CAAC,KAAc,EAA6C,EAAE;IAC9G,IAAI,OAAO,KAAK,KAAK,QAAQ,IAAI,KAAK,KAAK,IAAI,EAAE,CAAC;QAChD,OAAO,KAAK,CAAC;IACf,CAAC;IACD,MAAM,MAAM,GAAG,KAAgC,CAAC;IAChD,IAAI,CAAC,KAAK,CAAC,OAAO,CAAC,MAAM,CAAC,UAAU,CAAC,EAAE,CAAC;QACtC,OAAO,KAAK,CAAC;IACf,CAAC;IACD,OAAO,MAAM,CAAC,UAAU,CAAC,KAAK,CAAC,CAAC,SAAS,EAAE,EAAE,CAAC,4BAA4B,CAAC,SAAS,CAAC,CAAC,CAAC;AACzF,CAAC,CAAC"}
|
|
@@ -0,0 +1,36 @@
|
|
|
1
|
+
import type { CliConfig } from '../types.js';
|
|
2
|
+
import { type SweetLinkBootstrapDiagnostics } from './devtools.js';
|
|
3
|
+
import type { SweetLinkConsoleDump } from './session.js';
|
|
4
|
+
export declare const SMOKE_ROUTE_PRESETS: Record<string, string[]>;
|
|
5
|
+
export declare const DEFAULT_SMOKE_ROUTES: string[];
|
|
6
|
+
export declare const deriveSmokeRoutes: (raw: string | undefined, defaults: readonly string[]) => string[];
|
|
7
|
+
export declare const buildSmokeRouteUrl: (base: URL, route: string) => URL;
|
|
8
|
+
export declare const navigateSweetLinkSession: (params: {
|
|
9
|
+
sessionId: string;
|
|
10
|
+
targetUrl: URL;
|
|
11
|
+
config: CliConfig;
|
|
12
|
+
}) => Promise<void>;
|
|
13
|
+
export declare const triggerSweetLinkCliAuto: (devtoolsUrl: string, candidateUrl: string) => Promise<void>;
|
|
14
|
+
export declare const ensureSweetLinkSessionConnected: (params: {
|
|
15
|
+
config: CliConfig;
|
|
16
|
+
token: string;
|
|
17
|
+
sessionId: string;
|
|
18
|
+
devtoolsUrl: string;
|
|
19
|
+
currentUrl: string;
|
|
20
|
+
timeoutMs?: number;
|
|
21
|
+
onSessionIdChanged?: (nextSessionId: string) => void;
|
|
22
|
+
candidateUrls?: string[];
|
|
23
|
+
}) => Promise<boolean>;
|
|
24
|
+
export declare const waitForSmokeRouteReady: (params: {
|
|
25
|
+
devtoolsUrl: string;
|
|
26
|
+
targetUrl: URL;
|
|
27
|
+
timeoutMs: number;
|
|
28
|
+
}) => Promise<SweetLinkBootstrapDiagnostics | null>;
|
|
29
|
+
export declare function computeSmokeRouteSignature(routes: readonly string[]): string;
|
|
30
|
+
export declare function loadSmokeProgressIndex(baseOrigin: string, routes: readonly string[]): Promise<number | null>;
|
|
31
|
+
export declare function saveSmokeProgressIndex(baseOrigin: string, routes: readonly string[], nextIndex: number): Promise<void>;
|
|
32
|
+
export declare function clearSmokeProgress(baseOrigin: string, routes: readonly string[]): Promise<void>;
|
|
33
|
+
export declare const consoleEventIndicatesAuthIssue: (event: SweetLinkConsoleDump) => boolean;
|
|
34
|
+
export declare const consoleEventIndicatesRuntimeError: (event: SweetLinkConsoleDump) => boolean;
|
|
35
|
+
export declare const formatConsoleEventSummary: (event: SweetLinkConsoleDump) => string;
|
|
36
|
+
//# sourceMappingURL=smoke.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"smoke.d.ts","sourceRoot":"","sources":["../../../src/runtime/smoke.ts"],"names":[],"mappings":"AAOA,OAAO,KAAK,EAAE,SAAS,EAAE,MAAM,aAAa,CAAC;AAG7C,OAAO,EAIL,KAAK,6BAA6B,EACnC,MAAM,eAAe,CAAC;AACvB,OAAO,KAAK,EAAE,oBAAoB,EAAE,MAAM,cAAc,CAAC;AA0EzD,eAAO,MAAM,mBAAmB,EAAE,MAAM,CAAC,MAAM,EAAE,MAAM,EAAE,CAGxD,CAAC;AAoBF,eAAO,MAAM,oBAAoB,UAAwE,CAAC;AAE1G,eAAO,MAAM,iBAAiB,GAAI,KAAK,MAAM,GAAG,SAAS,EAAE,UAAU,SAAS,MAAM,EAAE,KAAG,MAAM,EAc9F,CAAC;AAuBF,eAAO,MAAM,kBAAkB,GAAI,MAAM,GAAG,EAAE,OAAO,MAAM,KAAG,GAsB7D,CAAC;AAEF,eAAO,MAAM,wBAAwB,GAAU,QAAQ;IACrD,SAAS,EAAE,MAAM,CAAC;IAClB,SAAS,EAAE,GAAG,CAAC;IACf,MAAM,EAAE,SAAS,CAAC;CACnB,KAAG,OAAO,CAAC,IAAI,CAuBf,CAAC;AAEF,eAAO,MAAM,uBAAuB,GAAU,aAAa,MAAM,EAAE,cAAc,MAAM,KAAG,OAAO,CAAC,IAAI,CAiCrG,CAAC;AAEF,eAAO,MAAM,+BAA+B,GAAU,QAAQ;IAC5D,MAAM,EAAE,SAAS,CAAC;IAClB,KAAK,EAAE,MAAM,CAAC;IACd,SAAS,EAAE,MAAM,CAAC;IAClB,WAAW,EAAE,MAAM,CAAC;IACpB,UAAU,EAAE,MAAM,CAAC;IACnB,SAAS,CAAC,EAAE,MAAM,CAAC;IACnB,kBAAkB,CAAC,EAAE,CAAC,aAAa,EAAE,MAAM,KAAK,IAAI,CAAC;IACrD,aAAa,CAAC,EAAE,MAAM,EAAE,CAAC;CAC1B,KAAG,OAAO,CAAC,OAAO,CA4ClB,CAAC;AAEF,eAAO,MAAM,sBAAsB,GAAU,QAAQ;IACnD,WAAW,EAAE,MAAM,CAAC;IACpB,SAAS,EAAE,GAAG,CAAC;IACf,SAAS,EAAE,MAAM,CAAC;CACnB,KAAG,OAAO,CAAC,6BAA6B,GAAG,IAAI,CAgC/C,CAAC;AAqCF,wBAAgB,0BAA0B,CAAC,MAAM,EAAE,SAAS,MAAM,EAAE,GAAG,MAAM,CAE5E;AAED,wBAAsB,sBAAsB,CAAC,UAAU,EAAE,MAAM,EAAE,MAAM,EAAE,SAAS,MAAM,EAAE,GAAG,OAAO,CAAC,MAAM,GAAG,IAAI,CAAC,CAQlH;AAED,wBAAsB,sBAAsB,CAC1C,UAAU,EAAE,MAAM,EAClB,MAAM,EAAE,SAAS,MAAM,EAAE,EACzB,SAAS,EAAE,MAAM,GAChB,OAAO,CAAC,IAAI,CAAC,CAkBf;AAED,wBAAsB,kBAAkB,CAAC,UAAU,EAAE,MAAM,EAAE,MAAM,EAAE,SAAS,MAAM,EAAE,GAAG,OAAO,CAAC,IAAI,CAAC,CAUrG;AAED,eAAO,MAAM,8BAA8B,GAAI,OAAO,oBAAoB,KAAG,OAkB5E,CAAC;AAEF,eAAO,MAAM,iCAAiC,GAAI,OAAO,oBAAoB,KAAG,OAuD/E,CAAC;AAEF,eAAO,MAAM,yBAAyB,GAAI,OAAO,oBAAoB,KAAG,MAOvE,CAAC"}
|
|
@@ -0,0 +1,417 @@
|
|
|
1
|
+
import { regex } from 'arkregex';
|
|
2
|
+
import { mkdir, readFile, writeFile } from 'node:fs/promises';
|
|
3
|
+
import os from 'node:os';
|
|
4
|
+
import path from 'node:path';
|
|
5
|
+
import { compact, uniq } from 'es-toolkit';
|
|
6
|
+
import { loadSweetLinkFileConfig } from '../core/config-file.js';
|
|
7
|
+
import { sweetLinkDebug } from '../env.js';
|
|
8
|
+
import { describeUnknown, isErrnoException } from '../util/errors.js';
|
|
9
|
+
import { delay } from '../util/time.js';
|
|
10
|
+
import { collectBootstrapDiagnostics, diagnosticsContainBlockingIssues, evaluateInDevToolsTab, } from './devtools.js';
|
|
11
|
+
import { executeRunScriptCommand, fetchSessionSummaries, getSessionSummaryById } from './session.js';
|
|
12
|
+
import { buildWaitCandidateUrls, configurePathRedirects, urlsRoughlyMatch } from './url.js';
|
|
13
|
+
const ABSOLUTE_URL_PATTERN = regex.as('^https?:', 'i');
|
|
14
|
+
const normalizeRouteList = (input) => {
|
|
15
|
+
if (typeof input === 'string') {
|
|
16
|
+
const trimmed = input.trim();
|
|
17
|
+
return trimmed.length > 0 ? [trimmed] : [];
|
|
18
|
+
}
|
|
19
|
+
if (!Array.isArray(input)) {
|
|
20
|
+
return [];
|
|
21
|
+
}
|
|
22
|
+
return compact(input.map((route) => {
|
|
23
|
+
if (typeof route !== 'string') {
|
|
24
|
+
return null;
|
|
25
|
+
}
|
|
26
|
+
const trimmed = route.trim();
|
|
27
|
+
return trimmed.length > 0 ? trimmed : null;
|
|
28
|
+
}));
|
|
29
|
+
};
|
|
30
|
+
const normalizeSmokePresets = (presets) => {
|
|
31
|
+
if (!presets || typeof presets !== 'object') {
|
|
32
|
+
return {};
|
|
33
|
+
}
|
|
34
|
+
const result = {};
|
|
35
|
+
for (const [key, value] of Object.entries(presets)) {
|
|
36
|
+
const routes = normalizeRouteList(value);
|
|
37
|
+
if (routes.length > 0) {
|
|
38
|
+
result[key] = routes;
|
|
39
|
+
}
|
|
40
|
+
}
|
|
41
|
+
return result;
|
|
42
|
+
};
|
|
43
|
+
const SMOKE_PROGRESS_PATH = path.join(os.homedir(), '.sweetlink', 'smoke-progress.json');
|
|
44
|
+
const builtinSmokePresets = {
|
|
45
|
+
main: ['timeline/home', 'insights', 'search', 'pulse'],
|
|
46
|
+
settings: [
|
|
47
|
+
'settings/account',
|
|
48
|
+
'settings/activity',
|
|
49
|
+
'settings/billing',
|
|
50
|
+
'settings/notifications',
|
|
51
|
+
'settings/social',
|
|
52
|
+
'settings/sync',
|
|
53
|
+
'settings/import',
|
|
54
|
+
'settings/extension',
|
|
55
|
+
'settings/beta',
|
|
56
|
+
],
|
|
57
|
+
'billing-only': ['settings/billing'],
|
|
58
|
+
'pulse-only': ['pulse'],
|
|
59
|
+
};
|
|
60
|
+
const { config: fileConfig } = loadSweetLinkFileConfig();
|
|
61
|
+
configurePathRedirects(fileConfig.redirects);
|
|
62
|
+
const configuredPresets = normalizeSmokePresets(fileConfig.smokeRoutes?.presets);
|
|
63
|
+
export const SMOKE_ROUTE_PRESETS = {
|
|
64
|
+
...builtinSmokePresets,
|
|
65
|
+
...configuredPresets,
|
|
66
|
+
};
|
|
67
|
+
const getPresetRoutes = (name) => normalizeRouteList(SMOKE_ROUTE_PRESETS[name]);
|
|
68
|
+
const configuredDefaults = normalizeRouteList(fileConfig.smokeRoutes?.defaults ?? []);
|
|
69
|
+
const mainPresetRoutes = getPresetRoutes('main');
|
|
70
|
+
const settingsPresetRoutes = getPresetRoutes('settings');
|
|
71
|
+
const fallbackDefaults = [];
|
|
72
|
+
if (mainPresetRoutes.length > 0) {
|
|
73
|
+
fallbackDefaults.push(...mainPresetRoutes);
|
|
74
|
+
}
|
|
75
|
+
else {
|
|
76
|
+
fallbackDefaults.push(...builtinSmokePresets.main);
|
|
77
|
+
}
|
|
78
|
+
if (settingsPresetRoutes.length > 0) {
|
|
79
|
+
fallbackDefaults.push(...settingsPresetRoutes);
|
|
80
|
+
}
|
|
81
|
+
else {
|
|
82
|
+
fallbackDefaults.push(...builtinSmokePresets.settings);
|
|
83
|
+
}
|
|
84
|
+
export const DEFAULT_SMOKE_ROUTES = configuredDefaults.length > 0 ? configuredDefaults : fallbackDefaults;
|
|
85
|
+
export const deriveSmokeRoutes = (raw, defaults) => {
|
|
86
|
+
if (!raw || raw.trim().length === 0) {
|
|
87
|
+
return [...defaults];
|
|
88
|
+
}
|
|
89
|
+
const segments = compact(raw.split(',').map((segment) => segment.trim()));
|
|
90
|
+
if (segments.length === 0) {
|
|
91
|
+
return [...defaults];
|
|
92
|
+
}
|
|
93
|
+
const expanded = segments.flatMap((segment) => {
|
|
94
|
+
const candidatePreset = SMOKE_ROUTE_PRESETS[segment.toLowerCase()];
|
|
95
|
+
return Array.isArray(candidatePreset) ? candidatePreset : [segment];
|
|
96
|
+
});
|
|
97
|
+
const uniqueRoutes = uniq(expanded);
|
|
98
|
+
return uniqueRoutes.length > 0 ? uniqueRoutes : [...defaults];
|
|
99
|
+
};
|
|
100
|
+
const normalizeRoutePath = (route) => {
|
|
101
|
+
const routeValue = typeof route === 'string' ? route : String(route ?? '');
|
|
102
|
+
if (!routeValue) {
|
|
103
|
+
return '/';
|
|
104
|
+
}
|
|
105
|
+
if (ABSOLUTE_URL_PATTERN.test(routeValue)) {
|
|
106
|
+
try {
|
|
107
|
+
const parsed = new URL(routeValue);
|
|
108
|
+
return parsed.pathname || '/';
|
|
109
|
+
}
|
|
110
|
+
catch {
|
|
111
|
+
return '/';
|
|
112
|
+
}
|
|
113
|
+
}
|
|
114
|
+
const trimmed = String.prototype.trim.call(routeValue);
|
|
115
|
+
if (!trimmed) {
|
|
116
|
+
return '/';
|
|
117
|
+
}
|
|
118
|
+
const withSlash = String.prototype.startsWith.call(trimmed, '/') ? trimmed : `/${trimmed}`;
|
|
119
|
+
return withSlash.replaceAll(/\/{2,}/g, '/');
|
|
120
|
+
};
|
|
121
|
+
export const buildSmokeRouteUrl = (base, route) => {
|
|
122
|
+
if (ABSOLUTE_URL_PATTERN.test(route)) {
|
|
123
|
+
try {
|
|
124
|
+
const parsed = new URL(route);
|
|
125
|
+
parsed.searchParams.set('sweetlink', 'auto');
|
|
126
|
+
return parsed;
|
|
127
|
+
}
|
|
128
|
+
catch {
|
|
129
|
+
// Fall back to treating as relative path.
|
|
130
|
+
}
|
|
131
|
+
}
|
|
132
|
+
const [pathPart, searchPart] = route.split('?', 2);
|
|
133
|
+
const next = new URL(base.toString());
|
|
134
|
+
next.search = '';
|
|
135
|
+
next.pathname = normalizeRoutePath(pathPart ?? '/');
|
|
136
|
+
if (searchPart) {
|
|
137
|
+
const extra = new URLSearchParams(searchPart);
|
|
138
|
+
for (const [key, value] of extra.entries()) {
|
|
139
|
+
next.searchParams.set(key, value);
|
|
140
|
+
}
|
|
141
|
+
}
|
|
142
|
+
next.searchParams.set('sweetlink', 'auto');
|
|
143
|
+
return next;
|
|
144
|
+
};
|
|
145
|
+
export const navigateSweetLinkSession = async (params) => {
|
|
146
|
+
const script = `(() => {
|
|
147
|
+
try {
|
|
148
|
+
const target = new URL(${JSON.stringify(params.targetUrl.toString())}, window.location.origin);
|
|
149
|
+
if (target.searchParams.get('sweetlink') !== 'auto') {
|
|
150
|
+
target.searchParams.set('sweetlink', 'auto');
|
|
151
|
+
}
|
|
152
|
+
if (window.location.href === target.toString()) {
|
|
153
|
+
return target.toString();
|
|
154
|
+
}
|
|
155
|
+
window.location.assign(target.toString());
|
|
156
|
+
return target.toString();
|
|
157
|
+
} catch (error) {
|
|
158
|
+
throw new Error(String(error ?? 'navigation failed'));
|
|
159
|
+
}
|
|
160
|
+
})()`;
|
|
161
|
+
await executeRunScriptCommand(params.config, {
|
|
162
|
+
sessionId: params.sessionId,
|
|
163
|
+
code: script,
|
|
164
|
+
timeoutMs: 15_000,
|
|
165
|
+
captureConsole: false,
|
|
166
|
+
});
|
|
167
|
+
};
|
|
168
|
+
export const triggerSweetLinkCliAuto = async (devtoolsUrl, candidateUrl) => {
|
|
169
|
+
const candidates = buildWaitCandidateUrls(candidateUrl);
|
|
170
|
+
const expression = `(() => {
|
|
171
|
+
try {
|
|
172
|
+
if (typeof console?.log === 'function') {
|
|
173
|
+
console.log('[SweetLink CLI] dispatching sweetlink:cli-auto event');
|
|
174
|
+
}
|
|
175
|
+
const event = new CustomEvent('sweetlink:cli-auto');
|
|
176
|
+
window.dispatchEvent(event);
|
|
177
|
+
try {
|
|
178
|
+
window.sessionStorage?.setItem('sweetlink:auto', 'pending');
|
|
179
|
+
window.sessionStorage?.removeItem('sweetlink:last-session');
|
|
180
|
+
} catch {}
|
|
181
|
+
try {
|
|
182
|
+
window.localStorage?.removeItem('sweetlink:last-session');
|
|
183
|
+
} catch {}
|
|
184
|
+
return { dispatched: true };
|
|
185
|
+
} catch (error) {
|
|
186
|
+
return { dispatched: false, error: String(error ?? 'failed') };
|
|
187
|
+
}
|
|
188
|
+
})()`;
|
|
189
|
+
for (const candidate of candidates) {
|
|
190
|
+
try {
|
|
191
|
+
// biome-ignore lint/performance/noAwaitInLoops: evaluate each candidate sequentially until one succeeds.
|
|
192
|
+
await evaluateInDevToolsTab(devtoolsUrl, candidate, expression);
|
|
193
|
+
break;
|
|
194
|
+
}
|
|
195
|
+
catch (error) {
|
|
196
|
+
if (sweetLinkDebug) {
|
|
197
|
+
console.warn('Failed to trigger SweetLink CLI auto bootstrap:', error);
|
|
198
|
+
}
|
|
199
|
+
}
|
|
200
|
+
}
|
|
201
|
+
};
|
|
202
|
+
export const ensureSweetLinkSessionConnected = async (params) => {
|
|
203
|
+
const timeoutMs = params.timeoutMs ?? 15_000;
|
|
204
|
+
const deadline = Date.now() + timeoutMs;
|
|
205
|
+
let lastTriggerAt = 0;
|
|
206
|
+
let activeSessionId = params.sessionId;
|
|
207
|
+
const candidateSources = [params.currentUrl, ...(params.candidateUrls ?? [])];
|
|
208
|
+
const candidateUrls = candidateSources.flatMap((source) => buildWaitCandidateUrls(source));
|
|
209
|
+
while (Date.now() < deadline) {
|
|
210
|
+
try {
|
|
211
|
+
// biome-ignore lint/performance/noAwaitInLoops: polling for a session must remain sequential.
|
|
212
|
+
const summary = await getSessionSummaryById(params.config, params.token, activeSessionId);
|
|
213
|
+
if (summary && summary.socketState === 'open') {
|
|
214
|
+
return true;
|
|
215
|
+
}
|
|
216
|
+
if (!summary) {
|
|
217
|
+
const sessions = await fetchSessionSummaries(params.config, params.token);
|
|
218
|
+
const replacement = sessions.find((candidate) => {
|
|
219
|
+
if (!candidate?.url) {
|
|
220
|
+
return false;
|
|
221
|
+
}
|
|
222
|
+
return candidateUrls.some((candidateUrl) => urlsRoughlyMatch(candidate.url, candidateUrl));
|
|
223
|
+
});
|
|
224
|
+
if (replacement) {
|
|
225
|
+
activeSessionId = replacement.sessionId;
|
|
226
|
+
params.onSessionIdChanged?.(replacement.sessionId);
|
|
227
|
+
if (replacement.socketState === 'open') {
|
|
228
|
+
return true;
|
|
229
|
+
}
|
|
230
|
+
}
|
|
231
|
+
}
|
|
232
|
+
}
|
|
233
|
+
catch {
|
|
234
|
+
/* ignore */
|
|
235
|
+
}
|
|
236
|
+
if (Date.now() - lastTriggerAt > 750) {
|
|
237
|
+
await triggerSweetLinkCliAuto(params.devtoolsUrl, params.currentUrl);
|
|
238
|
+
lastTriggerAt = Date.now();
|
|
239
|
+
}
|
|
240
|
+
await delay(500);
|
|
241
|
+
}
|
|
242
|
+
return false;
|
|
243
|
+
};
|
|
244
|
+
export const waitForSmokeRouteReady = async (params) => {
|
|
245
|
+
const candidates = buildWaitCandidateUrls(params.targetUrl.toString());
|
|
246
|
+
const deadline = Date.now() + params.timeoutMs;
|
|
247
|
+
let lastDiagnostics = null;
|
|
248
|
+
while (Date.now() < deadline) {
|
|
249
|
+
try {
|
|
250
|
+
// biome-ignore lint/performance/noAwaitInLoops: retries rely on sequential collection attempts.
|
|
251
|
+
const diagnostics = await collectBootstrapDiagnostics(params.devtoolsUrl, candidates);
|
|
252
|
+
if (diagnostics) {
|
|
253
|
+
lastDiagnostics = diagnostics;
|
|
254
|
+
if (diagnosticsContainBlockingIssues(diagnostics)) {
|
|
255
|
+
return diagnostics;
|
|
256
|
+
}
|
|
257
|
+
if (diagnostics.locationHref &&
|
|
258
|
+
urlsRoughlyMatch(diagnostics.locationHref, params.targetUrl.toString()) &&
|
|
259
|
+
diagnostics.readyState &&
|
|
260
|
+
(diagnostics.readyState === 'complete' || diagnostics.readyState === 'interactive')) {
|
|
261
|
+
return diagnostics;
|
|
262
|
+
}
|
|
263
|
+
}
|
|
264
|
+
}
|
|
265
|
+
catch (error) {
|
|
266
|
+
if (sweetLinkDebug) {
|
|
267
|
+
console.warn('Smoke wait diagnostics error:', error);
|
|
268
|
+
}
|
|
269
|
+
}
|
|
270
|
+
await delay(500);
|
|
271
|
+
}
|
|
272
|
+
return lastDiagnostics;
|
|
273
|
+
};
|
|
274
|
+
function routesSignatureKey(routes) {
|
|
275
|
+
return JSON.stringify(routes);
|
|
276
|
+
}
|
|
277
|
+
async function readSmokeProgressFile() {
|
|
278
|
+
try {
|
|
279
|
+
const raw = await readFile(SMOKE_PROGRESS_PATH, 'utf8');
|
|
280
|
+
const parsed = JSON.parse(raw);
|
|
281
|
+
if (parsed && Array.isArray(parsed.entries)) {
|
|
282
|
+
return {
|
|
283
|
+
entries: parsed.entries
|
|
284
|
+
.map((entry) => ({
|
|
285
|
+
baseOrigin: entry.baseOrigin,
|
|
286
|
+
routesSignature: entry.routesSignature,
|
|
287
|
+
nextIndex: entry.nextIndex ?? 0,
|
|
288
|
+
updatedAt: entry.updatedAt ?? Date.now(),
|
|
289
|
+
}))
|
|
290
|
+
.filter((entry) => typeof entry.baseOrigin === 'string' && typeof entry.routesSignature === 'string'),
|
|
291
|
+
};
|
|
292
|
+
}
|
|
293
|
+
}
|
|
294
|
+
catch (error) {
|
|
295
|
+
if (!isErrnoException(error) || error.code !== 'ENOENT') {
|
|
296
|
+
console.warn('Failed to read SweetLink smoke progress file:', error);
|
|
297
|
+
}
|
|
298
|
+
}
|
|
299
|
+
return { entries: [] };
|
|
300
|
+
}
|
|
301
|
+
async function writeSmokeProgressFile(file) {
|
|
302
|
+
const directory = path.dirname(SMOKE_PROGRESS_PATH);
|
|
303
|
+
await mkdir(directory, { recursive: true });
|
|
304
|
+
const payload = JSON.stringify({ entries: file.entries }, null, 2);
|
|
305
|
+
await writeFile(SMOKE_PROGRESS_PATH, payload, 'utf8');
|
|
306
|
+
}
|
|
307
|
+
export function computeSmokeRouteSignature(routes) {
|
|
308
|
+
return routesSignatureKey(routes);
|
|
309
|
+
}
|
|
310
|
+
export async function loadSmokeProgressIndex(baseOrigin, routes) {
|
|
311
|
+
const signature = routesSignatureKey(routes);
|
|
312
|
+
const file = await readSmokeProgressFile();
|
|
313
|
+
const match = file.entries.find((entry) => entry.baseOrigin === baseOrigin && entry.routesSignature === signature);
|
|
314
|
+
if (match && Number.isInteger(match.nextIndex) && match.nextIndex >= 0) {
|
|
315
|
+
return match.nextIndex;
|
|
316
|
+
}
|
|
317
|
+
return null;
|
|
318
|
+
}
|
|
319
|
+
export async function saveSmokeProgressIndex(baseOrigin, routes, nextIndex) {
|
|
320
|
+
const signature = routesSignatureKey(routes);
|
|
321
|
+
const file = await readSmokeProgressFile();
|
|
322
|
+
const now = Date.now();
|
|
323
|
+
const existingIndex = file.entries.findIndex((entry) => entry.baseOrigin === baseOrigin && entry.routesSignature === signature);
|
|
324
|
+
if (existingIndex === -1) {
|
|
325
|
+
file.entries.push({ baseOrigin, routesSignature: signature, nextIndex, updatedAt: now });
|
|
326
|
+
}
|
|
327
|
+
else {
|
|
328
|
+
file.entries[existingIndex] = {
|
|
329
|
+
baseOrigin,
|
|
330
|
+
routesSignature: signature,
|
|
331
|
+
nextIndex,
|
|
332
|
+
updatedAt: now,
|
|
333
|
+
};
|
|
334
|
+
}
|
|
335
|
+
await writeSmokeProgressFile(file);
|
|
336
|
+
}
|
|
337
|
+
export async function clearSmokeProgress(baseOrigin, routes) {
|
|
338
|
+
const signature = routesSignatureKey(routes);
|
|
339
|
+
const file = await readSmokeProgressFile();
|
|
340
|
+
const filtered = file.entries.filter((entry) => !(entry.baseOrigin === baseOrigin && entry.routesSignature === signature));
|
|
341
|
+
if (filtered.length === file.entries.length) {
|
|
342
|
+
return;
|
|
343
|
+
}
|
|
344
|
+
await writeSmokeProgressFile({ entries: filtered });
|
|
345
|
+
}
|
|
346
|
+
export const consoleEventIndicatesAuthIssue = (event) => {
|
|
347
|
+
const level = typeof event?.level === 'string' ? event.level.toLowerCase() : '';
|
|
348
|
+
if (level && level !== 'error' && level !== 'warn' && level !== 'assert') {
|
|
349
|
+
return false;
|
|
350
|
+
}
|
|
351
|
+
if (!(event && Array.isArray(event.args))) {
|
|
352
|
+
return false;
|
|
353
|
+
}
|
|
354
|
+
for (const value of event.args) {
|
|
355
|
+
const text = describeUnknown(value, '').toLowerCase();
|
|
356
|
+
if (!text) {
|
|
357
|
+
continue;
|
|
358
|
+
}
|
|
359
|
+
if (text.includes('authentication required') || text.includes('unauthorized') || text.includes('401')) {
|
|
360
|
+
return true;
|
|
361
|
+
}
|
|
362
|
+
}
|
|
363
|
+
return false;
|
|
364
|
+
};
|
|
365
|
+
export const consoleEventIndicatesRuntimeError = (event) => {
|
|
366
|
+
const level = typeof event?.level === 'string' ? event.level.toLowerCase() : '';
|
|
367
|
+
const isErrorLevel = level === 'error' || level === 'assert';
|
|
368
|
+
const args = Array.isArray(event?.args) ? event.args : [];
|
|
369
|
+
const renderedArgs = args
|
|
370
|
+
.map((value) => describeUnknown(value, ''))
|
|
371
|
+
.filter((value) => typeof value === 'string' && value.trim().length > 0);
|
|
372
|
+
if (renderedArgs.length === 0) {
|
|
373
|
+
return isErrorLevel;
|
|
374
|
+
}
|
|
375
|
+
const combined = renderedArgs.join(' ').toLowerCase();
|
|
376
|
+
if (combined.includes('[fast refresh]')) {
|
|
377
|
+
return false;
|
|
378
|
+
}
|
|
379
|
+
const isTrpcMetadataLog = combined.includes('[trpc]') && combined.includes('trpcclienterror');
|
|
380
|
+
if (isTrpcMetadataLog) {
|
|
381
|
+
return false;
|
|
382
|
+
}
|
|
383
|
+
if (isErrorLevel) {
|
|
384
|
+
return true;
|
|
385
|
+
}
|
|
386
|
+
if (level === 'warn') {
|
|
387
|
+
if (combined.includes('[trpc]')) {
|
|
388
|
+
return false;
|
|
389
|
+
}
|
|
390
|
+
return (combined.includes('uncaught') ||
|
|
391
|
+
combined.includes('unhandled') ||
|
|
392
|
+
combined.includes('sweetlink auto-activation failed') ||
|
|
393
|
+
(combined.includes('error:') && !combined.includes('trpcclienterror')));
|
|
394
|
+
}
|
|
395
|
+
if (!level || level === 'log' || level === 'info' || level === 'debug') {
|
|
396
|
+
if (combined.includes('sweetlink auto-activation failed')) {
|
|
397
|
+
return true;
|
|
398
|
+
}
|
|
399
|
+
if (combined.includes('uncaught') || combined.includes('unhandled')) {
|
|
400
|
+
return true;
|
|
401
|
+
}
|
|
402
|
+
if (combined.includes('error:') && !combined.includes('trpcclienterror') && !combined.includes('[trpc]')) {
|
|
403
|
+
return true;
|
|
404
|
+
}
|
|
405
|
+
return false;
|
|
406
|
+
}
|
|
407
|
+
return false;
|
|
408
|
+
};
|
|
409
|
+
export const formatConsoleEventSummary = (event) => {
|
|
410
|
+
const timestamp = Number.isFinite(event.timestamp) ? new Date(event.timestamp).toISOString() : 'unknown-time';
|
|
411
|
+
const message = event.args
|
|
412
|
+
.map((value) => describeUnknown(value, ''))
|
|
413
|
+
.join(' ')
|
|
414
|
+
.trim();
|
|
415
|
+
return `[${timestamp}] ${event.level ?? 'log'} ${message}`;
|
|
416
|
+
};
|
|
417
|
+
//# sourceMappingURL=smoke.js.map
|