@planet-matrix/mobius-model 0.5.0 → 0.9.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.
Files changed (379) hide show
  1. package/CHANGELOG.md +61 -0
  2. package/README.md +123 -36
  3. package/dist/index.js +715 -4
  4. package/dist/index.js.map +981 -13
  5. package/oxlint.config.ts +6 -0
  6. package/package.json +36 -18
  7. package/src/abort/README.md +92 -0
  8. package/src/abort/abort-manager.ts +278 -0
  9. package/src/abort/abort-signal-listener-manager.ts +81 -0
  10. package/src/abort/index.ts +2 -0
  11. package/src/ai/README.md +1 -0
  12. package/src/ai/ai.ts +107 -0
  13. package/src/ai/chat-completion-ai/aihubmix-chat-completion.ts +78 -0
  14. package/src/ai/chat-completion-ai/chat-completion-ai.ts +270 -0
  15. package/src/ai/chat-completion-ai/chat-completion.ts +189 -0
  16. package/src/ai/chat-completion-ai/index.ts +7 -0
  17. package/src/ai/chat-completion-ai/lingyiwanwu-chat-completion.ts +78 -0
  18. package/src/ai/chat-completion-ai/ohmygpt-chat-completion.ts +78 -0
  19. package/src/ai/chat-completion-ai/openai-next-chat-completion.ts +78 -0
  20. package/src/ai/embedding-ai/embedding-ai.ts +63 -0
  21. package/src/ai/embedding-ai/embedding.ts +50 -0
  22. package/src/ai/embedding-ai/index.ts +4 -0
  23. package/src/ai/embedding-ai/openai-next-embedding.ts +23 -0
  24. package/src/ai/index.ts +4 -0
  25. package/src/aio/README.md +100 -0
  26. package/src/aio/content.ts +141 -0
  27. package/src/aio/index.ts +3 -0
  28. package/src/aio/json.ts +127 -0
  29. package/src/aio/prompt.ts +246 -0
  30. package/src/basic/README.md +72 -116
  31. package/src/basic/error.ts +19 -5
  32. package/src/basic/function.ts +83 -64
  33. package/src/basic/index.ts +1 -0
  34. package/src/basic/is.ts +152 -71
  35. package/src/basic/promise.ts +29 -8
  36. package/src/basic/schedule.ts +111 -0
  37. package/src/basic/stream.ts +135 -25
  38. package/src/basic/string.ts +2 -33
  39. package/src/color/README.md +105 -0
  40. package/src/color/index.ts +3 -0
  41. package/src/color/internal.ts +42 -0
  42. package/src/color/rgb/analyze.ts +236 -0
  43. package/src/color/rgb/construct.ts +130 -0
  44. package/src/color/rgb/convert.ts +227 -0
  45. package/src/color/rgb/derive.ts +303 -0
  46. package/src/color/rgb/index.ts +6 -0
  47. package/src/color/rgb/internal.ts +208 -0
  48. package/src/color/rgb/parse.ts +302 -0
  49. package/src/color/rgb/serialize.ts +144 -0
  50. package/src/color/types.ts +57 -0
  51. package/src/color/xyz/analyze.ts +80 -0
  52. package/src/color/xyz/construct.ts +19 -0
  53. package/src/color/xyz/convert.ts +71 -0
  54. package/src/color/xyz/index.ts +3 -0
  55. package/src/color/xyz/internal.ts +23 -0
  56. package/src/credential/README.md +107 -0
  57. package/src/credential/api-key.ts +158 -0
  58. package/src/credential/bearer.ts +73 -0
  59. package/src/credential/index.ts +4 -0
  60. package/src/credential/json-web-token.ts +96 -0
  61. package/src/credential/password.ts +170 -0
  62. package/src/cron/README.md +86 -0
  63. package/src/cron/cron.ts +87 -0
  64. package/src/cron/index.ts +1 -0
  65. package/src/css/README.md +93 -0
  66. package/src/css/class.ts +559 -0
  67. package/src/css/index.ts +1 -0
  68. package/src/drizzle/README.md +1 -0
  69. package/src/drizzle/drizzle.ts +1 -0
  70. package/src/drizzle/helper.ts +47 -0
  71. package/src/drizzle/index.ts +5 -0
  72. package/src/drizzle/infer.ts +52 -0
  73. package/src/drizzle/kysely.ts +8 -0
  74. package/src/drizzle/pagination.ts +200 -0
  75. package/src/email/README.md +1 -0
  76. package/src/email/index.ts +1 -0
  77. package/src/email/resend.ts +25 -0
  78. package/src/encoding/README.md +66 -79
  79. package/src/encoding/base64.ts +13 -4
  80. package/src/environment/README.md +97 -0
  81. package/src/environment/basic.ts +26 -0
  82. package/src/environment/device.ts +311 -0
  83. package/src/environment/feature.ts +285 -0
  84. package/src/environment/geo.ts +337 -0
  85. package/src/environment/index.ts +7 -0
  86. package/src/environment/runtime.ts +400 -0
  87. package/src/environment/snapshot.ts +60 -0
  88. package/src/environment/variable.ts +239 -0
  89. package/src/event/README.md +90 -0
  90. package/src/event/class-event-proxy.ts +229 -0
  91. package/src/event/common.ts +29 -0
  92. package/src/event/event-manager.ts +203 -0
  93. package/src/event/index.ts +4 -0
  94. package/src/event/instance-event-proxy.ts +187 -0
  95. package/src/event/internal.ts +24 -0
  96. package/src/exception/README.md +96 -0
  97. package/src/exception/browser.ts +219 -0
  98. package/src/exception/index.ts +4 -0
  99. package/src/exception/nodejs.ts +169 -0
  100. package/src/exception/normalize.ts +106 -0
  101. package/src/exception/types.ts +99 -0
  102. package/src/form/README.md +25 -0
  103. package/src/form/index.ts +1 -0
  104. package/src/form/inputor-controller/base.ts +874 -0
  105. package/src/form/inputor-controller/boolean.ts +39 -0
  106. package/src/form/inputor-controller/file.ts +39 -0
  107. package/src/form/inputor-controller/form.ts +181 -0
  108. package/src/form/inputor-controller/helper.ts +117 -0
  109. package/src/form/inputor-controller/index.ts +17 -0
  110. package/src/form/inputor-controller/multi-select.ts +99 -0
  111. package/src/form/inputor-controller/number.ts +116 -0
  112. package/src/form/inputor-controller/select.ts +109 -0
  113. package/src/form/inputor-controller/text.ts +82 -0
  114. package/src/http/READMD.md +1 -0
  115. package/src/http/api/api-core.ts +84 -0
  116. package/src/http/api/api-handler.ts +79 -0
  117. package/src/http/api/api-host.ts +47 -0
  118. package/src/http/api/api-result.ts +56 -0
  119. package/src/http/api/api-schema.ts +154 -0
  120. package/src/http/api/api-server.ts +130 -0
  121. package/src/http/api/api-test.ts +142 -0
  122. package/src/http/api/api-type.ts +37 -0
  123. package/src/http/api/api.ts +81 -0
  124. package/src/http/api/index.ts +11 -0
  125. package/src/http/api-adapter/api-core-node-http.ts +260 -0
  126. package/src/http/api-adapter/api-host-node-http.ts +156 -0
  127. package/src/http/api-adapter/api-result-arktype.ts +297 -0
  128. package/src/http/api-adapter/api-result-zod.ts +286 -0
  129. package/src/http/api-adapter/index.ts +5 -0
  130. package/src/http/bin/gen-api-list/gen-api-list.ts +126 -0
  131. package/src/http/bin/gen-api-list/index.ts +1 -0
  132. package/src/http/bin/gen-api-test/gen-api-test.ts +136 -0
  133. package/src/http/bin/gen-api-test/index.ts +1 -0
  134. package/src/http/bin/gen-api-type/calc-code.ts +25 -0
  135. package/src/http/bin/gen-api-type/gen-api-type.ts +127 -0
  136. package/src/http/bin/gen-api-type/index.ts +2 -0
  137. package/src/http/bin/index.ts +2 -0
  138. package/src/http/index.ts +3 -0
  139. package/src/huawei/README.md +1 -0
  140. package/src/huawei/index.ts +2 -0
  141. package/src/huawei/moderation/index.ts +1 -0
  142. package/src/huawei/moderation/moderation.ts +355 -0
  143. package/src/huawei/obs/esdk-obs-nodejs.d.ts +87 -0
  144. package/src/huawei/obs/index.ts +1 -0
  145. package/src/huawei/obs/obs.ts +42 -0
  146. package/src/identifier/README.md +92 -0
  147. package/src/identifier/id.ts +119 -0
  148. package/src/identifier/index.ts +2 -0
  149. package/src/identifier/uuid.ts +187 -0
  150. package/src/index.ts +33 -1
  151. package/src/json/README.md +92 -0
  152. package/src/json/index.ts +1 -0
  153. package/src/json/repair.ts +18 -0
  154. package/src/log/README.md +79 -0
  155. package/src/log/index.ts +5 -0
  156. package/src/log/log-emitter.ts +72 -0
  157. package/src/log/log-record.ts +10 -0
  158. package/src/log/log-scheduler.ts +74 -0
  159. package/src/log/log-type.ts +8 -0
  160. package/src/log/logger.ts +554 -0
  161. package/src/openai/README.md +1 -0
  162. package/src/openai/index.ts +1 -0
  163. package/src/openai/openai.ts +510 -0
  164. package/src/orchestration/README.md +91 -0
  165. package/src/orchestration/coordination/barrier.ts +214 -0
  166. package/src/orchestration/coordination/count-down-latch.ts +215 -0
  167. package/src/orchestration/coordination/errors.ts +98 -0
  168. package/src/orchestration/coordination/index.ts +16 -0
  169. package/src/orchestration/coordination/internal/wait-constraints.ts +95 -0
  170. package/src/orchestration/coordination/internal/wait-queue.ts +109 -0
  171. package/src/orchestration/coordination/keyed-lock.ts +168 -0
  172. package/src/orchestration/coordination/mutex.ts +257 -0
  173. package/src/orchestration/coordination/permit.ts +127 -0
  174. package/src/orchestration/coordination/read-write-lock.ts +444 -0
  175. package/src/orchestration/coordination/semaphore.ts +280 -0
  176. package/src/orchestration/dispatching/dispatcher.ts +83 -0
  177. package/src/orchestration/dispatching/index.ts +2 -0
  178. package/src/orchestration/dispatching/selector/base-selector.ts +39 -0
  179. package/src/orchestration/dispatching/selector/down-count-selector.ts +119 -0
  180. package/src/orchestration/dispatching/selector/index.ts +2 -0
  181. package/src/orchestration/index.ts +3 -0
  182. package/src/orchestration/scheduling/index.ts +2 -0
  183. package/src/orchestration/scheduling/scheduler.ts +103 -0
  184. package/src/orchestration/scheduling/task.ts +32 -0
  185. package/src/random/README.md +56 -86
  186. package/src/random/base.ts +66 -0
  187. package/src/random/index.ts +5 -1
  188. package/src/random/random-boolean.ts +40 -0
  189. package/src/random/random-integer.ts +60 -0
  190. package/src/random/random-number.ts +72 -0
  191. package/src/random/random-string.ts +66 -0
  192. package/src/reactor/README.md +4 -0
  193. package/src/reactor/reactor-core/primitive.ts +9 -9
  194. package/src/reactor/reactor-core/reactive-system.ts +5 -5
  195. package/src/request/README.md +108 -0
  196. package/src/request/fetch/base.ts +108 -0
  197. package/src/request/fetch/browser.ts +285 -0
  198. package/src/request/fetch/general.ts +20 -0
  199. package/src/request/fetch/index.ts +4 -0
  200. package/src/request/fetch/nodejs.ts +285 -0
  201. package/src/request/index.ts +2 -0
  202. package/src/request/request/base.ts +250 -0
  203. package/src/request/request/general.ts +64 -0
  204. package/src/request/request/index.ts +3 -0
  205. package/src/request/request/resource.ts +68 -0
  206. package/src/result/README.md +4 -0
  207. package/src/result/controller.ts +54 -0
  208. package/src/result/either.ts +193 -0
  209. package/src/result/index.ts +2 -0
  210. package/src/route/README.md +105 -0
  211. package/src/route/adapter/browser.ts +122 -0
  212. package/src/route/adapter/driver.ts +56 -0
  213. package/src/route/adapter/index.ts +2 -0
  214. package/src/route/index.ts +3 -0
  215. package/src/route/router/index.ts +2 -0
  216. package/src/route/router/route.ts +630 -0
  217. package/src/route/router/router.ts +1642 -0
  218. package/src/route/uri/hash.ts +308 -0
  219. package/src/route/uri/index.ts +7 -0
  220. package/src/route/uri/pathname.ts +376 -0
  221. package/src/route/uri/search.ts +413 -0
  222. package/src/singleton/README.md +79 -0
  223. package/src/singleton/factory.ts +55 -0
  224. package/src/singleton/index.ts +2 -0
  225. package/src/singleton/manager.ts +204 -0
  226. package/src/socket/README.md +105 -0
  227. package/src/socket/client/index.ts +2 -0
  228. package/src/socket/client/socket-unit.ts +660 -0
  229. package/src/socket/client/socket.ts +203 -0
  230. package/src/socket/common/index.ts +2 -0
  231. package/src/socket/common/socket-unit-common.ts +23 -0
  232. package/src/socket/common/socket-unit-heartbeat.ts +427 -0
  233. package/src/socket/index.ts +3 -0
  234. package/src/socket/server/index.ts +3 -0
  235. package/src/socket/server/server.ts +183 -0
  236. package/src/socket/server/socket-unit.ts +449 -0
  237. package/src/socket/server/socket.ts +264 -0
  238. package/src/storage/README.md +107 -0
  239. package/src/storage/index.ts +1 -0
  240. package/src/storage/table.ts +449 -0
  241. package/src/timer/README.md +86 -0
  242. package/src/timer/expiration/expiration-manager.ts +594 -0
  243. package/src/timer/expiration/index.ts +3 -0
  244. package/src/timer/expiration/min-heap.ts +208 -0
  245. package/src/timer/expiration/remaining-manager.ts +241 -0
  246. package/src/timer/index.ts +1 -0
  247. package/src/tube/README.md +99 -0
  248. package/src/tube/helper.ts +138 -0
  249. package/src/tube/index.ts +2 -0
  250. package/src/tube/tube.ts +880 -0
  251. package/src/type/README.md +54 -307
  252. package/src/type/class.ts +2 -2
  253. package/src/type/index.ts +14 -14
  254. package/src/type/is.ts +265 -2
  255. package/src/type/object.ts +37 -0
  256. package/src/type/string.ts +7 -2
  257. package/src/type/tuple.ts +6 -6
  258. package/src/type/union.ts +16 -0
  259. package/src/web/README.md +77 -0
  260. package/src/web/capture.ts +35 -0
  261. package/src/web/clipboard.ts +97 -0
  262. package/src/web/dom.ts +117 -0
  263. package/src/web/download.ts +16 -0
  264. package/src/web/event.ts +46 -0
  265. package/src/web/index.ts +10 -0
  266. package/src/web/local-storage.ts +113 -0
  267. package/src/web/location.ts +28 -0
  268. package/src/web/permission.ts +172 -0
  269. package/src/web/script-loader.ts +432 -0
  270. package/src/weixin/README.md +1 -0
  271. package/src/weixin/index.ts +2 -0
  272. package/src/weixin/official-account/authorization.ts +159 -0
  273. package/src/weixin/official-account/index.ts +2 -0
  274. package/src/weixin/official-account/js-api.ts +134 -0
  275. package/src/weixin/open/index.ts +1 -0
  276. package/src/weixin/open/oauth2.ts +133 -0
  277. package/tests/unit/abort/abort-manager.spec.ts +225 -0
  278. package/tests/unit/abort/abort-signal-listener-manager.spec.ts +62 -0
  279. package/tests/unit/ai/ai.spec.ts +85 -0
  280. package/tests/unit/aio/content.spec.ts +105 -0
  281. package/tests/unit/aio/json.spec.ts +147 -0
  282. package/tests/unit/aio/prompt.spec.ts +111 -0
  283. package/tests/unit/basic/array.spec.ts +1 -1
  284. package/tests/unit/basic/error.spec.ts +16 -4
  285. package/tests/unit/basic/schedule.spec.ts +74 -0
  286. package/tests/unit/basic/stream.spec.ts +91 -38
  287. package/tests/unit/basic/string.spec.ts +0 -9
  288. package/tests/unit/color/rgb/analyze.spec.ts +110 -0
  289. package/tests/unit/color/rgb/construct.spec.ts +56 -0
  290. package/tests/unit/color/rgb/convert.spec.ts +60 -0
  291. package/tests/unit/color/rgb/derive.spec.ts +103 -0
  292. package/tests/unit/color/rgb/parse.spec.ts +66 -0
  293. package/tests/unit/color/rgb/serialize.spec.ts +46 -0
  294. package/tests/unit/color/xyz/analyze.spec.ts +33 -0
  295. package/tests/unit/color/xyz/construct.spec.ts +10 -0
  296. package/tests/unit/color/xyz/convert.spec.ts +18 -0
  297. package/tests/unit/credential/api-key.spec.ts +37 -0
  298. package/tests/unit/credential/bearer.spec.ts +23 -0
  299. package/tests/unit/credential/json-web-token.spec.ts +23 -0
  300. package/tests/unit/credential/password.spec.ts +41 -0
  301. package/tests/unit/cron/cron.spec.ts +84 -0
  302. package/tests/unit/css/class.spec.ts +157 -0
  303. package/tests/unit/environment/basic.spec.ts +20 -0
  304. package/tests/unit/environment/device.spec.ts +146 -0
  305. package/tests/unit/environment/feature.spec.ts +388 -0
  306. package/tests/unit/environment/geo.spec.ts +111 -0
  307. package/tests/unit/environment/runtime.spec.ts +364 -0
  308. package/tests/unit/environment/snapshot.spec.ts +4 -0
  309. package/tests/unit/environment/variable.spec.ts +190 -0
  310. package/tests/unit/event/class-event-proxy.spec.ts +225 -0
  311. package/tests/unit/event/event-manager.spec.ts +246 -0
  312. package/tests/unit/event/instance-event-proxy.spec.ts +187 -0
  313. package/tests/unit/exception/browser.spec.ts +213 -0
  314. package/tests/unit/exception/nodejs.spec.ts +144 -0
  315. package/tests/unit/exception/normalize.spec.ts +57 -0
  316. package/tests/unit/form/inputor-controller/base.spec.ts +458 -0
  317. package/tests/unit/form/inputor-controller/boolean.spec.ts +30 -0
  318. package/tests/unit/form/inputor-controller/file.spec.ts +27 -0
  319. package/tests/unit/form/inputor-controller/form.spec.ts +120 -0
  320. package/tests/unit/form/inputor-controller/helper.spec.ts +67 -0
  321. package/tests/unit/form/inputor-controller/multi-select.spec.ts +34 -0
  322. package/tests/unit/form/inputor-controller/number.spec.ts +36 -0
  323. package/tests/unit/form/inputor-controller/select.spec.ts +49 -0
  324. package/tests/unit/form/inputor-controller/text.spec.ts +34 -0
  325. package/tests/unit/http/api/api-core-host.spec.ts +207 -0
  326. package/tests/unit/http/api/api-schema.spec.ts +120 -0
  327. package/tests/unit/http/api/api-server.spec.ts +363 -0
  328. package/tests/unit/http/api/api-test.spec.ts +117 -0
  329. package/tests/unit/http/api/api.spec.ts +121 -0
  330. package/tests/unit/http/api-adapter/node-http.spec.ts +191 -0
  331. package/tests/unit/identifier/id.spec.ts +71 -0
  332. package/tests/unit/identifier/uuid.spec.ts +85 -0
  333. package/tests/unit/json/repair.spec.ts +11 -0
  334. package/tests/unit/log/log-emitter.spec.ts +33 -0
  335. package/tests/unit/log/log-scheduler.spec.ts +40 -0
  336. package/tests/unit/log/log-type.spec.ts +7 -0
  337. package/tests/unit/log/logger.spec.ts +237 -0
  338. package/tests/unit/openai/openai.spec.ts +64 -0
  339. package/tests/unit/orchestration/coordination/barrier.spec.ts +96 -0
  340. package/tests/unit/orchestration/coordination/count-down-latch.spec.ts +63 -0
  341. package/tests/unit/orchestration/coordination/errors.spec.ts +29 -0
  342. package/tests/unit/orchestration/coordination/keyed-lock.spec.ts +109 -0
  343. package/tests/unit/orchestration/coordination/mutex.spec.ts +132 -0
  344. package/tests/unit/orchestration/coordination/permit.spec.ts +43 -0
  345. package/tests/unit/orchestration/coordination/read-write-lock.spec.ts +154 -0
  346. package/tests/unit/orchestration/coordination/semaphore.spec.ts +135 -0
  347. package/tests/unit/orchestration/dispatching/dispatcher.spec.ts +41 -0
  348. package/tests/unit/orchestration/dispatching/selector/down-count-selector.spec.ts +81 -0
  349. package/tests/unit/orchestration/scheduling/scheduler.spec.ts +103 -0
  350. package/tests/unit/random/base.spec.ts +58 -0
  351. package/tests/unit/random/random-boolean.spec.ts +25 -0
  352. package/tests/unit/random/random-integer.spec.ts +32 -0
  353. package/tests/unit/random/random-number.spec.ts +33 -0
  354. package/tests/unit/random/random-string.spec.ts +22 -0
  355. package/tests/unit/reactor/alien-signals-effect.spec.ts +11 -10
  356. package/tests/unit/reactor/preact-signal.spec.ts +1 -2
  357. package/tests/unit/request/fetch/browser.spec.ts +222 -0
  358. package/tests/unit/request/fetch/general.spec.ts +43 -0
  359. package/tests/unit/request/fetch/nodejs.spec.ts +225 -0
  360. package/tests/unit/request/request/base.spec.ts +385 -0
  361. package/tests/unit/request/request/general.spec.ts +161 -0
  362. package/tests/unit/route/router/route.spec.ts +431 -0
  363. package/tests/unit/route/router/router.spec.ts +407 -0
  364. package/tests/unit/route/uri/hash.spec.ts +72 -0
  365. package/tests/unit/route/uri/pathname.spec.ts +147 -0
  366. package/tests/unit/route/uri/search.spec.ts +107 -0
  367. package/tests/unit/singleton/singleton.spec.ts +49 -0
  368. package/tests/unit/socket/client.spec.ts +208 -0
  369. package/tests/unit/socket/server.spec.ts +135 -0
  370. package/tests/unit/socket/socket-unit-heartbeat.spec.ts +214 -0
  371. package/tests/unit/storage/table.spec.ts +620 -0
  372. package/tests/unit/timer/expiration/expiration-manager.spec.ts +464 -0
  373. package/tests/unit/timer/expiration/min-heap.spec.ts +71 -0
  374. package/tests/unit/timer/expiration/remaining-manager.spec.ts +234 -0
  375. package/tests/unit/tube/helper.spec.ts +139 -0
  376. package/tests/unit/tube/tube.spec.ts +501 -0
  377. package/.oxlintrc.json +0 -5
  378. package/src/random/uuid.ts +0 -103
  379. package/tests/unit/random/uuid.spec.ts +0 -37
