@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.
Files changed (75) hide show
  1. package/LICENSE +201 -0
  2. package/README.md +217 -0
  3. package/dist/api.d.ts +87 -0
  4. package/dist/api.d.ts.map +1 -0
  5. package/dist/api.js +132 -0
  6. package/dist/api.js.map +1 -0
  7. package/dist/bin.d.ts +3 -0
  8. package/dist/bin.d.ts.map +1 -0
  9. package/dist/bin.js +49 -0
  10. package/dist/bin.js.map +1 -0
  11. package/dist/bridge/server.d.ts +97 -0
  12. package/dist/bridge/server.d.ts.map +1 -0
  13. package/dist/bridge/server.js +329 -0
  14. package/dist/bridge/server.js.map +1 -0
  15. package/dist/bridge/tokens.d.ts +10 -0
  16. package/dist/bridge/tokens.d.ts.map +1 -0
  17. package/dist/bridge/tokens.js +15 -0
  18. package/dist/bridge/tokens.js.map +1 -0
  19. package/dist/cli/args.d.ts +63 -0
  20. package/dist/cli/args.d.ts.map +1 -0
  21. package/dist/cli/args.js +388 -0
  22. package/dist/cli/args.js.map +1 -0
  23. package/dist/cli/commands.d.ts +8 -0
  24. package/dist/cli/commands.d.ts.map +1 -0
  25. package/dist/cli/commands.js +234 -0
  26. package/dist/cli/commands.js.map +1 -0
  27. package/dist/cli/format.d.ts +22 -0
  28. package/dist/cli/format.d.ts.map +1 -0
  29. package/dist/cli/format.js +152 -0
  30. package/dist/cli/format.js.map +1 -0
  31. package/dist/config.d.ts +17 -0
  32. package/dist/config.d.ts.map +1 -0
  33. package/dist/config.js +54 -0
  34. package/dist/config.js.map +1 -0
  35. package/dist/daemon/client.d.ts +28 -0
  36. package/dist/daemon/client.d.ts.map +1 -0
  37. package/dist/daemon/client.js +139 -0
  38. package/dist/daemon/client.js.map +1 -0
  39. package/dist/daemon/rpc-server.d.ts +31 -0
  40. package/dist/daemon/rpc-server.d.ts.map +1 -0
  41. package/dist/daemon/rpc-server.js +254 -0
  42. package/dist/daemon/rpc-server.js.map +1 -0
  43. package/dist/daemon/run.d.ts +20 -0
  44. package/dist/daemon/run.d.ts.map +1 -0
  45. package/dist/daemon/run.js +129 -0
  46. package/dist/daemon/run.js.map +1 -0
  47. package/dist/daemon/self.d.ts +25 -0
  48. package/dist/daemon/self.d.ts.map +1 -0
  49. package/dist/daemon/self.js +113 -0
  50. package/dist/daemon/self.js.map +1 -0
  51. package/dist/daemon/state.d.ts +25 -0
  52. package/dist/daemon/state.d.ts.map +1 -0
  53. package/dist/daemon/state.js +116 -0
  54. package/dist/daemon/state.js.map +1 -0
  55. package/dist/errors.d.ts +32 -0
  56. package/dist/errors.d.ts.map +1 -0
  57. package/dist/errors.js +83 -0
  58. package/dist/errors.js.map +1 -0
  59. package/dist/index.d.ts +17 -0
  60. package/dist/index.d.ts.map +1 -0
  61. package/dist/index.js +16 -0
  62. package/dist/index.js.map +1 -0
  63. package/dist/output.d.ts +13 -0
  64. package/dist/output.d.ts.map +1 -0
  65. package/dist/output.js +71 -0
  66. package/dist/output.js.map +1 -0
  67. package/dist/protocol.d.ts +144 -0
  68. package/dist/protocol.d.ts.map +1 -0
  69. package/dist/protocol.js +128 -0
  70. package/dist/protocol.js.map +1 -0
  71. package/dist/version.d.ts +11 -0
  72. package/dist/version.d.ts.map +1 -0
  73. package/dist/version.js +11 -0
  74. package/dist/version.js.map +1 -0
  75. 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
@@ -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,3 @@
1
+ #!/usr/bin/env node
2
+ export {};
3
+ //# sourceMappingURL=bin.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"bin.d.ts","sourceRoot":"","sources":["../src/bin.ts"],"names":[],"mappings":""}