@showrun/core 0.1.7 → 0.1.9
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/__tests__/dsl-validation.test.js +185 -0
- package/dist/__tests__/httpReplay.test.js +62 -0
- package/dist/__tests__/proxy.test.d.ts +2 -0
- package/dist/__tests__/proxy.test.d.ts.map +1 -0
- package/dist/__tests__/proxy.test.js +117 -0
- package/dist/__tests__/registry-client.test.d.ts +2 -0
- package/dist/__tests__/registry-client.test.d.ts.map +1 -0
- package/dist/__tests__/registry-client.test.js +228 -0
- package/dist/browserLauncher.d.ts +15 -0
- package/dist/browserLauncher.d.ts.map +1 -1
- package/dist/browserLauncher.js +62 -12
- package/dist/config.d.ts +1 -0
- package/dist/config.d.ts.map +1 -1
- package/dist/config.js +4 -3
- package/dist/dsl/builders.d.ts +22 -1
- package/dist/dsl/builders.d.ts.map +1 -1
- package/dist/dsl/builders.js +23 -0
- package/dist/dsl/interpreter.d.ts +5 -0
- package/dist/dsl/interpreter.d.ts.map +1 -1
- package/dist/dsl/interpreter.js +1 -0
- package/dist/dsl/stepHandlers.d.ts +3 -0
- package/dist/dsl/stepHandlers.d.ts.map +1 -1
- package/dist/dsl/stepHandlers.js +62 -2
- package/dist/dsl/types.d.ts +53 -1
- package/dist/dsl/types.d.ts.map +1 -1
- package/dist/dsl/validation.d.ts.map +1 -1
- package/dist/dsl/validation.js +90 -1
- package/dist/httpReplay.d.ts +5 -0
- package/dist/httpReplay.d.ts.map +1 -1
- package/dist/httpReplay.js +46 -2
- package/dist/index.d.ts +1 -0
- package/dist/index.d.ts.map +1 -1
- package/dist/index.js +2 -0
- package/dist/jsonPackValidator.js +1 -1
- package/dist/proxy/index.d.ts +4 -0
- package/dist/proxy/index.d.ts.map +1 -0
- package/dist/proxy/index.js +3 -0
- package/dist/proxy/oxylabs.d.ts +15 -0
- package/dist/proxy/oxylabs.d.ts.map +1 -0
- package/dist/proxy/oxylabs.js +34 -0
- package/dist/proxy/proxyService.d.ts +34 -0
- package/dist/proxy/proxyService.d.ts.map +1 -0
- package/dist/proxy/proxyService.js +69 -0
- package/dist/proxy/types.d.ts +59 -0
- package/dist/proxy/types.d.ts.map +1 -0
- package/dist/proxy/types.js +4 -0
- package/dist/registry/client.d.ts +33 -0
- package/dist/registry/client.d.ts.map +1 -0
- package/dist/registry/client.js +261 -0
- package/dist/registry/index.d.ts +4 -0
- package/dist/registry/index.d.ts.map +1 -0
- package/dist/registry/index.js +3 -0
- package/dist/registry/tokenStore.d.ts +13 -0
- package/dist/registry/tokenStore.d.ts.map +1 -0
- package/dist/registry/tokenStore.js +54 -0
- package/dist/registry/types.d.ts +110 -0
- package/dist/registry/types.d.ts.map +1 -0
- package/dist/registry/types.js +4 -0
- package/dist/runner.d.ts +4 -0
- package/dist/runner.d.ts.map +1 -1
- package/dist/runner.js +18 -8
- package/dist/types.d.ts +6 -0
- package/dist/types.d.ts.map +1 -1
- package/package.json +1 -1
|
@@ -0,0 +1,261 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Registry client for ShowRun pack registry.
|
|
3
|
+
*
|
|
4
|
+
* Communicates with the registry REST API to authenticate, publish, search,
|
|
5
|
+
* and install task packs. Uses the global token store for persistence and
|
|
6
|
+
* automatically refreshes access tokens before they expire.
|
|
7
|
+
*/
|
|
8
|
+
import { join } from 'path';
|
|
9
|
+
import { TaskPackLoader } from '../loader.js';
|
|
10
|
+
import { readJsonFile, ensureDir, writeTaskPackManifest, writeFlowJson } from '../packUtils.js';
|
|
11
|
+
import { loadTokens, saveTokens, clearTokens } from './tokenStore.js';
|
|
12
|
+
// ── Error class ───────────────────────────────────────────────────────────
|
|
13
|
+
export class RegistryError extends Error {
|
|
14
|
+
status;
|
|
15
|
+
body;
|
|
16
|
+
constructor(message, status, body) {
|
|
17
|
+
super(message);
|
|
18
|
+
this.status = status;
|
|
19
|
+
this.body = body;
|
|
20
|
+
this.name = 'RegistryError';
|
|
21
|
+
}
|
|
22
|
+
}
|
|
23
|
+
// ── JWT helpers ───────────────────────────────────────────────────────────
|
|
24
|
+
function decodeJwtPayload(token) {
|
|
25
|
+
try {
|
|
26
|
+
const parts = token.split('.');
|
|
27
|
+
if (parts.length !== 3)
|
|
28
|
+
return null;
|
|
29
|
+
const payload = Buffer.from(parts[1], 'base64url').toString('utf-8');
|
|
30
|
+
return JSON.parse(payload);
|
|
31
|
+
}
|
|
32
|
+
catch {
|
|
33
|
+
return null;
|
|
34
|
+
}
|
|
35
|
+
}
|
|
36
|
+
function tokenExpiresWithin(token, seconds) {
|
|
37
|
+
const payload = decodeJwtPayload(token);
|
|
38
|
+
if (!payload || typeof payload.exp !== 'number')
|
|
39
|
+
return true; // assume expired
|
|
40
|
+
const expiresAt = payload.exp * 1000;
|
|
41
|
+
return Date.now() + seconds * 1000 >= expiresAt;
|
|
42
|
+
}
|
|
43
|
+
// ── RegistryClient ────────────────────────────────────────────────────────
|
|
44
|
+
export class RegistryClient {
|
|
45
|
+
registryUrl;
|
|
46
|
+
constructor(registryUrl) {
|
|
47
|
+
const url = registryUrl || process.env.SHOWRUN_REGISTRY_URL;
|
|
48
|
+
if (!url) {
|
|
49
|
+
throw new RegistryError('Registry not configured. Set SHOWRUN_REGISTRY_URL or registry.url in config.json.', 0);
|
|
50
|
+
}
|
|
51
|
+
// Strip trailing slash
|
|
52
|
+
this.registryUrl = url.replace(/\/+$/, '');
|
|
53
|
+
}
|
|
54
|
+
// ── Auth (OAuth Device Flow — RFC 8628) ────────────────────────────────
|
|
55
|
+
async startDeviceLogin() {
|
|
56
|
+
return this.request('POST', '/api/auth/device', {}, false);
|
|
57
|
+
}
|
|
58
|
+
async pollDeviceLogin(deviceCode) {
|
|
59
|
+
const url = `${this.registryUrl}/api/auth/device/token`;
|
|
60
|
+
const res = await fetch(url, {
|
|
61
|
+
method: 'POST',
|
|
62
|
+
headers: { 'Content-Type': 'application/json' },
|
|
63
|
+
body: JSON.stringify({ deviceCode }),
|
|
64
|
+
});
|
|
65
|
+
if (res.status === 428 || res.status === 400) {
|
|
66
|
+
// authorization_pending or slow_down — user hasn't approved yet
|
|
67
|
+
const body = await res.json().catch(() => ({}));
|
|
68
|
+
const error = body.error;
|
|
69
|
+
if (error === 'expired') {
|
|
70
|
+
return { status: 'expired' };
|
|
71
|
+
}
|
|
72
|
+
return { status: 'pending' };
|
|
73
|
+
}
|
|
74
|
+
if (!res.ok) {
|
|
75
|
+
let errBody;
|
|
76
|
+
try {
|
|
77
|
+
errBody = await res.json();
|
|
78
|
+
}
|
|
79
|
+
catch {
|
|
80
|
+
errBody = '';
|
|
81
|
+
}
|
|
82
|
+
const message = (errBody && typeof errBody === 'object' && 'message' in errBody
|
|
83
|
+
? String(errBody.message)
|
|
84
|
+
: null) || `Device token request failed (${res.status})`;
|
|
85
|
+
throw new RegistryError(message, res.status, errBody);
|
|
86
|
+
}
|
|
87
|
+
const data = (await res.json());
|
|
88
|
+
// Store tokens
|
|
89
|
+
saveTokens({
|
|
90
|
+
accessToken: data.accessToken,
|
|
91
|
+
refreshToken: data.refreshToken,
|
|
92
|
+
user: data.user,
|
|
93
|
+
registryUrl: this.registryUrl,
|
|
94
|
+
savedAt: new Date().toISOString(),
|
|
95
|
+
});
|
|
96
|
+
return {
|
|
97
|
+
status: 'complete',
|
|
98
|
+
accessToken: data.accessToken,
|
|
99
|
+
refreshToken: data.refreshToken,
|
|
100
|
+
user: data.user,
|
|
101
|
+
};
|
|
102
|
+
}
|
|
103
|
+
async logout() {
|
|
104
|
+
clearTokens();
|
|
105
|
+
}
|
|
106
|
+
async whoami() {
|
|
107
|
+
return this.request('GET', '/api/auth/me', undefined, true);
|
|
108
|
+
}
|
|
109
|
+
isAuthenticated() {
|
|
110
|
+
const tokens = loadTokens();
|
|
111
|
+
return tokens !== null && tokens.registryUrl === this.registryUrl;
|
|
112
|
+
}
|
|
113
|
+
// ── Packs ─────────────────────────────────────────────────────────────
|
|
114
|
+
async publishPack(params) {
|
|
115
|
+
const { packPath, slug: userSlug, visibility = 'public', changelog } = params;
|
|
116
|
+
const warnings = [];
|
|
117
|
+
// Load local pack
|
|
118
|
+
const manifest = TaskPackLoader.loadManifest(packPath);
|
|
119
|
+
const flowPath = join(packPath, 'flow.json');
|
|
120
|
+
const flowData = readJsonFile(flowPath);
|
|
121
|
+
const slug = userSlug || manifest.id;
|
|
122
|
+
// Try to get existing pack; create if 404
|
|
123
|
+
let created = false;
|
|
124
|
+
try {
|
|
125
|
+
await this.request('GET', `/api/packs/${slug}`, undefined, true);
|
|
126
|
+
}
|
|
127
|
+
catch (err) {
|
|
128
|
+
if (err instanceof RegistryError && err.status === 404) {
|
|
129
|
+
await this.request('POST', '/api/packs', {
|
|
130
|
+
slug,
|
|
131
|
+
name: manifest.name,
|
|
132
|
+
description: manifest.description || '',
|
|
133
|
+
visibility,
|
|
134
|
+
}, true);
|
|
135
|
+
created = true;
|
|
136
|
+
}
|
|
137
|
+
else {
|
|
138
|
+
throw err;
|
|
139
|
+
}
|
|
140
|
+
}
|
|
141
|
+
// Publish version
|
|
142
|
+
const versionData = await this.request('POST', `/api/packs/${slug}/versions`, {
|
|
143
|
+
version: manifest.version,
|
|
144
|
+
manifest: {
|
|
145
|
+
id: manifest.id,
|
|
146
|
+
name: manifest.name,
|
|
147
|
+
version: manifest.version,
|
|
148
|
+
description: manifest.description,
|
|
149
|
+
kind: manifest.kind,
|
|
150
|
+
},
|
|
151
|
+
flow: flowData,
|
|
152
|
+
changelog,
|
|
153
|
+
}, true);
|
|
154
|
+
return {
|
|
155
|
+
slug,
|
|
156
|
+
version: versionData.version,
|
|
157
|
+
created,
|
|
158
|
+
warnings,
|
|
159
|
+
};
|
|
160
|
+
}
|
|
161
|
+
async searchPacks(query) {
|
|
162
|
+
const params = new URLSearchParams();
|
|
163
|
+
if (query.q)
|
|
164
|
+
params.set('q', query.q);
|
|
165
|
+
if (query.page)
|
|
166
|
+
params.set('page', String(query.page));
|
|
167
|
+
if (query.limit)
|
|
168
|
+
params.set('limit', String(query.limit));
|
|
169
|
+
const qs = params.toString();
|
|
170
|
+
const path = `/api/packs${qs ? `?${qs}` : ''}`;
|
|
171
|
+
return this.request('GET', path, undefined, false);
|
|
172
|
+
}
|
|
173
|
+
async installPack(slug, destDir, version) {
|
|
174
|
+
// Get pack detail
|
|
175
|
+
const detail = await this.request('GET', `/api/packs/${slug}`, undefined, false);
|
|
176
|
+
// Determine version to install
|
|
177
|
+
const targetVersion = version || detail.latestVersion;
|
|
178
|
+
if (!targetVersion) {
|
|
179
|
+
throw new RegistryError(`Pack "${slug}" has no published versions`, 404);
|
|
180
|
+
}
|
|
181
|
+
// Get version data (manifest + flow)
|
|
182
|
+
const versionData = await this.request('GET', `/api/packs/${slug}/versions/${targetVersion}`, undefined, false);
|
|
183
|
+
// Write to local directory
|
|
184
|
+
const packDir = join(destDir, slug);
|
|
185
|
+
ensureDir(packDir);
|
|
186
|
+
writeTaskPackManifest(packDir, versionData.manifest);
|
|
187
|
+
writeFlowJson(packDir, versionData.flow);
|
|
188
|
+
}
|
|
189
|
+
// ── Internal request helper ───────────────────────────────────────────
|
|
190
|
+
async request(method, path, body, authenticated = false) {
|
|
191
|
+
const url = `${this.registryUrl}${path}`;
|
|
192
|
+
const headers = {
|
|
193
|
+
'Content-Type': 'application/json',
|
|
194
|
+
};
|
|
195
|
+
if (authenticated) {
|
|
196
|
+
const accessToken = await this.getValidAccessToken();
|
|
197
|
+
headers['Authorization'] = `Bearer ${accessToken}`;
|
|
198
|
+
}
|
|
199
|
+
const res = await fetch(url, {
|
|
200
|
+
method,
|
|
201
|
+
headers,
|
|
202
|
+
body: body ? JSON.stringify(body) : undefined,
|
|
203
|
+
});
|
|
204
|
+
if (!res.ok) {
|
|
205
|
+
let errBody;
|
|
206
|
+
try {
|
|
207
|
+
errBody = await res.json();
|
|
208
|
+
}
|
|
209
|
+
catch {
|
|
210
|
+
errBody = await res.text().catch(() => '');
|
|
211
|
+
}
|
|
212
|
+
const message = (errBody && typeof errBody === 'object' && 'message' in errBody
|
|
213
|
+
? String(errBody.message)
|
|
214
|
+
: null) || `Registry request failed: ${method} ${path} (${res.status})`;
|
|
215
|
+
throw new RegistryError(message, res.status, errBody);
|
|
216
|
+
}
|
|
217
|
+
return (await res.json());
|
|
218
|
+
}
|
|
219
|
+
/**
|
|
220
|
+
* Get a valid access token, refreshing if it's about to expire (within 60s).
|
|
221
|
+
* If refresh fails, clears tokens and throws.
|
|
222
|
+
*/
|
|
223
|
+
async getValidAccessToken() {
|
|
224
|
+
const auth = loadTokens();
|
|
225
|
+
if (!auth) {
|
|
226
|
+
throw new RegistryError('Not logged in. Run `showrun registry login` first.', 401);
|
|
227
|
+
}
|
|
228
|
+
// Check if token is still valid (with 60s buffer)
|
|
229
|
+
if (!tokenExpiresWithin(auth.accessToken, 60)) {
|
|
230
|
+
return auth.accessToken;
|
|
231
|
+
}
|
|
232
|
+
// Token expired or about to expire — refresh
|
|
233
|
+
try {
|
|
234
|
+
const data = await this.refreshAccessToken(auth);
|
|
235
|
+
// Update stored tokens with new access token
|
|
236
|
+
saveTokens({
|
|
237
|
+
...auth,
|
|
238
|
+
accessToken: data.accessToken,
|
|
239
|
+
savedAt: new Date().toISOString(),
|
|
240
|
+
});
|
|
241
|
+
return data.accessToken;
|
|
242
|
+
}
|
|
243
|
+
catch {
|
|
244
|
+
// Refresh failed — clear tokens, user needs to log in again
|
|
245
|
+
clearTokens();
|
|
246
|
+
throw new RegistryError('Session expired. Run `showrun registry login` to authenticate again.', 401);
|
|
247
|
+
}
|
|
248
|
+
}
|
|
249
|
+
async refreshAccessToken(auth) {
|
|
250
|
+
const url = `${this.registryUrl}/api/auth/refresh`;
|
|
251
|
+
const res = await fetch(url, {
|
|
252
|
+
method: 'POST',
|
|
253
|
+
headers: { 'Content-Type': 'application/json' },
|
|
254
|
+
body: JSON.stringify({ refreshToken: auth.refreshToken }),
|
|
255
|
+
});
|
|
256
|
+
if (!res.ok) {
|
|
257
|
+
throw new RegistryError('Token refresh failed', res.status);
|
|
258
|
+
}
|
|
259
|
+
return (await res.json());
|
|
260
|
+
}
|
|
261
|
+
}
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../../src/registry/index.ts"],"names":[],"mappings":"AAAA,cAAc,YAAY,CAAC;AAC3B,cAAc,iBAAiB,CAAC;AAChC,OAAO,EAAE,cAAc,EAAE,aAAa,EAAE,MAAM,aAAa,CAAC"}
|
|
@@ -0,0 +1,13 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Persistent token storage for registry authentication.
|
|
3
|
+
*
|
|
4
|
+
* Tokens are stored in `auth.json` inside the global config directory
|
|
5
|
+
* (`~/.config/showrun/auth.json` on Linux/macOS, `%APPDATA%\showrun\auth.json`
|
|
6
|
+
* on Windows). File permissions are set to 0o600 on Unix to prevent other
|
|
7
|
+
* users from reading credentials.
|
|
8
|
+
*/
|
|
9
|
+
import type { StoredAuth } from './types.js';
|
|
10
|
+
export declare function loadTokens(): StoredAuth | null;
|
|
11
|
+
export declare function saveTokens(auth: StoredAuth): void;
|
|
12
|
+
export declare function clearTokens(): void;
|
|
13
|
+
//# sourceMappingURL=tokenStore.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"tokenStore.d.ts","sourceRoot":"","sources":["../../src/registry/tokenStore.ts"],"names":[],"mappings":"AAAA;;;;;;;GAOG;AAOH,OAAO,KAAK,EAAE,UAAU,EAAE,MAAM,YAAY,CAAC;AAQ7C,wBAAgB,UAAU,IAAI,UAAU,GAAG,IAAI,CAS9C;AAED,wBAAgB,UAAU,CAAC,IAAI,EAAE,UAAU,GAAG,IAAI,CAejD;AAED,wBAAgB,WAAW,IAAI,IAAI,CASlC"}
|
|
@@ -0,0 +1,54 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Persistent token storage for registry authentication.
|
|
3
|
+
*
|
|
4
|
+
* Tokens are stored in `auth.json` inside the global config directory
|
|
5
|
+
* (`~/.config/showrun/auth.json` on Linux/macOS, `%APPDATA%\showrun\auth.json`
|
|
6
|
+
* on Windows). File permissions are set to 0o600 on Unix to prevent other
|
|
7
|
+
* users from reading credentials.
|
|
8
|
+
*/
|
|
9
|
+
import { existsSync, chmodSync, unlinkSync } from 'fs';
|
|
10
|
+
import { join } from 'path';
|
|
11
|
+
import { platform } from 'os';
|
|
12
|
+
import { getGlobalConfigDir } from '../config.js';
|
|
13
|
+
import { ensureDir, atomicWrite, readJsonFile } from '../packUtils.js';
|
|
14
|
+
const AUTH_FILENAME = 'auth.json';
|
|
15
|
+
function getAuthPath() {
|
|
16
|
+
return join(getGlobalConfigDir(), AUTH_FILENAME);
|
|
17
|
+
}
|
|
18
|
+
export function loadTokens() {
|
|
19
|
+
const authPath = getAuthPath();
|
|
20
|
+
if (!existsSync(authPath))
|
|
21
|
+
return null;
|
|
22
|
+
try {
|
|
23
|
+
return readJsonFile(authPath);
|
|
24
|
+
}
|
|
25
|
+
catch {
|
|
26
|
+
return null;
|
|
27
|
+
}
|
|
28
|
+
}
|
|
29
|
+
export function saveTokens(auth) {
|
|
30
|
+
const configDir = getGlobalConfigDir();
|
|
31
|
+
ensureDir(configDir);
|
|
32
|
+
const authPath = join(configDir, AUTH_FILENAME);
|
|
33
|
+
atomicWrite(authPath, JSON.stringify(auth, null, 2) + '\n');
|
|
34
|
+
// Restrict file permissions on Unix (owner-only read/write)
|
|
35
|
+
if (platform() !== 'win32') {
|
|
36
|
+
try {
|
|
37
|
+
chmodSync(authPath, 0o600);
|
|
38
|
+
}
|
|
39
|
+
catch {
|
|
40
|
+
// Ignore permission errors (e.g. on some CI environments)
|
|
41
|
+
}
|
|
42
|
+
}
|
|
43
|
+
}
|
|
44
|
+
export function clearTokens() {
|
|
45
|
+
const authPath = getAuthPath();
|
|
46
|
+
if (existsSync(authPath)) {
|
|
47
|
+
try {
|
|
48
|
+
unlinkSync(authPath);
|
|
49
|
+
}
|
|
50
|
+
catch {
|
|
51
|
+
// Ignore if file is already gone
|
|
52
|
+
}
|
|
53
|
+
}
|
|
54
|
+
}
|
|
@@ -0,0 +1,110 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Registry API types — mirrors @showrun-registry/shared without taking a dependency.
|
|
3
|
+
*/
|
|
4
|
+
export interface UserProfile {
|
|
5
|
+
id: string;
|
|
6
|
+
username: string;
|
|
7
|
+
email: string;
|
|
8
|
+
displayName?: string;
|
|
9
|
+
}
|
|
10
|
+
/** Response from POST /api/auth/device — starts device authorization flow */
|
|
11
|
+
export interface DeviceCodeResponse {
|
|
12
|
+
deviceCode: string;
|
|
13
|
+
userCode: string;
|
|
14
|
+
verificationUri: string;
|
|
15
|
+
expiresIn: number;
|
|
16
|
+
interval: number;
|
|
17
|
+
}
|
|
18
|
+
/** Successful response from POST /api/auth/device/token after user approves */
|
|
19
|
+
export interface DeviceTokenResponse {
|
|
20
|
+
accessToken: string;
|
|
21
|
+
refreshToken: string;
|
|
22
|
+
user: UserProfile;
|
|
23
|
+
}
|
|
24
|
+
/**
|
|
25
|
+
* Result of polling the device token endpoint.
|
|
26
|
+
* `status` is 'pending' while the user hasn't approved yet,
|
|
27
|
+
* 'complete' with tokens on success, or 'expired' if the code timed out.
|
|
28
|
+
*/
|
|
29
|
+
export type DevicePollResult = {
|
|
30
|
+
status: 'pending';
|
|
31
|
+
} | {
|
|
32
|
+
status: 'expired';
|
|
33
|
+
} | {
|
|
34
|
+
status: 'complete';
|
|
35
|
+
accessToken: string;
|
|
36
|
+
refreshToken: string;
|
|
37
|
+
user: UserProfile;
|
|
38
|
+
};
|
|
39
|
+
export interface RegistryRefreshResponse {
|
|
40
|
+
accessToken: string;
|
|
41
|
+
}
|
|
42
|
+
export interface StoredAuth {
|
|
43
|
+
accessToken: string;
|
|
44
|
+
refreshToken: string;
|
|
45
|
+
user: UserProfile;
|
|
46
|
+
registryUrl: string;
|
|
47
|
+
/** ISO timestamp when auth was saved */
|
|
48
|
+
savedAt: string;
|
|
49
|
+
}
|
|
50
|
+
export interface PackSummary {
|
|
51
|
+
id: string;
|
|
52
|
+
slug: string;
|
|
53
|
+
name: string;
|
|
54
|
+
description?: string;
|
|
55
|
+
visibility: 'public' | 'private';
|
|
56
|
+
latestVersion?: string;
|
|
57
|
+
owner: {
|
|
58
|
+
id: string;
|
|
59
|
+
username: string;
|
|
60
|
+
};
|
|
61
|
+
createdAt: string;
|
|
62
|
+
updatedAt: string;
|
|
63
|
+
}
|
|
64
|
+
export interface PackVersionSummary {
|
|
65
|
+
version: string;
|
|
66
|
+
changelog?: string;
|
|
67
|
+
createdAt: string;
|
|
68
|
+
}
|
|
69
|
+
export interface PackDetail extends PackSummary {
|
|
70
|
+
versions: PackVersionSummary[];
|
|
71
|
+
}
|
|
72
|
+
export interface PaginatedResponse<T> {
|
|
73
|
+
data: T[];
|
|
74
|
+
total: number;
|
|
75
|
+
page: number;
|
|
76
|
+
limit: number;
|
|
77
|
+
totalPages: number;
|
|
78
|
+
}
|
|
79
|
+
export interface PublishParams {
|
|
80
|
+
/** Local pack directory path */
|
|
81
|
+
packPath: string;
|
|
82
|
+
/** Registry slug (defaults to pack ID) */
|
|
83
|
+
slug?: string;
|
|
84
|
+
/** Visibility: public or private */
|
|
85
|
+
visibility?: 'public' | 'private';
|
|
86
|
+
/** Changelog for this version */
|
|
87
|
+
changelog?: string;
|
|
88
|
+
}
|
|
89
|
+
export interface PublishResult {
|
|
90
|
+
slug: string;
|
|
91
|
+
version: string;
|
|
92
|
+
created: boolean;
|
|
93
|
+
warnings: string[];
|
|
94
|
+
}
|
|
95
|
+
export interface SearchQuery {
|
|
96
|
+
q?: string;
|
|
97
|
+
page?: number;
|
|
98
|
+
limit?: number;
|
|
99
|
+
}
|
|
100
|
+
export interface IRegistryClient {
|
|
101
|
+
startDeviceLogin(): Promise<DeviceCodeResponse>;
|
|
102
|
+
pollDeviceLogin(deviceCode: string): Promise<DevicePollResult>;
|
|
103
|
+
logout(): Promise<void>;
|
|
104
|
+
whoami(): Promise<UserProfile>;
|
|
105
|
+
isAuthenticated(): boolean;
|
|
106
|
+
publishPack(params: PublishParams): Promise<PublishResult>;
|
|
107
|
+
searchPacks(query: SearchQuery): Promise<PaginatedResponse<PackSummary>>;
|
|
108
|
+
installPack(slug: string, destDir: string, version?: string): Promise<void>;
|
|
109
|
+
}
|
|
110
|
+
//# sourceMappingURL=types.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"types.d.ts","sourceRoot":"","sources":["../../src/registry/types.ts"],"names":[],"mappings":"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"}
|
package/dist/runner.d.ts
CHANGED
|
@@ -36,6 +36,10 @@ export interface RunTaskPackOptions {
|
|
|
36
36
|
* Pre-loaded secrets (if not provided, will be loaded from packPath)
|
|
37
37
|
*/
|
|
38
38
|
secrets?: Record<string, string>;
|
|
39
|
+
/**
|
|
40
|
+
* Skip HTTP-only replay mode and always use browser execution
|
|
41
|
+
*/
|
|
42
|
+
skipHttpReplay?: boolean;
|
|
39
43
|
}
|
|
40
44
|
/**
|
|
41
45
|
* Result of running a task pack with paths
|
package/dist/runner.d.ts.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"runner.d.ts","sourceRoot":"","sources":["../src/runner.ts"],"names":[],"mappings":"AAGA,OAAO,KAAK,EAAE,QAAQ,EAAE,SAAS,EAAc,MAAM,YAAY,CAAC;AAElE,OAAO,KAAK,EAAE,MAAM,EAAE,MAAM,YAAY,CAAC;
|
|
1
|
+
{"version":3,"file":"runner.d.ts","sourceRoot":"","sources":["../src/runner.ts"],"names":[],"mappings":"AAGA,OAAO,KAAK,EAAE,QAAQ,EAAE,SAAS,EAAc,MAAM,YAAY,CAAC;AAElE,OAAO,KAAK,EAAE,MAAM,EAAE,MAAM,YAAY,CAAC;AAazC;;GAEG;AACH,MAAM,WAAW,kBAAkB;IACjC;;OAEG;IACH,MAAM,EAAE,MAAM,CAAC;IACf;;OAEG;IACH,MAAM,EAAE,MAAM,CAAC;IACf;;OAEG;IACH,QAAQ,CAAC,EAAE,OAAO,CAAC;IACnB;;OAEG;IACH,SAAS,CAAC,EAAE,MAAM,CAAC;IACnB;;OAEG;IACH,SAAS,CAAC,EAAE,MAAM,CAAC;IACnB;;OAEG;IACH,QAAQ,CAAC,EAAE,MAAM,CAAC;IAClB;;OAEG;IACH,QAAQ,CAAC,EAAE,MAAM,CAAC;IAClB;;OAEG;IACH,OAAO,CAAC,EAAE,MAAM,CAAC,MAAM,EAAE,MAAM,CAAC,CAAC;IACjC;;OAEG;IACH,cAAc,CAAC,EAAE,OAAO,CAAC;CAC1B;AAED;;GAEG;AACH,MAAM,WAAW,iBAAkB,SAAQ,SAAS;IAClD;;OAEG;IACH,MAAM,EAAE,MAAM,CAAC;IACf;;OAEG;IACH,UAAU,EAAE,MAAM,CAAC;IACnB;;OAEG;IACH,YAAY,EAAE,MAAM,CAAC;CACtB;AAED;;;GAGG;AACH,wBAAsB,WAAW,CAC/B,QAAQ,EAAE,QAAQ,EAClB,MAAM,EAAE,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,EAC/B,OAAO,EAAE,kBAAkB,GAC1B,OAAO,CAAC,iBAAiB,CAAC,CA6Q5B"}
|
package/dist/runner.js
CHANGED
|
@@ -3,6 +3,7 @@ import { join } from 'path';
|
|
|
3
3
|
import { InputValidator, RunContextFactory, runFlow, attachNetworkCapture, TaskPackLoader } from './index.js';
|
|
4
4
|
import { launchBrowser } from './browserLauncher.js';
|
|
5
5
|
import { isFlowHttpCompatible } from './httpReplay.js';
|
|
6
|
+
import { resolveProxy } from './proxy/proxyService.js';
|
|
6
7
|
import { writeSnapshots, extractTopLevelKeys, detectSensitiveHeaders, } from './requestSnapshot.js';
|
|
7
8
|
/**
|
|
8
9
|
* Runs a task pack with Playwright
|
|
@@ -15,12 +16,14 @@ export async function runTaskPack(taskPack, inputs, options) {
|
|
|
15
16
|
// Ensure directories exist
|
|
16
17
|
mkdirSync(runDir, { recursive: true });
|
|
17
18
|
mkdirSync(artifactsDir, { recursive: true });
|
|
18
|
-
// Auto-detect if we can run headful
|
|
19
|
-
//
|
|
20
|
-
|
|
19
|
+
// Auto-detect if we can run headful
|
|
20
|
+
// On Linux, a DISPLAY (X11) or WAYLAND_DISPLAY is required for headful mode.
|
|
21
|
+
// On macOS/Windows, native window management handles it — no env var needed.
|
|
22
|
+
const isLinux = process.platform === 'linux';
|
|
23
|
+
const hasDisplay = !isLinux || !!process.env.DISPLAY || !!process.env.WAYLAND_DISPLAY;
|
|
21
24
|
const headless = requestedHeadless || !hasDisplay;
|
|
22
25
|
if (!requestedHeadless && !hasDisplay) {
|
|
23
|
-
console.error('[Warning] Headful mode requested but no DISPLAY environment variable found. ' +
|
|
26
|
+
console.error('[Warning] Headful mode requested but no DISPLAY/WAYLAND_DISPLAY environment variable found. ' +
|
|
24
27
|
'Falling back to headless mode. Set DISPLAY or use xvfb-run to enable headful mode.');
|
|
25
28
|
}
|
|
26
29
|
const startTime = Date.now();
|
|
@@ -29,9 +32,14 @@ export async function runTaskPack(taskPack, inputs, options) {
|
|
|
29
32
|
InputValidator.validate(inputsWithDefaults, taskPack.inputs);
|
|
30
33
|
// Load secrets early (needed for both modes)
|
|
31
34
|
const secrets = providedSecrets ?? (packPath ? TaskPackLoader.loadSecrets(packPath) : {});
|
|
35
|
+
// ─── Resolve proxy ──────────────────────────────────────────────────
|
|
36
|
+
const resolvedProxy = resolveProxy(taskPack.browser?.proxy);
|
|
37
|
+
if (taskPack.browser?.proxy?.enabled && !resolvedProxy) {
|
|
38
|
+
console.log('[runner] Proxy enabled in pack but credentials not configured, running without proxy');
|
|
39
|
+
}
|
|
32
40
|
// ─── HTTP-first execution ───────────────────────────────────────────
|
|
33
41
|
const snapshots = taskPack.snapshots ?? null;
|
|
34
|
-
if (isFlowHttpCompatible(taskPack.flow, snapshots)) {
|
|
42
|
+
if (!options.skipHttpReplay && isFlowHttpCompatible(taskPack.flow, snapshots)) {
|
|
35
43
|
logger.log({
|
|
36
44
|
type: 'run_started',
|
|
37
45
|
data: {
|
|
@@ -41,7 +49,7 @@ export async function runTaskPack(taskPack, inputs, options) {
|
|
|
41
49
|
},
|
|
42
50
|
});
|
|
43
51
|
try {
|
|
44
|
-
const httpResult = await runHttpOnly(taskPack, inputsWithDefaults, snapshots, secrets, logger, options);
|
|
52
|
+
const httpResult = await runHttpOnly(taskPack, inputsWithDefaults, snapshots, secrets, logger, options, resolvedProxy);
|
|
45
53
|
const durationMs = Date.now() - startTime;
|
|
46
54
|
logger.log({ type: 'run_finished', data: { success: true, durationMs } });
|
|
47
55
|
return { ...httpResult, runDir, eventsPath, artifactsDir };
|
|
@@ -58,7 +66,7 @@ export async function runTaskPack(taskPack, inputs, options) {
|
|
|
58
66
|
let runContext = null;
|
|
59
67
|
try {
|
|
60
68
|
// Log run start (only if not already logged above)
|
|
61
|
-
if (!isFlowHttpCompatible(taskPack.flow, snapshots)) {
|
|
69
|
+
if (options.skipHttpReplay || !isFlowHttpCompatible(taskPack.flow, snapshots)) {
|
|
62
70
|
logger.log({
|
|
63
71
|
type: 'run_started',
|
|
64
72
|
data: {
|
|
@@ -74,6 +82,7 @@ export async function runTaskPack(taskPack, inputs, options) {
|
|
|
74
82
|
headless,
|
|
75
83
|
sessionId: options.sessionId,
|
|
76
84
|
packPath: options.packPath ?? options.cacheDir,
|
|
85
|
+
proxy: resolvedProxy ?? undefined,
|
|
77
86
|
});
|
|
78
87
|
page = browserSession.page;
|
|
79
88
|
// Attach network capture (rolling buffer, redacted for logs; full headers in-memory for replay only)
|
|
@@ -230,7 +239,7 @@ export async function runTaskPack(taskPack, inputs, options) {
|
|
|
230
239
|
* No browser is launched; network_replay steps use Node fetch().
|
|
231
240
|
* Throws if any snapshot response fails validation (caller should fall back to browser mode).
|
|
232
241
|
*/
|
|
233
|
-
async function runHttpOnly(taskPack, inputs, snapshots, secrets, logger, options) {
|
|
242
|
+
async function runHttpOnly(taskPack, inputs, snapshots, secrets, logger, options, proxy) {
|
|
234
243
|
console.log(`[runner] Running in HTTP-only mode (${Object.keys(snapshots.snapshots).length} snapshots)`);
|
|
235
244
|
// Build a minimal RunContext that doesn't require a browser.
|
|
236
245
|
// In HTTP mode the interpreter skips all DOM steps, so page/browser are never accessed.
|
|
@@ -255,6 +264,7 @@ async function runHttpOnly(taskPack, inputs, snapshots, secrets, logger, options
|
|
|
255
264
|
secrets,
|
|
256
265
|
httpMode: true,
|
|
257
266
|
snapshots,
|
|
267
|
+
proxy: proxy ?? undefined,
|
|
258
268
|
});
|
|
259
269
|
// Validate responses: re-check each network_replay step's snapshot validation.
|
|
260
270
|
// The actual validation happens inside the step handler via replayFromSnapshot +
|
package/dist/types.d.ts
CHANGED
|
@@ -2,6 +2,7 @@ import type { Browser, Page } from 'playwright';
|
|
|
2
2
|
import type { DslStep } from './dsl/types.js';
|
|
3
3
|
import type { NetworkCaptureApi } from './networkCapture.js';
|
|
4
4
|
import type { SnapshotFile } from './requestSnapshot.js';
|
|
5
|
+
import type { ProxyConfig } from './proxy/types.js';
|
|
5
6
|
/**
|
|
6
7
|
* Primitive types supported in input/collectible schemas
|
|
7
8
|
*/
|
|
@@ -40,6 +41,11 @@ export interface BrowserSettings {
|
|
|
40
41
|
* - 'profile': Persist in pack's .browser-profile/ directory
|
|
41
42
|
*/
|
|
42
43
|
persistence?: BrowserPersistence;
|
|
44
|
+
/**
|
|
45
|
+
* Proxy configuration for routing traffic through a proxy provider.
|
|
46
|
+
* Set by the agent's `set_proxy` tool or manually in taskpack.json.
|
|
47
|
+
*/
|
|
48
|
+
proxy?: ProxyConfig;
|
|
43
49
|
}
|
|
44
50
|
/**
|
|
45
51
|
* Field definition in a schema
|
package/dist/types.d.ts.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"types.d.ts","sourceRoot":"","sources":["../src/types.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,OAAO,EAAE,IAAI,EAAE,MAAM,YAAY,CAAC;AAChD,OAAO,KAAK,EAAE,OAAO,EAAE,MAAM,gBAAgB,CAAC;AAC9C,OAAO,KAAK,EAAE,iBAAiB,EAAE,MAAM,qBAAqB,CAAC;AAC7D,OAAO,KAAK,EAAE,YAAY,EAAE,MAAM,sBAAsB,CAAC;
|
|
1
|
+
{"version":3,"file":"types.d.ts","sourceRoot":"","sources":["../src/types.ts"],"names":[],"mappings":"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"}
|