rechrome 1.28.1 → 1.29.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/README.md +8 -7
- package/daemon-manager.js +21 -2
- package/daemon-manager.ts +33 -2
- package/package.json +1 -1
- package/rechrome.js +269 -45
- package/rechrome.ts +269 -45
- package/serve.js +86 -0
- package/serve.ts +86 -0
package/README.md
CHANGED
|
@@ -88,13 +88,14 @@ On the host (the machine with Chrome):
|
|
|
88
88
|
rech listener add share --listen local --prefix=rechrome --port 13776 --profile you@example.com
|
|
89
89
|
tailscale serve --bg --set-path=/rechrome 13776
|
|
90
90
|
rech listener set share --public-url https://host.example.ts.net/rechrome/
|
|
91
|
-
rech
|
|
91
|
+
rech share you@example.com # prints the URL to share — it contains a secret key
|
|
92
92
|
```
|
|
93
93
|
|
|
94
94
|
`rech listener add` prints these follow-up lines with your port filled in. For scripts,
|
|
95
95
|
`rech listener port share` prints the port (`$(rech listener port share)` in bash or PowerShell).
|
|
96
96
|
|
|
97
|
-
On the other machine, inside the project that should use it
|
|
97
|
+
On the other machine, inside the project that should use it (or just open the link in a
|
|
98
|
+
browser: it shows these commands, per shell, with a Copy button):
|
|
98
99
|
|
|
99
100
|
```bash
|
|
100
101
|
rech connect 'https://host.example.ts.net/rechrome/?profile=you%40example.com#key=…'
|
|
@@ -106,13 +107,13 @@ rech open https://example.com
|
|
|
106
107
|
interactions, but not `eval`/`run-code` or filesystem commands (see [Remote access](#remote-access)).
|
|
107
108
|
|
|
108
109
|
On a trusted LAN without a proxy, `rech setup --listen lan --profile you@example.com` binds the
|
|
109
|
-
profile to your LAN address directly (plain HTTP); share the result of `rech
|
|
110
|
+
profile to your LAN address directly (plain HTTP); share the result of `rech share`.
|
|
110
111
|
|
|
111
112
|
### 5. Manage access
|
|
112
113
|
|
|
113
114
|
```bash
|
|
114
|
-
rech
|
|
115
|
-
rech
|
|
115
|
+
rech share ls # everything shared: listener × profile, local and public URLs (keys hidden)
|
|
116
|
+
rech share you@example.com # print one URL again (add --save to use it in this project)
|
|
116
117
|
rech listener allow share teammate@example.com
|
|
117
118
|
rech listener deny share teammate@example.com
|
|
118
119
|
rech listener rotate-key share # revoke: every URL for this listener stops working
|
|
@@ -193,7 +194,7 @@ Connection parameters also accept URL fragments:
|
|
|
193
194
|
RECHROME_URL='https://your-host.ts.net/rechrome/?profile=qa#key=DAEMON_KEY' rech status
|
|
194
195
|
```
|
|
195
196
|
|
|
196
|
-
`rech setup` prints and saves this URI format. Retrieve it later with `rech
|
|
197
|
+
`rech setup` prints and saves this URI format. Retrieve it later with `rech share qa` (alias: `rech profile qa --print-uri`), or omit `qa` to use the configured profile. `profiles` remains an alias. The command prints only the URI to stdout, using the configured `RECHROME_URL` endpoint; `--listener local` selects a local listener instead. For example: `rech profile qa --print-uri --listener local`. The output contains a secret daemon key.
|
|
197
198
|
|
|
198
199
|
Direct connections use the root path, such as `http://127.0.0.1:13775/?profile=qa#key=DAEMON_KEY`. A prefix is optional and only added when explicitly configured with `--prefix`, for example for a proxy mounted at `/rechrome/`. Tailscale can also serve at the root without a prefix.
|
|
199
200
|
|
|
@@ -207,7 +208,7 @@ cp .env.example .env.local
|
|
|
207
208
|
|
|
208
209
|
| Variable | Description | Default |
|
|
209
210
|
| ----------------------------------- | ----------------------------------------------------------------------------------------------------------------------------------- | ---------------- |
|
|
210
|
-
| `RECHROME_URL` | Connection URL, saved by `rech setup` / `rech connect` / `rech
|
|
211
|
+
| `RECHROME_URL` | Connection URL, saved by `rech setup` / `rech connect` / `rech share --save`. Also accepts `?extension_id=`, `?token=`, `?profile=` query params | — |
|
|
211
212
|
| `PLAYWRIGHT_CLI` | Override the playwright-cli command/path (defaults to the bundled `@playwright/cli`; set this only for a custom or forked CLI) | bundled `@playwright/cli` |
|
|
212
213
|
| `RECH_HOST` | Legacy bind address, used only before listeners.json is configured | `127.0.0.1` |
|
|
213
214
|
| `PLAYWRIGHT_MCP_EXTENSION_ID` | Chrome extension ID (client overrides server) | — |
|
package/daemon-manager.js
CHANGED
|
@@ -24,13 +24,14 @@ function oxmgrHasWinfix(version) {
|
|
|
24
24
|
function pickDaemonManager(opts) {
|
|
25
25
|
const override = opts.override?.toLowerCase();
|
|
26
26
|
if (override === "oxmgr" && !opts.oxmgrBin) {
|
|
27
|
-
throw new Error("RECH_DAEMON_MANAGER=oxmgr, but oxmgr is not on PATH. Install
|
|
27
|
+
throw new Error("RECH_DAEMON_MANAGER=oxmgr, but oxmgr is not on PATH. Install it with `bun i -g oxmgr` and ensure the global bin directory is on PATH.");
|
|
28
28
|
}
|
|
29
29
|
if (override === "pm2" && !opts.pm2Bin) {
|
|
30
30
|
throw new Error("RECH_DAEMON_MANAGER=pm2, but pm2 is not on PATH. Install it with `bun add -g pm2` and ensure the global bin directory is on PATH.");
|
|
31
31
|
}
|
|
32
32
|
if (!opts.oxmgrBin && !opts.pm2Bin) {
|
|
33
|
-
|
|
33
|
+
const install = opts.isWindows ? "Install oxmgr with `bun i -g oxmgr` (on Windows, pm2 via `bun add -g pm2` is preferred unless oxmgr is the +winfix build)" : "Install oxmgr with `bun i -g oxmgr`";
|
|
34
|
+
throw new Error(`No daemon process manager found on PATH (oxmgr or pm2). ${install}, ensure the global bin directory is on PATH, then rerun \`bunx rechrome setup\`.`);
|
|
34
35
|
}
|
|
35
36
|
const oxmgr = { id: "oxmgr", bin: opts.oxmgrBin ?? "oxmgr" };
|
|
36
37
|
const pm2 = { id: "pm2", bin: opts.pm2Bin ?? "pm2" };
|
|
@@ -62,9 +63,27 @@ function oxmgrInstallCommand(env) {
|
|
|
62
63
|
return ["npm", "i", "-g", "oxmgr"];
|
|
63
64
|
return ["bun", "i", "-g", "oxmgr"];
|
|
64
65
|
}
|
|
66
|
+
var PM2_DEPRECATION = "pm2 is deprecated as the rech daemon manager; install oxmgr (`bun i -g oxmgr`) and rerun `rech setup` to migrate.";
|
|
67
|
+
function isDeprecatedPm2Fallback(mgr, opts) {
|
|
68
|
+
return mgr.id === "pm2" && !opts.isWindows && !opts.override;
|
|
69
|
+
}
|
|
70
|
+
function listsProcess(id, output, name) {
|
|
71
|
+
if (id === "pm2") {
|
|
72
|
+
try {
|
|
73
|
+
const list = JSON.parse(output);
|
|
74
|
+
return Array.isArray(list) && list.some((p) => p?.name === name);
|
|
75
|
+
} catch {
|
|
76
|
+
return false;
|
|
77
|
+
}
|
|
78
|
+
}
|
|
79
|
+
return output.split(/[\s\u2502|\u2503]+/).includes(name);
|
|
80
|
+
}
|
|
65
81
|
export {
|
|
66
82
|
OXMGR_WINFIX_BASE,
|
|
83
|
+
PM2_DEPRECATION,
|
|
67
84
|
compareVersion,
|
|
85
|
+
isDeprecatedPm2Fallback,
|
|
86
|
+
listsProcess,
|
|
68
87
|
oxmgrHasWinfix,
|
|
69
88
|
oxmgrInstallCommand,
|
|
70
89
|
pickDaemonManager
|
package/daemon-manager.ts
CHANGED
|
@@ -58,13 +58,18 @@ export function pickDaemonManager(opts: {
|
|
|
58
58
|
}): DaemonManager {
|
|
59
59
|
const override = opts.override?.toLowerCase();
|
|
60
60
|
if (override === "oxmgr" && !opts.oxmgrBin) {
|
|
61
|
-
throw new Error("RECH_DAEMON_MANAGER=oxmgr, but oxmgr is not on PATH. Install
|
|
61
|
+
throw new Error("RECH_DAEMON_MANAGER=oxmgr, but oxmgr is not on PATH. Install it with `bun i -g oxmgr` and ensure the global bin directory is on PATH.");
|
|
62
62
|
}
|
|
63
63
|
if (override === "pm2" && !opts.pm2Bin) {
|
|
64
64
|
throw new Error("RECH_DAEMON_MANAGER=pm2, but pm2 is not on PATH. Install it with `bun add -g pm2` and ensure the global bin directory is on PATH.");
|
|
65
65
|
}
|
|
66
66
|
if (!opts.oxmgrBin && !opts.pm2Bin) {
|
|
67
|
-
|
|
67
|
+
// oxmgr is the recommended manager. On Windows stock oxmgr is only used when pm2 is
|
|
68
|
+
// absent (see below), so pm2 stays a documented alternative there.
|
|
69
|
+
const install = opts.isWindows
|
|
70
|
+
? "Install oxmgr with `bun i -g oxmgr` (on Windows, pm2 via `bun add -g pm2` is preferred unless oxmgr is the +winfix build)"
|
|
71
|
+
: "Install oxmgr with `bun i -g oxmgr`";
|
|
72
|
+
throw new Error(`No daemon process manager found on PATH (oxmgr or pm2). ${install}, ensure the global bin directory is on PATH, then rerun \`bunx rechrome setup\`.`);
|
|
68
73
|
}
|
|
69
74
|
const oxmgr: DaemonManager = { id: "oxmgr", bin: opts.oxmgrBin ?? "oxmgr" };
|
|
70
75
|
const pm2: DaemonManager = { id: "pm2", bin: opts.pm2Bin ?? "pm2" };
|
|
@@ -97,3 +102,29 @@ export function oxmgrInstallCommand(env: { npm_config_user_agent?: string; npm_e
|
|
|
97
102
|
if (/(^|\/)(npm|npx)(-cli\.js|\.cmd|\.exe)?$/i.test(execPath)) return ["npm", "i", "-g", "oxmgr"];
|
|
98
103
|
return ["bun", "i", "-g", "oxmgr"];
|
|
99
104
|
}
|
|
105
|
+
|
|
106
|
+
export const PM2_DEPRECATION =
|
|
107
|
+
"pm2 is deprecated as the rech daemon manager; install oxmgr (`bun i -g oxmgr`) and rerun `rech setup` to migrate.";
|
|
108
|
+
|
|
109
|
+
// Whether `mgr` is pm2 only as a stopgap because oxmgr is missing: the case where the user
|
|
110
|
+
// should be nudged to oxmgr. Never on Windows, where pm2 is the deliberate choice over stock
|
|
111
|
+
// (non-winfix) oxmgr and installing oxmgr would not change the pick, and never for an explicit
|
|
112
|
+
// RECH_DAEMON_MANAGER=pm2.
|
|
113
|
+
export function isDeprecatedPm2Fallback(mgr: DaemonManager, opts: { isWindows: boolean; override?: string | null }): boolean {
|
|
114
|
+
return mgr.id === "pm2" && !opts.isWindows && !opts.override;
|
|
115
|
+
}
|
|
116
|
+
|
|
117
|
+
// Whether a manager's process list (pm2 `jlist` JSON / oxmgr `list` table) registers exactly
|
|
118
|
+
// `name`. A substring test false-positives on other processes whose names, paths or args
|
|
119
|
+
// mention it (a pm2 app running from a `.../rechrome/...` checkout, or legacy `rechrome-serve`).
|
|
120
|
+
export function listsProcess(id: DaemonManager["id"], output: string, name: string): boolean {
|
|
121
|
+
if (id === "pm2") {
|
|
122
|
+
try {
|
|
123
|
+
const list = JSON.parse(output);
|
|
124
|
+
return Array.isArray(list) && list.some((p: { name?: unknown } | null) => p?.name === name);
|
|
125
|
+
} catch {
|
|
126
|
+
return false;
|
|
127
|
+
}
|
|
128
|
+
}
|
|
129
|
+
return output.split(/[\s│|┃]+/).includes(name);
|
|
130
|
+
}
|