taro-bluetooth-print 2.1.0 → 2.1.1

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/dist/index.es.js CHANGED
@@ -43,6 +43,196 @@ var PrinterState = /* @__PURE__ */ ((PrinterState2) => {
43
43
  PrinterState2["PAUSED"] = "paused";
44
44
  return PrinterState2;
45
45
  })(PrinterState || {});
46
+ class EventEmitter {
47
+ constructor() {
48
+ this.listeners = /* @__PURE__ */ new Map();
49
+ }
50
+ /**
51
+ * Subscribe to an event
52
+ *
53
+ * @param event - Event name
54
+ * @param handler - Event handler function
55
+ * @returns Unsubscribe function
56
+ */
57
+ on(event, handler) {
58
+ if (!this.listeners.has(event)) {
59
+ this.listeners.set(event, /* @__PURE__ */ new Set());
60
+ }
61
+ this.listeners.get(event).add(handler);
62
+ return () => this.off(event, handler);
63
+ }
64
+ /**
65
+ * Subscribe to an event, but only for the first occurrence
66
+ *
67
+ * @param event - Event name
68
+ * @param handler - Event handler function
69
+ * @returns Unsubscribe function
70
+ */
71
+ once(event, handler) {
72
+ const wrappedHandler = (data) => {
73
+ handler(data);
74
+ this.off(event, wrappedHandler);
75
+ };
76
+ return this.on(event, wrappedHandler);
77
+ }
78
+ /**
79
+ * Adds a listener to the beginning of the listeners array for the specified event
80
+ *
81
+ * @param event - Event name
82
+ * @param handler - Event handler function
83
+ * @returns Unsubscribe function
84
+ */
85
+ prepend(event, handler) {
86
+ if (!this.listeners.has(event)) {
87
+ this.listeners.set(event, /* @__PURE__ */ new Set());
88
+ }
89
+ const existingHandlers = this.listeners.get(event);
90
+ const newHandlers = /* @__PURE__ */ new Set();
91
+ newHandlers.add(handler);
92
+ existingHandlers.forEach((h) => newHandlers.add(h));
93
+ this.listeners.set(event, newHandlers);
94
+ return () => this.off(event, handler);
95
+ }
96
+ /**
97
+ * Adds a one-time listener to the beginning of the listeners array for the specified event
98
+ *
99
+ * @param event - Event name
100
+ * @param handler - Event handler function
101
+ * @returns Unsubscribe function
102
+ */
103
+ prependOnce(event, handler) {
104
+ const wrappedHandler = (data) => {
105
+ handler(data);
106
+ this.off(event, wrappedHandler);
107
+ };
108
+ return this.prepend(event, wrappedHandler);
109
+ }
110
+ /**
111
+ * Unsubscribe from an event
112
+ *
113
+ * @param event - Event name
114
+ * @param handler - Event handler function to remove
115
+ */
116
+ off(event, handler) {
117
+ const handlers = this.listeners.get(event);
118
+ if (handlers) {
119
+ handlers.delete(handler);
120
+ if (handlers.size === 0) {
121
+ this.listeners.delete(event);
122
+ }
123
+ }
124
+ }
125
+ /**
126
+ * Emit an event to all subscribers
127
+ *
128
+ * @param event - Event name
129
+ * @param data - Event payload (optional for void events)
130
+ */
131
+ emit(event, data) {
132
+ const handlers = this.listeners.get(event);
133
+ if (!handlers || handlers.size === 0) {
134
+ return;
135
+ }
136
+ const handlersCopy = new Set(handlers);
137
+ handlersCopy.forEach((handler) => {
138
+ try {
139
+ if (data === void 0 || data === null) {
140
+ handler();
141
+ } else {
142
+ handler(data);
143
+ }
144
+ } catch (error) {
145
+ console.error(`Error in event handler for "${String(event)}":`, error);
146
+ }
147
+ });
148
+ }
149
+ /**
150
+ * Asynchronously emit an event to all subscribers, waiting for all handlers to complete
151
+ *
152
+ * @param event - Event name
153
+ * @param data - Event payload (optional for void events)
154
+ * @returns Promise that resolves when all handlers have completed
155
+ */
156
+ emitAsync(event, data) {
157
+ return __async(this, null, function* () {
158
+ const handlers = this.listeners.get(event);
159
+ if (!handlers || handlers.size === 0) {
160
+ return;
161
+ }
162
+ const handlersCopy = new Set(handlers);
163
+ const promises = [];
164
+ handlersCopy.forEach((handler) => {
165
+ promises.push(
166
+ new Promise((resolve) => {
167
+ try {
168
+ if (data === void 0 || data === null) {
169
+ handler();
170
+ } else {
171
+ handler(data);
172
+ }
173
+ } catch (error) {
174
+ console.error(`Error in event handler for "${String(event)}":`, error);
175
+ } finally {
176
+ resolve();
177
+ }
178
+ })
179
+ );
180
+ });
181
+ yield Promise.all(promises);
182
+ });
183
+ }
184
+ /**
185
+ * Remove all event listeners
186
+ * @param event - Optional event name to remove all listeners for a specific event
187
+ */
188
+ removeAllListeners(event) {
189
+ if (event) {
190
+ this.listeners.delete(event);
191
+ } else {
192
+ this.listeners.clear();
193
+ }
194
+ }
195
+ /**
196
+ * Get the number of listeners for an event
197
+ *
198
+ * @param event - Event name
199
+ * @returns Number of listeners
200
+ */
201
+ listenerCount(event) {
202
+ var _a, _b;
203
+ return (_b = (_a = this.listeners.get(event)) == null ? void 0 : _a.size) != null ? _b : 0;
204
+ }
205
+ /**
206
+ * Get all listeners for an event
207
+ *
208
+ * @param event - Event name
209
+ * @returns Array of event handlers
210
+ */
211
+ getListeners(event) {
212
+ const handlers = this.listeners.get(event);
213
+ if (!handlers) {
214
+ return [];
215
+ }
216
+ return Array.from(handlers);
217
+ }
218
+ /**
219
+ * Get all event names that have listeners
220
+ *
221
+ * @returns Array of event names
222
+ */
223
+ eventNames() {
224
+ return Array.from(this.listeners.keys());
225
+ }
226
+ /**
227
+ * Check if there are any listeners for an event
228
+ *
229
+ * @param event - Event name
230
+ * @returns True if there are listeners, false otherwise
231
+ */
232
+ hasListeners(event) {
233
+ return this.listenerCount(event) > 0;
234
+ }
235
+ }
46
236
  var LogLevel = /* @__PURE__ */ ((LogLevel2) => {
47
237
  LogLevel2[LogLevel2["DEBUG"] = 0] = "DEBUG";
48
238
  LogLevel2[LogLevel2["INFO"] = 1] = "INFO";
@@ -52,19 +242,97 @@ var LogLevel = /* @__PURE__ */ ((LogLevel2) => {
52
242
  return LogLevel2;
53
243
  })(LogLevel || {});
54
244
  const _Logger = class _Logger {
245
+ /**
246
+ * Configures the logger
247
+ *
248
+ * @param config - Configuration options
249
+ */
250
+ static configure(config) {
251
+ this.config = __spreadValues(__spreadValues({}, this.config), config);
252
+ }
55
253
  /**
56
254
  * Sets the global log level
57
255
  *
58
256
  * @param level - Minimum log level to output
59
257
  */
60
258
  static setLevel(level) {
61
- this.level = level;
259
+ this.config.level = level;
62
260
  }
63
261
  /**
64
262
  * Gets the current log level
65
263
  */
66
264
  static getLevel() {
67
- return this.level;
265
+ return this.config.level;
266
+ }
267
+ /**
268
+ * Formats the log prefix
269
+ */
270
+ static formatPrefix(level, scope) {
271
+ const levelNames = {
272
+ [
273
+ 0
274
+ /* DEBUG */
275
+ ]: "DEBUG",
276
+ [
277
+ 1
278
+ /* INFO */
279
+ ]: "INFO",
280
+ [
281
+ 2
282
+ /* WARN */
283
+ ]: "WARN",
284
+ [
285
+ 3
286
+ /* ERROR */
287
+ ]: "ERROR",
288
+ [
289
+ 4
290
+ /* NONE */
291
+ ]: "NONE"
292
+ };
293
+ const scopedPrefix = scope ? `${this.config.prefix}:${scope}` : this.config.prefix;
294
+ return `${scopedPrefix} [${levelNames[level]}]`;
295
+ }
296
+ /**
297
+ * Formats a complete log message for custom handlers
298
+ */
299
+ static formatMessage(level, message, args, scope) {
300
+ const prefix = this.formatPrefix(level, scope);
301
+ return `${prefix} ${message}`;
302
+ }
303
+ /**
304
+ * Logs a message with the specified level
305
+ */
306
+ static log(level, message, args, scope) {
307
+ if (this.config.level > level) {
308
+ return;
309
+ }
310
+ const prefix = this.formatPrefix(level, scope);
311
+ const formatted = this.formatMessage(level, message, args, scope);
312
+ const entry = {
313
+ level,
314
+ message,
315
+ args,
316
+ timestamp: /* @__PURE__ */ new Date(),
317
+ scope,
318
+ formatted
319
+ };
320
+ if (this.config.handler) {
321
+ this.config.handler(entry);
322
+ } else {
323
+ switch (level) {
324
+ case 0:
325
+ case 1:
326
+ console.log(prefix, message, ...args);
327
+ break;
328
+ case 2:
329
+ console.warn(prefix, message, ...args);
330
+ break;
331
+ case 3:
332
+ console.error(prefix, message, ...args);
333
+ break;
334
+ }
335
+ }
68
336
  }
69
337
  /**
70
338
  * Logs a debug message (only in DEBUG level)
@@ -73,9 +341,7 @@ const _Logger = class _Logger {
73
341
  * @param args - Additional arguments to log
74
342
  */
75
343
  static debug(message, ...args) {
76
- if (this.level <= 0) {
77
- console.log(`${this.prefix} [DEBUG]`, message, ...args);
78
- }
344
+ this.log(0, message, args);
79
345
  }
80
346
  /**
81
347
  * Logs an info message (DEBUG and INFO levels)
@@ -84,9 +350,7 @@ const _Logger = class _Logger {
84
350
  * @param args - Additional arguments to log
85
351
  */
86
352
  static info(message, ...args) {
87
- if (this.level <= 1) {
88
- console.log(`${this.prefix} [INFO]`, message, ...args);
89
- }
353
+ this.log(1, message, args);
90
354
  }
91
355
  /**
92
356
  * Logs a warning message (DEBUG, INFO, and WARN levels)
@@ -95,9 +359,7 @@ const _Logger = class _Logger {
95
359
  * @param args - Additional arguments to log
96
360
  */
97
361
  static warn(message, ...args) {
98
- if (this.level <= 2) {
99
- console.warn(`${this.prefix} [WARN]`, message, ...args);
100
- }
362
+ this.log(2, message, args);
101
363
  }
102
364
  /**
103
365
  * Logs an error message (all levels except NONE)
@@ -106,9 +368,7 @@ const _Logger = class _Logger {
106
368
  * @param args - Additional arguments to log
107
369
  */
108
370
  static error(message, ...args) {
109
- if (this.level <= 3) {
110
- console.error(`${this.prefix} [ERROR]`, message, ...args);
111
- }
371
+ this.log(3, message, args);
112
372
  }
113
373
  /**
114
374
  * Creates a scoped logger with a specific prefix
@@ -117,408 +377,549 @@ const _Logger = class _Logger {
117
377
  * @returns Scoped logger instance
118
378
  */
119
379
  static scope(scope) {
120
- const scopedPrefix = `${this.prefix}:${scope}`;
121
380
  return {
122
381
  debug: (message, ...args) => {
123
- if (_Logger.level <= 0) {
124
- console.log(`${scopedPrefix} [DEBUG]`, message, ...args);
125
- }
382
+ _Logger.log(0, message, args, scope);
126
383
  },
127
384
  info: (message, ...args) => {
128
- if (_Logger.level <= 1) {
129
- console.log(`${scopedPrefix} [INFO]`, message, ...args);
130
- }
385
+ _Logger.log(1, message, args, scope);
131
386
  },
132
387
  warn: (message, ...args) => {
133
- if (_Logger.level <= 2) {
134
- console.warn(`${scopedPrefix} [WARN]`, message, ...args);
135
- }
388
+ _Logger.log(2, message, args, scope);
136
389
  },
137
390
  error: (message, ...args) => {
138
- if (_Logger.level <= 3) {
139
- console.error(`${scopedPrefix} [ERROR]`, message, ...args);
140
- }
391
+ _Logger.log(3, message, args, scope);
141
392
  }
142
393
  };
143
394
  }
144
395
  };
145
- _Logger.level = 2;
146
- _Logger.prefix = "[TaroBTPrint]";
396
+ _Logger.config = {
397
+ level: 2,
398
+ prefix: "[TaroBTPrint]"
399
+ };
147
400
  let Logger = _Logger;
148
- const logger = Logger.scope("Encoding");
149
- const _Encoding = class _Encoding {
401
+ var ErrorCode = /* @__PURE__ */ ((ErrorCode2) => {
402
+ ErrorCode2["CONNECTION_FAILED"] = "CONNECTION_FAILED";
403
+ ErrorCode2["CONNECTION_TIMEOUT"] = "CONNECTION_TIMEOUT";
404
+ ErrorCode2["DEVICE_NOT_FOUND"] = "DEVICE_NOT_FOUND";
405
+ ErrorCode2["DEVICE_DISCONNECTED"] = "DEVICE_DISCONNECTED";
406
+ ErrorCode2["SERVICE_NOT_FOUND"] = "SERVICE_NOT_FOUND";
407
+ ErrorCode2["CHARACTERISTIC_NOT_FOUND"] = "CHARACTERISTIC_NOT_FOUND";
408
+ ErrorCode2["SERVICE_DISCOVERY_FAILED"] = "SERVICE_DISCOVERY_FAILED";
409
+ ErrorCode2["WRITE_FAILED"] = "WRITE_FAILED";
410
+ ErrorCode2["WRITE_TIMEOUT"] = "WRITE_TIMEOUT";
411
+ ErrorCode2["PRINT_JOB_IN_PROGRESS"] = "PRINT_JOB_IN_PROGRESS";
412
+ ErrorCode2["PRINT_JOB_CANCELLED"] = "PRINT_JOB_CANCELLED";
413
+ ErrorCode2["PRINT_JOB_FAILED"] = "PRINT_JOB_FAILED";
414
+ ErrorCode2["INVALID_CONFIGURATION"] = "INVALID_CONFIGURATION";
415
+ ErrorCode2["ENCODING_NOT_SUPPORTED"] = "ENCODING_NOT_SUPPORTED";
416
+ ErrorCode2["INVALID_IMAGE_DATA"] = "INVALID_IMAGE_DATA";
417
+ ErrorCode2["INVALID_QR_DATA"] = "INVALID_QR_DATA";
418
+ ErrorCode2["PLATFORM_NOT_SUPPORTED"] = "PLATFORM_NOT_SUPPORTED";
419
+ return ErrorCode2;
420
+ })(ErrorCode || {});
421
+ class BluetoothPrintError extends Error {
150
422
  /**
151
- * Encodes a string to a Uint8Array using the specified encoding
152
- *
153
- * @param text - Text to encode
154
- * @param encoding - Target encoding (default: 'GBK')
155
- * @returns Encoded bytes
156
- *
157
- * @remarks
158
- * Note: Native TextEncoder only supports UTF-8.
159
- * For GBK encoding, a third-party library or polyfill is recommended.
160
- * Currently falls back to UTF-8 with a warning.
161
- *
162
- * @example
163
- * ```typescript
164
- * // UTF-8 encoding
165
- * const utf8 = Encoding.encode('Hello', 'UTF-8');
423
+ * Creates a new BluetoothPrintError
166
424
  *
167
- * // GBK encoding (currently falls back to UTF-8)
168
- * const gbk = Encoding.encode('你好', 'GBK');
169
- * ```
425
+ * @param code - Error code from ErrorCode enum
426
+ * @param message - Human-readable error message
427
+ * @param originalError - Original error that caused this error (optional)
170
428
  */
171
- static encode(text, encoding = "GBK") {
172
- if (!text || typeof text !== "string") {
173
- return new Uint8Array(0);
174
- }
175
- const normalizedEncoding = encoding.toUpperCase().replace("-", "");
176
- if (normalizedEncoding === "UTF8" || normalizedEncoding === "UTF-8") {
177
- return this.utf8Encoder.encode(text);
178
- }
179
- if (!this.warningShown) {
180
- logger.warn(
181
- `Encoding ${encoding} not yet fully implemented, falling back to UTF-8. This may cause display issues with some printers.`
182
- );
183
- this.warningShown = true;
429
+ constructor(code, message, originalError) {
430
+ super(message);
431
+ this.code = code;
432
+ this.originalError = originalError;
433
+ this.name = "BluetoothPrintError";
434
+ if (Error.captureStackTrace) {
435
+ Error.captureStackTrace(this, BluetoothPrintError);
184
436
  }
185
- return this.utf8Encoder.encode(text);
186
437
  }
187
438
  /**
188
- * Checks if an encoding is supported
189
- *
190
- * @param encoding - Encoding name to check
191
- * @returns True if supported, false otherwise
192
- *
193
- * @example
194
- * ```typescript
195
- * if (Encoding.isSupported('GBK')) {
196
- * console.log('GBK is supported');
197
- * }
198
- * ```
439
+ * Returns a detailed error message including the error code
199
440
  */
200
- static isSupported(encoding) {
201
- if (!encoding || typeof encoding !== "string") {
202
- return false;
441
+ toString() {
442
+ let result = `${this.name} [${this.code}]: ${this.message}`;
443
+ if (this.originalError) {
444
+ result += `
445
+ Caused by: ${this.originalError.message}`;
203
446
  }
204
- const normalizedEncoding = encoding.toUpperCase().replace("-", "");
205
- return normalizedEncoding === "UTF8" || normalizedEncoding === "UTF-8";
447
+ return result;
206
448
  }
207
- };
208
- _Encoding.utf8Encoder = new TextEncoder();
209
- _Encoding.warningShown = false;
210
- let Encoding = _Encoding;
211
- class ImageProcessing {
212
- /**
213
- * Convert RGBA data to monochrome bitmap (1 bit per pixel)
214
- * suitable for ESC/POS GS v 0 command.
215
- * Uses Floyd-Steinberg dithering for better quality.
216
- *
217
- * @param data - RGBA pixel data as Uint8Array
218
- * @param width - Image width in pixels
219
- * @param height - Image height in pixels
220
- * @returns Monochrome bitmap data as Uint8Array
221
- *
222
- * @example
223
- * ```typescript
224
- * const imageData = new Uint8Array(width * height * 4); // RGBA
225
- * const bitmap = ImageProcessing.toBitmap(imageData, width, height);
226
- * ```
227
- */
228
- static toBitmap(data, width, height) {
229
- if (!data || !(data instanceof Uint8Array) || width <= 0 || height <= 0) {
230
- return new Uint8Array(0);
449
+ }
450
+ var Token = (
451
+ /** @class */
452
+ /* @__PURE__ */ function() {
453
+ function Token2(name) {
454
+ this.name = name;
231
455
  }
232
- if (data.length !== width * height * 4) {
233
- throw new Error(`Invalid image data length: expected ${width * height * 4}, got ${data.length}`);
456
+ return Token2;
457
+ }()
458
+ );
459
+ var __extends$1 = /* @__PURE__ */ function() {
460
+ var extendStatics = function(d, b) {
461
+ extendStatics = Object.setPrototypeOf || { __proto__: [] } instanceof Array && function(d2, b2) {
462
+ d2.__proto__ = b2;
463
+ } || function(d2, b2) {
464
+ for (var p in b2) if (Object.prototype.hasOwnProperty.call(b2, p)) d2[p] = b2[p];
465
+ };
466
+ return extendStatics(d, b);
467
+ };
468
+ return function(d, b) {
469
+ extendStatics(d, b);
470
+ function __() {
471
+ this.constructor = d;
234
472
  }
235
- const bytesPerLine = Math.ceil(width / 8);
236
- const bitmap = new Uint8Array(bytesPerLine * height);
237
- const grayscale = new Float32Array(width * height);
238
- for (let i = 0; i < data.length; i += 4) {
239
- const index = i / 4;
240
- const r = data[i] || 0;
241
- const g = data[i + 1] || 0;
242
- const b = data[i + 2] || 0;
243
- grayscale[index] = 0.299 * r + 0.587 * g + 0.114 * b;
473
+ d.prototype = b === null ? Object.create(b) : (__.prototype = b.prototype, new __());
474
+ };
475
+ }();
476
+ var ServiceNotFoundError = (
477
+ /** @class */
478
+ function(_super) {
479
+ __extends$1(ServiceNotFoundError2, _super);
480
+ function ServiceNotFoundError2(identifier) {
481
+ var _a, _b;
482
+ var _this = _super.call(this) || this;
483
+ _this.name = "ServiceNotFoundError";
484
+ _this.normalizedIdentifier = "<UNKNOWN_IDENTIFIER>";
485
+ if (typeof identifier === "string") {
486
+ _this.normalizedIdentifier = identifier;
487
+ } else if (identifier instanceof Token) {
488
+ _this.normalizedIdentifier = "Token<" + (identifier.name || "UNSET_NAME") + ">";
489
+ } else if (identifier && (identifier.name || ((_a = identifier.prototype) === null || _a === void 0 ? void 0 : _a.name))) {
490
+ _this.normalizedIdentifier = "MaybeConstructable<" + identifier.name + ">" || "MaybeConstructable<" + ((_b = identifier.prototype) === null || _b === void 0 ? void 0 : _b.name) + ">";
491
+ }
492
+ return _this;
244
493
  }
245
- for (let y = 0; y < height; y++) {
246
- for (let x = 0; x < width; x++) {
247
- const index = y * width + x;
248
- const oldPixel = grayscale[index] || 0;
249
- const newPixel = oldPixel < 128 ? 0 : 255;
250
- if (newPixel === 0) {
251
- const byteIndex = y * bytesPerLine + Math.floor(x / 8);
252
- const bitIndex = 7 - x % 8;
253
- bitmap[byteIndex] = (bitmap[byteIndex] || 0) | 1 << bitIndex;
494
+ Object.defineProperty(ServiceNotFoundError2.prototype, "message", {
495
+ get: function() {
496
+ return 'Service with "' + this.normalizedIdentifier + '" identifier was not found in the container. Register it before usage via explicitly calling the "Container.set" function or using the "@Service()" decorator.';
497
+ },
498
+ enumerable: false,
499
+ configurable: true
500
+ });
501
+ return ServiceNotFoundError2;
502
+ }(Error)
503
+ );
504
+ var __extends = /* @__PURE__ */ function() {
505
+ var extendStatics = function(d, b) {
506
+ extendStatics = Object.setPrototypeOf || { __proto__: [] } instanceof Array && function(d2, b2) {
507
+ d2.__proto__ = b2;
508
+ } || function(d2, b2) {
509
+ for (var p in b2) if (Object.prototype.hasOwnProperty.call(b2, p)) d2[p] = b2[p];
510
+ };
511
+ return extendStatics(d, b);
512
+ };
513
+ return function(d, b) {
514
+ extendStatics(d, b);
515
+ function __() {
516
+ this.constructor = d;
517
+ }
518
+ d.prototype = b === null ? Object.create(b) : (__.prototype = b.prototype, new __());
519
+ };
520
+ }();
521
+ var CannotInstantiateValueError = (
522
+ /** @class */
523
+ function(_super) {
524
+ __extends(CannotInstantiateValueError2, _super);
525
+ function CannotInstantiateValueError2(identifier) {
526
+ var _a, _b;
527
+ var _this = _super.call(this) || this;
528
+ _this.name = "CannotInstantiateValueError";
529
+ _this.normalizedIdentifier = "<UNKNOWN_IDENTIFIER>";
530
+ if (typeof identifier === "string") {
531
+ _this.normalizedIdentifier = identifier;
532
+ } else if (identifier instanceof Token) {
533
+ _this.normalizedIdentifier = "Token<" + (identifier.name || "UNSET_NAME") + ">";
534
+ } else if (identifier && (identifier.name || ((_a = identifier.prototype) === null || _a === void 0 ? void 0 : _a.name))) {
535
+ _this.normalizedIdentifier = "MaybeConstructable<" + identifier.name + ">" || "MaybeConstructable<" + ((_b = identifier.prototype) === null || _b === void 0 ? void 0 : _b.name) + ">";
536
+ }
537
+ return _this;
538
+ }
539
+ Object.defineProperty(CannotInstantiateValueError2.prototype, "message", {
540
+ get: function() {
541
+ return 'Cannot instantiate the requested value for the "' + this.normalizedIdentifier + `" identifier. The related metadata doesn't contain a factory or a type to instantiate.`;
542
+ },
543
+ enumerable: false,
544
+ configurable: true
545
+ });
546
+ return CannotInstantiateValueError2;
547
+ }(Error)
548
+ );
549
+ var EMPTY_VALUE = Symbol("EMPTY_VALUE");
550
+ var __assign = function() {
551
+ __assign = Object.assign || function(t) {
552
+ for (var s, i = 1, n = arguments.length; i < n; i++) {
553
+ s = arguments[i];
554
+ for (var p in s) if (Object.prototype.hasOwnProperty.call(s, p))
555
+ t[p] = s[p];
556
+ }
557
+ return t;
558
+ };
559
+ return __assign.apply(this, arguments);
560
+ };
561
+ var __spreadArrays = function() {
562
+ for (var s = 0, i = 0, il = arguments.length; i < il; i++) s += arguments[i].length;
563
+ for (var r = Array(s), k = 0, i = 0; i < il; i++)
564
+ for (var a = arguments[i], j = 0, jl = a.length; j < jl; j++, k++)
565
+ r[k] = a[j];
566
+ return r;
567
+ };
568
+ var ContainerInstance = (
569
+ /** @class */
570
+ function() {
571
+ function ContainerInstance2(id) {
572
+ this.services = [];
573
+ this.id = id;
574
+ }
575
+ ContainerInstance2.prototype.has = function(identifier) {
576
+ return !!this.findService(identifier);
577
+ };
578
+ ContainerInstance2.prototype.get = function(identifier) {
579
+ var globalContainer = Container.of(void 0);
580
+ var globalService = globalContainer.findService(identifier);
581
+ var scopedService = this.findService(identifier);
582
+ if (globalService && globalService.global === true)
583
+ return this.getServiceValue(globalService);
584
+ if (scopedService)
585
+ return this.getServiceValue(scopedService);
586
+ if (globalService && this !== globalContainer) {
587
+ var clonedService = __assign({}, globalService);
588
+ clonedService.value = EMPTY_VALUE;
589
+ this.set(clonedService);
590
+ var value = this.getServiceValue(clonedService);
591
+ this.set(__assign(__assign({}, clonedService), { value }));
592
+ return value;
593
+ }
594
+ if (globalService)
595
+ return this.getServiceValue(globalService);
596
+ throw new ServiceNotFoundError(identifier);
597
+ };
598
+ ContainerInstance2.prototype.getMany = function(identifier) {
599
+ var _this = this;
600
+ return this.findAllServices(identifier).map(function(service) {
601
+ return _this.getServiceValue(service);
602
+ });
603
+ };
604
+ ContainerInstance2.prototype.set = function(identifierOrServiceMetadata, value) {
605
+ var _this = this;
606
+ if (identifierOrServiceMetadata instanceof Array) {
607
+ identifierOrServiceMetadata.forEach(function(data) {
608
+ return _this.set(data);
609
+ });
610
+ return this;
611
+ }
612
+ if (typeof identifierOrServiceMetadata === "string" || identifierOrServiceMetadata instanceof Token) {
613
+ return this.set({
614
+ id: identifierOrServiceMetadata,
615
+ type: null,
616
+ value,
617
+ factory: void 0,
618
+ global: false,
619
+ multiple: false,
620
+ eager: false,
621
+ transient: false
622
+ });
623
+ }
624
+ if (typeof identifierOrServiceMetadata === "function") {
625
+ return this.set({
626
+ id: identifierOrServiceMetadata,
627
+ // TODO: remove explicit casting
628
+ type: identifierOrServiceMetadata,
629
+ value,
630
+ factory: void 0,
631
+ global: false,
632
+ multiple: false,
633
+ eager: false,
634
+ transient: false
635
+ });
636
+ }
637
+ var newService = __assign({ id: new Token("UNREACHABLE"), type: null, factory: void 0, value: EMPTY_VALUE, global: false, multiple: false, eager: false, transient: false }, identifierOrServiceMetadata);
638
+ var service = this.findService(newService.id);
639
+ if (service && service.multiple !== true) {
640
+ Object.assign(service, newService);
641
+ } else {
642
+ this.services.push(newService);
643
+ }
644
+ if (newService.eager) {
645
+ this.get(newService.id);
646
+ }
647
+ return this;
648
+ };
649
+ ContainerInstance2.prototype.remove = function(identifierOrIdentifierArray) {
650
+ var _this = this;
651
+ if (Array.isArray(identifierOrIdentifierArray)) {
652
+ identifierOrIdentifierArray.forEach(function(id) {
653
+ return _this.remove(id);
654
+ });
655
+ } else {
656
+ this.services = this.services.filter(function(service) {
657
+ if (service.id === identifierOrIdentifierArray) {
658
+ _this.destroyServiceInstance(service);
659
+ return false;
660
+ }
661
+ return true;
662
+ });
663
+ }
664
+ return this;
665
+ };
666
+ ContainerInstance2.prototype.reset = function(options) {
667
+ var _this = this;
668
+ if (options === void 0) {
669
+ options = { strategy: "resetValue" };
670
+ }
671
+ switch (options.strategy) {
672
+ case "resetValue":
673
+ this.services.forEach(function(service) {
674
+ return _this.destroyServiceInstance(service);
675
+ });
676
+ break;
677
+ case "resetServices":
678
+ this.services.forEach(function(service) {
679
+ return _this.destroyServiceInstance(service);
680
+ });
681
+ this.services = [];
682
+ break;
683
+ default:
684
+ throw new Error("Received invalid reset strategy.");
685
+ }
686
+ return this;
687
+ };
688
+ ContainerInstance2.prototype.findAllServices = function(identifier) {
689
+ return this.services.filter(function(service) {
690
+ return service.id === identifier;
691
+ });
692
+ };
693
+ ContainerInstance2.prototype.findService = function(identifier) {
694
+ return this.services.find(function(service) {
695
+ return service.id === identifier;
696
+ });
697
+ };
698
+ ContainerInstance2.prototype.getServiceValue = function(serviceMetadata) {
699
+ var _a;
700
+ var value = EMPTY_VALUE;
701
+ if (serviceMetadata.value !== EMPTY_VALUE) {
702
+ return serviceMetadata.value;
703
+ }
704
+ if (!serviceMetadata.factory && !serviceMetadata.type) {
705
+ throw new CannotInstantiateValueError(serviceMetadata.id);
706
+ }
707
+ if (serviceMetadata.factory) {
708
+ if (serviceMetadata.factory instanceof Array) {
709
+ var factoryInstance = void 0;
710
+ try {
711
+ factoryInstance = this.get(serviceMetadata.factory[0]);
712
+ } catch (error) {
713
+ if (error instanceof ServiceNotFoundError) {
714
+ factoryInstance = new serviceMetadata.factory[0]();
715
+ } else {
716
+ throw error;
717
+ }
718
+ }
719
+ value = factoryInstance[serviceMetadata.factory[1]](this, serviceMetadata.id);
720
+ } else {
721
+ value = serviceMetadata.factory(this, serviceMetadata.id);
254
722
  }
255
- const quantError = oldPixel - newPixel;
256
- this.distributeError(grayscale, width, height, x, y, quantError);
257
723
  }
724
+ if (!serviceMetadata.factory && serviceMetadata.type) {
725
+ var constructableTargetType = serviceMetadata.type;
726
+ var paramTypes = ((_a = Reflect) === null || _a === void 0 ? void 0 : _a.getMetadata("design:paramtypes", constructableTargetType)) || [];
727
+ var params = this.initializeParams(constructableTargetType, paramTypes);
728
+ params.push(this);
729
+ value = new (constructableTargetType.bind.apply(constructableTargetType, __spreadArrays([void 0], params)))();
730
+ }
731
+ if (!serviceMetadata.transient && value !== EMPTY_VALUE) {
732
+ serviceMetadata.value = value;
733
+ }
734
+ if (value === EMPTY_VALUE) {
735
+ throw new CannotInstantiateValueError(serviceMetadata.id);
736
+ }
737
+ if (serviceMetadata.type) {
738
+ this.applyPropertyHandlers(serviceMetadata.type, value);
739
+ }
740
+ return value;
741
+ };
742
+ ContainerInstance2.prototype.initializeParams = function(target, paramTypes) {
743
+ var _this = this;
744
+ return paramTypes.map(function(paramType, index) {
745
+ var paramHandler = Container.handlers.find(function(handler) {
746
+ return (handler.object === target || handler.object === Object.getPrototypeOf(target)) && handler.index === index;
747
+ });
748
+ if (paramHandler)
749
+ return paramHandler.value(_this);
750
+ if (paramType && paramType.name && !_this.isPrimitiveParamType(paramType.name)) {
751
+ return _this.get(paramType);
752
+ }
753
+ return void 0;
754
+ });
755
+ };
756
+ ContainerInstance2.prototype.isPrimitiveParamType = function(paramTypeName) {
757
+ return ["string", "boolean", "number", "object"].includes(paramTypeName.toLowerCase());
758
+ };
759
+ ContainerInstance2.prototype.applyPropertyHandlers = function(target, instance) {
760
+ var _this = this;
761
+ Container.handlers.forEach(function(handler) {
762
+ if (typeof handler.index === "number")
763
+ return;
764
+ if (handler.object.constructor !== target && !(target.prototype instanceof handler.object.constructor))
765
+ return;
766
+ if (handler.propertyName) {
767
+ instance[handler.propertyName] = handler.value(_this);
768
+ }
769
+ });
770
+ };
771
+ ContainerInstance2.prototype.destroyServiceInstance = function(serviceMetadata, force) {
772
+ if (force === void 0) {
773
+ force = false;
774
+ }
775
+ var shouldResetValue = force || !!serviceMetadata.type || !!serviceMetadata.factory;
776
+ if (shouldResetValue) {
777
+ if (typeof (serviceMetadata === null || serviceMetadata === void 0 ? void 0 : serviceMetadata.value)["destroy"] === "function") {
778
+ try {
779
+ serviceMetadata.value.destroy();
780
+ } catch (error) {
781
+ }
782
+ }
783
+ serviceMetadata.value = EMPTY_VALUE;
784
+ }
785
+ };
786
+ return ContainerInstance2;
787
+ }()
788
+ );
789
+ var Container = (
790
+ /** @class */
791
+ function() {
792
+ function Container2() {
258
793
  }
259
- return bitmap;
260
- }
261
- /**
262
- * Distribute quantization error to neighboring pixels using Floyd-Steinberg algorithm
263
- *
264
- * @param grayscale - Grayscale image data
265
- * @param width - Image width
266
- * @param height - Image height
267
- * @param x - Current x position
268
- * @param y - Current y position
269
- * @param error - Quantization error to distribute
270
- */
271
- static distributeError(grayscale, width, height, x, y, error) {
272
- const distribute = (dx, dy, factor) => {
273
- const nx = x + dx;
274
- const ny = y + dy;
275
- if (nx >= 0 && nx < width && ny >= 0 && ny < height) {
276
- const index = ny * width + nx;
277
- grayscale[index] = Math.max(0, Math.min(255, (grayscale[index] || 0) + error * factor));
794
+ Container2.of = function(containerId) {
795
+ if (containerId === void 0) {
796
+ containerId = "default";
797
+ }
798
+ if (containerId === "default")
799
+ return this.globalInstance;
800
+ var container = this.instances.find(function(instance) {
801
+ return instance.id === containerId;
802
+ });
803
+ if (!container) {
804
+ container = new ContainerInstance(containerId);
805
+ this.instances.push(container);
278
806
  }
807
+ return container;
279
808
  };
280
- distribute(1, 0, 7 / 16);
281
- distribute(-1, 1, 3 / 16);
282
- distribute(0, 1, 5 / 16);
283
- distribute(1, 1, 1 / 16);
284
- }
809
+ Container2.has = function(identifier) {
810
+ return this.globalInstance.has(identifier);
811
+ };
812
+ Container2.get = function(identifier) {
813
+ return this.globalInstance.get(identifier);
814
+ };
815
+ Container2.getMany = function(id) {
816
+ return this.globalInstance.getMany(id);
817
+ };
818
+ Container2.set = function(identifierOrServiceMetadata, value) {
819
+ this.globalInstance.set(identifierOrServiceMetadata, value);
820
+ return this;
821
+ };
822
+ Container2.remove = function(identifierOrIdentifierArray) {
823
+ this.globalInstance.remove(identifierOrIdentifierArray);
824
+ return this;
825
+ };
826
+ Container2.reset = function(containerId) {
827
+ if (containerId === void 0) {
828
+ containerId = "default";
829
+ }
830
+ if (containerId == "default") {
831
+ this.globalInstance.reset();
832
+ this.instances.forEach(function(instance2) {
833
+ return instance2.reset();
834
+ });
835
+ } else {
836
+ var instance = this.instances.find(function(instance2) {
837
+ return instance2.id === containerId;
838
+ });
839
+ if (instance) {
840
+ instance.reset();
841
+ this.instances.splice(this.instances.indexOf(instance), 1);
842
+ }
843
+ }
844
+ return this;
845
+ };
846
+ Container2.registerHandler = function(handler) {
847
+ this.handlers.push(handler);
848
+ return this;
849
+ };
850
+ Container2.import = function(services) {
851
+ return this;
852
+ };
853
+ Container2.handlers = [];
854
+ Container2.globalInstance = new ContainerInstance("default");
855
+ Container2.instances = [];
856
+ return Container2;
857
+ }()
858
+ );
859
+ function Service(optionsOrServiceIdentifier) {
860
+ return function(targetConstructor) {
861
+ var serviceMetadata = {
862
+ id: targetConstructor,
863
+ // TODO: Let's investigate why we receive Function type instead of a constructable.
864
+ type: targetConstructor,
865
+ factory: void 0,
866
+ multiple: false,
867
+ global: false,
868
+ eager: false,
869
+ transient: false,
870
+ value: EMPTY_VALUE
871
+ };
872
+ if (optionsOrServiceIdentifier instanceof Token || typeof optionsOrServiceIdentifier === "string") {
873
+ serviceMetadata.id = optionsOrServiceIdentifier;
874
+ }
875
+ Container.set(serviceMetadata);
876
+ };
285
877
  }
286
- class EscPos {
878
+ class BaseAdapter {
287
879
  constructor() {
288
- this.logger = Logger.scope("EscPos");
880
+ this.serviceCache = /* @__PURE__ */ new Map();
881
+ this.logger = Logger.scope("BaseAdapter");
289
882
  }
290
883
  /**
291
- * Initializes the printer
292
- * Sends ESC @ command to reset printer to default state
293
- *
294
- * @returns Array of command buffers
884
+ * Register a callback for connection state changes
885
+ * @param callback - Function to call when the state changes
295
886
  */
296
- init() {
297
- return [new Uint8Array([27, 64])];
887
+ onStateChange(callback) {
888
+ this.stateCallback = callback;
298
889
  }
299
890
  /**
300
- * Generates text print command
301
- *
302
- * @param content - Text content to print
303
- * @param encoding - Text encoding (default: 'GBK')
304
- * @returns Array of command buffers
305
- *
306
- * @example
307
- * ```typescript
308
- * driver.text('你好世界', 'GBK');
309
- * ```
891
+ * Updates the internal state and notifies callbacks
892
+ * @param state - New printer state
310
893
  */
311
- text(content, encoding = "GBK") {
312
- if (!content || typeof content !== "string") {
313
- return [];
894
+ updateState(state) {
895
+ if (this.stateCallback) {
896
+ this.stateCallback(state);
314
897
  }
315
- const encoded = Encoding.encode(content, encoding);
316
- return [encoded];
317
898
  }
318
899
  /**
319
- * Generates line feed command
320
- *
321
- * @param lines - Number of lines to feed (default: 1)
322
- * @returns Array of command buffers
323
- *
324
- * @example
325
- * ```typescript
326
- * driver.feed(3); // Feed 3 lines
327
- * ```
900
+ * Validates device ID
901
+ * @param deviceId - Device ID to validate
902
+ * @throws BluetoothPrintError if device ID is invalid
328
903
  */
329
- feed(lines = 1) {
330
- const safeLines = Math.max(1, Math.min(255, Math.floor(lines)));
331
- return [new Uint8Array([27, 100, safeLines])];
904
+ validateDeviceId(deviceId) {
905
+ if (!deviceId || typeof deviceId !== "string") {
906
+ throw new BluetoothPrintError(ErrorCode.DEVICE_NOT_FOUND, "Invalid device ID provided");
907
+ }
332
908
  }
333
909
  /**
334
- * Generates paper cut command
335
- *
336
- * @returns Array of command buffers
337
- *
338
- * @example
339
- * ```typescript
340
- * driver.cut();
341
- * ```
910
+ * Validates buffer data
911
+ * @param buffer - Buffer to validate
912
+ * @throws BluetoothPrintError if buffer is invalid
342
913
  */
343
- cut() {
344
- return [new Uint8Array([29, 86, 0])];
914
+ validateBuffer(buffer) {
915
+ if (!buffer || !(buffer instanceof ArrayBuffer)) {
916
+ throw new BluetoothPrintError(ErrorCode.PRINT_JOB_FAILED, "Invalid buffer data provided");
917
+ }
345
918
  }
346
919
  /**
347
- * Generates image print command
348
- * Uses Floyd-Steinberg dithering for better quality
349
- *
350
- * @param data - RGBA pixel data
351
- * @param width - Image width in pixels
352
- * @param height - Image height in pixels
353
- * @returns Array of command buffers
354
- *
355
- * @example
356
- * ```typescript
357
- * const imageData = new Uint8Array(width * height * 4); // RGBA
358
- * driver.image(imageData, 200, 100);
359
- * ```
360
- */
361
- image(data, width, height) {
362
- if (!data || !(data instanceof Uint8Array) || width <= 0 || height <= 0) {
363
- return [];
364
- }
365
- if (data.length !== width * height * 4) {
366
- this.logger.warn(`Invalid image data length: expected ${width * height * 4}, got ${data.length}`);
367
- return [];
368
- }
369
- const bitmap = ImageProcessing.toBitmap(data, width, height);
370
- const bytesPerLine = Math.ceil(width / 8);
371
- const xL = bytesPerLine % 256;
372
- const xH = Math.floor(bytesPerLine / 256);
373
- const yL = height % 256;
374
- const yH = Math.floor(height / 256);
375
- const header = new Uint8Array([29, 118, 48, 0, xL, xH, yL, yH]);
376
- return [header, bitmap];
377
- }
378
- /**
379
- * Generates QR code print command
380
- *
381
- * @param content - QR code content (URL, text, etc.)
382
- * @param options - QR code options
383
- * @returns Array of command buffers
384
- *
385
- * @example
386
- * ```typescript
387
- * driver.qr('https://example.com', {
388
- * model: 2,
389
- * size: 8,
390
- * errorCorrection: 'M'
391
- * });
392
- * ```
393
- */
394
- qr(content, options) {
395
- var _a, _b, _c, _d;
396
- if (!content || typeof content !== "string") {
397
- return [];
398
- }
399
- const model = (_a = options == null ? void 0 : options.model) != null ? _a : 2;
400
- const size = Math.max(1, Math.min(16, (_b = options == null ? void 0 : options.size) != null ? _b : 6));
401
- const errorCorrection = (_c = options == null ? void 0 : options.errorCorrection) != null ? _c : "M";
402
- const commands = [];
403
- commands.push(
404
- new Uint8Array([29, 40, 107, 4, 0, 49, 65, model === 1 ? 49 : 50, 0])
405
- );
406
- commands.push(new Uint8Array([29, 40, 107, 3, 0, 49, 67, size]));
407
- const ecMap = { L: 48, M: 49, Q: 50, H: 51 };
408
- const ecValue = (_d = ecMap[errorCorrection]) != null ? _d : 49;
409
- commands.push(
410
- new Uint8Array([29, 40, 107, 3, 0, 49, 69, ecValue])
411
- );
412
- const data = Encoding.encode(content, "GBK");
413
- const len = data.length + 3;
414
- const pL = len % 256;
415
- const pH = Math.floor(len / 256);
416
- commands.push(new Uint8Array([29, 40, 107, pL, pH, 49, 80, 48]));
417
- commands.push(data);
418
- commands.push(new Uint8Array([29, 40, 107, 3, 0, 49, 81, 48]));
419
- return commands;
420
- }
421
- }
422
- var ErrorCode = /* @__PURE__ */ ((ErrorCode2) => {
423
- ErrorCode2["CONNECTION_FAILED"] = "CONNECTION_FAILED";
424
- ErrorCode2["CONNECTION_TIMEOUT"] = "CONNECTION_TIMEOUT";
425
- ErrorCode2["DEVICE_NOT_FOUND"] = "DEVICE_NOT_FOUND";
426
- ErrorCode2["DEVICE_DISCONNECTED"] = "DEVICE_DISCONNECTED";
427
- ErrorCode2["SERVICE_NOT_FOUND"] = "SERVICE_NOT_FOUND";
428
- ErrorCode2["CHARACTERISTIC_NOT_FOUND"] = "CHARACTERISTIC_NOT_FOUND";
429
- ErrorCode2["SERVICE_DISCOVERY_FAILED"] = "SERVICE_DISCOVERY_FAILED";
430
- ErrorCode2["WRITE_FAILED"] = "WRITE_FAILED";
431
- ErrorCode2["WRITE_TIMEOUT"] = "WRITE_TIMEOUT";
432
- ErrorCode2["PRINT_JOB_IN_PROGRESS"] = "PRINT_JOB_IN_PROGRESS";
433
- ErrorCode2["PRINT_JOB_CANCELLED"] = "PRINT_JOB_CANCELLED";
434
- ErrorCode2["PRINT_JOB_FAILED"] = "PRINT_JOB_FAILED";
435
- ErrorCode2["INVALID_CONFIGURATION"] = "INVALID_CONFIGURATION";
436
- ErrorCode2["ENCODING_NOT_SUPPORTED"] = "ENCODING_NOT_SUPPORTED";
437
- ErrorCode2["INVALID_IMAGE_DATA"] = "INVALID_IMAGE_DATA";
438
- ErrorCode2["INVALID_QR_DATA"] = "INVALID_QR_DATA";
439
- ErrorCode2["PLATFORM_NOT_SUPPORTED"] = "PLATFORM_NOT_SUPPORTED";
440
- return ErrorCode2;
441
- })(ErrorCode || {});
442
- class BluetoothPrintError extends Error {
443
- /**
444
- * Creates a new BluetoothPrintError
445
- *
446
- * @param code - Error code from ErrorCode enum
447
- * @param message - Human-readable error message
448
- * @param originalError - Original error that caused this error (optional)
449
- */
450
- constructor(code, message, originalError) {
451
- super(message);
452
- this.code = code;
453
- this.originalError = originalError;
454
- this.name = "BluetoothPrintError";
455
- if (Error.captureStackTrace) {
456
- Error.captureStackTrace(this, BluetoothPrintError);
457
- }
458
- }
459
- /**
460
- * Returns a detailed error message including the error code
461
- */
462
- toString() {
463
- let result = `${this.name} [${this.code}]: ${this.message}`;
464
- if (this.originalError) {
465
- result += `
466
- Caused by: ${this.originalError.message}`;
467
- }
468
- return result;
469
- }
470
- }
471
- class BaseAdapter {
472
- constructor() {
473
- this.serviceCache = /* @__PURE__ */ new Map();
474
- this.logger = Logger.scope("BaseAdapter");
475
- }
476
- /**
477
- * Register a callback for connection state changes
478
- * @param callback - Function to call when the state changes
479
- */
480
- onStateChange(callback) {
481
- this.stateCallback = callback;
482
- }
483
- /**
484
- * Updates the internal state and notifies callbacks
485
- * @param state - New printer state
486
- */
487
- updateState(state) {
488
- if (this.stateCallback) {
489
- this.stateCallback(state);
490
- }
491
- }
492
- /**
493
- * Validates device ID
494
- * @param deviceId - Device ID to validate
495
- * @throws BluetoothPrintError if device ID is invalid
496
- */
497
- validateDeviceId(deviceId) {
498
- if (!deviceId || typeof deviceId !== "string") {
499
- throw new BluetoothPrintError(
500
- ErrorCode.DEVICE_NOT_FOUND,
501
- "Invalid device ID provided"
502
- );
503
- }
504
- }
505
- /**
506
- * Validates buffer data
507
- * @param buffer - Buffer to validate
508
- * @throws BluetoothPrintError if buffer is invalid
509
- */
510
- validateBuffer(buffer) {
511
- if (!buffer || !(buffer instanceof ArrayBuffer)) {
512
- throw new BluetoothPrintError(
513
- ErrorCode.PRINT_JOB_FAILED,
514
- "Invalid buffer data provided"
515
- );
516
- }
517
- }
518
- /**
519
- * Validates adapter options
520
- * @param options - Options to validate
521
- * @returns Validated options with default values
920
+ * Validates adapter options
921
+ * @param options - Options to validate
922
+ * @returns Validated options with default values
522
923
  */
523
924
  validateOptions(options) {
524
925
  var _a, _b, _c;
@@ -578,13 +979,17 @@ class TaroAdapter extends BaseAdapter {
578
979
  this.updateState(PrinterState.CONNECTING);
579
980
  this.logger.debug("Connecting to device:", deviceId);
580
981
  try {
982
+ let timeoutId;
581
983
  const connectionPromise = Taro.createBLEConnection({ deviceId });
582
984
  const timeoutPromise = new Promise((_, reject) => {
583
- setTimeout(() => {
985
+ timeoutId = setTimeout(() => {
584
986
  reject(new Error("Connection timeout after 10 seconds"));
585
987
  }, 1e4);
586
988
  });
587
989
  yield Promise.race([connectionPromise, timeoutPromise]);
990
+ if (timeoutId) {
991
+ clearTimeout(timeoutId);
992
+ }
588
993
  this.logger.info("BLE connection established");
589
994
  yield this.discoverServices(deviceId);
590
995
  this.updateState(PrinterState.CONNECTED);
@@ -661,10 +1066,7 @@ class TaroAdapter extends BaseAdapter {
661
1066
  const state = yield Taro.getBLEConnectionState({ deviceId });
662
1067
  if (!state.connected) {
663
1068
  this.cleanupDevice(deviceId);
664
- throw new BluetoothPrintError(
665
- ErrorCode.DEVICE_DISCONNECTED,
666
- "Device disconnected"
667
- );
1069
+ throw new BluetoothPrintError(ErrorCode.DEVICE_DISCONNECTED, "Device disconnected");
668
1070
  }
669
1071
  } catch (error) {
670
1072
  this.cleanupDevice(deviceId);
@@ -790,15 +1192,19 @@ class AlipayAdapter extends BaseAdapter {
790
1192
  this.updateState(PrinterState.CONNECTING);
791
1193
  this.logger.debug("Connecting to device:", deviceId);
792
1194
  try {
1195
+ let timeoutId;
793
1196
  const connectionPromise = my.createBLEConnection({
794
1197
  deviceId
795
1198
  });
796
1199
  const timeoutPromise = new Promise((_, reject) => {
797
- setTimeout(() => {
1200
+ timeoutId = setTimeout(() => {
798
1201
  reject(new Error("Connection timeout after 10 seconds"));
799
1202
  }, 1e4);
800
1203
  });
801
1204
  yield Promise.race([connectionPromise, timeoutPromise]);
1205
+ if (timeoutId) {
1206
+ clearTimeout(timeoutId);
1207
+ }
802
1208
  this.logger.info("BLE connection established");
803
1209
  yield this.discoverServices(deviceId);
804
1210
  this.updateState(PrinterState.CONNECTED);
@@ -879,10 +1285,7 @@ class AlipayAdapter extends BaseAdapter {
879
1285
  });
880
1286
  if (!state.connected) {
881
1287
  this.cleanupDevice(deviceId);
882
- throw new BluetoothPrintError(
883
- ErrorCode.DEVICE_DISCONNECTED,
884
- "Device disconnected"
885
- );
1288
+ throw new BluetoothPrintError(ErrorCode.DEVICE_DISCONNECTED, "Device disconnected");
886
1289
  }
887
1290
  } catch (error) {
888
1291
  this.cleanupDevice(deviceId);
@@ -1010,15 +1413,19 @@ class BaiduAdapter extends BaseAdapter {
1010
1413
  this.updateState(PrinterState.CONNECTING);
1011
1414
  this.logger.debug("Connecting to device:", deviceId);
1012
1415
  try {
1416
+ let timeoutId;
1013
1417
  const connectionPromise = swan.createBLEConnection({
1014
1418
  deviceId
1015
1419
  });
1016
1420
  const timeoutPromise = new Promise((_, reject) => {
1017
- setTimeout(() => {
1421
+ timeoutId = setTimeout(() => {
1018
1422
  reject(new Error("Connection timeout after 10 seconds"));
1019
1423
  }, 1e4);
1020
1424
  });
1021
1425
  yield Promise.race([connectionPromise, timeoutPromise]);
1426
+ if (timeoutId) {
1427
+ clearTimeout(timeoutId);
1428
+ }
1022
1429
  this.logger.info("BLE connection established");
1023
1430
  yield this.discoverServices(deviceId);
1024
1431
  this.updateState(PrinterState.CONNECTED);
@@ -1099,10 +1506,7 @@ class BaiduAdapter extends BaseAdapter {
1099
1506
  });
1100
1507
  if (!state.connected) {
1101
1508
  this.cleanupDevice(deviceId);
1102
- throw new BluetoothPrintError(
1103
- ErrorCode.DEVICE_DISCONNECTED,
1104
- "Device disconnected"
1105
- );
1509
+ throw new BluetoothPrintError(ErrorCode.DEVICE_DISCONNECTED, "Device disconnected");
1106
1510
  }
1107
1511
  } catch (error) {
1108
1512
  this.cleanupDevice(deviceId);
@@ -1230,15 +1634,19 @@ class ByteDanceAdapter extends BaseAdapter {
1230
1634
  this.updateState(PrinterState.CONNECTING);
1231
1635
  this.logger.debug("Connecting to device:", deviceId);
1232
1636
  try {
1637
+ let timeoutId;
1233
1638
  const connectionPromise = tt.createBLEConnection({
1234
1639
  deviceId
1235
1640
  });
1236
1641
  const timeoutPromise = new Promise((_, reject) => {
1237
- setTimeout(() => {
1642
+ timeoutId = setTimeout(() => {
1238
1643
  reject(new Error("Connection timeout after 10 seconds"));
1239
1644
  }, 1e4);
1240
1645
  });
1241
1646
  yield Promise.race([connectionPromise, timeoutPromise]);
1647
+ if (timeoutId) {
1648
+ clearTimeout(timeoutId);
1649
+ }
1242
1650
  this.logger.info("BLE connection established");
1243
1651
  yield this.discoverServices(deviceId);
1244
1652
  this.updateState(PrinterState.CONNECTED);
@@ -1319,10 +1727,7 @@ class ByteDanceAdapter extends BaseAdapter {
1319
1727
  });
1320
1728
  if (!state.connected) {
1321
1729
  this.cleanupDevice(deviceId);
1322
- throw new BluetoothPrintError(
1323
- ErrorCode.DEVICE_DISCONNECTED,
1324
- "Device disconnected"
1325
- );
1730
+ throw new BluetoothPrintError(ErrorCode.DEVICE_DISCONNECTED, "Device disconnected");
1326
1731
  }
1327
1732
  } catch (error) {
1328
1733
  this.cleanupDevice(deviceId);
@@ -1441,201 +1846,902 @@ var PlatformType = /* @__PURE__ */ ((PlatformType2) => {
1441
1846
  PlatformType2["UNKNOWN"] = "unknown";
1442
1847
  return PlatformType2;
1443
1848
  })(PlatformType || {});
1849
+ function hasRequestMethod(obj) {
1850
+ return typeof obj === "object" && obj !== null && "request" in obj;
1851
+ }
1852
+ function isWindowWithNavigator(obj) {
1853
+ return typeof obj === "object" && obj !== null && "navigator" in obj;
1854
+ }
1444
1855
  function detectPlatform() {
1445
- if (typeof wx !== "undefined" && wx.request) {
1856
+ if (typeof wx !== "undefined" && hasRequestMethod(wx)) {
1446
1857
  return "wechat";
1447
1858
  }
1448
- if (typeof my !== "undefined" && my.request) {
1859
+ if (typeof my !== "undefined" && hasRequestMethod(my)) {
1449
1860
  return "alipay";
1450
1861
  }
1451
- if (typeof swan !== "undefined" && swan.request) {
1862
+ if (typeof swan !== "undefined" && hasRequestMethod(swan)) {
1452
1863
  return "baidu";
1453
1864
  }
1454
- if (typeof tt !== "undefined" && tt.request) {
1865
+ if (typeof tt !== "undefined" && hasRequestMethod(tt)) {
1455
1866
  return "bytedance";
1456
1867
  }
1457
- if (typeof window !== "undefined" && window.navigator) {
1868
+ if (typeof window !== "undefined" && isWindowWithNavigator(window)) {
1458
1869
  return "web";
1459
1870
  }
1460
- return "unknown";
1871
+ return "unknown";
1872
+ }
1873
+ class AdapterFactory {
1874
+ /**
1875
+ * Creates an adapter instance based on the detected platform
1876
+ *
1877
+ * @returns An instance of the appropriate adapter for the current platform
1878
+ * @throws BluetoothPrintError if the platform is not supported
1879
+ */
1880
+ static create() {
1881
+ const platform = detectPlatform();
1882
+ switch (platform) {
1883
+ case PlatformType.WECHAT:
1884
+ return new TaroAdapter();
1885
+ case PlatformType.ALIPAY:
1886
+ return new AlipayAdapter();
1887
+ case PlatformType.BAIDU:
1888
+ return new BaiduAdapter();
1889
+ case PlatformType.BYTEDANCE:
1890
+ return new ByteDanceAdapter();
1891
+ default:
1892
+ throw new BluetoothPrintError(
1893
+ ErrorCode.PLATFORM_NOT_SUPPORTED,
1894
+ `Platform ${platform} is not supported. Please use a supported mini-program platform.`
1895
+ );
1896
+ }
1897
+ }
1898
+ /**
1899
+ * Creates an adapter instance for a specific platform
1900
+ *
1901
+ * @param platform - The platform type to create an adapter for
1902
+ * @returns An instance of the appropriate adapter for the specified platform
1903
+ * @throws BluetoothPrintError if the platform is not supported
1904
+ */
1905
+ static createForPlatform(platform) {
1906
+ switch (platform) {
1907
+ case PlatformType.WECHAT:
1908
+ return new TaroAdapter();
1909
+ case PlatformType.ALIPAY:
1910
+ return new AlipayAdapter();
1911
+ case PlatformType.BAIDU:
1912
+ return new BaiduAdapter();
1913
+ case PlatformType.BYTEDANCE:
1914
+ return new ByteDanceAdapter();
1915
+ default:
1916
+ throw new BluetoothPrintError(
1917
+ ErrorCode.PLATFORM_NOT_SUPPORTED,
1918
+ `Platform ${platform} is not supported.`
1919
+ );
1920
+ }
1921
+ }
1922
+ }
1923
+ var __getOwnPropDesc$3 = Object.getOwnPropertyDescriptor;
1924
+ var __decorateClass$3 = (decorators, target, key, kind) => {
1925
+ var result = kind > 1 ? void 0 : kind ? __getOwnPropDesc$3(target, key) : target;
1926
+ for (var i = decorators.length - 1, decorator; i >= 0; i--)
1927
+ if (decorator = decorators[i])
1928
+ result = decorator(result) || result;
1929
+ return result;
1930
+ };
1931
+ let ConnectionManager = class {
1932
+ /**
1933
+ * Creates a new ConnectionManager instance
1934
+ */
1935
+ constructor(adapter) {
1936
+ var _a, _b;
1937
+ this.deviceId = null;
1938
+ this.state = PrinterState.DISCONNECTED;
1939
+ this.logger = Logger.scope("ConnectionManager");
1940
+ this.adapter = adapter || AdapterFactory.create();
1941
+ (_b = (_a = this.adapter).onStateChange) == null ? void 0 : _b.call(_a, (state) => {
1942
+ this.state = state;
1943
+ this.logger.debug("State changed:", state);
1944
+ });
1945
+ }
1946
+ /**
1947
+ * Connects to a Bluetooth device
1948
+ *
1949
+ * @param deviceId - Bluetooth device ID
1950
+ * @returns Promise<void>
1951
+ */
1952
+ connect(deviceId) {
1953
+ return __async(this, null, function* () {
1954
+ this.logger.info("Connecting to device:", deviceId);
1955
+ try {
1956
+ this.deviceId = deviceId;
1957
+ yield this.adapter.connect(deviceId);
1958
+ this.state = PrinterState.CONNECTED;
1959
+ this.logger.info("Connected successfully");
1960
+ } catch (error) {
1961
+ this.deviceId = null;
1962
+ this.state = PrinterState.DISCONNECTED;
1963
+ const printError = error instanceof BluetoothPrintError ? error : new BluetoothPrintError(
1964
+ ErrorCode.CONNECTION_FAILED,
1965
+ "Connection failed",
1966
+ error
1967
+ );
1968
+ this.logger.error("Connection failed:", printError);
1969
+ throw printError;
1970
+ }
1971
+ });
1972
+ }
1973
+ /**
1974
+ * Disconnects from the current device
1975
+ *
1976
+ * @returns Promise<void>
1977
+ */
1978
+ disconnect() {
1979
+ return __async(this, null, function* () {
1980
+ if (!this.deviceId) {
1981
+ this.logger.warn("Disconnect called but no device connected");
1982
+ return;
1983
+ }
1984
+ const deviceId = this.deviceId;
1985
+ this.logger.info("Disconnecting from device:", deviceId);
1986
+ try {
1987
+ yield this.adapter.disconnect(deviceId);
1988
+ this.deviceId = null;
1989
+ this.state = PrinterState.DISCONNECTED;
1990
+ this.logger.info("Disconnected successfully");
1991
+ } catch (error) {
1992
+ const printError = new BluetoothPrintError(
1993
+ ErrorCode.DEVICE_DISCONNECTED,
1994
+ "Disconnect failed",
1995
+ error
1996
+ );
1997
+ this.logger.error("Disconnect failed:", printError);
1998
+ throw printError;
1999
+ }
2000
+ });
2001
+ }
2002
+ /**
2003
+ * Checks if a device is connected
2004
+ *
2005
+ * @returns boolean - True if connected, false otherwise
2006
+ */
2007
+ isConnected() {
2008
+ return this.state === PrinterState.CONNECTED;
2009
+ }
2010
+ /**
2011
+ * Gets the current device ID
2012
+ *
2013
+ * @returns string | null - Device ID or null if not connected
2014
+ */
2015
+ getDeviceId() {
2016
+ return this.deviceId;
2017
+ }
2018
+ /**
2019
+ * Gets the current connection state
2020
+ *
2021
+ * @returns PrinterState - Current state
2022
+ */
2023
+ getState() {
2024
+ return this.state;
2025
+ }
2026
+ /**
2027
+ * Gets the printer adapter instance
2028
+ *
2029
+ * @returns IPrinterAdapter - Printer adapter
2030
+ */
2031
+ getAdapter() {
2032
+ return this.adapter;
2033
+ }
2034
+ };
2035
+ ConnectionManager = __decorateClass$3([
2036
+ Service()
2037
+ ], ConnectionManager);
2038
+ var __getOwnPropDesc$2 = Object.getOwnPropertyDescriptor;
2039
+ var __decorateClass$2 = (decorators, target, key, kind) => {
2040
+ var result = kind > 1 ? void 0 : kind ? __getOwnPropDesc$2(target, key) : target;
2041
+ for (var i = decorators.length - 1, decorator; i >= 0; i--)
2042
+ if (decorator = decorators[i])
2043
+ result = decorator(result) || result;
2044
+ return result;
2045
+ };
2046
+ let PrintJobManager = class {
2047
+ /**
2048
+ * Creates a new PrintJobManager instance
2049
+ *
2050
+ * @param connectionManagerOrAdapter - Connection manager instance or adapter instance (for backward compatibility)
2051
+ * @param adapter - Printer adapter instance (optional, will be taken from connectionManager if not provided)
2052
+ */
2053
+ constructor(connectionManagerOrAdapter, adapter) {
2054
+ this.jobBuffer = null;
2055
+ this.jobOffset = 0;
2056
+ this._isPaused = false;
2057
+ this._isInProgress = false;
2058
+ this.adapterOptions = {};
2059
+ this.logger = Logger.scope("PrintJobManager");
2060
+ if (adapter) {
2061
+ this.connectionManager = connectionManagerOrAdapter;
2062
+ this.adapter = adapter;
2063
+ } else if (connectionManagerOrAdapter && typeof connectionManagerOrAdapter.connect === "function") {
2064
+ this.adapter = connectionManagerOrAdapter;
2065
+ this.connectionManager = {
2066
+ getDeviceId: () => "test-device",
2067
+ // Default device ID for backward compatibility
2068
+ isConnected: () => true,
2069
+ getState: () => PrinterState.CONNECTED,
2070
+ // Default to CONNECTED
2071
+ connect: () => Promise.resolve(),
2072
+ disconnect: () => Promise.resolve(),
2073
+ getAdapter: () => this.adapter
2074
+ };
2075
+ } else {
2076
+ this.connectionManager = connectionManagerOrAdapter;
2077
+ if (this.connectionManager && typeof this.connectionManager.getAdapter === "function") {
2078
+ this.adapter = this.connectionManager.getAdapter();
2079
+ } else {
2080
+ throw new Error(
2081
+ "Printer adapter not provided and could not be retrieved from connection manager"
2082
+ );
2083
+ }
2084
+ }
2085
+ }
2086
+ /**
2087
+ * Starts a print job
2088
+ *
2089
+ * @param buffer - Print data buffer
2090
+ * @returns Promise<void>
2091
+ */
2092
+ start(buffer) {
2093
+ return __async(this, null, function* () {
2094
+ if (this._isInProgress) {
2095
+ throw new BluetoothPrintError(
2096
+ ErrorCode.PRINT_JOB_IN_PROGRESS,
2097
+ "A print job is already in progress. Wait for completion or cancel it."
2098
+ );
2099
+ }
2100
+ this.logger.info(`Starting print job: ${buffer.length} bytes`);
2101
+ this.jobBuffer = buffer;
2102
+ this.jobOffset = 0;
2103
+ this._isPaused = false;
2104
+ this._isInProgress = true;
2105
+ try {
2106
+ yield this.processJob();
2107
+ if (this._isPaused) {
2108
+ this.logger.info("Print job paused");
2109
+ } else {
2110
+ this.logger.info("Print job completed successfully");
2111
+ this._isInProgress = false;
2112
+ this.jobBuffer = null;
2113
+ this.jobOffset = 0;
2114
+ }
2115
+ } catch (error) {
2116
+ this.logger.error("Print job failed:", error);
2117
+ this._isInProgress = false;
2118
+ this.jobBuffer = null;
2119
+ this.jobOffset = 0;
2120
+ const printError = error instanceof BluetoothPrintError ? error : new BluetoothPrintError(ErrorCode.PRINT_JOB_FAILED, "Print job failed", error);
2121
+ throw printError;
2122
+ }
2123
+ });
2124
+ }
2125
+ /**
2126
+ * Pauses the current print job
2127
+ */
2128
+ pause() {
2129
+ if (!this._isInProgress) {
2130
+ this.logger.warn("Pause called but no print job in progress");
2131
+ return;
2132
+ }
2133
+ this._isPaused = true;
2134
+ this.logger.info("Print job paused");
2135
+ }
2136
+ /**
2137
+ * Resumes a paused print job
2138
+ *
2139
+ * @returns Promise<void>
2140
+ */
2141
+ resume() {
2142
+ return __async(this, null, function* () {
2143
+ if (!this._isInProgress || !this._isPaused) {
2144
+ this.logger.warn("Resume called but no paused print job");
2145
+ return;
2146
+ }
2147
+ this._isPaused = false;
2148
+ this.logger.info("Print job resumed");
2149
+ try {
2150
+ yield this.processJob();
2151
+ if (!this._isPaused) {
2152
+ this.logger.info("Print job completed successfully");
2153
+ this._isInProgress = false;
2154
+ this.jobBuffer = null;
2155
+ this.jobOffset = 0;
2156
+ }
2157
+ } catch (error) {
2158
+ this.logger.error("Print job failed after resume:", error);
2159
+ this._isInProgress = false;
2160
+ this.jobBuffer = null;
2161
+ this.jobOffset = 0;
2162
+ const printError = error instanceof BluetoothPrintError ? error : new BluetoothPrintError(ErrorCode.PRINT_JOB_FAILED, "Print job failed", error);
2163
+ throw printError;
2164
+ }
2165
+ });
2166
+ }
2167
+ /**
2168
+ * Cancels the current print job
2169
+ */
2170
+ cancel() {
2171
+ if (!this._isInProgress) {
2172
+ this.logger.warn("Cancel called but no print job in progress");
2173
+ return;
2174
+ }
2175
+ this._isPaused = false;
2176
+ this._isInProgress = false;
2177
+ this.jobBuffer = null;
2178
+ this.jobOffset = 0;
2179
+ this.logger.info("Print job cancelled");
2180
+ }
2181
+ /**
2182
+ * Gets the number of bytes remaining to print
2183
+ *
2184
+ * @returns number - Bytes remaining
2185
+ */
2186
+ remaining() {
2187
+ if (this.jobBuffer) {
2188
+ return this.jobBuffer.length - this.jobOffset;
2189
+ }
2190
+ return 0;
2191
+ }
2192
+ /**
2193
+ * Checks if the print job is paused
2194
+ *
2195
+ * @returns boolean - True if paused, false otherwise
2196
+ */
2197
+ isPaused() {
2198
+ return this._isPaused;
2199
+ }
2200
+ /**
2201
+ * Checks if a print job is in progress
2202
+ *
2203
+ * @returns boolean - True if in progress, false otherwise
2204
+ */
2205
+ isInProgress() {
2206
+ return this._isInProgress;
2207
+ }
2208
+ /**
2209
+ * Sets adapter options for write operations
2210
+ *
2211
+ * @param options - Adapter options
2212
+ */
2213
+ setOptions(options) {
2214
+ this.adapterOptions = __spreadValues(__spreadValues({}, this.adapterOptions), options);
2215
+ this.logger.debug("Adapter options updated:", this.adapterOptions);
2216
+ }
2217
+ /**
2218
+ * Processes the print job in chunks
2219
+ * Supports pause/resume functionality
2220
+ *
2221
+ * @returns Promise<void>
2222
+ */
2223
+ processJob() {
2224
+ return __async(this, null, function* () {
2225
+ if (!this.jobBuffer) {
2226
+ return;
2227
+ }
2228
+ if (!this.adapter || typeof this.adapter.write !== "function") {
2229
+ throw new BluetoothPrintError(
2230
+ ErrorCode.INVALID_CONFIGURATION,
2231
+ "Printer adapter does not support write operation"
2232
+ );
2233
+ }
2234
+ const printerChunkSize = 512;
2235
+ const total = this.jobBuffer.length;
2236
+ const jobBuffer = this.jobBuffer;
2237
+ try {
2238
+ while (this.jobOffset < jobBuffer.length) {
2239
+ if (this._isPaused) {
2240
+ this.logger.debug("Job paused at offset:", this.jobOffset);
2241
+ return;
2242
+ }
2243
+ const end = Math.min(this.jobOffset + printerChunkSize, jobBuffer.length);
2244
+ const chunk = jobBuffer.slice(this.jobOffset, end);
2245
+ yield this.adapter.write(this.getDeviceId(), chunk.buffer, this.adapterOptions);
2246
+ this.jobOffset = end;
2247
+ this.logger.debug(`Processed ${this.jobOffset}/${total} bytes`);
2248
+ }
2249
+ } catch (error) {
2250
+ this.logger.error("Error processing job:", error);
2251
+ throw error;
2252
+ }
2253
+ });
2254
+ }
2255
+ /**
2256
+ * Gets the current device ID from the connection manager
2257
+ *
2258
+ * @returns string - Device ID
2259
+ * @throws BluetoothPrintError if no device is connected
2260
+ */
2261
+ getDeviceId() {
2262
+ const deviceId = this.connectionManager.getDeviceId();
2263
+ if (!deviceId) {
2264
+ throw new BluetoothPrintError(ErrorCode.DEVICE_DISCONNECTED, "Device ID not available");
2265
+ }
2266
+ return deviceId;
2267
+ }
2268
+ };
2269
+ PrintJobManager = __decorateClass$2([
2270
+ Service()
2271
+ ], PrintJobManager);
2272
+ const logger = Logger.scope("Encoding");
2273
+ const _Encoding = class _Encoding {
2274
+ /**
2275
+ * Configures the encoding utility
2276
+ *
2277
+ * @param config - Configuration options
2278
+ *
2279
+ * @example
2280
+ * ```typescript
2281
+ * Encoding.configure({
2282
+ * showWarnings: false
2283
+ * });
2284
+ * ```
2285
+ */
2286
+ static configure(config) {
2287
+ this.config = __spreadValues(__spreadValues({}, this.config), config);
2288
+ }
2289
+ /**
2290
+ * Encodes a string to a Uint8Array using the specified encoding
2291
+ *
2292
+ * @param text - Text to encode
2293
+ * @param encoding - Target encoding (default: 'GBK')
2294
+ * @returns Encoded bytes
2295
+ *
2296
+ * @remarks
2297
+ * Note: Native TextEncoder only supports UTF-8.
2298
+ * For GBK encoding, a third-party library or polyfill is recommended.
2299
+ * Currently falls back to UTF-8 with a warning (configurable).
2300
+ *
2301
+ * @example
2302
+ * ```typescript
2303
+ * // UTF-8 encoding
2304
+ * const utf8 = Encoding.encode('Hello', 'UTF-8');
2305
+ *
2306
+ * // GBK encoding (currently falls back to UTF-8)
2307
+ * const gbk = Encoding.encode('你好', 'GBK');
2308
+ * ```
2309
+ */
2310
+ static encode(text, encoding = "GBK") {
2311
+ if (!text || typeof text !== "string") {
2312
+ return new Uint8Array(0);
2313
+ }
2314
+ const normalizedEncoding = encoding.toUpperCase().replace("-", "");
2315
+ if (normalizedEncoding === "UTF8" || normalizedEncoding === "UTF-8") {
2316
+ return this.utf8Encoder.encode(text);
2317
+ }
2318
+ if (this.config.showWarnings && !this.warningShown) {
2319
+ logger.warn(
2320
+ `Encoding ${encoding} not yet fully implemented, falling back to UTF-8. This may cause display issues with some printers.`
2321
+ );
2322
+ this.warningShown = true;
2323
+ }
2324
+ return this.utf8Encoder.encode(text);
2325
+ }
2326
+ /**
2327
+ * Checks if an encoding is supported
2328
+ *
2329
+ * @param encoding - Encoding name to check
2330
+ * @returns True if supported, false otherwise
2331
+ *
2332
+ * @example
2333
+ * ```typescript
2334
+ * if (Encoding.isSupported('GBK')) {
2335
+ * console.log('GBK is supported');
2336
+ * }
2337
+ * ```
2338
+ */
2339
+ static isSupported(encoding) {
2340
+ if (!encoding || typeof encoding !== "string") {
2341
+ return false;
2342
+ }
2343
+ const normalizedEncoding = encoding.toUpperCase().replace("-", "");
2344
+ return normalizedEncoding === "UTF8" || normalizedEncoding === "UTF-8";
2345
+ }
2346
+ };
2347
+ _Encoding.utf8Encoder = new TextEncoder();
2348
+ _Encoding.warningShown = false;
2349
+ _Encoding.config = {
2350
+ showWarnings: true
2351
+ };
2352
+ let Encoding = _Encoding;
2353
+ class ImageProcessing {
2354
+ /**
2355
+ * Convert RGBA data to monochrome bitmap (1 bit per pixel)
2356
+ * suitable for ESC/POS GS v 0 command.
2357
+ * Uses Floyd-Steinberg dithering for better quality.
2358
+ *
2359
+ * @param data - RGBA pixel data as Uint8Array
2360
+ * @param width - Image width in pixels
2361
+ * @param height - Image height in pixels
2362
+ * @returns Monochrome bitmap data as Uint8Array
2363
+ *
2364
+ * @example
2365
+ * ```typescript
2366
+ * const imageData = new Uint8Array(width * height * 4); // RGBA
2367
+ * const bitmap = ImageProcessing.toBitmap(imageData, width, height);
2368
+ * ```
2369
+ */
2370
+ static toBitmap(data, width, height) {
2371
+ if (!data || !(data instanceof Uint8Array) || width <= 0 || height <= 0) {
2372
+ return new Uint8Array(0);
2373
+ }
2374
+ if (data.length !== width * height * 4) {
2375
+ throw new Error(
2376
+ `Invalid image data length: expected ${width * height * 4}, got ${data.length}`
2377
+ );
2378
+ }
2379
+ const bytesPerLine = Math.ceil(width / 8);
2380
+ const bitmap = new Uint8Array(bytesPerLine * height);
2381
+ const grayscale = new Float32Array(width * height);
2382
+ for (let i = 0; i < data.length; i += 4) {
2383
+ const index = i / 4;
2384
+ const r = data[i] || 0;
2385
+ const g = data[i + 1] || 0;
2386
+ const b = data[i + 2] || 0;
2387
+ grayscale[index] = 0.299 * r + 0.587 * g + 0.114 * b;
2388
+ }
2389
+ for (let y = 0; y < height; y++) {
2390
+ for (let x = 0; x < width; x++) {
2391
+ const index = y * width + x;
2392
+ const oldPixel = grayscale[index] || 0;
2393
+ const newPixel = oldPixel < 128 ? 0 : 255;
2394
+ if (newPixel === 0) {
2395
+ const byteIndex = y * bytesPerLine + Math.floor(x / 8);
2396
+ const bitIndex = 7 - x % 8;
2397
+ bitmap[byteIndex] = (bitmap[byteIndex] || 0) | 1 << bitIndex;
2398
+ }
2399
+ const quantError = oldPixel - newPixel;
2400
+ this.distributeError(grayscale, width, height, x, y, quantError);
2401
+ }
2402
+ }
2403
+ return bitmap;
2404
+ }
2405
+ /**
2406
+ * Distribute quantization error to neighboring pixels using Floyd-Steinberg algorithm
2407
+ *
2408
+ * @param grayscale - Grayscale image data
2409
+ * @param width - Image width
2410
+ * @param height - Image height
2411
+ * @param x - Current x position
2412
+ * @param y - Current y position
2413
+ * @param error - Quantization error to distribute
2414
+ */
2415
+ static distributeError(grayscale, width, height, x, y, error) {
2416
+ const distribute = (dx, dy, factor) => {
2417
+ const nx = x + dx;
2418
+ const ny = y + dy;
2419
+ if (nx >= 0 && nx < width && ny >= 0 && ny < height) {
2420
+ const index = ny * width + nx;
2421
+ grayscale[index] = Math.max(0, Math.min(255, (grayscale[index] || 0) + error * factor));
2422
+ }
2423
+ };
2424
+ distribute(1, 0, 7 / 16);
2425
+ distribute(-1, 1, 3 / 16);
2426
+ distribute(0, 1, 5 / 16);
2427
+ distribute(1, 1, 1 / 16);
2428
+ }
2429
+ }
2430
+ class EscPos {
2431
+ constructor() {
2432
+ this.logger = Logger.scope("EscPos");
2433
+ }
2434
+ /**
2435
+ * Initializes the printer
2436
+ * Sends ESC @ command to reset printer to default state
2437
+ *
2438
+ * @returns Array of command buffers
2439
+ */
2440
+ init() {
2441
+ return [new Uint8Array([27, 64])];
2442
+ }
2443
+ /**
2444
+ * Generates text print command
2445
+ *
2446
+ * @param content - Text content to print
2447
+ * @param encoding - Text encoding (default: 'GBK')
2448
+ * @returns Array of command buffers
2449
+ *
2450
+ * @example
2451
+ * ```typescript
2452
+ * driver.text('你好世界', 'GBK');
2453
+ * ```
2454
+ */
2455
+ text(content, encoding = "GBK") {
2456
+ if (!content || typeof content !== "string") {
2457
+ return [];
2458
+ }
2459
+ const encoded = Encoding.encode(content, encoding);
2460
+ return [encoded];
2461
+ }
2462
+ /**
2463
+ * Generates line feed command
2464
+ *
2465
+ * @param lines - Number of lines to feed (default: 1)
2466
+ * @returns Array of command buffers
2467
+ *
2468
+ * @example
2469
+ * ```typescript
2470
+ * driver.feed(3); // Feed 3 lines
2471
+ * ```
2472
+ */
2473
+ feed(lines = 1) {
2474
+ const safeLines = Math.max(1, Math.min(255, Math.floor(lines)));
2475
+ return [new Uint8Array([27, 100, safeLines])];
2476
+ }
2477
+ /**
2478
+ * Generates paper cut command
2479
+ *
2480
+ * @returns Array of command buffers
2481
+ *
2482
+ * @example
2483
+ * ```typescript
2484
+ * driver.cut();
2485
+ * ```
2486
+ */
2487
+ cut() {
2488
+ return [new Uint8Array([29, 86, 0])];
2489
+ }
2490
+ /**
2491
+ * Generates image print command
2492
+ * Uses Floyd-Steinberg dithering for better quality
2493
+ *
2494
+ * @param data - RGBA pixel data
2495
+ * @param width - Image width in pixels
2496
+ * @param height - Image height in pixels
2497
+ * @returns Array of command buffers
2498
+ *
2499
+ * @example
2500
+ * ```typescript
2501
+ * const imageData = new Uint8Array(width * height * 4); // RGBA
2502
+ * driver.image(imageData, 200, 100);
2503
+ * ```
2504
+ */
2505
+ image(data, width, height) {
2506
+ if (!data || !(data instanceof Uint8Array) || width <= 0 || height <= 0) {
2507
+ return [];
2508
+ }
2509
+ if (data.length !== width * height * 4) {
2510
+ this.logger.warn(
2511
+ `Invalid image data length: expected ${width * height * 4}, got ${data.length}`
2512
+ );
2513
+ return [];
2514
+ }
2515
+ const bitmap = ImageProcessing.toBitmap(data, width, height);
2516
+ const bytesPerLine = Math.ceil(width / 8);
2517
+ const xL = bytesPerLine % 256;
2518
+ const xH = Math.floor(bytesPerLine / 256);
2519
+ const yL = height % 256;
2520
+ const yH = Math.floor(height / 256);
2521
+ const header = new Uint8Array([29, 118, 48, 0, xL, xH, yL, yH]);
2522
+ return [header, bitmap];
2523
+ }
2524
+ /**
2525
+ * Generates QR code print command
2526
+ *
2527
+ * @param content - QR code content (URL, text, etc.)
2528
+ * @param options - QR code options
2529
+ * @returns Array of command buffers
2530
+ *
2531
+ * @example
2532
+ * ```typescript
2533
+ * driver.qr('https://example.com', {
2534
+ * model: 2,
2535
+ * size: 8,
2536
+ * errorCorrection: 'M'
2537
+ * });
2538
+ * ```
2539
+ */
2540
+ qr(content, options) {
2541
+ var _a, _b, _c, _d;
2542
+ if (!content || typeof content !== "string") {
2543
+ return [];
2544
+ }
2545
+ const model = (_a = options == null ? void 0 : options.model) != null ? _a : 2;
2546
+ const size = Math.max(1, Math.min(16, (_b = options == null ? void 0 : options.size) != null ? _b : 6));
2547
+ const errorCorrection = (_c = options == null ? void 0 : options.errorCorrection) != null ? _c : "M";
2548
+ const commands = [];
2549
+ commands.push(
2550
+ new Uint8Array([29, 40, 107, 4, 0, 49, 65, model === 1 ? 49 : 50, 0])
2551
+ );
2552
+ commands.push(new Uint8Array([29, 40, 107, 3, 0, 49, 67, size]));
2553
+ const ecMap = { L: 48, M: 49, Q: 50, H: 51 };
2554
+ const ecValue = (_d = ecMap[errorCorrection]) != null ? _d : 49;
2555
+ commands.push(new Uint8Array([29, 40, 107, 3, 0, 49, 69, ecValue]));
2556
+ const data = Encoding.encode(content, "GBK");
2557
+ const len = data.length + 3;
2558
+ const pL = len % 256;
2559
+ const pH = Math.floor(len / 256);
2560
+ commands.push(new Uint8Array([29, 40, 107, pL, pH, 49, 80, 48]));
2561
+ commands.push(data);
2562
+ commands.push(new Uint8Array([29, 40, 107, 3, 0, 49, 81, 48]));
2563
+ return commands;
2564
+ }
1461
2565
  }
1462
- class AdapterFactory {
2566
+ var __getOwnPropDesc$1 = Object.getOwnPropertyDescriptor;
2567
+ var __decorateClass$1 = (decorators, target, key, kind) => {
2568
+ var result = kind > 1 ? void 0 : kind ? __getOwnPropDesc$1(target, key) : target;
2569
+ for (var i = decorators.length - 1, decorator; i >= 0; i--)
2570
+ if (decorator = decorators[i])
2571
+ result = decorator(result) || result;
2572
+ return result;
2573
+ };
2574
+ let CommandBuilder = class {
1463
2575
  /**
1464
- * Creates an adapter instance based on the detected platform
1465
- *
1466
- * @returns An instance of the appropriate adapter for the current platform
1467
- * @throws BluetoothPrintError if the platform is not supported
2576
+ * Creates a new CommandBuilder instance
2577
+ *
2578
+ * @param driver - Printer driver instance
1468
2579
  */
1469
- static create() {
1470
- const platform = detectPlatform();
1471
- switch (platform) {
1472
- case PlatformType.WECHAT:
1473
- return new TaroAdapter();
1474
- case PlatformType.ALIPAY:
1475
- return new AlipayAdapter();
1476
- case PlatformType.BAIDU:
1477
- return new BaiduAdapter();
1478
- case PlatformType.BYTEDANCE:
1479
- return new ByteDanceAdapter();
1480
- default:
1481
- throw new BluetoothPrintError(
1482
- ErrorCode.PLATFORM_NOT_SUPPORTED,
1483
- `Platform ${platform} is not supported. Please use a supported mini-program platform.`
1484
- );
1485
- }
2580
+ constructor(driver) {
2581
+ this.buffer = [];
2582
+ this.logger = Logger.scope("CommandBuilder");
2583
+ this.driver = driver || new EscPos();
2584
+ this.buffer.push(...this.driver.init());
1486
2585
  }
1487
2586
  /**
1488
- * Creates an adapter instance for a specific platform
1489
- *
1490
- * @param platform - The platform type to create an adapter for
1491
- * @returns An instance of the appropriate adapter for the specified platform
1492
- * @throws BluetoothPrintError if the platform is not supported
2587
+ * Adds text to the print queue
2588
+ *
2589
+ * @param content - Text content
2590
+ * @param encoding - Text encoding
2591
+ * @returns this - For method chaining
1493
2592
  */
1494
- static createForPlatform(platform) {
1495
- switch (platform) {
1496
- case PlatformType.WECHAT:
1497
- return new TaroAdapter();
1498
- case PlatformType.ALIPAY:
1499
- return new AlipayAdapter();
1500
- case PlatformType.BAIDU:
1501
- return new BaiduAdapter();
1502
- case PlatformType.BYTEDANCE:
1503
- return new ByteDanceAdapter();
1504
- default:
1505
- throw new BluetoothPrintError(
1506
- ErrorCode.PLATFORM_NOT_SUPPORTED,
1507
- `Platform ${platform} is not supported.`
1508
- );
1509
- }
1510
- }
1511
- }
1512
- class EventEmitter {
1513
- constructor() {
1514
- this.listeners = /* @__PURE__ */ new Map();
2593
+ text(content, encoding) {
2594
+ this.logger.debug("Adding text:", content.substring(0, 50));
2595
+ this.buffer.push(...this.driver.text(content, encoding));
2596
+ return this;
1515
2597
  }
1516
2598
  /**
1517
- * Subscribe to an event
2599
+ * Adds line feeds to the print queue
1518
2600
  *
1519
- * @param event - Event name
1520
- * @param handler - Event handler function
1521
- * @returns Unsubscribe function
2601
+ * @param lines - Number of lines to feed
2602
+ * @returns this - For method chaining
1522
2603
  */
1523
- on(event, handler) {
1524
- if (!this.listeners.has(event)) {
1525
- this.listeners.set(event, /* @__PURE__ */ new Set());
1526
- }
1527
- this.listeners.get(event).add(handler);
1528
- return () => this.off(event, handler);
2604
+ feed(lines = 1) {
2605
+ this.logger.debug("Adding feed:", lines);
2606
+ this.buffer.push(...this.driver.feed(lines));
2607
+ return this;
1529
2608
  }
1530
2609
  /**
1531
- * Subscribe to an event, but only for the first occurrence
2610
+ * Adds a paper cut command to the print queue
1532
2611
  *
1533
- * @param event - Event name
1534
- * @param handler - Event handler function
1535
- * @returns Unsubscribe function
2612
+ * @returns this - For method chaining
1536
2613
  */
1537
- once(event, handler) {
1538
- const wrappedHandler = (data) => {
1539
- handler(data);
1540
- this.off(event, wrappedHandler);
1541
- };
1542
- return this.on(event, wrappedHandler);
2614
+ cut() {
2615
+ this.logger.debug("Adding cut command");
2616
+ this.buffer.push(...this.driver.cut());
2617
+ return this;
1543
2618
  }
1544
2619
  /**
1545
- * Unsubscribe from an event
2620
+ * Adds an image to the print queue
1546
2621
  *
1547
- * @param event - Event name
1548
- * @param handler - Event handler function to remove
2622
+ * @param data - Image data as Uint8Array
2623
+ * @param width - Image width
2624
+ * @param height - Image height
2625
+ * @returns this - For method chaining
1549
2626
  */
1550
- off(event, handler) {
1551
- const handlers = this.listeners.get(event);
1552
- if (handlers) {
1553
- handlers.delete(handler);
1554
- if (handlers.size === 0) {
1555
- this.listeners.delete(event);
1556
- }
1557
- }
2627
+ image(data, width, height) {
2628
+ this.logger.debug(`Adding image: ${width}x${height}`);
2629
+ this.buffer.push(...this.driver.image(data, width, height));
2630
+ return this;
1558
2631
  }
1559
2632
  /**
1560
- * Emit an event to all subscribers
2633
+ * Adds a QR code to the print queue
1561
2634
  *
1562
- * @param event - Event name
1563
- * @param data - Event payload (optional for void events)
2635
+ * @param content - QR code content
2636
+ * @param options - QR code options
2637
+ * @returns this - For method chaining
1564
2638
  */
1565
- emit(event, data) {
1566
- const handlers = this.listeners.get(event);
1567
- if (!handlers || handlers.size === 0) {
1568
- return;
1569
- }
1570
- const handlersCopy = new Set(handlers);
1571
- handlersCopy.forEach((handler) => {
1572
- try {
1573
- if (data === void 0 && data === null) {
1574
- handler("");
1575
- } else {
1576
- handler(data);
1577
- }
1578
- } catch (error) {
1579
- console.error(`Error in event handler for "${String(event)}":`, error);
1580
- }
1581
- });
2639
+ qr(content, options) {
2640
+ this.logger.debug("Adding QR code:", content.substring(0, 50));
2641
+ this.buffer.push(...this.driver.qr(content, options));
2642
+ return this;
1582
2643
  }
1583
2644
  /**
1584
- * Remove all event listeners
1585
- * @param event - Optional event name to remove all listeners for a specific event
2645
+ * Clears the print queue
2646
+ *
2647
+ * @returns this - For method chaining
1586
2648
  */
1587
- removeAllListeners(event) {
1588
- if (event) {
1589
- this.listeners.delete(event);
1590
- } else {
1591
- this.listeners.clear();
1592
- }
2649
+ clear() {
2650
+ this.logger.debug("Clearing buffer");
2651
+ this.buffer = [];
2652
+ this.buffer.push(...this.driver.init());
2653
+ return this;
1593
2654
  }
1594
2655
  /**
1595
- * Get the number of listeners for an event
2656
+ * Gets the current buffer
1596
2657
  *
1597
- * @param event - Event name
1598
- * @returns Number of listeners
2658
+ * @returns Uint8Array - Current print buffer
1599
2659
  */
1600
- listenerCount(event) {
1601
- var _a, _b;
1602
- return (_b = (_a = this.listeners.get(event)) == null ? void 0 : _a.size) != null ? _b : 0;
2660
+ getBuffer() {
2661
+ const totalLength = this.buffer.reduce((acc, b) => acc + b.length, 0);
2662
+ const combined = new Uint8Array(totalLength);
2663
+ let offset = 0;
2664
+ for (const b of this.buffer) {
2665
+ combined.set(b, offset);
2666
+ offset += b.length;
2667
+ }
2668
+ return combined;
1603
2669
  }
1604
2670
  /**
1605
- * Check if there are any listeners for an event
2671
+ * Gets the total number of bytes in the buffer
1606
2672
  *
1607
- * @param event - Event name
1608
- * @returns True if there are listeners, false otherwise
2673
+ * @returns number - Total bytes
1609
2674
  */
1610
- hasListeners(event) {
1611
- return this.listenerCount(event) > 0;
2675
+ getTotalBytes() {
2676
+ return this.buffer.reduce((acc, b) => acc + b.length, 0);
1612
2677
  }
1613
- }
1614
- class BluetoothPrinter extends EventEmitter {
2678
+ };
2679
+ CommandBuilder = __decorateClass$1([
2680
+ Service()
2681
+ ], CommandBuilder);
2682
+ var __getOwnPropDesc = Object.getOwnPropertyDescriptor;
2683
+ var __decorateClass = (decorators, target, key, kind) => {
2684
+ var result = kind > 1 ? void 0 : kind ? __getOwnPropDesc(target, key) : target;
2685
+ for (var i = decorators.length - 1, decorator; i >= 0; i--)
2686
+ if (decorator = decorators[i])
2687
+ result = decorator(result) || result;
2688
+ return result;
2689
+ };
2690
+ let BluetoothPrinter = class extends EventEmitter {
1615
2691
  /**
1616
2692
  * Creates a new BluetoothPrinter instance
1617
2693
  *
1618
- * @param adapter - Custom adapter implementation (defaults to platform-specific adapter)
1619
- * @param driver - Custom driver implementation (defaults to EscPos)
2694
+ * @param connectionManagerOrAdapter - Connection manager instance or printer adapter instance (for backward compatibility)
2695
+ * @param printJobManagerOrDriver - Print job manager instance or printer driver instance (for backward compatibility)
2696
+ * @param commandBuilder - Command builder instance (optional)
1620
2697
  */
1621
- constructor(adapter, driver) {
1622
- var _a, _b;
2698
+ constructor(connectionManagerOrAdapter, printJobManagerOrDriver, commandBuilder) {
1623
2699
  super();
1624
- this.deviceId = null;
1625
- this.buffer = [];
1626
- this.adapterOptions = {};
1627
- this.isPaused = false;
1628
- this.jobBuffer = null;
1629
- this.jobOffset = 0;
1630
2700
  this.logger = Logger.scope("BluetoothPrinter");
1631
2701
  this.state = PrinterState.DISCONNECTED;
1632
- this.adapter = adapter || AdapterFactory.create();
1633
- this.driver = driver || new EscPos();
1634
- (_b = (_a = this.adapter).onStateChange) == null ? void 0 : _b.call(_a, (state) => {
1635
- this.state = state;
1636
- this.emit("state-change", state);
1637
- this.logger.debug("State changed:", state);
1638
- });
2702
+ if (connectionManagerOrAdapter && typeof connectionManagerOrAdapter.connect === "function") {
2703
+ const adapter = connectionManagerOrAdapter;
2704
+ const driver = printJobManagerOrDriver;
2705
+ this.connectionManager = new ConnectionManager(adapter);
2706
+ this.printJobManager = new PrintJobManager(this.connectionManager, adapter);
2707
+ this.commandBuilder = new CommandBuilder(driver);
2708
+ } else {
2709
+ this.connectionManager = connectionManagerOrAdapter;
2710
+ this.printJobManager = printJobManagerOrDriver;
2711
+ this.commandBuilder = commandBuilder;
2712
+ if (!this.connectionManager) {
2713
+ this.connectionManager = new ConnectionManager();
2714
+ this.printJobManager = new PrintJobManager(this.connectionManager);
2715
+ this.commandBuilder = new CommandBuilder();
2716
+ }
2717
+ }
2718
+ this.updateState();
2719
+ }
2720
+ /**
2721
+ * Updates the current state based on the connection manager and print job manager states
2722
+ */
2723
+ updateState() {
2724
+ let connectionState;
2725
+ if (this.connectionManager && typeof this.connectionManager.getState === "function") {
2726
+ connectionState = this.connectionManager.getState();
2727
+ } else {
2728
+ connectionState = PrinterState.CONNECTED;
2729
+ }
2730
+ let isPrinting = false;
2731
+ let isPaused = false;
2732
+ if (this.printJobManager) {
2733
+ isPrinting = typeof this.printJobManager.isInProgress === "function" ? this.printJobManager.isInProgress() : false;
2734
+ isPaused = typeof this.printJobManager.isPaused === "function" ? this.printJobManager.isPaused() : false;
2735
+ }
2736
+ if (isPaused) {
2737
+ this.state = PrinterState.PAUSED;
2738
+ } else if (isPrinting) {
2739
+ this.state = PrinterState.PRINTING;
2740
+ } else {
2741
+ this.state = connectionState;
2742
+ }
2743
+ this.emit("state-change", this.state);
2744
+ this.logger.debug("State updated:", this.state);
1639
2745
  }
1640
2746
  /**
1641
2747
  * Connects to a Bluetooth device
@@ -1653,20 +2759,19 @@ class BluetoothPrinter extends EventEmitter {
1653
2759
  return __async(this, null, function* () {
1654
2760
  this.logger.info("Connecting to device:", deviceId);
1655
2761
  try {
1656
- this.deviceId = deviceId;
1657
- yield this.adapter.connect(deviceId);
1658
- this.buffer.push(...this.driver.init());
2762
+ yield this.connectionManager.connect(deviceId);
2763
+ this.updateState();
1659
2764
  this.emit("connected", deviceId);
1660
2765
  this.logger.info("Connected successfully");
1661
2766
  return this;
1662
2767
  } catch (error) {
1663
- this.deviceId = null;
1664
2768
  const printError = error instanceof BluetoothPrintError ? error : new BluetoothPrintError(
1665
2769
  ErrorCode.CONNECTION_FAILED,
1666
2770
  "Connection failed",
1667
2771
  error
1668
2772
  );
1669
2773
  this.emit("error", printError);
2774
+ this.updateState();
1670
2775
  throw printError;
1671
2776
  }
1672
2777
  });
@@ -1683,18 +2788,16 @@ class BluetoothPrinter extends EventEmitter {
1683
2788
  */
1684
2789
  disconnect() {
1685
2790
  return __async(this, null, function* () {
1686
- if (!this.deviceId) {
2791
+ const deviceId = this.connectionManager.getDeviceId();
2792
+ if (!deviceId) {
1687
2793
  this.logger.warn("Disconnect called but no device connected");
1688
2794
  return;
1689
2795
  }
1690
- const deviceId = this.deviceId;
1691
2796
  this.logger.info("Disconnecting from device:", deviceId);
1692
2797
  try {
1693
- yield this.adapter.disconnect(deviceId);
1694
- this.deviceId = null;
1695
- this.buffer = [];
1696
- this.jobBuffer = null;
1697
- this.jobOffset = 0;
2798
+ yield this.connectionManager.disconnect();
2799
+ this.printJobManager.cancel();
2800
+ this.updateState();
1698
2801
  this.emit("disconnected", deviceId);
1699
2802
  this.logger.info("Disconnected successfully");
1700
2803
  } catch (error) {
@@ -1704,6 +2807,7 @@ class BluetoothPrinter extends EventEmitter {
1704
2807
  error
1705
2808
  );
1706
2809
  this.emit("error", printError);
2810
+ this.updateState();
1707
2811
  throw printError;
1708
2812
  }
1709
2813
  });
@@ -1721,8 +2825,7 @@ class BluetoothPrinter extends EventEmitter {
1721
2825
  * ```
1722
2826
  */
1723
2827
  text(content, encoding) {
1724
- this.logger.debug("Adding text:", content.substring(0, 50));
1725
- this.buffer.push(...this.driver.text(content, encoding));
2828
+ this.commandBuilder.text(content, encoding);
1726
2829
  return this;
1727
2830
  }
1728
2831
  /**
@@ -1737,8 +2840,7 @@ class BluetoothPrinter extends EventEmitter {
1737
2840
  * ```
1738
2841
  */
1739
2842
  feed(lines = 1) {
1740
- this.logger.debug("Adding feed:", lines);
1741
- this.buffer.push(...this.driver.feed(lines));
2843
+ this.commandBuilder.feed(lines);
1742
2844
  return this;
1743
2845
  }
1744
2846
  /**
@@ -1752,8 +2854,7 @@ class BluetoothPrinter extends EventEmitter {
1752
2854
  * ```
1753
2855
  */
1754
2856
  cut() {
1755
- this.logger.debug("Adding cut command");
1756
- this.buffer.push(...this.driver.cut());
2857
+ this.commandBuilder.cut();
1757
2858
  return this;
1758
2859
  }
1759
2860
  /**
@@ -1771,8 +2872,7 @@ class BluetoothPrinter extends EventEmitter {
1771
2872
  * ```
1772
2873
  */
1773
2874
  image(data, width, height) {
1774
- this.logger.debug(`Adding image: ${width}x${height}`);
1775
- this.buffer.push(...this.driver.image(data, width, height));
2875
+ this.commandBuilder.image(data, width, height);
1776
2876
  return this;
1777
2877
  }
1778
2878
  /**
@@ -1788,8 +2888,7 @@ class BluetoothPrinter extends EventEmitter {
1788
2888
  * ```
1789
2889
  */
1790
2890
  qr(content, options) {
1791
- this.logger.debug("Adding QR code:", content.substring(0, 50));
1792
- this.buffer.push(...this.driver.qr(content, options));
2891
+ this.commandBuilder.qr(content, options);
1793
2892
  return this;
1794
2893
  }
1795
2894
  /**
@@ -1804,8 +2903,7 @@ class BluetoothPrinter extends EventEmitter {
1804
2903
  * ```
1805
2904
  */
1806
2905
  setOptions(options) {
1807
- this.adapterOptions = __spreadValues(__spreadValues({}, this.adapterOptions), options);
1808
- this.logger.debug("Adapter options updated:", this.adapterOptions);
2906
+ this.printJobManager.setOptions(options);
1809
2907
  return this;
1810
2908
  }
1811
2909
  /**
@@ -1820,9 +2918,8 @@ class BluetoothPrinter extends EventEmitter {
1820
2918
  * ```
1821
2919
  */
1822
2920
  pause() {
1823
- this.isPaused = true;
1824
- this.state = PrinterState.PAUSED;
1825
- this.emit("state-change", PrinterState.PAUSED);
2921
+ this.printJobManager.pause();
2922
+ this.updateState();
1826
2923
  this.logger.info("Print job paused");
1827
2924
  }
1828
2925
  /**
@@ -1837,16 +2934,11 @@ class BluetoothPrinter extends EventEmitter {
1837
2934
  */
1838
2935
  resume() {
1839
2936
  return __async(this, null, function* () {
1840
- if (!this.isPaused || !this.jobBuffer) {
1841
- this.logger.warn("Resume called but job not paused or no job buffer");
1842
- return;
1843
- }
1844
- this.isPaused = false;
1845
- this.state = PrinterState.PRINTING;
1846
- this.emit("state-change", PrinterState.PRINTING);
1847
- this.logger.info("Print job resumed");
2937
+ this.logger.info("Resuming print job");
1848
2938
  try {
1849
- yield this.processJob();
2939
+ yield this.printJobManager.resume();
2940
+ this.updateState();
2941
+ this.logger.info("Print job resumed");
1850
2942
  } catch (error) {
1851
2943
  const printError = new BluetoothPrintError(
1852
2944
  ErrorCode.PRINT_JOB_FAILED,
@@ -1854,6 +2946,7 @@ class BluetoothPrinter extends EventEmitter {
1854
2946
  error
1855
2947
  );
1856
2948
  this.emit("error", printError);
2949
+ this.updateState();
1857
2950
  throw printError;
1858
2951
  }
1859
2952
  });
@@ -1867,12 +2960,9 @@ class BluetoothPrinter extends EventEmitter {
1867
2960
  * ```
1868
2961
  */
1869
2962
  cancel() {
1870
- this.isPaused = false;
1871
- this.jobBuffer = null;
1872
- this.jobOffset = 0;
1873
- this.buffer = [];
1874
- this.state = this.deviceId ? PrinterState.CONNECTED : PrinterState.DISCONNECTED;
1875
- this.emit("state-change", this.state);
2963
+ this.printJobManager.cancel();
2964
+ this.commandBuilder.clear();
2965
+ this.updateState();
1876
2966
  this.logger.info("Print job cancelled");
1877
2967
  }
1878
2968
  /**
@@ -1886,10 +2976,7 @@ class BluetoothPrinter extends EventEmitter {
1886
2976
  * ```
1887
2977
  */
1888
2978
  remaining() {
1889
- if (this.jobBuffer) {
1890
- return this.jobBuffer.length - this.jobOffset;
1891
- }
1892
- return this.buffer.reduce((acc, b) => acc + b.length, 0);
2979
+ return this.printJobManager.remaining();
1893
2980
  }
1894
2981
  /**
1895
2982
  * Sends all queued commands to the printer
@@ -1907,91 +2994,39 @@ class BluetoothPrinter extends EventEmitter {
1907
2994
  */
1908
2995
  print() {
1909
2996
  return __async(this, null, function* () {
1910
- if (!this.deviceId) {
2997
+ if (!this.connectionManager.isConnected()) {
1911
2998
  throw new BluetoothPrintError(
1912
2999
  ErrorCode.CONNECTION_FAILED,
1913
3000
  "Printer not connected. Call connect() first."
1914
3001
  );
1915
3002
  }
1916
- if (this.jobBuffer) {
1917
- throw new BluetoothPrintError(
1918
- ErrorCode.PRINT_JOB_IN_PROGRESS,
1919
- "A print job is already in progress. Wait for completion or cancel it."
1920
- );
1921
- }
1922
- const totalLength = this.buffer.reduce((acc, b) => acc + b.length, 0);
1923
- this.logger.info(`Starting print job: ${totalLength} bytes`);
1924
- const combined = new Uint8Array(totalLength);
1925
- let offset = 0;
1926
- for (const b of this.buffer) {
1927
- combined.set(b, offset);
1928
- offset += b.length;
1929
- }
1930
- this.jobBuffer = combined;
1931
- this.jobOffset = 0;
1932
- this.buffer = [];
1933
- this.isPaused = false;
1934
- this.state = PrinterState.PRINTING;
1935
- this.emit("state-change", this.state);
3003
+ const buffer = this.commandBuilder.getBuffer();
3004
+ this.logger.info(`Starting print job: ${buffer.length} bytes`);
3005
+ this.commandBuilder.clear();
3006
+ this.updateState();
1936
3007
  try {
1937
- yield this.processJob();
1938
- if (this.isPaused) {
3008
+ yield this.printJobManager.start(buffer);
3009
+ const isPaused = typeof this.printJobManager.isPaused === "function" ? this.printJobManager.isPaused() : false;
3010
+ if (isPaused) {
1939
3011
  this.logger.info("Print job paused");
1940
3012
  } else {
1941
3013
  this.emit("print-complete");
1942
3014
  this.logger.info("Print job completed successfully");
1943
- this.state = PrinterState.CONNECTED;
1944
- this.emit("state-change", this.state);
1945
3015
  }
1946
3016
  } catch (error) {
3017
+ this.logger.error("Print job failed with error:", error);
1947
3018
  const printError = error instanceof BluetoothPrintError ? error : new BluetoothPrintError(ErrorCode.PRINT_JOB_FAILED, "Print job failed", error);
1948
3019
  this.emit("error", printError);
1949
- this.state = PrinterState.CONNECTED;
1950
- this.emit("state-change", this.state);
1951
3020
  throw printError;
1952
- }
1953
- });
1954
- }
1955
- /**
1956
- * Processes the print job in chunks
1957
- * Supports pause/resume and emits progress events
1958
- */
1959
- processJob() {
1960
- return __async(this, null, function* () {
1961
- if (!this.jobBuffer || !this.deviceId) return;
1962
- const printerChunkSize = 512;
1963
- const total = this.jobBuffer.length;
1964
- const deviceId = this.deviceId;
1965
- const jobBuffer = this.jobBuffer;
1966
- try {
1967
- while (this.jobOffset < jobBuffer.length) {
1968
- if (this.isPaused) {
1969
- this.logger.debug("Job paused at offset:", this.jobOffset);
1970
- return;
1971
- }
1972
- if (this.state !== PrinterState.CONNECTED && this.state !== PrinterState.PRINTING && this.state !== PrinterState.PAUSED) {
1973
- throw new BluetoothPrintError(
1974
- ErrorCode.DEVICE_DISCONNECTED,
1975
- "Device disconnected during print job"
1976
- );
1977
- }
1978
- const end = Math.min(this.jobOffset + printerChunkSize, jobBuffer.length);
1979
- const chunk = jobBuffer.slice(this.jobOffset, end);
1980
- yield this.adapter.write(deviceId, chunk.buffer, this.adapterOptions);
1981
- this.jobOffset = end;
1982
- if (this.hasListeners("progress")) {
1983
- this.emit("progress", { sent: this.jobOffset, total });
1984
- }
1985
- }
1986
3021
  } finally {
1987
- if (this.jobOffset >= jobBuffer.length) {
1988
- this.jobBuffer = null;
1989
- this.jobOffset = 0;
1990
- }
3022
+ this.updateState();
1991
3023
  }
1992
3024
  });
1993
3025
  }
1994
- }
3026
+ };
3027
+ BluetoothPrinter = __decorateClass([
3028
+ Service()
3029
+ ], BluetoothPrinter);
1995
3030
  const DEFAULT_CONFIG = {
1996
3031
  adapter: {
1997
3032
  chunkSize: 20,