taro-bluetooth-print 2.9.2 → 2.9.4

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.
@@ -147,6 +147,11 @@ export declare abstract class BaseAdapter implements IPrinterAdapter {
147
147
  * @param deviceId - Device ID
148
148
  */
149
149
  protected cleanupDevice(deviceId: string): void;
150
+ /**
151
+ * Cleanup resources and destroy the adapter instance
152
+ * Removes all event listeners and releases resources
153
+ */
154
+ destroy(): void;
150
155
  }
151
156
  /**
152
157
  * Base adapter for mini-program platforms (Taro/WeChat, Alipay, Baidu, ByteDance).
@@ -173,4 +173,9 @@ export declare class WebBluetoothAdapter extends BaseAdapter {
173
173
  * Uses device name + first seen timestamp as identifier
174
174
  */
175
175
  private generateFallbackDeviceId;
176
+ /**
177
+ * Cleanup resources and destroy the adapter instance
178
+ * Removes all event listeners and releases resources
179
+ */
180
+ destroy(): void;
176
181
  }
@@ -338,4 +338,14 @@ export declare class BluetoothPrinter extends EventEmitter<PrinterEvents> {
338
338
  * @returns Command builder instance
339
339
  */
340
340
  getCommandBuilder(): ICommandBuilder;
341
+ /**
342
+ * Cleanup resources and destroy the printer instance
343
+ * Removes all event listeners and releases resources
344
+ *
345
+ * @example
346
+ * ```typescript
347
+ * printer.destroy();
348
+ * ```
349
+ */
350
+ destroy(): void;
341
351
  }
@@ -46,4 +46,9 @@ export interface IConnectionManager {
46
46
  * @returns IPrinterAdapter - Printer adapter
47
47
  */
48
48
  getAdapter(): IPrinterAdapter;
49
+ /**
50
+ * Cleanup resources and destroy the connection manager
51
+ * Stops heartbeat, clears timers, and removes event listeners
52
+ */
53
+ destroy(): void;
49
54
  }
@@ -67,6 +67,11 @@ export interface IPrinterAdapter {
67
67
  * @param callback - Function to call when the state changes
68
68
  */
69
69
  onStateChange?(callback: (state: PrinterState) => void): void;
70
+ /**
71
+ * Cleanup resources and destroy the adapter instance
72
+ * Removes all event listeners and releases resources
73
+ */
74
+ destroy?(): void;
70
75
  }
71
76
  /**
72
77
  * Interface for printer drivers
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "taro-bluetooth-print",
3
- "version": "2.9.2",
3
+ "version": "2.9.4",
4
4
  "description": "Taro 蓝牙打印库 v2.6 - 轻量级、高性能、跨平台支持微信、支付宝、百度、字节跳动小程序及H5 Web Bluetooth",
5
5
  "type": "module",
6
6
  "main": "dist/index.cjs.js",
@@ -185,6 +185,16 @@ export abstract class BaseAdapter implements IPrinterAdapter {
185
185
  protected cleanupDevice(deviceId: string): void {
186
186
  this.serviceCache.delete(deviceId);
187
187
  }
188
+
189
+ /**
190
+ * Cleanup resources and destroy the adapter instance
191
+ * Removes all event listeners and releases resources
192
+ */
193
+ destroy(): void {
194
+ this.logger.debug('Destroying BaseAdapter');
195
+ this.serviceCache.clear();
196
+ this.stateCallback = undefined;
197
+ }
188
198
  }
189
199
 
190
200
  /**
@@ -10,6 +10,14 @@ import { IAdapterOptions, PrinterState } from '@/types';
10
10
  import { BaseAdapter } from './BaseAdapter';
11
11
  import { BluetoothPrintError, ErrorCode } from '@/errors/BluetoothError';
12
12
 
13
+ /**
14
+ * Extended Bluetooth device interface with RSSI support
15
+ * This is a vendor-specific extension not part of the standard Web Bluetooth API
16
+ */
17
+ interface BluetoothDeviceWithRssi extends BluetoothDevice {
18
+ readRemoteRssi(): Promise<number>;
19
+ }
20
+
13
21
  /**
14
22
  * Web Bluetooth device information
15
23
  */
