@gohcltech/edge-print-client 2.0.40-develop → 2.0.42-develop

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/src/edge-print.ts DELETED
@@ -1,685 +0,0 @@
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
- /**
21
- * Identifies the target printer.
22
- *
23
- * - Pass a `string` to use a printer by its OS name (e.g. `"Office Laser"`).
24
- * - Pass `{ host, port }` to route to a network printer by address.
25
- */
26
- export type PrinterTarget = string | { host: string; port: number }
27
-
28
- /**
29
- * Configuration options for a print job.
30
- *
31
- * All fields except `printer` are optional; omitted fields use the printer's
32
- * own defaults.
33
- */
34
- export interface PrintConfig {
35
- /** Target printer — OS name string or remote `{ host, port }` object. */
36
- printer: PrinterTarget
37
- /** Number of copies to print (default: 1). */
38
- copies?: number
39
- /**
40
- * Duplex (double-sided) mode.
41
- * - `'none'` — single-sided
42
- * - `'long-edge'` — flip on the long edge (standard book binding)
43
- * - `'short-edge'` — flip on the short edge (calendar binding)
44
- */
45
- duplex?: 'none' | 'long-edge' | 'short-edge'
46
- /** Page orientation (default: determined by document content). */
47
- orientation?: 'portrait' | 'landscape'
48
- /** Human-readable name shown in the OS print queue. */
49
- jobName?: string
50
- /**
51
- * Color output mode.
52
- * - `'color'` — full color
53
- * - `'grayscale'` — color converted to gray
54
- * - `'black-white'` — pure monochrome (fastest on mono printers)
55
- */
56
- colorType?: 'color' | 'grayscale' | 'black-white'
57
- /**
58
- * Paper size, exactly as returned by {@link PrinterInfo.papers}
59
- * (e.g. `"Letter"`, `"A4"`). Omit to use the printer's current default.
60
- */
61
- paperSize?: string
62
- /**
63
- * Input tray, exactly as returned by {@link TrayInfo.name} inside
64
- * {@link PrinterInfo.trays} (e.g. `"Tray 1"`, `"Auto"`).
65
- * Omit to use the printer's current default.
66
- */
67
- tray?: string
68
- }
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
- /**
126
- * An input tray/bin reported by the printer driver.
127
- *
128
- * Returned inside {@link PrinterInfo.trays}.
129
- */
130
- export interface TrayInfo {
131
- /** Tray name exactly as the driver reports it (e.g. `"Tray 1"`, `"Auto"`). */
132
- name: string
133
- /**
134
- * Paper sizes this tray can hold, when the driver reports per-tray
135
- * capability. Empty when the driver does not distinguish by tray —
136
- * fall back to {@link PrinterInfo.papers} in that case.
137
- */
138
- papers?: string[]
139
- }
140
-
141
- /**
142
- * Metadata about a printer available on the agent machine.
143
- *
144
- * Returned by {@link EdgePrintClient.printers}.
145
- * Use {@link name} as the value for {@link PrintConfig.printer}.
146
- */
147
- export interface PrinterInfo {
148
- /** OS-assigned printer name. Pass this to {@link PrintConfig.printer}. */
149
- name: string
150
- /** `true` if this is the system default printer. */
151
- isDefault: boolean
152
- /**
153
- * Current printer status reported by the OS.
154
- *
155
- * Possible values: `"idle"` | `"printing"` | `"offline"` | `"error"` |
156
- * `"paused"` | `"paper_jam"` | `"paper_out"` | `"disabled"` | `"unknown"`
157
- */
158
- status: string
159
- /** Driver name as reported by the OS (present when available). */
160
- driver?: string
161
- /** Port or URI the printer is connected on (e.g. `"USB001"`, `"ipp://…"`). */
162
- port?: string
163
- /** Physical location string set in the printer properties. */
164
- location?: string
165
- /** Freeform comment from the printer properties. */
166
- comment?: string
167
- /** Windows share name, if the printer is shared on the network. */
168
- shareName?: string
169
- /** `true` if the printer supports color output. */
170
- color?: boolean
171
- /** `true` if the printer supports duplex (double-sided) printing. */
172
- duplex?: boolean
173
- /**
174
- * Input trays available on this printer.
175
- * Pass a {@link TrayInfo.name} value to {@link PrintConfig.tray}.
176
- */
177
- trays?: TrayInfo[]
178
- /**
179
- * All paper sizes the printer supports, regardless of tray.
180
- * Pass one of these values to {@link PrintConfig.paperSize}.
181
- */
182
- papers?: string[]
183
- /** Maximum number of copies the driver accepts in a single job. */
184
- copiesMax?: number
185
- /** Page orientations the driver supports (e.g. `["portrait", "landscape"]`). */
186
- orientations?: string[]
187
- /**
188
- * `true` for Developer (virtual) printers — injected by the agent when
189
- * Developer Printers mode is enabled in Settings. These printers capture
190
- * jobs to disk or render a ZPL preview rather than sending to physical hardware.
191
- */
192
- virtualPrinter?: boolean
193
- }
194
-
195
- /**
196
- * Options passed to {@link EdgePrintClient.connect}.
197
- */
198
- export interface ConnectOptions {
199
- /**
200
- * Hostname or IP of the machine running the Edge Printing agent.
201
- * @default '127.0.0.1'
202
- */
203
- host?: string
204
- /**
205
- * Port the agent is listening on.
206
- * @default 8181
207
- */
208
- port?: number
209
- /**
210
- * API token shown in the Edge Printing settings window.
211
- * Every WebSocket session must authenticate with this token before
212
- * any other requests are accepted.
213
- */
214
- token: string
215
- /**
216
- * Name shown for this application in the agent's Clients tab and in the
217
- * approval prompt the user sees when connecting with an unapproved token.
218
- *
219
- * Strongly recommended: without it the user is asked to trust an
220
- * "Unknown client", which is not much of a decision.
221
- */
222
- clientName?: string
223
- /**
224
- * Maximum number of additional connection attempts after the first failure.
225
- * @default 3
226
- */
227
- retries?: number
228
- /**
229
- * Milliseconds to wait between retry attempts.
230
- * @default 1000
231
- */
232
- retryDelay?: number
233
- }
234
-
235
- type Pending = { resolve: (v: unknown) => void; reject: (e: Error) => void }
236
-
237
- /**
238
- * WebSocket client for the Edge Printing agent.
239
- *
240
- * Each instance manages a single persistent connection. For most applications
241
- * the exported {@link ep} singleton is sufficient; create additional instances
242
- * only when you need concurrent connections to different agents.
243
- *
244
- * ### Lifecycle
245
- * ```
246
- * connect() → printers() / print() / … → disconnect()
247
- * ```
248
- *
249
- * @example
250
- * ```ts
251
- * import { EdgePrintClient } from '@gohcltech/edge-print-client'
252
- *
253
- * const client = new EdgePrintClient()
254
- * await client.connect({ token: 'abc123' })
255
- * ```
256
- */
257
- export class EdgePrintClient {
258
- private ws: WebSocket | null = null
259
- private pending = new Map<string, Pending>()
260
- /** Rejects the connect currently waiting on `onopen`, if there is one. */
261
- private pendingOpen: ((e: Error) => void) | null = null
262
- /** Bumped per connect, so a superseded one can tell it is no longer current. */
263
- private connectGeneration = 0
264
- /**
265
- * Whether a connection currently exists from the application's point of view:
266
- * a socket that opened *and* authenticated, and has not since gone away.
267
- *
268
- * Distinct from `authenticated`, which tracks one socket. This tracks whether
269
- * there is anything for `onClose` to report the loss of, and is the single
270
- * rule every teardown path consults — the alternative was each path deciding
271
- * for itself, which is how the same event came to be announced in one place
272
- * and swallowed in another.
273
- */
274
- private established = false
275
- private authenticated = false
276
- private closeListeners: Array<() => void> = []
277
-
278
- /**
279
- * Open a WebSocket connection to the Edge Printing agent and authenticate.
280
- *
281
- * On failure the client retries up to `options.retries` times (default 3),
282
- * waiting `options.retryDelay` ms (default 1 000) between attempts. If all
283
- * attempts fail the last error is re-thrown.
284
- *
285
- * Calling this on an already-connected client **replaces** the connection:
286
- * the existing socket is torn down before the new one is attempted, and its
287
- * in-flight requests reject. If the new attempt then fails there is no
288
- * connection left, and close listeners are notified. Guard a
289
- * connect-on-demand helper with {@link EdgePrintClient.isConnected} rather
290
- * than reconnecting unconditionally.
291
- *
292
- * @throws {Error} If the agent is unreachable or the token is rejected after
293
- * all retries are exhausted.
294
- *
295
- * @example
296
- * ```ts
297
- * await ep.connect({
298
- * host: '127.0.0.1',
299
- * port: 8181,
300
- * token: 'abc123',
301
- * retries: 5,
302
- * retryDelay: 2000,
303
- * })
304
- * ```
305
- */
306
- async connect(options: ConnectOptions): Promise<void> {
307
- const {
308
- host = '127.0.0.1',
309
- port = 8181,
310
- token,
311
- clientName,
312
- retries = 3,
313
- retryDelay = 1000,
314
- } = options
315
-
316
- // A negative count would skip the loop altogether and resolve without ever
317
- // opening a socket, leaving the caller believing it is connected while
318
- // every later call rejects with "Not connected".
319
- const attempts = Math.max(0, retries)
320
-
321
- const generation = ++this.connectGeneration
322
-
323
- for (let attempt = 0; attempt <= attempts; attempt++) {
324
- // Checked before every attempt, not only after a failed one. A connect
325
- // sleeping between retries would otherwise wake and open a socket —
326
- // discarding whatever connection was established while it slept, and
327
- // reconnecting after an explicit disconnect.
328
- if (this.connectGeneration !== generation) {
329
- throw new Error('Connection superseded')
330
- }
331
-
332
- try {
333
- await this.openSocket(`wss://${host}:${port}`)
334
- // Omitted entirely when unset, rather than sent as undefined/null —
335
- // the agent treats a missing key as "no name given".
336
- await this.request('auth', clientName ? { token, clientName } : { token })
337
- this.authenticated = true
338
- this.established = true
339
- return
340
- } catch (err) {
341
- // A newer connect has taken over since this attempt began. Its socket
342
- // is not this attempt's to tear down.
343
- if (this.connectGeneration !== generation) throw err
344
-
345
- this.discardSocket(new Error('Connection closed'))
346
-
347
- // Every failure retries, including a refused token. The agent answers a
348
- // token still awaiting approval with the same "Invalid token" it gives
349
- // a bad one, so the client cannot tell them apart — and retrying while
350
- // someone clicks Approve is the documented flow. Repeat attempts only
351
- // bump a counter on the pending entry; the notification fires once.
352
- if (attempt === attempts) {
353
- this.markClosed()
354
- throw err
355
- }
356
- await sleep(retryDelay)
357
- }
358
- }
359
- }
360
-
361
- /**
362
- * Return all printers available on the agent machine.
363
- *
364
- * @throws {Error} If not connected.
365
- *
366
- * @example
367
- * ```ts
368
- * const printers = await ep.printers()
369
- * const colorPrinters = printers.filter(p => p.color)
370
- * ```
371
- */
372
- async printers(): Promise<PrinterInfo[]> {
373
- const resp = await this.request('get_printers', {}) as { printers: PrinterInfo[] }
374
- return resp.printers
375
- }
376
-
377
- /**
378
- * Return the name of the OS default printer.
379
- *
380
- * Cheaper than calling {@link printers} when you only need the default name
381
- * and no other printer metadata.
382
- *
383
- * @throws {Error} If not connected.
384
- */
385
- async defaultPrinter(): Promise<string> {
386
- const resp = await this.request('get_default_printer', {}) as { name: string }
387
- return resp.name
388
- }
389
-
390
- /**
391
- * Submit a print job to the agent.
392
- *
393
- * @param config - Printer selection and job settings.
394
- * @param data - One or more content items to print (pages, labels, …).
395
- * @returns The job ID assigned by the agent.
396
- *
397
- * @throws {Error} If not connected, if the agent rejects the job, or if the
398
- * job fails on the way to the spooler.
399
- *
400
- * A resolved promise means the job was handed to the OS print spooler — not
401
- * that paper came out. A printer that is offline, jammed or out of paper
402
- * after the spooler accepts the job still resolves.
403
- *
404
- * A rejection is also not proof that nothing printed: a request that exceeds
405
- * the client's 30 s timeout rejects while the agent may still be spooling it.
406
- * Do not resubmit a print automatically on rejection.
407
- *
408
- * When the agent had already created a job before it failed, the thrown error
409
- * carries a `jobId` property matching the entry in the agent's job history —
410
- * useful when surfacing a failure someone has to chase:
411
- *
412
- * ```ts
413
- * try {
414
- * await ep.print(config, data)
415
- * } catch (err) {
416
- * const jobId = (err as Error & { jobId?: string }).jobId
417
- * }
418
- * ```
419
- *
420
- * @example Print a PDF
421
- * ```ts
422
- * const jobId = await ep.print(
423
- * { printer: 'Office Laser', copies: 2, duplex: 'long-edge' },
424
- * [{ type: 'pixel', format: 'pdf', flavor: 'base64', data: pdfBase64 }],
425
- * )
426
- * ```
427
- *
428
- * @example Print a ZPL label
429
- * ```ts
430
- * await ep.print(
431
- * { printer: 'Zebra ZT410' },
432
- * [{ type: 'raw', format: 'command', flavor: 'plain', data: zplString }],
433
- * )
434
- * ```
435
- */
436
- async print(config: PrintConfig, data: PrintData[]): Promise<string> {
437
- const resp = await this.request('print', { config, data }) as { jobId: string }
438
- return resp.jobId
439
- }
440
-
441
- /**
442
- * Close the WebSocket connection and reset client state.
443
- *
444
- * Any in-flight requests are rejected. Safe to call when already
445
- * disconnected.
446
- */
447
- disconnect(): void {
448
- // Routed through the same teardown as a replacement: nulling the reference
449
- // alone leaves the socket's handlers attached, and its close then arrives
450
- // later and tears down whatever connection has taken its place.
451
- // Invalidates any connect still running, so a retry cannot wake up after
452
- // this and quietly reconnect.
453
- this.connectGeneration++
454
-
455
- this.discardSocket(new Error('Disconnected'))
456
- // Detaching the handlers means the socket's own close never arrives, so
457
- // without this the loss would go unannounced.
458
- this.markClosed()
459
- }
460
-
461
- /**
462
- * `true` when the WebSocket is open and the session is authenticated.
463
- *
464
- * Use this to guard print calls in components that may render before the
465
- * connection is established.
466
- */
467
- isConnected(): boolean {
468
- return this.ws?.readyState === WebSocket.OPEN && this.authenticated
469
- }
470
-
471
- /**
472
- * Register a callback invoked whenever the connection closes — whether from
473
- * a network drop, an agent restart, or an explicit {@link disconnect} call.
474
- *
475
- * Multiple listeners can be registered; all are called in registration order.
476
- *
477
- * @returns A function that removes this listener. Registering inside a
478
- * reconnect path without unsubscribing stacks a duplicate listener on every
479
- * attempt, so hold onto this if the caller can register more than once.
480
- *
481
- * @example
482
- * ```ts
483
- * const stop = ep.onClose(() => {
484
- * console.warn('Lost connection to Edge Printing agent — reconnecting…')
485
- * reconnect()
486
- * })
487
- *
488
- * // later, e.g. when the component unmounts
489
- * stop()
490
- * ```
491
- */
492
- onClose(fn: () => void): () => void {
493
- this.closeListeners.push(fn)
494
- return () => {
495
- const i = this.closeListeners.indexOf(fn)
496
- if (i !== -1) this.closeListeners.splice(i, 1)
497
- }
498
- }
499
-
500
- // ── internals ────────────────────────────────────────────────────────────
501
-
502
- /**
503
- * Announces the loss of an established connection, exactly once.
504
- *
505
- * A socket that never authenticated was never a connection, so its going
506
- * away is not something `onClose` reports — announcing it would have an
507
- * onClose-driven reconnect racing the retry loop already running.
508
- */
509
- private markClosed(): void {
510
- if (!this.established) return
511
- this.established = false
512
- // Copied: a listener may remove itself via the function onClose returns,
513
- // and splicing the live array mid-iteration skips the next one.
514
- ;[...this.closeListeners].forEach(fn => fn())
515
- }
516
-
517
- /**
518
- * Tears down the current socket so it cannot reach this client again.
519
- *
520
- * Handlers are detached before closing, because the close event arrives in a
521
- * later task — by which time the socket may have been replaced, and its
522
- * `onclose` would otherwise report the *replacement* as disconnected.
523
- *
524
- * Detaching means the teardown that handler would have done has to happen
525
- * here instead: clearing `authenticated`, settling in-flight requests, and
526
- * settling a connect still waiting on `onopen`. That last one is easy to
527
- * miss — a connect whose handlers are removed before either fires has
528
- * nothing left to settle it, and `request()`'s timeout does not cover it, so
529
- * it would wait forever.
530
- *
531
- * Close listeners are not fired from here. Whether a caller hears about a
532
- * lost connection is `markClosed`'s decision, because only it knows whether
533
- * there was an established connection to lose.
534
- */
535
- private discardSocket(reason: Error): void {
536
- const ws = this.ws
537
- const settleOpen = this.pendingOpen
538
- this.ws = null
539
- this.pendingOpen = null
540
- this.authenticated = false
541
-
542
- if (ws) {
543
- ws.onopen = null
544
- ws.onmessage = null
545
- ws.onclose = null
546
- ws.onerror = null
547
- try { ws.close() } catch { /* already closing or closed */ }
548
- }
549
-
550
- settleOpen?.(reason)
551
- this.rejectPending(reason)
552
- }
553
-
554
- private openSocket(url: string): Promise<void> {
555
- return new Promise((resolve, reject) => {
556
- // Never hold two sockets. This covers a retry, a reconnect on a live
557
- // client, and a second connect racing the first.
558
- this.discardSocket(new Error('Connection superseded'))
559
-
560
- const ws = new WebSocket(url)
561
- this.ws = ws
562
- this.pendingOpen = reject
563
-
564
- const settled = () => { this.pendingOpen = null }
565
- ws.onopen = () => { settled(); resolve() }
566
- ws.onerror = () => {
567
- settled()
568
- reject(new Error(`Cannot reach Edge Printing agent at ${url}`))
569
- }
570
- ws.onmessage = (ev) => this.handleMessage(String(ev.data))
571
- ws.onclose = () => {
572
- // A socket can close during the handshake, before either onopen or
573
- // onerror fires. Clearing the pending open without settling it would
574
- // leave this connect waiting forever — request()'s timeout does not
575
- // cover the open.
576
- const openWaiting = this.pendingOpen
577
- settled()
578
- openWaiting?.(new Error(`Cannot reach Edge Printing agent at ${url}`))
579
-
580
- this.ws = null
581
- this.authenticated = false
582
- this.rejectPending(new Error('Connection closed'))
583
- this.markClosed()
584
- }
585
- })
586
- }
587
-
588
- private handleMessage(raw: string): void {
589
- let msg: Record<string, unknown>
590
- try { msg = JSON.parse(raw) } catch { return }
591
-
592
- const id = msg['id'] as string | undefined
593
- if (!id || !this.pending.has(id)) return
594
-
595
- const { resolve, reject } = this.pending.get(id)!
596
- this.pending.delete(id)
597
-
598
- // `error` means the request never became a job. `print_error` means a job
599
- // was created and then failed — it carries a real jobId, which is why
600
- // matching only on `error` let failed prints resolve as successes.
601
- // Matched by suffix so error types added later reject by default rather
602
- // than silently resolving.
603
- const type = String(msg['type'] ?? '')
604
- if (type === 'error' || type.endsWith('_error')) {
605
- const failure = new Error((msg['message'] as string) ?? 'Unknown error')
606
-
607
- // `print_error` carries the id of the job the agent created and then
608
- // failed, which is the handle a caller needs to find it in the agent's
609
- // job history. Attached rather than given an exported error type: the
610
- // typed client error that formalises this arrives later, and a second
611
- // error shape now would only have to be reconciled with it.
612
- const jobId = msg['jobId']
613
- if (typeof jobId === 'string' && jobId.length > 0) {
614
- Object.assign(failure, { jobId })
615
- }
616
-
617
- reject(failure)
618
- } else {
619
- resolve(msg)
620
- }
621
- }
622
-
623
- private request(type: string, payload: Record<string, unknown>): Promise<unknown> {
624
- return new Promise((resolve, reject) => {
625
- if (!this.ws || this.ws.readyState !== WebSocket.OPEN) {
626
- reject(new Error('Not connected to Edge Printing agent'))
627
- return
628
- }
629
- const id = crypto.randomUUID()
630
-
631
- const timeout = setTimeout(() => {
632
- if (this.pending.delete(id)) {
633
- reject(new Error(`Request "${type}" timed out`))
634
- }
635
- }, 30_000)
636
-
637
- // Registered once, already wrapped. The previous version inserted the
638
- // raw handlers, sent, then replaced the entry with wrapped ones that
639
- // closed over what it read back out of the map. A close in that window
640
- // made rejectPending clear the map first, so the replacement re-inserted
641
- // an entry whose captured handlers were undefined — poisoning the map for
642
- // the next rejectPending, which then threw mid-loop and left every later
643
- // request unsettled.
644
- this.pending.set(id, {
645
- resolve: (v) => { clearTimeout(timeout); resolve(v) },
646
- reject: (e) => { clearTimeout(timeout); reject(e) },
647
- })
648
-
649
- try {
650
- this.ws.send(JSON.stringify({ type, id, ...payload }))
651
- } catch (err) {
652
- clearTimeout(timeout)
653
- this.pending.delete(id)
654
- reject(err instanceof Error ? err : new Error(String(err)))
655
- }
656
- })
657
- }
658
-
659
- private rejectPending(err: Error): void {
660
- for (const { reject } of this.pending.values()) reject(err)
661
- this.pending.clear()
662
- }
663
- }
664
-
665
- function sleep(ms: number): Promise<void> {
666
- return new Promise(resolve => setTimeout(resolve, ms))
667
- }
668
-
669
- /**
670
- * Shared singleton `EdgePrintClient` instance.
671
- *
672
- * Suitable for most single-page applications. Call {@link EdgePrintClient.connect}
673
- * once at app startup, then use `ep` from any module without passing the
674
- * client around.
675
- *
676
- * @example
677
- * ```ts
678
- * import ep from '@gohcltech/edge-print-client'
679
- *
680
- * await ep.connect({ token: 'abc123' })
681
- * await ep.print({ printer: 'Office Laser' }, [pdfData])
682
- * ```
683
- */
684
- export const ep = new EdgePrintClient()
685
- export default ep
package/tsconfig.json DELETED
@@ -1,14 +0,0 @@
1
- {
2
- "compilerOptions": {
3
- "target": "ES2020",
4
- "module": "ESNext",
5
- "moduleResolution": "bundler",
6
- "declaration": true,
7
- "declarationDir": "./dist",
8
- "outDir": "./dist",
9
- "strict": true,
10
- "lib": ["ES2020", "DOM"]
11
- },
12
- "include": ["src/**/*.ts"],
13
- "exclude": ["src/**/*.test.ts"]
14
- }