@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,311 @@
1
+ import type { BrowserName, BrowserType, CPUArch, DeviceType, DeviceVendor, EngineName, Extension, OSName } from "ua-parser-js/enums"
2
+
3
+ import { UAParser } from "ua-parser-js"
4
+ import { isAppleSilicon } from "ua-parser-js/device-detection"
5
+ import { isFrozenUA } from "ua-parser-js/helpers"
6
+ import { isAIAssistant, isAICrawler, isBot } from "ua-parser-js/bot-detection"
7
+ import { isChromeFamily, isElectron, isFromEU, isStandalonePWA } from "ua-parser-js/browser-detection"
8
+
9
+ import { Bots, CLIs, Crawlers, Emails, ExtraDevices, Fetchers, InApps, Libraries, MediaPlayers, Vehicles } from "ua-parser-js/extensions"
10
+
11
+ import type { IResult } from "ua-parser-js"
12
+
13
+ interface NetworkInformation {
14
+ downlink: number
15
+ downlinkMax: number
16
+ effectiveType: "slow-2g" | "2g" | "3g" | "4g"
17
+ rtt: number
18
+ saveData: boolean
19
+ type: "bluetooth" | "cellular" | "ethernet" | "none" | "wifi" | "wimax" | "other" | "unknown"
20
+ }
21
+ const getNetworkInformation = (): NetworkInformation | undefined => {
22
+ let connection: NetworkInformation | undefined;
23
+ if ("connection" in navigator) {
24
+ // oxlint-disable-next-line no-unsafe-type-assertion
25
+ connection = navigator.connection as NetworkInformation;
26
+ } else if ("mozConnection" in navigator) {
27
+ // oxlint-disable-next-line no-unsafe-type-assertion
28
+ connection = navigator.mozConnection as NetworkInformation;
29
+ } else if ("webkitConnection" in navigator) {
30
+ // oxlint-disable-next-line no-unsafe-type-assertion
31
+ connection = navigator.webkitConnection as NetworkInformation;
32
+ }
33
+ return connection;
34
+ };
35
+
36
+ /**
37
+ * Describe navigator-level device and network metadata.
38
+ */
39
+ export interface DeviceNavigatorInfo {
40
+ oscpu: string | undefined
41
+ deviceMemory: number | undefined
42
+ hardwareConcurrency: number | undefined
43
+ maxTouchPoints: number | undefined
44
+ platform: Navigator['platform']
45
+
46
+ devicePosture: "continuous" | "folded" | undefined
47
+ connectionDownlink: NetworkInformation['downlink'] | undefined
48
+ connectionDownlinkMax: NetworkInformation['downlinkMax'] | undefined
49
+ connectionEffectiveType: NetworkInformation['effectiveType'] | undefined
50
+ connectionRtt: NetworkInformation['rtt'] | undefined
51
+ connectionSaveData: NetworkInformation['saveData'] | undefined
52
+ connectionType: NetworkInformation['type'] | undefined
53
+ online: boolean
54
+ cookiesEnabled: boolean
55
+ language: string
56
+ languages: string[]
57
+ pdfViewerEnabled: boolean
58
+ }
59
+ /**
60
+ * Collect device information from the Navigator API.
61
+ */
62
+ export const getDeviceNavigatorInfo = (): DeviceNavigatorInfo => {
63
+ const connection = getNetworkInformation();
64
+
65
+ return {
66
+ oscpu: "oscpu" in navigator ? String(navigator.oscpu) : undefined,
67
+ hardwareConcurrency: "hardwareConcurrency" in navigator ? Number.parseInt(String(navigator.hardwareConcurrency), 10) : undefined,
68
+ deviceMemory: "deviceMemory" in navigator ? Number.parseFloat(String(navigator.deviceMemory)) : undefined,
69
+ maxTouchPoints: navigator.maxTouchPoints,
70
+ platform: navigator.platform,
71
+
72
+ // oxlint-disable-next-line no-unsafe-type-assertion
73
+ devicePosture: "devicePosture" in navigator ? (navigator.devicePosture as { type: "continuous" | "folded" }).type : undefined,
74
+ connectionDownlink: connection?.downlink ?? undefined,
75
+ connectionDownlinkMax: connection?.downlinkMax ?? undefined,
76
+ connectionEffectiveType: connection?.effectiveType ?? undefined,
77
+ connectionRtt: connection?.rtt ?? undefined,
78
+ connectionSaveData: connection?.saveData ?? undefined,
79
+ connectionType: connection?.type ?? undefined,
80
+ online: navigator.onLine,
81
+ cookiesEnabled: navigator.cookieEnabled,
82
+ language: navigator.language,
83
+ languages: [...navigator.languages],
84
+ pdfViewerEnabled: navigator.pdfViewerEnabled,
85
+ }
86
+ }
87
+
88
+ /**
89
+ * Describe device metadata parsed from a user-agent string.
90
+ */
91
+ export interface DeviceUserAgentInfo {
92
+ ua: string
93
+ uaIsFrozen: boolean
94
+
95
+ cpuArchitecture: typeof CPUArch[keyof typeof CPUArch] | undefined
96
+
97
+ osName: typeof OSName[keyof typeof OSName] | undefined
98
+ osVersion: IResult['os']['version'] | undefined
99
+
100
+ engineName: typeof EngineName[keyof typeof EngineName] | undefined
101
+ engineVersion: IResult['engine']['version'] | undefined
102
+
103
+ browserName:
104
+ | typeof BrowserName[keyof typeof BrowserName]
105
+ | typeof Extension['BrowserName']['CLI'][keyof typeof Extension['BrowserName']['CLI']]
106
+ | typeof Extension['BrowserName']['Crawler'][keyof typeof Extension['BrowserName']['Crawler']]
107
+ | typeof Extension['BrowserName']['Email'][keyof typeof Extension['BrowserName']['Email']]
108
+ | typeof Extension['BrowserName']['Fetcher'][keyof typeof Extension['BrowserName']['Fetcher']]
109
+ | typeof Extension['BrowserName']['InApp'][keyof typeof Extension['BrowserName']['InApp']]
110
+ | typeof Extension['BrowserName']['Library'][keyof typeof Extension['BrowserName']['Library']]
111
+ | undefined
112
+ browserVersion: IResult['browser']['version'] | undefined
113
+ browserMajor: IResult['browser']['major'] | undefined
114
+ browserType: typeof BrowserType[keyof typeof BrowserType] | undefined
115
+ browserIsAiAssistant: boolean
116
+ browserIsAiCrawler: boolean
117
+ browserIsBot: boolean
118
+ browserIsChromeFamily: boolean
119
+ browserIsElectron: boolean
120
+ browserIsFromEU: boolean
121
+ browserIsStandalonePWA: boolean
122
+
123
+ deviceType: typeof DeviceType[keyof typeof DeviceType] | undefined
124
+ deviceVendor:
125
+ | typeof DeviceVendor[keyof typeof DeviceVendor]
126
+ | typeof Extension['DeviceVendor']['Vehicle'][keyof typeof Extension['DeviceVendor']['Vehicle']]
127
+ | undefined
128
+ deviceModel: IResult['device']['model'] | undefined
129
+ deviceIsAppleSilicon: boolean
130
+ }
131
+ /**
132
+ * Parse the user-agent string into normalized device metadata.
133
+ *
134
+ * @see {@link https://docs.uaparser.dev/ | UAParser.js}
135
+ */
136
+ export const parseUserAgent = (userAgent: string): DeviceUserAgentInfo => {
137
+ // @ts-expect-error - UAParser.js type definitions has unknown issue with extensions
138
+ const parser = new UAParser([Bots, CLIs, Crawlers, Emails, ExtraDevices, Fetchers, InApps, Libraries, MediaPlayers, Vehicles])
139
+ parser.setUA(userAgent)
140
+ const result = parser.getResult()
141
+
142
+ let browserIsElectron: boolean
143
+ try {
144
+ browserIsElectron = isElectron()
145
+ } catch {
146
+ browserIsElectron = false
147
+ }
148
+
149
+ let browserIsStandalonePWA: boolean
150
+ try {
151
+ browserIsStandalonePWA = isStandalonePWA()
152
+ } catch {
153
+ browserIsStandalonePWA = false
154
+ }
155
+
156
+ return {
157
+ ua: userAgent,
158
+ uaIsFrozen: isFrozenUA(userAgent),
159
+
160
+ cpuArchitecture: result.cpu.architecture,
161
+
162
+ // oxlint-disable-next-line no-unsafe-type-assertion
163
+ osName: result.os.name as typeof OSName[keyof typeof OSName],
164
+ osVersion: result.os.version,
165
+
166
+ engineName: result.engine.name,
167
+ engineVersion: result.engine.version,
168
+
169
+ // oxlint-disable-next-line no-unsafe-type-assertion
170
+ browserName: result.browser.name as typeof BrowserName[keyof typeof BrowserName],
171
+ browserVersion: result.browser.version,
172
+ browserMajor: result.browser.major,
173
+ browserType: result.browser.type,
174
+ browserIsAiAssistant: isAIAssistant(userAgent),
175
+ browserIsAiCrawler: isAICrawler(userAgent),
176
+ browserIsBot: isBot(userAgent),
177
+ browserIsChromeFamily: isChromeFamily(userAgent),
178
+ browserIsElectron,
179
+ browserIsFromEU: isFromEU(),
180
+ browserIsStandalonePWA,
181
+
182
+ deviceType: result.device.type,
183
+ // oxlint-disable-next-line no-unsafe-type-assertion
184
+ deviceVendor: result.device.vendor as typeof DeviceVendor[keyof typeof DeviceVendor],
185
+ deviceModel: result.device.model,
186
+ deviceIsAppleSilicon: isAppleSilicon(userAgent),
187
+ }
188
+ }
189
+
190
+ const getSafeAreaInset = (edge: "top" | "bottom" | "left" | "right"): number => {
191
+ const style = getComputedStyle(document.documentElement);
192
+
193
+ // 尝试 env(),现代 Safari
194
+ let value = style.getPropertyValue(`env(safe-area-inset-${edge})`);
195
+ if (value === "") {
196
+ // 尝试 constant(),旧版 iOS
197
+ value = style.getPropertyValue(`constant(safe-area-inset-${edge})`);
198
+ }
199
+
200
+ return value !== "" ? Number.parseFloat(value) : 0;
201
+ }
202
+
203
+ /**
204
+ * Describe screen, viewport, and safe-area metadata.
205
+ */
206
+ export interface DeviceScreenInfo {
207
+ pixelRatio: number
208
+ orientationOriginal: OrientationType | 'unknown'
209
+ orientationCalculated: 'portrait' | 'landscape'
210
+
211
+ screenWidth: number
212
+ screenHeight: number
213
+ screenAvailableWidth: number
214
+ screenAvailableHeight: number
215
+ browserWidth: number
216
+ browserHeight: number
217
+ /**
218
+ * With scrollbar.
219
+ */
220
+ viewportWidth: number
221
+ /**
222
+ * With scrollbar.
223
+ */
224
+ viewportHeight: number
225
+ /**
226
+ * Without scrollbar.
227
+ */
228
+ viewportAvailableWidth: number
229
+ /**
230
+ * Without scrollbar.
231
+ */
232
+ viewportAvailableHeight: number
233
+ /**
234
+ * Without scrollbar.
235
+ */
236
+ visualViewportWidth: number | undefined
237
+ /**
238
+ * Without scrollbar.
239
+ */
240
+ visualViewportHeight: number | undefined
241
+ visualViewportOffsetLeft: number | undefined
242
+ visualViewportOffsetTop: number | undefined
243
+ visualViewportPageLeft: number | undefined
244
+ visualViewportPageTop: number | undefined
245
+ visualViewportScale: number | undefined
246
+ safeAreaTop: number
247
+ safeAreaBottom: number
248
+ safeAreaLeft: number
249
+ safeAreaRight: number
250
+ contentWidth: number
251
+ contentHeight: number
252
+ }
253
+ /**
254
+ * Collect screen and viewport information from the current window.
255
+ *
256
+ * @see {@link https://developer.mozilla.org/en-US/docs/Web/API/Window/visualViewport}
257
+ */
258
+ export const getDeviceScreenInfo = (): DeviceScreenInfo => {
259
+ return {
260
+ pixelRatio: window.devicePixelRatio,
261
+ orientationOriginal: window.screen.orientation?.type || 'unknown',
262
+ orientationCalculated: window.innerWidth > window.innerHeight ? 'landscape' : 'portrait',
263
+
264
+ screenWidth: window.screen.width,
265
+ screenHeight: window.screen.height,
266
+ screenAvailableWidth: window.screen.availWidth,
267
+ screenAvailableHeight: window.screen.availHeight,
268
+ browserWidth: window.outerWidth,
269
+ browserHeight: window.outerHeight,
270
+ viewportWidth: window.innerWidth,
271
+ viewportHeight: window.innerHeight,
272
+ viewportAvailableWidth: document.documentElement.clientWidth,
273
+ viewportAvailableHeight: document.documentElement.clientHeight,
274
+ visualViewportWidth: window.visualViewport?.width,
275
+ visualViewportHeight: window.visualViewport?.height,
276
+ visualViewportOffsetLeft: window.visualViewport?.offsetLeft,
277
+ visualViewportOffsetTop: window.visualViewport?.offsetTop,
278
+ visualViewportPageLeft: window.visualViewport?.pageLeft,
279
+ visualViewportPageTop: window.visualViewport?.pageTop,
280
+ visualViewportScale: window.visualViewport?.scale,
281
+ safeAreaTop: getSafeAreaInset('top'),
282
+ safeAreaBottom: getSafeAreaInset('bottom'),
283
+ safeAreaLeft: getSafeAreaInset('left'),
284
+ safeAreaRight: getSafeAreaInset('right'),
285
+ contentWidth: document.documentElement.scrollWidth,
286
+ contentHeight: document.documentElement.scrollHeight
287
+ };
288
+ }
289
+
290
+ /**
291
+ * Describe merged device information from navigator, UA, and screen.
292
+ */
293
+ export interface DeviceInfo {
294
+ navigator: DeviceNavigatorInfo
295
+ userAgent: DeviceUserAgentInfo
296
+ screen: DeviceScreenInfo
297
+ }
298
+ /**
299
+ * Get merged device information from navigator, user-agent, and screen.
300
+ */
301
+ export const getDeviceInfo = (userAgent: string): DeviceInfo => {
302
+ const navigatorInfo = getDeviceNavigatorInfo();
303
+ const userAgentInfo = parseUserAgent(userAgent);
304
+ const screenInfo = getDeviceScreenInfo();
305
+
306
+ return {
307
+ navigator: navigatorInfo,
308
+ userAgent: userAgentInfo,
309
+ screen: screenInfo
310
+ };
311
+ }
@@ -0,0 +1,285 @@
1
+ import { useFactory } from "./basic.ts"
2
+
3
+ import type { Use } from "./basic.ts"
4
+
5
+ import type { StringAutoCompletable } from "../type/string.ts"
6
+
7
+ /**
8
+ * Define built-in and custom feature keys for capability detection.
9
+ */
10
+ export type Feature =
11
+ | StringAutoCompletable
12
+ | "process"
13
+ | "navigator"
14
+ | "permissions"
15
+ | "document"
16
+ | "css"
17
+
18
+ interface FeatureRegistryItem {
19
+ feature: Feature
20
+ detect: () => boolean
21
+ }
22
+ const internalFeatureRegistry = new Map<Feature, FeatureRegistryItem>();
23
+ /**
24
+ * Check whether a feature is registered.
25
+ */
26
+ export const isFeatureRegistered = (feature: Feature): boolean => {
27
+ return internalFeatureRegistry.has(feature);
28
+ };
29
+ /**
30
+ * Register a feature detector.
31
+ */
32
+ export const registerFeature = (item: FeatureRegistryItem): void => {
33
+ internalFeatureRegistry.set(item.feature, item);
34
+ };
35
+ /**
36
+ * Unregister a feature detector.
37
+ */
38
+ export const unregisterFeature = (feature: Feature): void => {
39
+ internalFeatureRegistry.delete(feature);
40
+ };
41
+ /**
42
+ * List all registered feature keys.
43
+ */
44
+ export const listFeatures = (): Feature[] => {
45
+ return Array.from(internalFeatureRegistry.keys());
46
+ }
47
+
48
+ /**
49
+ * Get a feature registry item by feature key.
50
+ */
51
+ export const getFeatureRegistryItem = (feature: Feature): FeatureRegistryItem | undefined => {
52
+ return internalFeatureRegistry.get(feature);
53
+ }
54
+
55
+ /**
56
+ * Define detection results for registered features.
57
+ */
58
+ export type FeatureFlags = Record<Feature, boolean>;
59
+ /**
60
+ * Get the flags for all registered features.
61
+ */
62
+ export const getFeatureFlags = (): FeatureFlags => {
63
+ // oxlint-disable-next-line no-unsafe-type-assertion
64
+ const flags: FeatureFlags = {} as FeatureFlags;
65
+
66
+ for (const [name, item] of internalFeatureRegistry) {
67
+ flags[name] = item.detect();
68
+ }
69
+
70
+ return flags;
71
+ }
72
+
73
+ /**
74
+ * Check if the current environment satisfies the specified feature.
75
+ */
76
+ export const isSatisfiesFeature = (feature: Feature): boolean => {
77
+ const featureRegistryItem = getFeatureRegistryItem(feature);
78
+ if (featureRegistryItem === undefined) {
79
+ throw new Error(`Feature "${feature}" is not registered.`);
80
+ }
81
+ return featureRegistryItem.detect() === true;
82
+ }
83
+
84
+ /**
85
+ * Check if the current environment satisfies the specified feature conditions.
86
+ */
87
+ export const isSatisfiesFeatures = (condition: Partial<FeatureFlags>): boolean => {
88
+ let result = true;
89
+ Object.keys(condition).forEach((feature) => {
90
+ const featureRegistryItem = getFeatureRegistryItem(feature as Feature);
91
+ if (featureRegistryItem === undefined) {
92
+ throw new Error(`Feature "${feature}" is not registered.`);
93
+ }
94
+ if (featureRegistryItem.detect() !== condition[feature]) {
95
+ result = false;
96
+ }
97
+ });
98
+ return result;
99
+ }
100
+
101
+ /**
102
+ * Check if the `process` object is available in the environment.
103
+ */
104
+ export const supportProcess = (): boolean => {
105
+ return typeof process !== "undefined" && process !== null && typeof process === "object"
106
+ }
107
+ /**
108
+ * Get the `process` object from the current environment.
109
+ */
110
+ export const getProcess = (): NodeJS.Process => {
111
+ return globalThis.process
112
+ }
113
+ /**
114
+ * Get the `process` object if it is available, otherwise throw an error.
115
+ */
116
+ export const ensureProcess = (): NodeJS.Process => {
117
+ if (supportProcess() === true) {
118
+ return getProcess()
119
+ } else {
120
+ throw new Error("The process object is not supported in the current environment.")
121
+ }
122
+ }
123
+ /**
124
+ * Execute a function with the `process` object if it is available.
125
+ */
126
+ export const useProcess: Use<NodeJS.Process> = useFactory(getProcess, supportProcess)
127
+ registerFeature({
128
+ feature: "process",
129
+ detect: supportProcess,
130
+ })
131
+
132
+ /**
133
+ * Check if the `navigator` object is available in the environment.
134
+ */
135
+ export const supportNavigator = (): boolean => {
136
+ return typeof navigator !== "undefined" && navigator !== null && typeof navigator === "object"
137
+ }
138
+ /**
139
+ * Get the `navigator` object from the current environment.
140
+ */
141
+ export const getNavigator = (): Navigator => {
142
+ return globalThis.navigator
143
+ }
144
+ /**
145
+ * Get the `navigator` object if it is available, otherwise throw an error.
146
+ */
147
+ export const ensureNavigator = (): Navigator => {
148
+ if (supportNavigator() === true) {
149
+ return getNavigator()
150
+ } else {
151
+ throw new Error("The navigator object is not supported in the current environment.")
152
+ }
153
+ }
154
+ /**
155
+ * Execute a function with the `navigator` object if it is available.
156
+ */
157
+ export const useNavigator: Use<Navigator> = useFactory(getNavigator, supportNavigator)
158
+ registerFeature({
159
+ feature: "navigator",
160
+ detect: supportNavigator,
161
+ })
162
+
163
+ /**
164
+ * Check if the `clipboard` API is available in the environment.
165
+ */
166
+ export const supportClipboard = (): boolean => {
167
+ return supportNavigator() && "clipboard" in navigator
168
+ }
169
+ /**
170
+ * Get the `clipboard` API from the current environment.
171
+ */
172
+ export const getClipboard = (): Clipboard => {
173
+ return navigator.clipboard
174
+ }
175
+ /**
176
+ * Get the `clipboard` API if it is available, otherwise throw an error.
177
+ */
178
+ export const ensureClipboard = (): Clipboard => {
179
+ if (supportClipboard() === true) {
180
+ return getClipboard()
181
+ } else {
182
+ throw new Error("The clipboard API is not supported in the current environment.")
183
+ }
184
+ }
185
+ /**
186
+ * Execute a function with the `clipboard` API if it is available.
187
+ */
188
+ export const useClipboard: Use<Clipboard> = useFactory(getClipboard, supportClipboard)
189
+ registerFeature({
190
+ feature: "clipboard",
191
+ detect: supportClipboard,
192
+ })
193
+
194
+ /**
195
+ * Check if the `permissions` API is available in the environment.
196
+ */
197
+ export const supportPermissions = (): boolean => {
198
+ return supportNavigator() && "permissions" in navigator
199
+ }
200
+ /**
201
+ * Get the `permissions` API from the current environment.
202
+ */
203
+ export const getPermissions = (): Permissions => {
204
+ return navigator.permissions
205
+ }
206
+ /**
207
+ * Get the `permissions` API if it is available, otherwise throw an error.
208
+ */
209
+ export const ensurePermissions = (): Permissions => {
210
+ if (supportPermissions() === true) {
211
+ return getPermissions()
212
+ } else {
213
+ throw new Error("The permissions API is not supported in the current environment.")
214
+ }
215
+ }
216
+ /**
217
+ * Execute a function with the `permissions` API if it is available.
218
+ */
219
+ export const usePermissions: Use<Permissions> = useFactory(getPermissions, supportPermissions)
220
+ registerFeature({
221
+ feature: "permissions",
222
+ detect: supportPermissions,
223
+ })
224
+
225
+ /**
226
+ * Check if the `document` object is available in the environment.
227
+ */
228
+ export const supportDocument = (): boolean => {
229
+ return typeof document !== "undefined" && document !== null && typeof document === "object"
230
+ }
231
+ /**
232
+ * Get the `document` object from the current environment.
233
+ */
234
+ export const getDocument = (): Document => {
235
+ return globalThis.document
236
+ }
237
+ /**
238
+ * Get the `document` object if it is available, otherwise throw an error.
239
+ */
240
+ export const ensureDocument = (): Document => {
241
+ if (supportDocument() === true) {
242
+ return getDocument()
243
+ } else {
244
+ throw new Error("The document object is not supported in the current environment.")
245
+ }
246
+ }
247
+ /**
248
+ * Execute a function with the `document` object if it is available.
249
+ */
250
+ export const useDocument: Use<Document> = useFactory(getDocument, supportDocument)
251
+ registerFeature({
252
+ feature: "document",
253
+ detect: supportDocument,
254
+ })
255
+
256
+ /**
257
+ * Check if the `CSS` object is available in the environment.
258
+ */
259
+ export const supportCSS = (): boolean => {
260
+ return typeof CSS !== "undefined" && CSS !== null && typeof CSS === "object"
261
+ }
262
+ /**
263
+ * Get the `CSS` object from the current environment.
264
+ */
265
+ export const getCSS = (): typeof CSS => {
266
+ return globalThis.CSS
267
+ }
268
+ /**
269
+ * Get the `CSS` object if it is available, otherwise throw an error.
270
+ */
271
+ export const ensureCSS = (): typeof CSS => {
272
+ if (supportCSS() === true) {
273
+ return getCSS()
274
+ } else {
275
+ throw new Error("The CSS object is not supported in the current environment.")
276
+ }
277
+ }
278
+ /**
279
+ * Execute a function with the `CSS` object if it is available.
280
+ */
281
+ export const useCSS: Use<typeof CSS> = useFactory(getCSS, supportCSS)
282
+ registerFeature({
283
+ feature: "css",
284
+ detect: supportCSS,
285
+ })