@praveen-palanisamy/agent-browser-runtime 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 +23 -0
- package/LICENSE +23 -0
- package/README.md +261 -0
- package/action.yml +185 -0
- package/dist/attribution.d.ts +22 -0
- package/dist/attribution.d.ts.map +1 -0
- package/dist/attribution.js +57 -0
- package/dist/attribution.js.map +1 -0
- package/dist/cli.d.ts +21 -0
- package/dist/cli.d.ts.map +1 -0
- package/dist/cli.js +242 -0
- package/dist/cli.js.map +1 -0
- package/dist/client/index.d.ts +9 -0
- package/dist/client/index.d.ts.map +1 -0
- package/dist/client/index.js +26 -0
- package/dist/client/index.js.map +1 -0
- package/dist/client/runner-client.d.ts +41 -0
- package/dist/client/runner-client.d.ts.map +1 -0
- package/dist/client/runner-client.js +98 -0
- package/dist/client/runner-client.js.map +1 -0
- package/dist/core/capture.d.ts +50 -0
- package/dist/core/capture.d.ts.map +1 -0
- package/dist/core/capture.js +129 -0
- package/dist/core/capture.js.map +1 -0
- package/dist/core/poster.d.ts +45 -0
- package/dist/core/poster.d.ts.map +1 -0
- package/dist/core/poster.js +132 -0
- package/dist/core/poster.js.map +1 -0
- package/dist/core/stores.d.ts +35 -0
- package/dist/core/stores.d.ts.map +1 -0
- package/dist/core/stores.js +32 -0
- package/dist/core/stores.js.map +1 -0
- package/dist/core/types.d.ts +138 -0
- package/dist/core/types.d.ts.map +1 -0
- package/dist/core/types.js +13 -0
- package/dist/core/types.js.map +1 -0
- package/dist/index.d.ts +20 -0
- package/dist/index.d.ts.map +1 -0
- package/dist/index.js +48 -0
- package/dist/index.js.map +1 -0
- package/dist/platform.d.ts +6 -0
- package/dist/platform.d.ts.map +1 -0
- package/dist/platform.js +3 -0
- package/dist/platform.js.map +1 -0
- package/dist/protocol.d.ts +84 -0
- package/dist/protocol.d.ts.map +1 -0
- package/dist/protocol.js +24 -0
- package/dist/protocol.js.map +1 -0
- package/dist/providers/kernel.d.ts +53 -0
- package/dist/providers/kernel.d.ts.map +1 -0
- package/dist/providers/kernel.js +82 -0
- package/dist/providers/kernel.js.map +1 -0
- package/dist/providers/playwright.d.ts +88 -0
- package/dist/providers/playwright.d.ts.map +1 -0
- package/dist/providers/playwright.js +114 -0
- package/dist/providers/playwright.js.map +1 -0
- package/dist/providers/steel.d.ts +48 -0
- package/dist/providers/steel.d.ts.map +1 -0
- package/dist/providers/steel.js +79 -0
- package/dist/providers/steel.js.map +1 -0
- package/dist/service/config.d.ts +33 -0
- package/dist/service/config.d.ts.map +1 -0
- package/dist/service/config.js +59 -0
- package/dist/service/config.js.map +1 -0
- package/dist/service/index.d.ts +30 -0
- package/dist/service/index.d.ts.map +1 -0
- package/dist/service/index.js +53 -0
- package/dist/service/index.js.map +1 -0
- package/dist/service/live-proxy.d.ts +27 -0
- package/dist/service/live-proxy.d.ts.map +1 -0
- package/dist/service/live-proxy.js +146 -0
- package/dist/service/live-proxy.js.map +1 -0
- package/dist/service/runner.d.ts +35 -0
- package/dist/service/runner.d.ts.map +1 -0
- package/dist/service/runner.js +139 -0
- package/dist/service/runner.js.map +1 -0
- package/dist/service/serialized-provider.d.ts +20 -0
- package/dist/service/serialized-provider.d.ts.map +1 -0
- package/dist/service/serialized-provider.js +68 -0
- package/dist/service/serialized-provider.js.map +1 -0
- package/dist/service/server.d.ts +17 -0
- package/dist/service/server.d.ts.map +1 -0
- package/dist/service/server.js +159 -0
- package/dist/service/server.js.map +1 -0
- package/docs/AGENTS.md +46 -0
- package/docs/ARCHITECTURE.md +73 -0
- package/docs/DEPLOY.md +61 -0
- package/docs/GITHUB_ACTION.md +92 -0
- package/examples/demo-strategy/index.js +53 -0
- package/examples/demo-strategy/session.json +5 -0
- package/package.json +96 -0
|
@@ -0,0 +1,53 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
/**
|
|
3
|
+
* Agent runner service entry point.
|
|
4
|
+
*
|
|
5
|
+
* import { startRunner } from 'agent-browser-runtime/service';
|
|
6
|
+
* startRunner({ strategies: [new MyPlatformStrategy()] });
|
|
7
|
+
*
|
|
8
|
+
* The runner is platform-agnostic; the embedding application supplies the
|
|
9
|
+
* `WebPostStrategy` implementations it wants to expose.
|
|
10
|
+
*/
|
|
11
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
12
|
+
exports.isAuthorized = exports.HttpError = exports.createRunnerServer = exports.SerializedProvider = exports.Mutex = exports.defaultProviderFactory = exports.AgentRunner = exports.rewriteLiveHtml = exports.parseLivePath = exports.handleLiveUpgrade = exports.handleLiveHttp = exports.loadConfig = void 0;
|
|
13
|
+
exports.startRunner = startRunner;
|
|
14
|
+
const config_1 = require("./config");
|
|
15
|
+
const runner_1 = require("./runner");
|
|
16
|
+
const server_1 = require("./server");
|
|
17
|
+
var config_2 = require("./config");
|
|
18
|
+
Object.defineProperty(exports, "loadConfig", { enumerable: true, get: function () { return config_2.loadConfig; } });
|
|
19
|
+
var live_proxy_1 = require("./live-proxy");
|
|
20
|
+
Object.defineProperty(exports, "handleLiveHttp", { enumerable: true, get: function () { return live_proxy_1.handleLiveHttp; } });
|
|
21
|
+
Object.defineProperty(exports, "handleLiveUpgrade", { enumerable: true, get: function () { return live_proxy_1.handleLiveUpgrade; } });
|
|
22
|
+
Object.defineProperty(exports, "parseLivePath", { enumerable: true, get: function () { return live_proxy_1.parseLivePath; } });
|
|
23
|
+
Object.defineProperty(exports, "rewriteLiveHtml", { enumerable: true, get: function () { return live_proxy_1.rewriteLiveHtml; } });
|
|
24
|
+
var runner_2 = require("./runner");
|
|
25
|
+
Object.defineProperty(exports, "AgentRunner", { enumerable: true, get: function () { return runner_2.AgentRunner; } });
|
|
26
|
+
Object.defineProperty(exports, "defaultProviderFactory", { enumerable: true, get: function () { return runner_2.defaultProviderFactory; } });
|
|
27
|
+
var serialized_provider_1 = require("./serialized-provider");
|
|
28
|
+
Object.defineProperty(exports, "Mutex", { enumerable: true, get: function () { return serialized_provider_1.Mutex; } });
|
|
29
|
+
Object.defineProperty(exports, "SerializedProvider", { enumerable: true, get: function () { return serialized_provider_1.SerializedProvider; } });
|
|
30
|
+
var server_2 = require("./server");
|
|
31
|
+
Object.defineProperty(exports, "createRunnerServer", { enumerable: true, get: function () { return server_2.createRunnerServer; } });
|
|
32
|
+
Object.defineProperty(exports, "HttpError", { enumerable: true, get: function () { return server_2.HttpError; } });
|
|
33
|
+
Object.defineProperty(exports, "isAuthorized", { enumerable: true, get: function () { return server_2.isAuthorized; } });
|
|
34
|
+
function startRunner(opts) {
|
|
35
|
+
const config = (0, config_1.loadConfig)(opts.env ?? process.env);
|
|
36
|
+
const runner = new runner_1.AgentRunner(config, opts.strategies, opts.providerFactory);
|
|
37
|
+
const server = (0, server_1.createRunnerServer)(runner);
|
|
38
|
+
server.listen(config.port, () => {
|
|
39
|
+
console.log(`[agent-browser-runtime] listening on :${config.port} jobs=${config.jobProvider} capture=${config.captureProvider} public=${config.publicUrl} strategies=${opts.strategies
|
|
40
|
+
.map((s) => s.platform)
|
|
41
|
+
.join(',')}`);
|
|
42
|
+
opts.onListening?.({ port: config.port });
|
|
43
|
+
});
|
|
44
|
+
const stop = async () => {
|
|
45
|
+
server.close();
|
|
46
|
+
await runner.shutdown();
|
|
47
|
+
process.exit(0);
|
|
48
|
+
};
|
|
49
|
+
process.on('SIGTERM', stop);
|
|
50
|
+
process.on('SIGINT', stop);
|
|
51
|
+
return { server, runner, config };
|
|
52
|
+
}
|
|
53
|
+
//# sourceMappingURL=index.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"index.js","sourceRoot":"","sources":["../../src/service/index.ts"],"names":[],"mappings":";AAAA;;;;;;;;GAQG;;;;AAGH,qCAAsC;AACtC,qCAA6D;AAC7D,qCAA8C;AAE9C,mCAA4E;AAAnE,oGAAA,UAAU,OAAA;AACnB,2CAKsB;AAJpB,4GAAA,cAAc,OAAA;AACd,+GAAA,iBAAiB,OAAA;AACjB,2GAAA,aAAa,OAAA;AACb,6GAAA,eAAe,OAAA;AAEjB,mCAIkB;AAHhB,qGAAA,WAAW,OAAA;AACX,gHAAA,sBAAsB,OAAA;AAGxB,6DAAkE;AAAzD,4GAAA,KAAK,OAAA;AAAE,yHAAA,kBAAkB,OAAA;AAClC,mCAAuE;AAA9D,4GAAA,kBAAkB,OAAA;AAAE,mGAAA,SAAS,OAAA;AAAE,sGAAA,YAAY,OAAA;AASpD,qBAA4B,IAAwB;IAClD,MAAM,MAAM,GAAG,IAAA,mBAAU,EAAC,IAAI,CAAC,GAAG,IAAI,OAAO,CAAC,GAAG,CAAC,CAAC;IACnD,MAAM,MAAM,GAAG,IAAI,oBAAW,CAAC,MAAM,EAAE,IAAI,CAAC,UAAU,EAAE,IAAI,CAAC,eAAe,CAAC,CAAC;IAC9E,MAAM,MAAM,GAAG,IAAA,2BAAkB,EAAC,MAAM,CAAC,CAAC;IAC1C,MAAM,CAAC,MAAM,CAAC,MAAM,CAAC,IAAI,EAAE,GAAG,EAAE;QAC9B,OAAO,CAAC,GAAG,CACT,yCAAyC,MAAM,CAAC,IAAI,SAAS,MAAM,CAAC,WAAW,YAAY,MAAM,CAAC,eAAe,WAAW,MAAM,CAAC,SAAS,eAAe,IAAI,CAAC,UAAU;aACvK,GAAG,CAAC,CAAC,CAAC,EAAE,EAAE,CAAC,CAAC,CAAC,QAAQ,CAAC;aACtB,IAAI,CAAC,GAAG,CAAC,EAAE,CACf,CAAC;QACF,IAAI,CAAC,WAAW,EAAE,CAAC,EAAE,IAAI,EAAE,MAAM,CAAC,IAAI,EAAE,CAAC,CAAC;IAC5C,CAAC,CAAC,CAAC;IACH,MAAM,IAAI,GAAG,KAAK,IAAI,EAAE;QACtB,MAAM,CAAC,KAAK,EAAE,CAAC;QACf,MAAM,MAAM,CAAC,QAAQ,EAAE,CAAC;QACxB,OAAO,CAAC,IAAI,CAAC,CAAC,CAAC,CAAC;IAClB,CAAC,CAAC;IACF,OAAO,CAAC,EAAE,CAAC,SAAS,EAAE,IAAI,CAAC,CAAC;IAC5B,OAAO,CAAC,EAAE,CAAC,QAAQ,EAAE,IAAI,CAAC,CAAC;IAC3B,OAAO,EAAE,MAAM,EAAE,MAAM,EAAE,MAAM,EAAE,CAAC;AACpC,CAAC"}
|
|
@@ -0,0 +1,27 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Live-view proxy.
|
|
3
|
+
*
|
|
4
|
+
* Steel's live view (`/v1/sessions/debug` + `/v1/sessions/cast` websocket)
|
|
5
|
+
* is served by the Steel API, which we keep private. The runner exposes it
|
|
6
|
+
* under `/live/{captureId}/...` so the embedding app can iframe it while the user
|
|
7
|
+
* signs in. The capture id is unguessable and only valid while the capture
|
|
8
|
+
* is active; the HTML is rewritten so its absolute Steel URLs point back
|
|
9
|
+
* through this proxy.
|
|
10
|
+
*/
|
|
11
|
+
import type { IncomingMessage, ServerResponse } from 'node:http';
|
|
12
|
+
import type { Duplex } from 'node:stream';
|
|
13
|
+
export type LiveProxyDeps = {
|
|
14
|
+
/** Resolve a capture id to the upstream live view URL (absolute). */
|
|
15
|
+
resolve: (captureId: string) => string | undefined;
|
|
16
|
+
publicUrl: string;
|
|
17
|
+
livePrefix: string;
|
|
18
|
+
};
|
|
19
|
+
export declare function parseLivePath(pathname: string, livePrefix: string): {
|
|
20
|
+
captureId: string;
|
|
21
|
+
rest: string;
|
|
22
|
+
} | null;
|
|
23
|
+
/** Rewrite Steel's absolute self-references to go through the proxy. */
|
|
24
|
+
export declare function rewriteLiveHtml(html: string, upstreamOrigin: string, proxyBase: string): string;
|
|
25
|
+
export declare function handleLiveHttp(req: IncomingMessage, res: ServerResponse, deps: LiveProxyDeps): boolean;
|
|
26
|
+
export declare function handleLiveUpgrade(req: IncomingMessage, socket: Duplex, head: Buffer, deps: LiveProxyDeps): boolean;
|
|
27
|
+
//# sourceMappingURL=live-proxy.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"live-proxy.d.ts","sourceRoot":"","sources":["../../src/service/live-proxy.ts"],"names":[],"mappings":"AAAA;;;;;;;;;GASG;AAEH,OAAO,KAAK,EAAE,eAAe,EAAE,cAAc,EAAE,MAAM,WAAW,CAAC;AAIjE,OAAO,KAAK,EAAE,MAAM,EAAE,MAAM,aAAa,CAAC;AAG1C,MAAM,MAAM,aAAa,GAAG;IAC1B,qEAAqE;IACrE,OAAO,EAAE,CAAC,SAAS,EAAE,MAAM,KAAK,MAAM,GAAG,SAAS,CAAC;IACnD,SAAS,EAAE,MAAM,CAAC;IAClB,UAAU,EAAE,MAAM,CAAC;CACpB,CAAC;AAEF,wBAAgB,aAAa,CAC3B,QAAQ,EAAE,MAAM,EAChB,UAAU,EAAE,MAAM,GACjB;IAAE,SAAS,EAAE,MAAM,CAAC;IAAC,IAAI,EAAE,MAAM,CAAA;CAAE,GAAG,IAAI,CAS5C;AAED,wEAAwE;AACxE,wBAAgB,eAAe,CAC7B,IAAI,EAAE,MAAM,EACZ,cAAc,EAAE,MAAM,EACtB,SAAS,EAAE,MAAM,GAChB,MAAM,CAKR;AAED,wBAAgB,cAAc,CAC5B,GAAG,EAAE,eAAe,EACpB,GAAG,EAAE,cAAc,EACnB,IAAI,EAAE,aAAa,GAClB,OAAO,CAwET;AAED,wBAAgB,iBAAiB,CAC/B,GAAG,EAAE,eAAe,EACpB,MAAM,EAAE,MAAM,EACd,IAAI,EAAE,MAAM,EACZ,IAAI,EAAE,aAAa,GAClB,OAAO,CA+CT"}
|
|
@@ -0,0 +1,146 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
/**
|
|
3
|
+
* Live-view proxy.
|
|
4
|
+
*
|
|
5
|
+
* Steel's live view (`/v1/sessions/debug` + `/v1/sessions/cast` websocket)
|
|
6
|
+
* is served by the Steel API, which we keep private. The runner exposes it
|
|
7
|
+
* under `/live/{captureId}/...` so the embedding app can iframe it while the user
|
|
8
|
+
* signs in. The capture id is unguessable and only valid while the capture
|
|
9
|
+
* is active; the HTML is rewritten so its absolute Steel URLs point back
|
|
10
|
+
* through this proxy.
|
|
11
|
+
*/
|
|
12
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
13
|
+
exports.parseLivePath = parseLivePath;
|
|
14
|
+
exports.rewriteLiveHtml = rewriteLiveHtml;
|
|
15
|
+
exports.handleLiveHttp = handleLiveHttp;
|
|
16
|
+
exports.handleLiveUpgrade = handleLiveUpgrade;
|
|
17
|
+
const node_http_1 = require("node:http");
|
|
18
|
+
const node_https_1 = require("node:https");
|
|
19
|
+
const node_net_1 = require("node:net");
|
|
20
|
+
const node_tls_1 = require("node:tls");
|
|
21
|
+
function parseLivePath(pathname, livePrefix) {
|
|
22
|
+
if (!pathname.startsWith(`${livePrefix}/`)) {
|
|
23
|
+
return null;
|
|
24
|
+
}
|
|
25
|
+
const remainder = pathname.slice(livePrefix.length + 1);
|
|
26
|
+
const slash = remainder.indexOf('/');
|
|
27
|
+
const captureId = slash === -1 ? remainder : remainder.slice(0, slash);
|
|
28
|
+
const rest = slash === -1 ? '/' : remainder.slice(slash);
|
|
29
|
+
return captureId ? { captureId, rest } : null;
|
|
30
|
+
}
|
|
31
|
+
/** Rewrite Steel's absolute self-references to go through the proxy. */
|
|
32
|
+
function rewriteLiveHtml(html, upstreamOrigin, proxyBase) {
|
|
33
|
+
const httpOrigin = upstreamOrigin.replace(/\/+$/, '');
|
|
34
|
+
const wsOrigin = httpOrigin.replace(/^http/, 'ws');
|
|
35
|
+
const wsProxy = proxyBase.replace(/^http/, 'ws');
|
|
36
|
+
return html.split(wsOrigin).join(wsProxy).split(httpOrigin).join(proxyBase);
|
|
37
|
+
}
|
|
38
|
+
function handleLiveHttp(req, res, deps) {
|
|
39
|
+
const url = new URL(req.url || '/', 'http://runner');
|
|
40
|
+
const parsed = parseLivePath(url.pathname, deps.livePrefix);
|
|
41
|
+
if (!parsed) {
|
|
42
|
+
return false;
|
|
43
|
+
}
|
|
44
|
+
const upstream = deps.resolve(parsed.captureId);
|
|
45
|
+
if (!upstream) {
|
|
46
|
+
res.writeHead(404, { 'Content-Type': 'text/plain' });
|
|
47
|
+
res.end('Capture not found or expired');
|
|
48
|
+
return true;
|
|
49
|
+
}
|
|
50
|
+
const upstreamUrl = new URL(upstream);
|
|
51
|
+
// Root of the capture -> the provider's live view page (interactive).
|
|
52
|
+
const targetPath = parsed.rest === '/'
|
|
53
|
+
? `${upstreamUrl.pathname}?interactive=true&showControls=false`
|
|
54
|
+
: `${parsed.rest}${url.search}`;
|
|
55
|
+
const proxyBase = `${deps.publicUrl}${deps.livePrefix}/${parsed.captureId}`;
|
|
56
|
+
const requester = upstreamUrl.protocol === 'https:' ? node_https_1.request : node_http_1.request;
|
|
57
|
+
// Drop accept-encoding so the upstream body is plain text we can rewrite.
|
|
58
|
+
const { 'accept-encoding': _enc, ...forwarded } = req.headers;
|
|
59
|
+
const headers = { ...forwarded, host: upstreamUrl.host };
|
|
60
|
+
const proxyReq = requester({
|
|
61
|
+
protocol: upstreamUrl.protocol,
|
|
62
|
+
hostname: upstreamUrl.hostname,
|
|
63
|
+
port: upstreamUrl.port || (upstreamUrl.protocol === 'https:' ? 443 : 80),
|
|
64
|
+
method: req.method,
|
|
65
|
+
path: targetPath,
|
|
66
|
+
headers,
|
|
67
|
+
}, (proxyRes) => {
|
|
68
|
+
const contentType = String(proxyRes.headers['content-type'] || '');
|
|
69
|
+
// We may change the body (let node compute length) and the page must be
|
|
70
|
+
// embeddable in the caller's iframe.
|
|
71
|
+
const { 'content-length': _len, 'x-frame-options': _xfo, 'content-security-policy': _csp, ...responseHeaders } = proxyRes.headers;
|
|
72
|
+
if (contentType.includes('text/html') ||
|
|
73
|
+
contentType.includes('javascript')) {
|
|
74
|
+
const chunks = [];
|
|
75
|
+
proxyRes.on('data', (c) => chunks.push(c));
|
|
76
|
+
proxyRes.on('end', () => {
|
|
77
|
+
const body = rewriteLiveHtml(Buffer.concat(chunks).toString('utf8'), upstreamUrl.origin, proxyBase);
|
|
78
|
+
res.writeHead(proxyRes.statusCode || 200, responseHeaders);
|
|
79
|
+
res.end(body);
|
|
80
|
+
});
|
|
81
|
+
}
|
|
82
|
+
else {
|
|
83
|
+
res.writeHead(proxyRes.statusCode || 200, responseHeaders);
|
|
84
|
+
proxyRes.pipe(res);
|
|
85
|
+
}
|
|
86
|
+
});
|
|
87
|
+
proxyReq.on('error', () => {
|
|
88
|
+
if (!res.headersSent) {
|
|
89
|
+
res.writeHead(502, { 'Content-Type': 'text/plain' });
|
|
90
|
+
}
|
|
91
|
+
res.end('Live view upstream unavailable');
|
|
92
|
+
});
|
|
93
|
+
req.pipe(proxyReq);
|
|
94
|
+
return true;
|
|
95
|
+
}
|
|
96
|
+
function handleLiveUpgrade(req, socket, head, deps) {
|
|
97
|
+
const url = new URL(req.url || '/', 'http://runner');
|
|
98
|
+
const parsed = parseLivePath(url.pathname, deps.livePrefix);
|
|
99
|
+
if (!parsed) {
|
|
100
|
+
return false;
|
|
101
|
+
}
|
|
102
|
+
const upstream = deps.resolve(parsed.captureId);
|
|
103
|
+
if (!upstream) {
|
|
104
|
+
socket.write('HTTP/1.1 404 Not Found\r\n\r\n');
|
|
105
|
+
socket.destroy();
|
|
106
|
+
return true;
|
|
107
|
+
}
|
|
108
|
+
const upstreamUrl = new URL(upstream);
|
|
109
|
+
const secure = upstreamUrl.protocol === 'https:';
|
|
110
|
+
const port = Number(upstreamUrl.port || (secure ? 443 : 80));
|
|
111
|
+
const target = secure
|
|
112
|
+
? (0, node_tls_1.connect)({
|
|
113
|
+
host: upstreamUrl.hostname,
|
|
114
|
+
port,
|
|
115
|
+
servername: upstreamUrl.hostname,
|
|
116
|
+
})
|
|
117
|
+
: (0, node_net_1.connect)({ host: upstreamUrl.hostname, port });
|
|
118
|
+
target.on('connect', () => {
|
|
119
|
+
const lines = [`${req.method} ${parsed.rest}${url.search} HTTP/1.1`];
|
|
120
|
+
for (const [key, value] of Object.entries(req.headers)) {
|
|
121
|
+
if (key === 'host') {
|
|
122
|
+
lines.push(`host: ${upstreamUrl.host}`);
|
|
123
|
+
}
|
|
124
|
+
else if (Array.isArray(value)) {
|
|
125
|
+
for (const v of value)
|
|
126
|
+
lines.push(`${key}: ${v}`);
|
|
127
|
+
}
|
|
128
|
+
else if (value !== undefined) {
|
|
129
|
+
lines.push(`${key}: ${value}`);
|
|
130
|
+
}
|
|
131
|
+
}
|
|
132
|
+
target.write(`${lines.join('\r\n')}\r\n\r\n`);
|
|
133
|
+
if (head.length) {
|
|
134
|
+
target.write(head);
|
|
135
|
+
}
|
|
136
|
+
socket.pipe(target).pipe(socket);
|
|
137
|
+
});
|
|
138
|
+
const teardown = () => {
|
|
139
|
+
socket.destroy();
|
|
140
|
+
target.destroy();
|
|
141
|
+
};
|
|
142
|
+
target.on('error', teardown);
|
|
143
|
+
socket.on('error', teardown);
|
|
144
|
+
return true;
|
|
145
|
+
}
|
|
146
|
+
//# sourceMappingURL=live-proxy.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"live-proxy.js","sourceRoot":"","sources":["../../src/service/live-proxy.ts"],"names":[],"mappings":"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"}
|
|
@@ -0,0 +1,35 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Agent runner: wires providers, the caller's strategies, poster and capture
|
|
3
|
+
* manager according to config, and exposes typed handlers for the HTTP layer.
|
|
4
|
+
*
|
|
5
|
+
* Headless jobs run on the job provider (local Chromium by default: every
|
|
6
|
+
* job gets a fresh isolated context with the user's cookies injected, so
|
|
7
|
+
* jobs are parallel and stateless). Interactive captures run on the capture
|
|
8
|
+
* provider (Steel by default, for its live view). The OSS Steel server hosts
|
|
9
|
+
* one browser session at a time, so Steel access is serialized. Kernel can
|
|
10
|
+
* back either role for burst scale.
|
|
11
|
+
*/
|
|
12
|
+
import { SessionCaptureManager } from '../core/capture';
|
|
13
|
+
import type { SessionProvider, WebPostStrategy } from '../core/types';
|
|
14
|
+
import type { RunnerCaptureFinishRequest, RunnerCaptureFinishResponse, RunnerCaptureStartRequest, RunnerCaptureStartResponse, RunnerPostRequest, RunnerPostResponse, RunnerProbeRequest, RunnerProbeResponse } from '../protocol';
|
|
15
|
+
import type { ProviderKind, RunnerConfig } from './config';
|
|
16
|
+
export type ProviderFactory = (kind: ProviderKind) => SessionProvider;
|
|
17
|
+
export declare function defaultProviderFactory(config: RunnerConfig): ProviderFactory;
|
|
18
|
+
export declare class AgentRunner {
|
|
19
|
+
readonly config: RunnerConfig;
|
|
20
|
+
readonly jobProvider: SessionProvider;
|
|
21
|
+
readonly captureProvider: SessionProvider;
|
|
22
|
+
readonly capture: SessionCaptureManager;
|
|
23
|
+
private readonly strategies;
|
|
24
|
+
constructor(config: RunnerConfig, strategies: WebPostStrategy[], providerFactory?: ProviderFactory);
|
|
25
|
+
private poster;
|
|
26
|
+
post(req: RunnerPostRequest): Promise<RunnerPostResponse>;
|
|
27
|
+
probe(req: RunnerProbeRequest): Promise<RunnerProbeResponse>;
|
|
28
|
+
captureStart(req: RunnerCaptureStartRequest): Promise<RunnerCaptureStartResponse>;
|
|
29
|
+
captureFinish(req: RunnerCaptureFinishRequest): Promise<RunnerCaptureFinishResponse>;
|
|
30
|
+
captureCancel(req: RunnerCaptureFinishRequest): Promise<{
|
|
31
|
+
ok: true;
|
|
32
|
+
}>;
|
|
33
|
+
shutdown(): Promise<void>;
|
|
34
|
+
}
|
|
35
|
+
//# sourceMappingURL=runner.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"runner.d.ts","sourceRoot":"","sources":["../../src/service/runner.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;GAUG;AAEH,OAAO,EAAE,qBAAqB,EAAE,MAAM,iBAAiB,CAAC;AAGxD,OAAO,KAAK,EAAE,eAAe,EAAE,eAAe,EAAE,MAAM,eAAe,CAAC;AACtE,OAAO,KAAK,EACV,0BAA0B,EAC1B,2BAA2B,EAC3B,yBAAyB,EACzB,0BAA0B,EAC1B,iBAAiB,EACjB,kBAAkB,EAClB,kBAAkB,EAClB,mBAAmB,EACpB,MAAM,aAAa,CAAC;AAKrB,OAAO,KAAK,EAAE,YAAY,EAAE,YAAY,EAAE,MAAM,UAAU,CAAC;AAG3D,MAAM,MAAM,eAAe,GAAG,CAAC,IAAI,EAAE,YAAY,KAAK,eAAe,CAAC;AAEtE,wBAAgB,sBAAsB,CAAC,MAAM,EAAE,YAAY,GAAG,eAAe,CA4B5E;AAED,qBAAa,WAAW;IAOpB,QAAQ,CAAC,MAAM,EAAE,YAAY;IAN/B,QAAQ,CAAC,WAAW,EAAE,eAAe,CAAC;IACtC,QAAQ,CAAC,eAAe,EAAE,eAAe,CAAC;IAC1C,QAAQ,CAAC,OAAO,EAAE,qBAAqB,CAAC;IACxC,OAAO,CAAC,QAAQ,CAAC,UAAU,CAAoB;IAE/C,YACW,MAAM,EAAE,YAAY,EAC7B,UAAU,EAAE,eAAe,EAAE,EAC7B,eAAe,GAAE,eAAgD,EAiBlE;IAED,OAAO,CAAC,MAAM;IAUR,IAAI,CAAC,GAAG,EAAE,iBAAiB,GAAG,OAAO,CAAC,kBAAkB,CAAC,CAoB9D;IAEK,KAAK,CAAC,GAAG,EAAE,kBAAkB,GAAG,OAAO,CAAC,mBAAmB,CAAC,CAajE;IAEK,YAAY,CAChB,GAAG,EAAE,yBAAyB,GAC7B,OAAO,CAAC,0BAA0B,CAAC,CAUrC;IAED,aAAa,CACX,GAAG,EAAE,0BAA0B,GAC9B,OAAO,CAAC,2BAA2B,CAAC,CAEtC;IAEK,aAAa,CAAC,GAAG,EAAE,0BAA0B,GAAG,OAAO,CAAC;QAAE,EAAE,EAAE,IAAI,CAAA;KAAE,CAAC,CAG1E;IAEK,QAAQ,IAAI,OAAO,CAAC,IAAI,CAAC,CAE9B;CACF"}
|
|
@@ -0,0 +1,139 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
/**
|
|
3
|
+
* Agent runner: wires providers, the caller's strategies, poster and capture
|
|
4
|
+
* manager according to config, and exposes typed handlers for the HTTP layer.
|
|
5
|
+
*
|
|
6
|
+
* Headless jobs run on the job provider (local Chromium by default: every
|
|
7
|
+
* job gets a fresh isolated context with the user's cookies injected, so
|
|
8
|
+
* jobs are parallel and stateless). Interactive captures run on the capture
|
|
9
|
+
* provider (Steel by default, for its live view). The OSS Steel server hosts
|
|
10
|
+
* one browser session at a time, so Steel access is serialized. Kernel can
|
|
11
|
+
* back either role for burst scale.
|
|
12
|
+
*/
|
|
13
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
14
|
+
exports.AgentRunner = void 0;
|
|
15
|
+
exports.defaultProviderFactory = defaultProviderFactory;
|
|
16
|
+
const capture_1 = require("../core/capture");
|
|
17
|
+
const poster_1 = require("../core/poster");
|
|
18
|
+
const stores_1 = require("../core/stores");
|
|
19
|
+
const protocol_1 = require("../protocol");
|
|
20
|
+
const kernel_1 = require("../providers/kernel");
|
|
21
|
+
const playwright_1 = require("../providers/playwright");
|
|
22
|
+
const steel_1 = require("../providers/steel");
|
|
23
|
+
const serialized_provider_1 = require("./serialized-provider");
|
|
24
|
+
function defaultProviderFactory(config) {
|
|
25
|
+
const steelMutex = new serialized_provider_1.Mutex();
|
|
26
|
+
return (kind) => {
|
|
27
|
+
if (kind === 'steel') {
|
|
28
|
+
if (!config.steel) {
|
|
29
|
+
throw new Error('Steel provider selected without STEEL_API_URL');
|
|
30
|
+
}
|
|
31
|
+
return new serialized_provider_1.SerializedProvider(new steel_1.SteelSessionProvider({
|
|
32
|
+
baseUrl: config.steel.baseUrl,
|
|
33
|
+
apiKey: config.steel.apiKey,
|
|
34
|
+
interactiveTimeoutMs: config.captureTtlMs,
|
|
35
|
+
}), steelMutex);
|
|
36
|
+
}
|
|
37
|
+
if (kind === 'kernel') {
|
|
38
|
+
if (!config.kernel) {
|
|
39
|
+
throw new Error('Kernel provider selected without KERNEL_API_KEY');
|
|
40
|
+
}
|
|
41
|
+
return new kernel_1.KernelSessionProvider({
|
|
42
|
+
apiKey: config.kernel.apiKey,
|
|
43
|
+
baseUrl: config.kernel.baseUrl,
|
|
44
|
+
interactiveTimeoutSeconds: Math.ceil(config.captureTtlMs / 1000),
|
|
45
|
+
});
|
|
46
|
+
}
|
|
47
|
+
return new playwright_1.LocalBrowserSessionProvider({ headless: true });
|
|
48
|
+
};
|
|
49
|
+
}
|
|
50
|
+
class AgentRunner {
|
|
51
|
+
config;
|
|
52
|
+
jobProvider;
|
|
53
|
+
captureProvider;
|
|
54
|
+
capture;
|
|
55
|
+
strategies;
|
|
56
|
+
constructor(config, strategies, providerFactory = defaultProviderFactory(config)) {
|
|
57
|
+
this.config = config;
|
|
58
|
+
if (strategies.length === 0) {
|
|
59
|
+
throw new Error('AgentRunner requires at least one WebPostStrategy');
|
|
60
|
+
}
|
|
61
|
+
this.strategies = strategies;
|
|
62
|
+
this.jobProvider = providerFactory(config.jobProvider);
|
|
63
|
+
this.captureProvider =
|
|
64
|
+
config.captureProvider === config.jobProvider
|
|
65
|
+
? this.jobProvider
|
|
66
|
+
: providerFactory(config.captureProvider);
|
|
67
|
+
this.capture = new capture_1.SessionCaptureManager(this.captureProvider, {
|
|
68
|
+
ttlMs: config.captureTtlMs,
|
|
69
|
+
});
|
|
70
|
+
for (const s of strategies) {
|
|
71
|
+
this.capture.register(s);
|
|
72
|
+
}
|
|
73
|
+
}
|
|
74
|
+
poster(store) {
|
|
75
|
+
const poster = new poster_1.AgentPoster(this.jobProvider, store, {
|
|
76
|
+
pacing: this.config.pacing,
|
|
77
|
+
});
|
|
78
|
+
for (const s of this.strategies) {
|
|
79
|
+
poster.register(s);
|
|
80
|
+
}
|
|
81
|
+
return poster;
|
|
82
|
+
}
|
|
83
|
+
async post(req) {
|
|
84
|
+
const started = Date.now();
|
|
85
|
+
const key = { workspaceId: req.workspaceId, accountId: req.accountId };
|
|
86
|
+
const store = new stores_1.InMemorySessionStore([[key, req.session]]);
|
|
87
|
+
const result = await this.poster(store).post({
|
|
88
|
+
...key,
|
|
89
|
+
platform: req.platform,
|
|
90
|
+
content: req.content,
|
|
91
|
+
accountHandle: req.accountHandle,
|
|
92
|
+
});
|
|
93
|
+
const refreshed = store.peek(key);
|
|
94
|
+
return {
|
|
95
|
+
...result,
|
|
96
|
+
refreshedSession: refreshed && refreshed !== req.session ? refreshed : undefined,
|
|
97
|
+
runner: {
|
|
98
|
+
provider: this.jobProvider.id,
|
|
99
|
+
durationMs: Date.now() - started,
|
|
100
|
+
},
|
|
101
|
+
};
|
|
102
|
+
}
|
|
103
|
+
async probe(req) {
|
|
104
|
+
const key = { workspaceId: req.workspaceId, accountId: req.accountId };
|
|
105
|
+
const store = new stores_1.InMemorySessionStore([[key, req.session]]);
|
|
106
|
+
const result = await this.poster(store).probe({
|
|
107
|
+
...key,
|
|
108
|
+
platform: req.platform,
|
|
109
|
+
});
|
|
110
|
+
const refreshed = store.peek(key);
|
|
111
|
+
return {
|
|
112
|
+
...result,
|
|
113
|
+
refreshedSession: refreshed && refreshed !== req.session ? refreshed : undefined,
|
|
114
|
+
};
|
|
115
|
+
}
|
|
116
|
+
async captureStart(req) {
|
|
117
|
+
const started = await this.capture.start({
|
|
118
|
+
platform: req.platform,
|
|
119
|
+
userAgent: req.userAgent,
|
|
120
|
+
});
|
|
121
|
+
return {
|
|
122
|
+
captureId: started.captureId,
|
|
123
|
+
liveViewUrl: `${this.config.publicUrl}${protocol_1.RUNNER_ROUTES.live}/${started.captureId}/`,
|
|
124
|
+
expiresAt: started.expiresAt,
|
|
125
|
+
};
|
|
126
|
+
}
|
|
127
|
+
captureFinish(req) {
|
|
128
|
+
return this.capture.finish(req.captureId);
|
|
129
|
+
}
|
|
130
|
+
async captureCancel(req) {
|
|
131
|
+
await this.capture.cancel(req.captureId);
|
|
132
|
+
return { ok: true };
|
|
133
|
+
}
|
|
134
|
+
async shutdown() {
|
|
135
|
+
await this.capture.disposeAll();
|
|
136
|
+
}
|
|
137
|
+
}
|
|
138
|
+
exports.AgentRunner = AgentRunner;
|
|
139
|
+
//# sourceMappingURL=runner.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"runner.js","sourceRoot":"","sources":["../../src/service/runner.ts"],"names":[],"mappings":"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"}
|
|
@@ -0,0 +1,20 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Serializes access to a single-session provider (the OSS Steel server hosts
|
|
3
|
+
* one browser session at a time). The lock is held from `acquire` until the
|
|
4
|
+
* returned handle is disposed.
|
|
5
|
+
*/
|
|
6
|
+
import type { AgentSessionHandle, SessionProvider } from '../core/types';
|
|
7
|
+
export declare class Mutex {
|
|
8
|
+
private locked;
|
|
9
|
+
private waiters;
|
|
10
|
+
lock(): Promise<() => void>;
|
|
11
|
+
get isLocked(): boolean;
|
|
12
|
+
}
|
|
13
|
+
export declare class SerializedProvider implements SessionProvider {
|
|
14
|
+
private inner;
|
|
15
|
+
private mutex;
|
|
16
|
+
readonly id: string;
|
|
17
|
+
constructor(inner: SessionProvider, mutex: Mutex);
|
|
18
|
+
acquire(input: Parameters<SessionProvider['acquire']>[0]): Promise<AgentSessionHandle>;
|
|
19
|
+
}
|
|
20
|
+
//# sourceMappingURL=serialized-provider.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"serialized-provider.d.ts","sourceRoot":"","sources":["../../src/service/serialized-provider.ts"],"names":[],"mappings":"AAAA;;;;GAIG;AAEH,OAAO,KAAK,EAAE,kBAAkB,EAAE,eAAe,EAAE,MAAM,eAAe,CAAC;AAEzE,qBAAa,KAAK;IAChB,OAAO,CAAC,MAAM,CAAS;IACvB,OAAO,CAAC,OAAO,CAAyB;IAElC,IAAI,IAAI,OAAO,CAAC,MAAM,IAAI,CAAC,CAkBhC;IAED,IAAI,QAAQ,IAAI,OAAO,CAEtB;CACF;AAED,qBAAa,kBAAmB,YAAW,eAAe;IAItD,OAAO,CAAC,KAAK;IACb,OAAO,CAAC,KAAK;IAJf,QAAQ,CAAC,EAAE,EAAE,MAAM,CAAC;IAEpB,YACU,KAAK,EAAE,eAAe,EACtB,KAAK,EAAE,KAAK,EAGrB;IAEK,OAAO,CACX,KAAK,EAAE,UAAU,CAAC,eAAe,CAAC,SAAS,CAAC,CAAC,CAAC,CAAC,CAAC,GAC/C,OAAO,CAAC,kBAAkB,CAAC,CAiB7B;CACF"}
|
|
@@ -0,0 +1,68 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
/**
|
|
3
|
+
* Serializes access to a single-session provider (the OSS Steel server hosts
|
|
4
|
+
* one browser session at a time). The lock is held from `acquire` until the
|
|
5
|
+
* returned handle is disposed.
|
|
6
|
+
*/
|
|
7
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
8
|
+
exports.SerializedProvider = exports.Mutex = void 0;
|
|
9
|
+
class Mutex {
|
|
10
|
+
locked = false;
|
|
11
|
+
waiters = [];
|
|
12
|
+
async lock() {
|
|
13
|
+
if (this.locked) {
|
|
14
|
+
await new Promise((resolve) => this.waiters.push(resolve));
|
|
15
|
+
}
|
|
16
|
+
this.locked = true;
|
|
17
|
+
let released = false;
|
|
18
|
+
return () => {
|
|
19
|
+
if (released) {
|
|
20
|
+
return;
|
|
21
|
+
}
|
|
22
|
+
released = true;
|
|
23
|
+
const next = this.waiters.shift();
|
|
24
|
+
if (next) {
|
|
25
|
+
next();
|
|
26
|
+
}
|
|
27
|
+
else {
|
|
28
|
+
this.locked = false;
|
|
29
|
+
}
|
|
30
|
+
};
|
|
31
|
+
}
|
|
32
|
+
get isLocked() {
|
|
33
|
+
return this.locked;
|
|
34
|
+
}
|
|
35
|
+
}
|
|
36
|
+
exports.Mutex = Mutex;
|
|
37
|
+
class SerializedProvider {
|
|
38
|
+
inner;
|
|
39
|
+
mutex;
|
|
40
|
+
id;
|
|
41
|
+
constructor(inner, mutex) {
|
|
42
|
+
this.inner = inner;
|
|
43
|
+
this.mutex = mutex;
|
|
44
|
+
this.id = inner.id;
|
|
45
|
+
}
|
|
46
|
+
async acquire(input) {
|
|
47
|
+
const release = await this.mutex.lock();
|
|
48
|
+
try {
|
|
49
|
+
const handle = await this.inner.acquire(input);
|
|
50
|
+
const dispose = handle.dispose.bind(handle);
|
|
51
|
+
handle.dispose = async () => {
|
|
52
|
+
try {
|
|
53
|
+
await dispose();
|
|
54
|
+
}
|
|
55
|
+
finally {
|
|
56
|
+
release();
|
|
57
|
+
}
|
|
58
|
+
};
|
|
59
|
+
return handle;
|
|
60
|
+
}
|
|
61
|
+
catch (e) {
|
|
62
|
+
release();
|
|
63
|
+
throw e;
|
|
64
|
+
}
|
|
65
|
+
}
|
|
66
|
+
}
|
|
67
|
+
exports.SerializedProvider = SerializedProvider;
|
|
68
|
+
//# sourceMappingURL=serialized-provider.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"serialized-provider.js","sourceRoot":"","sources":["../../src/service/serialized-provider.ts"],"names":[],"mappings":";AAAA;;;;GAIG;;;AAIH;IACU,MAAM,GAAG,KAAK,CAAC;IACf,OAAO,GAAsB,EAAE,CAAC;IAExC,KAAK,CAAC,IAAI;QACR,IAAI,IAAI,CAAC,MAAM,EAAE,CAAC;YAChB,MAAM,IAAI,OAAO,CAAO,CAAC,OAAO,EAAE,EAAE,CAAC,IAAI,CAAC,OAAO,CAAC,IAAI,CAAC,OAAO,CAAC,CAAC,CAAC;QACnE,CAAC;QACD,IAAI,CAAC,MAAM,GAAG,IAAI,CAAC;QACnB,IAAI,QAAQ,GAAG,KAAK,CAAC;QACrB,OAAO,GAAG,EAAE;YACV,IAAI,QAAQ,EAAE,CAAC;gBACb,OAAO;YACT,CAAC;YACD,QAAQ,GAAG,IAAI,CAAC;YAChB,MAAM,IAAI,GAAG,IAAI,CAAC,OAAO,CAAC,KAAK,EAAE,CAAC;YAClC,IAAI,IAAI,EAAE,CAAC;gBACT,IAAI,EAAE,CAAC;YACT,CAAC;iBAAM,CAAC;gBACN,IAAI,CAAC,MAAM,GAAG,KAAK,CAAC;YACtB,CAAC;QACH,CAAC,CAAC;IACJ,CAAC;IAED,IAAI,QAAQ;QACV,OAAO,IAAI,CAAC,MAAM,CAAC;IACrB,CAAC;CACF;;AAED;IAIY,KAAK;IACL,KAAK;IAJN,EAAE,CAAS;IAEpB,YACU,KAAsB,EACtB,KAAY;qBADZ,KAAK;qBACL,KAAK;QAEb,IAAI,CAAC,EAAE,GAAG,KAAK,CAAC,EAAE,CAAC;IACrB,CAAC;IAED,KAAK,CAAC,OAAO,CACX,KAAgD;QAEhD,MAAM,OAAO,GAAG,MAAM,IAAI,CAAC,KAAK,CAAC,IAAI,EAAE,CAAC;QACxC,IAAI,CAAC;YACH,MAAM,MAAM,GAAG,MAAM,IAAI,CAAC,KAAK,CAAC,OAAO,CAAC,KAAK,CAAC,CAAC;YAC/C,MAAM,OAAO,GAAG,MAAM,CAAC,OAAO,CAAC,IAAI,CAAC,MAAM,CAAC,CAAC;YAC5C,MAAM,CAAC,OAAO,GAAG,KAAK,IAAI,EAAE;gBAC1B,IAAI,CAAC;oBACH,MAAM,OAAO,EAAE,CAAC;gBAClB,CAAC;wBAAS,CAAC;oBACT,OAAO,EAAE,CAAC;gBACZ,CAAC;YACH,CAAC,CAAC;YACF,OAAO,MAAM,CAAC;QAChB,CAAC;QAAC,OAAO,CAAC,EAAE,CAAC;YACX,OAAO,EAAE,CAAC;YACV,MAAM,CAAC,CAAC;QACV,CAAC;IACH,CAAC;CACF"}
|
|
@@ -0,0 +1,17 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Minimal HTTP layer for the agent runner (no framework: `node:http` only).
|
|
3
|
+
*
|
|
4
|
+
* - Bearer-token auth on every /v1 route
|
|
5
|
+
* - JSON bodies, size-capped
|
|
6
|
+
* - /live/{captureId}/... proxies the provider live view (no token: the
|
|
7
|
+
* capture id is the credential, scoped to an active capture)
|
|
8
|
+
*/
|
|
9
|
+
import { type Server } from 'node:http';
|
|
10
|
+
import type { AgentRunner } from './runner';
|
|
11
|
+
export declare class HttpError extends Error {
|
|
12
|
+
readonly status: number;
|
|
13
|
+
constructor(status: number, message: string);
|
|
14
|
+
}
|
|
15
|
+
export declare function isAuthorized(header: string | undefined, token: string): boolean;
|
|
16
|
+
export declare function createRunnerServer(runner: AgentRunner): Server;
|
|
17
|
+
//# sourceMappingURL=server.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"server.d.ts","sourceRoot":"","sources":["../../src/service/server.ts"],"names":[],"mappings":"AAAA;;;;;;;GAOG;AAGH,OAAO,EAGL,KAAK,MAAM,EAEZ,MAAM,WAAW,CAAC;AAInB,OAAO,KAAK,EAAE,WAAW,EAAE,MAAM,UAAU,CAAC;AAI5C,qBAAa,SAAU,SAAQ,KAAK;IAEhC,QAAQ,CAAC,MAAM,EAAE,MAAM;IADzB,YACW,MAAM,EAAE,MAAM,EACvB,OAAO,EAAE,MAAM,EAGhB;CACF;AA8BD,wBAAgB,YAAY,CAC1B,MAAM,EAAE,MAAM,GAAG,SAAS,EAC1B,KAAK,EAAE,MAAM,GACZ,OAAO,CAKT;AAUD,wBAAgB,kBAAkB,CAAC,MAAM,EAAE,WAAW,GAAG,MAAM,CA4F9D"}
|