@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/LICENSE
ADDED
|
@@ -0,0 +1,201 @@
|
|
|
1
|
+
Apache License
|
|
2
|
+
Version 2.0, January 2004
|
|
3
|
+
http://www.apache.org/licenses/
|
|
4
|
+
|
|
5
|
+
TERMS AND CONDITIONS FOR USE, REPRODUCTION, AND DISTRIBUTION
|
|
6
|
+
|
|
7
|
+
1. Definitions.
|
|
8
|
+
|
|
9
|
+
"License" shall mean the terms and conditions for use, reproduction,
|
|
10
|
+
and distribution as defined by Sections 1 through 9 of this document.
|
|
11
|
+
|
|
12
|
+
"Licensor" shall mean the copyright owner or entity authorized by
|
|
13
|
+
the copyright owner that is granting the License.
|
|
14
|
+
|
|
15
|
+
"Legal Entity" shall mean the union of the acting entity and all
|
|
16
|
+
other entities that control, are controlled by, or are under common
|
|
17
|
+
control with that entity. For the purposes of this definition,
|
|
18
|
+
"control" means (i) the power, direct or indirect, to cause the
|
|
19
|
+
direction or management of such entity, whether by contract or
|
|
20
|
+
otherwise, or (ii) ownership of fifty percent (50%) or more of the
|
|
21
|
+
outstanding shares, or (iii) beneficial ownership of such entity.
|
|
22
|
+
|
|
23
|
+
"You" (or "Your") shall mean an individual or Legal Entity
|
|
24
|
+
exercising permissions granted by this License.
|
|
25
|
+
|
|
26
|
+
"Source" form shall mean the preferred form for making modifications,
|
|
27
|
+
including but not limited to software source code, documentation
|
|
28
|
+
source, and configuration files.
|
|
29
|
+
|
|
30
|
+
"Object" form shall mean any form resulting from mechanical
|
|
31
|
+
transformation or translation of a Source form, including but
|
|
32
|
+
not limited to compiled object code, generated documentation,
|
|
33
|
+
and conversions to other media types.
|
|
34
|
+
|
|
35
|
+
"Work" shall mean the work of authorship, whether in Source or
|
|
36
|
+
Object form, made available under the License, as indicated by a
|
|
37
|
+
copyright notice that is included in or attached to the work
|
|
38
|
+
(an example is provided in the Appendix below).
|
|
39
|
+
|
|
40
|
+
"Derivative Works" shall mean any work, whether in Source or Object
|
|
41
|
+
form, that is based on (or derived from) the Work and for which the
|
|
42
|
+
editorial revisions, annotations, elaborations, or other modifications
|
|
43
|
+
represent, as a whole, an original work of authorship. For the purposes
|
|
44
|
+
of this License, Derivative Works shall not include works that remain
|
|
45
|
+
separable from, or merely link (or bind by name) to the interfaces of,
|
|
46
|
+
the Work and Derivative Works thereof.
|
|
47
|
+
|
|
48
|
+
"Contribution" shall mean any work of authorship, including
|
|
49
|
+
the original version of the Work and any modifications or additions
|
|
50
|
+
to that Work or Derivative Works thereof, that is intentionally
|
|
51
|
+
submitted to Licensor for inclusion in the Work by the copyright owner
|
|
52
|
+
or by an individual or Legal Entity authorized to submit on behalf of
|
|
53
|
+
the copyright owner. For the purposes of this definition, "submitted"
|
|
54
|
+
means any form of electronic, verbal, or written communication sent
|
|
55
|
+
to the Licensor or its representatives, including but not limited to
|
|
56
|
+
communication on electronic mailing lists, source code control systems,
|
|
57
|
+
and issue tracking systems that are managed by, or on behalf of, the
|
|
58
|
+
Licensor for the purpose of discussing and improving the Work, but
|
|
59
|
+
excluding communication that is conspicuously marked or otherwise
|
|
60
|
+
designated in writing by the copyright owner as "Not a Contribution."
|
|
61
|
+
|
|
62
|
+
"Contributor" shall mean Licensor and any individual or Legal Entity
|
|
63
|
+
on behalf of whom a Contribution has been received by Licensor and
|
|
64
|
+
subsequently incorporated within the Work.
|
|
65
|
+
|
|
66
|
+
2. Grant of Copyright License. Subject to the terms and conditions of
|
|
67
|
+
this License, each Contributor hereby grants to You a perpetual,
|
|
68
|
+
worldwide, non-exclusive, no-charge, royalty-free, irrevocable
|
|
69
|
+
copyright license to reproduce, prepare Derivative Works of,
|
|
70
|
+
publicly display, publicly perform, sublicense, and distribute the
|
|
71
|
+
Work and such Derivative Works in Source or Object form.
|
|
72
|
+
|
|
73
|
+
3. Grant of Patent License. Subject to the terms and conditions of
|
|
74
|
+
this License, each Contributor hereby grants to You a perpetual,
|
|
75
|
+
worldwide, non-exclusive, no-charge, royalty-free, irrevocable
|
|
76
|
+
(except as stated in this section) patent license to make, have made,
|
|
77
|
+
use, offer to sell, sell, import, and otherwise transfer the Work,
|
|
78
|
+
where such license applies only to those patent claims licensable
|
|
79
|
+
by such Contributor that are necessarily infringed by their
|
|
80
|
+
Contribution(s) alone or by combination of their Contribution(s)
|
|
81
|
+
with the Work to which such Contribution(s) was submitted. If You
|
|
82
|
+
institute patent litigation against any entity (including a
|
|
83
|
+
cross-claim or counterclaim in a lawsuit) alleging that the Work
|
|
84
|
+
or a Contribution incorporated within the Work constitutes direct
|
|
85
|
+
or contributory patent infringement, then any patent licenses
|
|
86
|
+
granted to You under this License for that Work shall terminate
|
|
87
|
+
as of the date such litigation is filed.
|
|
88
|
+
|
|
89
|
+
4. Redistribution. You may reproduce and distribute copies of the
|
|
90
|
+
Work or Derivative Works thereof in any medium, with or without
|
|
91
|
+
modifications, and in Source or Object form, provided that You
|
|
92
|
+
meet the following conditions:
|
|
93
|
+
|
|
94
|
+
(a) You must give any other recipients of the Work or
|
|
95
|
+
Derivative Works a copy of this License; and
|
|
96
|
+
|
|
97
|
+
(b) You must cause any modified files to carry prominent notices
|
|
98
|
+
stating that You changed the files; and
|
|
99
|
+
|
|
100
|
+
(c) You must retain, in the Source form of any Derivative Works
|
|
101
|
+
that You distribute, all copyright, patent, trademark, and
|
|
102
|
+
attribution notices from the Source form of the Work,
|
|
103
|
+
excluding those notices that do not pertain to any part of
|
|
104
|
+
the Derivative Works; and
|
|
105
|
+
|
|
106
|
+
(d) If the Work includes a "NOTICE" text file as part of its
|
|
107
|
+
distribution, then any Derivative Works that You distribute must
|
|
108
|
+
include a readable copy of the attribution notices contained
|
|
109
|
+
within such NOTICE file, excluding those notices that do not
|
|
110
|
+
pertain to any part of the Derivative Works, in at least one
|
|
111
|
+
of the following places: within a NOTICE text file distributed
|
|
112
|
+
as part of the Derivative Works; within the Source form or
|
|
113
|
+
documentation, if provided along with the Derivative Works; or,
|
|
114
|
+
within a display generated by the Derivative Works, if and
|
|
115
|
+
wherever such third-party notices normally appear. The contents
|
|
116
|
+
of the NOTICE file are for informational purposes only and
|
|
117
|
+
do not modify the License. You may add Your own attribution
|
|
118
|
+
notices within Derivative Works that You distribute, alongside
|
|
119
|
+
or as an addendum to the NOTICE text from the Work, provided
|
|
120
|
+
that such additional attribution notices cannot be construed
|
|
121
|
+
as modifying the License.
|
|
122
|
+
|
|
123
|
+
You may add Your own copyright statement to Your modifications and
|
|
124
|
+
may provide additional or different license terms and conditions
|
|
125
|
+
for use, reproduction, or distribution of Your modifications, or
|
|
126
|
+
for any such Derivative Works as a whole, provided Your use,
|
|
127
|
+
reproduction, and distribution of the Work otherwise complies with
|
|
128
|
+
the conditions stated in this License.
|
|
129
|
+
|
|
130
|
+
5. Submission of Contributions. Unless You explicitly state otherwise,
|
|
131
|
+
any Contribution intentionally submitted for inclusion in the Work
|
|
132
|
+
by You to the Licensor shall be under the terms and conditions of
|
|
133
|
+
this License, without any additional terms or conditions.
|
|
134
|
+
Notwithstanding the above, nothing herein shall supersede or modify
|
|
135
|
+
the terms of any separate license agreement you may have executed
|
|
136
|
+
with Licensor regarding such Contributions.
|
|
137
|
+
|
|
138
|
+
6. Trademarks. This License does not grant permission to use the trade
|
|
139
|
+
names, trademarks, service marks, or product names of the Licensor,
|
|
140
|
+
except as required for reasonable and customary use in describing the
|
|
141
|
+
origin of the Work and reproducing the content of the NOTICE file.
|
|
142
|
+
|
|
143
|
+
7. Disclaimer of Warranty. Unless required by applicable law or
|
|
144
|
+
agreed to in writing, Licensor provides the Work (and each
|
|
145
|
+
Contributor provides its Contributions) on an "AS IS" BASIS,
|
|
146
|
+
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or
|
|
147
|
+
implied, including, without limitation, any warranties or conditions
|
|
148
|
+
of TITLE, NON-INFRINGEMENT, MERCHANTABILITY, or FITNESS FOR A
|
|
149
|
+
PARTICULAR PURPOSE. You are solely responsible for determining the
|
|
150
|
+
appropriateness of using or redistributing the Work and assume any
|
|
151
|
+
risks associated with Your exercise of permissions under this License.
|
|
152
|
+
|
|
153
|
+
8. Limitation of Liability. In no event and under no legal theory,
|
|
154
|
+
whether in tort (including negligence), contract, or otherwise,
|
|
155
|
+
unless required by applicable law (such as deliberate and grossly
|
|
156
|
+
negligent acts) or agreed to in writing, shall any Contributor be
|
|
157
|
+
liable to You for damages, including any direct, indirect, special,
|
|
158
|
+
incidental, or consequential damages of any character arising as a
|
|
159
|
+
result of this License or out of the use or inability to use the
|
|
160
|
+
Work (including but not limited to damages for loss of goodwill,
|
|
161
|
+
work stoppage, computer failure or malfunction, or any and all
|
|
162
|
+
other commercial damages or losses), even if such Contributor
|
|
163
|
+
has been advised of the possibility of such damages.
|
|
164
|
+
|
|
165
|
+
9. Accepting Warranty or Additional Liability. While redistributing
|
|
166
|
+
the Work or Derivative Works thereof, You may choose to offer,
|
|
167
|
+
and charge a fee for, acceptance of support, warranty, indemnity,
|
|
168
|
+
or other liability obligations and/or rights consistent with this
|
|
169
|
+
License. However, in accepting such obligations, You may act only
|
|
170
|
+
on Your own behalf and on Your sole responsibility, not on behalf
|
|
171
|
+
of any other Contributor, and only if You agree to indemnify,
|
|
172
|
+
defend, and hold each Contributor harmless for any liability
|
|
173
|
+
incurred by, or claims asserted against, such Contributor by reason
|
|
174
|
+
of your accepting any such warranty or additional liability.
|
|
175
|
+
|
|
176
|
+
END OF TERMS AND CONDITIONS
|
|
177
|
+
|
|
178
|
+
APPENDIX: How to apply the Apache License to your work.
|
|
179
|
+
|
|
180
|
+
To apply the Apache License to your work, attach the following
|
|
181
|
+
boilerplate notice, with the fields enclosed by brackets "[]"
|
|
182
|
+
replaced with your own identifying information. (Don't include
|
|
183
|
+
the brackets!) The text should be enclosed in the appropriate
|
|
184
|
+
comment syntax for the file format. We also recommend that a
|
|
185
|
+
file or class name and description of purpose be included on the
|
|
186
|
+
same "printed page" as the copyright notice for easier
|
|
187
|
+
identification within third-party archives.
|
|
188
|
+
|
|
189
|
+
Copyright 2026 Byungdon Yoon
|
|
190
|
+
|
|
191
|
+
Licensed under the Apache License, Version 2.0 (the "License");
|
|
192
|
+
you may not use this file except in compliance with the License.
|
|
193
|
+
You may obtain a copy of the License at
|
|
194
|
+
|
|
195
|
+
http://www.apache.org/licenses/LICENSE-2.0
|
|
196
|
+
|
|
197
|
+
Unless required by applicable law or agreed to in writing, software
|
|
198
|
+
distributed under the License is distributed on an "AS IS" BASIS,
|
|
199
|
+
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
|
200
|
+
See the License for the specific language governing permissions and
|
|
201
|
+
limitations under the License.
|
package/README.md
ADDED
|
@@ -0,0 +1,217 @@
|
|
|
1
|
+
# page-scanner
|
|
2
|
+
|
|
3
|
+
Capture a whole web page from the command line, as a PDF whose text is still text.
|
|
4
|
+
|
|
5
|
+
```bash
|
|
6
|
+
npx @page-scanner/cli pair
|
|
7
|
+
npx @page-scanner/cli scan --url https://en.wikipedia.org/wiki/PDF --out ./pdf.pdf
|
|
8
|
+
```
|
|
9
|
+
|
|
10
|
+
The capture is done by the **Page Scanner Chrome extension**, in a Chrome you are already signed
|
|
11
|
+
in to. This package is the other half: it listens on loopback for that extension to connect, and
|
|
12
|
+
turns `scan` into a file on your disk. A page behind a login is a page you are logged into, and no
|
|
13
|
+
second browser is started.
|
|
14
|
+
|
|
15
|
+
It is also the engine behind [`@page-scanner/mcp`](../mcp/README.md), which is the same four
|
|
16
|
+
operations as MCP tools for an agent.
|
|
17
|
+
|
|
18
|
+
## Requirements
|
|
19
|
+
|
|
20
|
+
- Node.js 24 or newer.
|
|
21
|
+
- Google Chrome, or another Chromium browser, with the Page Scanner extension installed.
|
|
22
|
+
|
|
23
|
+
## Install
|
|
24
|
+
|
|
25
|
+
Three ways, in the order most people want them:
|
|
26
|
+
|
|
27
|
+
```bash
|
|
28
|
+
npx @page-scanner/cli --help # no install
|
|
29
|
+
npm install -g @page-scanner/cli # then just `page-scanner`
|
|
30
|
+
```
|
|
31
|
+
|
|
32
|
+
Or a standalone binary from the [releases
|
|
33
|
+
page](https://github.com/sbd530/page-scanner/releases), which needs no Node at all. The binaries
|
|
34
|
+
are **not code-signed**. On macOS, Gatekeeper will refuse the first run until you clear the
|
|
35
|
+
quarantine flag:
|
|
36
|
+
|
|
37
|
+
```bash
|
|
38
|
+
xattr -d com.apple.quarantine ./page-scanner
|
|
39
|
+
```
|
|
40
|
+
|
|
41
|
+
On Windows, SmartScreen shows "Windows protected your PC"; the binary runs from **More info** then
|
|
42
|
+
**Run anyway**. Verify what you downloaded against `SHA256SUMS` on the same release.
|
|
43
|
+
|
|
44
|
+
## Pairing
|
|
45
|
+
|
|
46
|
+
Once per machine:
|
|
47
|
+
|
|
48
|
+
```bash
|
|
49
|
+
page-scanner pair
|
|
50
|
+
```
|
|
51
|
+
|
|
52
|
+
It prints a port and a token and saves them to `~/.page-scanner/config.json`. Open the Page
|
|
53
|
+
Scanner settings page in Chrome (the gear in the editor toolbar), paste both into **Local agents**,
|
|
54
|
+
name the browser, and press **Connect**. `pair` waits up to two minutes and tells you when the
|
|
55
|
+
browser arrives.
|
|
56
|
+
|
|
57
|
+
Chrome runs a separate copy of the extension in every profile, so your work profile and your
|
|
58
|
+
personal profile are two different browsers here. Naming them is how you tell them apart later.
|
|
59
|
+
|
|
60
|
+
`page-scanner pair --rotate` issues a new token and invalidates the old one. Every browser has to
|
|
61
|
+
be re-paired after that.
|
|
62
|
+
|
|
63
|
+
## Commands
|
|
64
|
+
|
|
65
|
+
```
|
|
66
|
+
page-scanner pair [--port <n>] [--rotate] [--wait <s>=120] [--no-wait] [--json]
|
|
67
|
+
page-scanner status [--json]
|
|
68
|
+
page-scanner browsers [--json]
|
|
69
|
+
page-scanner tabs [--browser <id|label>] [--wait <s>=30] [--json]
|
|
70
|
+
page-scanner scan (--url <u> | --tab <id>) [--window <id>] [--browser <id|label>]
|
|
71
|
+
[--format pdf|png|jpeg=pdf] [--page-size auto|a4|letter=a4]
|
|
72
|
+
[--quality <0-1>] [--video frame|blank] [--open-editor]
|
|
73
|
+
[--out <file|dir>] [--wait <s>=30] [--timeout <s>=120] [--json]
|
|
74
|
+
page-scanner serve [--daemon] [--idle <min>]
|
|
75
|
+
page-scanner stop
|
|
76
|
+
page-scanner --version | --help
|
|
77
|
+
```
|
|
78
|
+
|
|
79
|
+
`--browser` takes a browserId or a label, matched without regard to case, and is only needed when
|
|
80
|
+
more than one browser is connected.
|
|
81
|
+
|
|
82
|
+
`--out` is a file when it ends in a 2 to 5 character extension and is not an existing directory,
|
|
83
|
+
and a directory otherwise, in which case the browser's suggested filename is used inside it.
|
|
84
|
+
Parent directories are created. A relative path is relative to **your** working directory, not the
|
|
85
|
+
daemon's, which is why the daemon hands the bytes back rather than writing them itself.
|
|
86
|
+
|
|
87
|
+
`--page-size` decides what a PDF is laid onto. `a4` and `letter` slice the capture across printable
|
|
88
|
+
sheets with a half-inch margin; `auto` is one page the exact size of the capture, which is not
|
|
89
|
+
printable and which Acrobat clamps past 200 inches.
|
|
90
|
+
|
|
91
|
+
`--wait 0` means do not wait at all. Chrome retires the extension's service worker after about
|
|
92
|
+
thirty seconds of silence, so the default wait exists to cover the reconnect that follows.
|
|
93
|
+
|
|
94
|
+
## What a command prints
|
|
95
|
+
|
|
96
|
+
- **stdout** carries the answer and nothing else. For `scan` that is one line, the absolute path
|
|
97
|
+
of the file it wrote. For `tabs` and `browsers` it is a column-aligned table with no separator
|
|
98
|
+
row, so `awk` can read it.
|
|
99
|
+
- **stderr** carries anything addressed to a person: progress, warnings, the reason something
|
|
100
|
+
failed.
|
|
101
|
+
- **`--json`** puts exactly one JSON document on stdout, for success and for failure alike, and
|
|
102
|
+
leaves stderr empty.
|
|
103
|
+
|
|
104
|
+
```json
|
|
105
|
+
{
|
|
106
|
+
"ok": true,
|
|
107
|
+
"path": "/Users/you/pdf.pdf",
|
|
108
|
+
"width": 1280,
|
|
109
|
+
"height": 4200,
|
|
110
|
+
"mode": "vector",
|
|
111
|
+
"selectableText": true,
|
|
112
|
+
"truncated": null,
|
|
113
|
+
"browserId": "b-9f2c41",
|
|
114
|
+
"fileName": "PDF - Wikipedia.pdf"
|
|
115
|
+
}
|
|
116
|
+
```
|
|
117
|
+
|
|
118
|
+
```json
|
|
119
|
+
{ "ok": false, "code": 3, "error": "NO_BROWSER", "message": "No browser is connected." }
|
|
120
|
+
```
|
|
121
|
+
|
|
122
|
+
`truncated` is `null` rather than absent when the capture was whole, so a reader can see the
|
|
123
|
+
question was asked. When it is not null it carries what the page measured, what was captured, and
|
|
124
|
+
a sentence naming the gap.
|
|
125
|
+
|
|
126
|
+
### Exit codes
|
|
127
|
+
|
|
128
|
+
| Code | Meaning |
|
|
129
|
+
| ---- | ----------------------------------------------------------------------------- |
|
|
130
|
+
| 0 | success |
|
|
131
|
+
| 1 | the browser was reached and the work failed |
|
|
132
|
+
| 2 | the arguments were wrong |
|
|
133
|
+
| 3 | no usable browser: none connected, several connected, or the one named is not |
|
|
134
|
+
| 4 | not paired |
|
|
135
|
+
| 5 | the daemon would not start |
|
|
136
|
+
|
|
137
|
+
## The daemon
|
|
138
|
+
|
|
139
|
+
The extension is the WebSocket **client**: nothing outside Chrome can open a connection into a
|
|
140
|
+
service worker, so something has to be listening before Chrome can dial in. That something is a
|
|
141
|
+
background daemon, started on demand by the first command that needs it.
|
|
142
|
+
|
|
143
|
+
```
|
|
144
|
+
page-scanner scan ──HTTP /rpc──┐
|
|
145
|
+
page-scanner-mcp ──HTTP /rpc──┼──> page-scanner daemon ──ws :45711──< Chrome extension(s)
|
|
146
|
+
Claude Desktop ─HTTP /rpc───┘ (127.0.0.1, ephemeral RPC port)
|
|
147
|
+
```
|
|
148
|
+
|
|
149
|
+
Two ports, deliberately. 45711 is the one the extension dials, and it refuses anything whose
|
|
150
|
+
`Origin` is not a `chrome-extension://`, which is exactly what a local CLI process is. The RPC port
|
|
151
|
+
is ephemeral, carries a bearer secret regenerated on every run, and is what the commands talk to.
|
|
152
|
+
|
|
153
|
+
`page-scanner serve` runs it in the foreground, which is the way to see why it will not start.
|
|
154
|
+
`page-scanner stop` stops it. It exits on its own after 15 minutes with no browser connected and
|
|
155
|
+
nothing calling (`PAGE_SCANNER_IDLE_MINUTES`, `0` for never), and **never** while a browser is
|
|
156
|
+
attached: the open socket is what keeps Chrome's service worker alive, and dropping it would make
|
|
157
|
+
the next command wait for a reconnect.
|
|
158
|
+
|
|
159
|
+
## Files
|
|
160
|
+
|
|
161
|
+
Everything lives in `~/.page-scanner`, or in `$PAGE_SCANNER_HOME` if that is set.
|
|
162
|
+
|
|
163
|
+
| File | What it is |
|
|
164
|
+
| ------------- | ------------------------------------------------------------- |
|
|
165
|
+
| `config.json` | the pairing: `{ port, token }`, mode 0600 |
|
|
166
|
+
| `daemon.json` | the running daemon: pid, RPC port, secret, version. Mode 0600 |
|
|
167
|
+
| `daemon.log` | stdout and stderr of a daemon started in the background |
|
|
168
|
+
|
|
169
|
+
**Windows**: those 0600 modes are a no-op. NTFS does not implement POSIX permissions, so both files
|
|
170
|
+
are readable by anything running as you. That is usually fine on a personal machine. On a shared
|
|
171
|
+
one, restrict the directory yourself:
|
|
172
|
+
|
|
173
|
+
```
|
|
174
|
+
icacls %USERPROFILE%\.page-scanner /inheritance:r /grant:r %USERNAME%:F
|
|
175
|
+
```
|
|
176
|
+
|
|
177
|
+
## Security
|
|
178
|
+
|
|
179
|
+
The token is the only thing between a local process and a scan of any tab you have open, because a
|
|
180
|
+
loopback port is reachable by everything running as you. So:
|
|
181
|
+
|
|
182
|
+
- The bridge binds `127.0.0.1` only, never `0.0.0.0`.
|
|
183
|
+
- Every connection must present a `chrome-extension://` Origin **and** the shared token in its
|
|
184
|
+
first frame. The Origin check alone is not enough: a local process can forge that header.
|
|
185
|
+
- There is no port discovery. Loopback `fetch` is blocked for an extension origin by Local Network
|
|
186
|
+
Access, so probing for a port would need a host permission the extension does not have.
|
|
187
|
+
- The token is printed by `pair`, on stdout, and never appears in any other output or in the log.
|
|
188
|
+
- The extension refuses tabs Chrome will not let it touch: `chrome://` pages, the Web Store, and
|
|
189
|
+
the PDF viewer.
|
|
190
|
+
|
|
191
|
+
## Using it from Node
|
|
192
|
+
|
|
193
|
+
```js
|
|
194
|
+
import { scan, listTabs } from '@page-scanner/cli';
|
|
195
|
+
|
|
196
|
+
const { tabs } = await listTabs();
|
|
197
|
+
const result = await scan({ tabId: tabs[0].tabId, out: './out/', format: 'pdf' });
|
|
198
|
+
console.log(result.path, result.selectableText);
|
|
199
|
+
```
|
|
200
|
+
|
|
201
|
+
The package's main entry point does not load `ws`: the bridge runs in the daemon, which is a
|
|
202
|
+
separate process. `@page-scanner/cli/daemon` is the entry point that starts one in-process, and it is
|
|
203
|
+
the only one that pulls the WebSocket server in.
|
|
204
|
+
|
|
205
|
+
## Limits
|
|
206
|
+
|
|
207
|
+
- No raster fallback. The extension can stitch screenshots when Chrome's debugger cannot attach,
|
|
208
|
+
but that path needs a user gesture, so a scan started from here fails loudly instead.
|
|
209
|
+
- `chrome.debugger` cannot attach while DevTools is open on the same tab. Close it, or scan a
|
|
210
|
+
different tab.
|
|
211
|
+
- A page larger than 60,000 CSS pixels on a side is captured up to that limit, and the result says
|
|
212
|
+
so in `truncated`.
|
|
213
|
+
- One pairing per machine, shared by every browser profile that connects to it.
|
|
214
|
+
|
|
215
|
+
## Licence
|
|
216
|
+
|
|
217
|
+
Apache-2.0. See [LICENSE](LICENSE).
|
package/dist/api.d.ts
ADDED
|
@@ -0,0 +1,87 @@
|
|
|
1
|
+
import type { PairingConfig } from './config.js';
|
|
2
|
+
import type { ExportFormatId, PageSizeId, TabSummary, TruncationReport, VideoHandling, WindowSummary } from './protocol.js';
|
|
3
|
+
import { stopDaemon, type ConnectOptions } from './daemon/client.js';
|
|
4
|
+
import type { ConnectedBrowser } from './bridge/server.js';
|
|
5
|
+
export interface CommonOptions extends ConnectOptions {
|
|
6
|
+
/** Id or label of the browser to act on. Optional when only one is connected. */
|
|
7
|
+
browser?: string;
|
|
8
|
+
/** How long to wait for a browser to connect. 0 fails immediately. */
|
|
9
|
+
waitSeconds?: number;
|
|
10
|
+
}
|
|
11
|
+
export interface ScanOptions extends CommonOptions {
|
|
12
|
+
url?: string;
|
|
13
|
+
tabId?: number;
|
|
14
|
+
windowId?: number;
|
|
15
|
+
format?: ExportFormatId;
|
|
16
|
+
pageSize?: PageSizeId;
|
|
17
|
+
quality?: number;
|
|
18
|
+
videoHandling?: VideoHandling;
|
|
19
|
+
openEditor?: boolean;
|
|
20
|
+
/** A file, or a directory to put the browser's suggested filename in. */
|
|
21
|
+
out?: string;
|
|
22
|
+
/** What a relative `out` is relative to. Defaults to process.cwd(). */
|
|
23
|
+
cwd?: string;
|
|
24
|
+
/** How long to give the browser to produce the capture. */
|
|
25
|
+
timeoutSeconds?: number;
|
|
26
|
+
}
|
|
27
|
+
export interface ScanResult {
|
|
28
|
+
/** Absolute path of the file this wrote. */
|
|
29
|
+
path: string;
|
|
30
|
+
width: number;
|
|
31
|
+
height: number;
|
|
32
|
+
mode: 'vector' | 'raster';
|
|
33
|
+
/** True only for a PDF that came out of the vector pipeline. */
|
|
34
|
+
selectableText: boolean;
|
|
35
|
+
/** Null rather than absent: the question was asked and answered. */
|
|
36
|
+
truncated: TruncationReport | null;
|
|
37
|
+
browserId: string;
|
|
38
|
+
fileName: string;
|
|
39
|
+
}
|
|
40
|
+
export interface TabsResult {
|
|
41
|
+
browserId: string;
|
|
42
|
+
label: string;
|
|
43
|
+
windows: WindowSummary[];
|
|
44
|
+
tabs: TabSummary[];
|
|
45
|
+
}
|
|
46
|
+
export interface StatusReport {
|
|
47
|
+
version: string;
|
|
48
|
+
paired: boolean;
|
|
49
|
+
bridgePort: number;
|
|
50
|
+
configPath: string;
|
|
51
|
+
/** False on Windows, where the 0600 on the config file is not enforced. */
|
|
52
|
+
configOwnerOnly: boolean;
|
|
53
|
+
daemon: {
|
|
54
|
+
running: false;
|
|
55
|
+
} | {
|
|
56
|
+
running: true;
|
|
57
|
+
pid: number;
|
|
58
|
+
rpcPort: number;
|
|
59
|
+
version: string;
|
|
60
|
+
};
|
|
61
|
+
browsers: ConnectedBrowser[];
|
|
62
|
+
}
|
|
63
|
+
export interface PairResult extends PairingConfig {
|
|
64
|
+
configPath: string;
|
|
65
|
+
/** False on Windows: NTFS does not implement the mode the file is written with. */
|
|
66
|
+
ownerOnly: boolean;
|
|
67
|
+
}
|
|
68
|
+
/**
|
|
69
|
+
* Writes (or rotates) the pairing and restarts the daemon so it picks the new
|
|
70
|
+
* one up. A daemon holding the old token would keep refusing the browser.
|
|
71
|
+
*/
|
|
72
|
+
export declare function pair(options?: {
|
|
73
|
+
port?: number;
|
|
74
|
+
rotate?: boolean;
|
|
75
|
+
} & ConnectOptions): Promise<PairResult>;
|
|
76
|
+
export declare function listBrowsers(options?: ConnectOptions): Promise<ConnectedBrowser[]>;
|
|
77
|
+
/** Blocks until a browser is connected, or the wait runs out. */
|
|
78
|
+
export declare function waitForBrowser(options?: CommonOptions): Promise<{
|
|
79
|
+
browserId: string;
|
|
80
|
+
label: string;
|
|
81
|
+
}>;
|
|
82
|
+
export declare function listTabs(options?: CommonOptions): Promise<TabsResult>;
|
|
83
|
+
export declare function scan(options: ScanOptions): Promise<ScanResult>;
|
|
84
|
+
/** Everything `page-scanner status` reports, without starting a daemon. */
|
|
85
|
+
export declare function status(): Promise<StatusReport>;
|
|
86
|
+
export { stopDaemon as stop };
|
|
87
|
+
//# sourceMappingURL=api.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"api.d.ts","sourceRoot":"","sources":["../src/api.ts"],"names":[],"mappings":"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"}
|
package/dist/api.js
ADDED
|
@@ -0,0 +1,132 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* The programmatic surface, and what every command is built on.
|
|
3
|
+
*
|
|
4
|
+
* Nothing here loads `ws`. The daemon is a separate process reached over
|
|
5
|
+
* loopback HTTP, so a caller that only wants to take a scan never pays for
|
|
6
|
+
* the WebSocket server; `@page-scanner/cli/daemon` is the subpath that does.
|
|
7
|
+
*/
|
|
8
|
+
import { ensureConfig, readConfig, configPath, configFileIsOwnerOnly } from './config.js';
|
|
9
|
+
import { PageScannerError } from './errors.js';
|
|
10
|
+
import { resolveOutputPath, writeScanFile } from './output.js';
|
|
11
|
+
import { DEFAULT_PAGE_SIZE } from './protocol.js';
|
|
12
|
+
import { connectDaemon, stopDaemon } from './daemon/client.js';
|
|
13
|
+
import { readDaemonState } from './daemon/state.js';
|
|
14
|
+
import { CLI_VERSION } from './version.js';
|
|
15
|
+
function requirePairing() {
|
|
16
|
+
const config = readConfig();
|
|
17
|
+
if (!config.token) {
|
|
18
|
+
throw new PageScannerError('NOT_PAIRED', 'This machine has no Page Scanner pairing.', 'Run `page-scanner pair`, then paste the port and token into the extension settings page.');
|
|
19
|
+
}
|
|
20
|
+
return config;
|
|
21
|
+
}
|
|
22
|
+
/**
|
|
23
|
+
* Writes (or rotates) the pairing and restarts the daemon so it picks the new
|
|
24
|
+
* one up. A daemon holding the old token would keep refusing the browser.
|
|
25
|
+
*/
|
|
26
|
+
export async function pair(options = {}) {
|
|
27
|
+
const previous = readDaemonState();
|
|
28
|
+
if (previous)
|
|
29
|
+
await stopDaemon().catch(() => undefined);
|
|
30
|
+
const config = ensureConfig({
|
|
31
|
+
...(options.port !== undefined ? { port: options.port } : {}),
|
|
32
|
+
rotate: options.rotate ?? false,
|
|
33
|
+
});
|
|
34
|
+
return {
|
|
35
|
+
...config,
|
|
36
|
+
configPath: configPath(),
|
|
37
|
+
ownerOnly: configFileIsOwnerOnly(),
|
|
38
|
+
};
|
|
39
|
+
}
|
|
40
|
+
export async function listBrowsers(options = {}) {
|
|
41
|
+
requirePairing();
|
|
42
|
+
const daemon = await connectDaemon(options);
|
|
43
|
+
const answer = await daemon.call('listBrowsers');
|
|
44
|
+
return answer.browsers;
|
|
45
|
+
}
|
|
46
|
+
/** Blocks until a browser is connected, or the wait runs out. */
|
|
47
|
+
export async function waitForBrowser(options = {}) {
|
|
48
|
+
requirePairing();
|
|
49
|
+
const daemon = await connectDaemon(options);
|
|
50
|
+
const waitMs = Math.round((options.waitSeconds ?? 30) * 1000);
|
|
51
|
+
return daemon.call('waitForBrowser', {
|
|
52
|
+
...(options.browser !== undefined ? { browserId: options.browser } : {}),
|
|
53
|
+
timeoutMs: waitMs,
|
|
54
|
+
}, waitMs + 30_000);
|
|
55
|
+
}
|
|
56
|
+
export async function listTabs(options = {}) {
|
|
57
|
+
requirePairing();
|
|
58
|
+
const daemon = await connectDaemon(options);
|
|
59
|
+
const waitMs = Math.round((options.waitSeconds ?? 30) * 1000);
|
|
60
|
+
return daemon.call('listTabs', {
|
|
61
|
+
...(options.browser !== undefined ? { browserId: options.browser } : {}),
|
|
62
|
+
timeoutMs: waitMs,
|
|
63
|
+
}, waitMs + 30_000);
|
|
64
|
+
}
|
|
65
|
+
export async function scan(options) {
|
|
66
|
+
requirePairing();
|
|
67
|
+
if ((options.url === undefined) === (options.tabId === undefined)) {
|
|
68
|
+
throw new PageScannerError('BAD_REQUEST', 'Give exactly one of url and tabId.');
|
|
69
|
+
}
|
|
70
|
+
const waitMs = Math.round((options.waitSeconds ?? 30) * 1000);
|
|
71
|
+
const scanMs = Math.round((options.timeoutSeconds ?? 120) * 1000);
|
|
72
|
+
const daemon = await connectDaemon(options);
|
|
73
|
+
const answer = await daemon.call('scan', {
|
|
74
|
+
...(options.browser !== undefined ? { browserId: options.browser } : {}),
|
|
75
|
+
...(options.url !== undefined ? { url: options.url } : {}),
|
|
76
|
+
...(options.tabId !== undefined ? { tabId: options.tabId } : {}),
|
|
77
|
+
...(options.windowId !== undefined ? { windowId: options.windowId } : {}),
|
|
78
|
+
format: options.format ?? 'pdf',
|
|
79
|
+
pageSize: options.pageSize ?? DEFAULT_PAGE_SIZE,
|
|
80
|
+
...(options.quality !== undefined ? { quality: options.quality } : {}),
|
|
81
|
+
...(options.videoHandling !== undefined ? { videoHandling: options.videoHandling } : {}),
|
|
82
|
+
...(options.openEditor !== undefined ? { openEditor: options.openEditor } : {}),
|
|
83
|
+
timeoutMs: waitMs,
|
|
84
|
+
scanTimeoutMs: scanMs,
|
|
85
|
+
}, waitMs + scanMs);
|
|
86
|
+
// The daemon hands back bytes, not a path. It may have been started hours
|
|
87
|
+
// ago from another directory; only this process knows what a relative
|
|
88
|
+
// `--out` means.
|
|
89
|
+
const target = resolveOutputPath(options.out, answer.fileName, options.cwd);
|
|
90
|
+
writeScanFile(target, answer.bytesBase64);
|
|
91
|
+
return {
|
|
92
|
+
path: target,
|
|
93
|
+
width: answer.width,
|
|
94
|
+
height: answer.height,
|
|
95
|
+
mode: answer.mode,
|
|
96
|
+
selectableText: answer.mode === 'vector' && (options.format ?? 'pdf') === 'pdf',
|
|
97
|
+
truncated: answer.truncated,
|
|
98
|
+
browserId: answer.browserId,
|
|
99
|
+
fileName: answer.fileName,
|
|
100
|
+
};
|
|
101
|
+
}
|
|
102
|
+
/** Everything `page-scanner status` reports, without starting a daemon. */
|
|
103
|
+
export async function status() {
|
|
104
|
+
const config = readConfig();
|
|
105
|
+
const state = readDaemonState();
|
|
106
|
+
let browsers = [];
|
|
107
|
+
if (state) {
|
|
108
|
+
// Best effort. A daemon that has just died should show as stopped rather
|
|
109
|
+
// than taking the whole command down.
|
|
110
|
+
try {
|
|
111
|
+
const daemon = await connectDaemon({ startDaemon: () => undefined, startTimeoutMs: 0 });
|
|
112
|
+
const answer = await daemon.call('listBrowsers');
|
|
113
|
+
browsers = answer.browsers;
|
|
114
|
+
}
|
|
115
|
+
catch {
|
|
116
|
+
browsers = [];
|
|
117
|
+
}
|
|
118
|
+
}
|
|
119
|
+
return {
|
|
120
|
+
version: CLI_VERSION,
|
|
121
|
+
paired: config.token.length > 0,
|
|
122
|
+
bridgePort: config.port,
|
|
123
|
+
configPath: configPath(),
|
|
124
|
+
configOwnerOnly: configFileIsOwnerOnly(),
|
|
125
|
+
daemon: state
|
|
126
|
+
? { running: true, pid: state.pid, rpcPort: state.rpcPort, version: state.version }
|
|
127
|
+
: { running: false },
|
|
128
|
+
browsers,
|
|
129
|
+
};
|
|
130
|
+
}
|
|
131
|
+
export { stopDaemon as stop };
|
|
132
|
+
//# sourceMappingURL=api.js.map
|
package/dist/api.js.map
ADDED
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"api.js","sourceRoot":"","sources":["../src/api.ts"],"names":[],"mappings":"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"}
|
package/dist/bin.d.ts
ADDED
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"bin.d.ts","sourceRoot":"","sources":["../src/bin.ts"],"names":[],"mappings":""}
|