jc-printer-sdk-ts 0.1.1 → 0.1.2

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/package.json CHANGED
@@ -1,7 +1,7 @@
1
1
  {
2
2
  "name": "jc-printer-sdk-ts",
3
3
  "type": "module",
4
- "version": "0.1.1",
4
+ "version": "0.1.2",
5
5
  "description": "TypeScript surface for the JCPrintApi printer SDK",
6
6
  "license": "UNLICENSED",
7
7
  "keywords": [
package/src/client.ts CHANGED
@@ -29,7 +29,9 @@ import type {
29
29
  PrinterSdkCallback,
30
30
  PrinterAddress,
31
31
  PrinterInfo,
32
+ PrinterReadiness,
32
33
  PrinterState,
34
+ PrinterStatusSnapshot,
33
35
  Point,
34
36
  ScanCallback,
35
37
  } from "./types.js";
@@ -54,6 +56,64 @@ function resolveBoolean(result: MaybePromise<boolean | void> | undefined): Maybe
54
56
  return typeof result === "boolean" ? result : true;
55
57
  }
56
58
 
59
+ function createLocalReadiness(
60
+ state: PrinterState,
61
+ connection: number,
62
+ ): PrinterReadiness {
63
+ const connected = connection === 0 && state !== "Disconnected";
64
+ const status: PrinterStatusSnapshot = {
65
+ connected,
66
+ state,
67
+ statusAvailable: false,
68
+ };
69
+
70
+ if (!connected) {
71
+ return {
72
+ canPrint: false,
73
+ code: "not_connected",
74
+ reason: "Printer is not connected.",
75
+ warnings: [],
76
+ state,
77
+ connected,
78
+ status,
79
+ };
80
+ }
81
+
82
+ if (state === "Printing") {
83
+ return {
84
+ canPrint: false,
85
+ code: "sdk_printing",
86
+ reason: "A print job is already in progress.",
87
+ warnings: [],
88
+ state,
89
+ connected,
90
+ status,
91
+ };
92
+ }
93
+
94
+ if (state === "Working") {
95
+ return {
96
+ canPrint: false,
97
+ code: "printer_working",
98
+ reason: "Printer is currently working.",
99
+ warnings: [],
100
+ state,
101
+ connected,
102
+ status,
103
+ };
104
+ }
105
+
106
+ return {
107
+ canPrint: true,
108
+ code: "status_unavailable",
109
+ reason: "Printer is connected; live hardware status is not available in this transport.",
110
+ warnings: [],
111
+ state,
112
+ connected,
113
+ status,
114
+ };
115
+ }
116
+
57
117
  function toPrinterAddress(device: BluetoothDeviceLike): PrinterAddress {
58
118
  return {
59
119
  macAddress: device.address,
@@ -417,6 +477,46 @@ export class PrinterClient {
417
477
  return this.transport.getPrinterInfo?.() ?? null;
418
478
  }
419
479
 
480
+ queryPrinterStatus(timeoutMs?: number): MaybePromise<PrinterStatusSnapshot> {
481
+ const status = this.transport.queryPrinterStatus?.(timeoutMs);
482
+ if (status) {
483
+ return status;
484
+ }
485
+
486
+ const state = this.getPrinterState();
487
+ const connection = this.isConnection();
488
+ if (isPromise(state) || isPromise(connection)) {
489
+ return Promise.all([state, connection]).then(([resolvedState, resolvedConnection]) => ({
490
+ connected: resolvedConnection === 0 && resolvedState !== "Disconnected",
491
+ state: resolvedState,
492
+ statusAvailable: false,
493
+ }));
494
+ }
495
+
496
+ return {
497
+ connected: connection === 0 && state !== "Disconnected",
498
+ state,
499
+ statusAvailable: false,
500
+ };
501
+ }
502
+
503
+ canStartPrintJob(timeoutMs?: number): MaybePromise<PrinterReadiness> {
504
+ const readiness = this.transport.canStartPrintJob?.(timeoutMs);
505
+ if (readiness) {
506
+ return readiness;
507
+ }
508
+
509
+ const state = this.getPrinterState();
510
+ const connection = this.isConnection();
511
+ if (isPromise(state) || isPromise(connection)) {
512
+ return Promise.all([state, connection]).then(([resolvedState, resolvedConnection]) =>
513
+ createLocalReadiness(resolvedState, resolvedConnection),
514
+ );
515
+ }
516
+
517
+ return createLocalReadiness(state, connection);
518
+ }
519
+
420
520
  getPrinterState(): MaybePromise<PrinterState> {
421
521
  return this.transport.getPrinterState?.() ?? "Disconnected";
422
522
  }
package/src/imagePrint.ts CHANGED
@@ -98,6 +98,8 @@ export const DEFAULT_IMAGE_PRINT_SETTINGS: ResolvedImagePrintSettings = {
98
98
  meta: {},
99
99
  };
100
100
 
101
+ const imagePrintQueues = new WeakMap<PrintableImageClient, Promise<void>>();
102
+
101
103
  function finiteNumber(value: number | undefined, fallback: number): number {
102
104
  return Number.isFinite(value) ? Number(value) : fallback;
103
105
  }
@@ -157,6 +159,22 @@ function toPrintCallback(callback?: Partial<PrintCallback>): PrintCallback {
157
159
  };
158
160
  }
159
161
 
162
+ function queueImagePrintJob<T>(
163
+ printer: PrintableImageClient,
164
+ run: () => Promise<T>,
165
+ ): Promise<T> {
166
+ const previous = imagePrintQueues.get(printer) ?? Promise.resolve();
167
+ const queued = previous.catch(() => undefined).then(run);
168
+ imagePrintQueues.set(
169
+ printer,
170
+ queued.then(
171
+ () => undefined,
172
+ () => undefined,
173
+ ),
174
+ );
175
+ return queued;
176
+ }
177
+
160
178
  export function fitRect(
161
179
  boxWidth: number,
162
180
  boxHeight: number,
@@ -253,28 +271,30 @@ export async function printImageData(
253
271
  sources: ImagePrintSource,
254
272
  settings: ImagePrintSettings,
255
273
  ): Promise<PrintImageResult> {
256
- const resolved = normalizeSettings(settings);
257
- const images = await loadImageSources(sources);
258
- const document = buildPrintDocument(images, resolved);
259
- const callback = toPrintCallback(resolved.callback);
260
- let started = false;
274
+ return queueImagePrintJob(printer, async () => {
275
+ const resolved = normalizeSettings(settings);
276
+ const images = await loadImageSources(sources);
277
+ const document = buildPrintDocument(images, resolved);
278
+ const callback = toPrintCallback(resolved.callback);
279
+ let started = false;
261
280
 
262
- try {
263
- await printer.startPrintJob(resolved.density, resolved.paperType, resolved.printMode, callback);
264
- started = true;
265
- await printer.commitDocument(document);
266
- await printer.endPrintJob();
267
- return { document, images };
268
- } catch (error) {
269
- if (started && printer.cancelJob) {
270
- try {
271
- await printer.cancelJob();
272
- } catch {
273
- // Keep the original print error.
281
+ try {
282
+ await printer.startPrintJob(resolved.density, resolved.paperType, resolved.printMode, callback);
283
+ started = true;
284
+ await printer.commitDocument(document);
285
+ await printer.endPrintJob();
286
+ return { document, images };
287
+ } catch (error) {
288
+ if (started && printer.cancelJob) {
289
+ try {
290
+ await printer.cancelJob();
291
+ } catch {
292
+ // Keep the original print error.
293
+ }
274
294
  }
295
+ throw error;
275
296
  }
276
- throw error;
277
- }
297
+ });
278
298
  }
279
299
 
280
300
  export async function printCanvases(
package/src/transport.ts CHANGED
@@ -8,8 +8,10 @@ import type {
8
8
  PrintDocument,
9
9
  PrinterDevice,
10
10
  PrinterInfo,
11
+ PrinterReadiness,
11
12
  PrinterSdkCallback,
12
13
  PrinterState,
14
+ PrinterStatusSnapshot,
13
15
  ScanCallback,
14
16
  } from "./types.js";
15
17
 
@@ -70,6 +72,8 @@ export interface PrinterTransport {
70
72
  getPrintScaleMultiplier?(): MaybePromise<number>;
71
73
  getPrinterName?(): MaybePromise<string>;
72
74
  getPrinterInfo?(): MaybePromise<PrinterInfo | null>;
75
+ queryPrinterStatus?(timeoutMs?: number): MaybePromise<PrinterStatusSnapshot>;
76
+ canStartPrintJob?(timeoutMs?: number): MaybePromise<PrinterReadiness>;
73
77
  getPrinterState?(): MaybePromise<PrinterState>;
74
78
  waitPrinterState?(
75
79
  state: PrinterState,
@@ -149,6 +153,60 @@ function defaultPaperInfo(): PaperInfo {
149
153
  };
150
154
  }
151
155
 
156
+ function createMemoryPrinterStatus(state: PrinterState): PrinterStatusSnapshot {
157
+ return {
158
+ connected: state !== "Disconnected",
159
+ state,
160
+ statusAvailable: false,
161
+ };
162
+ }
163
+
164
+ function createMemoryReadiness(state: PrinterState): PrinterReadiness {
165
+ const status = createMemoryPrinterStatus(state);
166
+ if (!status.connected) {
167
+ return {
168
+ canPrint: false,
169
+ code: "not_connected",
170
+ reason: "Printer is not connected.",
171
+ warnings: [],
172
+ state,
173
+ connected: false,
174
+ status,
175
+ };
176
+ }
177
+ if (state === "Printing") {
178
+ return {
179
+ canPrint: false,
180
+ code: "sdk_printing",
181
+ reason: "A print job is already in progress.",
182
+ warnings: [],
183
+ state,
184
+ connected: true,
185
+ status,
186
+ };
187
+ }
188
+ if (state === "Working") {
189
+ return {
190
+ canPrint: false,
191
+ code: "printer_working",
192
+ reason: "Printer is currently working.",
193
+ warnings: [],
194
+ state,
195
+ connected: true,
196
+ status,
197
+ };
198
+ }
199
+ return {
200
+ canPrint: true,
201
+ code: "status_unavailable",
202
+ reason: "Printer is connected; live hardware status is not available in this transport.",
203
+ warnings: [],
204
+ state,
205
+ connected: true,
206
+ status,
207
+ };
208
+ }
209
+
152
210
  function dimensionsFromInfo(info: string): Pick<BitmapLike, "width" | "height"> {
153
211
  try {
154
212
  const parsed = JSON.parse(info) as {
@@ -425,6 +483,14 @@ export class MemoryPrinterTransport implements PrinterTransport {
425
483
  return clone(this.printerInfo);
426
484
  }
427
485
 
486
+ queryPrinterStatus(): PrinterStatusSnapshot {
487
+ return createMemoryPrinterStatus(this.printerState);
488
+ }
489
+
490
+ canStartPrintJob(): PrinterReadiness {
491
+ return createMemoryReadiness(this.printerState);
492
+ }
493
+
428
494
  getPrinterState(): PrinterState {
429
495
  return this.printerState;
430
496
  }
package/src/types.ts CHANGED
@@ -137,6 +137,50 @@ export interface PaperInfo {
137
137
  tailLength: number;
138
138
  }
139
139
 
140
+ export interface PrinterStatusSnapshot {
141
+ connected: boolean;
142
+ state: PrinterState;
143
+ statusAvailable: boolean;
144
+ responseCommand?: number;
145
+ rawData?: number[];
146
+ chargeLevel?: number;
147
+ temperature?: number;
148
+ lidClosed?: boolean;
149
+ paperInserted?: boolean;
150
+ paperRfidSuccess?: boolean;
151
+ ribbonInserted?: boolean;
152
+ ribbonRfidSuccess?: boolean;
153
+ wifiRssi?: number;
154
+ lightingErrorCode?: number;
155
+ voltageState?: number;
156
+ }
157
+
158
+ export type PrinterReadinessCode =
159
+ | "ready"
160
+ | "status_unavailable"
161
+ | "not_connected"
162
+ | "sdk_printing"
163
+ | "printer_working"
164
+ | "cover_open"
165
+ | "paper_missing"
166
+ | "voltage_error";
167
+
168
+ export type PrinterReadinessWarningCode =
169
+ | "paper_rfid_failed"
170
+ | "ribbon_missing"
171
+ | "ribbon_rfid_failed"
172
+ | "lighting_error";
173
+
174
+ export interface PrinterReadiness {
175
+ canPrint: boolean;
176
+ code: PrinterReadinessCode;
177
+ reason: string;
178
+ warnings: PrinterReadinessWarningCode[];
179
+ state: PrinterState;
180
+ connected: boolean;
181
+ status?: PrinterStatusSnapshot;
182
+ }
183
+
140
184
  export interface ColorSupport {
141
185
  normalMode: number;
142
186
  rbMode: number;