@planet-matrix/mobius-model 0.6.0 → 0.10.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.
Files changed (258) hide show
  1. package/CHANGELOG.md +50 -0
  2. package/oxlint.config.ts +1 -2
  3. package/package.json +29 -17
  4. package/scripts/build.ts +2 -52
  5. package/src/ai/README.md +1 -0
  6. package/src/ai/ai.ts +107 -0
  7. package/src/ai/chat-completion-ai/aihubmix-chat-completion.ts +78 -0
  8. package/src/ai/chat-completion-ai/chat-completion-ai.ts +270 -0
  9. package/src/ai/chat-completion-ai/chat-completion.ts +189 -0
  10. package/src/ai/chat-completion-ai/index.ts +7 -0
  11. package/src/ai/chat-completion-ai/lingyiwanwu-chat-completion.ts +78 -0
  12. package/src/ai/chat-completion-ai/ohmygpt-chat-completion.ts +78 -0
  13. package/src/ai/chat-completion-ai/openai-next-chat-completion.ts +78 -0
  14. package/src/ai/embedding-ai/embedding-ai.ts +63 -0
  15. package/src/ai/embedding-ai/embedding.ts +50 -0
  16. package/src/ai/embedding-ai/index.ts +4 -0
  17. package/src/ai/embedding-ai/openai-next-embedding.ts +23 -0
  18. package/src/ai/index.ts +4 -0
  19. package/src/aio/README.md +100 -0
  20. package/src/aio/content.ts +141 -0
  21. package/src/aio/index.ts +3 -0
  22. package/src/aio/json.ts +127 -0
  23. package/src/aio/prompt.ts +246 -0
  24. package/src/basic/README.md +20 -15
  25. package/src/basic/error.ts +19 -5
  26. package/src/basic/function.ts +2 -2
  27. package/src/basic/index.ts +1 -0
  28. package/src/basic/promise.ts +141 -71
  29. package/src/basic/schedule.ts +111 -0
  30. package/src/basic/stream.ts +135 -25
  31. package/src/credential/README.md +107 -0
  32. package/src/credential/api-key.ts +158 -0
  33. package/src/credential/bearer.ts +73 -0
  34. package/src/credential/index.ts +4 -0
  35. package/src/credential/json-web-token.ts +96 -0
  36. package/src/credential/password.ts +170 -0
  37. package/src/cron/README.md +86 -0
  38. package/src/cron/cron.ts +87 -0
  39. package/src/cron/index.ts +1 -0
  40. package/src/drizzle/README.md +1 -0
  41. package/src/drizzle/drizzle.ts +1 -0
  42. package/src/drizzle/helper.ts +47 -0
  43. package/src/drizzle/index.ts +5 -0
  44. package/src/drizzle/infer.ts +52 -0
  45. package/src/drizzle/kysely.ts +8 -0
  46. package/src/drizzle/pagination.ts +198 -0
  47. package/src/email/README.md +1 -0
  48. package/src/email/index.ts +1 -0
  49. package/src/email/resend.ts +25 -0
  50. package/src/event/class-event-proxy.ts +5 -6
  51. package/src/event/common.ts +13 -3
  52. package/src/event/event-manager.ts +3 -3
  53. package/src/event/instance-event-proxy.ts +5 -6
  54. package/src/event/internal.ts +4 -4
  55. package/src/exception/README.md +28 -19
  56. package/src/exception/error/error.ts +123 -0
  57. package/src/exception/error/index.ts +2 -0
  58. package/src/exception/error/match.ts +38 -0
  59. package/src/exception/error/must-fix.ts +17 -0
  60. package/src/exception/index.ts +2 -0
  61. package/src/file-system/find.ts +53 -0
  62. package/src/file-system/index.ts +2 -0
  63. package/src/file-system/path.ts +76 -0
  64. package/src/file-system/resolve.ts +22 -0
  65. package/src/form/README.md +25 -0
  66. package/src/form/index.ts +1 -0
  67. package/src/form/inputor-controller/base.ts +861 -0
  68. package/src/form/inputor-controller/boolean.ts +39 -0
  69. package/src/form/inputor-controller/file.ts +39 -0
  70. package/src/form/inputor-controller/form.ts +179 -0
  71. package/src/form/inputor-controller/helper.ts +117 -0
  72. package/src/form/inputor-controller/index.ts +17 -0
  73. package/src/form/inputor-controller/multi-select.ts +99 -0
  74. package/src/form/inputor-controller/number.ts +116 -0
  75. package/src/form/inputor-controller/select.ts +109 -0
  76. package/src/form/inputor-controller/text.ts +82 -0
  77. package/src/http/READMD.md +1 -0
  78. package/src/http/api/api-core.ts +84 -0
  79. package/src/http/api/api-handler.ts +79 -0
  80. package/src/http/api/api-host.ts +47 -0
  81. package/src/http/api/api-result.ts +56 -0
  82. package/src/http/api/api-schema.ts +154 -0
  83. package/src/http/api/api-server.ts +130 -0
  84. package/src/http/api/api-test.ts +142 -0
  85. package/src/http/api/api-type.ts +34 -0
  86. package/src/http/api/api.ts +81 -0
  87. package/src/http/api/index.ts +11 -0
  88. package/src/http/api-adapter/api-core-node-http.ts +260 -0
  89. package/src/http/api-adapter/api-host-node-http.ts +156 -0
  90. package/src/http/api-adapter/api-result-arktype.ts +294 -0
  91. package/src/http/api-adapter/api-result-zod.ts +286 -0
  92. package/src/http/api-adapter/index.ts +5 -0
  93. package/src/http/bin/gen-api-list/gen-api-list.ts +126 -0
  94. package/src/http/bin/gen-api-list/index.ts +1 -0
  95. package/src/http/bin/gen-api-test/gen-api-test.ts +136 -0
  96. package/src/http/bin/gen-api-test/index.ts +1 -0
  97. package/src/http/bin/gen-api-type/calc-code.ts +25 -0
  98. package/src/http/bin/gen-api-type/gen-api-type.ts +127 -0
  99. package/src/http/bin/gen-api-type/index.ts +2 -0
  100. package/src/http/bin/index.ts +2 -0
  101. package/src/http/index.ts +3 -0
  102. package/src/huawei/README.md +1 -0
  103. package/src/huawei/index.ts +2 -0
  104. package/src/huawei/moderation/index.ts +1 -0
  105. package/src/huawei/moderation/moderation.ts +355 -0
  106. package/src/huawei/obs/esdk-obs-nodejs.d.ts +87 -0
  107. package/src/huawei/obs/index.ts +1 -0
  108. package/src/huawei/obs/obs.ts +42 -0
  109. package/src/index.ts +21 -2
  110. package/src/json/README.md +92 -0
  111. package/src/json/index.ts +1 -0
  112. package/src/json/repair.ts +18 -0
  113. package/src/log/logger.ts +15 -4
  114. package/src/openai/README.md +1 -0
  115. package/src/openai/index.ts +1 -0
  116. package/src/openai/openai.ts +509 -0
  117. package/src/orchestration/README.md +9 -7
  118. package/src/orchestration/dispatching/dispatcher.ts +83 -0
  119. package/src/orchestration/dispatching/index.ts +2 -0
  120. package/src/orchestration/dispatching/selector/base-selector.ts +39 -0
  121. package/src/orchestration/dispatching/selector/down-count-selector.ts +119 -0
  122. package/src/orchestration/dispatching/selector/index.ts +2 -0
  123. package/src/orchestration/index.ts +2 -0
  124. package/src/orchestration/scheduling/index.ts +2 -0
  125. package/src/orchestration/scheduling/scheduler.ts +103 -0
  126. package/src/orchestration/scheduling/task.ts +32 -0
  127. package/src/random/README.md +8 -7
  128. package/src/random/base.ts +66 -0
  129. package/src/random/index.ts +5 -1
  130. package/src/random/random-boolean.ts +40 -0
  131. package/src/random/random-integer.ts +60 -0
  132. package/src/random/random-number.ts +72 -0
  133. package/src/random/random-string.ts +66 -0
  134. package/src/request/README.md +108 -0
  135. package/src/request/fetch/base.ts +108 -0
  136. package/src/request/fetch/browser.ts +280 -0
  137. package/src/request/fetch/general.ts +20 -0
  138. package/src/request/fetch/index.ts +4 -0
  139. package/src/request/fetch/nodejs.ts +280 -0
  140. package/src/request/index.ts +2 -0
  141. package/src/request/request/base.ts +246 -0
  142. package/src/request/request/general.ts +63 -0
  143. package/src/request/request/index.ts +3 -0
  144. package/src/request/request/resource.ts +68 -0
  145. package/src/result/README.md +4 -0
  146. package/src/result/controller.ts +58 -0
  147. package/src/result/either.ts +363 -0
  148. package/src/result/generator.ts +168 -0
  149. package/src/result/index.ts +3 -0
  150. package/src/route/README.md +105 -0
  151. package/src/route/adapter/browser.ts +122 -0
  152. package/src/route/adapter/driver.ts +56 -0
  153. package/src/route/adapter/index.ts +2 -0
  154. package/src/route/index.ts +3 -0
  155. package/src/route/router/index.ts +2 -0
  156. package/src/route/router/route.ts +630 -0
  157. package/src/route/router/router.ts +1641 -0
  158. package/src/route/uri/hash.ts +307 -0
  159. package/src/route/uri/index.ts +7 -0
  160. package/src/route/uri/pathname.ts +376 -0
  161. package/src/route/uri/search.ts +412 -0
  162. package/src/service/README.md +1 -0
  163. package/src/service/index.ts +1 -0
  164. package/src/service/service.ts +110 -0
  165. package/src/socket/README.md +105 -0
  166. package/src/socket/client/index.ts +2 -0
  167. package/src/socket/client/socket-unit.ts +658 -0
  168. package/src/socket/client/socket.ts +203 -0
  169. package/src/socket/common/index.ts +2 -0
  170. package/src/socket/common/socket-unit-common.ts +23 -0
  171. package/src/socket/common/socket-unit-heartbeat.ts +427 -0
  172. package/src/socket/index.ts +3 -0
  173. package/src/socket/server/index.ts +3 -0
  174. package/src/socket/server/server.ts +183 -0
  175. package/src/socket/server/socket-unit.ts +448 -0
  176. package/src/socket/server/socket.ts +264 -0
  177. package/src/storage/table.ts +3 -3
  178. package/src/timer/expiration/expiration-manager.ts +3 -3
  179. package/src/timer/expiration/remaining-manager.ts +3 -3
  180. package/src/tube/README.md +99 -0
  181. package/src/tube/helper.ts +137 -0
  182. package/src/tube/index.ts +2 -0
  183. package/src/tube/tube.ts +880 -0
  184. package/src/weixin/README.md +1 -0
  185. package/src/weixin/index.ts +2 -0
  186. package/src/weixin/official-account/authorization.ts +157 -0
  187. package/src/weixin/official-account/index.ts +2 -0
  188. package/src/weixin/official-account/js-api.ts +132 -0
  189. package/src/weixin/open/index.ts +1 -0
  190. package/src/weixin/open/oauth2.ts +131 -0
  191. package/tests/unit/ai/ai.spec.ts +85 -0
  192. package/tests/unit/aio/content.spec.ts +105 -0
  193. package/tests/unit/aio/json.spec.ts +146 -0
  194. package/tests/unit/aio/prompt.spec.ts +111 -0
  195. package/tests/unit/basic/error.spec.ts +16 -4
  196. package/tests/unit/basic/promise.spec.ts +158 -50
  197. package/tests/unit/basic/schedule.spec.ts +74 -0
  198. package/tests/unit/basic/stream.spec.ts +90 -37
  199. package/tests/unit/credential/api-key.spec.ts +36 -0
  200. package/tests/unit/credential/bearer.spec.ts +23 -0
  201. package/tests/unit/credential/json-web-token.spec.ts +23 -0
  202. package/tests/unit/credential/password.spec.ts +40 -0
  203. package/tests/unit/cron/cron.spec.ts +84 -0
  204. package/tests/unit/event/class-event-proxy.spec.ts +3 -3
  205. package/tests/unit/event/event-manager.spec.ts +3 -3
  206. package/tests/unit/event/instance-event-proxy.spec.ts +3 -3
  207. package/tests/unit/exception/error/error.spec.ts +83 -0
  208. package/tests/unit/exception/error/match.spec.ts +81 -0
  209. package/tests/unit/form/inputor-controller/base.spec.ts +458 -0
  210. package/tests/unit/form/inputor-controller/boolean.spec.ts +30 -0
  211. package/tests/unit/form/inputor-controller/file.spec.ts +27 -0
  212. package/tests/unit/form/inputor-controller/form.spec.ts +120 -0
  213. package/tests/unit/form/inputor-controller/helper.spec.ts +67 -0
  214. package/tests/unit/form/inputor-controller/multi-select.spec.ts +34 -0
  215. package/tests/unit/form/inputor-controller/number.spec.ts +36 -0
  216. package/tests/unit/form/inputor-controller/select.spec.ts +49 -0
  217. package/tests/unit/form/inputor-controller/text.spec.ts +34 -0
  218. package/tests/unit/http/api/api-core-host.spec.ts +207 -0
  219. package/tests/unit/http/api/api-schema.spec.ts +120 -0
  220. package/tests/unit/http/api/api-server.spec.ts +363 -0
  221. package/tests/unit/http/api/api-test.spec.ts +117 -0
  222. package/tests/unit/http/api/api.spec.ts +121 -0
  223. package/tests/unit/http/api-adapter/node-http.spec.ts +187 -0
  224. package/tests/unit/identifier/uuid.spec.ts +0 -1
  225. package/tests/unit/json/repair.spec.ts +11 -0
  226. package/tests/unit/log/logger.spec.ts +19 -4
  227. package/tests/unit/openai/openai.spec.ts +64 -0
  228. package/tests/unit/orchestration/dispatching/dispatcher.spec.ts +41 -0
  229. package/tests/unit/orchestration/dispatching/selector/down-count-selector.spec.ts +81 -0
  230. package/tests/unit/orchestration/scheduling/scheduler.spec.ts +103 -0
  231. package/tests/unit/random/base.spec.ts +58 -0
  232. package/tests/unit/random/random-boolean.spec.ts +25 -0
  233. package/tests/unit/random/random-integer.spec.ts +32 -0
  234. package/tests/unit/random/random-number.spec.ts +33 -0
  235. package/tests/unit/random/random-string.spec.ts +22 -0
  236. package/tests/unit/request/fetch/browser.spec.ts +222 -0
  237. package/tests/unit/request/fetch/general.spec.ts +43 -0
  238. package/tests/unit/request/fetch/nodejs.spec.ts +225 -0
  239. package/tests/unit/request/request/base.spec.ts +382 -0
  240. package/tests/unit/request/request/general.spec.ts +160 -0
  241. package/tests/unit/result/controller.spec.ts +82 -0
  242. package/tests/unit/result/either.spec.ts +377 -0
  243. package/tests/unit/result/generator.spec.ts +273 -0
  244. package/tests/unit/route/router/route.spec.ts +430 -0
  245. package/tests/unit/route/router/router.spec.ts +407 -0
  246. package/tests/unit/route/uri/hash.spec.ts +72 -0
  247. package/tests/unit/route/uri/pathname.spec.ts +146 -0
  248. package/tests/unit/route/uri/search.spec.ts +107 -0
  249. package/tests/unit/socket/client.spec.ts +208 -0
  250. package/tests/unit/socket/server.spec.ts +133 -0
  251. package/tests/unit/socket/socket-unit-heartbeat.spec.ts +214 -0
  252. package/tests/unit/tube/helper.spec.ts +139 -0
  253. package/tests/unit/tube/tube.spec.ts +501 -0
  254. package/vite.config.ts +2 -1
  255. package/dist/index.js +0 -50
  256. package/dist/index.js.map +0 -209
  257. package/src/random/string.ts +0 -35
  258. package/tests/unit/random/string.spec.ts +0 -11
