@dg-kit/protocol 1.6.1 → 1.7.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.
@@ -0,0 +1,36 @@
1
+ /**
2
+ * Retry helper for the "GATT services not visible yet" race that hits every
3
+ * BLE transport this library supports, not just Tauri/Android: the
4
+ * underlying platform's `connect()` (Web Bluetooth's `gatt.connect()`,
5
+ * plugin-blec's `connect()` on Android, ...) can resolve before service
6
+ * discovery is guaranteed complete. The first `getPrimaryService()` /
7
+ * subscribe call inside a protocol adapter's `onConnected()` then fails
8
+ * with "No services matching UUID ..." even though the device genuinely
9
+ * has that service — it just hasn't been indexed by the platform's GATT
10
+ * cache yet, most commonly on a first-time pairing.
11
+ *
12
+ * Every protocol adapter resets its own state on a failed `onConnected()`,
13
+ * so retrying it is always safe.
14
+ */
15
+ export interface GattReadyRetryOptions {
16
+ /**
17
+ * Grace period after the transport's own `connect()` resolves, before the
18
+ * first `onConnected()` attempt. Defaults to 300ms.
19
+ */
20
+ gattReadyInitialDelayMs?: number;
21
+ /** Total budget for retrying after the first attempt fails. Defaults to 3000ms. */
22
+ gattReadyTimeoutMs?: number;
23
+ /** Delay between retry attempts. Defaults to 250ms. */
24
+ gattReadyIntervalMs?: number;
25
+ /**
26
+ * Substrings (case-insensitive) that identify a transient GATT-not-ready
27
+ * error, as opposed to a real failure worth surfacing immediately.
28
+ */
29
+ gattReadyErrorPatterns?: string[];
30
+ }
31
+ export declare const DEFAULT_GATT_READY_INITIAL_DELAY_MS = 300;
32
+ export declare const DEFAULT_GATT_READY_TIMEOUT_MS = 3000;
33
+ export declare const DEFAULT_GATT_READY_INTERVAL_MS = 250;
34
+ export declare const DEFAULT_GATT_READY_ERROR_PATTERNS: string[];
35
+ export declare function runWithGattReadyRetry(attempt: () => Promise<void>, options: GattReadyRetryOptions): Promise<void>;
36
+ //# sourceMappingURL=gatt-ready.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"gatt-ready.d.ts","sourceRoot":"","sources":["../src/gatt-ready.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;GAaG;AACH,MAAM,WAAW,qBAAqB;IACpC;;;OAGG;IACH,uBAAuB,CAAC,EAAE,MAAM,CAAC;IACjC,mFAAmF;IACnF,kBAAkB,CAAC,EAAE,MAAM,CAAC;IAC5B,uDAAuD;IACvD,mBAAmB,CAAC,EAAE,MAAM,CAAC;IAC7B;;;OAGG;IACH,sBAAsB,CAAC,EAAE,MAAM,EAAE,CAAC;CACnC;AAED,eAAO,MAAM,mCAAmC,MAAM,CAAC;AACvD,eAAO,MAAM,6BAA6B,OAAO,CAAC;AAClD,eAAO,MAAM,8BAA8B,MAAM,CAAC;AAClD,eAAO,MAAM,iCAAiC,UAO7C,CAAC;AAEF,wBAAsB,qBAAqB,CACzC,OAAO,EAAE,MAAM,OAAO,CAAC,IAAI,CAAC,EAC5B,OAAO,EAAE,qBAAqB,GAC7B,OAAO,CAAC,IAAI,CAAC,CAuBf"}
@@ -0,0 +1,46 @@
1
+ export const DEFAULT_GATT_READY_INITIAL_DELAY_MS = 300;
2
+ export const DEFAULT_GATT_READY_TIMEOUT_MS = 3000;
3
+ export const DEFAULT_GATT_READY_INTERVAL_MS = 250;
4
+ export const DEFAULT_GATT_READY_ERROR_PATTERNS = [
5
+ 'no services matching',
6
+ 'service not found',
7
+ 'no such service',
8
+ 'characteristic not found',
9
+ 'no such characteristic',
10
+ 'not connected',
11
+ ];
12
+ export async function runWithGattReadyRetry(attempt, options) {
13
+ const initialDelay = options.gattReadyInitialDelayMs ?? DEFAULT_GATT_READY_INITIAL_DELAY_MS;
14
+ const totalTimeout = options.gattReadyTimeoutMs ?? DEFAULT_GATT_READY_TIMEOUT_MS;
15
+ const interval = options.gattReadyIntervalMs ?? DEFAULT_GATT_READY_INTERVAL_MS;
16
+ const patterns = options.gattReadyErrorPatterns ?? DEFAULT_GATT_READY_ERROR_PATTERNS;
17
+ if (initialDelay > 0)
18
+ await delay(initialDelay);
19
+ const deadline = Date.now() + Math.max(0, totalTimeout);
20
+ let lastError;
21
+ // First try after the grace delay; if it works, we're done with one pass.
22
+ while (true) {
23
+ try {
24
+ await attempt();
25
+ return;
26
+ }
27
+ catch (error) {
28
+ lastError = error;
29
+ if (!isGattNotReadyError(error, patterns))
30
+ throw error;
31
+ if (Date.now() >= deadline)
32
+ break;
33
+ await delay(interval);
34
+ }
35
+ }
36
+ throw lastError instanceof Error ? lastError : new Error('GATT 服务发现超时,请重新连接');
37
+ }
38
+ function isGattNotReadyError(error, patterns) {
39
+ const msg = error instanceof Error ? error.message : typeof error === 'string' ? error : String(error);
40
+ const lower = msg.toLowerCase();
41
+ return patterns.some((p) => lower.includes(p.toLowerCase()));
42
+ }
43
+ function delay(ms) {
44
+ return new Promise((resolve) => setTimeout(resolve, ms));
45
+ }
46
+ //# sourceMappingURL=gatt-ready.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"gatt-ready.js","sourceRoot":"","sources":["../src/gatt-ready.ts"],"names":[],"mappings":"AA+BA,MAAM,CAAC,MAAM,mCAAmC,GAAG,GAAG,CAAC;AACvD,MAAM,CAAC,MAAM,6BAA6B,GAAG,IAAI,CAAC;AAClD,MAAM,CAAC,MAAM,8BAA8B,GAAG,GAAG,CAAC;AAClD,MAAM,CAAC,MAAM,iCAAiC,GAAG;IAC/C,sBAAsB;IACtB,mBAAmB;IACnB,iBAAiB;IACjB,0BAA0B;IAC1B,wBAAwB;IACxB,eAAe;CAChB,CAAC;AAEF,MAAM,CAAC,KAAK,UAAU,qBAAqB,CACzC,OAA4B,EAC5B,OAA8B;IAE9B,MAAM,YAAY,GAAG,OAAO,CAAC,uBAAuB,IAAI,mCAAmC,CAAC;IAC5F,MAAM,YAAY,GAAG,OAAO,CAAC,kBAAkB,IAAI,6BAA6B,CAAC;IACjF,MAAM,QAAQ,GAAG,OAAO,CAAC,mBAAmB,IAAI,8BAA8B,CAAC;IAC/E,MAAM,QAAQ,GAAG,OAAO,CAAC,sBAAsB,IAAI,iCAAiC,CAAC;IAErF,IAAI,YAAY,GAAG,CAAC;QAAE,MAAM,KAAK,CAAC,YAAY,CAAC,CAAC;IAEhD,MAAM,QAAQ,GAAG,IAAI,CAAC,GAAG,EAAE,GAAG,IAAI,CAAC,GAAG,CAAC,CAAC,EAAE,YAAY,CAAC,CAAC;IACxD,IAAI,SAAkB,CAAC;IACvB,0EAA0E;IAC1E,OAAO,IAAI,EAAE,CAAC;QACZ,IAAI,CAAC;YACH,MAAM,OAAO,EAAE,CAAC;YAChB,OAAO;QACT,CAAC;QAAC,OAAO,KAAK,EAAE,CAAC;YACf,SAAS,GAAG,KAAK,CAAC;YAClB,IAAI,CAAC,mBAAmB,CAAC,KAAK,EAAE,QAAQ,CAAC;gBAAE,MAAM,KAAK,CAAC;YACvD,IAAI,IAAI,CAAC,GAAG,EAAE,IAAI,QAAQ;gBAAE,MAAM;YAClC,MAAM,KAAK,CAAC,QAAQ,CAAC,CAAC;QACxB,CAAC;IACH,CAAC;IACD,MAAM,SAAS,YAAY,KAAK,CAAC,CAAC,CAAC,SAAS,CAAC,CAAC,CAAC,IAAI,KAAK,CAAC,mBAAmB,CAAC,CAAC;AAChF,CAAC;AAED,SAAS,mBAAmB,CAAC,KAAc,EAAE,QAAkB;IAC7D,MAAM,GAAG,GACP,KAAK,YAAY,KAAK,CAAC,CAAC,CAAC,KAAK,CAAC,OAAO,CAAC,CAAC,CAAC,OAAO,KAAK,KAAK,QAAQ,CAAC,CAAC,CAAC,KAAK,CAAC,CAAC,CAAC,MAAM,CAAC,KAAK,CAAC,CAAC;IAC7F,MAAM,KAAK,GAAG,GAAG,CAAC,WAAW,EAAE,CAAC;IAChC,OAAO,QAAQ,CAAC,IAAI,CAAC,CAAC,CAAC,EAAE,EAAE,CAAC,KAAK,CAAC,QAAQ,CAAC,CAAC,CAAC,WAAW,EAAE,CAAC,CAAC,CAAC;AAC/D,CAAC;AAED,SAAS,KAAK,CAAC,EAAU;IACvB,OAAO,IAAI,OAAO,CAAC,CAAC,OAAO,EAAE,EAAE,CAAC,UAAU,CAAC,OAAO,EAAE,EAAE,CAAC,CAAC,CAAC;AAC3D,CAAC"}
package/dist/index.d.ts CHANGED
@@ -1,6 +1,7 @@
1
1
  export * from './constants.js';