@@ -0,0 +1,204 @@
1
+ /**
2
+ * 定义创建具名单例项时使用的选项。
3
+ */
4
+ export interface SingletonOptions<Name extends string, Value> {
5
+ name: Name
6
+ value: () => Value
7
+ }
8
+
9
+ /**
10
+ * 表示一个具名且按需初始化的单例项。
11
+ */
12
+ export class SingletonItem<Name extends string, Value> {
13
+ private name: Name
14
+ private value: () => Value
15
+
16
+ private cache: Value | null = null
17
+
18
+ /**
19
+ * 使用名称和值工厂创建单例项。
20
+ */
21
+ constructor(options: SingletonOptions<Name, Value>) {
22
+ this.name = options.name
23
+ this.value = options.value
24
+ }
25
+
26
+ /**
27
+ * 获取该单例项的名称。
28
+ */
29
+ getName(): Name {
30
+ return this.name
31
+ }
32
+
33
+ /**
34
+ * 获取该单例项的值,并在首次访问时完成初始化。
35
+ */
36
+ getValue(): Value {
37
+ if (this.cache === null) {
38
+ this.cache = this.value()
39
+ }
40
+ return this.cache
41
+ }
42
+ }
43
+
44
+ /**
45
+ * 创建一个具名单例项实例。
46
+ *
47
+ * @example
48
+ * ```
49
+ * // Scenario 1: the item keeps a stable name and caches the computed value.
50
+ * let calls = 0
51
+ * const item = singletonItem("token", () => {
52
+ * calls += 1
53
+ * return "secret"
54
+ * })
55
+ *
56
+ * const example1 = item.getValue()
57
+ * const example2 = item.getValue()
58
+ * const example3 = item.getName()
59
+ * const example4 = example1 === example2
60
+ * const example5 = calls
61
+ *
62
+ * // Expect: "token"
63
+ * example3
64
+ * // Expect: true
65
+ * example4
66
+ * // Expect: 1
67
+ * example5
68
+ *
69
+ * // Scenario 2: different items keep independent caches.
70
+ * let leftCalls = 0
71
+ * let rightCalls = 0
72
+ * const left = singletonItem("left", () => {
73
+ * leftCalls += 1
74
+ * return 1
75
+ * })
76
+ * const right = singletonItem("right", () => {
77
+ * rightCalls += 1
78
+ * return 2
79
+ * })
80
+ *
81
+ * const example6 = left.getValue()
82
+ * const example7 = right.getValue()
83
+ * const example8 = leftCalls
84
+ * const example9 = rightCalls
85
+ *
86
+ * // Expect: 1
87
+ * example6
88
+ * // Expect: 2
89
+ * example7
90
+ * // Expect: 1
91
+ * example8
92
+ * // Expect: 1
93
+ * example9
94
+ * ```
95
+ */
96
+ export const singletonItem = <Name extends string, Value>(
97
+ name: Name,
98
+ value: () => Value
99
+ ): SingletonItem<Name, Value> => {
100
+ return new SingletonItem({ name, value })
101
+ }
102
+
103
+ type TupleToUnion<T> = T extends unknown[] ? T[number] : never
104
+ type GetName<Items> = Items extends []
105
+ ? []
106
+ : (
107
+ Items extends [infer x, ...infer xs]
108
+ ? (
109
+ x extends SingletonItem<infer Name, unknown>
110
+ ? [Name, ...GetName<xs>]
111
+ : never
112
+ )
113
+ : never
114
+ )
115
+ type GetValue<Items, Name> = Items extends []
116
+ ? never
117
+ : (
118
+ Items extends [infer x, ...infer xs]
119
+ ? (
120
+ x extends SingletonItem<infer name, infer value>
121
+ ? (
122
+ name extends Name
123
+ ? (Name extends name
124
+ ? value
125
+ : GetValue<xs, Name>
126
+ )
127
+ : GetValue<xs, Name>
128
+ )
129
+ : never
130
+ )
131
+ : never
132
+ )
133
+
134
+ /**
135
+ * 表示一个可按名称检索单例值的集合。
136
+ */
137
+ export class SingletonCollection<Item extends Array<SingletonItem<string, unknown>>> {
138
+ private map: Map<string, SingletonItem<string, unknown>>
139
+
140
+ /**
141
+ * 使用一组单例项创建集合。
142
+ */
143
+ constructor(items: [...Item]) {
144
+ this.map = new Map()
145
+ items.forEach(item => this.map.set(item.getName(), item))
146
+ }
147
+
148
+ /**
149
+ * 按名称获取集合中的单例值。
150
+ *
151
+ * @throws 当名称不存在于集合中时抛出错误。
152
+ */
153
+ getItem<Name extends TupleToUnion<GetName<Item>>>(name: Name): GetValue<Item, Name> {
154
+ const item = this.map.get(name)
155
+ if (item === undefined) {
156
+ throw new Error(`GlobalService: item ${String(name)} not found`)
157
+ }
158
+ // oxlint-disable-next-line no-unsafe-type-assertion
159
+ return item.getValue() as GetValue<Item, Name>
160
+ }
161
+ }
162
+
163
+ /**
164
+ * 从多个单例项创建单例集合。
165
+ *
166
+ * @example
167
+ * ```
168
+ * // Scenario 1: different names resolve to their corresponding cached values.
169
+ * const item1 = singletonItem("count", () => 1)
170
+ * const item2 = singletonItem("label", () => "ok")
171
+ * const collection = singletonCollection([item1, item2])
172
+ *
173
+ * const example1 = collection.getItem("count")
174
+ * const example2 = collection.getItem("label")
175
+ *
176
+ * // Expect: 1
177
+ * example1
178
+ * // Expect: "ok"
179
+ * example2
180
+ *
181
+ * // Scenario 2: reading the same name repeatedly returns the same cached value.
182
+ * let calls = 0
183
+ * const item3 = singletonItem("config", () => {
184
+ * calls += 1
185
+ * return { enabled: true }
186
+ * })
187
+ * const collection2 = singletonCollection([item3])
188
+ *
189
+ * const example3 = collection2.getItem("config")
190
+ * const example4 = collection2.getItem("config")
191
+ * const example5 = example3 === example4
192
+ * const example6 = calls
193
+ *
194
+ * // Expect: true
195
+ * example5
196
+ * // Expect: 1
197
+ * example6
198
+ * ```
199
+ */
200
+ export const singletonCollection = <Item extends Array<SingletonItem<string, unknown>>>(
201
+ items: [...Item]
202
+ ): SingletonCollection<Item> => {
203
+ return new SingletonCollection(items)
204
+ }
@@ -0,0 +1,105 @@
1
+ # Socket
2
+
3
+ ## Description
4
+
5
+ Socket 模块提供围绕双向数据通道(bidirectional data channel)的基础建模能力,用于在客户端与服务端之间组织一类可持续存在、可观测、可发送、可关闭、并带有稳定生命周期语义的数据连接。
6
+
7
+ Socket 本质上首先是数据通道,而不是某个特定业务协议的实现容器。无论是业务消息,还是心跳、初始化消息等机制性消息,从这个模块的边界来看都属于“通道中流动的数据”;它们可以在行为上被区别对待,但不应在模块级类型边界里被人为拆成两套完全不同的体系。
8
+
9
+ ## For Understanding
10
+
11
+ 理解 Socket 模块时,最重要的前提不是“WebSocket 怎么用”,而是“一个稳定的数据通道模型该对外承诺什么”。这个模块试图表达的,并不是原生 API 的逐项映射,而是以下几类更稳定的公共语义:
12
+
13
+ - 连接生命周期应被建模为可以推断和观察的状态,而不是依赖零散事件时序去猜测。
14
+ - 通道 ready 语义应明确:只有在传输已打开且当前端点已具备可工作的身份条件后,业务消息和初始消息才应真正发送。
15
+ - 心跳属于通道运行机制的一部分,但仍然是消息流中的数据,不要求固定包结构,也不应把客户端与服务端的方向差异实现成两套长期分叉的运行时。
16
+ - 对外事件应尽量表达稳定状态转移,而不是传播实现过程中的偶然中间态或重复噪音。
17
+
18
+ 因此,这个模块更适合被理解为“围绕数据通道生命周期、消息流转与连接保活机制的统一模型层”,而不是简单的 WebSocket 工具封装。这里有几个关键理解边界需要守住。
19
+
20
+ 第一,客户端和服务端虽然在方向上不同,但它们共享的是同一种问题域:如何让一个通道稳定地进入可工作状态、如何让消息在这个状态下流转、以及如何在通道不再可靠时完成清理。因此,心跳运行时应尽量收束为一套共享实现,用配置表达主动与被动方向差异,而不是把方向差异扩大成重复类层次。
21
+
22
+ 第二,心跳不应要求固定消息形状。这个模块允许使用者通过消息处理器定义“什么是 ping、什么是 pong、如何匹配响应”,统一运行时只负责调度、保留轮次状态、按规则匹配与在超时后做出关闭决策。也就是说,模块公共边界关注的是心跳行为模型,而不是某个预设协议字段。
23
+
24
+ 第三,公共事件的语义必须稳定。比如服务端的 `connect` 应在对应 `SocketUnit` 已经进入可观察、可工作的 started 状态后再发出;客户端的状态事件也应以真实状态迁移为准,而不是在重复消息流量下不断重新广播同一个 `OPEN`。如果公共事件失去这类稳定性,接入者就会被迫去猜内部实现细节,从而破坏模块边界。
25
+
26
+ 第四,这个模块关心的是“通道模型”,不是完整协议栈。它不负责定义认证协商、业务指令格式、重连策略编排、分布式会话一致性或消息持久化语义;这些都可以建立在 Socket 之上,但不应反过来改写 Socket 模块自身的父边界。
27
+
28
+ ## For Using
29
+
30
+ 从使用角度看,Socket 模块大致可以理解为四类能力。
31
+
32
+ - 通道生命周期能力:用 `SocketUnit` 与更高层的 `Socket` 表达连接的创建、关闭、重建、ready 判定与状态观察,让上层不必直接围绕原生事件时序写分散逻辑。
33
+ - 消息通道能力:统一处理业务消息、初始消息与机制性消息的发送边界。对于调用方来说,只需要关心“当前是否 ready 以及消息何时真正出站”,而不是在每处都手动判断底层传输状态。
34
+ - 心跳保活能力:通过统一心跳运行时支持主动 ping、被动 pong、超时统计、消息匹配与诊断快照。客户端与服务端在方向上可不同,但都应接入同一套共享的心跳建模方式。
35
+ - 服务端承载能力:通过服务端 `Socket` 与 `WebSocketServer` 包装类,管理多连接接入、稳定的连接事件时机,以及可直接用于本地开发和测试的服务地址发现结果。
36
+
37
+ 实际接入时,更合理的思路通常不是先盯着某个方法名,而是先判断你的问题是否确实属于“数据通道模型”边界。例如,如果你需要:
38
+
39
+ - 在 ready 之前先缓存待发送动作,等连接真正具备工作条件后再统一发送;
40
+ - 把连接状态变化暴露成稳定事件,而不是围绕原生事件做重复判定;
41
+ - 用业务自定义消息结构实现心跳,而不是被迫接受某种固定心跳包格式;
42
+ - 在服务端统一管理多条连接,并对外暴露稳定的 `connect / close / message` 事件面;
43
+
44
+ 那么这个模块就是合适的边界。
45
+
46
+ 相反,如果你的目标主要是定义一套业务协议、管理复杂重连退避、实现会话恢复、做消息落盘或做跨节点广播,这些通常已经超出 Socket 模块本身,应该在更上层的协议、编排或基础设施边界中处理。
47
+
48
+ ## For Contributing
49
+
50
+ 为 Socket 模块继续贡献时,应优先维护这几个不能退让的设计精神,而不是只追求局部功能可用。
51
+
52
+ - Socket 首先是数据通道模型,文档与实现都不应把它收窄成某个具体业务协议的包装层。
53
+ - 机制性消息与业务消息都属于通道中的数据;心跳可以有自己的行为分支,但不应被提升为一套强绑定消息格式。
54
+ - 心跳运行时应保持单一共享实现,客户端与服务端的方向差异应通过配置、处理器或薄适配层表达,而不是重新复制一套长期分叉的运行时代码。
55
+ - 生命周期事件必须表达稳定状态转移。若某个公开事件只是内部实现顺序的偶然产物,或会在同一状态下重复噪音式触发,就应优先调整实现语义,而不是把不稳定性转嫁给调用方。
56
+ - 服务端连接与客户端连接在语义上应尽量对齐:错误必须被显式观测并进入确定性的清理路径,关闭路径必须保持幂等,ready 相关副作用应由明确的状态转移驱动。
57
+
58
+ ### JSDoc 注释格式要求
59
+
60
+ - 每个公开导出的目标(类型、函数、变量、类等)都应包含 JSDoc 注释,让人在不跳转实现的情况下就能理解用途。
61
+ - JSDoc 注释第一行应为清晰且简洁的描述,该描述优先使用中文(英文也可以)。
62
+ - 如果描述后还有其他内容,应在描述后加一个空行。
63
+ - 如果有示例,应使用 `@example` 标签,后接三重反引号代码块(不带语言标识)。
64
+ - 如果有示例,应包含多个场景,展示不同用法,尤其要覆盖常见组合方式或边界输入。
65
+ - 如果有示例,应使用注释格式说明每个场景:`// Expect: <result>`。
66
+ - 如果有示例,应将结果赋值给 `example1`、`example2` 之类的变量,以保持示例易读。
67
+ - 如果有示例,`// Expect: <result>` 应该位于 `example1`、`example2` 之前,以保持示例的逻辑清晰。
68
+ - 如果有示例,应优先使用确定性示例;避免断言精确的随机输出。
69
+ - 如果函数返回结构化字符串,应展示其预期格式特征。
70
+ - 如果有参考资料,应将 `@see` 放在 `@example` 代码块之后,并用一个空行分隔。
71
+
72
+ ### 实现规范要求
73
+
74
+ - 不同程序元素之间使用一个空行分隔,保持结构清楚。这里的程序元素,通常指函数、类型、常量,以及直接服务于它们的辅助元素。
75
+ - 某程序元素独占的辅助元素与该程序元素本身视为一个整体,不要在它们之间添加空行。
76
+ - 程序元素的辅助元素应该放置在该程序元素的上方,以保持阅读时的逻辑顺序。
77
+ - 若辅助元素被多个程序元素共享,则应将其视为独立的程序元素,放在这些程序元素中第一个相关目标的上方,并与后续程序元素之间保留一个空行。
78
+ - 辅助元素也应该像其它程序元素一样,保持清晰的命名和适当的注释,以便在需要阅读实现细节时能够快速理解它们的作用和使用方式。
79
+ - 辅助元素的命名必须以前缀 `internal` 开头(或 `Internal`,大小写不敏感)。
80
+ - 辅助元素永远不要公开导出。
81
+ - 被模块内多个不同文件中的程序元素共享的辅助元素,应该放在一个单独的文件中,例如 `./src/socket/internal.ts`。
82
+ - 模块内可以包含子模块。只有当某个子目录表达一个稳定、可单独理解、且可能被父模块重导出的子问题域时,才应将其视为子模块。
83
+ - 子模块包含多个文件时,应该为其单独创建子文件夹,并为其创建单独的 Barrel 文件;父模块的 Barrel 文件再重导出子模块的 Barrel 文件。
84
+ - 子模块不需要有自己的 `README.md`。
85
+ - 子模块可以有自己的 `internal.ts` 文件,多个子模块共享的辅助元素应该放在父模块的 `internal.ts` 文件中,单个子模块共享的辅助元素应该放在该子模块的 `internal.ts` 文件中。
86
+ - 对模块依赖关系的要求(通常是不循环依赖或不反向依赖)与对 DRY 的要求可能产生冲突。此时,若复用的代码数量不大,可以适当牺牲 DRY,复制粘贴并保留必要的注释说明;若复用的代码数量较大,则可以将其抽象到新的文件或子模块中,如 `common.ts`,并在需要的地方导入使用。
87
+ - 与 socket 相关的实现应优先围绕生命周期状态、ready 语义、消息流转、连接级错误处理、心跳匹配与关闭策略组织,避免把协议专属细节或业务会话策略直接下沉为模块长期公共语义。
88
+
89
+ ### 导出策略要求
90
+
91
+ - 保持内部辅助项和内部符号为私有,不要让外部接入依赖临时性的内部结构。
92
+ - 每个模块都应有一个用于重导出所有公共 API 的 Barrel 文件。
93
+ - Barrel 文件应命名为 `index.ts`,放在模块目录根部,并且所有公共 API 都应从该文件导出。
94
+ - 新增公共能力时,应优先检查它是否表达稳定、清楚且值得长期维护的通道语义,而不是某段实现细节的便捷暴露;仅在确认需要长期对外承诺时再加入 Barrel 导出。
95
+
96
+ ### 测试要求
97
+
98
+ - 若程序元素是函数,则只为该函数编写一个测试,如果该函数需要测试多个用例,应放在同一个测试中。
99
+ - 若程序元素是类,则至少要为该类的每一个方法编写一个测试,如果该方法需要测试多个用例,应放在同一个测试中。
100
+ - 若程序元素是类,除了为该类的每一个方法编写至少一个测试之外,还可以为该类编写任意多个测试,以覆盖该类的不同使用场景或边界情况。
101
+ - 若编写测试时需要用到辅助元素(Mock 或 Spy 等),可以在测试文件中直接定义这些辅助元素。若辅助元素较为简单,则可以直接放在每一个测试内部,优先保证每个测试的独立性,而不是追求极致 DRY;若辅助元素较为复杂或需要在多个测试中复用,则可以放在测试文件顶部,供该测试文件中的所有测试使用。
102
+ - 测试顺序应与源文件中被测试目标的原始顺序保持一致。
103
+ - 若该模块不需要测试,必须在说明文件中明确说明该模块不需要测试,并说明理由。一般来说,只有在该模块没有可执行的公共函数、只承载类型层表达,或其语义已被上层模块的测试完整覆盖且重复测试几乎不再带来额外价值时,才适合这样处理。
104
+ - 模块的单元测试文件目录是 `./tests/unit/socket`,若模块包含子模块,则子模块的单元测试文件目录为 `./tests/unit/socket/<sub-module-name>`。
105
+ - 对这个模块来说,测试应优先覆盖 ready 状态转移、消息排队与释放、服务端连接事件时机、错误与关闭路径的幂等性、心跳消息匹配顺序、超时关闭阈值,以及服务地址发现结果在本地环境中的可用性。
@@ -0,0 +1,2 @@
1
+ export * from "./socket.ts"
2
+ export * from "./socket-unit.ts"