@@ -0,0 +1,880 @@
1
+ import type { LoggerFriendly, LoggerFriendlyOptions } from "#Source/log/index.ts"
2
+ import { Logger } from "#Source/log/index.ts"
3
+ import { scheduleMacroTask } from "#Source/basic/index.ts"
4
+
5
+ /**
6
+ * 表示 Tube 中的订阅回调。
7
+ */
8
+ export type Subscriber<D> = ((data: D) => void) | ((data: D) => Promise<void>)
9
+
10
+ /**
11
+ * 表示用于移除订阅关系的函数。
12
+ */
13
+ export type Unsubscribe = () => void
14
+
15
+ /**
16
+ * `open` 事件的订阅配置。
17
+ */
18
+ export interface OpenEventSubscribeOptions {
19
+ subscriber: Subscriber<void>
20
+ }
21
+ interface OpenEventSubscribeStates {
22
+ subscriber: OpenEventSubscribeOptions["subscriber"]
23
+ unsubscribe: Unsubscribe
24
+ }
25
+
26
+ /**
27
+ * `close` 事件的订阅配置。
28
+ */
29
+ export interface CloseEventSubscribeOptions {
30
+ subscriber: Subscriber<void>
31
+ }
32
+ interface CloseEventSubscribeStates {
33
+ subscriber: CloseEventSubscribeOptions["subscriber"]
34
+ unsubscribe: Unsubscribe
35
+ }
36
+
37
+ /**
38
+ * `start` 事件的订阅配置。
39
+ */
40
+ export interface StartEventSubscribeOptions {
41
+ subscriber: Subscriber<void>
42
+ }
43
+ interface StartEventSubscribeStates {
44
+ subscriber: StartEventSubscribeOptions["subscriber"]
45
+ unsubscribe: Unsubscribe
46
+ }
47
+
48
+ /**
49
+ * `end` 事件的订阅配置。
50
+ */
51
+ export interface EndEventSubscribeOptions {
52
+ subscriber: Subscriber<void>
53
+ }
54
+ interface EndEventSubscribeStates {
55
+ subscriber: EndEventSubscribeOptions["subscriber"]
56
+ unsubscribe: Unsubscribe
57
+ }
58
+
59
+ /**
60
+ * `error` 事件的订阅配置。
61
+ */
62
+ export interface ErrorEventSubscribeOptions<E = Error> {
63
+ subscriber: Subscriber<E>
64
+ }
65
+ interface ErrorEventSubscribeStates<E = Error> {
66
+ subscriber: ErrorEventSubscribeOptions<E>["subscriber"]
67
+ unsubscribe: Unsubscribe
68
+ }
69
+
70
+ /**
71
+ * `wet` 事件的订阅配置。
72
+ */
73
+ export interface WetEventSubscribeOptions {
74
+ subscriber: Subscriber<void>
75
+ }
76
+ interface WetEventSubscribeStates {
77
+ subscriber: WetEventSubscribeOptions["subscriber"]
78
+ unsubscribe: Unsubscribe
79
+ }
80
+
81
+ /**
82
+ * 数据事件的订阅配置。
83
+ */
84
+ export interface DataEventSubscribeOptions<D> {
85
+ subscriber: Subscriber<D>
86
+ /**
87
+ * 是否重放历史记录。
88
+ *
89
+ * @default DataOptions.replayHistory
90
+ */
91
+ replayHistory?: boolean
92
+ }
93
+ interface DataEventSubscribeStates<D> {
94
+ subscriber: DataEventSubscribeOptions<D>["subscriber"]
95
+ replayHistory: boolean
96
+ unsubscribe: Unsubscribe
97
+ }
98
+
99
+ interface TubeRunningStates {
100
+ /**
101
+ * true: 可以进数据。
102
+ * false: 不可以进数据。
103
+ */
104
+ isOpen: boolean
105
+ /**
106
+ * true: 数据进入启动。
107
+ * false: 数据进入停止。
108
+ */
109
+ isStart: boolean
110
+ /**
111
+ * true: 发生错误。
112
+ * false: 未发生错误。
113
+ */
114
+ isError: boolean
115
+ /**
116
+ * true: 数据为空。
117
+ * false: 数据不为空。
118
+ */
119
+ isEmpty: boolean
120
+ /**
121
+ * true: 已打开过。
122
+ * false: 未打开过。
123
+ */
124
+ hasOpened: boolean
125
+ /**
126
+ * true: 已开始过。
127
+ * false: 未开始过。
128
+ */
129
+ hasStarted: boolean
130
+ /**
131
+ * true: 已结束过。
132
+ * false: 未结束过。
133
+ */
134
+ hasEnded: boolean
135
+ /**
136
+ * true: 已关闭过。
137
+ * false: 未关闭过。
138
+ */
139
+ hasClosed: boolean
140
+ }
141
+ interface DataReplayStates<D> {
142
+ dataHistory: D[]
143
+ }
144
+
145
+ /**
146
+ * `Tube` 的配置项。
147
+ */
148
+ export interface TubeOptions extends LoggerFriendlyOptions {
149
+ /**
150
+ * @default true
151
+ */
152
+ autoStartOnOpen?: boolean
153
+ /**
154
+ * @default true
155
+ */
156
+ autoOpenOnStart?: boolean
157
+ /**
158
+ * @default true
159
+ */
160
+ autoEndOnClose?: boolean
161
+ /**
162
+ * @default true
163
+ */
164
+ autoCloseOnEnd?: boolean
165
+ /**
166
+ * @default true
167
+ */
168
+ autoStartOnData?: boolean
169
+ /**
170
+ * @default true
171
+ */
172
+ autoOpenOnData?: boolean
173
+ /**
174
+ * @default true
175
+ */
176
+ autoOpenOnError?: boolean
177
+ /**
178
+ * @default true
179
+ */
180
+ autoEndOnError?: boolean
181
+ /**
182
+ * @default true
183
+ */
184
+ autoCloseOnError?: boolean
185
+ /**
186
+ * 保留多少个历史记录。
187
+ *
188
+ * @default 3
189
+ */
190
+ historyCount: number
191
+ /**
192
+ * 是否重放历史记录。
193
+ *
194
+ * @default false
195
+ */
196
+ replayHistory: boolean
197
+ }
198
+
199
+ /**
200
+ * 表示一条带生命周期、错误语义和历史回放能力的数据通道。
201
+ *
202
+ * 一般的事件顺序是:Open - Data - Data - ... - Data - Data - Close。
203
+ * Error 可能出现在 Open 和 Close 之间的任何位置。
204
+ */
205
+ export class Tube<D, E = Error> implements LoggerFriendly {
206
+ logger: Logger
207
+
208
+ // 基础配置
209
+ protected autoStartOnOpen: boolean
210
+ protected autoOpenOnStart: boolean
211
+ protected autoEndOnClose: boolean
212
+ protected autoCloseOnEnd: boolean
213
+ protected autoStartOnData: boolean
214
+ protected autoOpenOnData: boolean
215
+ protected autoOpenOnError: boolean
216
+ protected autoEndOnError: boolean
217
+ protected autoCloseOnError: boolean
218
+ protected historyCount: number
219
+ protected replayHistory: boolean
220
+
221
+ // 整体状态
222
+ protected runningStates: TubeRunningStates
223
+
224
+ // 事件订阅
225
+ protected openEventSubscribeStatesMap: Map<Subscriber<void>, OpenEventSubscribeStates>
226
+ protected closeEventSubscribeStatesMap: Map<Subscriber<void>, CloseEventSubscribeStates>
227
+ protected startEventSubscribeStatesMap: Map<Subscriber<void>, StartEventSubscribeStates>
228
+ protected endEventSubscribeStatesMap: Map<Subscriber<void>, EndEventSubscribeStates>
229
+ protected errorEventSubscribeStatesMap: Map<Subscriber<E>, ErrorEventSubscribeStates<E>>
230
+ protected wetEventSubscribeStatesMap: Map<Subscriber<void>, WetEventSubscribeStates>
231
+ protected dataEventSubscribeStatesMap: Map<Subscriber<D>, DataEventSubscribeStates<D>>
232
+
233
+ // 其它
234
+ protected errorHistory: E[]
235
+ protected dataHistory: D[]
236
+ protected dataReplayStatesMap: Map<Subscriber<D>, DataReplayStates<D>>
237
+
238
+ /**
239
+ * 创建一个 Tube 实例。
240
+ */
241
+ constructor(options: TubeOptions) {
242
+ this.logger = Logger.fromOptions(options).setDefaultName("Tube")
243
+
244
+ this.autoStartOnOpen = options.autoStartOnOpen ?? true
245
+ this.autoOpenOnStart = options.autoOpenOnStart ?? true
246
+ this.autoEndOnClose = options.autoEndOnClose ?? true
247
+ this.autoCloseOnEnd = options.autoCloseOnEnd ?? true
248
+ this.autoStartOnData = options.autoStartOnData ?? true
249
+ this.autoOpenOnData = options.autoOpenOnData ?? true
250
+ this.autoOpenOnError = options.autoOpenOnError ?? true
251
+ this.autoEndOnError = options.autoEndOnError ?? true
252
+ this.autoCloseOnError = options.autoCloseOnError ?? true
253
+ this.historyCount = options.historyCount ?? 3
254
+ this.replayHistory = options.replayHistory ?? false
255
+
256
+ if (this.historyCount < 1) {
257
+ throw new Error("historyCount must be greater than or equal to 1")
258
+ }
259
+
260
+ this.runningStates = {
261
+ isOpen: false,
262
+ isStart: false,
263
+ isError: false,
264
+ isEmpty: true,
265
+ hasOpened: false,
266
+ hasStarted: false,
267
+ hasEnded: false,
268
+ hasClosed: false,
269
+ }
270
+
271
+ this.openEventSubscribeStatesMap = new Map()
272
+ this.closeEventSubscribeStatesMap = new Map()
273
+ this.startEventSubscribeStatesMap = new Map()
274
+ this.endEventSubscribeStatesMap = new Map()
275
+ this.errorEventSubscribeStatesMap = new Map()
276
+ this.wetEventSubscribeStatesMap = new Map()
277
+ this.dataEventSubscribeStatesMap = new Map()
278
+
279
+ this.errorHistory = []
280
+ this.dataHistory = []
281
+ this.dataReplayStatesMap = new Map()
282
+ }
283
+
284
+ /**
285
+ * 安全地获取最近一条数据;若当前还没有任何数据则抛出错误。
286
+ *
287
+ * 当数据列表为空时,此方法会抛出错误,请妥善处理。
288
+ *
289
+ * 如果不希望错误发生,可以通过 {@link isWet} 方法判断数据列表是否为空。
290
+ */
291
+ safeGetLatestData(): D {
292
+ const latestData = this.dataHistory.at(-1)
293
+ if (latestData === undefined) {
294
+ throw new Error("latestData is undefined")
295
+ }
296
+ return latestData
297
+ }
298
+
299
+ /**
300
+ * 安全地获取最近一次错误;若当前还没有错误记录则抛出错误。
301
+ *
302
+ * 当错误列表为空时,此方法会抛出错误,请妥善处理。
303
+ *
304
+ * 如果不希望错误发生,可以通过 {@link isError} 方法判断错误列表是否为空。
305
+ */
306
+ safeGetLatestError(): E {
307
+ const latestError = this.errorHistory.at(-1)
308
+ if (latestError === undefined) {
309
+ throw new Error("latestError is undefined")
310
+ }
311
+ return latestError
312
+ }
313
+
314
+ /**
315
+ * 判断 Tube 当前是否处于打开状态。
316
+ */
317
+ isOpen(): boolean {
318
+ return this.runningStates.isOpen === true
319
+ }
320
+
321
+ /**
322
+ * 判断 Tube 是否曾经被打开过。
323
+ */
324
+ hasOpened(): boolean {
325
+ return this.runningStates.hasOpened === true
326
+ }
327
+
328
+ /**
329
+ * 打开 Tube,并在需要时自动启动。
330
+ */
331
+ async open(): Promise<void> {
332
+ if (this.isOpen() === true) {
333
+ return
334
+ }
335
+
336
+ if (this.hasClosed() === true) {
337
+ return
338
+ }
339
+
340
+ this.runningStates.isOpen = true
341
+ this.runningStates.hasOpened = true
342
+ this.triggerOpenEventForAll()
343
+
344
+ if (this.autoStartOnOpen === true) {
345
+ await this.start()
346
+ }
347
+ }
348
+
349
+ /**
350
+ * 判断 Tube 当前是否处于关闭状态。
351
+ */
352
+ isClose(): boolean {
353
+ return this.runningStates.isOpen === false
354
+ }
355
+
356
+ /**
357
+ * 判断 Tube 是否曾经被关闭过。
358
+ */
359
+ hasClosed(): boolean {
360
+ return this.runningStates.hasClosed === true
361
+ }
362
+
363
+ /**
364
+ * 关闭 Tube,并在需要时自动结束。
365
+ */
366
+ async close(): Promise<void> {
367
+ if (this.isClose() === true) {
368
+ return
369
+ }
370
+
371
+ if (this.autoEndOnClose === true) {
372
+ await this.end()
373
+ }
374
+
375
+ this.runningStates.isOpen = false
376
+ this.runningStates.hasClosed = true
377
+ this.triggerCloseEventForAll()
378
+ }
379
+
380
+ /**
381
+ * 判断 Tube 当前是否处于启动状态。
382
+ */
383
+ isStart(): boolean {
384
+ return this.runningStates.isStart === true
385
+ }
386
+
387
+ /**
388
+ * 判断 Tube 是否曾经进入过启动状态。
389
+ */
390
+ hasStarted(): boolean {
391
+ return this.runningStates.hasStarted === true
392
+ }
393
+
394
+ /**
395
+ * 启动 Tube,并在需要时自动打开。
396
+ */
397
+ async start(): Promise<void> {
398
+ if (this.isStart() === true) {
399
+ return
400
+ }
401
+
402
+ if (this.autoOpenOnStart === true) {
403
+ await this.open()
404
+ }
405
+
406
+ if (this.isOpen() === false) {
407
+ return
408
+ }
409
+
410
+ this.runningStates.isStart = true
411
+ this.runningStates.hasStarted = true
412
+ this.triggerStartEventForAll()
413
+ }
414
+
415
+ /**
416
+ * 判断 Tube 当前是否处于结束状态。
417
+ */
418
+ isEnd(): boolean {
419
+ return this.runningStates.isStart === false
420
+ }
421
+
422
+ /**
423
+ * 判断 Tube 是否曾经结束过。
424
+ */
425
+ hasEnded(): boolean {
426
+ return this.runningStates.hasEnded === true
427
+ }
428
+
429
+ /**
430
+ * 结束 Tube,并在需要时自动关闭。
431
+ */
432
+ async end(): Promise<void> {
433
+ if (this.isEnd() === true) {
434
+ return
435
+ }
436
+
437
+ if (this.isOpen() === false) {
438
+ return
439
+ }
440
+
441
+ this.runningStates.isStart = false
442
+ this.runningStates.hasEnded = true
443
+ this.triggerEndEventForAll()
444
+
445
+ if (this.autoCloseOnEnd === true) {
446
+ await this.close()
447
+ }
448
+ }
449
+
450
+ /**
451
+ * 判断 Tube 是否已经记录过错误。
452
+ */
453
+ isError(): boolean {
454
+ return this.runningStates.isError === true
455
+ }
456
+
457
+ protected async error(): Promise<void> {
458
+ if (this.isOpen() === false) {
459
+ if (this.autoOpenOnError === true) {
460
+ await this.open()
461
+ }
462
+ }
463
+
464
+ if (this.isOpen() === false) {
465
+ return
466
+ }
467
+
468
+ // NOTE: 允许在错误状态下继续推送数据,且允许发生多次错误。
469
+ // if (this.isError() === true) {
470
+ // return
471
+ // }
472
+ this.runningStates.isError = true
473
+ this.triggerErrorEventForAll()
474
+
475
+ if (this.autoEndOnError === true) {
476
+ await this.end()
477
+ }
478
+ if (this.autoCloseOnError === true) {
479
+ await this.close()
480
+ }
481
+ }
482
+
483
+ /**
484
+ * 判断 Tube 是否已经接收过至少一条数据。
485
+ */
486
+ isWet(): boolean {
487
+ return this.runningStates.isEmpty === false
488
+ }
489
+
490
+ // oxlint-disable-next-line require-await
491
+ protected async wet(): Promise<void> {
492
+ if (this.isWet() === true) {
493
+ return
494
+ }
495
+
496
+ this.runningStates.isEmpty = false
497
+ this.triggerWetEventForAll()
498
+ }
499
+
500
+ protected async data(): Promise<void> {
501
+ if (this.isOpen() === false) {
502
+ if (this.autoOpenOnData === true) {
503
+ await this.open()
504
+ }
505
+ else {
506
+ return
507
+ }
508
+ }
509
+ if (this.isOpen() === false) {
510
+ return
511
+ }
512
+ if (this.isStart() === false) {
513
+ if (this.autoStartOnData === true) {
514
+ await this.start()
515
+ }
516
+ else {
517
+ return
518
+ }
519
+ }
520
+ if (this.isStart() === false) {
521
+ return
522
+ }
523
+ }
524
+
525
+ protected triggerOpenEventForOne(subscriber: OpenEventSubscribeOptions["subscriber"]): void {
526
+ scheduleMacroTask({ task: async () => await subscriber() })
527
+ }
528
+
529
+ protected triggerOpenEventForAll(): void {
530
+ this.openEventSubscribeStatesMap.forEach((subscribeStates) => {
531
+ scheduleMacroTask({ task: async () => await subscribeStates.subscriber() })
532
+ })
533
+ }
534
+
535
+ /**
536
+ * 订阅 Tube 的 `open` 事件。
537
+ */
538
+ subscribeOpenEvent(options: OpenEventSubscribeOptions): Unsubscribe {
539
+ const states = this.openEventSubscribeStatesMap.get(options.subscriber)
540
+ if (states !== undefined) {
541
+ return states.unsubscribe
542
+ }
543
+
544
+ const subscriber = options.subscriber
545
+ const unsubscribe = (): void => {
546
+ this.openEventSubscribeStatesMap.delete(subscriber)
547
+ }
548
+ this.openEventSubscribeStatesMap.set(subscriber, {
549
+ subscriber,
550
+ unsubscribe,
551
+ })
552
+ return unsubscribe
553
+ }
554
+
555
+ /**
556
+ * 取消指定的 `open` 事件订阅。
557
+ */
558
+ unsubscribeOpenEvent(subscriber: OpenEventSubscribeOptions["subscriber"]): void {
559
+ const subscribeStates = this.openEventSubscribeStatesMap.get(subscriber)
560
+ if (subscribeStates === undefined) {
561
+ return
562
+ }
563
+ subscribeStates.unsubscribe()
564
+ }
565
+
566
+ protected triggerCloseEventForOne(subscriber: CloseEventSubscribeOptions["subscriber"]): void {
567
+ scheduleMacroTask({ task: async () => await subscriber() })
568
+ }
569
+
570
+ protected triggerCloseEventForAll(): void {
571
+ this.closeEventSubscribeStatesMap.forEach((subscribeStates) => {
572
+ scheduleMacroTask({ task: async () => await subscribeStates.subscriber() })
573
+ })
574
+ }
575
+
576
+ /**
577
+ * 订阅 Tube 的 `close` 事件。
578
+ */
579
+ subscribeCloseEvent(options: CloseEventSubscribeOptions): Unsubscribe {
580
+ const states = this.closeEventSubscribeStatesMap.get(options.subscriber)
581
+ if (states !== undefined) {
582
+ return states.unsubscribe
583
+ }
584
+
585
+ const subscriber = options.subscriber
586
+ const unsubscribe = (): void => {
587
+ this.closeEventSubscribeStatesMap.delete(subscriber)
588
+ }
589
+ this.closeEventSubscribeStatesMap.set(subscriber, {
590
+ subscriber,
591
+ unsubscribe,
592
+ })
593
+ return unsubscribe
594
+ }
595
+
596
+ /**
597
+ * 取消指定的 `close` 事件订阅。
598
+ */
599
+ unsubscribeCloseEvent(subscriber: CloseEventSubscribeOptions["subscriber"]): void {
600
+ const subscribeStates = this.closeEventSubscribeStatesMap.get(subscriber)
601
+ if (subscribeStates === undefined) {
602
+ return
603
+ }
604
+ subscribeStates.unsubscribe()
605
+ }
606
+
607
+ protected triggerStartEventForOne(subscriber: StartEventSubscribeOptions["subscriber"]): void {
608
+ scheduleMacroTask({ task: async () => await subscriber() })
609
+ }
610
+
611
+ protected triggerStartEventForAll(): void {
612
+ this.startEventSubscribeStatesMap.forEach((subscribeStates) => {
613
+ scheduleMacroTask({ task: async () => await subscribeStates.subscriber() })
614
+ })
615
+ }
616
+
617
+ /**
618
+ * 订阅 Tube 的 `start` 事件。
619
+ */
620
+ subscribeStartEvent(options: StartEventSubscribeOptions): Unsubscribe {
621
+ const states = this.startEventSubscribeStatesMap.get(options.subscriber)
622
+ if (states !== undefined) {
623
+ return states.unsubscribe
624
+ }
625
+
626
+ const subscriber = options.subscriber
627
+ const unsubscribe = (): void => {
628
+ this.startEventSubscribeStatesMap.delete(subscriber)
629
+ }
630
+ this.startEventSubscribeStatesMap.set(subscriber, {
631
+ subscriber,
632
+ unsubscribe,
633
+ })
634
+ return unsubscribe
635
+ }
636
+
637
+ /**
638
+ * 取消指定的 `start` 事件订阅。
639
+ */
640
+ unsubscribeStartEvent(subscriber: StartEventSubscribeOptions["subscriber"]): void {
641
+ const subscribeStates = this.startEventSubscribeStatesMap.get(subscriber)
642
+ if (subscribeStates === undefined) {
643
+ return
644
+ }
645
+ subscribeStates.unsubscribe()
646
+ }
647
+
648
+ protected triggerEndEventForOne(subscriber: EndEventSubscribeOptions["subscriber"]): void {
649
+ scheduleMacroTask({ task: async () => await subscriber() })
650
+ }
651
+
652
+ protected triggerEndEventForAll(): void {
653
+ this.endEventSubscribeStatesMap.forEach((subscribeStates) => {
654
+ scheduleMacroTask({ task: async () => await subscribeStates.subscriber() })
655
+ })
656
+ }
657
+
658
+ /**
659
+ * 订阅 Tube 的 `end` 事件。
660
+ */
661
+ subscribeEndEvent(options: EndEventSubscribeOptions): Unsubscribe {
662
+ const states = this.endEventSubscribeStatesMap.get(options.subscriber)
663
+ if (states !== undefined) {
664
+ return states.unsubscribe
665
+ }
666
+
667
+ const subscriber = options.subscriber
668
+ const unsubscribe = (): void => {
669
+ this.endEventSubscribeStatesMap.delete(subscriber)
670
+ }
671
+ this.endEventSubscribeStatesMap.set(subscriber, {
672
+ subscriber,
673
+ unsubscribe,
674
+ })
675
+ return unsubscribe
676
+ }
677
+
678
+ /**
679
+ * 取消指定的 `end` 事件订阅。
680
+ */
681
+ unsubscribeEndEvent(subscriber: EndEventSubscribeOptions["subscriber"]): void {
682
+ const subscribeStates = this.endEventSubscribeStatesMap.get(subscriber)
683
+ if (subscribeStates === undefined) {
684
+ return
685
+ }
686
+ subscribeStates.unsubscribe()
687
+ }
688
+
689
+ protected triggerWetEventForOne(subscriber: WetEventSubscribeOptions["subscriber"]): void {
690
+ scheduleMacroTask({ task: async () => await subscriber() })
691
+ }
692
+
693
+ protected triggerWetEventForAll(): void {
694
+ this.wetEventSubscribeStatesMap.forEach((subscribeStates) => {
695
+ scheduleMacroTask({ task: async () => await subscribeStates.subscriber() })
696
+ })
697
+ }
698
+
699
+ /**
700
+ * 订阅 Tube 首次变为非空时触发的 `wet` 事件。
701
+ */
702
+ subscribeWetEvent(options: WetEventSubscribeOptions): Unsubscribe {
703
+ const states = this.wetEventSubscribeStatesMap.get(options.subscriber)
704
+ if (states !== undefined) {
705
+ return states.unsubscribe
706
+ }
707
+
708
+ const subscriber = options.subscriber
709
+ const unsubscribe = (): void => {
710
+ this.wetEventSubscribeStatesMap.delete(subscriber)
711
+ }
712
+ this.wetEventSubscribeStatesMap.set(subscriber, {
713
+ subscriber,
714
+ unsubscribe,
715
+ })
716
+ return unsubscribe
717
+ }
718
+
719
+ /**
720
+ * 取消指定的 `wet` 事件订阅。
721
+ */
722
+ unsubscribeWetEvent(subscriber: WetEventSubscribeOptions["subscriber"]): void {
723
+ const subscribeStates = this.wetEventSubscribeStatesMap.get(subscriber)
724
+ if (subscribeStates === undefined) {
725
+ return
726
+ }
727
+ subscribeStates.unsubscribe()
728
+ }
729
+
730
+ /**
731
+ * 向 Tube 推送一个错误,并触发错误生命周期。
732
+ */
733
+ async pushError(error: E): Promise<void> {
734
+ this.errorHistory.push(error)
735
+ await this.error()
736
+ }
737
+
738
+ protected triggerErrorEventForOne(subscriber: ErrorEventSubscribeOptions<E>["subscriber"]): void {
739
+ const latestErrorData = this.errorHistory.at(-1)
740
+ if (latestErrorData === undefined) {
741
+ throw new Error("latestErrorData is undefined")
742
+ }
743
+ scheduleMacroTask({ task: async () => await subscriber(latestErrorData) })
744
+ }
745
+
746
+ protected triggerErrorEventForAll(): void {
747
+ const latestErrorData = this.errorHistory.at(-1)
748
+ if (latestErrorData === undefined) {
749
+ throw new Error("latestErrorData is undefined")
750
+ }
751
+ this.errorEventSubscribeStatesMap.forEach((subscribeStates) => {
752
+ scheduleMacroTask({ task: async () => await subscribeStates.subscriber(latestErrorData) })
753
+ })
754
+ }
755
+
756
+ /**
757
+ * 订阅 Tube 的 `error` 事件。
758
+ */
759
+ subscribeErrorEvent(options: ErrorEventSubscribeOptions<E>): Unsubscribe {
760
+ const states = this.errorEventSubscribeStatesMap.get(options.subscriber)
761
+ if (states !== undefined) {
762
+ return states.unsubscribe
763
+ }
764
+
765
+ const subscriber = options.subscriber
766
+ const unsubscribe = (): void => {
767
+ this.errorEventSubscribeStatesMap.delete(subscriber)
768
+ }
769
+ this.errorEventSubscribeStatesMap.set(subscriber, {
770
+ subscriber,
771
+ unsubscribe,
772
+ })
773
+ return unsubscribe
774
+ }
775
+
776
+ /**
777
+ * 取消指定的 `error` 事件订阅。
778
+ */
779
+ unsubscribeErrorEvent(subscriber: ErrorEventSubscribeOptions<E>["subscriber"]): void {
780
+ const subscribeStates = this.errorEventSubscribeStatesMap.get(subscriber)
781
+ if (subscribeStates === undefined) {
782
+ return
783
+ }
784
+ subscribeStates.unsubscribe()
785
+ }
786
+
787
+ /**
788
+ * 向 Tube 推送一条数据,并在需要时自动打开、启动与变为非空。
789
+ */
790
+ async pushData(data: D): Promise<void> {
791
+ await this.data()
792
+
793
+ this.dataHistory.push(data)
794
+ if (this.dataHistory.length > this.historyCount) {
795
+ this.dataHistory.shift()
796
+ }
797
+ const allDataEventSubscribeStatesList = Array.from(this.dataEventSubscribeStatesMap.values())
798
+ const replayingDataSubscriberList = Array.from(this.dataReplayStatesMap.keys())
799
+ const notReplayingDataEventSubscribeStatesList = allDataEventSubscribeStatesList.filter((subscribeStates) => {
800
+ return replayingDataSubscriberList.includes(subscribeStates.subscriber) === false
801
+ })
802
+ // 对于不处于重放状态的监听器,直接触发
803
+ notReplayingDataEventSubscribeStatesList.forEach((subscribeStates) => {
804
+ scheduleMacroTask({ task: async () => await subscribeStates.subscriber(data) })
805
+ })
806
+ // 对于处于重放状态的监听器,将数据推入重放队列
807
+ this.dataReplayStatesMap.forEach((replayStates) => {
808
+ replayStates.dataHistory.push(data)
809
+ })
810
+
811
+ if (this.isWet() === false) {
812
+ await this.wet()
813
+ }
814
+ }
815
+
816
+ protected startReplay(subscriber: Subscriber<D>): void {
817
+ const isReplaying = this.dataReplayStatesMap.has(subscriber)
818
+ if (isReplaying === true) {
819
+ return
820
+ }
821
+
822
+ const dataHistoryToReplay = [...this.dataHistory]
823
+ this.dataReplayStatesMap.set(subscriber, { dataHistory: dataHistoryToReplay })
824
+
825
+ scheduleMacroTask({
826
+ task: async () => {
827
+ while (dataHistoryToReplay.length !== 0) {
828
+ const data = dataHistoryToReplay.shift()!
829
+ await subscriber(data)
830
+ }
831
+ await this.stopReplay(subscriber)
832
+ }
833
+ })
834
+ }
835
+
836
+ // oxlint-disable-next-line require-await
837
+ protected async stopReplay(subscriber: Subscriber<D>): Promise<void> {
838
+ this.dataReplayStatesMap.delete(subscriber)
839
+ }
840
+
841
+ /**
842
+ * 订阅 Tube 的数据事件,并可选地重放已有历史。
843
+ */
844
+ subscribeData(options: DataEventSubscribeOptions<D>): Unsubscribe {
845
+ const states = this.dataEventSubscribeStatesMap.get(options.subscriber)
846
+ if (states !== undefined) {
847
+ return states.unsubscribe
848
+ }
849
+
850
+ const subscriber = options.subscriber
851
+ const replayHistory = options.replayHistory ?? this.replayHistory
852
+ const unsubscribe = (): void => {
853
+ this.dataEventSubscribeStatesMap.delete(subscriber)
854
+ this.dataReplayStatesMap.delete(subscriber)
855
+ }
856
+ this.dataEventSubscribeStatesMap.set(subscriber, {
857
+ subscriber,
858
+ replayHistory,
859
+ unsubscribe,
860
+ })
861
+
862
+ if (replayHistory === true) {
863
+ // NOTE: 开始 Replay 的方法必须同步调用,即第一时间将目标订阅者设为 Replay 状态,避免丢失数据。
864
+ this.startReplay(subscriber)
865
+ }
866
+
867
+ return unsubscribe
868
+ }
869
+
870
+ /**
871
+ * 取消指定的数据订阅。
872
+ */
873
+ unsubscribeData(subscriber: Subscriber<D>): void {
874
+ const subscribeStates = this.dataEventSubscribeStatesMap.get(subscriber)
875
+ if (subscribeStates === undefined) {
876
+ return
877
+ }
878
+ subscribeStates.unsubscribe()
879
+ }
880
+ }