2
2
  export * from './types.js';
3
3
  export { BaseCoyoteProtocolAdapter, INACTIVE_FREQ, INACTIVE_INT, SILENT_WAVE_STEP, type ChannelWaveState, type Quad, type StateListener, type WaveStep, type WebBluetoothAvailability, type WebBluetoothConnectionContext, type WebBluetoothProtocolAdapter, type WebBluetoothSensorAdapter, } from './base.js';
4
+ export { runWithGattReadyRetry, DEFAULT_GATT_READY_INITIAL_DELAY_MS, DEFAULT_GATT_READY_TIMEOUT_MS, DEFAULT_GATT_READY_INTERVAL_MS, DEFAULT_GATT_READY_ERROR_PATTERNS, type GattReadyRetryOptions, } from './gatt-ready.js';
4
5
  export { CoyoteV2ProtocolAdapter } from './v2.js';
5
6
  export { CoyoteV3ProtocolAdapter } from './v3.js';
6
7
  export { CoyoteProtocolAdapter } from './facade.js';
@@ -1 +1 @@
1
- {"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":"AAAA,cAAc,gBAAgB,CAAC;AAC/B,cAAc,YAAY,CAAC;AAC3B,OAAO,EACL,yBAAyB,EACzB,aAAa,EACb,YAAY,EACZ,gBAAgB,EAChB,KAAK,gBAAgB,EACrB,KAAK,IAAI,EACT,KAAK,aAAa,EAClB,KAAK,QAAQ,EACb,KAAK,wBAAwB,EAC7B,KAAK,6BAA6B,EAClC,KAAK,2BAA2B,EAChC,KAAK,yBAAyB,GAC/B,MAAM,WAAW,CAAC;AACnB,OAAO,EAAE,uBAAuB,EAAE,MAAM,SAAS,CAAC;AAClD,OAAO,EAAE,uBAAuB,EAAE,MAAM,SAAS,CAAC;AAClD,OAAO,EAAE,qBAAqB,EAAE,MAAM,aAAa,CAAC;AACpD,OAAO,EACL,sBAAsB,EACtB,KAAK,gBAAgB,EACrB,KAAK,wBAAwB,EAC7B,KAAK,sBAAsB,GAC5B,MAAM,iBAAiB,CAAC;AACzB,OAAO,EAAE,0BAA0B,EAAE,KAAK,oBAAoB,EAAE,MAAM,mBAAmB,CAAC;AAC1F,OAAO,EACL,qBAAqB,EACrB,uBAAuB,EACvB,KAAK,YAAY,EACjB,KAAK,aAAa,EAClB,KAAK,kBAAkB,GACxB,MAAM,cAAc,CAAC"}
1
+ {"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":"AAAA,cAAc,gBAAgB,CAAC;AAC/B,cAAc,YAAY,CAAC;AAC3B,OAAO,EACL,yBAAyB,EACzB,aAAa,EACb,YAAY,EACZ,gBAAgB,EAChB,KAAK,gBAAgB,EACrB,KAAK,IAAI,EACT,KAAK,aAAa,EAClB,KAAK,QAAQ,EACb,KAAK,wBAAwB,EAC7B,KAAK,6BAA6B,EAClC,KAAK,2BAA2B,EAChC,KAAK,yBAAyB,GAC/B,MAAM,WAAW,CAAC;AACnB,OAAO,EACL,qBAAqB,EACrB,mCAAmC,EACnC,6BAA6B,EAC7B,8BAA8B,EAC9B,iCAAiC,EACjC,KAAK,qBAAqB,GAC3B,MAAM,iBAAiB,CAAC;AACzB,OAAO,EAAE,uBAAuB,EAAE,MAAM,SAAS,CAAC;AAClD,OAAO,EAAE,uBAAuB,EAAE,MAAM,SAAS,CAAC;AAClD,OAAO,EAAE,qBAAqB,EAAE,MAAM,aAAa,CAAC;AACpD,OAAO,EACL,sBAAsB,EACtB,KAAK,gBAAgB,EACrB,KAAK,wBAAwB,EAC7B,KAAK,sBAAsB,GAC5B,MAAM,iBAAiB,CAAC;AACzB,OAAO,EAAE,0BAA0B,EAAE,KAAK,oBAAoB,EAAE,MAAM,mBAAmB,CAAC;AAC1F,OAAO,EACL,qBAAqB,EACrB,uBAAuB,EACvB,KAAK,YAAY,EACjB,KAAK,aAAa,EAClB,KAAK,kBAAkB,GACxB,MAAM,cAAc,CAAC"}
package/dist/index.js CHANGED
@@ -1,6 +1,7 @@
1
1
  export * from './constants.js';
