@showrun/core 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/LICENSE +21 -0
- package/dist/__tests__/dsl-validation.test.d.ts +2 -0
- package/dist/__tests__/dsl-validation.test.d.ts.map +1 -0
- package/dist/__tests__/dsl-validation.test.js +203 -0
- package/dist/__tests__/pack-versioning.test.d.ts +2 -0
- package/dist/__tests__/pack-versioning.test.d.ts.map +1 -0
- package/dist/__tests__/pack-versioning.test.js +165 -0
- package/dist/__tests__/validator.test.d.ts +2 -0
- package/dist/__tests__/validator.test.d.ts.map +1 -0
- package/dist/__tests__/validator.test.js +149 -0
- package/dist/authResilience.d.ts +146 -0
- package/dist/authResilience.d.ts.map +1 -0
- package/dist/authResilience.js +378 -0
- package/dist/browserLauncher.d.ts +74 -0
- package/dist/browserLauncher.d.ts.map +1 -0
- package/dist/browserLauncher.js +159 -0
- package/dist/browserPersistence.d.ts +49 -0
- package/dist/browserPersistence.d.ts.map +1 -0
- package/dist/browserPersistence.js +143 -0
- package/dist/context.d.ts +10 -0
- package/dist/context.d.ts.map +1 -0
- package/dist/context.js +30 -0
- package/dist/dsl/builders.d.ts +340 -0
- package/dist/dsl/builders.d.ts.map +1 -0
- package/dist/dsl/builders.js +416 -0
- package/dist/dsl/conditions.d.ts +33 -0
- package/dist/dsl/conditions.d.ts.map +1 -0
- package/dist/dsl/conditions.js +169 -0
- package/dist/dsl/interpreter.d.ts +24 -0
- package/dist/dsl/interpreter.d.ts.map +1 -0
- package/dist/dsl/interpreter.js +491 -0
- package/dist/dsl/stepHandlers.d.ts +32 -0
- package/dist/dsl/stepHandlers.d.ts.map +1 -0
- package/dist/dsl/stepHandlers.js +787 -0
- package/dist/dsl/target.d.ts +28 -0
- package/dist/dsl/target.d.ts.map +1 -0
- package/dist/dsl/target.js +110 -0
- package/dist/dsl/templating.d.ts +21 -0
- package/dist/dsl/templating.d.ts.map +1 -0
- package/dist/dsl/templating.js +73 -0
- package/dist/dsl/types.d.ts +695 -0
- package/dist/dsl/types.d.ts.map +1 -0
- package/dist/dsl/types.js +7 -0
- package/dist/dsl/validation.d.ts +15 -0
- package/dist/dsl/validation.d.ts.map +1 -0
- package/dist/dsl/validation.js +974 -0
- package/dist/index.d.ts +20 -0
- package/dist/index.d.ts.map +1 -0
- package/dist/index.js +20 -0
- package/dist/jsonPackValidator.d.ts +11 -0
- package/dist/jsonPackValidator.d.ts.map +1 -0
- package/dist/jsonPackValidator.js +61 -0
- package/dist/loader.d.ts +35 -0
- package/dist/loader.d.ts.map +1 -0
- package/dist/loader.js +107 -0
- package/dist/networkCapture.d.ts +107 -0
- package/dist/networkCapture.d.ts.map +1 -0
- package/dist/networkCapture.js +390 -0
- package/dist/packUtils.d.ts +36 -0
- package/dist/packUtils.d.ts.map +1 -0
- package/dist/packUtils.js +97 -0
- package/dist/packVersioning.d.ts +25 -0
- package/dist/packVersioning.d.ts.map +1 -0
- package/dist/packVersioning.js +137 -0
- package/dist/runner.d.ts +62 -0
- package/dist/runner.d.ts.map +1 -0
- package/dist/runner.js +170 -0
- package/dist/types.d.ts +336 -0
- package/dist/types.d.ts.map +1 -0
- package/dist/types.js +1 -0
- package/dist/validator.d.ts +20 -0
- package/dist/validator.d.ts.map +1 -0
- package/dist/validator.js +68 -0
- package/package.json +49 -0
|
@@ -0,0 +1,159 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Unified browser launcher
|
|
3
|
+
*
|
|
4
|
+
* Provides a unified interface for launching browsers with different engines
|
|
5
|
+
* (Chromium, Camoufox) and persistence modes.
|
|
6
|
+
*/
|
|
7
|
+
import { chromium } from 'playwright';
|
|
8
|
+
import { resolveBrowserDataDir } from './browserPersistence.js';
|
|
9
|
+
/**
|
|
10
|
+
* Launches a browser with the specified configuration
|
|
11
|
+
*
|
|
12
|
+
* @param config - Browser launch configuration
|
|
13
|
+
* @returns Browser session with context, page, and close function
|
|
14
|
+
*/
|
|
15
|
+
export async function launchBrowser(config) {
|
|
16
|
+
const { browserSettings = {}, headless = true, sessionId, packPath, } = config;
|
|
17
|
+
const engine = browserSettings.engine ?? 'camoufox';
|
|
18
|
+
const persistence = browserSettings.persistence ?? 'none';
|
|
19
|
+
// Resolve user data directory based on persistence mode
|
|
20
|
+
const userDataDir = resolveBrowserDataDir({
|
|
21
|
+
persistence,
|
|
22
|
+
sessionId,
|
|
23
|
+
packPath,
|
|
24
|
+
});
|
|
25
|
+
if (engine === 'camoufox') {
|
|
26
|
+
return launchCamoufox({
|
|
27
|
+
headless,
|
|
28
|
+
userDataDir,
|
|
29
|
+
persistence,
|
|
30
|
+
});
|
|
31
|
+
}
|
|
32
|
+
// Default: Chromium
|
|
33
|
+
return launchChromium({
|
|
34
|
+
headless,
|
|
35
|
+
userDataDir,
|
|
36
|
+
persistence,
|
|
37
|
+
});
|
|
38
|
+
}
|
|
39
|
+
/**
|
|
40
|
+
* Launches Chromium browser
|
|
41
|
+
*/
|
|
42
|
+
async function launchChromium(config) {
|
|
43
|
+
const { headless, userDataDir, persistence } = config;
|
|
44
|
+
let browser;
|
|
45
|
+
let context;
|
|
46
|
+
let page;
|
|
47
|
+
if (userDataDir) {
|
|
48
|
+
// Use persistent context when user data dir is specified
|
|
49
|
+
context = await chromium.launchPersistentContext(userDataDir, {
|
|
50
|
+
headless,
|
|
51
|
+
});
|
|
52
|
+
browser = null; // Persistent context doesn't expose browser
|
|
53
|
+
page = context.pages()[0] || await context.newPage();
|
|
54
|
+
}
|
|
55
|
+
else {
|
|
56
|
+
// Ephemeral browser
|
|
57
|
+
browser = await chromium.launch({ headless });
|
|
58
|
+
context = await browser.newContext();
|
|
59
|
+
page = await context.newPage();
|
|
60
|
+
}
|
|
61
|
+
return {
|
|
62
|
+
context,
|
|
63
|
+
page,
|
|
64
|
+
browser,
|
|
65
|
+
engine: 'chromium',
|
|
66
|
+
persistence,
|
|
67
|
+
userDataDir,
|
|
68
|
+
async close() {
|
|
69
|
+
if (browser) {
|
|
70
|
+
await browser.close().catch(() => { });
|
|
71
|
+
}
|
|
72
|
+
else {
|
|
73
|
+
await context.close().catch(() => { });
|
|
74
|
+
}
|
|
75
|
+
},
|
|
76
|
+
};
|
|
77
|
+
}
|
|
78
|
+
/**
|
|
79
|
+
* Launches Camoufox browser (Firefox-based anti-detection)
|
|
80
|
+
*
|
|
81
|
+
* Note: When user_data_dir is provided, Camoufox returns a BrowserContext directly
|
|
82
|
+
* (not a Browser). This is different from the ephemeral case where it returns Browser.
|
|
83
|
+
*/
|
|
84
|
+
async function launchCamoufox(config) {
|
|
85
|
+
const { headless, userDataDir, persistence } = config;
|
|
86
|
+
// Desktop-only screen constraints to prevent mobile fingerprints
|
|
87
|
+
const screen = { minWidth: 1024, minHeight: 768 };
|
|
88
|
+
// Dynamic import to avoid loading Camoufox when not needed
|
|
89
|
+
let Camoufox;
|
|
90
|
+
try {
|
|
91
|
+
const camoufoxModule = await import('camoufox-js');
|
|
92
|
+
Camoufox = camoufoxModule.Camoufox;
|
|
93
|
+
}
|
|
94
|
+
catch (error) {
|
|
95
|
+
throw new Error('Camoufox is not available. Run "npx camoufox-js fetch" to download the browser. ' +
|
|
96
|
+
`Error: ${error instanceof Error ? error.message : String(error)}`);
|
|
97
|
+
}
|
|
98
|
+
if (userDataDir) {
|
|
99
|
+
// With user_data_dir, Camoufox returns BrowserContext directly (persistent context)
|
|
100
|
+
// humanize: adds human-like cursor movement delays (up to 2 seconds)
|
|
101
|
+
const context = await Camoufox({
|
|
102
|
+
headless,
|
|
103
|
+
humanize: 2.0,
|
|
104
|
+
screen,
|
|
105
|
+
user_data_dir: userDataDir,
|
|
106
|
+
});
|
|
107
|
+
const page = context.pages()[0] || await context.newPage();
|
|
108
|
+
return {
|
|
109
|
+
context,
|
|
110
|
+
page,
|
|
111
|
+
browser: null, // No browser instance with persistent context
|
|
112
|
+
engine: 'camoufox',
|
|
113
|
+
persistence,
|
|
114
|
+
userDataDir,
|
|
115
|
+
async close() {
|
|
116
|
+
await context.close().catch(() => { });
|
|
117
|
+
},
|
|
118
|
+
};
|
|
119
|
+
}
|
|
120
|
+
// Without user_data_dir, Camoufox returns Browser (ephemeral)
|
|
121
|
+
// humanize: adds human-like cursor movement delays (up to 2 seconds)
|
|
122
|
+
const browser = await Camoufox({
|
|
123
|
+
headless,
|
|
124
|
+
humanize: 2.0,
|
|
125
|
+
screen,
|
|
126
|
+
});
|
|
127
|
+
const context = await browser.newContext();
|
|
128
|
+
const page = await context.newPage();
|
|
129
|
+
return {
|
|
130
|
+
context,
|
|
131
|
+
page,
|
|
132
|
+
browser,
|
|
133
|
+
engine: 'camoufox',
|
|
134
|
+
persistence,
|
|
135
|
+
userDataDir,
|
|
136
|
+
async close() {
|
|
137
|
+
await browser.close().catch(() => { });
|
|
138
|
+
},
|
|
139
|
+
};
|
|
140
|
+
}
|
|
141
|
+
/**
|
|
142
|
+
* Checks if a browser engine is available
|
|
143
|
+
*/
|
|
144
|
+
export async function isBrowserEngineAvailable(engine) {
|
|
145
|
+
if (engine === 'chromium') {
|
|
146
|
+
// Chromium is always available via Playwright
|
|
147
|
+
return true;
|
|
148
|
+
}
|
|
149
|
+
if (engine === 'camoufox') {
|
|
150
|
+
try {
|
|
151
|
+
await import('camoufox-js');
|
|
152
|
+
return true;
|
|
153
|
+
}
|
|
154
|
+
catch {
|
|
155
|
+
return false;
|
|
156
|
+
}
|
|
157
|
+
}
|
|
158
|
+
return false;
|
|
159
|
+
}
|
|
@@ -0,0 +1,49 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Browser data persistence management
|
|
3
|
+
*
|
|
4
|
+
* Handles user data directory resolution for different persistence modes:
|
|
5
|
+
* - none: No persistence, browser uses ephemeral profile
|
|
6
|
+
* - session: Temp directory persistence with automatic cleanup
|
|
7
|
+
* - profile: Pack-local persistent profile
|
|
8
|
+
*/
|
|
9
|
+
import type { BrowserPersistence } from './types.js';
|
|
10
|
+
/**
|
|
11
|
+
* Configuration for resolving browser data directory
|
|
12
|
+
*/
|
|
13
|
+
export interface BrowserDataDirConfig {
|
|
14
|
+
/**
|
|
15
|
+
* Persistence mode
|
|
16
|
+
*/
|
|
17
|
+
persistence: BrowserPersistence;
|
|
18
|
+
/**
|
|
19
|
+
* Session ID (required for 'session' mode)
|
|
20
|
+
*/
|
|
21
|
+
sessionId?: string;
|
|
22
|
+
/**
|
|
23
|
+
* Pack directory path (required for 'profile' mode)
|
|
24
|
+
*/
|
|
25
|
+
packPath?: string;
|
|
26
|
+
}
|
|
27
|
+
/**
|
|
28
|
+
* Resolves the user data directory path based on persistence configuration
|
|
29
|
+
*
|
|
30
|
+
* @param config - Persistence configuration
|
|
31
|
+
* @returns User data directory path, or undefined for 'none' persistence
|
|
32
|
+
*/
|
|
33
|
+
export declare function resolveBrowserDataDir(config: BrowserDataDirConfig): string | undefined;
|
|
34
|
+
/**
|
|
35
|
+
* Cleans up inactive session directories
|
|
36
|
+
*
|
|
37
|
+
* Sessions that haven't been accessed in SESSION_INACTIVITY_MS are removed.
|
|
38
|
+
* Should be called periodically (e.g., on dashboard startup or interval).
|
|
39
|
+
*/
|
|
40
|
+
export declare function cleanupInactiveSessions(): number;
|
|
41
|
+
/**
|
|
42
|
+
* Gets the session base directory path (for testing/debugging)
|
|
43
|
+
*/
|
|
44
|
+
export declare function getSessionBaseDir(): string;
|
|
45
|
+
/**
|
|
46
|
+
* Gets the profile directory path for a pack
|
|
47
|
+
*/
|
|
48
|
+
export declare function getProfileDir(packPath: string): string;
|
|
49
|
+
//# sourceMappingURL=browserPersistence.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"browserPersistence.d.ts","sourceRoot":"","sources":["../src/browserPersistence.ts"],"names":[],"mappings":"AAAA;;;;;;;GAOG;AAKH,OAAO,KAAK,EAAE,kBAAkB,EAAE,MAAM,YAAY,CAAC;AAiBrD;;GAEG;AACH,MAAM,WAAW,oBAAoB;IACnC;;OAEG;IACH,WAAW,EAAE,kBAAkB,CAAC;IAChC;;OAEG;IACH,SAAS,CAAC,EAAE,MAAM,CAAC;IACnB;;OAEG;IACH,QAAQ,CAAC,EAAE,MAAM,CAAC;CACnB;AAED;;;;;GAKG;AACH,wBAAgB,qBAAqB,CAAC,MAAM,EAAE,oBAAoB,GAAG,MAAM,GAAG,SAAS,CAkCtF;AAED;;;;;GAKG;AACH,wBAAgB,uBAAuB,IAAI,MAAM,CAsChD;AAED;;GAEG;AACH,wBAAgB,iBAAiB,IAAI,MAAM,CAE1C;AAED;;GAEG;AACH,wBAAgB,aAAa,CAAC,QAAQ,EAAE,MAAM,GAAG,MAAM,CAEtD"}
|
|
@@ -0,0 +1,143 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Browser data persistence management
|
|
3
|
+
*
|
|
4
|
+
* Handles user data directory resolution for different persistence modes:
|
|
5
|
+
* - none: No persistence, browser uses ephemeral profile
|
|
6
|
+
* - session: Temp directory persistence with automatic cleanup
|
|
7
|
+
* - profile: Pack-local persistent profile
|
|
8
|
+
*/
|
|
9
|
+
import { existsSync, mkdirSync, readdirSync, statSync, rmSync } from 'fs';
|
|
10
|
+
import { join } from 'path';
|
|
11
|
+
import { tmpdir } from 'os';
|
|
12
|
+
/**
|
|
13
|
+
* Session inactivity timeout for cleanup (30 minutes in milliseconds)
|
|
14
|
+
*/
|
|
15
|
+
const SESSION_INACTIVITY_MS = 30 * 60 * 1000;
|
|
16
|
+
/**
|
|
17
|
+
* Base directory name for session storage in temp
|
|
18
|
+
*/
|
|
19
|
+
const SESSION_BASE_DIR = 'showrun-browser-sessions';
|
|
20
|
+
/**
|
|
21
|
+
* Profile directory name within pack directory
|
|
22
|
+
*/
|
|
23
|
+
const PROFILE_DIR_NAME = '.browser-profile';
|
|
24
|
+
/**
|
|
25
|
+
* Resolves the user data directory path based on persistence configuration
|
|
26
|
+
*
|
|
27
|
+
* @param config - Persistence configuration
|
|
28
|
+
* @returns User data directory path, or undefined for 'none' persistence
|
|
29
|
+
*/
|
|
30
|
+
export function resolveBrowserDataDir(config) {
|
|
31
|
+
const { persistence, sessionId, packPath } = config;
|
|
32
|
+
switch (persistence) {
|
|
33
|
+
case 'none':
|
|
34
|
+
return undefined;
|
|
35
|
+
case 'session': {
|
|
36
|
+
if (!sessionId) {
|
|
37
|
+
console.warn('[browserPersistence] Session persistence requires sessionId, falling back to none');
|
|
38
|
+
return undefined;
|
|
39
|
+
}
|
|
40
|
+
const baseDir = join(tmpdir(), SESSION_BASE_DIR);
|
|
41
|
+
ensureDir(baseDir);
|
|
42
|
+
const sessionDir = join(baseDir, sanitizeSessionId(sessionId));
|
|
43
|
+
ensureDir(sessionDir);
|
|
44
|
+
// Touch the directory to update mtime for activity tracking
|
|
45
|
+
touchDirectory(sessionDir);
|
|
46
|
+
return sessionDir;
|
|
47
|
+
}
|
|
48
|
+
case 'profile': {
|
|
49
|
+
if (!packPath) {
|
|
50
|
+
console.warn('[browserPersistence] Profile persistence requires packPath, falling back to none');
|
|
51
|
+
return undefined;
|
|
52
|
+
}
|
|
53
|
+
const profileDir = join(packPath, PROFILE_DIR_NAME);
|
|
54
|
+
ensureDir(profileDir);
|
|
55
|
+
return profileDir;
|
|
56
|
+
}
|
|
57
|
+
default:
|
|
58
|
+
return undefined;
|
|
59
|
+
}
|
|
60
|
+
}
|
|
61
|
+
/**
|
|
62
|
+
* Cleans up inactive session directories
|
|
63
|
+
*
|
|
64
|
+
* Sessions that haven't been accessed in SESSION_INACTIVITY_MS are removed.
|
|
65
|
+
* Should be called periodically (e.g., on dashboard startup or interval).
|
|
66
|
+
*/
|
|
67
|
+
export function cleanupInactiveSessions() {
|
|
68
|
+
const baseDir = join(tmpdir(), SESSION_BASE_DIR);
|
|
69
|
+
if (!existsSync(baseDir)) {
|
|
70
|
+
return 0;
|
|
71
|
+
}
|
|
72
|
+
const now = Date.now();
|
|
73
|
+
let cleanedCount = 0;
|
|
74
|
+
try {
|
|
75
|
+
const entries = readdirSync(baseDir);
|
|
76
|
+
for (const entry of entries) {
|
|
77
|
+
const sessionDir = join(baseDir, entry);
|
|
78
|
+
try {
|
|
79
|
+
const stats = statSync(sessionDir);
|
|
80
|
+
if (!stats.isDirectory())
|
|
81
|
+
continue;
|
|
82
|
+
const lastAccess = stats.mtime.getTime();
|
|
83
|
+
const inactiveMs = now - lastAccess;
|
|
84
|
+
if (inactiveMs > SESSION_INACTIVITY_MS) {
|
|
85
|
+
rmSync(sessionDir, { recursive: true, force: true });
|
|
86
|
+
cleanedCount++;
|
|
87
|
+
console.log(`[browserPersistence] Cleaned up inactive session: ${entry}`);
|
|
88
|
+
}
|
|
89
|
+
}
|
|
90
|
+
catch (error) {
|
|
91
|
+
// Ignore errors for individual sessions (might be in use)
|
|
92
|
+
console.warn(`[browserPersistence] Could not check/clean session ${entry}:`, error);
|
|
93
|
+
}
|
|
94
|
+
}
|
|
95
|
+
}
|
|
96
|
+
catch (error) {
|
|
97
|
+
console.warn('[browserPersistence] Error during session cleanup:', error);
|
|
98
|
+
}
|
|
99
|
+
return cleanedCount;
|
|
100
|
+
}
|
|
101
|
+
/**
|
|
102
|
+
* Gets the session base directory path (for testing/debugging)
|
|
103
|
+
*/
|
|
104
|
+
export function getSessionBaseDir() {
|
|
105
|
+
return join(tmpdir(), SESSION_BASE_DIR);
|
|
106
|
+
}
|
|
107
|
+
/**
|
|
108
|
+
* Gets the profile directory path for a pack
|
|
109
|
+
*/
|
|
110
|
+
export function getProfileDir(packPath) {
|
|
111
|
+
return join(packPath, PROFILE_DIR_NAME);
|
|
112
|
+
}
|
|
113
|
+
/**
|
|
114
|
+
* Ensures a directory exists
|
|
115
|
+
*/
|
|
116
|
+
function ensureDir(dir) {
|
|
117
|
+
if (!existsSync(dir)) {
|
|
118
|
+
mkdirSync(dir, { recursive: true });
|
|
119
|
+
}
|
|
120
|
+
}
|
|
121
|
+
/**
|
|
122
|
+
* Sanitizes a session ID for use as a directory name
|
|
123
|
+
*/
|
|
124
|
+
function sanitizeSessionId(sessionId) {
|
|
125
|
+
// Replace unsafe characters with underscores
|
|
126
|
+
return sessionId.replace(/[^a-zA-Z0-9_-]/g, '_');
|
|
127
|
+
}
|
|
128
|
+
/**
|
|
129
|
+
* Touches a directory to update its mtime
|
|
130
|
+
*/
|
|
131
|
+
function touchDirectory(dir) {
|
|
132
|
+
try {
|
|
133
|
+
const now = new Date();
|
|
134
|
+
// Node doesn't have a direct utimes for directories, but we can use a marker file
|
|
135
|
+
const markerPath = join(dir, '.last_access');
|
|
136
|
+
const fs = require('fs');
|
|
137
|
+
fs.closeSync(fs.openSync(markerPath, 'w'));
|
|
138
|
+
fs.utimesSync(dir, now, now);
|
|
139
|
+
}
|
|
140
|
+
catch {
|
|
141
|
+
// Ignore errors - touch is best-effort for cleanup tracking
|
|
142
|
+
}
|
|
143
|
+
}
|
|
@@ -0,0 +1,10 @@
|
|
|
1
|
+
import type { Browser, Page } from 'playwright';
|
|
2
|
+
import type { Logger, RunContext } from './types.js';
|
|
3
|
+
import type { NetworkCaptureApi } from './networkCapture.js';
|
|
4
|
+
/**
|
|
5
|
+
* Creates a RunContext for task pack execution
|
|
6
|
+
*/
|
|
7
|
+
export declare class RunContextFactory {
|
|
8
|
+
static create(page: Page, browser: Browser, logger: Logger, artifactsDir: string, networkCapture?: NetworkCaptureApi): RunContext;
|
|
9
|
+
}
|
|
10
|
+
//# sourceMappingURL=context.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"context.d.ts","sourceRoot":"","sources":["../src/context.ts"],"names":[],"mappings":"AAEA,OAAO,KAAK,EAAE,OAAO,EAAE,IAAI,EAAE,MAAM,YAAY,CAAC;AAChD,OAAO,KAAK,EAAE,MAAM,EAAmB,UAAU,EAAE,MAAM,YAAY,CAAC;AACtE,OAAO,KAAK,EAAE,iBAAiB,EAAE,MAAM,qBAAqB,CAAC;AAE7D;;GAEG;AACH,qBAAa,iBAAiB;IAC5B,MAAM,CAAC,MAAM,CACX,IAAI,EAAE,IAAI,EACV,OAAO,EAAE,OAAO,EAChB,MAAM,EAAE,MAAM,EACd,YAAY,EAAE,MAAM,EACpB,cAAc,CAAC,EAAE,iBAAiB,GACjC,UAAU;CAyBd"}
|
package/dist/context.js
ADDED
|
@@ -0,0 +1,30 @@
|
|
|
1
|
+
import { writeFileSync, mkdirSync } from 'fs';
|
|
2
|
+
import { join } from 'path';
|
|
3
|
+
/**
|
|
4
|
+
* Creates a RunContext for task pack execution
|
|
5
|
+
*/
|
|
6
|
+
export class RunContextFactory {
|
|
7
|
+
static create(page, browser, logger, artifactsDir, networkCapture) {
|
|
8
|
+
// Ensure artifacts directory exists
|
|
9
|
+
mkdirSync(artifactsDir, { recursive: true });
|
|
10
|
+
const artifacts = {
|
|
11
|
+
async saveScreenshot(name) {
|
|
12
|
+
const path = join(artifactsDir, `${name}.png`);
|
|
13
|
+
await page.screenshot({ path, fullPage: true });
|
|
14
|
+
return path;
|
|
15
|
+
},
|
|
16
|
+
async saveHTML(name, html) {
|
|
17
|
+
const path = join(artifactsDir, `${name}.html`);
|
|
18
|
+
writeFileSync(path, html, 'utf-8');
|
|
19
|
+
return path;
|
|
20
|
+
},
|
|
21
|
+
};
|
|
22
|
+
return {
|
|
23
|
+
page,
|
|
24
|
+
browser,
|
|
25
|
+
logger,
|
|
26
|
+
artifacts,
|
|
27
|
+
networkCapture,
|
|
28
|
+
};
|
|
29
|
+
}
|
|
30
|
+
}
|