@page-scanner/cli 0.1.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/LICENSE +201 -0
- package/README.md +217 -0
- package/dist/api.d.ts +87 -0
- package/dist/api.d.ts.map +1 -0
- package/dist/api.js +132 -0
- package/dist/api.js.map +1 -0
- package/dist/bin.d.ts +3 -0
- package/dist/bin.d.ts.map +1 -0
- package/dist/bin.js +49 -0
- package/dist/bin.js.map +1 -0
- package/dist/bridge/server.d.ts +97 -0
- package/dist/bridge/server.d.ts.map +1 -0
- package/dist/bridge/server.js +329 -0
- package/dist/bridge/server.js.map +1 -0
- package/dist/bridge/tokens.d.ts +10 -0
- package/dist/bridge/tokens.d.ts.map +1 -0
- package/dist/bridge/tokens.js +15 -0
- package/dist/bridge/tokens.js.map +1 -0
- package/dist/cli/args.d.ts +63 -0
- package/dist/cli/args.d.ts.map +1 -0
- package/dist/cli/args.js +388 -0
- package/dist/cli/args.js.map +1 -0
- package/dist/cli/commands.d.ts +8 -0
- package/dist/cli/commands.d.ts.map +1 -0
- package/dist/cli/commands.js +234 -0
- package/dist/cli/commands.js.map +1 -0
- package/dist/cli/format.d.ts +22 -0
- package/dist/cli/format.d.ts.map +1 -0
- package/dist/cli/format.js +152 -0
- package/dist/cli/format.js.map +1 -0
- package/dist/config.d.ts +17 -0
- package/dist/config.d.ts.map +1 -0
- package/dist/config.js +54 -0
- package/dist/config.js.map +1 -0
- package/dist/daemon/client.d.ts +28 -0
- package/dist/daemon/client.d.ts.map +1 -0
- package/dist/daemon/client.js +139 -0
- package/dist/daemon/client.js.map +1 -0
- package/dist/daemon/rpc-server.d.ts +31 -0
- package/dist/daemon/rpc-server.d.ts.map +1 -0
- package/dist/daemon/rpc-server.js +254 -0
- package/dist/daemon/rpc-server.js.map +1 -0
- package/dist/daemon/run.d.ts +20 -0
- package/dist/daemon/run.d.ts.map +1 -0
- package/dist/daemon/run.js +129 -0
- package/dist/daemon/run.js.map +1 -0
- package/dist/daemon/self.d.ts +25 -0
- package/dist/daemon/self.d.ts.map +1 -0
- package/dist/daemon/self.js +113 -0
- package/dist/daemon/self.js.map +1 -0
- package/dist/daemon/state.d.ts +25 -0
- package/dist/daemon/state.d.ts.map +1 -0
- package/dist/daemon/state.js +116 -0
- package/dist/daemon/state.js.map +1 -0
- package/dist/errors.d.ts +32 -0
- package/dist/errors.d.ts.map +1 -0
- package/dist/errors.js +83 -0
- package/dist/errors.js.map +1 -0
- package/dist/index.d.ts +17 -0
- package/dist/index.d.ts.map +1 -0
- package/dist/index.js +16 -0
- package/dist/index.js.map +1 -0
- package/dist/output.d.ts +13 -0
- package/dist/output.d.ts.map +1 -0
- package/dist/output.js +71 -0
- package/dist/output.js.map +1 -0
- package/dist/protocol.d.ts +144 -0
- package/dist/protocol.d.ts.map +1 -0
- package/dist/protocol.js +128 -0
- package/dist/protocol.js.map +1 -0
- package/dist/version.d.ts +11 -0
- package/dist/version.d.ts.map +1 -0
- package/dist/version.js +11 -0
- package/dist/version.js.map +1 -0
- package/package.json +77 -0
package/dist/cli/args.js
ADDED
|
@@ -0,0 +1,388 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* The whole argument surface, parsed with `node:util.parseArgs`.
|
|
3
|
+
*
|
|
4
|
+
* A CLI that ships one runtime dependency should not spend it on an argument
|
|
5
|
+
* parser, and the surface here is small enough that the platform's own parser
|
|
6
|
+
* covers it: one command, a handful of flags, no subcommand trees and no
|
|
7
|
+
* short aliases beyond `-h` and `-v`.
|
|
8
|
+
*
|
|
9
|
+
* Every rejection leaves through `PageScannerError('BAD_REQUEST', …)`, which
|
|
10
|
+
* the caller turns into exit code 2, so a script never has to read the prose
|
|
11
|
+
* to know it passed the wrong thing. The messages name the flag, what it
|
|
12
|
+
* expected and what it got, because that is the whole diagnosis.
|
|
13
|
+
*/
|
|
14
|
+
import { parseArgs as parseNodeArgs } from 'node:util';
|
|
15
|
+
import { PageScannerError } from '../errors.js';
|
|
16
|
+
import { DEFAULT_PAGE_SIZE, EXPORT_FORMAT_IDS, PAGE_SIZE_IDS, VIDEO_HANDLINGS, } from '../protocol.js';
|
|
17
|
+
export const COMMANDS = [
|
|
18
|
+
'pair',
|
|
19
|
+
'status',
|
|
20
|
+
'browsers',
|
|
21
|
+
'tabs',
|
|
22
|
+
'scan',
|
|
23
|
+
'serve',
|
|
24
|
+
'stop',
|
|
25
|
+
'help',
|
|
26
|
+
'version',
|
|
27
|
+
];
|
|
28
|
+
/** Named once and interpolated into USAGE, so the help cannot drift from them. */
|
|
29
|
+
const PAIR_WAIT_SECONDS = 120;
|
|
30
|
+
const TABS_WAIT_SECONDS = 30;
|
|
31
|
+
const SCAN_WAIT_SECONDS = 30;
|
|
32
|
+
const SCAN_TIMEOUT_SECONDS = 120;
|
|
33
|
+
export const USAGE = `page-scanner - capture a whole web page from the command line,
|
|
34
|
+
through the Page Scanner Chrome extension.
|
|
35
|
+
|
|
36
|
+
Usage:
|
|
37
|
+
page-scanner pair [--port <n>] [--rotate] [--wait <s>=${PAIR_WAIT_SECONDS}] [--no-wait]
|
|
38
|
+
[--json]
|
|
39
|
+
page-scanner status [--json]
|
|
40
|
+
page-scanner browsers [--json]
|
|
41
|
+
page-scanner tabs [--browser <id|label>] [--wait <s>=${TABS_WAIT_SECONDS}] [--json]
|
|
42
|
+
page-scanner scan (--url <u> | --tab <id>) [--window <id>]
|
|
43
|
+
[--browser <id|label>] [--format pdf|png|jpeg=pdf]
|
|
44
|
+
[--page-size auto|a4|letter=a4] [--quality <0-1>]
|
|
45
|
+
[--video frame|blank] [--open-editor]
|
|
46
|
+
[--out <file|dir>] [--wait <s>=${SCAN_WAIT_SECONDS}]
|
|
47
|
+
[--timeout <s>=${SCAN_TIMEOUT_SECONDS}]
|
|
48
|
+
[--json]
|
|
49
|
+
page-scanner serve [--daemon] [--idle <min>]
|
|
50
|
+
page-scanner stop [--json]
|
|
51
|
+
page-scanner --version | --help (-v and -h also work)
|
|
52
|
+
|
|
53
|
+
Commands:
|
|
54
|
+
pair Write the port and token the browser needs, then wait for it.
|
|
55
|
+
status Say whether there is a pairing, a daemon and a browser.
|
|
56
|
+
browsers List the browsers connected right now.
|
|
57
|
+
tabs List one browser's windows and tabs.
|
|
58
|
+
scan Capture a page and write it to a file.
|
|
59
|
+
serve Run the bridge in this terminal, or start it in the background.
|
|
60
|
+
stop Stop the background bridge.
|
|
61
|
+
|
|
62
|
+
--browser takes a browserId or a label, matched without regard to case, and
|
|
63
|
+
is needed only when more than one browser is connected. --wait 0 means do
|
|
64
|
+
not wait at all. --json prints one JSON document on stdout, on success and
|
|
65
|
+
on failure alike.
|
|
66
|
+
|
|
67
|
+
Exit codes:
|
|
68
|
+
0 success
|
|
69
|
+
1 the browser was reached and the work failed
|
|
70
|
+
2 the arguments were wrong
|
|
71
|
+
3 no usable browser: none connected, several connected, or the one
|
|
72
|
+
named is not
|
|
73
|
+
4 not paired: run \`page-scanner pair\`
|
|
74
|
+
5 the daemon would not start
|
|
75
|
+
`;
|
|
76
|
+
function badRequest(message, hint) {
|
|
77
|
+
return new PageScannerError('BAD_REQUEST', message, hint);
|
|
78
|
+
}
|
|
79
|
+
/** Quoting the offending text keeps an empty or space-only value visible. */
|
|
80
|
+
function quote(raw) {
|
|
81
|
+
return JSON.stringify(raw);
|
|
82
|
+
}
|
|
83
|
+
/**
|
|
84
|
+
* One numeric gate for every numeric flag. `accept` carries the range, and
|
|
85
|
+
* `expectation` the same range in words, so the check and the message cannot
|
|
86
|
+
* describe different things.
|
|
87
|
+
*/
|
|
88
|
+
function requireNumber(flag, raw, expectation, accept) {
|
|
89
|
+
// Number('') and Number(' ') are both 0, so an empty value would otherwise
|
|
90
|
+
// pass every range below as a perfectly legal zero.
|
|
91
|
+
const value = raw.trim() === '' ? Number.NaN : Number(raw);
|
|
92
|
+
if (!Number.isFinite(value) || !accept(value)) {
|
|
93
|
+
throw badRequest(`${flag} must be ${expectation} (got ${quote(raw)}).`);
|
|
94
|
+
}
|
|
95
|
+
return value;
|
|
96
|
+
}
|
|
97
|
+
const DECIMAL_INTEGER = /^[+-]?\d+$/;
|
|
98
|
+
/**
|
|
99
|
+
* `Number` is more permissive than "an integer" in three ways that matter
|
|
100
|
+
* here: it reads `0x10` as 16, it accepts `+7`, and it rounds
|
|
101
|
+
* `9007199254740993` down to `...992`. The last is the dangerous one, because
|
|
102
|
+
* a tab id would be quietly turned into a different tab id rather than
|
|
103
|
+
* rejected.
|
|
104
|
+
*/
|
|
105
|
+
function requireInteger(flag, raw) {
|
|
106
|
+
if (!DECIMAL_INTEGER.test(raw.trim())) {
|
|
107
|
+
throw badRequest(`${flag} must be an integer (got ${quote(raw)}).`);
|
|
108
|
+
}
|
|
109
|
+
return requireNumber(flag, raw, 'an integer', Number.isSafeInteger);
|
|
110
|
+
}
|
|
111
|
+
function requireSeconds(flag, raw) {
|
|
112
|
+
return requireNumber(flag, raw, 'a number of seconds, 0 or more', (value) => value >= 0);
|
|
113
|
+
}
|
|
114
|
+
function requireEnum(flag, raw, allowed) {
|
|
115
|
+
const match = allowed.find((candidate) => candidate === raw);
|
|
116
|
+
if (match === undefined) {
|
|
117
|
+
throw badRequest(`${flag} must be one of ${allowed.join(', ')} (got ${quote(raw)}).`);
|
|
118
|
+
}
|
|
119
|
+
return match;
|
|
120
|
+
}
|
|
121
|
+
function requireText(flag, raw) {
|
|
122
|
+
if (raw.trim() === '')
|
|
123
|
+
throw badRequest(`${flag} needs a value.`);
|
|
124
|
+
return raw;
|
|
125
|
+
}
|
|
126
|
+
function optionalInteger(flag, raw) {
|
|
127
|
+
return raw === undefined ? undefined : requireInteger(flag, raw);
|
|
128
|
+
}
|
|
129
|
+
function optionalText(flag, raw) {
|
|
130
|
+
return raw === undefined ? undefined : requireText(flag, raw);
|
|
131
|
+
}
|
|
132
|
+
/**
|
|
133
|
+
* `parseArgs` throws its own ERR_PARSE_ARGS_* errors for an unknown option, a
|
|
134
|
+
* missing value or a stray positional. Those are usage mistakes like any
|
|
135
|
+
* other, so they become BAD_REQUEST and exit 2 rather than an uncaught crash
|
|
136
|
+
* with Node's own exit code; the original sentence is the clearest account of
|
|
137
|
+
* what happened, so it is kept verbatim.
|
|
138
|
+
*/
|
|
139
|
+
function readOptions(read) {
|
|
140
|
+
try {
|
|
141
|
+
return read();
|
|
142
|
+
}
|
|
143
|
+
catch (error) {
|
|
144
|
+
const message = error instanceof Error ? error.message : String(error);
|
|
145
|
+
throw badRequest(message, 'Run `page-scanner --help` for the commands and their options.');
|
|
146
|
+
}
|
|
147
|
+
}
|
|
148
|
+
/**
|
|
149
|
+
* `page-scanner scan --help` asks for the help, not for a scan.
|
|
150
|
+
*
|
|
151
|
+
* Every command declares `--help`, so this is read AFTER Node has parsed the
|
|
152
|
+
* whole line. Sweeping the raw tokens for it beforehand was wrong: in
|
|
153
|
+
* `page-scanner tabs --browser --help` the `--help` is the missing value of
|
|
154
|
+
* `--browser`, and the sweep turned a usage error into a successful exit 0.
|
|
155
|
+
*/
|
|
156
|
+
function wantsHelp(values) {
|
|
157
|
+
return values.help === true;
|
|
158
|
+
}
|
|
159
|
+
function parsePair(argv) {
|
|
160
|
+
const { values } = readOptions(() => parseNodeArgs({
|
|
161
|
+
args: argv,
|
|
162
|
+
strict: true,
|
|
163
|
+
allowPositionals: false,
|
|
164
|
+
options: {
|
|
165
|
+
help: { type: 'boolean', short: 'h' },
|
|
166
|
+
port: { type: 'string' },
|
|
167
|
+
rotate: { type: 'boolean' },
|
|
168
|
+
wait: { type: 'string' },
|
|
169
|
+
'no-wait': { type: 'boolean' },
|
|
170
|
+
json: { type: 'boolean' },
|
|
171
|
+
},
|
|
172
|
+
}));
|
|
173
|
+
if (wantsHelp(values))
|
|
174
|
+
return { command: 'help' };
|
|
175
|
+
// Validate first, then let --no-wait override. Short-circuiting on --no-wait
|
|
176
|
+
// meant `--wait oops --no-wait` was accepted, so whether a typo was caught
|
|
177
|
+
// depended on an unrelated flag.
|
|
178
|
+
const requested = values.wait === undefined ? PAIR_WAIT_SECONDS : requireSeconds('--wait', values.wait);
|
|
179
|
+
// --no-wait wins over --wait: it is the more explicit of the two, and a
|
|
180
|
+
// script that sets both meant the one that says "return immediately".
|
|
181
|
+
const waitSeconds = values['no-wait'] === true ? 0 : requested;
|
|
182
|
+
return {
|
|
183
|
+
command: 'pair',
|
|
184
|
+
port: values.port === undefined
|
|
185
|
+
? undefined
|
|
186
|
+
: requireNumber('--port', values.port, 'an integer from 1 to 65535',
|
|
187
|
+
// Port 0 would ask the kernel for any free port, which the browser
|
|
188
|
+
// then has no way of learning: the pairing file is the only thing
|
|
189
|
+
// that tells it where to dial.
|
|
190
|
+
(value) => Number.isInteger(value) && value >= 1 && value <= 65535),
|
|
191
|
+
rotate: values.rotate === true,
|
|
192
|
+
waitSeconds,
|
|
193
|
+
json: values.json === true,
|
|
194
|
+
};
|
|
195
|
+
}
|
|
196
|
+
function parseStatus(argv) {
|
|
197
|
+
const { values } = readOptions(() => parseNodeArgs({
|
|
198
|
+
args: argv,
|
|
199
|
+
strict: true,
|
|
200
|
+
allowPositionals: false,
|
|
201
|
+
options: {
|
|
202
|
+
help: { type: 'boolean', short: 'h' },
|
|
203
|
+
json: { type: 'boolean' },
|
|
204
|
+
},
|
|
205
|
+
}));
|
|
206
|
+
if (wantsHelp(values))
|
|
207
|
+
return { command: 'help' };
|
|
208
|
+
return { command: 'status', json: values.json === true };
|
|
209
|
+
}
|
|
210
|
+
function parseBrowsers(argv) {
|
|
211
|
+
const { values } = readOptions(() => parseNodeArgs({
|
|
212
|
+
args: argv,
|
|
213
|
+
strict: true,
|
|
214
|
+
allowPositionals: false,
|
|
215
|
+
options: {
|
|
216
|
+
help: { type: 'boolean', short: 'h' },
|
|
217
|
+
json: { type: 'boolean' },
|
|
218
|
+
},
|
|
219
|
+
}));
|
|
220
|
+
if (wantsHelp(values))
|
|
221
|
+
return { command: 'help' };
|
|
222
|
+
return { command: 'browsers', json: values.json === true };
|
|
223
|
+
}
|
|
224
|
+
function parseTabs(argv) {
|
|
225
|
+
const { values } = readOptions(() => parseNodeArgs({
|
|
226
|
+
args: argv,
|
|
227
|
+
strict: true,
|
|
228
|
+
allowPositionals: false,
|
|
229
|
+
options: {
|
|
230
|
+
help: { type: 'boolean', short: 'h' },
|
|
231
|
+
browser: { type: 'string' },
|
|
232
|
+
wait: { type: 'string' },
|
|
233
|
+
json: { type: 'boolean' },
|
|
234
|
+
},
|
|
235
|
+
}));
|
|
236
|
+
if (wantsHelp(values))
|
|
237
|
+
return { command: 'help' };
|
|
238
|
+
return {
|
|
239
|
+
command: 'tabs',
|
|
240
|
+
browser: optionalText('--browser', values.browser),
|
|
241
|
+
waitSeconds: values.wait === undefined ? TABS_WAIT_SECONDS : requireSeconds('--wait', values.wait),
|
|
242
|
+
json: values.json === true,
|
|
243
|
+
};
|
|
244
|
+
}
|
|
245
|
+
function parseScan(argv) {
|
|
246
|
+
const { values } = readOptions(() => parseNodeArgs({
|
|
247
|
+
args: argv,
|
|
248
|
+
strict: true,
|
|
249
|
+
allowPositionals: false,
|
|
250
|
+
options: {
|
|
251
|
+
help: { type: 'boolean', short: 'h' },
|
|
252
|
+
url: { type: 'string' },
|
|
253
|
+
tab: { type: 'string' },
|
|
254
|
+
window: { type: 'string' },
|
|
255
|
+
browser: { type: 'string' },
|
|
256
|
+
format: { type: 'string' },
|
|
257
|
+
'page-size': { type: 'string' },
|
|
258
|
+
quality: { type: 'string' },
|
|
259
|
+
video: { type: 'string' },
|
|
260
|
+
'open-editor': { type: 'boolean' },
|
|
261
|
+
out: { type: 'string' },
|
|
262
|
+
wait: { type: 'string' },
|
|
263
|
+
timeout: { type: 'string' },
|
|
264
|
+
json: { type: 'boolean' },
|
|
265
|
+
},
|
|
266
|
+
}));
|
|
267
|
+
if (wantsHelp(values))
|
|
268
|
+
return { command: 'help' };
|
|
269
|
+
// Exactly one target. Neither leaves nothing to scan; both would make the
|
|
270
|
+
// extension choose, and the two mean different things (open a tab, or use
|
|
271
|
+
// the one already open).
|
|
272
|
+
if (values.url === undefined && values.tab === undefined) {
|
|
273
|
+
throw badRequest('scan needs a page to capture: give --url <address> or --tab <id>.', 'Run `page-scanner tabs` to see the tabs that are open.');
|
|
274
|
+
}
|
|
275
|
+
if (values.url !== undefined && values.tab !== undefined) {
|
|
276
|
+
throw badRequest('scan takes --url or --tab, not both.');
|
|
277
|
+
}
|
|
278
|
+
return {
|
|
279
|
+
command: 'scan',
|
|
280
|
+
url: optionalText('--url', values.url),
|
|
281
|
+
tabId: optionalInteger('--tab', values.tab),
|
|
282
|
+
windowId: optionalInteger('--window', values.window),
|
|
283
|
+
browser: optionalText('--browser', values.browser),
|
|
284
|
+
format: values.format === undefined
|
|
285
|
+
? 'pdf'
|
|
286
|
+
: requireEnum('--format', values.format, EXPORT_FORMAT_IDS),
|
|
287
|
+
pageSize: values['page-size'] === undefined
|
|
288
|
+
? DEFAULT_PAGE_SIZE
|
|
289
|
+
: requireEnum('--page-size', values['page-size'], PAGE_SIZE_IDS),
|
|
290
|
+
quality: values.quality === undefined
|
|
291
|
+
? undefined
|
|
292
|
+
: requireNumber('--quality', values.quality, 'a number greater than 0 and at most 1', (value) => value > 0 && value <= 1),
|
|
293
|
+
videoHandling: values.video === undefined
|
|
294
|
+
? undefined
|
|
295
|
+
: requireEnum('--video', values.video, VIDEO_HANDLINGS),
|
|
296
|
+
openEditor: values['open-editor'] === true,
|
|
297
|
+
out: optionalText('--out', values.out),
|
|
298
|
+
waitSeconds: values.wait === undefined ? SCAN_WAIT_SECONDS : requireSeconds('--wait', values.wait),
|
|
299
|
+
timeoutSeconds: values.timeout === undefined
|
|
300
|
+
? SCAN_TIMEOUT_SECONDS
|
|
301
|
+
: requireSeconds('--timeout', values.timeout),
|
|
302
|
+
json: values.json === true,
|
|
303
|
+
};
|
|
304
|
+
}
|
|
305
|
+
function parseServe(argv) {
|
|
306
|
+
const { values } = readOptions(() => parseNodeArgs({
|
|
307
|
+
args: argv,
|
|
308
|
+
strict: true,
|
|
309
|
+
allowPositionals: false,
|
|
310
|
+
options: {
|
|
311
|
+
help: { type: 'boolean', short: 'h' },
|
|
312
|
+
daemon: { type: 'boolean' },
|
|
313
|
+
idle: { type: 'string' },
|
|
314
|
+
},
|
|
315
|
+
}));
|
|
316
|
+
if (wantsHelp(values))
|
|
317
|
+
return { command: 'help' };
|
|
318
|
+
return {
|
|
319
|
+
command: 'serve',
|
|
320
|
+
daemon: values.daemon === true,
|
|
321
|
+
idleMinutes: values.idle === undefined
|
|
322
|
+
? undefined
|
|
323
|
+
: requireNumber('--idle', values.idle, 'a number of minutes, 0 or more', (v) => v >= 0),
|
|
324
|
+
};
|
|
325
|
+
}
|
|
326
|
+
function parseStop(argv) {
|
|
327
|
+
const { values } = readOptions(() => parseNodeArgs({
|
|
328
|
+
args: argv,
|
|
329
|
+
strict: true,
|
|
330
|
+
allowPositionals: false,
|
|
331
|
+
options: {
|
|
332
|
+
help: { type: 'boolean', short: 'h' },
|
|
333
|
+
json: { type: 'boolean' },
|
|
334
|
+
},
|
|
335
|
+
}));
|
|
336
|
+
if (wantsHelp(values))
|
|
337
|
+
return { command: 'help' };
|
|
338
|
+
return { command: 'stop', json: values.json === true };
|
|
339
|
+
}
|
|
340
|
+
/** The two commands that are also spelled as flags, in both spellings. */
|
|
341
|
+
const COMMAND_FLAGS = new Map([
|
|
342
|
+
['--help', 'help'],
|
|
343
|
+
['-h', 'help'],
|
|
344
|
+
['--version', 'version'],
|
|
345
|
+
['-v', 'version'],
|
|
346
|
+
]);
|
|
347
|
+
function isCommandName(value) {
|
|
348
|
+
return COMMANDS.some((command) => command === value);
|
|
349
|
+
}
|
|
350
|
+
/** What a user may reasonably be asked to type: `help` and `version` are extras. */
|
|
351
|
+
const RUNNABLE_COMMANDS = COMMANDS.filter((command) => command !== 'help' && command !== 'version').join(', ');
|
|
352
|
+
/**
|
|
353
|
+
* `argv` is what follows the node executable and the script, i.e.
|
|
354
|
+
* `process.argv.slice(2)`.
|
|
355
|
+
*/
|
|
356
|
+
export function parseArgs(argv) {
|
|
357
|
+
const first = argv[0];
|
|
358
|
+
if (first === undefined)
|
|
359
|
+
return { command: 'help' };
|
|
360
|
+
const command = COMMAND_FLAGS.get(first) ?? (isCommandName(first) ? first : undefined);
|
|
361
|
+
if (command === undefined) {
|
|
362
|
+
throw first.startsWith('-')
|
|
363
|
+
? badRequest(`Unknown option ${quote(first)}. A command comes first: one of ${RUNNABLE_COMMANDS}.`)
|
|
364
|
+
: badRequest(`Unknown command ${quote(first)}. Expected one of ${RUNNABLE_COMMANDS}.`);
|
|
365
|
+
}
|
|
366
|
+
const rest = argv.slice(1);
|
|
367
|
+
switch (command) {
|
|
368
|
+
case 'pair':
|
|
369
|
+
return parsePair(rest);
|
|
370
|
+
case 'status':
|
|
371
|
+
return parseStatus(rest);
|
|
372
|
+
case 'browsers':
|
|
373
|
+
return parseBrowsers(rest);
|
|
374
|
+
case 'tabs':
|
|
375
|
+
return parseTabs(rest);
|
|
376
|
+
case 'scan':
|
|
377
|
+
return parseScan(rest);
|
|
378
|
+
case 'serve':
|
|
379
|
+
return parseServe(rest);
|
|
380
|
+
case 'stop':
|
|
381
|
+
return parseStop(rest);
|
|
382
|
+
case 'help':
|
|
383
|
+
return { command: 'help' };
|
|
384
|
+
case 'version':
|
|
385
|
+
return { command: 'version' };
|
|
386
|
+
}
|
|
387
|
+
}
|
|
388
|
+
//# sourceMappingURL=args.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"args.js","sourceRoot":"","sources":["../../src/cli/args.ts"],"names":[],"mappings":"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"}
|
|
@@ -0,0 +1,8 @@
|
|
|
1
|
+
import type { ParsedArgs } from './args.js';
|
|
2
|
+
export interface CommandIo {
|
|
3
|
+
stdout: (text: string) => void;
|
|
4
|
+
stderr: (text: string) => void;
|
|
5
|
+
}
|
|
6
|
+
/** Runs one parsed command and returns the process exit code. */
|
|
7
|
+
export declare function runCommand(parsed: ParsedArgs, io: CommandIo): Promise<number>;
|
|
8
|
+
//# sourceMappingURL=commands.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"commands.d.ts","sourceRoot":"","sources":["../../src/cli/commands.ts"],"names":[],"mappings":"AA6BA,OAAO,KAAK,EAAE,UAAU,EAAE,MAAM,WAAW,CAAC;AAI5C,MAAM,WAAW,SAAS;IACxB,MAAM,EAAE,CAAC,IAAI,EAAE,MAAM,KAAK,IAAI,CAAC;IAC/B,MAAM,EAAE,CAAC,IAAI,EAAE,MAAM,KAAK,IAAI,CAAC;CAChC;AA0FD,iEAAiE;AACjE,wBAAsB,UAAU,CAAC,MAAM,EAAE,UAAU,EAAE,EAAE,EAAE,SAAS,GAAG,OAAO,CAAC,MAAM,CAAC,CAqJnF"}
|
|
@@ -0,0 +1,234 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* What each command prints, and what it exits with.
|
|
3
|
+
*
|
|
4
|
+
* The output contract, which the README states and `bin.test.ts` enforces:
|
|
5
|
+
*
|
|
6
|
+
* - stdout carries the answer and nothing else. For a scan that is one line,
|
|
7
|
+
* the absolute path; for a listing it is a column-aligned table. Both are
|
|
8
|
+
* meant to be piped.
|
|
9
|
+
* - stderr carries anything addressed to a person: progress, warnings, the
|
|
10
|
+
* reason something failed.
|
|
11
|
+
* - `--json` puts exactly one JSON document on stdout, for success and for
|
|
12
|
+
* failure alike, and stderr stays empty. A script should never have to
|
|
13
|
+
* parse prose.
|
|
14
|
+
* - The pairing token is printed by `pair`, on stdout, and nowhere else ever.
|
|
15
|
+
*/
|
|
16
|
+
import { listBrowsers, listTabs, pair, scan, status, stop, waitForBrowser, } from '../api.js';
|
|
17
|
+
import { exitCodeFor, toPageScannerError } from '../errors.js';
|
|
18
|
+
import { formatBrowsers, formatDuration, formatTabs, formatTruncation } from './format.js';
|
|
19
|
+
import { USAGE } from './args.js';
|
|
20
|
+
import { CLI_VERSION } from '../version.js';
|
|
21
|
+
function line(io, text) {
|
|
22
|
+
io.stdout(`${text}\n`);
|
|
23
|
+
}
|
|
24
|
+
function note(io, text) {
|
|
25
|
+
io.stderr(`${text}\n`);
|
|
26
|
+
}
|
|
27
|
+
function json(io, payload) {
|
|
28
|
+
io.stdout(`${JSON.stringify(payload, null, 2)}\n`);
|
|
29
|
+
}
|
|
30
|
+
/**
|
|
31
|
+
* Says once, on stderr, that nothing is connected yet, so a person watching a
|
|
32
|
+
* command that appears to hang knows what it is waiting for and what to do.
|
|
33
|
+
* Skipped for `--json`, whose consumer is not watching.
|
|
34
|
+
*/
|
|
35
|
+
async function warnIfWaiting(io, waitSeconds, useJson) {
|
|
36
|
+
if (useJson || waitSeconds <= 0)
|
|
37
|
+
return;
|
|
38
|
+
try {
|
|
39
|
+
const browsers = await listBrowsers();
|
|
40
|
+
if (browsers.length > 0)
|
|
41
|
+
return;
|
|
42
|
+
}
|
|
43
|
+
catch {
|
|
44
|
+
// The daemon is not up yet, or something else is wrong. Either way the
|
|
45
|
+
// real command is about to report it properly.
|
|
46
|
+
return;
|
|
47
|
+
}
|
|
48
|
+
note(io, `Waiting for Chrome to connect (up to ${waitSeconds}s). Open the Page Scanner settings ` +
|
|
49
|
+
'page and press Connect.');
|
|
50
|
+
}
|
|
51
|
+
function reportScan(io, result, format, useJson) {
|
|
52
|
+
if (useJson) {
|
|
53
|
+
json(io, { ok: true, ...result });
|
|
54
|
+
return;
|
|
55
|
+
}
|
|
56
|
+
if (result.truncated)
|
|
57
|
+
note(io, formatTruncation(result.truncated));
|
|
58
|
+
if (result.mode === 'raster') {
|
|
59
|
+
// Worth saying for a PDF, where it is the difference between a document
|
|
60
|
+
// and a picture of one. For a PNG or a JPEG the output is an image
|
|
61
|
+
// either way, and the only thing that changed is how it was assembled.
|
|
62
|
+
note(io, format === 'pdf'
|
|
63
|
+
? 'Chrome would not attach its debugger, so this was stitched from screenshots: the ' +
|
|
64
|
+
"PDF's text is an image, not text."
|
|
65
|
+
: 'Chrome would not attach its debugger, so this was stitched from screenshots.');
|
|
66
|
+
}
|
|
67
|
+
line(io, result.path);
|
|
68
|
+
}
|
|
69
|
+
function reportStatus(io, report, useJson) {
|
|
70
|
+
if (useJson) {
|
|
71
|
+
json(io, { ok: true, ...report });
|
|
72
|
+
return;
|
|
73
|
+
}
|
|
74
|
+
const rows = [
|
|
75
|
+
`page-scanner ${report.version}`,
|
|
76
|
+
`pairing ${report.paired ? `port ${report.bridgePort}` : 'none, run `page-scanner pair`'}`,
|
|
77
|
+
`config ${report.configPath}${report.configOwnerOnly ? '' : ' (not owner-only on this platform)'}`,
|
|
78
|
+
report.daemon.running
|
|
79
|
+
? `daemon running, pid ${report.daemon.pid}, version ${report.daemon.version}`
|
|
80
|
+
: 'daemon not running',
|
|
81
|
+
];
|
|
82
|
+
for (const row of rows)
|
|
83
|
+
line(io, row);
|
|
84
|
+
if (report.browsers.length === 0) {
|
|
85
|
+
line(io, 'browsers none connected');
|
|
86
|
+
return;
|
|
87
|
+
}
|
|
88
|
+
line(io, 'browsers');
|
|
89
|
+
for (const browser of report.browsers) {
|
|
90
|
+
line(io, ` ${browser.label} (${browser.browserId}) extension ${browser.extensionVersion}, ` +
|
|
91
|
+
`connected ${formatDuration(browser.connectedForMs)}`);
|
|
92
|
+
}
|
|
93
|
+
}
|
|
94
|
+
/** Runs one parsed command and returns the process exit code. */
|
|
95
|
+
export async function runCommand(parsed, io) {
|
|
96
|
+
try {
|
|
97
|
+
switch (parsed.command) {
|
|
98
|
+
case 'help':
|
|
99
|
+
line(io, USAGE);
|
|
100
|
+
return 0;
|
|
101
|
+
case 'version':
|
|
102
|
+
line(io, CLI_VERSION);
|
|
103
|
+
return 0;
|
|
104
|
+
case 'pair': {
|
|
105
|
+
const result = await pair({
|
|
106
|
+
...(parsed.port !== undefined ? { port: parsed.port } : {}),
|
|
107
|
+
rotate: parsed.rotate,
|
|
108
|
+
});
|
|
109
|
+
if (parsed.json) {
|
|
110
|
+
json(io, { ok: true, ...result });
|
|
111
|
+
}
|
|
112
|
+
else {
|
|
113
|
+
line(io, '');
|
|
114
|
+
line(io, 'Paste these into Chrome: Page Scanner settings, "Local agents".');
|
|
115
|
+
line(io, '');
|
|
116
|
+
line(io, ` Port ${result.port}`);
|
|
117
|
+
line(io, ` Token ${result.token}`);
|
|
118
|
+
line(io, '');
|
|
119
|
+
line(io, `Saved to ${result.configPath}${result.ownerOnly ? ' (owner-readable only).' : '.'}`);
|
|
120
|
+
if (!result.ownerOnly) {
|
|
121
|
+
note(io, 'Windows does not enforce the owner-only mode this file is written with. On a ' +
|
|
122
|
+
'shared machine, restrict it yourself: see the README.');
|
|
123
|
+
}
|
|
124
|
+
line(io, 'Name the browser too, so an agent can tell your profiles apart, then press Connect.');
|
|
125
|
+
}
|
|
126
|
+
if (parsed.waitSeconds > 0) {
|
|
127
|
+
if (!parsed.json) {
|
|
128
|
+
note(io, `Waiting up to ${parsed.waitSeconds}s for the browser to connect.`);
|
|
129
|
+
}
|
|
130
|
+
// Not connecting is not a failure of `pair`: the pairing is written
|
|
131
|
+
// and correct either way, and the user may simply not have Chrome
|
|
132
|
+
// open yet. Say so and exit 0.
|
|
133
|
+
try {
|
|
134
|
+
const connected = await waitForBrowser({ waitSeconds: parsed.waitSeconds });
|
|
135
|
+
if (!parsed.json) {
|
|
136
|
+
note(io, `Connected as "${connected.label}" (${connected.browserId}).`);
|
|
137
|
+
}
|
|
138
|
+
}
|
|
139
|
+
catch {
|
|
140
|
+
if (!parsed.json) {
|
|
141
|
+
note(io, 'No browser connected yet. The pairing is saved; press Connect when ready.');
|
|
142
|
+
}
|
|
143
|
+
}
|
|
144
|
+
}
|
|
145
|
+
return 0;
|
|
146
|
+
}
|
|
147
|
+
case 'status':
|
|
148
|
+
reportStatus(io, await status(), parsed.json);
|
|
149
|
+
return 0;
|
|
150
|
+
case 'browsers': {
|
|
151
|
+
const browsers = await listBrowsers();
|
|
152
|
+
if (parsed.json) {
|
|
153
|
+
json(io, { ok: true, browsers });
|
|
154
|
+
}
|
|
155
|
+
else if (browsers.length === 0) {
|
|
156
|
+
note(io, 'No browser is connected. Open the Page Scanner settings page in Chrome and press Connect.');
|
|
157
|
+
return 3;
|
|
158
|
+
}
|
|
159
|
+
else {
|
|
160
|
+
line(io, formatBrowsers(browsers));
|
|
161
|
+
}
|
|
162
|
+
return 0;
|
|
163
|
+
}
|
|
164
|
+
case 'tabs': {
|
|
165
|
+
await warnIfWaiting(io, parsed.waitSeconds, parsed.json);
|
|
166
|
+
const result = await listTabs({
|
|
167
|
+
...(parsed.browser !== undefined ? { browser: parsed.browser } : {}),
|
|
168
|
+
waitSeconds: parsed.waitSeconds,
|
|
169
|
+
});
|
|
170
|
+
if (parsed.json) {
|
|
171
|
+
json(io, { ok: true, ...result });
|
|
172
|
+
}
|
|
173
|
+
else {
|
|
174
|
+
line(io, formatTabs(result.windows, result.tabs));
|
|
175
|
+
}
|
|
176
|
+
return 0;
|
|
177
|
+
}
|
|
178
|
+
case 'scan': {
|
|
179
|
+
await warnIfWaiting(io, parsed.waitSeconds, parsed.json);
|
|
180
|
+
const result = await scan({
|
|
181
|
+
...(parsed.url !== undefined ? { url: parsed.url } : {}),
|
|
182
|
+
...(parsed.tabId !== undefined ? { tabId: parsed.tabId } : {}),
|
|
183
|
+
...(parsed.windowId !== undefined ? { windowId: parsed.windowId } : {}),
|
|
184
|
+
...(parsed.browser !== undefined ? { browser: parsed.browser } : {}),
|
|
185
|
+
...(parsed.quality !== undefined ? { quality: parsed.quality } : {}),
|
|
186
|
+
...(parsed.videoHandling !== undefined ? { videoHandling: parsed.videoHandling } : {}),
|
|
187
|
+
...(parsed.out !== undefined ? { out: parsed.out } : {}),
|
|
188
|
+
format: parsed.format,
|
|
189
|
+
pageSize: parsed.pageSize,
|
|
190
|
+
openEditor: parsed.openEditor,
|
|
191
|
+
waitSeconds: parsed.waitSeconds,
|
|
192
|
+
timeoutSeconds: parsed.timeoutSeconds,
|
|
193
|
+
});
|
|
194
|
+
reportScan(io, result, parsed.format, parsed.json);
|
|
195
|
+
return 0;
|
|
196
|
+
}
|
|
197
|
+
case 'stop': {
|
|
198
|
+
const wasRunning = await stop();
|
|
199
|
+
if (parsed.json)
|
|
200
|
+
json(io, { ok: true, stopped: wasRunning });
|
|
201
|
+
else
|
|
202
|
+
note(io, wasRunning ? 'Stopped.' : 'No daemon was running.');
|
|
203
|
+
return 0;
|
|
204
|
+
}
|
|
205
|
+
case 'serve': {
|
|
206
|
+
// Only this branch loads the WebSocket server, so every other command
|
|
207
|
+
// stays free of `ws`. The Bun binary bundles it either way; the npm
|
|
208
|
+
// package does not pay for it on a scan.
|
|
209
|
+
const { runDaemon } = await import('../daemon/run.js');
|
|
210
|
+
await runDaemon({
|
|
211
|
+
detached: parsed.daemon,
|
|
212
|
+
...(parsed.idleMinutes !== undefined ? { idleMinutes: parsed.idleMinutes } : {}),
|
|
213
|
+
log: (message) => note(io, message),
|
|
214
|
+
});
|
|
215
|
+
return 0;
|
|
216
|
+
}
|
|
217
|
+
}
|
|
218
|
+
}
|
|
219
|
+
catch (error) {
|
|
220
|
+
const failure = toPageScannerError(error);
|
|
221
|
+
const code = exitCodeFor(failure.code);
|
|
222
|
+
const useJson = 'json' in parsed && parsed.json === true;
|
|
223
|
+
if (useJson) {
|
|
224
|
+
json(io, { ok: false, code, error: failure.code, message: failure.message });
|
|
225
|
+
}
|
|
226
|
+
else {
|
|
227
|
+
note(io, failure.message);
|
|
228
|
+
if (failure.hint)
|
|
229
|
+
note(io, failure.hint);
|
|
230
|
+
}
|
|
231
|
+
return code;
|
|
232
|
+
}
|
|
233
|
+
}
|
|
234
|
+
//# sourceMappingURL=commands.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"commands.js","sourceRoot":"","sources":["../../src/cli/commands.ts"],"names":[],"mappings":"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"}
|