vue-network-time 1.0.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/LICENSE +21 -0
- package/README.md +257 -0
- package/dist/core/DriftCorrector.d.ts +47 -0
- package/dist/core/DriftCorrector.d.ts.map +1 -0
- package/dist/core/RetryStrategy.d.ts +31 -0
- package/dist/core/RetryStrategy.d.ts.map +1 -0
- package/dist/core/TimeParser.d.ts +32 -0
- package/dist/core/TimeParser.d.ts.map +1 -0
- package/dist/core/TimeSyncClient.d.ts +100 -0
- package/dist/core/TimeSyncClient.d.ts.map +1 -0
- package/dist/core/TimeSyncSingleton.d.ts +36 -0
- package/dist/core/TimeSyncSingleton.d.ts.map +1 -0
- package/dist/core/Timezone.d.ts +39 -0
- package/dist/core/Timezone.d.ts.map +1 -0
- package/dist/core/WorkerClient.d.ts +58 -0
- package/dist/core/WorkerClient.d.ts.map +1 -0
- package/dist/index.d.ts +16 -0
- package/dist/index.d.ts.map +1 -0
- package/dist/types.d.ts +100 -0
- package/dist/types.d.ts.map +1 -0
- package/dist/vue/useNetworkTime.d.ts +37 -0
- package/dist/vue/useNetworkTime.d.ts.map +1 -0
- package/dist/vue-network-time.js +702 -0
- package/dist/vue-network-time.js.map +1 -0
- package/dist/vue-network-time.umd.cjs +3 -0
- package/dist/vue-network-time.umd.cjs.map +1 -0
- package/dist/worker/time.worker.d.ts +2 -0
- package/dist/worker/time.worker.d.ts.map +1 -0
- package/package.json +63 -0
package/LICENSE
ADDED
|
@@ -0,0 +1,21 @@
|
|
|
1
|
+
MIT License
|
|
2
|
+
|
|
3
|
+
Copyright (c) 2026 WatcherDing
|
|
4
|
+
|
|
5
|
+
Permission is hereby granted, free of charge, to any person obtaining a copy
|
|
6
|
+
of this software and associated documentation files (the "Software"), to deal
|
|
7
|
+
in the Software without restriction, including without limitation the rights
|
|
8
|
+
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
|
9
|
+
copies of the Software, and to permit persons to whom the Software is
|
|
10
|
+
furnished to do so, subject to the following conditions:
|
|
11
|
+
|
|
12
|
+
The above copyright notice and this permission notice shall be included in all
|
|
13
|
+
copies or substantial portions of the Software.
|
|
14
|
+
|
|
15
|
+
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
|
16
|
+
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
|
17
|
+
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
|
18
|
+
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
|
19
|
+
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
|
20
|
+
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
|
|
21
|
+
SOFTWARE.
|
package/README.md
ADDED
|
@@ -0,0 +1,257 @@
|
|
|
1
|
+
# Vue Network Time
|
|
2
|
+
|
|
3
|
+
<p align="center">
|
|
4
|
+
<strong>🕐 生产级 Vue 3 网络时间同步 SDK</strong>
|
|
5
|
+
</p>
|
|
6
|
+
|
|
7
|
+
<p align="center">
|
|
8
|
+
支持多时间源、Web Worker、时区格式化等企业级特性
|
|
9
|
+
</p>
|
|
10
|
+
|
|
11
|
+
## ✨ 特性
|
|
12
|
+
|
|
13
|
+
- 🎯 **精确同步** - 基于 NTP 算法的 RTT 时间漂移修正
|
|
14
|
+
- 🔄 **多时间源** - 支持多个时间源,提供 first-success 和 average 两种策略
|
|
15
|
+
- 🚀 **Web Worker** - 后台线程同步,防止浏览器标签页挂起影响时间精度
|
|
16
|
+
- 🌍 **时区支持** - 基于 Intl.DateTimeFormat 的时区格式化
|
|
17
|
+
- 🔁 **自动重试** - 可配置的重试次数和指数退避策略
|
|
18
|
+
- 💾 **单例模式** - 多组件共享同一实例,避免重复请求
|
|
19
|
+
- 📦 **TypeScript** - 完整的类型定义和类型安全
|
|
20
|
+
- 🌲 **Tree-shaking** - 模块化设计,支持按需引入
|
|
21
|
+
- ⚡ **轻量级** - 核心代码约 15-20KB(minified)
|
|
22
|
+
|
|
23
|
+
## 📦 安装
|
|
24
|
+
|
|
25
|
+
```bash
|
|
26
|
+
# npm
|
|
27
|
+
npm install vue-network-time
|
|
28
|
+
|
|
29
|
+
# pnpm
|
|
30
|
+
pnpm add vue-network-time
|
|
31
|
+
|
|
32
|
+
# yarn
|
|
33
|
+
yarn add vue-network-time
|
|
34
|
+
```
|
|
35
|
+
|
|
36
|
+
## 🚀 快速开始
|
|
37
|
+
|
|
38
|
+
```vue
|
|
39
|
+
<template>
|
|
40
|
+
<div>
|
|
41
|
+
<p>当前时间: {{ now }}</p>
|
|
42
|
+
<p>格式化时间: {{ formatted }}</p>
|
|
43
|
+
<p>时间偏移: {{ offset }}ms</p>
|
|
44
|
+
<button @click="start">启动</button>
|
|
45
|
+
<button @click="stop">停止</button>
|
|
46
|
+
</div>
|
|
47
|
+
</template>
|
|
48
|
+
|
|
49
|
+
<script setup lang="ts">
|
|
50
|
+
import { onMounted } from 'vue'
|
|
51
|
+
import { useNetworkTime } from 'vue-network-time'
|
|
52
|
+
|
|
53
|
+
const { now, formatted, offset, running, start, stop, syncNow } = useNetworkTime({
|
|
54
|
+
url: 'https://worldtimeapi.org/api/timezone/Asia/Shanghai',
|
|
55
|
+
timeField: 'unixtime',
|
|
56
|
+
timeFormat: 's',
|
|
57
|
+
timezone: 'Asia/Shanghai',
|
|
58
|
+
syncInterval: 60000,
|
|
59
|
+
debug: true
|
|
60
|
+
})
|
|
61
|
+
|
|
62
|
+
onMounted(() => start())
|
|
63
|
+
</script>
|
|
64
|
+
```
|
|
65
|
+
|
|
66
|
+
## 📖 API 文档
|
|
67
|
+
|
|
68
|
+
### `useNetworkTime(options)`
|
|
69
|
+
|
|
70
|
+
主要的 Vue 3 组合式函数。
|
|
71
|
+
|
|
72
|
+
#### 参数:`NetworkTimeOptions`
|
|
73
|
+
|
|
74
|
+
| 参数 | 类型 | 默认值 | 说明 |
|
|
75
|
+
|------|------|--------|------|
|
|
76
|
+
| `url` | `string` | - | 单个时间源 URL |
|
|
77
|
+
| `urls` | `string[]` | - | 多个时间源 URL |
|
|
78
|
+
| `urlStrategy` | `'first-success' \| 'average'` | `'first-success'` | 多 URL 策略 |
|
|
79
|
+
| `syncInterval` | `number` | `60000` | 同步间隔(毫秒) |
|
|
80
|
+
| `tickInterval` | `number` | `1000` | Tick 间隔(毫秒) |
|
|
81
|
+
| `timezone` | `string` | - | 时区(如 'Asia/Shanghai') |
|
|
82
|
+
| `timeField` | `string \| (resp: any) => number` | `'time'` | 时间字段名或提取函数 |
|
|
83
|
+
| `timeFormat` | `'ms' \| 's' \| 'iso'` | `'ms'` | 时间格式 |
|
|
84
|
+
| `parseTime` | `(resp: any) => number` | - | 自定义解析函数 |
|
|
85
|
+
| `retry` | `RetryConfig` | `{ times: 3, interval: 1000, backoff: true }` | 重试配置 |
|
|
86
|
+
| `offlineMode` | `'local' \| 'freeze' \| 'error'` | `'local'` | 离线模式 |
|
|
87
|
+
| `singleton` | `boolean` | `false` | 是否启用单例模式 |
|
|
88
|
+
| `cacheKey` | `string` | - | 单例缓存键 |
|
|
89
|
+
| `useWorker` | `boolean` | `false` | 是否使用 Web Worker |
|
|
90
|
+
| `debug` | `boolean` | `false` | 是否启用调试日志 |
|
|
91
|
+
| `onError` | `(err: Error) => void` | - | 错误回调 |
|
|
92
|
+
| `onSync` | `(time: number) => void` | - | 同步成功回调 |
|
|
93
|
+
| `onTick` | `(time: number) => void` | - | Tick 回调 |
|
|
94
|
+
|
|
95
|
+
#### 返回值:`UseNetworkTimeReturn`
|
|
96
|
+
|
|
97
|
+
| 属性 | 类型 | 说明 |
|
|
98
|
+
|------|------|------|
|
|
99
|
+
| `now` | `Ref<number>` | 当前时间戳(毫秒) |
|
|
100
|
+
| `formatted` | `Ref<string>` | 格式化后的时间字符串 |
|
|
101
|
+
| `offset` | `Ref<number>` | 时间偏移量(毫秒) |
|
|
102
|
+
| `running` | `Ref<boolean>` | 是否正在运行 |
|
|
103
|
+
| `start` | `() => void` | 启动时间同步 |
|
|
104
|
+
| `stop` | `() => void` | 停止时间同步 |
|
|
105
|
+
| `syncNow` | `() => Promise<void>` | 立即同步 |
|
|
106
|
+
|
|
107
|
+
## 💡 使用示例
|
|
108
|
+
|
|
109
|
+
### 多时间源 + 平均策略
|
|
110
|
+
|
|
111
|
+
```ts
|
|
112
|
+
const { now, offset } = useNetworkTime({
|
|
113
|
+
urls: [
|
|
114
|
+
'https://worldtimeapi.org/api/timezone/Asia/Shanghai',
|
|
115
|
+
'https://timeapi.io/api/Time/current/zone?timeZone=Asia/Shanghai'
|
|
116
|
+
],
|
|
117
|
+
urlStrategy: 'average', // 使用多个时间源的平均值
|
|
118
|
+
timeField: (resp) => {
|
|
119
|
+
// 自定义解析函数,适配不同 API
|
|
120
|
+
if (resp.unixtime) return resp.unixtime * 1000
|
|
121
|
+
if (resp.dateTime) return new Date(resp.dateTime).getTime()
|
|
122
|
+
return Date.now()
|
|
123
|
+
}
|
|
124
|
+
})
|
|
125
|
+
```
|
|
126
|
+
|
|
127
|
+
### Web Worker 模式
|
|
128
|
+
|
|
129
|
+
```ts
|
|
130
|
+
const { now, formatted } = useNetworkTime({
|
|
131
|
+
url: 'https://worldtimeapi.org/api/timezone/Asia/Shanghai',
|
|
132
|
+
useWorker: true, // 在 Worker 中运行,防止标签页挂起
|
|
133
|
+
timezone: 'Asia/Shanghai',
|
|
134
|
+
syncInterval: 60000
|
|
135
|
+
})
|
|
136
|
+
```
|
|
137
|
+
|
|
138
|
+
### 单例模式(多组件共享)
|
|
139
|
+
|
|
140
|
+
```ts
|
|
141
|
+
// 组件 A
|
|
142
|
+
const time1 = useNetworkTime({
|
|
143
|
+
url: 'https://worldtimeapi.org/api/timezone/Asia/Shanghai',
|
|
144
|
+
singleton: true,
|
|
145
|
+
cacheKey: 'global-time'
|
|
146
|
+
})
|
|
147
|
+
|
|
148
|
+
// 组件 B(共享同一实例,不会重复请求)
|
|
149
|
+
const time2 = useNetworkTime({
|
|
150
|
+
url: 'https://worldtimeapi.org/api/timezone/Asia/Shanghai',
|
|
151
|
+
singleton: true,
|
|
152
|
+
cacheKey: 'global-time'
|
|
153
|
+
})
|
|
154
|
+
```
|
|
155
|
+
|
|
156
|
+
### 自定义重试策略
|
|
157
|
+
|
|
158
|
+
```ts
|
|
159
|
+
const { now } = useNetworkTime({
|
|
160
|
+
url: 'https://worldtimeapi.org/api/timezone/Asia/Shanghai',
|
|
161
|
+
retry: {
|
|
162
|
+
times: 5, // 重试 5 次
|
|
163
|
+
interval: 2000, // 初始间隔 2 秒
|
|
164
|
+
backoff: true // 启用指数退避
|
|
165
|
+
}
|
|
166
|
+
})
|
|
167
|
+
```
|
|
168
|
+
|
|
169
|
+
### 离线模式处理
|
|
170
|
+
|
|
171
|
+
```ts
|
|
172
|
+
const { now } = useNetworkTime({
|
|
173
|
+
url: 'https://worldtimeapi.org/api/timezone/Asia/Shanghai',
|
|
174
|
+
offlineMode: 'local', // 'local' | 'freeze' | 'error'
|
|
175
|
+
onError: (error) => {
|
|
176
|
+
console.error('同步失败:', error)
|
|
177
|
+
}
|
|
178
|
+
})
|
|
179
|
+
```
|
|
180
|
+
|
|
181
|
+
## 🔧 核心算法
|
|
182
|
+
|
|
183
|
+
### RTT 时间漂移修正
|
|
184
|
+
|
|
185
|
+
本 SDK 使用类似 NTP 的算法计算时间偏移:
|
|
186
|
+
|
|
187
|
+
```
|
|
188
|
+
offset = serverTime - (requestStart + RTT / 2)
|
|
189
|
+
correctedTime = Date.now() + offset
|
|
190
|
+
```
|
|
191
|
+
|
|
192
|
+
其中:
|
|
193
|
+
- `serverTime`: 服务器返回的时间戳
|
|
194
|
+
- `requestStart`: 请求开始时间
|
|
195
|
+
- `RTT`: 往返时间(Round Trip Time)
|
|
196
|
+
|
|
197
|
+
### 多时间源策略
|
|
198
|
+
|
|
199
|
+
**First-Success(默认)**
|
|
200
|
+
- 按顺序尝试每个时间源
|
|
201
|
+
- 使用第一个成功的响应
|
|
202
|
+
- 速度快,适合对精度要求不高的场景
|
|
203
|
+
|
|
204
|
+
**Average**
|
|
205
|
+
- 并发请求所有时间源
|
|
206
|
+
- 计算所有成功响应的平均偏移量
|
|
207
|
+
- 精度高,适合对时间精度要求高的场景
|
|
208
|
+
|
|
209
|
+
## ⚠️ 注意事项
|
|
210
|
+
|
|
211
|
+
### CORS 要求
|
|
212
|
+
|
|
213
|
+
时间 API 必须支持 CORS,否则会出现跨域错误。推荐的公共时间 API:
|
|
214
|
+
|
|
215
|
+
- [WorldTimeAPI](https://worldtimeapi.org/)
|
|
216
|
+
- [TimeAPI](https://timeapi.io/)
|
|
217
|
+
- [WorldClockAPI](http://worldclockapi.com/)
|
|
218
|
+
|
|
219
|
+
### Web Worker 限制
|
|
220
|
+
|
|
221
|
+
- 需要 HTTPS 环境(生产环境)
|
|
222
|
+
- 某些浏览器可能不支持 Worker
|
|
223
|
+
- Worker 中无法访问 DOM
|
|
224
|
+
|
|
225
|
+
### 时区支持
|
|
226
|
+
|
|
227
|
+
- 依赖浏览器的 `Intl.DateTimeFormat` API
|
|
228
|
+
- 需要现代浏览器支持
|
|
229
|
+
- 时区标识符遵循 IANA 标准
|
|
230
|
+
|
|
231
|
+
## 📊 性能指标
|
|
232
|
+
|
|
233
|
+
- **包大小**: ~15-20KB (minified)
|
|
234
|
+
- **内存占用**: 单实例 ~1-2KB,Worker 额外 ~5KB
|
|
235
|
+
- **网络请求**: 可配置同步间隔,默认 60 秒
|
|
236
|
+
- **时间精度**: ±10-50ms(取决于网络延迟)
|
|
237
|
+
|
|
238
|
+
## 🛠️ 开发
|
|
239
|
+
|
|
240
|
+
```bash
|
|
241
|
+
# 安装依赖
|
|
242
|
+
pnpm install
|
|
243
|
+
|
|
244
|
+
# 类型检查
|
|
245
|
+
pnpm run type-check
|
|
246
|
+
|
|
247
|
+
# 构建
|
|
248
|
+
pnpm run build
|
|
249
|
+
```
|
|
250
|
+
|
|
251
|
+
## 📄 License
|
|
252
|
+
|
|
253
|
+
MIT License © 2026
|
|
254
|
+
|
|
255
|
+
## 🤝 贡献
|
|
256
|
+
|
|
257
|
+
欢迎提交 Issue 和 Pull Request!
|
|
@@ -0,0 +1,47 @@
|
|
|
1
|
+
import type { TimeSyncResponse } from '../types';
|
|
2
|
+
/**
|
|
3
|
+
* 时间漂移修正器
|
|
4
|
+
* 使用 RTT(往返时间)算法计算和修正本地时间偏移
|
|
5
|
+
*/
|
|
6
|
+
export declare class DriftCorrector {
|
|
7
|
+
private offset;
|
|
8
|
+
private lastSyncTime;
|
|
9
|
+
private rttHistory;
|
|
10
|
+
private readonly maxHistorySize;
|
|
11
|
+
/**
|
|
12
|
+
* 计算时间偏移量
|
|
13
|
+
* 算法:offset = serverTime - (requestStart + RTT / 2)
|
|
14
|
+
*
|
|
15
|
+
* @param response 时间同步响应
|
|
16
|
+
* @returns 计算出的偏移量(毫秒)
|
|
17
|
+
*/
|
|
18
|
+
calculateOffset(response: TimeSyncResponse): number;
|
|
19
|
+
/**
|
|
20
|
+
* 计算多个时间源的平均偏移量
|
|
21
|
+
* @param responses 多个时间同步响应
|
|
22
|
+
* @returns 平均偏移量
|
|
23
|
+
*/
|
|
24
|
+
calculateAverageOffset(responses: TimeSyncResponse[]): number;
|
|
25
|
+
/**
|
|
26
|
+
* 获取当前修正后的时间
|
|
27
|
+
* @returns 修正后的时间戳(毫秒)
|
|
28
|
+
*/
|
|
29
|
+
getCorrectedTime(): number;
|
|
30
|
+
/**
|
|
31
|
+
* 获取当前偏移量
|
|
32
|
+
*/
|
|
33
|
+
getOffset(): number;
|
|
34
|
+
/**
|
|
35
|
+
* 获取上次同步时间
|
|
36
|
+
*/
|
|
37
|
+
getLastSyncTime(): number;
|
|
38
|
+
/**
|
|
39
|
+
* 获取平均 RTT
|
|
40
|
+
*/
|
|
41
|
+
getAverageRTT(): number;
|
|
42
|
+
/**
|
|
43
|
+
* 重置偏移量
|
|
44
|
+
*/
|
|
45
|
+
reset(): void;
|
|
46
|
+
}
|
|
47
|
+
//# sourceMappingURL=DriftCorrector.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"DriftCorrector.d.ts","sourceRoot":"","sources":["../../src/core/DriftCorrector.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,gBAAgB,EAAE,MAAM,UAAU,CAAA;AAEhD;;;GAGG;AACH,qBAAa,cAAc;IACzB,OAAO,CAAC,MAAM,CAAY;IAC1B,OAAO,CAAC,YAAY,CAAY;IAChC,OAAO,CAAC,UAAU,CAAe;IACjC,OAAO,CAAC,QAAQ,CAAC,cAAc,CAAK;IAEpC;;;;;;OAMG;IACH,eAAe,CAAC,QAAQ,EAAE,gBAAgB,GAAG,MAAM;IA4BnD;;;;OAIG;IACH,sBAAsB,CAAC,SAAS,EAAE,gBAAgB,EAAE,GAAG,MAAM;IA+B7D;;;OAGG;IACH,gBAAgB,IAAI,MAAM;IAI1B;;OAEG;IACH,SAAS,IAAI,MAAM;IAInB;;OAEG;IACH,eAAe,IAAI,MAAM;IAIzB;;OAEG;IACH,aAAa,IAAI,MAAM;IAKvB;;OAEG;IACH,KAAK,IAAI,IAAI;CAKd"}
|
|
@@ -0,0 +1,31 @@
|
|
|
1
|
+
import type { RetryConfig } from '../types';
|
|
2
|
+
/**
|
|
3
|
+
* 重试策略
|
|
4
|
+
* 支持固定间隔和指数退避
|
|
5
|
+
*/
|
|
6
|
+
export declare class RetryStrategy {
|
|
7
|
+
private currentAttempt;
|
|
8
|
+
private readonly config;
|
|
9
|
+
constructor(config?: RetryConfig);
|
|
10
|
+
/**
|
|
11
|
+
* 执行带重试的异步操作
|
|
12
|
+
* @param fn 要执行的异步函数
|
|
13
|
+
* @param onRetry 重试时的回调
|
|
14
|
+
* @returns 操作结果
|
|
15
|
+
*/
|
|
16
|
+
execute<T>(fn: () => Promise<T>, onRetry?: (attempt: number, error: Error) => void): Promise<T>;
|
|
17
|
+
/**
|
|
18
|
+
* 等待指定时间
|
|
19
|
+
* 如果启用指数退避,等待时间会随重试次数增加
|
|
20
|
+
*/
|
|
21
|
+
private wait;
|
|
22
|
+
/**
|
|
23
|
+
* 获取当前重试次数
|
|
24
|
+
*/
|
|
25
|
+
getCurrentAttempt(): number;
|
|
26
|
+
/**
|
|
27
|
+
* 重置重试计数
|
|
28
|
+
*/
|
|
29
|
+
reset(): void;
|
|
30
|
+
}
|
|
31
|
+
//# sourceMappingURL=RetryStrategy.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"RetryStrategy.d.ts","sourceRoot":"","sources":["../../src/core/RetryStrategy.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,WAAW,EAAE,MAAM,UAAU,CAAA;AAE3C;;;GAGG;AACH,qBAAa,aAAa;IACxB,OAAO,CAAC,cAAc,CAAY;IAClC,OAAO,CAAC,QAAQ,CAAC,MAAM,CAAuB;gBAElC,MAAM,GAAE,WAA0C;IAQ9D;;;;;OAKG;IACG,OAAO,CAAC,CAAC,EACb,EAAE,EAAE,MAAM,OAAO,CAAC,CAAC,CAAC,EACpB,OAAO,CAAC,EAAE,CAAC,OAAO,EAAE,MAAM,EAAE,KAAK,EAAE,KAAK,KAAK,IAAI,GAChD,OAAO,CAAC,CAAC,CAAC;IA6Bb;;;OAGG;IACH,OAAO,CAAC,IAAI;IAQZ;;OAEG;IACH,iBAAiB,IAAI,MAAM;IAI3B;;OAEG;IACH,KAAK,IAAI,IAAI;CAGd"}
|
|
@@ -0,0 +1,32 @@
|
|
|
1
|
+
import type { TimeFormat } from '../types';
|
|
2
|
+
/**
|
|
3
|
+
* 时间解析器
|
|
4
|
+
* 负责从各种格式中解析时间戳
|
|
5
|
+
*/
|
|
6
|
+
export declare class TimeParser {
|
|
7
|
+
/**
|
|
8
|
+
* 从响应中解析时间
|
|
9
|
+
* @param response 服务器响应
|
|
10
|
+
* @param timeField 时间字段名或提取函数
|
|
11
|
+
* @param timeFormat 时间格式
|
|
12
|
+
* @param parseTime 自定义解析函数
|
|
13
|
+
* @returns 时间戳(毫秒)
|
|
14
|
+
*/
|
|
15
|
+
static parse(response: any, timeField?: string | ((resp: any) => number), timeFormat?: TimeFormat, parseTime?: (resp: any) => number): number;
|
|
16
|
+
/**
|
|
17
|
+
* 标准化时间值为毫秒时间戳
|
|
18
|
+
*/
|
|
19
|
+
private static normalize;
|
|
20
|
+
/**
|
|
21
|
+
* 获取嵌套对象的值
|
|
22
|
+
* 支持 'data.time' 这样的路径
|
|
23
|
+
*/
|
|
24
|
+
private static getNestedValue;
|
|
25
|
+
/**
|
|
26
|
+
* 验证时间戳是否合理
|
|
27
|
+
* @param timestamp 时间戳(毫秒)
|
|
28
|
+
* @returns 是否有效
|
|
29
|
+
*/
|
|
30
|
+
static isValidTimestamp(timestamp: number): boolean;
|
|
31
|
+
}
|
|
32
|
+
//# sourceMappingURL=TimeParser.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"TimeParser.d.ts","sourceRoot":"","sources":["../../src/core/TimeParser.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,UAAU,EAAE,MAAM,UAAU,CAAA;AAE1C;;;GAGG;AACH,qBAAa,UAAU;IACrB;;;;;;;OAOG;IACH,MAAM,CAAC,KAAK,CACV,QAAQ,EAAE,GAAG,EACb,SAAS,CAAC,EAAE,MAAM,GAAG,CAAC,CAAC,IAAI,EAAE,GAAG,KAAK,MAAM,CAAC,EAC5C,UAAU,GAAE,UAAiB,EAC7B,SAAS,CAAC,EAAE,CAAC,IAAI,EAAE,GAAG,KAAK,MAAM,GAChC,MAAM;IAqBT;;OAEG;IACH,OAAO,CAAC,MAAM,CAAC,SAAS;IAgCxB;;;OAGG;IACH,OAAO,CAAC,MAAM,CAAC,cAAc;IAI7B;;;;OAIG;IACH,MAAM,CAAC,gBAAgB,CAAC,SAAS,EAAE,MAAM,GAAG,OAAO;CAYpD"}
|
|
@@ -0,0 +1,100 @@
|
|
|
1
|
+
import type { NetworkTimeOptions } from '../types';
|
|
2
|
+
/**
|
|
3
|
+
* 时间同步客户端
|
|
4
|
+
* 核心时间同步逻辑的协调器
|
|
5
|
+
*/
|
|
6
|
+
export declare class TimeSyncClient {
|
|
7
|
+
private options;
|
|
8
|
+
private driftCorrector;
|
|
9
|
+
private retryStrategy;
|
|
10
|
+
private timezone;
|
|
11
|
+
private syncTimer;
|
|
12
|
+
private tickTimer;
|
|
13
|
+
private running;
|
|
14
|
+
private currentTime;
|
|
15
|
+
private formattedTime;
|
|
16
|
+
private onTimeUpdate?;
|
|
17
|
+
private onFormattedUpdate?;
|
|
18
|
+
private onOffsetUpdate?;
|
|
19
|
+
private onRunningUpdate?;
|
|
20
|
+
constructor(options: NetworkTimeOptions);
|
|
21
|
+
/**
|
|
22
|
+
* 合并默认选项
|
|
23
|
+
*/
|
|
24
|
+
private mergeDefaultOptions;
|
|
25
|
+
/**
|
|
26
|
+
* 启动时间同步
|
|
27
|
+
*/
|
|
28
|
+
start(): void;
|
|
29
|
+
/**
|
|
30
|
+
* 停止时间同步
|
|
31
|
+
*/
|
|
32
|
+
stop(): void;
|
|
33
|
+
/**
|
|
34
|
+
* 立即执行同步
|
|
35
|
+
*/
|
|
36
|
+
syncNow(): Promise<void>;
|
|
37
|
+
/**
|
|
38
|
+
* 执行时间同步
|
|
39
|
+
*/
|
|
40
|
+
private performSync;
|
|
41
|
+
/**
|
|
42
|
+
* 第一个成功策略
|
|
43
|
+
*/
|
|
44
|
+
private syncFirstSuccess;
|
|
45
|
+
/**
|
|
46
|
+
* 平均值策略
|
|
47
|
+
*/
|
|
48
|
+
private syncAverage;
|
|
49
|
+
/**
|
|
50
|
+
* 从单个 URL 获取时间
|
|
51
|
+
*/
|
|
52
|
+
private fetchTime;
|
|
53
|
+
/**
|
|
54
|
+
* Tick 更新
|
|
55
|
+
*/
|
|
56
|
+
private tick;
|
|
57
|
+
/**
|
|
58
|
+
* 处理同步错误
|
|
59
|
+
*/
|
|
60
|
+
private handleSyncError;
|
|
61
|
+
/**
|
|
62
|
+
* 设置回调函数
|
|
63
|
+
*/
|
|
64
|
+
onUpdate(callbacks: {
|
|
65
|
+
onTime?: (time: number) => void;
|
|
66
|
+
onFormatted?: (formatted: string) => void;
|
|
67
|
+
onOffset?: (offset: number) => void;
|
|
68
|
+
onRunning?: (running: boolean) => void;
|
|
69
|
+
}): void;
|
|
70
|
+
/**
|
|
71
|
+
* 更新时间
|
|
72
|
+
*/
|
|
73
|
+
private updateTime;
|
|
74
|
+
/**
|
|
75
|
+
* 更新格式化时间
|
|
76
|
+
*/
|
|
77
|
+
private updateFormatted;
|
|
78
|
+
/**
|
|
79
|
+
* 更新偏移量
|
|
80
|
+
*/
|
|
81
|
+
private updateOffset;
|
|
82
|
+
/**
|
|
83
|
+
* 更新运行状态
|
|
84
|
+
*/
|
|
85
|
+
private updateRunning;
|
|
86
|
+
/**
|
|
87
|
+
* 获取当前状态
|
|
88
|
+
*/
|
|
89
|
+
getState(): {
|
|
90
|
+
now: number;
|
|
91
|
+
offset: number;
|
|
92
|
+
running: boolean;
|
|
93
|
+
formatted: string;
|
|
94
|
+
};
|
|
95
|
+
/**
|
|
96
|
+
* 日志输出
|
|
97
|
+
*/
|
|
98
|
+
private log;
|
|
99
|
+
}
|
|
100
|
+
//# sourceMappingURL=TimeSyncClient.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"TimeSyncClient.d.ts","sourceRoot":"","sources":["../../src/core/TimeSyncClient.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,kBAAkB,EAAoB,MAAM,UAAU,CAAA;AAkBpE;;;GAGG;AACH,qBAAa,cAAc;IACzB,OAAO,CAAC,OAAO,CAA8B;IAC7C,OAAO,CAAC,cAAc,CAAgB;IACtC,OAAO,CAAC,aAAa,CAAe;IACpC,OAAO,CAAC,QAAQ,CAAwB;IAExC,OAAO,CAAC,SAAS,CAAsB;IACvC,OAAO,CAAC,SAAS,CAAsB;IACvC,OAAO,CAAC,OAAO,CAAiB;IAEhC,OAAO,CAAC,WAAW,CAAqB;IACxC,OAAO,CAAC,aAAa,CAAa;IAGlC,OAAO,CAAC,YAAY,CAAC,CAAwB;IAC7C,OAAO,CAAC,iBAAiB,CAAC,CAA6B;IACvD,OAAO,CAAC,cAAc,CAAC,CAA0B;IACjD,OAAO,CAAC,eAAe,CAAC,CAA4B;gBAExC,OAAO,EAAE,kBAAkB;IAgBvC;;OAEG;IACH,OAAO,CAAC,mBAAmB;IA0C3B;;OAEG;IACH,KAAK,IAAI,IAAI;IA4Bb;;OAEG;IACH,IAAI,IAAI,IAAI;IAqBZ;;OAEG;IACG,OAAO,IAAI,OAAO,CAAC,IAAI,CAAC;IAiB9B;;OAEG;YACW,WAAW;IAgBzB;;OAEG;YACW,gBAAgB;IAe9B;;OAEG;YACW,WAAW;IAuBzB;;OAEG;YACW,SAAS;IAwDvB;;OAEG;IACH,OAAO,CAAC,IAAI;IAgBZ;;OAEG;IACH,OAAO,CAAC,eAAe;IAmBvB;;OAEG;IACH,QAAQ,CAAC,SAAS,EAAE;QAClB,MAAM,CAAC,EAAE,CAAC,IAAI,EAAE,MAAM,KAAK,IAAI,CAAA;QAC/B,WAAW,CAAC,EAAE,CAAC,SAAS,EAAE,MAAM,KAAK,IAAI,CAAA;QACzC,QAAQ,CAAC,EAAE,CAAC,MAAM,EAAE,MAAM,KAAK,IAAI,CAAA;QACnC,SAAS,CAAC,EAAE,CAAC,OAAO,EAAE,OAAO,KAAK,IAAI,CAAA;KACvC,GAAG,IAAI;IAOR;;OAEG;IACH,OAAO,CAAC,UAAU;IAIlB;;OAEG;IACH,OAAO,CAAC,eAAe;IAIvB;;OAEG;IACH,OAAO,CAAC,YAAY;IAIpB;;OAEG;IACH,OAAO,CAAC,aAAa;IAIrB;;OAEG;IACH,QAAQ;;;;;;IASR;;OAEG;IACH,OAAO,CAAC,GAAG;CAKZ"}
|
|
@@ -0,0 +1,36 @@
|
|
|
1
|
+
import type { NetworkTimeOptions } from '../types';
|
|
2
|
+
import { TimeSyncClient } from './TimeSyncClient';
|
|
3
|
+
/**
|
|
4
|
+
* 时间同步单例管理器
|
|
5
|
+
* 用于在多个组件间共享同一个时间同步实例
|
|
6
|
+
*/
|
|
7
|
+
export declare class TimeSyncSingleton {
|
|
8
|
+
private static instances;
|
|
9
|
+
private static refCounts;
|
|
10
|
+
/**
|
|
11
|
+
* 获取或创建单例实例
|
|
12
|
+
* @param options 配置选项
|
|
13
|
+
* @returns 时间同步客户端实例
|
|
14
|
+
*/
|
|
15
|
+
static getInstance(options: NetworkTimeOptions): TimeSyncClient;
|
|
16
|
+
/**
|
|
17
|
+
* 释放实例引用
|
|
18
|
+
* 当引用计数归零时,销毁实例
|
|
19
|
+
* @param options 配置选项
|
|
20
|
+
*/
|
|
21
|
+
static releaseInstance(options: NetworkTimeOptions): void;
|
|
22
|
+
/**
|
|
23
|
+
* 生成缓存键
|
|
24
|
+
* 基于 URL 和主要配置生成唯一键
|
|
25
|
+
*/
|
|
26
|
+
private static generateKey;
|
|
27
|
+
/**
|
|
28
|
+
* 清除所有实例(用于测试或重置)
|
|
29
|
+
*/
|
|
30
|
+
static clearAll(): void;
|
|
31
|
+
/**
|
|
32
|
+
* 获取当前实例数量
|
|
33
|
+
*/
|
|
34
|
+
static getInstanceCount(): number;
|
|
35
|
+
}
|
|
36
|
+
//# sourceMappingURL=TimeSyncSingleton.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"TimeSyncSingleton.d.ts","sourceRoot":"","sources":["../../src/core/TimeSyncSingleton.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,kBAAkB,EAAE,MAAM,UAAU,CAAA;AAClD,OAAO,EAAE,cAAc,EAAE,MAAM,kBAAkB,CAAA;AAEjD;;;GAGG;AACH,qBAAa,iBAAiB;IAC5B,OAAO,CAAC,MAAM,CAAC,SAAS,CAAyC;IACjE,OAAO,CAAC,MAAM,CAAC,SAAS,CAAiC;IAEzD;;;;OAIG;IACH,MAAM,CAAC,WAAW,CAAC,OAAO,EAAE,kBAAkB,GAAG,cAAc;IAkB/D;;;;OAIG;IACH,MAAM,CAAC,eAAe,CAAC,OAAO,EAAE,kBAAkB,GAAG,IAAI;IAkBzD;;;OAGG;IACH,OAAO,CAAC,MAAM,CAAC,WAAW;IAS1B;;OAEG;IACH,MAAM,CAAC,QAAQ,IAAI,IAAI;IAMvB;;OAEG;IACH,MAAM,CAAC,gBAAgB,IAAI,MAAM;CAGlC"}
|
|
@@ -0,0 +1,39 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* 时区格式化器
|
|
3
|
+
* 使用 Intl.DateTimeFormat 进行时区转换和格式化
|
|
4
|
+
*/
|
|
5
|
+
export declare class Timezone {
|
|
6
|
+
private formatter;
|
|
7
|
+
private timezone;
|
|
8
|
+
constructor(timezone?: string);
|
|
9
|
+
/**
|
|
10
|
+
* 创建格式化器
|
|
11
|
+
*/
|
|
12
|
+
private createFormatter;
|
|
13
|
+
/**
|
|
14
|
+
* 格式化时间戳
|
|
15
|
+
* @param timestamp 时间戳(毫秒)
|
|
16
|
+
* @returns 格式化后的时间字符串
|
|
17
|
+
*/
|
|
18
|
+
format(timestamp: number): string;
|
|
19
|
+
/**
|
|
20
|
+
* 使用自定义选项格式化
|
|
21
|
+
* @param timestamp 时间戳(毫秒)
|
|
22
|
+
* @param options Intl.DateTimeFormat 选项
|
|
23
|
+
* @returns 格式化后的时间字符串
|
|
24
|
+
*/
|
|
25
|
+
formatCustom(timestamp: number, options: Intl.DateTimeFormatOptions): string;
|
|
26
|
+
/**
|
|
27
|
+
* 获取当前时区
|
|
28
|
+
*/
|
|
29
|
+
getTimezone(): string;
|
|
30
|
+
/**
|
|
31
|
+
* 设置新时区
|
|
32
|
+
*/
|
|
33
|
+
setTimezone(timezone: string): void;
|
|
34
|
+
/**
|
|
35
|
+
* 验证时区是否有效
|
|
36
|
+
*/
|
|
37
|
+
static isValidTimezone(timezone: string): boolean;
|
|
38
|
+
}
|
|
39
|
+
//# sourceMappingURL=Timezone.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"Timezone.d.ts","sourceRoot":"","sources":["../../src/core/Timezone.ts"],"names":[],"mappings":"AAAA;;;GAGG;AACH,qBAAa,QAAQ;IACnB,OAAO,CAAC,SAAS,CAAmC;IACpD,OAAO,CAAC,QAAQ,CAAQ;gBAEZ,QAAQ,GAAE,MAAc;IAKpC;;OAEG;IACH,OAAO,CAAC,eAAe;IA4BvB;;;;OAIG;IACH,MAAM,CAAC,SAAS,EAAE,MAAM,GAAG,MAAM;IAajC;;;;;OAKG;IACH,YAAY,CAAC,SAAS,EAAE,MAAM,EAAE,OAAO,EAAE,IAAI,CAAC,qBAAqB,GAAG,MAAM;IAa5E;;OAEG;IACH,WAAW,IAAI,MAAM;IAIrB;;OAEG;IACH,WAAW,CAAC,QAAQ,EAAE,MAAM,GAAG,IAAI;IAKnC;;OAEG;IACH,MAAM,CAAC,eAAe,CAAC,QAAQ,EAAE,MAAM,GAAG,OAAO;CAQlD"}
|
|
@@ -0,0 +1,58 @@
|
|
|
1
|
+
import type { NetworkTimeOptions } from '../types';
|
|
2
|
+
/**
|
|
3
|
+
* Worker 客户端
|
|
4
|
+
* 主线程与 Worker 线程的通信接口
|
|
5
|
+
*/
|
|
6
|
+
export declare class WorkerClient {
|
|
7
|
+
private worker;
|
|
8
|
+
private options;
|
|
9
|
+
private onTick?;
|
|
10
|
+
private onSynced?;
|
|
11
|
+
private onError?;
|
|
12
|
+
constructor(options: NetworkTimeOptions);
|
|
13
|
+
/**
|
|
14
|
+
* 初始化 Worker
|
|
15
|
+
*/
|
|
16
|
+
init(): Promise<void>;
|
|
17
|
+
/**
|
|
18
|
+
* 启动 Worker
|
|
19
|
+
*/
|
|
20
|
+
start(): void;
|
|
21
|
+
/**
|
|
22
|
+
* 停止 Worker
|
|
23
|
+
*/
|
|
24
|
+
stop(): void;
|
|
25
|
+
/**
|
|
26
|
+
* 立即同步
|
|
27
|
+
*/
|
|
28
|
+
syncNow(): void;
|
|
29
|
+
/**
|
|
30
|
+
* 销毁 Worker
|
|
31
|
+
*/
|
|
32
|
+
destroy(): void;
|
|
33
|
+
/**
|
|
34
|
+
* 设置回调函数
|
|
35
|
+
*/
|
|
36
|
+
setCallbacks(callbacks: {
|
|
37
|
+
onTick?: (time: number, offset: number) => void;
|
|
38
|
+
onSynced?: (offset: number) => void;
|
|
39
|
+
onError?: (error: Error) => void;
|
|
40
|
+
}): void;
|
|
41
|
+
/**
|
|
42
|
+
* 发送消息到 Worker
|
|
43
|
+
*/
|
|
44
|
+
private postMessage;
|
|
45
|
+
/**
|
|
46
|
+
* 处理来自 Worker 的消息
|
|
47
|
+
*/
|
|
48
|
+
private handleMessage;
|
|
49
|
+
/**
|
|
50
|
+
* 处理 Worker 错误
|
|
51
|
+
*/
|
|
52
|
+
private handleError;
|
|
53
|
+
/**
|
|
54
|
+
* 检查 Worker 是否可用
|
|
55
|
+
*/
|
|
56
|
+
static isSupported(): boolean;
|
|
57
|
+
}
|
|
58
|
+
//# sourceMappingURL=WorkerClient.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"WorkerClient.d.ts","sourceRoot":"","sources":["../../src/core/WorkerClient.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,kBAAkB,EAAiB,MAAM,UAAU,CAAA;AAEjE;;;GAGG;AACH,qBAAa,YAAY;IACvB,OAAO,CAAC,MAAM,CAAsB;IACpC,OAAO,CAAC,OAAO,CAAoB;IAGnC,OAAO,CAAC,MAAM,CAAC,CAAwC;IACvD,OAAO,CAAC,QAAQ,CAAC,CAA0B;IAC3C,OAAO,CAAC,OAAO,CAAC,CAAwB;gBAE5B,OAAO,EAAE,kBAAkB;IAIvC;;OAEG;IACG,IAAI,IAAI,OAAO,CAAC,IAAI,CAAC;IAwB3B;;OAEG;IACH,KAAK,IAAI,IAAI;IAIb;;OAEG;IACH,IAAI,IAAI,IAAI;IAIZ;;OAEG;IACH,OAAO,IAAI,IAAI;IAIf;;OAEG;IACH,OAAO,IAAI,IAAI;IAQf;;OAEG;IACH,YAAY,CAAC,SAAS,EAAE;QACtB,MAAM,CAAC,EAAE,CAAC,IAAI,EAAE,MAAM,EAAE,MAAM,EAAE,MAAM,KAAK,IAAI,CAAA;QAC/C,QAAQ,CAAC,EAAE,CAAC,MAAM,EAAE,MAAM,KAAK,IAAI,CAAA;QACnC,OAAO,CAAC,EAAE,CAAC,KAAK,EAAE,KAAK,KAAK,IAAI,CAAA;KACjC,GAAG,IAAI;IAMR;;OAEG;IACH,OAAO,CAAC,WAAW;IASnB;;OAEG;IACH,OAAO,CAAC,aAAa;IA2BrB;;OAEG;IACH,OAAO,CAAC,WAAW;IAOnB;;OAEG;IACH,MAAM,CAAC,WAAW,IAAI,OAAO;CAG9B"}
|
package/dist/index.d.ts
ADDED
|
@@ -0,0 +1,16 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Vue Network Time - 生产级网络时间同步 SDK
|
|
3
|
+
*
|
|
4
|
+
* @packageDocumentation
|
|
5
|
+
*/
|
|
6
|
+
export { useNetworkTime } from './vue/useNetworkTime';
|
|
7
|
+
export type { UseNetworkTimeReturn } from './vue/useNetworkTime';
|
|
8
|
+
export type { NetworkTimeOptions, TimeSyncState, TimeSyncResponse, TimeSourceStrategy, TimeFormat, OfflineMode, RetryConfig, WorkerMessage, WorkerMessageType } from './types';
|
|
9
|
+
export { TimeSyncClient } from './core/TimeSyncClient';
|
|
10
|
+
export { TimeSyncSingleton } from './core/TimeSyncSingleton';
|
|
11
|
+
export { TimeParser } from './core/TimeParser';
|
|
12
|
+
export { DriftCorrector } from './core/DriftCorrector';
|
|
13
|
+
export { RetryStrategy } from './core/RetryStrategy';
|
|
14
|
+
export { Timezone } from './core/Timezone';
|
|
15
|
+
export { WorkerClient } from './core/WorkerClient';
|
|
16
|
+
//# sourceMappingURL=index.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":"AAAA;;;;GAIG;AAGH,OAAO,EAAE,cAAc,EAAE,MAAM,sBAAsB,CAAA;AACrD,YAAY,EAAE,oBAAoB,EAAE,MAAM,sBAAsB,CAAA;AAGhE,YAAY,EACV,kBAAkB,EAClB,aAAa,EACb,gBAAgB,EAChB,kBAAkB,EAClB,UAAU,EACV,WAAW,EACX,WAAW,EACX,aAAa,EACb,iBAAiB,EAClB,MAAM,SAAS,CAAA;AAGhB,OAAO,EAAE,cAAc,EAAE,MAAM,uBAAuB,CAAA;AACtD,OAAO,EAAE,iBAAiB,EAAE,MAAM,0BAA0B,CAAA;AAC5D,OAAO,EAAE,UAAU,EAAE,MAAM,mBAAmB,CAAA;AAC9C,OAAO,EAAE,cAAc,EAAE,MAAM,uBAAuB,CAAA;AACtD,OAAO,EAAE,aAAa,EAAE,MAAM,sBAAsB,CAAA;AACpD,OAAO,EAAE,QAAQ,EAAE,MAAM,iBAAiB,CAAA;AAC1C,OAAO,EAAE,YAAY,EAAE,MAAM,qBAAqB,CAAA"}
|