@@ -210,10 +218,9 @@ export class WebBluetoothAdapter extends BaseAdapter {
210
218
  // Get RSSI if available (may not be available on all devices)
211
219
  let rssi: number | undefined;
212
220
  try {
213
- if ('readRemoteRssi' in characteristic.service.device) {
214
- /* eslint-disable @typescript-eslint/no-explicit-any, @typescript-eslint/no-unsafe-member-access, @typescript-eslint/no-unsafe-call, @typescript-eslint/no-unsafe-assignment */
215
- rssi = await (characteristic.service.device as any).readRemoteRssi();
216
- /* eslint-enable @typescript-eslint/no-explicit-any, @typescript-eslint/no-unsafe-member-access, @typescript-eslint/no-unsafe-call, @typescript-eslint/no-unsafe-assignment */
221
+ const deviceWithRssi = characteristic.service.device as BluetoothDeviceWithRssi;
222
+ if ('readRemoteRssi' in deviceWithRssi && typeof deviceWithRssi.readRemoteRssi === 'function') {
223
+ rssi = await deviceWithRssi.readRemoteRssi();
217
224
  }
218
225
  } catch {
219
226
  this.logger.debug('RSSI reading not supported on this device');
@@ -681,4 +688,38 @@ export class WebBluetoothAdapter extends BaseAdapter {
681
688
  const timestamp = Date.now().toString(36);
682
689
  return `fallback_${name}_${timestamp}`;
683
690
  }
691
+
692
+ /**
693
+ * Cleanup resources and destroy the adapter instance
694
+ * Removes all event listeners and releases resources
695
+ */
696
+ destroy(): void {
697
+ this.logger.debug('Destroying WebBluetoothAdapter');
698
+
699
+ // Clear any pending connection cleanup timeout
700
+ if (this.connectionCleanupTimeout) {
701
+ clearTimeout(this.connectionCleanupTimeout);
702
+ this.connectionCleanupTimeout = null;
703
+ }
704
+
705
+ // Disconnect all devices
706
+ for (const [deviceId, deviceInfo] of this.devices) {
707
+ try {
708
+ if (deviceInfo.server.connected) {
709
+ deviceInfo.server.disconnect();
710
+ }
711
+ } catch (error) {
712
+ this.logger.warn(`Error disconnecting device ${deviceId}:`, error);
713
+ }
714
+ }
715
+
716
+ // Clear all device caches
717
+ this.devices.clear();
718
+ this.discoveredDevices.clear();
719
+
720
+ // Call parent destroy
721
+ super.destroy();
722
+
723
+ this.logger.info('WebBluetoothAdapter destroyed');
724
+ }
684
725
  }
@@ -131,19 +131,12 @@ export class BluetoothPrinter extends EventEmitter<PrinterEvents> {
131
131
  * Updates the current state based on the connection manager and print job manager states
132
132
  */
133
133
  private updateState(): void {
134
- // Safe fallbacks for mock objects in tests
135
- const connectionState =
136
- typeof this.connectionManager.getState === 'function'
137
- ? this.connectionManager.getState()
138
- : PrinterState.CONNECTED;
134
+ // All interface methods are guaranteed to exist
135
+ const connectionState = this.connectionManager.getState();
139
136
 
140
- const isPrinting =
141
- typeof this.printJobManager.isInProgress === 'function'
142
- ? this.printJobManager.isInProgress()
143
- : false;
137
+ const isPrinting = this.printJobManager.isInProgress();
144
138
 
145
- const isPaused =
146
- typeof this.printJobManager.isPaused === 'function' ? this.printJobManager.isPaused() : false;
139
+ const isPaused = this.printJobManager.isPaused();
147
140
 
148
141
  // Determine the final state
149
142
  if (isPaused) {
@@ -425,10 +418,7 @@ export class BluetoothPrinter extends EventEmitter<PrinterEvents> {
425
418
  * ```
426
419
  */
427
420
  async print(): Promise<void> {
428
- const isConnected =
429
- typeof this.connectionManager.isConnected === 'function'
430
- ? this.connectionManager.isConnected()
431
- : true; // Default to true for mock objects
421
+ const isConnected = this.connectionManager.isConnected();
432
422
 
433
423
  if (!isConnected) {
434
424
  throw new BluetoothPrintError(
@@ -453,10 +443,7 @@ export class BluetoothPrinter extends EventEmitter<PrinterEvents> {
453
443
  try {
454
444
  await this.printJobManager.start(buffer);
455
445
 
456
- const isPaused =
457
- typeof this.printJobManager.isPaused === 'function'
458
- ? this.printJobManager.isPaused()
459
- : false;
446
+ const isPaused = this.printJobManager.isPaused();
460
447
 
461
448
  if (isPaused) {
462
449
  // Print job was paused
@@ -607,4 +594,38 @@ export class BluetoothPrinter extends EventEmitter<PrinterEvents> {
607
594
  getCommandBuilder(): ICommandBuilder {
608
595
  return this.commandBuilder;
609
596
  }
597
+
598
+ /**
599
+ * Cleanup resources and destroy the printer instance
600
+ * Removes all event listeners and releases resources
601
+ *
602
+ * @example
603
+ * ```typescript
604
+ * printer.destroy();
605
+ * ```
606
+ */
607
+ destroy(): void {
608
+ this.printerLogger.info('Destroying BluetoothPrinter instance');
609
+
610
+ // Cancel any pending print job
611
+ this.printJobManager.cancel();
612
+
613
+ // Clear command buffer
614
+ this.commandBuilder.clear();
615
+
616
+ // Disconnect if connected
617
+ if (this.connectionManager.isConnected()) {
618
+ this.connectionManager.disconnect().catch(error => {
619
+ this.printerLogger.warn('Error during disconnect in destroy:', error);
620
+ });
621
+ }
622
+
623
+ // Cleanup connection manager resources (IConnectionManager now has destroy())
624
+ this.connectionManager.destroy();
625
+
626
+ // Remove all event listeners
627
+ this.removeAllListeners();
628
+
629
+ this.printerLogger.info('BluetoothPrinter instance destroyed');
630
+ }
610
631
  }
@@ -311,7 +311,7 @@ export const rootContainer = new Container();
311
311
  export function injectable<T extends Constructor<object>>(constructor: T): T {
312
312
  // 标记类为可注入
313
313
  // eslint-disable-next-line @typescript-eslint/no-unsafe-member-access
314
- (constructor as Constructor & { __injectable: boolean }).__injectable = true;
314
+ (constructor as unknown as { __injectable: boolean }).__injectable = true;
315
315
  return constructor;
316
316
  }
317
317
 
@@ -310,7 +310,7 @@ export class ConnectionManager
310
310
  /**
311
311
  * Attempt to reconnect
312
312
  */
313
- private attemptReconnect(): void {
313
+ private async attemptReconnect(): Promise<void> {
314
314
  if (!this.deviceId) {
315
315
  this.isReconnecting = false;
316
316
  return;
@@ -345,27 +345,25 @@ export class ConnectionManager
345
345
  this.state = PrinterState.CONNECTING;
346
346
  this.emit('state-change', PrinterState.CONNECTING);
347
347
 
348
- this.adapter
349
- .connect(deviceId)
350
- .then(() => {
351
- this.connLogger.info('Reconnected successfully');
352
- this.isReconnecting = false;
353
- this.reconnectAttempts = 0;
354
- this.state = PrinterState.CONNECTED;
355
- this.emit('state-change', PrinterState.CONNECTED);
356
- this.emit('reconnected', deviceId);
348
+ try {
349
+ await this.adapter.connect(deviceId);
350
+ this.connLogger.info('Reconnected successfully');
351
+ this.isReconnecting = false;
352
+ this.reconnectAttempts = 0;
353
+ this.state = PrinterState.CONNECTED;
354
+ this.emit('state-change', PrinterState.CONNECTED);
355
+ this.emit('reconnected', deviceId);
357
356
 
358
- if (this.config.heartbeatEnabled) {
359
- this.startHeartbeat();
360
- }
361
- })
362
- .catch(error => {
363
- this.connLogger.warn(`Reconnect attempt ${this.reconnectAttempts} failed:`, error);
357
+ if (this.config.heartbeatEnabled) {
358
+ this.startHeartbeat();
359
+ }
360
+ } catch (error) {
361
+ this.connLogger.warn(`Reconnect attempt ${this.reconnectAttempts} failed:`, error);
364
362
 
365
- this.reconnectTimer = setTimeout(() => {
366
- this.attemptReconnect();
367
- }, this.config.reconnectInterval);
368
- });
363
+ this.reconnectTimer = setTimeout(() => {
364
+ this.attemptReconnect();
365
+ }, this.config.reconnectInterval);
366
+ }
369
367
  }
370
368
 
371
369
  /**
@@ -55,4 +55,10 @@ export interface IConnectionManager {
55
55
  * @returns IPrinterAdapter - Printer adapter
56
56
  */
57
57
  getAdapter(): IPrinterAdapter;
58
+
59
+ /**
60
+ * Cleanup resources and destroy the connection manager
61
+ * Stops heartbeat, clears timers, and removes event listeners
62
+ */
63
+ destroy(): void;
58
64
  }
package/src/types.ts CHANGED
@@ -75,6 +75,12 @@ export interface IPrinterAdapter {
75
75
  * @param callback - Function to call when the state changes
76
76
  */
77
77
  onStateChange?(callback: (state: PrinterState) => void): void;
78
+
79
+ /**
80
+ * Cleanup resources and destroy the adapter instance
81
+ * Removes all event listeners and releases resources
82
+ */
83
+ destroy?(): void;
78
84
  }
79
85
 
80
86
  /**