@gohcltech/edge-print-client 0.2.0-dev.6
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/README.md +301 -0
- package/dist/edge-print.d.ts +367 -0
- package/dist/edge-print.js +259 -0
- package/package.json +22 -0
- package/src/edge-print.ts +484 -0
- package/tsconfig.json +13 -0
package/README.md
ADDED
|
@@ -0,0 +1,301 @@
|
|
|
1
|
+
# @gohcltech/edge-print-client
|
|
2
|
+
|
|
3
|
+
Browser-side WebSocket client for the [Edge Printing](https://github.com/gohcltech/edge-printing) agent. Connects your web app to a locally-installed print agent so users can print PDFs, images, labels, and raw commands to any printer on their machine — without browser print dialogs or plugins.
|
|
4
|
+
|
|
5
|
+
Intended as a drop-in replacement for qz-tray.js with a simpler token-based auth model.
|
|
6
|
+
|
|
7
|
+
---
|
|
8
|
+
|
|
9
|
+
## Prerequisites
|
|
10
|
+
|
|
11
|
+
1. **Edge Printing agent** must be installed and running on the user's machine. The agent listens on `wss://127.0.0.1:8181` by default.
|
|
12
|
+
2. **API token** — the user opens the Edge Printing settings window and copies their token. Your app must receive this token (e.g. via your own backend, or by prompting the user to paste it).
|
|
13
|
+
|
|
14
|
+
---
|
|
15
|
+
|
|
16
|
+
## Installation
|
|
17
|
+
|
|
18
|
+
```bash
|
|
19
|
+
npm install @gohcltech/edge-print-client
|
|
20
|
+
# or
|
|
21
|
+
pnpm add @gohcltech/edge-print-client
|
|
22
|
+
```
|
|
23
|
+
|
|
24
|
+
---
|
|
25
|
+
|
|
26
|
+
## Quick start
|
|
27
|
+
|
|
28
|
+
```ts
|
|
29
|
+
import ep from '@gohcltech/edge-print-client'
|
|
30
|
+
|
|
31
|
+
// 1. Connect and authenticate
|
|
32
|
+
await ep.connect({ token: 'user-api-token-here' })
|
|
33
|
+
|
|
34
|
+
// 2. List available printers
|
|
35
|
+
const printers = await ep.printers()
|
|
36
|
+
console.log(printers.map(p => p.name))
|
|
37
|
+
|
|
38
|
+
// 3. Print a PDF (base64-encoded)
|
|
39
|
+
const jobId = await ep.print(
|
|
40
|
+
{ printer: 'Office Laser', copies: 1 },
|
|
41
|
+
[{ type: 'pixel', format: 'pdf', flavor: 'base64', data: pdfBase64 }],
|
|
42
|
+
)
|
|
43
|
+
console.log('Queued as', jobId)
|
|
44
|
+
|
|
45
|
+
// 4. Disconnect when done
|
|
46
|
+
ep.disconnect()
|
|
47
|
+
```
|
|
48
|
+
|
|
49
|
+
---
|
|
50
|
+
|
|
51
|
+
## API reference
|
|
52
|
+
|
|
53
|
+
### `connect(options)`
|
|
54
|
+
|
|
55
|
+
Opens a WebSocket connection to the agent and authenticates. Retries automatically on failure.
|
|
56
|
+
|
|
57
|
+
```ts
|
|
58
|
+
await ep.connect({
|
|
59
|
+
host: '127.0.0.1', // default
|
|
60
|
+
port: 8181, // default
|
|
61
|
+
token: 'abc123', // required — from the agent settings window
|
|
62
|
+
retries: 3, // default — additional attempts after the first failure
|
|
63
|
+
retryDelay: 1000, // default — ms between retries
|
|
64
|
+
})
|
|
65
|
+
```
|
|
66
|
+
|
|
67
|
+
| Option | Type | Default | Description |
|
|
68
|
+
|---|---|---|---|
|
|
69
|
+
| `host` | `string` | `'127.0.0.1'` | Hostname or IP of the agent machine |
|
|
70
|
+
| `port` | `number` | `8181` | Port the agent listens on |
|
|
71
|
+
| `token` | `string` | _(required)_ | API token from the Edge Printing settings window |
|
|
72
|
+
| `retries` | `number` | `3` | Max additional connection attempts after the first failure |
|
|
73
|
+
| `retryDelay` | `number` | `1000` | Ms to wait between retry attempts |
|
|
74
|
+
|
|
75
|
+
Throws if the agent is unreachable or the token is rejected after all retries.
|
|
76
|
+
|
|
77
|
+
---
|
|
78
|
+
|
|
79
|
+
### `printers()`
|
|
80
|
+
|
|
81
|
+
Returns all printers available on the agent machine.
|
|
82
|
+
|
|
83
|
+
```ts
|
|
84
|
+
const printers = await ep.printers()
|
|
85
|
+
// [{ name: 'Office Laser', is_default: true, status: 'idle', color: true, ... }]
|
|
86
|
+
```
|
|
87
|
+
|
|
88
|
+
Each `PrinterInfo` object includes:
|
|
89
|
+
|
|
90
|
+
| Field | Type | Description |
|
|
91
|
+
|---|---|---|
|
|
92
|
+
| `name` | `string` | OS printer name — use this in `PrintConfig.printer` |
|
|
93
|
+
| `is_default` | `boolean` | `true` if this is the system default |
|
|
94
|
+
| `status` | `string` | `"idle"` \| `"printing"` \| `"offline"` \| `"error"` \| `"paused"` \| `"paper_jam"` \| `"paper_out"` \| `"disabled"` \| `"unknown"` |
|
|
95
|
+
| `driver` | `string?` | Driver name |
|
|
96
|
+
| `port` | `string?` | Port or URI (e.g. `"USB001"`, `"ipp://…"`) |
|
|
97
|
+
| `location` | `string?` | Physical location string from printer properties |
|
|
98
|
+
| `comment` | `string?` | Freeform comment from printer properties |
|
|
99
|
+
| `share_name` | `string?` | Windows share name if the printer is network-shared |
|
|
100
|
+
| `color` | `boolean?` | `true` if the printer supports color output |
|
|
101
|
+
| `duplex` | `boolean?` | `true` if the printer supports double-sided printing |
|
|
102
|
+
| `trays` | `TrayInfo[]?` | Input trays/bins (see below) |
|
|
103
|
+
| `papers` | `string[]?` | All supported paper sizes (e.g. `["Letter", "A4"]`) |
|
|
104
|
+
| `copies_max` | `number?` | Maximum copies the driver accepts in one job |
|
|
105
|
+
| `orientations` | `string[]?` | Supported orientations (e.g. `["portrait", "landscape"]`) |
|
|
106
|
+
|
|
107
|
+
`TrayInfo`:
|
|
108
|
+
|
|
109
|
+
| Field | Type | Description |
|
|
110
|
+
|---|---|---|
|
|
111
|
+
| `name` | `string` | Tray name — use this in `PrintConfig.tray` |
|
|
112
|
+
| `papers` | `string[]?` | Paper sizes this tray supports; may be empty if the driver doesn't report per-tray capability — fall back to `PrinterInfo.papers` |
|
|
113
|
+
|
|
114
|
+
---
|
|
115
|
+
|
|
116
|
+
### `defaultPrinter()`
|
|
117
|
+
|
|
118
|
+
Returns the name of the OS default printer. Cheaper than `printers()` when you only need the default.
|
|
119
|
+
|
|
120
|
+
```ts
|
|
121
|
+
const name = await ep.defaultPrinter() // "Office Laser"
|
|
122
|
+
```
|
|
123
|
+
|
|
124
|
+
---
|
|
125
|
+
|
|
126
|
+
### `print(config, data)`
|
|
127
|
+
|
|
128
|
+
Submits a print job. Returns the job ID assigned by the agent.
|
|
129
|
+
|
|
130
|
+
```ts
|
|
131
|
+
const jobId = await ep.print(config, data)
|
|
132
|
+
```
|
|
133
|
+
|
|
134
|
+
**`config`** — `PrintConfig`
|
|
135
|
+
|
|
136
|
+
| Field | Type | Description |
|
|
137
|
+
|---|---|---|
|
|
138
|
+
| `printer` | `string \| { host, port }` | Printer name from `PrinterInfo.name`, or a remote network address |
|
|
139
|
+
| `copies` | `number?` | Number of copies (default: 1) |
|
|
140
|
+
| `duplex` | `'none' \| 'long-edge' \| 'short-edge'?` | Duplex mode |
|
|
141
|
+
| `orientation` | `'portrait' \| 'landscape'?` | Page orientation |
|
|
142
|
+
| `jobName` | `string?` | Name shown in the OS print queue |
|
|
143
|
+
| `colorType` | `'color' \| 'grayscale' \| 'black-white'?` | Color mode |
|
|
144
|
+
| `paperSize` | `string?` | Paper size from `PrinterInfo.papers` (e.g. `"Letter"`) |
|
|
145
|
+
| `tray` | `string?` | Tray name from `TrayInfo.name` (e.g. `"Tray 1"`) |
|
|
146
|
+
|
|
147
|
+
**`data`** — `PrintData[]`
|
|
148
|
+
|
|
149
|
+
Each item in the array is one unit of content (page, label, etc.).
|
|
150
|
+
|
|
151
|
+
| Field | Type | Description |
|
|
152
|
+
|---|---|---|
|
|
153
|
+
| `type` | `'raw' \| 'pixel'` | `'raw'` — bytes forwarded verbatim (ESC/POS, ZPL, …); `'pixel'` — agent rasterises before printing (PDF, HTML, image) |
|
|
154
|
+
| `format` | `'command' \| 'pdf' \| 'html' \| 'image'` | Content format |
|
|
155
|
+
| `flavor` | `'plain' \| 'base64' \| 'hex' \| 'file'` | How `data` is encoded; `'file'` = absolute path on the agent machine |
|
|
156
|
+
| `data` | `string` | The content, encoded per `flavor` |
|
|
157
|
+
| `options` | `Record<string, unknown>?` | Format-specific options forwarded to the agent renderer |
|
|
158
|
+
|
|
159
|
+
#### Print examples
|
|
160
|
+
|
|
161
|
+
```ts
|
|
162
|
+
// PDF from base64
|
|
163
|
+
await ep.print(
|
|
164
|
+
{ printer: 'Office Laser', copies: 2, duplex: 'long-edge' },
|
|
165
|
+
[{ type: 'pixel', format: 'pdf', flavor: 'base64', data: pdfBase64 }],
|
|
166
|
+
)
|
|
167
|
+
|
|
168
|
+
// ZPL label (raw command)
|
|
169
|
+
await ep.print(
|
|
170
|
+
{ printer: 'Zebra ZT410' },
|
|
171
|
+
[{ type: 'raw', format: 'command', flavor: 'plain', data: '^XA^FO50,50^ADN,36,20^FDHello^FS^XZ' }],
|
|
172
|
+
)
|
|
173
|
+
|
|
174
|
+
// Image file already on the agent machine
|
|
175
|
+
await ep.print(
|
|
176
|
+
{ printer: 'Office Laser', paperSize: 'Letter' },
|
|
177
|
+
[{ type: 'pixel', format: 'image', flavor: 'file', data: 'C:\\Reports\\invoice.png' }],
|
|
178
|
+
)
|
|
179
|
+
```
|
|
180
|
+
|
|
181
|
+
---
|
|
182
|
+
|
|
183
|
+
### `disconnect()`
|
|
184
|
+
|
|
185
|
+
Closes the connection. Any in-flight requests are rejected. Safe to call when already disconnected.
|
|
186
|
+
|
|
187
|
+
```ts
|
|
188
|
+
ep.disconnect()
|
|
189
|
+
```
|
|
190
|
+
|
|
191
|
+
---
|
|
192
|
+
|
|
193
|
+
### `isConnected()`
|
|
194
|
+
|
|
195
|
+
Returns `true` when the WebSocket is open and authenticated.
|
|
196
|
+
|
|
197
|
+
```ts
|
|
198
|
+
if (!ep.isConnected()) {
|
|
199
|
+
await ep.connect({ token })
|
|
200
|
+
}
|
|
201
|
+
```
|
|
202
|
+
|
|
203
|
+
---
|
|
204
|
+
|
|
205
|
+
### `onClose(fn)`
|
|
206
|
+
|
|
207
|
+
Registers a callback that fires whenever the connection closes — network drop, agent restart, or an explicit `disconnect()` call. Multiple listeners are supported.
|
|
208
|
+
|
|
209
|
+
```ts
|
|
210
|
+
ep.onClose(() => {
|
|
211
|
+
console.warn('Connection lost — reconnecting…')
|
|
212
|
+
reconnect()
|
|
213
|
+
})
|
|
214
|
+
```
|
|
215
|
+
|
|
216
|
+
---
|
|
217
|
+
|
|
218
|
+
## Using a custom instance
|
|
219
|
+
|
|
220
|
+
The default export `ep` is a module-level singleton. If you need to connect to multiple agents simultaneously, create separate instances:
|
|
221
|
+
|
|
222
|
+
```ts
|
|
223
|
+
import { EdgePrintClient } from '@gohcltech/edge-print-client'
|
|
224
|
+
|
|
225
|
+
const officeAgent = new EdgePrintClient()
|
|
226
|
+
const warehouseAgent = new EdgePrintClient()
|
|
227
|
+
|
|
228
|
+
await officeAgent.connect({ token: officeToken })
|
|
229
|
+
await warehouseAgent.connect({ host: '192.168.1.50', token: warehouseToken })
|
|
230
|
+
```
|
|
231
|
+
|
|
232
|
+
---
|
|
233
|
+
|
|
234
|
+
## Reconnect pattern
|
|
235
|
+
|
|
236
|
+
The client does not reconnect automatically after a connection drop. A simple
|
|
237
|
+
exponential-backoff reconnect loop:
|
|
238
|
+
|
|
239
|
+
```ts
|
|
240
|
+
import ep, { ConnectOptions } from '@gohcltech/edge-print-client'
|
|
241
|
+
|
|
242
|
+
async function connectWithBackoff(opts: ConnectOptions, maxMs = 30_000) {
|
|
243
|
+
let delay = 1_000
|
|
244
|
+
while (true) {
|
|
245
|
+
try {
|
|
246
|
+
await ep.connect(opts)
|
|
247
|
+
return
|
|
248
|
+
} catch {
|
|
249
|
+
await new Promise(r => setTimeout(r, delay))
|
|
250
|
+
delay = Math.min(delay * 2, maxMs)
|
|
251
|
+
}
|
|
252
|
+
}
|
|
253
|
+
}
|
|
254
|
+
|
|
255
|
+
ep.onClose(() => connectWithBackoff({ token: storedToken }))
|
|
256
|
+
await connectWithBackoff({ token: storedToken })
|
|
257
|
+
```
|
|
258
|
+
|
|
259
|
+
---
|
|
260
|
+
|
|
261
|
+
## Troubleshooting
|
|
262
|
+
|
|
263
|
+
### Browser blocks the WebSocket connection (`net::ERR_CERT_AUTHORITY_INVALID`)
|
|
264
|
+
|
|
265
|
+
The agent uses `wss://` (TLS) so it works from HTTPS pages. Its certificate is
|
|
266
|
+
self-signed and must be trusted by the OS before the browser will allow the
|
|
267
|
+
connection.
|
|
268
|
+
|
|
269
|
+
**This is handled automatically by the Edge Printing installer.** If a user
|
|
270
|
+
sees this error it almost always means one of the following:
|
|
271
|
+
|
|
272
|
+
| Cause | Fix |
|
|
273
|
+
|---|---|
|
|
274
|
+
| Agent was not installed with administrator rights | Re-run the installer as an administrator |
|
|
275
|
+
| OS certificate store was updated and the trust was removed | Re-run the installer to re-register the certificate |
|
|
276
|
+
| Corporate policy blocks user-trusted certificates | Ask IT to trust the certificate via Group Policy, or whitelist `127.0.0.1:8181` |
|
|
277
|
+
| macOS Keychain prompt was dismissed without clicking "Always Allow" | Open Keychain Access, find the **Edge Printing** certificate, and set trust to **Always Trust** |
|
|
278
|
+
|
|
279
|
+
To confirm the certificate is trusted, open `https://127.0.0.1:8181` in the
|
|
280
|
+
browser. If the page loads (even with an empty body) the certificate is fine.
|
|
281
|
+
If you see a security warning, the certificate is not yet trusted.
|
|
282
|
+
|
|
283
|
+
### `connect()` throws "Cannot reach Edge Printing agent"
|
|
284
|
+
|
|
285
|
+
- Confirm the Edge Printing agent is running (check the system tray / menu bar).
|
|
286
|
+
- Confirm `host` and `port` match the agent's configured values (default `127.0.0.1:8181`).
|
|
287
|
+
|
|
288
|
+
### `connect()` throws after authentication
|
|
289
|
+
|
|
290
|
+
The token was rejected. Generate a new one from the Edge Printing settings window.
|
|
291
|
+
|
|
292
|
+
### Requests time out after 30 seconds
|
|
293
|
+
|
|
294
|
+
The agent accepted the connection but stopped responding. Restart the agent. If
|
|
295
|
+
the problem persists, file an issue with the agent log attached.
|
|
296
|
+
|
|
297
|
+
---
|
|
298
|
+
|
|
299
|
+
## License
|
|
300
|
+
|
|
301
|
+
MIT © GOH Clinical Technology
|
|
@@ -0,0 +1,367 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* @module edge-print
|
|
3
|
+
*
|
|
4
|
+
* Browser-side WebSocket client for the Edge Printing agent.
|
|
5
|
+
* Drop-in replacement for qz-tray.js with a simpler token-based auth model.
|
|
6
|
+
*
|
|
7
|
+
* @example
|
|
8
|
+
* ```ts
|
|
9
|
+
* import ep from '@gohcltech/edge-print-client'
|
|
10
|
+
*
|
|
11
|
+
* await ep.connect({ token: 'your-api-token' })
|
|
12
|
+
* const printers = await ep.printers()
|
|
13
|
+
* const jobId = await ep.print(
|
|
14
|
+
* { printer: 'Office Laser' },
|
|
15
|
+
* [{ type: 'pixel', format: 'pdf', flavor: 'base64', data: pdfBase64 }],
|
|
16
|
+
* )
|
|
17
|
+
* ```
|
|
18
|
+
*/
|
|
19
|
+
/**
|
|
20
|
+
* Identifies the target printer.
|
|
21
|
+
*
|
|
22
|
+
* - Pass a `string` to use a printer by its OS name (e.g. `"Office Laser"`).
|
|
23
|
+
* - Pass `{ host, port }` to route to a network printer by address.
|
|
24
|
+
*/
|
|
25
|
+
export type PrinterTarget = string | {
|
|
26
|
+
host: string;
|
|
27
|
+
port: number;
|
|
28
|
+
};
|
|
29
|
+
/**
|
|
30
|
+
* Configuration options for a print job.
|
|
31
|
+
*
|
|
32
|
+
* All fields except `printer` are optional; omitted fields use the printer's
|
|
33
|
+
* own defaults.
|
|
34
|
+
*/
|
|
35
|
+
export interface PrintConfig {
|
|
36
|
+
/** Target printer — OS name string or remote `{ host, port }` object. */
|
|
37
|
+
printer: PrinterTarget;
|
|
38
|
+
/** Number of copies to print (default: 1). */
|
|
39
|
+
copies?: number;
|
|
40
|
+
/**
|
|
41
|
+
* Duplex (double-sided) mode.
|
|
42
|
+
* - `'none'` — single-sided
|
|
43
|
+
* - `'long-edge'` — flip on the long edge (standard book binding)
|
|
44
|
+
* - `'short-edge'` — flip on the short edge (calendar binding)
|
|
45
|
+
*/
|
|
46
|
+
duplex?: 'none' | 'long-edge' | 'short-edge';
|
|
47
|
+
/** Page orientation (default: determined by document content). */
|
|
48
|
+
orientation?: 'portrait' | 'landscape';
|
|
49
|
+
/** Human-readable name shown in the OS print queue. */
|
|
50
|
+
jobName?: string;
|
|
51
|
+
/**
|
|
52
|
+
* Color output mode.
|
|
53
|
+
* - `'color'` — full color
|
|
54
|
+
* - `'grayscale'` — color converted to gray
|
|
55
|
+
* - `'black-white'` — pure monochrome (fastest on mono printers)
|
|
56
|
+
*/
|
|
57
|
+
colorType?: 'color' | 'grayscale' | 'black-white';
|
|
58
|
+
/**
|
|
59
|
+
* Paper size, exactly as returned by {@link PrinterInfo.papers}
|
|
60
|
+
* (e.g. `"Letter"`, `"A4"`). Omit to use the printer's current default.
|
|
61
|
+
*/
|
|
62
|
+
paperSize?: string;
|
|
63
|
+
/**
|
|
64
|
+
* Input tray, exactly as returned by {@link TrayInfo.name} inside
|
|
65
|
+
* {@link PrinterInfo.trays} (e.g. `"Tray 1"`, `"Auto"`).
|
|
66
|
+
* Omit to use the printer's current default.
|
|
67
|
+
*/
|
|
68
|
+
tray?: string;
|
|
69
|
+
}
|
|
70
|
+
/**
|
|
71
|
+
* A single unit of content to be printed.
|
|
72
|
+
*
|
|
73
|
+
* Pass an array of `PrintData` to {@link EdgePrintClient.print} — each item
|
|
74
|
+
* maps to one page or label in the job.
|
|
75
|
+
*
|
|
76
|
+
* @example PDF from a base64 string
|
|
77
|
+
* ```ts
|
|
78
|
+
* const page: PrintData = {
|
|
79
|
+
* type: 'pixel',
|
|
80
|
+
* format: 'pdf',
|
|
81
|
+
* flavor: 'base64',
|
|
82
|
+
* data: '<base64-encoded PDF>',
|
|
83
|
+
* }
|
|
84
|
+
* ```
|
|
85
|
+
*
|
|
86
|
+
* @example ZPL label (raw command)
|
|
87
|
+
* ```ts
|
|
88
|
+
* const label: PrintData = {
|
|
89
|
+
* type: 'raw',
|
|
90
|
+
* format: 'command',
|
|
91
|
+
* flavor: 'plain',
|
|
92
|
+
* data: '^XA^FO50,50^ADN,36,20^FDHello^FS^XZ',
|
|
93
|
+
* }
|
|
94
|
+
* ```
|
|
95
|
+
*/
|
|
96
|
+
export interface PrintData {
|
|
97
|
+
/**
|
|
98
|
+
* Rendering pipeline.
|
|
99
|
+
* - `'raw'` — bytes are forwarded to the printer verbatim (ESC/POS, ZPL, EPL, …)
|
|
100
|
+
* - `'pixel'` — the agent rasterises the content before printing (PDF, HTML, image)
|
|
101
|
+
*/
|
|
102
|
+
type: 'raw' | 'pixel';
|
|
103
|
+
/**
|
|
104
|
+
* Content format.
|
|
105
|
+
* - `'command'` — raw printer command language
|
|
106
|
+
* - `'pdf'` — Portable Document Format
|
|
107
|
+
* - `'html'` — HTML markup (agent renders to pixels)
|
|
108
|
+
* - `'image'` — raster image (PNG, JPEG, …)
|
|
109
|
+
*/
|
|
110
|
+
format: 'command' | 'pdf' | 'html' | 'image';
|
|
111
|
+
/**
|
|
112
|
+
* How `data` is encoded.
|
|
113
|
+
* - `'plain'` — UTF-8 text
|
|
114
|
+
* - `'base64'` — Base64-encoded binary
|
|
115
|
+
* - `'hex'` — hex-encoded binary
|
|
116
|
+
* - `'file'` — absolute file path on the agent machine (agent reads the file)
|
|
117
|
+
*/
|
|
118
|
+
flavor: 'plain' | 'base64' | 'hex' | 'file';
|
|
119
|
+
/** The content, encoded according to `flavor`. */
|
|
120
|
+
data: string;
|
|
121
|
+
/** Format-specific extra options forwarded to the agent renderer. */
|
|
122
|
+
options?: Record<string, unknown>;
|
|
123
|
+
}
|
|
124
|
+
/**
|
|
125
|
+
* An input tray/bin reported by the printer driver.
|
|
126
|
+
*
|
|
127
|
+
* Returned inside {@link PrinterInfo.trays}.
|
|
128
|
+
*/
|
|
129
|
+
export interface TrayInfo {
|
|
130
|
+
/** Tray name exactly as the driver reports it (e.g. `"Tray 1"`, `"Auto"`). */
|
|
131
|
+
name: string;
|
|
132
|
+
/**
|
|
133
|
+
* Paper sizes this tray can hold, when the driver reports per-tray
|
|
134
|
+
* capability. Empty when the driver does not distinguish by tray —
|
|
135
|
+
* fall back to {@link PrinterInfo.papers} in that case.
|
|
136
|
+
*/
|
|
137
|
+
papers?: string[];
|
|
138
|
+
}
|
|
139
|
+
/**
|
|
140
|
+
* Metadata about a printer available on the agent machine.
|
|
141
|
+
*
|
|
142
|
+
* Returned by {@link EdgePrintClient.printers}.
|
|
143
|
+
* Use {@link name} as the value for {@link PrintConfig.printer}.
|
|
144
|
+
*/
|
|
145
|
+
export interface PrinterInfo {
|
|
146
|
+
/** OS-assigned printer name. Pass this to {@link PrintConfig.printer}. */
|
|
147
|
+
name: string;
|
|
148
|
+
/** `true` if this is the system default printer. */
|
|
149
|
+
is_default: boolean;
|
|
150
|
+
/**
|
|
151
|
+
* Current printer status reported by the OS.
|
|
152
|
+
*
|
|
153
|
+
* Possible values: `"idle"` | `"printing"` | `"offline"` | `"error"` |
|
|
154
|
+
* `"paused"` | `"paper_jam"` | `"paper_out"` | `"disabled"` | `"unknown"`
|
|
155
|
+
*/
|
|
156
|
+
status: string;
|
|
157
|
+
/** Driver name as reported by the OS (present when available). */
|
|
158
|
+
driver?: string;
|
|
159
|
+
/** Port or URI the printer is connected on (e.g. `"USB001"`, `"ipp://…"`). */
|
|
160
|
+
port?: string;
|
|
161
|
+
/** Physical location string set in the printer properties. */
|
|
162
|
+
location?: string;
|
|
163
|
+
/** Freeform comment from the printer properties. */
|
|
164
|
+
comment?: string;
|
|
165
|
+
/** Windows share name, if the printer is shared on the network. */
|
|
166
|
+
share_name?: string;
|
|
167
|
+
/** `true` if the printer supports color output. */
|
|
168
|
+
color?: boolean;
|
|
169
|
+
/** `true` if the printer supports duplex (double-sided) printing. */
|
|
170
|
+
duplex?: boolean;
|
|
171
|
+
/**
|
|
172
|
+
* Input trays available on this printer.
|
|
173
|
+
* Pass a {@link TrayInfo.name} value to {@link PrintConfig.tray}.
|
|
174
|
+
*/
|
|
175
|
+
trays?: TrayInfo[];
|
|
176
|
+
/**
|
|
177
|
+
* All paper sizes the printer supports, regardless of tray.
|
|
178
|
+
* Pass one of these values to {@link PrintConfig.paperSize}.
|
|
179
|
+
*/
|
|
180
|
+
papers?: string[];
|
|
181
|
+
/** Maximum number of copies the driver accepts in a single job. */
|
|
182
|
+
copies_max?: number;
|
|
183
|
+
/** Page orientations the driver supports (e.g. `["portrait", "landscape"]`). */
|
|
184
|
+
orientations?: string[];
|
|
185
|
+
/**
|
|
186
|
+
* `true` for Developer (virtual) printers — injected by the agent when
|
|
187
|
+
* Developer Printers mode is enabled in Settings. These printers capture
|
|
188
|
+
* jobs to disk or render a ZPL preview rather than sending to physical hardware.
|
|
189
|
+
*/
|
|
190
|
+
virtual?: boolean;
|
|
191
|
+
}
|
|
192
|
+
/**
|
|
193
|
+
* Options passed to {@link EdgePrintClient.connect}.
|
|
194
|
+
*/
|
|
195
|
+
export interface ConnectOptions {
|
|
196
|
+
/**
|
|
197
|
+
* Hostname or IP of the machine running the Edge Printing agent.
|
|
198
|
+
* @default '127.0.0.1'
|
|
199
|
+
*/
|
|
200
|
+
host?: string;
|
|
201
|
+
/**
|
|
202
|
+
* Port the agent is listening on.
|
|
203
|
+
* @default 8181
|
|
204
|
+
*/
|
|
205
|
+
port?: number;
|
|
206
|
+
/**
|
|
207
|
+
* API token shown in the Edge Printing settings window.
|
|
208
|
+
* Every WebSocket session must authenticate with this token before
|
|
209
|
+
* any other requests are accepted.
|
|
210
|
+
*/
|
|
211
|
+
token: string;
|
|
212
|
+
/**
|
|
213
|
+
* Maximum number of additional connection attempts after the first failure.
|
|
214
|
+
* @default 3
|
|
215
|
+
*/
|
|
216
|
+
retries?: number;
|
|
217
|
+
/**
|
|
218
|
+
* Milliseconds to wait between retry attempts.
|
|
219
|
+
* @default 1000
|
|
220
|
+
*/
|
|
221
|
+
retryDelay?: number;
|
|
222
|
+
}
|
|
223
|
+
/**
|
|
224
|
+
* WebSocket client for the Edge Printing agent.
|
|
225
|
+
*
|
|
226
|
+
* Each instance manages a single persistent connection. For most applications
|
|
227
|
+
* the exported {@link ep} singleton is sufficient; create additional instances
|
|
228
|
+
* only when you need concurrent connections to different agents.
|
|
229
|
+
*
|
|
230
|
+
* ### Lifecycle
|
|
231
|
+
* ```
|
|
232
|
+
* connect() → printers() / print() / … → disconnect()
|
|
233
|
+
* ```
|
|
234
|
+
*
|
|
235
|
+
* @example
|
|
236
|
+
* ```ts
|
|
237
|
+
* import { EdgePrintClient } from '@gohcltech/edge-print-client'
|
|
238
|
+
*
|
|
239
|
+
* const client = new EdgePrintClient()
|
|
240
|
+
* await client.connect({ token: 'abc123' })
|
|
241
|
+
* ```
|
|
242
|
+
*/
|
|
243
|
+
export declare class EdgePrintClient {
|
|
244
|
+
private ws;
|
|
245
|
+
private pending;
|
|
246
|
+
private authenticated;
|
|
247
|
+
private closeListeners;
|
|
248
|
+
/**
|
|
249
|
+
* Open a WebSocket connection to the Edge Printing agent and authenticate.
|
|
250
|
+
*
|
|
251
|
+
* On failure the client retries up to `options.retries` times (default 3),
|
|
252
|
+
* waiting `options.retryDelay` ms (default 1 000) between attempts. If all
|
|
253
|
+
* attempts fail the last error is re-thrown.
|
|
254
|
+
*
|
|
255
|
+
* @throws {Error} If the agent is unreachable or the token is rejected after
|
|
256
|
+
* all retries are exhausted.
|
|
257
|
+
*
|
|
258
|
+
* @example
|
|
259
|
+
* ```ts
|
|
260
|
+
* await ep.connect({
|
|
261
|
+
* host: '127.0.0.1',
|
|
262
|
+
* port: 8181,
|
|
263
|
+
* token: 'abc123',
|
|
264
|
+
* retries: 5,
|
|
265
|
+
* retryDelay: 2000,
|
|
266
|
+
* })
|
|
267
|
+
* ```
|
|
268
|
+
*/
|
|
269
|
+
connect(options: ConnectOptions): Promise<void>;
|
|
270
|
+
/**
|
|
271
|
+
* Return all printers available on the agent machine.
|
|
272
|
+
*
|
|
273
|
+
* @throws {Error} If not connected.
|
|
274
|
+
*
|
|
275
|
+
* @example
|
|
276
|
+
* ```ts
|
|
277
|
+
* const printers = await ep.printers()
|
|
278
|
+
* const colorPrinters = printers.filter(p => p.color)
|
|
279
|
+
* ```
|
|
280
|
+
*/
|
|
281
|
+
printers(): Promise<PrinterInfo[]>;
|
|
282
|
+
/**
|
|
283
|
+
* Return the name of the OS default printer.
|
|
284
|
+
*
|
|
285
|
+
* Cheaper than calling {@link printers} when you only need the default name
|
|
286
|
+
* and no other printer metadata.
|
|
287
|
+
*
|
|
288
|
+
* @throws {Error} If not connected.
|
|
289
|
+
*/
|
|
290
|
+
defaultPrinter(): Promise<string>;
|
|
291
|
+
/**
|
|
292
|
+
* Submit a print job to the agent.
|
|
293
|
+
*
|
|
294
|
+
* @param config - Printer selection and job settings.
|
|
295
|
+
* @param data - One or more content items to print (pages, labels, …).
|
|
296
|
+
* @returns The job ID assigned by the agent.
|
|
297
|
+
*
|
|
298
|
+
* @throws {Error} If not connected, or if the agent rejects the job.
|
|
299
|
+
*
|
|
300
|
+
* @example Print a PDF
|
|
301
|
+
* ```ts
|
|
302
|
+
* const jobId = await ep.print(
|
|
303
|
+
* { printer: 'Office Laser', copies: 2, duplex: 'long-edge' },
|
|
304
|
+
* [{ type: 'pixel', format: 'pdf', flavor: 'base64', data: pdfBase64 }],
|
|
305
|
+
* )
|
|
306
|
+
* ```
|
|
307
|
+
*
|
|
308
|
+
* @example Print a ZPL label
|
|
309
|
+
* ```ts
|
|
310
|
+
* await ep.print(
|
|
311
|
+
* { printer: 'Zebra ZT410' },
|
|
312
|
+
* [{ type: 'raw', format: 'command', flavor: 'plain', data: zplString }],
|
|
313
|
+
* )
|
|
314
|
+
* ```
|
|
315
|
+
*/
|
|
316
|
+
print(config: PrintConfig, data: PrintData[]): Promise<string>;
|
|
317
|
+
/**
|
|
318
|
+
* Close the WebSocket connection and reset client state.
|
|
319
|
+
*
|
|
320
|
+
* Any in-flight requests are rejected. Safe to call when already
|
|
321
|
+
* disconnected.
|
|
322
|
+
*/
|
|
323
|
+
disconnect(): void;
|
|
324
|
+
/**
|
|
325
|
+
* `true` when the WebSocket is open and the session is authenticated.
|
|
326
|
+
*
|
|
327
|
+
* Use this to guard print calls in components that may render before the
|
|
328
|
+
* connection is established.
|
|
329
|
+
*/
|
|
330
|
+
isConnected(): boolean;
|
|
331
|
+
/**
|
|
332
|
+
* Register a callback invoked whenever the connection closes — whether from
|
|
333
|
+
* a network drop, an agent restart, or an explicit {@link disconnect} call.
|
|
334
|
+
*
|
|
335
|
+
* Multiple listeners can be registered; all are called in registration order.
|
|
336
|
+
*
|
|
337
|
+
* @example
|
|
338
|
+
* ```ts
|
|
339
|
+
* ep.onClose(() => {
|
|
340
|
+
* console.warn('Lost connection to Edge Printing agent — reconnecting…')
|
|
341
|
+
* reconnect()
|
|
342
|
+
* })
|
|
343
|
+
* ```
|
|
344
|
+
*/
|
|
345
|
+
onClose(fn: () => void): void;
|
|
346
|
+
private openSocket;
|
|
347
|
+
private handleMessage;
|
|
348
|
+
private request;
|
|
349
|
+
private rejectPending;
|
|
350
|
+
}
|
|
351
|
+
/**
|
|
352
|
+
* Shared singleton `EdgePrintClient` instance.
|
|
353
|
+
*
|
|
354
|
+
* Suitable for most single-page applications. Call {@link EdgePrintClient.connect}
|
|
355
|
+
* once at app startup, then use `ep` from any module without passing the
|
|
356
|
+
* client around.
|
|
357
|
+
*
|
|
358
|
+
* @example
|
|
359
|
+
* ```ts
|
|
360
|
+
* import ep from '@gohcltech/edge-print-client'
|
|
361
|
+
*
|
|
362
|
+
* await ep.connect({ token: 'abc123' })
|
|
363
|
+
* await ep.print({ printer: 'Office Laser' }, [pdfData])
|
|
364
|
+
* ```
|
|
365
|
+
*/
|
|
366
|
+
export declare const ep: EdgePrintClient;
|
|
367
|
+
export default ep;
|