@ray-js/robot-data-stream 0.0.17-beta.4 → 0.0.17-beta.6

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.
@@ -1,3 +1,4 @@
1
+ import { MqttError } from '../promise';
1
2
  import { BaseResponse } from '../type/protocols/base';
2
3
  /**
3
4
  * 统一的 MQTT 消息发送 Hook
@@ -9,4 +10,4 @@ export declare const useStructuredMessage: () => {
9
10
  /**
10
11
  * 错误处理工具函数
11
12
  */
12
- export declare const handleMqttError: (error: unknown, defaultMessage: string) => Error;
13
+ export declare const handleMqttError: (error: unknown, defaultMessage: string) => MqttError;
@@ -5,7 +5,7 @@ import { useCallback, useEffect, useRef } from 'react';
5
5
  import { getBitValue, logger } from '../../utils';
6
6
  import { createSetCommonParams } from '../createCommonOptions';
7
7
  import { useMqtt } from '../mqttProvider';
8
- import { normalResolve } from '../promise';
8
+ import { MqttError, normalResolve } from '../promise';
9
9
  // 常量定义
10
10
  const COMMUNICATION_CHANNELS = {
11
11
  MQTT: 'mqtt',
@@ -196,11 +196,18 @@ export const useStructuredMessage = () => {
196
196
  * 错误处理工具函数
197
197
  */
198
198
  export const handleMqttError = (error, defaultMessage) => {
199
- if (error instanceof Error) {
199
+ var _errCode, _reqType;
200
+ // 已是本库错误则直接透传
201
+ if (error instanceof MqttError) {
200
202
  return error;
201
203
  }
202
- if (typeof error === 'string') {
203
- return new Error(error);
204
- }
205
- return new Error(defaultMessage);
204
+
205
+ // 统一包装为 MqttError,打上标记,便于全局 unhandledrejection 兜底时识别为本库错误
206
+ const message = error instanceof Error ? error.message : typeof error === 'string' ? error : defaultMessage;
207
+ const errCode = (_errCode = error === null || error === void 0 ? void 0 : error.errCode) !== null && _errCode !== void 0 ? _errCode : -1;
208
+ const reqType = (_reqType = error === null || error === void 0 ? void 0 : error.reqType) !== null && _reqType !== void 0 ? _reqType : '';
209
+ return new MqttError(message, {
210
+ errCode,
211
+ reqType
212
+ });
206
213
  };
@@ -3,7 +3,7 @@ import { registerMQTTProtocolListener } from '@ray-js/ray';
3
3
  import { get, isFunction, isNil } from 'lodash-es';
4
4
  import React, { createContext, useCallback, useContext, useEffect, useMemo, useRef } from 'react';
5
5
  import { emitter } from '../utils';
6
- import { setUnhandledRejectionHandler } from './promise';
6
+ import { dispatchUnhandledRejection, setUnhandledRejectionHandler } from './promise';
7
7
  import { ProtocolEnum } from './type';
8
8
  import log4js from '@ray-js/log4js';
9
9
 
@@ -94,25 +94,27 @@ export function MqttProvider(_ref) {
94
94
 
95
95
  // 设置全局错误处理器(不依赖 window,适用于小程序环境)
96
96
  useEffect(() => {
97
- if (onError) {
98
- // 设置全局错误处理器
99
- setUnhandledRejectionHandler(error => {
100
- try {
101
- onError(error);
102
- } catch (handlerError) {
103
- // 避免错误处理器本身抛出错误导致无限循环
104
- console.error('Error in MQTT error handler:', handlerError);
105
- }
106
- });
107
- } else {
108
- // 如果没有提供错误处理器,设置默认处理器(记录警告)
109
- setUnhandledRejectionHandler(error => {
110
- console.warn(`[MQTT] Unhandled rejection for ${error.reqType}:`, error.message);
111
- });
112
- }
97
+ var _tyGlobal$onUnhandled;
98
+ // 注册处理器:业务方传了 onError 就用它,否则退化为警告日志
99
+ setUnhandledRejectionHandler(onError !== null && onError !== void 0 ? onError : error => {
100
+ console.warn(`[MQTT] Unhandled rejection for ${error.reqType}:`, error.message);
101
+ });
102
+
103
+ // 兜底:监听小程序全局未处理的 Promise rejection。
104
+ // 当业务方"即发即忘"地调用 query/request(未 catch)且失败时,rejection 会走到这里;
105
+ // dispatchUnhandledRejection 只转发本库产生的 MqttError 给上面注册的处理器(onError),
106
+ // 从而避免这类错误作为未处理异常继续向上冒泡,同时不会误吞无关的应用级 rejection。
107
+ const onGlobalUnhandledRejection = res => {
108
+ dispatchUnhandledRejection(res === null || res === void 0 ? void 0 : res.reason);
109
+ };
110
+ // 部分环境 / 旧类型定义未声明该 API,做类型收窄 + 运行时判空,避免非小程序环境(如测试)报错
111
+ const tyGlobal = typeof ty === 'undefined' ? undefined : ty;
112
+ tyGlobal === null || tyGlobal === void 0 || (_tyGlobal$onUnhandled = tyGlobal.onUnhandledRejection) === null || _tyGlobal$onUnhandled === void 0 || _tyGlobal$onUnhandled.call(tyGlobal, onGlobalUnhandledRejection);
113
113
 
114
- // 清理函数:组件卸载时移除全局处理器
114
+ // 清理函数:组件卸载时移除全局处理器与监听
115
115
  return () => {
116
+ var _tyGlobal$offUnhandle;
117
+ tyGlobal === null || tyGlobal === void 0 || (_tyGlobal$offUnhandle = tyGlobal.offUnhandledRejection) === null || _tyGlobal$offUnhandle === void 0 || _tyGlobal$offUnhandle.call(tyGlobal, onGlobalUnhandledRejection);
116
118
  setUnhandledRejectionHandler(null);
117
119
  };
118
120
  }, [onError]);
@@ -24,6 +24,18 @@ export declare class MqttError extends Error {
24
24
  reqType: string;
25
25
  });
26
26
  }
27
+ /**
28
+ * 判断是否为本库(MQTT 请求)产生的错误。
29
+ * 用于全局 unhandledrejection 兜底时,只处理本库错误,避免误吞/误报无关的应用级 rejection。
30
+ */
31
+ export declare function isMqttError(error: unknown): error is MqttError;
32
+ /**
33
+ * 分发一个未被业务方 catch 的 rejection。
34
+ * 仅当它是本库产生的 MQTT 错误、且已通过 setUnhandledRejectionHandler 注册处理器时,才转发给该处理器。
35
+ *
36
+ * @returns 是否已被本库处理(true 表示已转发给 onError,可视为"已消费")
37
+ */
38
+ export declare function dispatchUnhandledRejection(reason: unknown): boolean;
27
39
  /**
28
40
  * MQTT 响应消息类型(兼容 MQTT 响应格式)
29
41
  */
@@ -51,6 +51,33 @@ export class MqttError extends Error {
51
51
  }
52
52
  }
53
53
 
54
+ /**
55
+ * 判断是否为本库(MQTT 请求)产生的错误。
56
+ * 用于全局 unhandledrejection 兜底时,只处理本库错误,避免误吞/误报无关的应用级 rejection。
57
+ */
58
+ export function isMqttError(error) {
59
+ return error instanceof MqttError || (error === null || error === void 0 ? void 0 : error.name) === 'MqttError';
60
+ }
61
+
62
+ /**
63
+ * 分发一个未被业务方 catch 的 rejection。
64
+ * 仅当它是本库产生的 MQTT 错误、且已通过 setUnhandledRejectionHandler 注册处理器时,才转发给该处理器。
65
+ *
66
+ * @returns 是否已被本库处理(true 表示已转发给 onError,可视为"已消费")
67
+ */
68
+ export function dispatchUnhandledRejection(reason) {
69
+ if (!isMqttError(reason) || !globalUnhandledRejectionHandler) {
70
+ return false;
71
+ }
72
+ try {
73
+ globalUnhandledRejectionHandler(reason);
74
+ } catch (handlerError) {
75
+ // 避免错误处理器本身抛出错误导致无限循环
76
+ console.error('Error in MQTT error handler:', handlerError);
77
+ }
78
+ return true;
79
+ }
80
+
54
81
  /**
55
82
  * MQTT 响应消息类型(兼容 MQTT 响应格式)
56
83
  */
@@ -3,15 +3,15 @@ import type { BaseResponse } from './base';
3
3
  export type CruiseCmd = 'start' | 'pause' | 'resume' | 'stop';
4
4
  /** 巡航状态:idle 未巡航 / cruising 巡航中 / paused 已暂停 */
5
5
  export type CruiseStatus = 'idle' | 'cruising' | 'paused';
6
- /** 巡航类型:whole_house 全屋巡航 / select_room 定点巡航(按房间工作点) */
7
- export type CruiseType = 'whole_house' | 'select_room';
6
+ /** 巡航类型:whole_house 全屋巡航 / spot 定点巡航(按净化点坐标) */
7
+ export type CruiseType = 'whole_house' | 'spot';
8
8
  export interface SetCruiseData {
9
9
  /** start 开始 / pause 暂停 / resume 继续 / stop 结束 */
10
10
  cmd: CruiseCmd;
11
11
  /** 巡航类型,cmd 为 start 时必填 */
12
12
  cruiseType?: CruiseType;
13
- /** select_room 时的房间 ID 列表;不传表示全部工作点 */
14
- ids?: number[];
13
+ /** spot 定点巡航时的净化点坐标列表,格式 "x, y";不传表示全部净化点 */
14
+ polygons?: string[];
15
15
  version?: string;
16
16
  }
17
17
  export interface RequestCruiseData {
@@ -23,12 +23,10 @@ export interface CruiseResponse extends BaseResponse {
23
23
  mapId: number;
24
24
  /** 巡航类型;idle 时可不携带 */
25
25
  cruiseType?: CruiseType;
26
- /** select_room 时本次巡航的房间 ID 列表 */
27
- ids?: number[];
28
- /** 当前正在工作的房间 ID */
29
- currentId?: number;
30
- /** 当前工作点坐标 "x, y" */
31
- polygon?: string;
26
+ /** spot 定点巡航时的净化点坐标列表,格式 "x, y" */
27
+ polygons?: string[];
28
+ /** 当前正在净化的坐标 "x, y" */
29
+ currentPolygon?: string;
32
30
  }
33
31
  export type TRequestCruise = (message?: RequestCruiseData) => Promise<CruiseResponse>;
34
32
  export type TSetCruise = (message: SetCruiseData) => Promise<CruiseResponse>;
@@ -1,6 +1,12 @@
1
1
  import type { BaseResponse } from './base';
2
- /** 工作类型:select_room 选房净化 / whole_house 整屋净化 */
3
- export type PurifierWorkType = 'select_room' | 'whole_house';
2
+ /**
3
+ * 工作类型:
4
+ * - select_room 选房净化(携带 ids)
5
+ * - whole_house 整屋净化
6
+ * - spot 定点净化
7
+ * - current_location 原地净化
8
+ */
9
+ export type PurifierWorkType = 'select_room' | 'whole_house' | 'spot' | 'current_location';
4
10
  /** 风速档位,透传字符串,不限制具体取值(不同设备支持的档位不同) */
5
11
  export type PurifierFanMode = string;
6
12
  export interface PurifierScheduleItem {
@@ -10,9 +16,9 @@ export interface PurifierScheduleItem {
10
16
  cycle: number[];
11
17
  /** 执行时间 [时, 分],24 小时制 */
12
18
  time: number[];
13
- /** 房间 ID 列表;workTypes 为 whole_house 时为空数组 */
19
+ /** 房间 ID 列表;workTypes 为 whole_house / spot / current_location 时为空数组 */
14
20
  ids: number[];
15
- /** 工作类型,与 ids 对齐;整屋时单元素 whole_house */
21
+ /** 工作类型,与 ids 对齐;非 select_room 时为单元素 */
16
22
  workTypes: PurifierWorkType[];
17
23
  /** 风速,与 ids 对齐(整屋时单元素) */
18
24
  fanModes: PurifierFanMode[];
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@ray-js/robot-data-stream",
3
- "version": "0.0.17-beta.4",
3
+ "version": "0.0.17-beta.6",
4
4
  "description": "扫地机P2P数据流标准化组件",
5
5
  "main": "lib/index",
6
6
  "files": [