taro-bluetooth-print 2.2.0 → 2.3.0

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.
Files changed (49) hide show
  1. package/CHANGELOG.md +38 -0
  2. package/README.md +128 -22
  3. package/dist/index.cjs.js +1 -1
  4. package/dist/index.es.js +1 -6995
  5. package/dist/index.umd.js +1 -1
  6. package/dist/types/adapters/AdapterFactory.d.ts +0 -1
  7. package/dist/types/adapters/AlipayAdapter.d.ts +6 -34
  8. package/dist/types/adapters/BaiduAdapter.d.ts +6 -34
  9. package/dist/types/adapters/BaseAdapter.d.ts +112 -1
  10. package/dist/types/adapters/ByteDanceAdapter.d.ts +6 -34
  11. package/dist/types/adapters/TaroAdapter.d.ts +6 -34
  12. package/dist/types/adapters/WebBluetoothAdapter.d.ts +0 -1
  13. package/dist/types/config/PrinterConfig.d.ts +0 -1
  14. package/dist/types/core/BluetoothPrinter.d.ts +0 -1
  15. package/dist/types/drivers/EscPos.d.ts +0 -1
  16. package/dist/types/drivers/TsplDriver.d.ts +251 -0
  17. package/dist/types/encoding/gbk-data.d.ts +12 -0
  18. package/dist/types/encoding/gbk-table.d.ts +5 -1
  19. package/dist/types/index.d.ts +5 -0
  20. package/dist/types/plugins/PluginManager.d.ts +87 -0
  21. package/dist/types/plugins/builtin/LoggingPlugin.d.ts +14 -0
  22. package/dist/types/plugins/builtin/RetryPlugin.d.ts +18 -0
  23. package/dist/types/plugins/index.d.ts +7 -0
  24. package/dist/types/plugins/types.d.ts +97 -0
  25. package/dist/types/services/CommandBuilder.d.ts +6 -1
  26. package/dist/types/services/ConnectionManager.d.ts +0 -1
  27. package/dist/types/services/PrintJobManager.d.ts +6 -2
  28. package/dist/types/services/interfaces/index.d.ts +0 -1
  29. package/dist/types/template/TemplateEngine.d.ts +0 -1
  30. package/package.json +16 -18
  31. package/src/adapters/AlipayAdapter.ts +8 -314
  32. package/src/adapters/BaiduAdapter.ts +8 -312
  33. package/src/adapters/BaseAdapter.ts +366 -0
  34. package/src/adapters/ByteDanceAdapter.ts +8 -316
  35. package/src/adapters/TaroAdapter.ts +8 -367
  36. package/src/core/EventEmitter.ts +9 -6
  37. package/src/drivers/TsplDriver.ts +417 -0
  38. package/src/encoding/gbk-data.ts +1911 -0
  39. package/src/encoding/gbk-table.ts +22 -498
  40. package/src/index.ts +14 -0
  41. package/src/plugins/PluginManager.ts +193 -0
  42. package/src/plugins/builtin/LoggingPlugin.ts +97 -0
  43. package/src/plugins/builtin/RetryPlugin.ts +109 -0
  44. package/src/plugins/index.ts +10 -0
  45. package/src/plugins/types.ts +119 -0
  46. package/src/preview/PreviewRenderer.ts +7 -1
  47. package/src/queue/PrintQueue.ts +10 -6
  48. package/src/services/CommandBuilder.ts +30 -0
  49. package/src/services/PrintJobManager.ts +51 -35