2
2
  export * from './types.js';
3
3
  export { BaseCoyoteProtocolAdapter, INACTIVE_FREQ, INACTIVE_INT, SILENT_WAVE_STEP, } from './base.js';
4
+ export { runWithGattReadyRetry, DEFAULT_GATT_READY_INITIAL_DELAY_MS, DEFAULT_GATT_READY_TIMEOUT_MS, DEFAULT_GATT_READY_INTERVAL_MS, DEFAULT_GATT_READY_ERROR_PATTERNS, } from './gatt-ready.js';
4
5
  export { CoyoteV2ProtocolAdapter } from './v2.js';
5
6
  export { CoyoteV3ProtocolAdapter } from './v3.js';
6
7
  export { CoyoteProtocolAdapter } from './facade.js';
package/dist/index.js.map CHANGED
@@ -1 +1 @@
1
- {"version":3,"file":"index.js","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":"AAAA,cAAc,gBAAgB,CAAC;AAC/B,cAAc,YAAY,CAAC;AAC3B,OAAO,EACL,yBAAyB,EACzB,aAAa,EACb,YAAY,EACZ,gBAAgB,GASjB,MAAM,WAAW,CAAC;AACnB,OAAO,EAAE,uBAAuB,EAAE,MAAM,SAAS,CAAC;AAClD,OAAO,EAAE,uBAAuB,EAAE,MAAM,SAAS,CAAC;AAClD,OAAO,EAAE,qBAAqB,EAAE,MAAM,aAAa,CAAC;AACpD,OAAO,EACL,sBAAsB,GAIvB,MAAM,iBAAiB,CAAC;AACzB,OAAO,EAAE,0BAA0B,EAA6B,MAAM,mBAAmB,CAAC;AAC1F,OAAO,EACL,qBAAqB,EACrB,uBAAuB,GAIxB,MAAM,cAAc,CAAC"}
1
+ {"version":3,"file":"index.js","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":"AAAA,cAAc,gBAAgB,CAAC;AAC/B,cAAc,YAAY,CAAC;AAC3B,OAAO,EACL,yBAAyB,EACzB,aAAa,EACb,YAAY,EACZ,gBAAgB,GASjB,MAAM,WAAW,CAAC;AACnB,OAAO,EACL,qBAAqB,EACrB,mCAAmC,EACnC,6BAA6B,EAC7B,8BAA8B,EAC9B,iCAAiC,GAElC,MAAM,iBAAiB,CAAC;AACzB,OAAO,EAAE,uBAAuB,EAAE,MAAM,SAAS,CAAC;AAClD,OAAO,EAAE,uBAAuB,EAAE,MAAM,SAAS,CAAC;AAClD,OAAO,EAAE,qBAAqB,EAAE,MAAM,aAAa,CAAC;AACpD,OAAO,EACL,sBAAsB,GAIvB,MAAM,iBAAiB,CAAC;AACzB,OAAO,EAAE,0BAA0B,EAA6B,MAAM,mBAAmB,CAAC;AAC1F,OAAO,EACL,qBAAqB,EACrB,uBAAuB,GAIxB,MAAM,cAAc,CAAC"}
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@dg-kit/protocol",
3
- "version": "1.6.1",
3
+ "version": "1.7.1",
4
4
  "description": "DG-Lab Coyote V2 / V3 BLE protocol adapters (transport-agnostic)",
5
5
  "license": "MIT",
6
6
  "author": "0xNullAI",
@@ -27,7 +27,7 @@
27
27
  "access": "public"
28
28
  },
29
29
  "dependencies": {
30
- "@dg-kit/core": "1.6.1"
30
+ "@dg-kit/core": "1.7.1"
31
31
  },
32
32
  "scripts": {
33
33
  "build": "tsc -p tsconfig.json",