@ziztechnology/dial-library 0.0.1 → 0.0.2
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/README.md +183 -0
- package/dist/index.d.mts +260 -6
- package/dist/index.mjs +1662 -1
- package/package.json +11 -6
package/README.md
CHANGED
|
@@ -1 +1,184 @@
|
|
|
1
1
|
# Toooony 表盘用户 SDK
|
|
2
|
+
|
|
3
|
+
> [!NOTE]
|
|
4
|
+
> 最低支持 Runtime 版本 `v1.5.20`。行车状态传感器 Bridge 仅供经过审核的 `PACKAGED_H5` 使用;第三方应依赖本 SDK API,不要把 Runtime 的 `window` 内部方法当作稳定接口。
|
|
5
|
+
|
|
6
|
+
## 安装
|
|
7
|
+
|
|
8
|
+
```bash
|
|
9
|
+
npm i @ziztechnology/dial-library
|
|
10
|
+
```
|
|
11
|
+
|
|
12
|
+
## 行车状态母版快速接入
|
|
13
|
+
|
|
14
|
+
```ts
|
|
15
|
+
import {
|
|
16
|
+
OFFICIAL_DRIVING_EXPRESSION_FALLBACKS,
|
|
17
|
+
createDrivingExpressionPlayer,
|
|
18
|
+
createDrivingStatusController,
|
|
19
|
+
readDrivingExpressionsConfig,
|
|
20
|
+
} from '@ziztechnology/dial-library';
|
|
21
|
+
|
|
22
|
+
const config = readDrivingExpressionsConfig();
|
|
23
|
+
if (!config) throw new Error('Unsupported or invalid drivingExpressions config');
|
|
24
|
+
|
|
25
|
+
const player = createDrivingExpressionPlayer(document.querySelector('#expression')!, {
|
|
26
|
+
config,
|
|
27
|
+
// 官方母版必须显式传入;第三方不传时不会自动获得官方 Emoji。
|
|
28
|
+
fallbacks: OFFICIAL_DRIVING_EXPRESSION_FALLBACKS,
|
|
29
|
+
});
|
|
30
|
+
const controller = createDrivingStatusController();
|
|
31
|
+
|
|
32
|
+
await player.show('STOPPED');
|
|
33
|
+
const unsubscribe = controller.subscribe((event) => {
|
|
34
|
+
if (event.type === 'status_changed') void player.show(event.status);
|
|
35
|
+
});
|
|
36
|
+
controller.start();
|
|
37
|
+
|
|
38
|
+
// 也可以由母版显式控制;默认会自动接入 Runtime pause/resume 和页面生命周期。
|
|
39
|
+
const pause = () => {
|
|
40
|
+
controller.stop();
|
|
41
|
+
player.pause();
|
|
42
|
+
};
|
|
43
|
+
const resume = () => {
|
|
44
|
+
player.resume();
|
|
45
|
+
controller.start();
|
|
46
|
+
};
|
|
47
|
+
|
|
48
|
+
// 页面销毁时:
|
|
49
|
+
const destroy = () => {
|
|
50
|
+
unsubscribe();
|
|
51
|
+
controller.destroy();
|
|
52
|
+
player.destroy();
|
|
53
|
+
};
|
|
54
|
+
```
|
|
55
|
+
|
|
56
|
+
重复调用 `start()`、`stop()`、`destroy()`、`pause()` 或 `resume()`是安全的。启动时 UI 应先显示 `STOPPED`,只有已提交状态才触发媒体切换,候选状态不会触发 UI。
|
|
57
|
+
|
|
58
|
+
## 稳定的八状态协议
|
|
59
|
+
|
|
60
|
+
`CarRunningStatus` 的 wire 值和 `CAR_RUNNING_STATUSES` 固定为:
|
|
61
|
+
|
|
62
|
+
```text
|
|
63
|
+
STOPPED
|
|
64
|
+
STEADY_DRIVING
|
|
65
|
+
ACCELERATION
|
|
66
|
+
RAPID_ACCELERATION
|
|
67
|
+
BRAKING
|
|
68
|
+
SUDDEN_BRAKING
|
|
69
|
+
LEFT_TURN
|
|
70
|
+
RIGHT_TURN
|
|
71
|
+
```
|
|
72
|
+
|
|
73
|
+
`OFFICIAL_DRIVING_EXPRESSION_FALLBACKS` 提供官方母版的固定默认值:`😐 😊 😄 😲 😣 😱 🤨 🤨`。SDK 不会自动使用这张表;第三方未传 `fallbacks` 时,素材缺失或加载失败只会上报错误。
|
|
74
|
+
|
|
75
|
+
## 配置解析
|
|
76
|
+
|
|
77
|
+
`drivingExpressions` 使用 schema v1,八个状态必须完整且不能包含未知状态。`parseDrivingExpressionsConfig()` 同时接受 JSON 对象和 JSON 字符串,并返回完整、结构化的配置:
|
|
78
|
+
|
|
79
|
+
```ts
|
|
80
|
+
import { parseDrivingExpressionsConfig } from '@ziztechnology/dial-library';
|
|
81
|
+
|
|
82
|
+
const config = parseDrivingExpressionsConfig(customField.value);
|
|
83
|
+
```
|
|
84
|
+
|
|
85
|
+
支持的素材为:
|
|
86
|
+
|
|
87
|
+
```ts
|
|
88
|
+
type StructuredDrivingExpressionMedia =
|
|
89
|
+
| { kind: 'emoji'; text: string }
|
|
90
|
+
| { kind: 'image'; mediaAssetId?: number; url: string; mimeType?: string }
|
|
91
|
+
| { kind: 'video'; mediaAssetId?: number; url: string; coverUrl?: string; mimeType?: string }
|
|
92
|
+
| { kind: 'live_photo'; mediaAssetId?: number; coverUrl: string; motionUrl: string }
|
|
93
|
+
| { kind: 'tgs'; mediaAssetId?: number; url: string; coverUrl?: string };
|
|
94
|
+
```
|
|
95
|
+
|
|
96
|
+
解析器拒绝缺项、轮播字段、非法 kind/字段组合、非单个可见 grapheme 的 Emoji,以及 `http:`、`data:`、`blob:`、localhost、内网/保留 IP、内部单标签 host、带 COS/GCS/OSS 等常见临时签名参数的非长期公网 HTTPS URL。普通公网 HTTPS 与无签名业务 query 仍可使用。后端仍必须按 `mediaAssetId + userID` 重建可信 URL;SDK 静态校验不能替代服务端所有权、DNS 解析和 host allowlist 校验。
|
|
97
|
+
|
|
98
|
+
`readDrivingExpressionsConfig()` 优先读取 Runtime 注入的 `window.__TOOOONY_DRIVING_EXPRESSIONS__`,再兼容旧 `__TOOOONY_FACE_CONFIG__` 路径;非法或不支持的配置返回 `null`,不会隐式填充官方默认值。
|
|
99
|
+
|
|
100
|
+
首版 SDK 接受过裸图片 URL。为兼容旧表盘,`resolveDrivingExpression()` 及 `DrivingExpressionsConfig` 仍保留旧形状;只有显式设置 `{ allowLegacyImageUrls: true }` 时,schema 解析器才会把裸 HTTPS URL 归一化为 `kind: 'image'`。
|
|
101
|
+
|
|
102
|
+
## 纯函数分类
|
|
103
|
+
|
|
104
|
+
```ts
|
|
105
|
+
import { classifyDrivingSnapshot, unifiedSensorInfo } from '@ziztechnology/dial-library';
|
|
106
|
+
|
|
107
|
+
const status = classifyDrivingSnapshot(await unifiedSensorInfo());
|
|
108
|
+
```
|
|
109
|
+
|
|
110
|
+
`classifyDrivingSnapshot(info, tuning?)` 是无状态纯函数。原 API `checkRunningStatus()` 保留为同一函数的兼容别名。数据不可用、非法或超过 1 秒未更新时返回 `null`。
|
|
111
|
+
|
|
112
|
+
固定安装方向:
|
|
113
|
+
|
|
114
|
+
```text
|
|
115
|
+
+X = 车身右侧
|
|
116
|
+
+Y = 上方
|
|
117
|
+
-Z = 车辆前进方向
|
|
118
|
+
```
|
|
119
|
+
|
|
120
|
+
即 `longitudinal = -linearAcceleration.z`、`lateral = linearAcceleration.x`、`yaw = gyroscope.y`。左转为正 yaw 或负 lateral,右转符号相反。
|
|
121
|
+
|
|
122
|
+
默认阈值集中在 `DEFAULT_DRIVING_STATUS_TUNING`,版本为 `driving-status-v1`。仅靠惯性传感器无法严格区分静止和理想匀速直线运动;v1 使用 `motionIntensity` 和陀螺仪扰动近似判断,必须通过固定安装真机路测继续调参。
|
|
123
|
+
|
|
124
|
+
## 状态控制器
|
|
125
|
+
|
|
126
|
+
```ts
|
|
127
|
+
const controller = createDrivingStatusController({
|
|
128
|
+
pollIntervalMs: 200,
|
|
129
|
+
unavailableFallbackMs: 3_000,
|
|
130
|
+
initialStatus: 'STOPPED',
|
|
131
|
+
tuning: { turnYawThreshold: 0.32 },
|
|
132
|
+
onDiagnostic(event) {
|
|
133
|
+
// 诊断事件不包含完整媒体 URL或逐帧传感器数据。
|
|
134
|
+
},
|
|
135
|
+
});
|
|
136
|
+
```
|
|
137
|
+
|
|
138
|
+
控制器统一实现:
|
|
139
|
+
|
|
140
|
+
- 默认 200ms 轮询,读取期间不会发起重叠请求;`stop()` 会通过 `AbortSignal` 取消/忽略未完成读取。
|
|
141
|
+
- 普通动作短窗口平滑,急动作检查未平滑峰值。
|
|
142
|
+
- 急刹车 > 急加速 > 转弯 > 刹车 > 加速 > 静止/匀速的抢占优先级。
|
|
143
|
+
- 急动作 1 样本、转弯/普通动作 2 样本、匀速 3 样本、静止 5 样本的连续确认。
|
|
144
|
+
- 动作退出阈值为入口阈值的 `0.75`,并对静止/匀速使用反向滞回区间。
|
|
145
|
+
- 每个已提交状态的最短展示时间;更高优先级候选可抢占,锁期间继续采样。
|
|
146
|
+
- 单次/短暂不可用保持最后状态;连续不可用达到 3 秒强制提交 `STOPPED`;恢复后重新确认候选。
|
|
147
|
+
|
|
148
|
+
`getSnapshot()` 返回生命周期、已提交状态、候选计数、不可用起点和 tuning 版本。`subscribe()` 只发送稳定的 `status_changed` 事件;更细的 `sample_available`、`candidate_changed`、`status_held_by_min_duration`、`fallback_to_stopped` 等通过可选 `onDiagnostic` 获取。
|
|
149
|
+
|
|
150
|
+
测试和离线回放可注入 `sensorProvider` 与 `clock`。provider 可接收 `AbortSignal`:
|
|
151
|
+
|
|
152
|
+
```ts
|
|
153
|
+
const controller = createDrivingStatusController({
|
|
154
|
+
sensorProvider: (signal) => replay.next(signal),
|
|
155
|
+
clock: fakeClock,
|
|
156
|
+
});
|
|
157
|
+
```
|
|
158
|
+
|
|
159
|
+
## 媒体播放器
|
|
160
|
+
|
|
161
|
+
`createDrivingExpressionPlayer(container, options)` 同时只保留一个活动动态播放器:
|
|
162
|
+
|
|
163
|
+
- Emoji 直接渲染本地文本。
|
|
164
|
+
- 图片/GIF 使用原生 `<img>`,保留 GIF 动画。
|
|
165
|
+
- 视频复用一个 `<video muted loop playsinline>`;离开状态时停止并清空,重新进入从 `0` 开始。
|
|
166
|
+
- Live Photo 先显示 cover,motion 就绪后使用静音循环视频;motion 失败时应用该状态 fallback,不会永久停在 cover。
|
|
167
|
+
- TGS 以无凭据 CORS fetch 读取,限制压缩/解压大小、图层数、帧率和帧数;使用 `fflate` 解压并通过 `lottie-web` 循环渲染。
|
|
168
|
+
- TGS 仅接受约定的 TGS、gzip 或 JSON Content-Type;HTML 和无关 MIME 会立即回退。
|
|
169
|
+
- 默认加载超时 5 秒。失败后应用显式 fallback,并按退避时间重试;状态离开、pause 或 destroy 会取消网络、预加载和动画。
|
|
170
|
+
- 轻量预加载顺序为当前状态、`STOPPED`、其余状态;只缓存图片/cover 提示,不同时解码八个视频。
|
|
171
|
+
|
|
172
|
+
控制器和播放器默认共享 `window.__watchFaceRuntimePause` / `window.__watchFaceRuntimeResume`、visibility/page 事件及设备传感器 release/resume 事件。SDK 会链接并在最后一个订阅者销毁时恢复页面原有 hook,避免两者相互覆盖。播放器可通过 `managePageLifecycle: false` 显式关闭自动生命周期管理。
|
|
173
|
+
|
|
174
|
+
可使用 `onDiagnostic` 监听 `media_ready`、`media_load_failed` 和 `media_fallback_applied`。诊断会截断错误消息并移除 URL query,避免记录临时 token。
|
|
175
|
+
|
|
176
|
+
## 开发验证
|
|
177
|
+
|
|
178
|
+
```bash
|
|
179
|
+
pnpm test
|
|
180
|
+
pnpm exec tsc --noEmit
|
|
181
|
+
pnpm run fmt:check
|
|
182
|
+
```
|
|
183
|
+
|
|
184
|
+
测试使用 fake clock、fake sensor provider 和轻量 DOM,覆盖八状态边界、优先级、候选确认、滞回、最短展示、2.9/3 秒不可用边界、生命周期幂等、所有配置 kind、官方/第三方 fallback 差异,以及图片/视频/Live Photo/TGS 播放行为。
|
package/dist/index.d.mts
CHANGED
|
@@ -1,5 +1,15 @@
|
|
|
1
|
-
//#region src/sensor/
|
|
1
|
+
//#region src/sensor/constants.d.ts
|
|
2
2
|
type UnifiedSensorUnavailableReason = 'SENSOR_MISSING' | 'NO_SAMPLE' | 'PLATFORM_UNAVAILABLE' | 'PERMISSION_DENIED' | 'NOT_CONNECTED';
|
|
3
|
+
type BatteryStatus = 'CHARGING' | 'DISCHARGING' | 'FULL' | 'NOT_CHARGING' | 'UNKNOWN';
|
|
4
|
+
type BatteryPlugged = 'AC' | 'USB' | 'WIRELESS' | 'DOCK' | 'NONE';
|
|
5
|
+
type BatteryHealth = 'GOOD' | 'OVERHEAT' | 'DEAD' | 'OVER_VOLTAGE' | 'UNSPECIFIED_FAILURE' | 'COLD' | 'UNKNOWN';
|
|
6
|
+
declare const BATTERY_HEALTH_LABELS: Record<BatteryHealth, string>;
|
|
7
|
+
type CarRunningStatus = 'STOPPED' | 'STEADY_DRIVING' | 'ACCELERATION' | 'RAPID_ACCELERATION' | 'BRAKING' | 'SUDDEN_BRAKING' | 'LEFT_TURN' | 'RIGHT_TURN';
|
|
8
|
+
declare const CAR_RUNNING_LABELS: Record<CarRunningStatus, string>;
|
|
9
|
+
declare const CAR_RUNNING_STATUSES: readonly ["STOPPED", "STEADY_DRIVING", "ACCELERATION", "RAPID_ACCELERATION", "BRAKING", "SUDDEN_BRAKING", "LEFT_TURN", "RIGHT_TURN"];
|
|
10
|
+
declare const CAR_RUNNING_STATUS_PRIORITY: Readonly<Record<CarRunningStatus, number>>;
|
|
11
|
+
//#endregion
|
|
12
|
+
//#region src/sensor/unified_info.d.ts
|
|
3
13
|
interface Vector3Value {
|
|
4
14
|
x: number;
|
|
5
15
|
y: number;
|
|
@@ -14,9 +24,6 @@ interface BatteryCapacityValue {
|
|
|
14
24
|
levelPercent: number | null;
|
|
15
25
|
chargeCounterUah: number | null;
|
|
16
26
|
}
|
|
17
|
-
type BatteryStatus = 'CHARGING' | 'DISCHARGING' | 'FULL' | 'NOT_CHARGING' | 'UNKNOWN';
|
|
18
|
-
type BatteryPlugged = 'AC' | 'USB' | 'WIRELESS' | 'DOCK' | 'NONE';
|
|
19
|
-
type BatteryHealth = 'GOOD' | 'OVERHEAT' | 'DEAD' | 'OVER_VOLTAGE' | 'UNSPECIFIED_FAILURE' | 'COLD' | 'UNKNOWN';
|
|
20
27
|
interface BatteryStateValue {
|
|
21
28
|
present: boolean;
|
|
22
29
|
charging: boolean;
|
|
@@ -45,6 +52,7 @@ type UnifiedSensorMetric<T, TSource extends string, TUnit extends string | null,
|
|
|
45
52
|
interface UnifiedSensorInfoPayload {
|
|
46
53
|
capturedAtMs: number;
|
|
47
54
|
gyroscope: UnifiedSensorMetric<Vector3Value, 'TYPE_GYROSCOPE', 'rad/s', 'SENSOR_MISSING' | 'NO_SAMPLE', number | null>;
|
|
55
|
+
accelerometer: UnifiedSensorMetric<Vector3Value, 'TYPE_ACCELEROMETER', 'm/s²', 'SENSOR_MISSING' | 'NO_SAMPLE', number | null>;
|
|
48
56
|
batteryCapacity: UnifiedSensorMetric<BatteryCapacityValue, 'BatteryManager', null, null, number>;
|
|
49
57
|
wifiSsid: UnifiedSensorMetric<string, 'NetworkCapabilities.WifiInfo', null, 'PERMISSION_DENIED' | 'NOT_CONNECTED' | 'PLATFORM_UNAVAILABLE'>;
|
|
50
58
|
battery: UnifiedSensorMetric<BatteryStateValue, 'ACTION_BATTERY_CHANGED', null, 'PLATFORM_UNAVAILABLE'>;
|
|
@@ -52,8 +60,254 @@ interface UnifiedSensorInfoPayload {
|
|
|
52
60
|
gravity: UnifiedSensorMetric<Vector3Value, 'TYPE_GRAVITY', 'm/s²', 'SENSOR_MISSING' | 'NO_SAMPLE', number | null>;
|
|
53
61
|
orientation: UnifiedSensorMetric<OrientationValue, 'TYPE_ROTATION_VECTOR' | 'ACCELEROMETER_MAGNETIC_FIELD', 'degree', 'SENSOR_MISSING' | 'NO_SAMPLE', number | null>;
|
|
54
62
|
magneticField: UnifiedSensorMetric<Vector3Value, 'TYPE_MAGNETIC_FIELD', 'µT', 'SENSOR_MISSING' | 'NO_SAMPLE', number | null>;
|
|
55
|
-
linearAcceleration: UnifiedSensorMetric<Vector3Value, 'TYPE_LINEAR_ACCELERATION', 'm/s²', 'SENSOR_MISSING' | 'NO_SAMPLE', number | null>;
|
|
63
|
+
linearAcceleration: UnifiedSensorMetric<Vector3Value, 'TYPE_LINEAR_ACCELERATION' | 'DERIVED_ACCELEROMETER_GRAVITY', 'm/s²', 'SENSOR_MISSING' | 'NO_SAMPLE', number | null>;
|
|
64
|
+
motionIntensity?: UnifiedSensorMetric<number, 'DERIVED_ACCELEROMETER_MAGNITUDE_STDDEV', 'm/s²', 'SENSOR_MISSING' | 'NO_SAMPLE', number | null>;
|
|
56
65
|
}
|
|
57
66
|
declare const unifiedSensorInfo: () => Promise<UnifiedSensorInfoPayload>;
|
|
58
67
|
//#endregion
|
|
59
|
-
|
|
68
|
+
//#region src/sensor/check_status.d.ts
|
|
69
|
+
interface DrivingStatusTuning {
|
|
70
|
+
version: string;
|
|
71
|
+
maxSampleAgeMs: number;
|
|
72
|
+
rapidLongitudinalThreshold: number;
|
|
73
|
+
longitudinalThreshold: number;
|
|
74
|
+
turnYawThreshold: number;
|
|
75
|
+
turnLateralThreshold: number;
|
|
76
|
+
stoppedMotionThreshold: number;
|
|
77
|
+
stoppedGyroThreshold: number;
|
|
78
|
+
hysteresisRatio: number;
|
|
79
|
+
smoothingWindowSize: number;
|
|
80
|
+
confirmationSamples: Readonly<Record<CarRunningStatus, number>>;
|
|
81
|
+
minimumDisplayMs: Readonly<Record<CarRunningStatus, number>>;
|
|
82
|
+
}
|
|
83
|
+
type DrivingStatusTuningOverrides = Partial<Omit<DrivingStatusTuning, 'confirmationSamples' | 'minimumDisplayMs'>> & {
|
|
84
|
+
confirmationSamples?: Partial<Record<CarRunningStatus, number>>;
|
|
85
|
+
minimumDisplayMs?: Partial<Record<CarRunningStatus, number>>;
|
|
86
|
+
};
|
|
87
|
+
declare const DEFAULT_DRIVING_STATUS_TUNING: Readonly<DrivingStatusTuning>;
|
|
88
|
+
interface DrivingSnapshotMetrics {
|
|
89
|
+
capturedAtMs: number;
|
|
90
|
+
longitudinal: number;
|
|
91
|
+
lateral: number;
|
|
92
|
+
yaw: number;
|
|
93
|
+
motionIntensity: number;
|
|
94
|
+
gyroMagnitude: number;
|
|
95
|
+
}
|
|
96
|
+
declare const classifyDrivingSnapshot: (info: UnifiedSensorInfoPayload, tuningOverrides?: DrivingStatusTuningOverrides) => CarRunningStatus | null;
|
|
97
|
+
declare const checkRunningStatus: (info: UnifiedSensorInfoPayload, tuningOverrides?: DrivingStatusTuningOverrides) => CarRunningStatus | null;
|
|
98
|
+
declare const resolveDrivingStatusTuning: (overrides?: DrivingStatusTuningOverrides) => DrivingStatusTuning;
|
|
99
|
+
declare const extractDrivingSnapshotMetrics: (info: UnifiedSensorInfoPayload, tuning?: Pick<DrivingStatusTuning, "maxSampleAgeMs">) => DrivingSnapshotMetrics | null;
|
|
100
|
+
declare const classifyDrivingMetrics: (metrics: DrivingSnapshotMetrics, tuning?: DrivingStatusTuning) => CarRunningStatus;
|
|
101
|
+
//#endregion
|
|
102
|
+
//#region src/sensor/driving_expressions.d.ts
|
|
103
|
+
interface MediaLibraryRef {
|
|
104
|
+
mediaAssetId?: number;
|
|
105
|
+
}
|
|
106
|
+
interface EmojiDrivingExpressionMedia {
|
|
107
|
+
kind: 'emoji';
|
|
108
|
+
text: string;
|
|
109
|
+
}
|
|
110
|
+
interface ImageDrivingExpressionMedia extends MediaLibraryRef {
|
|
111
|
+
kind: 'image';
|
|
112
|
+
url: string;
|
|
113
|
+
mimeType?: string;
|
|
114
|
+
}
|
|
115
|
+
interface VideoDrivingExpressionMedia extends MediaLibraryRef {
|
|
116
|
+
kind: 'video';
|
|
117
|
+
url: string;
|
|
118
|
+
coverUrl?: string;
|
|
119
|
+
mimeType?: string;
|
|
120
|
+
}
|
|
121
|
+
interface LivePhotoDrivingExpressionMedia extends MediaLibraryRef {
|
|
122
|
+
kind: 'live_photo';
|
|
123
|
+
coverUrl: string;
|
|
124
|
+
motionUrl: string;
|
|
125
|
+
}
|
|
126
|
+
interface TgsDrivingExpressionMedia extends MediaLibraryRef {
|
|
127
|
+
kind: 'tgs';
|
|
128
|
+
url: string;
|
|
129
|
+
coverUrl?: string;
|
|
130
|
+
}
|
|
131
|
+
type StructuredDrivingExpressionMedia = EmojiDrivingExpressionMedia | ImageDrivingExpressionMedia | VideoDrivingExpressionMedia | LivePhotoDrivingExpressionMedia | TgsDrivingExpressionMedia;
|
|
132
|
+
type DrivingExpressionMedia = string | StructuredDrivingExpressionMedia;
|
|
133
|
+
/**
|
|
134
|
+
* Compatibility shape exported by the first SDK release. New persisted
|
|
135
|
+
* configurations should be parsed as CompleteDrivingExpressionsConfig.
|
|
136
|
+
*/
|
|
137
|
+
interface DrivingExpressionsConfig {
|
|
138
|
+
schemaVersion: 1;
|
|
139
|
+
states: Partial<Record<CarRunningStatus, DrivingExpressionMedia>> & Pick<Record<CarRunningStatus, DrivingExpressionMedia>, 'STOPPED' | 'STEADY_DRIVING'>;
|
|
140
|
+
}
|
|
141
|
+
interface CompleteDrivingExpressionsConfig {
|
|
142
|
+
schemaVersion: 1;
|
|
143
|
+
states: Record<CarRunningStatus, StructuredDrivingExpressionMedia>;
|
|
144
|
+
}
|
|
145
|
+
type DrivingExpressionsConfigInput = DrivingExpressionsConfig | CompleteDrivingExpressionsConfig;
|
|
146
|
+
declare const OFFICIAL_DRIVING_EXPRESSION_FALLBACKS: Readonly<Record<CarRunningStatus, Readonly<EmojiDrivingExpressionMedia>>>;
|
|
147
|
+
declare const OFFICIAL_DRIVING_EXPRESSIONS_CONFIG: Readonly<CompleteDrivingExpressionsConfig>;
|
|
148
|
+
type DrivingExpressionsConfigErrorCode = 'DRIVING_EXPRESSIONS_INVALID_SCHEMA' | 'DRIVING_EXPRESSIONS_INCOMPLETE' | 'DRIVING_EXPRESSION_INVALID_MEDIA' | 'MEDIA_URL_NOT_PUBLIC_HTTPS';
|
|
149
|
+
declare class DrivingExpressionsConfigError extends Error {
|
|
150
|
+
readonly code: DrivingExpressionsConfigErrorCode;
|
|
151
|
+
readonly state?: CarRunningStatus;
|
|
152
|
+
constructor(code: DrivingExpressionsConfigErrorCode, message: string, state?: CarRunningStatus);
|
|
153
|
+
}
|
|
154
|
+
declare class DrivingExpressionResolutionError extends Error {
|
|
155
|
+
readonly status: CarRunningStatus;
|
|
156
|
+
constructor(status: CarRunningStatus);
|
|
157
|
+
}
|
|
158
|
+
interface ParseDrivingExpressionsOptions {
|
|
159
|
+
/** Accept the v0 bare HTTPS image URL and normalize it to kind=image. */
|
|
160
|
+
allowLegacyImageUrls?: boolean;
|
|
161
|
+
}
|
|
162
|
+
declare const parseDrivingExpressionsConfig: (raw: unknown, options?: ParseDrivingExpressionsOptions) => CompleteDrivingExpressionsConfig;
|
|
163
|
+
declare const tryParseDrivingExpressionsConfig: (raw: unknown, options?: ParseDrivingExpressionsOptions) => CompleteDrivingExpressionsConfig | null;
|
|
164
|
+
/**
|
|
165
|
+
* Reads Runtime's typed injection first, then the legacy face-config value.
|
|
166
|
+
* It never installs official fallbacks implicitly.
|
|
167
|
+
*/
|
|
168
|
+
declare const readDrivingExpressionsConfig: (raw?: unknown, options?: ParseDrivingExpressionsOptions) => CompleteDrivingExpressionsConfig | null;
|
|
169
|
+
/** Original resolver behavior: missing legacy slots fall back to STEADY_DRIVING. */
|
|
170
|
+
declare const resolveDrivingExpression: (config: DrivingExpressionsConfigInput, status: CarRunningStatus) => DrivingExpressionMedia;
|
|
171
|
+
/** Strict resolver used by the player; official fallbacks are opt-in. */
|
|
172
|
+
declare const resolveDrivingExpressionStrict: (config: DrivingExpressionsConfigInput, status: CarRunningStatus, fallbacks?: Partial<Readonly<Record<CarRunningStatus, StructuredDrivingExpressionMedia>>>) => DrivingExpressionMedia;
|
|
173
|
+
declare const isPublicDrivingMediaUrl: (value: string) => boolean;
|
|
174
|
+
//#endregion
|
|
175
|
+
//#region src/sensor/driving_status_controller.d.ts
|
|
176
|
+
type DrivingStatusChangeReason = 'candidate_confirmed' | 'unavailable_fallback';
|
|
177
|
+
interface DrivingStatusEvent {
|
|
178
|
+
type: 'status_changed';
|
|
179
|
+
status: CarRunningStatus;
|
|
180
|
+
previousStatus: CarRunningStatus;
|
|
181
|
+
reason: DrivingStatusChangeReason;
|
|
182
|
+
atMs: number;
|
|
183
|
+
}
|
|
184
|
+
type DrivingStatusDiagnosticEvent = {
|
|
185
|
+
type: 'sample_available';
|
|
186
|
+
atMs: number;
|
|
187
|
+
capturedAtMs: number;
|
|
188
|
+
tuningVersion: string;
|
|
189
|
+
} | {
|
|
190
|
+
type: 'sample_unavailable';
|
|
191
|
+
atMs: number;
|
|
192
|
+
unavailableForMs: number;
|
|
193
|
+
category: 'provider_error' | 'invalid_or_stale_snapshot';
|
|
194
|
+
tuningVersion: string;
|
|
195
|
+
} | {
|
|
196
|
+
type: 'candidate_changed';
|
|
197
|
+
atMs: number;
|
|
198
|
+
candidate: CarRunningStatus | null;
|
|
199
|
+
previousCandidate: CarRunningStatus | null;
|
|
200
|
+
tuningVersion: string;
|
|
201
|
+
} | {
|
|
202
|
+
type: 'status_committed';
|
|
203
|
+
atMs: number;
|
|
204
|
+
status: CarRunningStatus;
|
|
205
|
+
previousStatus: CarRunningStatus;
|
|
206
|
+
reason: DrivingStatusChangeReason;
|
|
207
|
+
tuningVersion: string;
|
|
208
|
+
} | {
|
|
209
|
+
type: 'status_held_by_min_duration';
|
|
210
|
+
atMs: number;
|
|
211
|
+
status: CarRunningStatus;
|
|
212
|
+
candidate: CarRunningStatus;
|
|
213
|
+
remainingMs: number;
|
|
214
|
+
tuningVersion: string;
|
|
215
|
+
} | {
|
|
216
|
+
type: 'fallback_to_stopped';
|
|
217
|
+
atMs: number;
|
|
218
|
+
unavailableForMs: number;
|
|
219
|
+
tuningVersion: string;
|
|
220
|
+
};
|
|
221
|
+
interface DrivingControllerSnapshot {
|
|
222
|
+
lifecycle: 'stopped' | 'running' | 'destroyed';
|
|
223
|
+
status: CarRunningStatus;
|
|
224
|
+
candidate: CarRunningStatus | null;
|
|
225
|
+
candidateConfirmationCount: number;
|
|
226
|
+
statusCommittedAtMs: number;
|
|
227
|
+
lastAvailableAtMs: number | null;
|
|
228
|
+
unavailableSinceMs: number | null;
|
|
229
|
+
tuningVersion: string;
|
|
230
|
+
}
|
|
231
|
+
interface DrivingStatusClock {
|
|
232
|
+
now(): number;
|
|
233
|
+
setTimeout(callback: () => void, delayMs: number): unknown;
|
|
234
|
+
clearTimeout(handle: unknown): void;
|
|
235
|
+
}
|
|
236
|
+
type DrivingSensorProvider = (signal?: AbortSignal) => UnifiedSensorInfoPayload | Promise<UnifiedSensorInfoPayload>;
|
|
237
|
+
interface DrivingStatusControllerOptions {
|
|
238
|
+
sensorProvider?: DrivingSensorProvider;
|
|
239
|
+
pollIntervalMs?: number;
|
|
240
|
+
unavailableFallbackMs?: number;
|
|
241
|
+
tuning?: DrivingStatusTuningOverrides;
|
|
242
|
+
initialStatus?: CarRunningStatus;
|
|
243
|
+
clock?: DrivingStatusClock;
|
|
244
|
+
onDiagnostic?: (event: DrivingStatusDiagnosticEvent) => void;
|
|
245
|
+
/** Pause on Runtime/visibility/page hooks and resume only if start() is still requested. */
|
|
246
|
+
managePageLifecycle?: boolean;
|
|
247
|
+
}
|
|
248
|
+
interface DrivingStatusController {
|
|
249
|
+
start(): void;
|
|
250
|
+
stop(): void;
|
|
251
|
+
destroy(): void;
|
|
252
|
+
getSnapshot(): DrivingControllerSnapshot;
|
|
253
|
+
subscribe(listener: (event: DrivingStatusEvent) => void): () => void;
|
|
254
|
+
}
|
|
255
|
+
declare const createDrivingStatusController: (options?: DrivingStatusControllerOptions) => DrivingStatusController;
|
|
256
|
+
//#endregion
|
|
257
|
+
//#region src/sensor/driving_expression_player.d.ts
|
|
258
|
+
type DrivingExpressionPlayerErrorCategory = 'invalid_config' | 'network' | 'timeout' | 'decode' | 'unsupported';
|
|
259
|
+
type DrivingExpressionPlayerDiagnosticEvent = {
|
|
260
|
+
type: 'media_ready';
|
|
261
|
+
status: CarRunningStatus;
|
|
262
|
+
kind: StructuredDrivingExpressionMedia['kind'];
|
|
263
|
+
elapsedMs: number;
|
|
264
|
+
} | {
|
|
265
|
+
type: 'media_load_failed';
|
|
266
|
+
status: CarRunningStatus;
|
|
267
|
+
kind: StructuredDrivingExpressionMedia['kind'] | 'unknown';
|
|
268
|
+
category: DrivingExpressionPlayerErrorCategory;
|
|
269
|
+
message: string;
|
|
270
|
+
} | {
|
|
271
|
+
type: 'media_fallback_applied';
|
|
272
|
+
status: CarRunningStatus;
|
|
273
|
+
kind: StructuredDrivingExpressionMedia['kind'];
|
|
274
|
+
};
|
|
275
|
+
interface DrivingExpressionPlayerSnapshot {
|
|
276
|
+
lifecycle: 'active' | 'paused' | 'destroyed';
|
|
277
|
+
status: CarRunningStatus | null;
|
|
278
|
+
phase: 'idle' | 'loading' | 'ready' | 'fallback' | 'error';
|
|
279
|
+
mediaKind: StructuredDrivingExpressionMedia['kind'] | null;
|
|
280
|
+
errorCategory: DrivingExpressionPlayerErrorCategory | null;
|
|
281
|
+
}
|
|
282
|
+
interface DrivingTgsAnimationHandle {
|
|
283
|
+
destroy(): void;
|
|
284
|
+
pause?(): void;
|
|
285
|
+
play?(): void;
|
|
286
|
+
restart?(): void;
|
|
287
|
+
}
|
|
288
|
+
type DrivingTgsRenderer = (container: HTMLElement, animationData: Record<string, unknown>, signal: AbortSignal) => DrivingTgsAnimationHandle | Promise<DrivingTgsAnimationHandle>;
|
|
289
|
+
interface DrivingExpressionPlayerOptions {
|
|
290
|
+
config: DrivingExpressionsConfigInput;
|
|
291
|
+
fallbacks?: Partial<Readonly<Record<CarRunningStatus, StructuredDrivingExpressionMedia>>>;
|
|
292
|
+
loadTimeoutMs?: number;
|
|
293
|
+
retryBackoffMs?: number;
|
|
294
|
+
fit?: 'contain' | 'cover';
|
|
295
|
+
tgsRenderer?: DrivingTgsRenderer;
|
|
296
|
+
fetch?: typeof globalThis.fetch;
|
|
297
|
+
onDiagnostic?: (event: DrivingExpressionPlayerDiagnosticEvent) => void;
|
|
298
|
+
maxTgsCompressedBytes?: number;
|
|
299
|
+
maxTgsJsonBytes?: number;
|
|
300
|
+
maxTgsLayers?: number;
|
|
301
|
+
/** Pause/cancel work on Runtime and page lifecycle hooks. Defaults to true. */
|
|
302
|
+
managePageLifecycle?: boolean;
|
|
303
|
+
}
|
|
304
|
+
interface DrivingExpressionPlayer {
|
|
305
|
+
show(status: CarRunningStatus): Promise<void>;
|
|
306
|
+
pause(): void;
|
|
307
|
+
resume(): void;
|
|
308
|
+
destroy(): void;
|
|
309
|
+
getSnapshot(): DrivingExpressionPlayerSnapshot;
|
|
310
|
+
}
|
|
311
|
+
declare const createDrivingExpressionPlayer: (container: HTMLElement, options: DrivingExpressionPlayerOptions) => DrivingExpressionPlayer;
|
|
312
|
+
//#endregion
|
|
313
|
+
export { AvailableSensorMetric, BATTERY_HEALTH_LABELS, BatteryCapacityValue, BatteryHealth, BatteryPlugged, BatteryStateValue, BatteryStatus, CAR_RUNNING_LABELS, CAR_RUNNING_STATUSES, CAR_RUNNING_STATUS_PRIORITY, CarRunningStatus, CompleteDrivingExpressionsConfig, DEFAULT_DRIVING_STATUS_TUNING, DrivingControllerSnapshot, DrivingExpressionMedia, DrivingExpressionPlayer, DrivingExpressionPlayerDiagnosticEvent, DrivingExpressionPlayerErrorCategory, DrivingExpressionPlayerOptions, DrivingExpressionPlayerSnapshot, DrivingExpressionResolutionError, DrivingExpressionsConfig, DrivingExpressionsConfigError, DrivingExpressionsConfigErrorCode, DrivingExpressionsConfigInput, DrivingSensorProvider, DrivingSnapshotMetrics, DrivingStatusChangeReason, DrivingStatusClock, DrivingStatusController, DrivingStatusControllerOptions, DrivingStatusDiagnosticEvent, DrivingStatusEvent, DrivingStatusTuning, DrivingStatusTuningOverrides, DrivingTgsAnimationHandle, DrivingTgsRenderer, EmojiDrivingExpressionMedia, ImageDrivingExpressionMedia, LivePhotoDrivingExpressionMedia, MediaLibraryRef, OFFICIAL_DRIVING_EXPRESSIONS_CONFIG, OFFICIAL_DRIVING_EXPRESSION_FALLBACKS, OrientationValue, ParseDrivingExpressionsOptions, StructuredDrivingExpressionMedia, TgsDrivingExpressionMedia, UnavailableSensorMetric, UnifiedSensorInfoPayload, UnifiedSensorMetric, UnifiedSensorUnavailableReason, Vector3Value, VideoDrivingExpressionMedia, checkRunningStatus, classifyDrivingMetrics, classifyDrivingSnapshot, createDrivingExpressionPlayer, createDrivingStatusController, extractDrivingSnapshotMetrics, isPublicDrivingMediaUrl, parseDrivingExpressionsConfig, readDrivingExpressionsConfig, resolveDrivingExpression, resolveDrivingExpressionStrict, resolveDrivingStatusTuning, tryParseDrivingExpressionsConfig, unifiedSensorInfo };
|