@rynx-ai/daemon 0.1.0 → 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/browser-cli-args.d.ts +20 -0
- package/dist/browser-cli-args.js +100 -0
- package/dist/browser-runner-session-context.d.ts +24 -0
- package/dist/browser-runner-session-context.js +113 -0
- package/dist/cdp-keyboard-input.d.ts +6 -0
- package/dist/cdp-keyboard-input.js +209 -0
- package/dist/channel-store.d.ts +0 -6
- package/dist/channel-store.js +2 -18
- package/dist/chrome-for-testing-release-resolver.d.ts +34 -0
- package/dist/chrome-for-testing-release-resolver.js +214 -0
- package/dist/chrome-for-testing-store.d.ts +85 -0
- package/dist/chrome-for-testing-store.js +836 -0
- package/dist/cli.js +467 -30
- package/dist/control-client.d.ts +113 -0
- package/dist/control-client.js +792 -0
- package/dist/control-deps.js +37 -6
- package/dist/control-endpoint.d.ts +14 -0
- package/dist/control-endpoint.js +124 -0
- package/dist/control-link-store.d.ts +16 -0
- package/dist/control-link-store.js +53 -0
- package/dist/daemon-owner.d.ts +14 -0
- package/dist/daemon-owner.js +104 -0
- package/dist/daemon-server.d.ts +12 -2
- package/dist/daemon-server.js +559 -28
- package/dist/db.js +140 -10
- package/dist/desktop-browser-host-client.d.ts +34 -0
- package/dist/desktop-browser-host-client.js +413 -0
- package/dist/direct-runtime-authenticator.d.ts +13 -0
- package/dist/direct-runtime-authenticator.js +127 -0
- package/dist/direct-runtime-config.d.ts +20 -0
- package/dist/direct-runtime-config.js +101 -0
- package/dist/embedded-browser-profile-cleanup.d.ts +58 -0
- package/dist/embedded-browser-profile-cleanup.js +338 -0
- package/dist/headless-browser-host.d.ts +14 -0
- package/dist/headless-browser-host.js +2156 -0
- package/dist/index-daemon.js +28 -5
- package/dist/installation-id.d.ts +33 -0
- package/dist/installation-id.js +692 -0
- package/dist/migrations/cleanup-legacy-sessions.d.ts +0 -3
- package/dist/migrations/cleanup-legacy-sessions.js +10 -28
- package/dist/plugin-cli.d.ts +30 -0
- package/dist/plugin-cli.js +270 -0
- package/dist/plugin-host-rpc.d.ts +85 -0
- package/dist/plugin-host-rpc.js +878 -0
- package/dist/plugin-install-restart.d.ts +13 -0
- package/dist/plugin-install-restart.js +24 -0
- package/dist/plugin-installer.d.ts +36 -15
- package/dist/plugin-installer.js +420 -155
- package/dist/plugin-package.d.ts +38 -0
- package/dist/plugin-package.js +553 -0
- package/dist/plugin-runtime-control.d.ts +2 -0
- package/dist/plugin-runtime-control.js +37 -0
- package/dist/plugin-store.d.ts +37 -8
- package/dist/plugin-store.js +80 -15
- package/dist/plugin-supervisor.d.ts +160 -0
- package/dist/plugin-supervisor.js +1143 -0
- package/dist/pm2.d.ts +3 -1
- package/dist/pm2.js +55 -13
- package/dist/provider-cli-service.d.ts +46 -0
- package/dist/provider-cli-service.js +510 -0
- package/dist/registry.d.ts +6 -19
- package/dist/registry.js +22 -87
- package/dist/remote-runtime-access-store.d.ts +61 -0
- package/dist/remote-runtime-access-store.js +386 -0
- package/dist/remote-runtime-admin.d.ts +32 -0
- package/dist/remote-runtime-admin.js +107 -0
- package/dist/remote-runtime-connection-manager.d.ts +92 -0
- package/dist/remote-runtime-connection-manager.js +1409 -0
- package/dist/remote-runtime-credential-store.d.ts +45 -0
- package/dist/remote-runtime-credential-store.js +639 -0
- package/dist/remote-runtime-target-control.d.ts +47 -0
- package/dist/remote-runtime-target-control.js +433 -0
- package/dist/remote-runtime-target-store.d.ts +53 -0
- package/dist/remote-runtime-target-store.js +307 -0
- package/dist/runtime-share-addresses.d.ts +21 -0
- package/dist/runtime-share-addresses.js +50 -0
- package/dist/session-browser-capability-store.d.ts +13 -0
- package/dist/session-browser-capability-store.js +58 -0
- package/dist/session-emulator-binding-store.d.ts +10 -0
- package/dist/session-emulator-binding-store.js +61 -0
- package/dist/session-launch-operations.d.ts +41 -0
- package/dist/session-launch-operations.js +124 -0
- package/dist/session-meta-store.d.ts +3 -2
- package/dist/session-meta-store.js +57 -7
- package/dist/setup.js +9 -4
- package/dist/skills-catalog.js +8 -4
- package/dist/update.d.ts +11 -2
- package/dist/update.js +0 -27
- package/package.json +18 -10
|
@@ -0,0 +1,214 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Resolves an explicit Chrome for Testing channel or full version through the
|
|
3
|
+
* public GoogleChromeLabs JSON API.
|
|
4
|
+
*
|
|
5
|
+
* The upstream manifests intentionally contain download URLs but no archive
|
|
6
|
+
* digest. A resolved release therefore does not claim a SHA-256. The artifact
|
|
7
|
+
* store computes and records the archive digest when it installs these bytes.
|
|
8
|
+
*/
|
|
9
|
+
import { resolveChromeForTestingPlatform, } from "./chrome-for-testing-store.js";
|
|
10
|
+
const MANIFEST_BASE_URL = "https://googlechromelabs.github.io/chrome-for-testing/";
|
|
11
|
+
const CHANNEL_MANIFEST_URL = `${MANIFEST_BASE_URL}last-known-good-versions-with-downloads.json`;
|
|
12
|
+
const ARTIFACT_BASE_URL = "https://storage.googleapis.com/chrome-for-testing-public/";
|
|
13
|
+
const MAX_MANIFEST_BYTES = 64 * 1024;
|
|
14
|
+
const MAX_CHROME_DOWNLOADS = 16;
|
|
15
|
+
const MAX_URL_BYTES = 2 * 1024;
|
|
16
|
+
const VERSION_PATTERN = /^\d{1,6}\.\d{1,6}\.\d{1,6}\.\d{1,6}$/;
|
|
17
|
+
const REVISION_PATTERN = /^\d{1,20}$/;
|
|
18
|
+
export async function resolveChromeForTestingRelease(selector, options = {}) {
|
|
19
|
+
const platform = resolveChromeForTestingPlatform(options.platform ?? process.platform, options.arch ?? process.arch);
|
|
20
|
+
const normalizedSelector = validateSelector(selector);
|
|
21
|
+
const manifestUrl = normalizedSelector.kind === "channel"
|
|
22
|
+
? CHANNEL_MANIFEST_URL
|
|
23
|
+
: `${MANIFEST_BASE_URL}${normalizedSelector.version}.json`;
|
|
24
|
+
const manifest = await fetchManifest(manifestUrl, options.fetchMetadata ?? defaultFetchMetadata, options.signal);
|
|
25
|
+
const release = normalizedSelector.kind === "channel"
|
|
26
|
+
? selectChannelRelease(manifest, normalizedSelector.channel)
|
|
27
|
+
: selectVersionRelease(manifest, normalizedSelector.version);
|
|
28
|
+
const url = selectChromeDownload(release, platform.artifactPlatform);
|
|
29
|
+
return {
|
|
30
|
+
version: release.version,
|
|
31
|
+
platform: platform.artifactPlatform,
|
|
32
|
+
url,
|
|
33
|
+
manifestUrl,
|
|
34
|
+
};
|
|
35
|
+
}
|
|
36
|
+
function validateSelector(selector) {
|
|
37
|
+
if (!isRecord(selector)) {
|
|
38
|
+
throw new Error("Chrome for Testing release selector must be an object");
|
|
39
|
+
}
|
|
40
|
+
if (selector.kind === "channel") {
|
|
41
|
+
if (!isReleaseChannel(selector.channel)) {
|
|
42
|
+
throw new Error("Chrome for Testing channel must be Stable, Beta, Dev, or Canary");
|
|
43
|
+
}
|
|
44
|
+
return { kind: "channel", channel: selector.channel };
|
|
45
|
+
}
|
|
46
|
+
if (selector.kind === "version") {
|
|
47
|
+
if (typeof selector.version !== "string" || !VERSION_PATTERN.test(selector.version)) {
|
|
48
|
+
throw new Error("Chrome for Testing version must be an explicit four-part build version");
|
|
49
|
+
}
|
|
50
|
+
return { kind: "version", version: selector.version };
|
|
51
|
+
}
|
|
52
|
+
throw new Error("Chrome for Testing release selector kind must be channel or version");
|
|
53
|
+
}
|
|
54
|
+
async function fetchManifest(manifestUrl, fetchMetadata, signal) {
|
|
55
|
+
assertManifestUrl(manifestUrl);
|
|
56
|
+
const response = await fetchMetadata(manifestUrl, {
|
|
57
|
+
signal,
|
|
58
|
+
redirect: "error",
|
|
59
|
+
headers: { accept: "application/json" },
|
|
60
|
+
});
|
|
61
|
+
if (!response.ok) {
|
|
62
|
+
throw new Error(`Chrome for Testing metadata request failed: HTTP ${response.status}${response.statusText ? ` ${response.statusText}` : ""}`);
|
|
63
|
+
}
|
|
64
|
+
if (!response.body)
|
|
65
|
+
throw new Error("Chrome for Testing metadata response has no body");
|
|
66
|
+
const contentLength = parseContentLength(response.headers.get("content-length"));
|
|
67
|
+
if (contentLength !== undefined && contentLength > MAX_MANIFEST_BYTES) {
|
|
68
|
+
throw new Error(`Chrome for Testing metadata exceeds ${MAX_MANIFEST_BYTES} bytes`);
|
|
69
|
+
}
|
|
70
|
+
const reader = response.body.getReader();
|
|
71
|
+
const chunks = [];
|
|
72
|
+
let bytes = 0;
|
|
73
|
+
try {
|
|
74
|
+
while (true) {
|
|
75
|
+
const next = await reader.read();
|
|
76
|
+
if (next.done)
|
|
77
|
+
break;
|
|
78
|
+
bytes += next.value.byteLength;
|
|
79
|
+
if (bytes > MAX_MANIFEST_BYTES) {
|
|
80
|
+
await reader.cancel("Chrome for Testing metadata exceeds its transfer limit");
|
|
81
|
+
throw new Error(`Chrome for Testing metadata exceeds ${MAX_MANIFEST_BYTES} bytes`);
|
|
82
|
+
}
|
|
83
|
+
chunks.push(Buffer.from(next.value));
|
|
84
|
+
}
|
|
85
|
+
}
|
|
86
|
+
finally {
|
|
87
|
+
reader.releaseLock();
|
|
88
|
+
}
|
|
89
|
+
let text;
|
|
90
|
+
try {
|
|
91
|
+
text = new TextDecoder("utf-8", { fatal: true }).decode(Buffer.concat(chunks, bytes));
|
|
92
|
+
}
|
|
93
|
+
catch {
|
|
94
|
+
throw new Error("Chrome for Testing metadata is not valid UTF-8");
|
|
95
|
+
}
|
|
96
|
+
try {
|
|
97
|
+
return JSON.parse(text);
|
|
98
|
+
}
|
|
99
|
+
catch {
|
|
100
|
+
throw new Error("Chrome for Testing metadata is invalid JSON");
|
|
101
|
+
}
|
|
102
|
+
}
|
|
103
|
+
function selectChannelRelease(manifest, channel) {
|
|
104
|
+
if (!isRecord(manifest))
|
|
105
|
+
throw invalidManifest();
|
|
106
|
+
if (typeof manifest.timestamp !== "string" ||
|
|
107
|
+
!Number.isFinite(Date.parse(manifest.timestamp)) ||
|
|
108
|
+
!isRecord(manifest.channels)) {
|
|
109
|
+
throw invalidManifest();
|
|
110
|
+
}
|
|
111
|
+
const release = manifest.channels[channel];
|
|
112
|
+
const parsed = validateRelease(release);
|
|
113
|
+
if (parsed.channel !== channel)
|
|
114
|
+
throw invalidManifest();
|
|
115
|
+
return parsed;
|
|
116
|
+
}
|
|
117
|
+
function selectVersionRelease(manifest, expectedVersion) {
|
|
118
|
+
const release = validateRelease(manifest);
|
|
119
|
+
if (release.version !== expectedVersion || release.channel !== undefined)
|
|
120
|
+
throw invalidManifest();
|
|
121
|
+
return release;
|
|
122
|
+
}
|
|
123
|
+
function validateRelease(value) {
|
|
124
|
+
if (!isRecord(value))
|
|
125
|
+
throw invalidManifest();
|
|
126
|
+
if (typeof value.version !== "string" ||
|
|
127
|
+
!VERSION_PATTERN.test(value.version) ||
|
|
128
|
+
typeof value.revision !== "string" ||
|
|
129
|
+
!REVISION_PATTERN.test(value.revision) ||
|
|
130
|
+
!isRecord(value.downloads) ||
|
|
131
|
+
!Array.isArray(value.downloads.chrome) ||
|
|
132
|
+
value.downloads.chrome.length === 0 ||
|
|
133
|
+
value.downloads.chrome.length > MAX_CHROME_DOWNLOADS) {
|
|
134
|
+
throw invalidManifest();
|
|
135
|
+
}
|
|
136
|
+
if ("channel" in value && !isReleaseChannel(value.channel))
|
|
137
|
+
throw invalidManifest();
|
|
138
|
+
return {
|
|
139
|
+
version: value.version,
|
|
140
|
+
channel: value.channel,
|
|
141
|
+
chromeDownloads: value.downloads.chrome,
|
|
142
|
+
};
|
|
143
|
+
}
|
|
144
|
+
function selectChromeDownload(release, platform) {
|
|
145
|
+
let selected;
|
|
146
|
+
for (const entry of release.chromeDownloads) {
|
|
147
|
+
if (!isRecord(entry) ||
|
|
148
|
+
typeof entry.platform !== "string" ||
|
|
149
|
+
entry.platform.length > 32 ||
|
|
150
|
+
typeof entry.url !== "string" ||
|
|
151
|
+
Buffer.byteLength(entry.url, "utf8") > MAX_URL_BYTES) {
|
|
152
|
+
throw invalidManifest();
|
|
153
|
+
}
|
|
154
|
+
if (entry.platform !== platform)
|
|
155
|
+
continue;
|
|
156
|
+
if (selected !== undefined) {
|
|
157
|
+
throw new Error(`Chrome for Testing metadata contains duplicate ${platform} downloads`);
|
|
158
|
+
}
|
|
159
|
+
selected = validateArtifactUrl(entry.url, release.version, platform);
|
|
160
|
+
}
|
|
161
|
+
if (selected === undefined) {
|
|
162
|
+
throw new Error(`Chrome for Testing metadata has no Chrome download for ${platform}`);
|
|
163
|
+
}
|
|
164
|
+
return selected;
|
|
165
|
+
}
|
|
166
|
+
function assertManifestUrl(value) {
|
|
167
|
+
let url;
|
|
168
|
+
try {
|
|
169
|
+
url = new URL(value);
|
|
170
|
+
}
|
|
171
|
+
catch {
|
|
172
|
+
throw new Error("Chrome for Testing manifest URL is invalid");
|
|
173
|
+
}
|
|
174
|
+
if (url.origin !== "https://googlechromelabs.github.io" ||
|
|
175
|
+
!url.pathname.startsWith("/chrome-for-testing/") ||
|
|
176
|
+
url.username ||
|
|
177
|
+
url.password ||
|
|
178
|
+
url.search ||
|
|
179
|
+
url.hash) {
|
|
180
|
+
throw new Error("Chrome for Testing manifest URL is not an allowed official URL");
|
|
181
|
+
}
|
|
182
|
+
}
|
|
183
|
+
function validateArtifactUrl(value, version, platform) {
|
|
184
|
+
let url;
|
|
185
|
+
try {
|
|
186
|
+
url = new URL(value);
|
|
187
|
+
}
|
|
188
|
+
catch {
|
|
189
|
+
throw new Error("Chrome for Testing metadata contains an invalid artifact URL");
|
|
190
|
+
}
|
|
191
|
+
const expected = `${ARTIFACT_BASE_URL}${version}/${platform}/chrome-${platform}.zip`;
|
|
192
|
+
if (url.href !== expected || url.username || url.password || url.search || url.hash) {
|
|
193
|
+
throw new Error("Chrome for Testing metadata contains a non-official artifact URL");
|
|
194
|
+
}
|
|
195
|
+
return url.href;
|
|
196
|
+
}
|
|
197
|
+
function parseContentLength(raw) {
|
|
198
|
+
if (raw === null || !/^\d+$/.test(raw))
|
|
199
|
+
return undefined;
|
|
200
|
+
const value = Number(raw);
|
|
201
|
+
return Number.isSafeInteger(value) ? value : undefined;
|
|
202
|
+
}
|
|
203
|
+
function invalidManifest() {
|
|
204
|
+
return new Error("invalid Chrome for Testing release metadata");
|
|
205
|
+
}
|
|
206
|
+
function isReleaseChannel(value) {
|
|
207
|
+
return value === "Stable" || value === "Beta" || value === "Dev" || value === "Canary";
|
|
208
|
+
}
|
|
209
|
+
function isRecord(value) {
|
|
210
|
+
return typeof value === "object" && value !== null && !Array.isArray(value);
|
|
211
|
+
}
|
|
212
|
+
async function defaultFetchMetadata(url, init) {
|
|
213
|
+
return fetch(url, init);
|
|
214
|
+
}
|
|
@@ -0,0 +1,85 @@
|
|
|
1
|
+
export type ChromeForTestingHostPlatform = "darwin-arm64" | "darwin-x64" | "linux-x64";
|
|
2
|
+
export type ChromeForTestingArtifactPlatform = "mac-arm64" | "mac-x64" | "linux64";
|
|
3
|
+
export interface ChromeForTestingPlatformDescriptor {
|
|
4
|
+
hostPlatform: ChromeForTestingHostPlatform;
|
|
5
|
+
artifactPlatform: ChromeForTestingArtifactPlatform;
|
|
6
|
+
executableRelativePath: string;
|
|
7
|
+
}
|
|
8
|
+
/** Exact release metadata supplied by configuration or an explicit install/update command. */
|
|
9
|
+
export interface ChromeForTestingBuildMetadata {
|
|
10
|
+
version: string;
|
|
11
|
+
platform: ChromeForTestingArtifactPlatform;
|
|
12
|
+
url: string;
|
|
13
|
+
/** Lowercase hexadecimal SHA-256 of the downloaded ZIP archive. */
|
|
14
|
+
sha256: string;
|
|
15
|
+
}
|
|
16
|
+
/**
|
|
17
|
+
* A release resolved from the official Chrome for Testing manifest.
|
|
18
|
+
*
|
|
19
|
+
* The upstream manifest has no digest. `installResolved` computes the archive
|
|
20
|
+
* SHA-256 during the first HTTPS download and records it as the immutable local
|
|
21
|
+
* build identity; this is not represented as an upstream authenticity proof.
|
|
22
|
+
*/
|
|
23
|
+
export interface ResolvedChromeForTestingBuildMetadata {
|
|
24
|
+
version: string;
|
|
25
|
+
platform: ChromeForTestingArtifactPlatform;
|
|
26
|
+
url: string;
|
|
27
|
+
}
|
|
28
|
+
export interface InstalledChromeForTestingBuild {
|
|
29
|
+
version: string;
|
|
30
|
+
hostPlatform: ChromeForTestingHostPlatform;
|
|
31
|
+
artifactPlatform: ChromeForTestingArtifactPlatform;
|
|
32
|
+
sha256: string;
|
|
33
|
+
sourceUrl: string;
|
|
34
|
+
installedAt: string;
|
|
35
|
+
installPath: string;
|
|
36
|
+
executablePath: string;
|
|
37
|
+
}
|
|
38
|
+
export type ChromeForTestingArtifactFetcher = (url: string, init: {
|
|
39
|
+
signal?: AbortSignal;
|
|
40
|
+
}) => Promise<Response>;
|
|
41
|
+
export type ChromeForTestingZipExtractor = (archivePath: string, destination: string) => Promise<void>;
|
|
42
|
+
export interface ChromeForTestingArtifactStoreOptions {
|
|
43
|
+
/** Defaults to ~/.rynx/cache/browser/chrome-for-testing. */
|
|
44
|
+
rootDir?: string;
|
|
45
|
+
/** Injectable only so platform behavior can be tested on any build host. */
|
|
46
|
+
platform?: string;
|
|
47
|
+
/** Injectable only so platform behavior can be tested on any build host. */
|
|
48
|
+
arch?: string;
|
|
49
|
+
fetchArtifact?: ChromeForTestingArtifactFetcher;
|
|
50
|
+
extractZip?: ChromeForTestingZipExtractor;
|
|
51
|
+
maxArchiveBytes?: number;
|
|
52
|
+
now?: () => Date;
|
|
53
|
+
/** Defaults to ~/.rynx/browser/profiles/headless-chromium. */
|
|
54
|
+
headlessProfileRoot?: string;
|
|
55
|
+
/** Injectable only for deterministic live-process lease tests. */
|
|
56
|
+
isProcessLive?: (pid: number) => boolean;
|
|
57
|
+
}
|
|
58
|
+
export interface InstallChromeForTestingOptions {
|
|
59
|
+
signal?: AbortSignal;
|
|
60
|
+
onProgress?: (message: string) => void;
|
|
61
|
+
}
|
|
62
|
+
export interface PruneChromeForTestingStagingOptions {
|
|
63
|
+
olderThanMs?: number;
|
|
64
|
+
}
|
|
65
|
+
export interface PruneChromeForTestingBuildsResult {
|
|
66
|
+
removedBuilds: InstalledChromeForTestingBuild[];
|
|
67
|
+
retainedBuilds: InstalledChromeForTestingBuild[];
|
|
68
|
+
}
|
|
69
|
+
export interface ChromeForTestingLaunchReservation {
|
|
70
|
+
build: InstalledChromeForTestingBuild;
|
|
71
|
+
/** Release after the Browser process lease has been published, or launch fails. */
|
|
72
|
+
release(): void;
|
|
73
|
+
}
|
|
74
|
+
export interface ChromeForTestingArtifactStore {
|
|
75
|
+
install(build: ChromeForTestingBuildMetadata, options?: InstallChromeForTestingOptions): Promise<InstalledChromeForTestingBuild>;
|
|
76
|
+
installResolved(build: ResolvedChromeForTestingBuildMetadata, options?: InstallChromeForTestingOptions): Promise<InstalledChromeForTestingBuild>;
|
|
77
|
+
readActive(): InstalledChromeForTestingBuild | undefined;
|
|
78
|
+
reserveActiveForLaunch(): Promise<ChromeForTestingLaunchReservation | undefined>;
|
|
79
|
+
pruneBuilds(): PruneChromeForTestingBuildsResult;
|
|
80
|
+
pruneStaging(options?: PruneChromeForTestingStagingOptions): number;
|
|
81
|
+
}
|
|
82
|
+
/** The support matrix is deliberately explicit; adding a host requires tests and a known layout. */
|
|
83
|
+
export declare function resolveChromeForTestingPlatform(platform?: string, arch?: string): ChromeForTestingPlatformDescriptor;
|
|
84
|
+
export declare function isChromeForTestingHostSupported(platform?: string, arch?: string): boolean;
|
|
85
|
+
export declare function createChromeForTestingArtifactStore(options?: ChromeForTestingArtifactStoreOptions): ChromeForTestingArtifactStore;
|