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.
- package/CHANGELOG.md +38 -0
- package/README.md +128 -22
- package/dist/index.cjs.js +1 -1
- package/dist/index.es.js +1 -6995
- package/dist/index.umd.js +1 -1
- package/dist/types/adapters/AdapterFactory.d.ts +0 -1
- package/dist/types/adapters/AlipayAdapter.d.ts +6 -34
- package/dist/types/adapters/BaiduAdapter.d.ts +6 -34
- package/dist/types/adapters/BaseAdapter.d.ts +112 -1
- package/dist/types/adapters/ByteDanceAdapter.d.ts +6 -34
- package/dist/types/adapters/TaroAdapter.d.ts +6 -34
- package/dist/types/adapters/WebBluetoothAdapter.d.ts +0 -1
- package/dist/types/config/PrinterConfig.d.ts +0 -1
- package/dist/types/core/BluetoothPrinter.d.ts +0 -1
- package/dist/types/drivers/EscPos.d.ts +0 -1
- package/dist/types/drivers/TsplDriver.d.ts +251 -0
- package/dist/types/encoding/gbk-data.d.ts +12 -0
- package/dist/types/encoding/gbk-table.d.ts +5 -1
- package/dist/types/index.d.ts +5 -0
- package/dist/types/plugins/PluginManager.d.ts +87 -0
- package/dist/types/plugins/builtin/LoggingPlugin.d.ts +14 -0
- package/dist/types/plugins/builtin/RetryPlugin.d.ts +18 -0
- package/dist/types/plugins/index.d.ts +7 -0
- package/dist/types/plugins/types.d.ts +97 -0
- package/dist/types/services/CommandBuilder.d.ts +6 -1
- package/dist/types/services/ConnectionManager.d.ts +0 -1
- package/dist/types/services/PrintJobManager.d.ts +6 -2
- package/dist/types/services/interfaces/index.d.ts +0 -1
- package/dist/types/template/TemplateEngine.d.ts +0 -1
- package/package.json +16 -18
- package/src/adapters/AlipayAdapter.ts +8 -314
- package/src/adapters/BaiduAdapter.ts +8 -312
- package/src/adapters/BaseAdapter.ts +366 -0
- package/src/adapters/ByteDanceAdapter.ts +8 -316
- package/src/adapters/TaroAdapter.ts +8 -367
- package/src/core/EventEmitter.ts +9 -6
- package/src/drivers/TsplDriver.ts +417 -0
- package/src/encoding/gbk-data.ts +1911 -0
- package/src/encoding/gbk-table.ts +22 -498
- package/src/index.ts +14 -0
- package/src/plugins/PluginManager.ts +193 -0
- package/src/plugins/builtin/LoggingPlugin.ts +97 -0
- package/src/plugins/builtin/RetryPlugin.ts +109 -0
- package/src/plugins/index.ts +10 -0
- package/src/plugins/types.ts +119 -0
- package/src/preview/PreviewRenderer.ts +7 -1
- package/src/queue/PrintQueue.ts +10 -6
- package/src/services/CommandBuilder.ts +30 -0
- package/src/services/PrintJobManager.ts +51 -35
|
@@ -3,77 +3,19 @@
|
|
|
3
3
|
* Implements the IPrinterAdapter interface for ByteDance Mini Program
|
|
4
4
|
*/
|
|
5
5
|
|
|
6
|
-
import {
|
|
7
|
-
import { BaseAdapter } from './BaseAdapter';
|
|
8
|
-
import { BluetoothPrintError, ErrorCode } from '@/errors/BluetoothError';
|
|
6
|
+
import { MiniProgramAdapter, MiniProgramBLEApi } from './BaseAdapter';
|
|
9
7
|
|
|
10
8
|
// Declare ByteDance global for TypeScript
|
|
11
|
-
interface
|
|
12
|
-
uuid: string;
|
|
13
|
-
}
|
|
14
|
-
|
|
15
|
-
interface ByteDanceBLECharacteristicProperties {
|
|
16
|
-
write?: boolean;
|
|
17
|
-
writeWithoutResponse?: boolean;
|
|
18
|
-
read?: boolean;
|
|
19
|
-
notify?: boolean;
|
|
20
|
-
indicate?: boolean;
|
|
21
|
-
}
|
|
22
|
-
|
|
23
|
-
interface ByteDanceBLECharacteristic {
|
|
24
|
-
uuid: string;
|
|
25
|
-
properties: ByteDanceBLECharacteristicProperties;
|
|
26
|
-
}
|
|
27
|
-
|
|
28
|
-
interface ByteDanceBLEDeviceServicesResult {
|
|
29
|
-
services: ByteDanceBLEService[];
|
|
30
|
-
}
|
|
31
|
-
|
|
32
|
-
interface ByteDanceBLEDeviceCharacteristicsResult {
|
|
33
|
-
characteristics: ByteDanceBLECharacteristic[];
|
|
34
|
-
}
|
|
35
|
-
|
|
36
|
-
interface ByteDanceBLEConnectionStateResult {
|
|
37
|
-
connected: boolean;
|
|
38
|
-
}
|
|
39
|
-
|
|
40
|
-
interface ByteDanceBLEConnectionOptions {
|
|
41
|
-
deviceId: string;
|
|
42
|
-
}
|
|
43
|
-
|
|
44
|
-
interface ByteDanceBLEWriteOptions {
|
|
45
|
-
deviceId: string;
|
|
46
|
-
serviceId: string;
|
|
47
|
-
characteristicId: string;
|
|
48
|
-
value: ArrayBuffer;
|
|
49
|
-
}
|
|
50
|
-
|
|
51
|
-
interface ByteDanceBLEConnectionStateChangeCallback {
|
|
52
|
-
(res: { deviceId: string; connected: boolean }): void;
|
|
53
|
-
}
|
|
54
|
-
|
|
55
|
-
interface ByteDanceGlobal {
|
|
56
|
-
createBLEConnection(options: ByteDanceBLEConnectionOptions): Promise<void>;
|
|
57
|
-
closeBLEConnection(options: ByteDanceBLEConnectionOptions): Promise<void>;
|
|
58
|
-
getBLEConnectionState(
|
|
59
|
-
options: ByteDanceBLEConnectionOptions
|
|
60
|
-
): Promise<ByteDanceBLEConnectionStateResult>;
|
|
61
|
-
writeBLECharacteristicValue(options: ByteDanceBLEWriteOptions): Promise<void>;
|
|
62
|
-
getBLEDeviceServices(
|
|
63
|
-
options: ByteDanceBLEConnectionOptions
|
|
64
|
-
): Promise<ByteDanceBLEDeviceServicesResult>;
|
|
65
|
-
getBLEDeviceCharacteristics(options: {
|
|
66
|
-
deviceId: string;
|
|
67
|
-
serviceId: string;
|
|
68
|
-
}): Promise<ByteDanceBLEDeviceCharacteristicsResult>;
|
|
69
|
-
onBLEConnectionStateChange(callback: ByteDanceBLEConnectionStateChangeCallback): void;
|
|
70
|
-
}
|
|
9
|
+
interface ByteDanceGlobal extends MiniProgramBLEApi {}
|
|
71
10
|
|
|
72
11
|
declare const tt: ByteDanceGlobal;
|
|
73
12
|
|
|
74
13
|
/**
|
|
75
14
|
* ByteDance Bluetooth Low Energy adapter
|
|
76
15
|
*
|
|
16
|
+
* Uses the ByteDance mini-program's BLE APIs (tt.xxx, for Douyin/TikTok etc).
|
|
17
|
+
* All connection, write, and service discovery logic is inherited from MiniProgramAdapter.
|
|
18
|
+
*
|
|
77
19
|
* @example
|
|
78
20
|
* ```typescript
|
|
79
21
|
* const adapter = new ByteDanceAdapter();
|
|
@@ -82,258 +24,8 @@ declare const tt: ByteDanceGlobal;
|
|
|
82
24
|
* await adapter.disconnect('device-id-123');
|
|
83
25
|
* ```
|
|
84
26
|
*/
|
|
85
|
-
export class ByteDanceAdapter extends
|
|
86
|
-
|
|
87
|
-
|
|
88
|
-
*
|
|
89
|
-
* @param deviceId - Bluetooth device ID
|
|
90
|
-
* @throws {BluetoothPrintError} When connection fails
|
|
91
|
-
*/
|
|
92
|
-
async connect(deviceId: string): Promise<void> {
|
|
93
|
-
this.validateDeviceId(deviceId);
|
|
94
|
-
|
|
95
|
-
// Check if already connected
|
|
96
|
-
if (this.isDeviceConnected(deviceId)) {
|
|
97
|
-
this.logger.warn('Device already connected:', deviceId);
|
|
98
|
-
this.updateState(PrinterState.CONNECTED);
|
|
99
|
-
return;
|
|
100
|
-
}
|
|
101
|
-
|
|
102
|
-
this.updateState(PrinterState.CONNECTING);
|
|
103
|
-
this.logger.debug('Connecting to device:', deviceId);
|
|
104
|
-
|
|
105
|
-
try {
|
|
106
|
-
// Add connection timeout handling
|
|
107
|
-
let timeoutId: NodeJS.Timeout | undefined;
|
|
108
|
-
const connectionPromise = tt.createBLEConnection({
|
|
109
|
-
deviceId,
|
|
110
|
-
});
|
|
111
|
-
|
|
112
|
-
const timeoutPromise = new Promise((_, reject) => {
|
|
113
|
-
timeoutId = setTimeout(() => {
|
|
114
|
-
reject(new Error('Connection timeout after 10 seconds'));
|
|
115
|
-
}, 10000);
|
|
116
|
-
});
|
|
117
|
-
|
|
118
|
-
await Promise.race([connectionPromise, timeoutPromise]);
|
|
119
|
-
if (timeoutId) {
|
|
120
|
-
clearTimeout(timeoutId); // Clear timeout after successful connection
|
|
121
|
-
}
|
|
122
|
-
this.logger.info('BLE connection established');
|
|
123
|
-
|
|
124
|
-
// Discover and cache services
|
|
125
|
-
await this.discoverServices(deviceId);
|
|
126
|
-
|
|
127
|
-
this.updateState(PrinterState.CONNECTED);
|
|
128
|
-
this.logger.info('Device connected successfully');
|
|
129
|
-
|
|
130
|
-
// Listen for connection state changes
|
|
131
|
-
tt.onBLEConnectionStateChange((res: { deviceId: string; connected: boolean }) => {
|
|
132
|
-
if (res.deviceId === deviceId && !res.connected) {
|
|
133
|
-
this.logger.warn('Device disconnected unexpectedly');
|
|
134
|
-
this.updateState(PrinterState.DISCONNECTED);
|
|
135
|
-
this.cleanupDevice(deviceId);
|
|
136
|
-
}
|
|
137
|
-
});
|
|
138
|
-
} catch (error) {
|
|
139
|
-
this.updateState(PrinterState.DISCONNECTED);
|
|
140
|
-
this.logger.error('Connection failed:', error);
|
|
141
|
-
|
|
142
|
-
// Return more specific error codes based on error message
|
|
143
|
-
const errorMessage = (error as Error).message || '';
|
|
144
|
-
if (errorMessage.includes('timeout')) {
|
|
145
|
-
throw new BluetoothPrintError(
|
|
146
|
-
ErrorCode.CONNECTION_TIMEOUT,
|
|
147
|
-
`Connection to device ${deviceId} timed out`,
|
|
148
|
-
error as Error
|
|
149
|
-
);
|
|
150
|
-
} else if (errorMessage.includes('not found')) {
|
|
151
|
-
throw new BluetoothPrintError(
|
|
152
|
-
ErrorCode.DEVICE_NOT_FOUND,
|
|
153
|
-
`Device ${deviceId} not found`,
|
|
154
|
-
error as Error
|
|
155
|
-
);
|
|
156
|
-
}
|
|
157
|
-
|
|
158
|
-
throw new BluetoothPrintError(
|
|
159
|
-
ErrorCode.CONNECTION_FAILED,
|
|
160
|
-
`Failed to connect to device ${deviceId}`,
|
|
161
|
-
error as Error
|
|
162
|
-
);
|
|
163
|
-
}
|
|
164
|
-
}
|
|
165
|
-
|
|
166
|
-
/**
|
|
167
|
-
* Disconnects from a Bluetooth device
|
|
168
|
-
*
|
|
169
|
-
* @param deviceId - Bluetooth device ID
|
|
170
|
-
*/
|
|
171
|
-
async disconnect(deviceId: string): Promise<void> {
|
|
172
|
-
this.validateDeviceId(deviceId);
|
|
173
|
-
this.updateState(PrinterState.DISCONNECTING);
|
|
174
|
-
this.logger.debug('Disconnecting from device:', deviceId);
|
|
175
|
-
|
|
176
|
-
try {
|
|
177
|
-
await tt.closeBLEConnection({
|
|
178
|
-
deviceId,
|
|
179
|
-
});
|
|
180
|
-
this.cleanupDevice(deviceId);
|
|
181
|
-
this.updateState(PrinterState.DISCONNECTED);
|
|
182
|
-
this.logger.info('Device disconnected successfully');
|
|
183
|
-
} catch (error) {
|
|
184
|
-
// Ignore error on disconnect, but log it
|
|
185
|
-
this.logger.warn('Disconnect error (ignored):', error);
|
|
186
|
-
this.cleanupDevice(deviceId);
|
|
187
|
-
this.updateState(PrinterState.DISCONNECTED);
|
|
188
|
-
}
|
|
189
|
-
}
|
|
190
|
-
|
|
191
|
-
/**
|
|
192
|
-
* Writes data to the Bluetooth device in chunks with retry logic
|
|
193
|
-
*
|
|
194
|
-
* @param deviceId - Bluetooth device ID
|
|
195
|
-
* @param buffer - Data to write as ArrayBuffer
|
|
196
|
-
* @param options - Write options (chunk size, delay, retries)
|
|
197
|
-
* @throws {BluetoothPrintError} When write fails after retries
|
|
198
|
-
*/
|
|
199
|
-
async write(deviceId: string, buffer: ArrayBuffer, options?: IAdapterOptions): Promise<void> {
|
|
200
|
-
this.validateDeviceId(deviceId);
|
|
201
|
-
this.validateBuffer(buffer);
|
|
202
|
-
const serviceInfo = this.getServiceInfo(deviceId);
|
|
203
|
-
const validatedOptions = this.validateOptions(options);
|
|
204
|
-
|
|
205
|
-
// Validate device is still connected
|
|
206
|
-
try {
|
|
207
|
-
const state = await tt.getBLEConnectionState({
|
|
208
|
-
deviceId,
|
|
209
|
-
});
|
|
210
|
-
if (!state.connected) {
|
|
211
|
-
this.cleanupDevice(deviceId);
|
|
212
|
-
throw new BluetoothPrintError(ErrorCode.DEVICE_DISCONNECTED, 'Device disconnected');
|
|
213
|
-
}
|
|
214
|
-
} catch (error) {
|
|
215
|
-
this.cleanupDevice(deviceId);
|
|
216
|
-
throw new BluetoothPrintError(
|
|
217
|
-
ErrorCode.DEVICE_DISCONNECTED,
|
|
218
|
-
'Device disconnected',
|
|
219
|
-
error as Error
|
|
220
|
-
);
|
|
221
|
-
}
|
|
222
|
-
|
|
223
|
-
const { chunkSize, delay, retries } = validatedOptions;
|
|
224
|
-
const data = new Uint8Array(buffer);
|
|
225
|
-
const totalChunks = Math.ceil(data.length / chunkSize);
|
|
226
|
-
|
|
227
|
-
this.logger.debug(`Writing ${data.length} bytes in ${totalChunks} chunks`);
|
|
228
|
-
|
|
229
|
-
// If no data to write, return directly
|
|
230
|
-
if (data.length === 0) {
|
|
231
|
-
this.logger.warn('No data to write');
|
|
232
|
-
return;
|
|
233
|
-
}
|
|
234
|
-
|
|
235
|
-
for (let i = 0; i < data.length; i += chunkSize) {
|
|
236
|
-
const chunk = data.slice(i, i + chunkSize);
|
|
237
|
-
const chunkNum = Math.floor(i / chunkSize) + 1;
|
|
238
|
-
|
|
239
|
-
let attempt = 0;
|
|
240
|
-
while (attempt <= retries) {
|
|
241
|
-
try {
|
|
242
|
-
// Add write timeout handling
|
|
243
|
-
const writePromise = tt.writeBLECharacteristicValue({
|
|
244
|
-
deviceId,
|
|
245
|
-
serviceId: serviceInfo.serviceId,
|
|
246
|
-
characteristicId: serviceInfo.characteristicId,
|
|
247
|
-
value: chunk.buffer,
|
|
248
|
-
});
|
|
249
|
-
|
|
250
|
-
const timeoutPromise = new Promise((_, reject) => {
|
|
251
|
-
setTimeout(() => {
|
|
252
|
-
reject(new Error('Write timeout after 5 seconds'));
|
|
253
|
-
}, 5000);
|
|
254
|
-
});
|
|
255
|
-
|
|
256
|
-
await Promise.race([writePromise, timeoutPromise]);
|
|
257
|
-
|
|
258
|
-
this.logger.debug(`Chunk ${chunkNum}/${totalChunks} written successfully`);
|
|
259
|
-
break; // Success
|
|
260
|
-
} catch (error) {
|
|
261
|
-
attempt++;
|
|
262
|
-
if (attempt > retries) {
|
|
263
|
-
this.logger.error(`Chunk ${chunkNum} failed after ${retries} retries`);
|
|
264
|
-
throw new BluetoothPrintError(
|
|
265
|
-
ErrorCode.WRITE_FAILED,
|
|
266
|
-
`Failed to write chunk ${chunkNum}/${totalChunks}`,
|
|
267
|
-
error as Error
|
|
268
|
-
);
|
|
269
|
-
}
|
|
270
|
-
this.logger.warn(`Chunk ${chunkNum} write failed, retry ${attempt}/${retries}`);
|
|
271
|
-
// Wait before retry
|
|
272
|
-
await new Promise(r => setTimeout(r, delay * 2));
|
|
273
|
-
}
|
|
274
|
-
}
|
|
275
|
-
|
|
276
|
-
// Small delay to prevent congestion
|
|
277
|
-
if (i + chunkSize < data.length) {
|
|
278
|
-
await new Promise(r => setTimeout(r, delay));
|
|
279
|
-
}
|
|
280
|
-
}
|
|
281
|
-
|
|
282
|
-
this.logger.info(`Successfully wrote ${data.length} bytes`);
|
|
283
|
-
}
|
|
284
|
-
|
|
285
|
-
/**
|
|
286
|
-
* Discovers services and characteristics for a device
|
|
287
|
-
* Caches the writeable characteristic for future writes
|
|
288
|
-
*
|
|
289
|
-
* @param deviceId - Bluetooth device ID
|
|
290
|
-
* @throws {BluetoothPrintError} When no writeable characteristic is found
|
|
291
|
-
*/
|
|
292
|
-
private async discoverServices(deviceId: string): Promise<void> {
|
|
293
|
-
this.logger.debug('Discovering services for device:', deviceId);
|
|
294
|
-
|
|
295
|
-
try {
|
|
296
|
-
const services = await tt.getBLEDeviceServices({
|
|
297
|
-
deviceId,
|
|
298
|
-
});
|
|
299
|
-
|
|
300
|
-
for (const service of services.services) {
|
|
301
|
-
const chars = await tt.getBLEDeviceCharacteristics({
|
|
302
|
-
deviceId,
|
|
303
|
-
serviceId: service.uuid,
|
|
304
|
-
});
|
|
305
|
-
|
|
306
|
-
const writeChar = chars.characteristics.find(
|
|
307
|
-
(c: ByteDanceBLECharacteristic) => c.properties.write || c.properties.writeWithoutResponse
|
|
308
|
-
);
|
|
309
|
-
|
|
310
|
-
if (writeChar) {
|
|
311
|
-
this.serviceCache.set(deviceId, {
|
|
312
|
-
serviceId: service.uuid,
|
|
313
|
-
characteristicId: writeChar.uuid,
|
|
314
|
-
});
|
|
315
|
-
this.logger.info('Found writeable characteristic:', {
|
|
316
|
-
service: service.uuid,
|
|
317
|
-
characteristic: writeChar.uuid,
|
|
318
|
-
});
|
|
319
|
-
return;
|
|
320
|
-
}
|
|
321
|
-
}
|
|
322
|
-
|
|
323
|
-
// No writeable characteristic found
|
|
324
|
-
throw new BluetoothPrintError(
|
|
325
|
-
ErrorCode.CHARACTERISTIC_NOT_FOUND,
|
|
326
|
-
'No writeable characteristic found. Make sure the device is a supported printer.'
|
|
327
|
-
);
|
|
328
|
-
} catch (error) {
|
|
329
|
-
if (error instanceof BluetoothPrintError) {
|
|
330
|
-
throw error;
|
|
331
|
-
}
|
|
332
|
-
throw new BluetoothPrintError(
|
|
333
|
-
ErrorCode.SERVICE_DISCOVERY_FAILED,
|
|
334
|
-
'Failed to discover device services',
|
|
335
|
-
error as Error
|
|
336
|
-
);
|
|
337
|
-
}
|
|
27
|
+
export class ByteDanceAdapter extends MiniProgramAdapter {
|
|
28
|
+
protected getApi(): MiniProgramBLEApi {
|
|
29
|
+
return tt;
|
|
338
30
|
}
|
|
339
31
|
}
|