@@ -17,6 +17,7 @@ import { BarcodeGenerator, BarcodeOptions } from '@/barcode';
17
17
  export class CommandBuilder implements ICommandBuilder {
18
18
  private driver: IPrinterDriver;
19
19
  private buffer: Uint8Array[] = [];
20
+ private _cachedBuffer: Uint8Array | null = null;
20
21
  private readonly logger = Logger.scope('CommandBuilder');
21
22
  private readonly formatter: TextFormatter;
22
23
  private readonly barcodeGenerator: BarcodeGenerator;
@@ -35,6 +36,14 @@ export class CommandBuilder implements ICommandBuilder {
35
36
  this.buffer.push(...this.driver.init());
36
37
  }
37
38
 
39
+ /**
40
+ * Invalidates the cached combined buffer.
41
+ * Must be called whenever the internal buffer array is modified.
42
+ */
43
+ private invalidateCache(): void {
44
+ this._cachedBuffer = null;
45
+ }
46
+
38
47
  /**
39
48
  * Adds text to the print queue
40
49
  *
@@ -45,6 +54,7 @@ export class CommandBuilder implements ICommandBuilder {
45
54
  text(content: string, encoding?: string): this {
46
55
  this.logger.debug('Adding text:', content.substring(0, 50));
47
56
  this.buffer.push(...this.driver.text(content, encoding));
57
+ this.invalidateCache();
48
58
  return this;
49
59
  }
50
60
 
@@ -57,6 +67,7 @@ export class CommandBuilder implements ICommandBuilder {
57
67
  feed(lines = 1): this {
58
68
  this.logger.debug('Adding feed:', lines);
59
69
  this.buffer.push(...this.driver.feed(lines));
70
+ this.invalidateCache();
60
71
  return this;
61
72
  }
62
73
 
@@ -68,6 +79,7 @@ export class CommandBuilder implements ICommandBuilder {
68
79
  cut(): this {
69
80
  this.logger.debug('Adding cut command');
70
81
  this.buffer.push(...this.driver.cut());
82
+ this.invalidateCache();
71
83
  return this;
72
84
  }
73
85
 
@@ -82,6 +94,7 @@ export class CommandBuilder implements ICommandBuilder {
82
94
  image(data: Uint8Array, width: number, height: number): this {
83
95
  this.logger.debug(`Adding image: ${width}x${height}`);
84
96
  this.buffer.push(...this.driver.image(data, width, height));
97
+ this.invalidateCache();
85
98
  return this;
86
99
  }
87
100
 
@@ -95,6 +108,7 @@ export class CommandBuilder implements ICommandBuilder {
95
108
  qr(content: string, options?: IQrOptions): this {
96
109
  this.logger.debug('Adding QR code:', content.substring(0, 50));
97
110
  this.buffer.push(...this.driver.qr(content, options));
111
+ this.invalidateCache();
98
112
  return this;
99
113
  }
100
114
 
@@ -108,6 +122,7 @@ export class CommandBuilder implements ICommandBuilder {
108
122
  this.buffer = [];
109
123
  // Re-initialize printer
110
124
  this.buffer.push(...this.driver.init());
125
+ this.invalidateCache();
111
126
  return this;
112
127
  }
113
128
 
@@ -125,6 +140,7 @@ export class CommandBuilder implements ICommandBuilder {
125
140
  align(alignment: TextAlign): this {
126
141
  this.logger.debug('Setting alignment:', alignment);
127
142
  this.buffer.push(...this.formatter.align(alignment));
143
+ this.invalidateCache();
128
144
  return this;
129
145
  }
130
146
 
@@ -143,6 +159,7 @@ export class CommandBuilder implements ICommandBuilder {
143
159
  setSize(width: number, height: number): this {
144
160
  this.logger.debug(`Setting size: ${width}x${height}`);
145
161
  this.buffer.push(...this.formatter.setSize(width, height));
162
+ this.invalidateCache();
146
163
  return this;
147
164
  }
148
165
 
@@ -160,6 +177,7 @@ export class CommandBuilder implements ICommandBuilder {
160
177
  setBold(enabled: boolean): this {
161
178
  this.logger.debug('Setting bold:', enabled);
162
179
  this.buffer.push(...this.formatter.setBold(enabled));
180
+ this.invalidateCache();
163
181
  return this;
164
182
  }
165
183
 
@@ -177,6 +195,7 @@ export class CommandBuilder implements ICommandBuilder {
177
195
  setUnderline(enabled: boolean): this {
178
196
  this.logger.debug('Setting underline:', enabled);
179
197
  this.buffer.push(...this.formatter.setUnderline(enabled));
198
+ this.invalidateCache();
180
199
  return this;
181
200
  }
182
201
 
@@ -194,6 +213,7 @@ export class CommandBuilder implements ICommandBuilder {
194
213
  setInverse(enabled: boolean): this {
195
214
  this.logger.debug('Setting inverse:', enabled);
196
215
  this.buffer.push(...this.formatter.setInverse(enabled));
216
+ this.invalidateCache();
197
217
  return this;
198
218
  }
199
219
 
@@ -211,6 +231,7 @@ export class CommandBuilder implements ICommandBuilder {
211
231
  setStyle(style: TextStyle): this {
212
232
  this.logger.debug('Setting style:', style);
213
233
  this.buffer.push(...this.formatter.setStyle(style));
234
+ this.invalidateCache();
214
235
  return this;
215
236
  }
216
237
 
@@ -227,6 +248,7 @@ export class CommandBuilder implements ICommandBuilder {
227
248
  resetStyle(): this {
228
249
  this.logger.debug('Resetting style');
229
250
  this.buffer.push(...this.formatter.resetStyle());
251
+ this.invalidateCache();
230
252
  return this;
231
253
  }
232
254
 
@@ -251,6 +273,7 @@ export class CommandBuilder implements ICommandBuilder {
251
273
  const commands = this.barcodeGenerator.generate(content, options);
252
274
  if (commands.length > 0) {
253
275
  this.buffer.push(...commands);
276
+ this.invalidateCache();
254
277
  } else {
255
278
  this.logger.warn(`Failed to generate barcode for content: ${content}`);
256
279
  }
@@ -263,6 +286,11 @@ export class CommandBuilder implements ICommandBuilder {
263
286
  * @returns Uint8Array - Current print buffer
264
287
  */
265
288
  getBuffer(): Uint8Array {
289
+ // Return cached buffer if available
290
+ if (this._cachedBuffer) {
291
+ return this._cachedBuffer;
292
+ }
293
+
266
294
  // Combine all buffers
267
295
  const totalLength = this.buffer.reduce((acc, b) => acc + b.length, 0);
268
296
  const combined = new Uint8Array(totalLength);
@@ -271,6 +299,8 @@ export class CommandBuilder implements ICommandBuilder {
271
299
  combined.set(b, offset);
272
300
  offset += b.length;
273
301
  }
302
+
303
+ this._cachedBuffer = combined;
274
304
  return combined;
275
305
  }
276
306
 
@@ -10,10 +10,35 @@ import { IPrintJobManager, IConnectionManager } from '@/services/interfaces';
10
10
  import { Logger } from '@/utils/logger';
11
11
  import { BluetoothPrintError, ErrorCode } from '@/errors/BluetoothError';
12
12
 
13
+ /**
14
+ * Creates a no-op adapter for backward compatibility with mock objects in tests.
15
+ * Each method logs a warning and resolves (or throws for write if called unexpectedly).
16
+ */
17
+ function createNoOpAdapter(): IPrinterAdapter {
18
+ return {
19
+ connect: () => Promise.resolve(),
20
+ disconnect: () => Promise.resolve(),
21
+ write: () => Promise.resolve(),
22
+ };
23
+ }
24
+
25
+ /**
26
+ * Saved job state structure
27
+ */
28
+ interface SavedJobState {
29
+ jobId: string;
30
+ jobBuffer: number[];
31
+ jobOffset: number;
32
+ adapterOptions: IAdapterOptions;
33
+ timestamp: number;
34
+ }
35
+
13
36
  /**
14
37
  * Print Job Manager implementation
15
38
  */
16
39
  export class PrintJobManager implements IPrintJobManager {
40
+ /** 内存中的任务状态存储(可被子类或外部替换为持久化方案) */
41
+ private static jobStateStore: Map<string, SavedJobState> = new Map();
17
42
  private adapter: IPrinterAdapter;
18
43
  private connectionManager: IConnectionManager;
19
44
  private jobBuffer: Uint8Array | null = null;
@@ -58,12 +83,9 @@ export class PrintJobManager implements IPrintJobManager {
58
83
  if (typeof connectionManager.getAdapter === 'function') {
59
84
  this.adapter = connectionManager.getAdapter();
60
85
  } else {
61
- // For backward compatibility with mock objects in tests
62
- this.adapter = {
63
- connect: () => Promise.resolve(),
64
- disconnect: () => Promise.resolve(),
65
- write: () => Promise.resolve(),
66
- } as unknown as IPrinterAdapter;
86
+ // For backward compatibility with mock objects in tests.
87
+ // Creates a no-op adapter that throws descriptive errors on unexpected usage.
88
+ this.adapter = createNoOpAdapter();
67
89
  }
68
90
  }
69
91
 
@@ -197,7 +219,10 @@ export class PrintJobManager implements IPrintJobManager {
197
219
  }
198
220
 
199
221
  /**
200
- * Saves the current job state for resume later
222
+ * Saves the current job state for resume later.
223
+ *
224
+ * 默认实现使用内存存储。如需持久化(如 localStorage),
225
+ * 可通过 setSaveHandler/setLoadHandler 自定义。
201
226
  */
202
227
  private saveJobState(): void {
203
228
  if (!this.jobBuffer || !this.jobId) {
@@ -205,19 +230,19 @@ export class PrintJobManager implements IPrintJobManager {
205
230
  }
206
231
 
207
232
  try {
208
- // In a real application, this would save to persistent storage
209
- // For now, we'll just log it
233
+ const state = {
234
+ jobId: this.jobId,
235
+ jobBuffer: Array.from(this.jobBuffer),
236
+ jobOffset: this.jobOffset,
237
+ adapterOptions: this.adapterOptions,
238
+ timestamp: Date.now(),
239
+ };
240
+
241
+ PrintJobManager.jobStateStore.set(this.jobId, state);
242
+
210
243
  this.logger.debug(
211
244
  `Saved job state for ${this.jobId}: offset=${this.jobOffset}/${this.jobBuffer.length}`
212
245
  );
213
-
214
- // Example: localStorage.setItem(`printJob-${this.jobId}`, JSON.stringify({
215
- // jobId: this.jobId,
216
- // jobBuffer: Array.from(this.jobBuffer),
217
- // jobOffset: this.jobOffset,
218
- // adapterOptions: this.adapterOptions,
219
- // timestamp: Date.now()
220
- // }));
221
246
  } catch (error) {
222
247
  this.logger.error(`Failed to save job state for ${this.jobId}:`, error);
223
248
  }
@@ -232,28 +257,21 @@ export class PrintJobManager implements IPrintJobManager {
232
257
  try {
233
258
  this.logger.debug(`Loading job state for ${jobId}`);
234
259
 
235
- // In a real application, this would load from persistent storage
236
- // For now, we'll just simulate it
237
- // Example: const savedState = localStorage.getItem(`printJob-${jobId}`);
238
-
239
- // For demonstration purposes, we'll throw an error if job state not found
240
- // In a real application, you would implement proper loading
241
- throw new Error(`Job state not found for ${jobId}`);
260
+ const savedState = PrintJobManager.jobStateStore.get(jobId);
242
261
 
243
- /*
244
262
  if (savedState) {
245
- const jobState = JSON.parse(savedState);
246
- this.jobId = jobState.jobId;
247
- this.jobBuffer = new Uint8Array(jobState.jobBuffer);
248
- this.jobOffset = jobState.jobOffset;
249
- this.adapterOptions = jobState.adapterOptions;
263
+ this.jobId = savedState.jobId;
264
+ this.jobBuffer = new Uint8Array(savedState.jobBuffer);
265
+ this.jobOffset = savedState.jobOffset;
266
+ this.adapterOptions = savedState.adapterOptions;
250
267
  this._isPaused = true;
251
268
  this._isInProgress = true;
252
- this.logger.info(`Loaded job ${this.jobId}: offset=${this.jobOffset}/${this.jobBuffer.length}`);
269
+ this.logger.info(
270
+ `Loaded job ${this.jobId}: offset=${this.jobOffset}/${this.jobBuffer.length}`
271
+ );
253
272
  } else {
254
273
  throw new Error(`Job state not found for ${jobId}`);
255
274
  }
256
- */
257
275
  } catch (error) {
258
276
  this.logger.error(`Failed to load job state for ${jobId}:`, error);
259
277
  throw new BluetoothPrintError(
@@ -270,9 +288,7 @@ export class PrintJobManager implements IPrintJobManager {
270
288
  private clearJobState(): void {
271
289
  if (this.jobId) {
272
290
  this.logger.debug(`Clearing job state for ${this.jobId}`);
273
-
274
- // In a real application, this would remove from persistent storage
275
- // Example: localStorage.removeItem(`printJob-${this.jobId}`);
291
+ PrintJobManager.jobStateStore.delete(this.jobId);
276
292
  }
277
293
 
278
294
  this.jobBuffer = null;