@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.
- package/CHANGELOG.md +61 -0
- package/README.md +123 -36
- package/dist/index.js +715 -4
- package/dist/index.js.map +981 -13
- package/oxlint.config.ts +6 -0
- package/package.json +36 -18
- package/src/abort/README.md +92 -0
- package/src/abort/abort-manager.ts +278 -0
- package/src/abort/abort-signal-listener-manager.ts +81 -0
- package/src/abort/index.ts +2 -0
- package/src/ai/README.md +1 -0
- package/src/ai/ai.ts +107 -0
- package/src/ai/chat-completion-ai/aihubmix-chat-completion.ts +78 -0
- package/src/ai/chat-completion-ai/chat-completion-ai.ts +270 -0
- package/src/ai/chat-completion-ai/chat-completion.ts +189 -0
- package/src/ai/chat-completion-ai/index.ts +7 -0
- package/src/ai/chat-completion-ai/lingyiwanwu-chat-completion.ts +78 -0
- package/src/ai/chat-completion-ai/ohmygpt-chat-completion.ts +78 -0
- package/src/ai/chat-completion-ai/openai-next-chat-completion.ts +78 -0
- package/src/ai/embedding-ai/embedding-ai.ts +63 -0
- package/src/ai/embedding-ai/embedding.ts +50 -0
- package/src/ai/embedding-ai/index.ts +4 -0
- package/src/ai/embedding-ai/openai-next-embedding.ts +23 -0
- package/src/ai/index.ts +4 -0
- package/src/aio/README.md +100 -0
- package/src/aio/content.ts +141 -0
- package/src/aio/index.ts +3 -0
- package/src/aio/json.ts +127 -0
- package/src/aio/prompt.ts +246 -0
- package/src/basic/README.md +72 -116
- package/src/basic/error.ts +19 -5
- package/src/basic/function.ts +83 -64
- package/src/basic/index.ts +1 -0
- package/src/basic/is.ts +152 -71
- package/src/basic/promise.ts +29 -8
- package/src/basic/schedule.ts +111 -0
- package/src/basic/stream.ts +135 -25
- package/src/basic/string.ts +2 -33
- package/src/color/README.md +105 -0
- package/src/color/index.ts +3 -0
- package/src/color/internal.ts +42 -0
- package/src/color/rgb/analyze.ts +236 -0
- package/src/color/rgb/construct.ts +130 -0
- package/src/color/rgb/convert.ts +227 -0
- package/src/color/rgb/derive.ts +303 -0
- package/src/color/rgb/index.ts +6 -0
- package/src/color/rgb/internal.ts +208 -0
- package/src/color/rgb/parse.ts +302 -0
- package/src/color/rgb/serialize.ts +144 -0
- package/src/color/types.ts +57 -0
- package/src/color/xyz/analyze.ts +80 -0
- package/src/color/xyz/construct.ts +19 -0
- package/src/color/xyz/convert.ts +71 -0
- package/src/color/xyz/index.ts +3 -0
- package/src/color/xyz/internal.ts +23 -0
- package/src/credential/README.md +107 -0
- package/src/credential/api-key.ts +158 -0
- package/src/credential/bearer.ts +73 -0
- package/src/credential/index.ts +4 -0
- package/src/credential/json-web-token.ts +96 -0
- package/src/credential/password.ts +170 -0
- package/src/cron/README.md +86 -0
- package/src/cron/cron.ts +87 -0
- package/src/cron/index.ts +1 -0
- package/src/css/README.md +93 -0
- package/src/css/class.ts +559 -0
- package/src/css/index.ts +1 -0
- package/src/drizzle/README.md +1 -0
- package/src/drizzle/drizzle.ts +1 -0
- package/src/drizzle/helper.ts +47 -0
- package/src/drizzle/index.ts +5 -0
- package/src/drizzle/infer.ts +52 -0
- package/src/drizzle/kysely.ts +8 -0
- package/src/drizzle/pagination.ts +200 -0
- package/src/email/README.md +1 -0
- package/src/email/index.ts +1 -0
- package/src/email/resend.ts +25 -0
- package/src/encoding/README.md +66 -79
- package/src/encoding/base64.ts +13 -4
- package/src/environment/README.md +97 -0
- package/src/environment/basic.ts +26 -0
- package/src/environment/device.ts +311 -0
- package/src/environment/feature.ts +285 -0
- package/src/environment/geo.ts +337 -0
- package/src/environment/index.ts +7 -0
- package/src/environment/runtime.ts +400 -0
- package/src/environment/snapshot.ts +60 -0
- package/src/environment/variable.ts +239 -0
- package/src/event/README.md +90 -0
- package/src/event/class-event-proxy.ts +229 -0
- package/src/event/common.ts +29 -0
- package/src/event/event-manager.ts +203 -0
- package/src/event/index.ts +4 -0
- package/src/event/instance-event-proxy.ts +187 -0
- package/src/event/internal.ts +24 -0
- package/src/exception/README.md +96 -0
- package/src/exception/browser.ts +219 -0
- package/src/exception/index.ts +4 -0
- package/src/exception/nodejs.ts +169 -0
- package/src/exception/normalize.ts +106 -0
- package/src/exception/types.ts +99 -0
- package/src/form/README.md +25 -0
- package/src/form/index.ts +1 -0
- package/src/form/inputor-controller/base.ts +874 -0
- package/src/form/inputor-controller/boolean.ts +39 -0
- package/src/form/inputor-controller/file.ts +39 -0
- package/src/form/inputor-controller/form.ts +181 -0
- package/src/form/inputor-controller/helper.ts +117 -0
- package/src/form/inputor-controller/index.ts +17 -0
- package/src/form/inputor-controller/multi-select.ts +99 -0
- package/src/form/inputor-controller/number.ts +116 -0
- package/src/form/inputor-controller/select.ts +109 -0
- package/src/form/inputor-controller/text.ts +82 -0
- package/src/http/READMD.md +1 -0
- package/src/http/api/api-core.ts +84 -0
- package/src/http/api/api-handler.ts +79 -0
- package/src/http/api/api-host.ts +47 -0
- package/src/http/api/api-result.ts +56 -0
- package/src/http/api/api-schema.ts +154 -0
- package/src/http/api/api-server.ts +130 -0
- package/src/http/api/api-test.ts +142 -0
- package/src/http/api/api-type.ts +37 -0
- package/src/http/api/api.ts +81 -0
- package/src/http/api/index.ts +11 -0
- package/src/http/api-adapter/api-core-node-http.ts +260 -0
- package/src/http/api-adapter/api-host-node-http.ts +156 -0
- package/src/http/api-adapter/api-result-arktype.ts +297 -0
- package/src/http/api-adapter/api-result-zod.ts +286 -0
- package/src/http/api-adapter/index.ts +5 -0
- package/src/http/bin/gen-api-list/gen-api-list.ts +126 -0
- package/src/http/bin/gen-api-list/index.ts +1 -0
- package/src/http/bin/gen-api-test/gen-api-test.ts +136 -0
- package/src/http/bin/gen-api-test/index.ts +1 -0
- package/src/http/bin/gen-api-type/calc-code.ts +25 -0
- package/src/http/bin/gen-api-type/gen-api-type.ts +127 -0
- package/src/http/bin/gen-api-type/index.ts +2 -0
- package/src/http/bin/index.ts +2 -0
- package/src/http/index.ts +3 -0
- package/src/huawei/README.md +1 -0
- package/src/huawei/index.ts +2 -0
- package/src/huawei/moderation/index.ts +1 -0
- package/src/huawei/moderation/moderation.ts +355 -0
- package/src/huawei/obs/esdk-obs-nodejs.d.ts +87 -0
- package/src/huawei/obs/index.ts +1 -0
- package/src/huawei/obs/obs.ts +42 -0
- package/src/identifier/README.md +92 -0
- package/src/identifier/id.ts +119 -0
- package/src/identifier/index.ts +2 -0
- package/src/identifier/uuid.ts +187 -0
- package/src/index.ts +33 -1
- package/src/json/README.md +92 -0
- package/src/json/index.ts +1 -0
- package/src/json/repair.ts +18 -0
- package/src/log/README.md +79 -0
- package/src/log/index.ts +5 -0
- package/src/log/log-emitter.ts +72 -0
- package/src/log/log-record.ts +10 -0
- package/src/log/log-scheduler.ts +74 -0
- package/src/log/log-type.ts +8 -0
- package/src/log/logger.ts +554 -0
- package/src/openai/README.md +1 -0
- package/src/openai/index.ts +1 -0
- package/src/openai/openai.ts +510 -0
- package/src/orchestration/README.md +91 -0
- package/src/orchestration/coordination/barrier.ts +214 -0
- package/src/orchestration/coordination/count-down-latch.ts +215 -0
- package/src/orchestration/coordination/errors.ts +98 -0
- package/src/orchestration/coordination/index.ts +16 -0
- package/src/orchestration/coordination/internal/wait-constraints.ts +95 -0
- package/src/orchestration/coordination/internal/wait-queue.ts +109 -0
- package/src/orchestration/coordination/keyed-lock.ts +168 -0
- package/src/orchestration/coordination/mutex.ts +257 -0
- package/src/orchestration/coordination/permit.ts +127 -0
- package/src/orchestration/coordination/read-write-lock.ts +444 -0
- package/src/orchestration/coordination/semaphore.ts +280 -0
- package/src/orchestration/dispatching/dispatcher.ts +83 -0
- package/src/orchestration/dispatching/index.ts +2 -0
- package/src/orchestration/dispatching/selector/base-selector.ts +39 -0
- package/src/orchestration/dispatching/selector/down-count-selector.ts +119 -0
- package/src/orchestration/dispatching/selector/index.ts +2 -0
- package/src/orchestration/index.ts +3 -0
- package/src/orchestration/scheduling/index.ts +2 -0
- package/src/orchestration/scheduling/scheduler.ts +103 -0
- package/src/orchestration/scheduling/task.ts +32 -0
- package/src/random/README.md +56 -86
- package/src/random/base.ts +66 -0
- package/src/random/index.ts +5 -1
- package/src/random/random-boolean.ts +40 -0
- package/src/random/random-integer.ts +60 -0
- package/src/random/random-number.ts +72 -0
- package/src/random/random-string.ts +66 -0
- package/src/reactor/README.md +4 -0
- package/src/reactor/reactor-core/primitive.ts +9 -9
- package/src/reactor/reactor-core/reactive-system.ts +5 -5
- package/src/request/README.md +108 -0
- package/src/request/fetch/base.ts +108 -0
- package/src/request/fetch/browser.ts +285 -0
- package/src/request/fetch/general.ts +20 -0
- package/src/request/fetch/index.ts +4 -0
- package/src/request/fetch/nodejs.ts +285 -0
- package/src/request/index.ts +2 -0
- package/src/request/request/base.ts +250 -0
- package/src/request/request/general.ts +64 -0
- package/src/request/request/index.ts +3 -0
- package/src/request/request/resource.ts +68 -0
- package/src/result/README.md +4 -0
- package/src/result/controller.ts +54 -0
- package/src/result/either.ts +193 -0
- package/src/result/index.ts +2 -0
- package/src/route/README.md +105 -0
- package/src/route/adapter/browser.ts +122 -0
- package/src/route/adapter/driver.ts +56 -0
- package/src/route/adapter/index.ts +2 -0
- package/src/route/index.ts +3 -0
- package/src/route/router/index.ts +2 -0
- package/src/route/router/route.ts +630 -0
- package/src/route/router/router.ts +1642 -0
- package/src/route/uri/hash.ts +308 -0
- package/src/route/uri/index.ts +7 -0
- package/src/route/uri/pathname.ts +376 -0
- package/src/route/uri/search.ts +413 -0
- package/src/singleton/README.md +79 -0
- package/src/singleton/factory.ts +55 -0
- package/src/singleton/index.ts +2 -0
- package/src/singleton/manager.ts +204 -0
- package/src/socket/README.md +105 -0
- package/src/socket/client/index.ts +2 -0
- package/src/socket/client/socket-unit.ts +660 -0
- package/src/socket/client/socket.ts +203 -0
- package/src/socket/common/index.ts +2 -0
- package/src/socket/common/socket-unit-common.ts +23 -0
- package/src/socket/common/socket-unit-heartbeat.ts +427 -0
- package/src/socket/index.ts +3 -0
- package/src/socket/server/index.ts +3 -0
- package/src/socket/server/server.ts +183 -0
- package/src/socket/server/socket-unit.ts +449 -0
- package/src/socket/server/socket.ts +264 -0
- package/src/storage/README.md +107 -0
- package/src/storage/index.ts +1 -0
- package/src/storage/table.ts +449 -0
- package/src/timer/README.md +86 -0
- package/src/timer/expiration/expiration-manager.ts +594 -0
- package/src/timer/expiration/index.ts +3 -0
- package/src/timer/expiration/min-heap.ts +208 -0
- package/src/timer/expiration/remaining-manager.ts +241 -0
- package/src/timer/index.ts +1 -0
- package/src/tube/README.md +99 -0
- package/src/tube/helper.ts +138 -0
- package/src/tube/index.ts +2 -0
- package/src/tube/tube.ts +880 -0
- package/src/type/README.md +54 -307
- package/src/type/class.ts +2 -2
- package/src/type/index.ts +14 -14
- package/src/type/is.ts +265 -2
- package/src/type/object.ts +37 -0
- package/src/type/string.ts +7 -2
- package/src/type/tuple.ts +6 -6
- package/src/type/union.ts +16 -0
- package/src/web/README.md +77 -0
- package/src/web/capture.ts +35 -0
- package/src/web/clipboard.ts +97 -0
- package/src/web/dom.ts +117 -0
- package/src/web/download.ts +16 -0
- package/src/web/event.ts +46 -0
- package/src/web/index.ts +10 -0
- package/src/web/local-storage.ts +113 -0
- package/src/web/location.ts +28 -0
- package/src/web/permission.ts +172 -0
- package/src/web/script-loader.ts +432 -0
- package/src/weixin/README.md +1 -0
- package/src/weixin/index.ts +2 -0
- package/src/weixin/official-account/authorization.ts +159 -0
- package/src/weixin/official-account/index.ts +2 -0
- package/src/weixin/official-account/js-api.ts +134 -0
- package/src/weixin/open/index.ts +1 -0
- package/src/weixin/open/oauth2.ts +133 -0
- package/tests/unit/abort/abort-manager.spec.ts +225 -0
- package/tests/unit/abort/abort-signal-listener-manager.spec.ts +62 -0
- package/tests/unit/ai/ai.spec.ts +85 -0
- package/tests/unit/aio/content.spec.ts +105 -0
- package/tests/unit/aio/json.spec.ts +147 -0
- package/tests/unit/aio/prompt.spec.ts +111 -0
- package/tests/unit/basic/array.spec.ts +1 -1
- package/tests/unit/basic/error.spec.ts +16 -4
- package/tests/unit/basic/schedule.spec.ts +74 -0
- package/tests/unit/basic/stream.spec.ts +91 -38
- package/tests/unit/basic/string.spec.ts +0 -9
- package/tests/unit/color/rgb/analyze.spec.ts +110 -0
- package/tests/unit/color/rgb/construct.spec.ts +56 -0
- package/tests/unit/color/rgb/convert.spec.ts +60 -0
- package/tests/unit/color/rgb/derive.spec.ts +103 -0
- package/tests/unit/color/rgb/parse.spec.ts +66 -0
- package/tests/unit/color/rgb/serialize.spec.ts +46 -0
- package/tests/unit/color/xyz/analyze.spec.ts +33 -0
- package/tests/unit/color/xyz/construct.spec.ts +10 -0
- package/tests/unit/color/xyz/convert.spec.ts +18 -0
- package/tests/unit/credential/api-key.spec.ts +37 -0
- package/tests/unit/credential/bearer.spec.ts +23 -0
- package/tests/unit/credential/json-web-token.spec.ts +23 -0
- package/tests/unit/credential/password.spec.ts +41 -0
- package/tests/unit/cron/cron.spec.ts +84 -0
- package/tests/unit/css/class.spec.ts +157 -0
- package/tests/unit/environment/basic.spec.ts +20 -0
- package/tests/unit/environment/device.spec.ts +146 -0
- package/tests/unit/environment/feature.spec.ts +388 -0
- package/tests/unit/environment/geo.spec.ts +111 -0
- package/tests/unit/environment/runtime.spec.ts +364 -0
- package/tests/unit/environment/snapshot.spec.ts +4 -0
- package/tests/unit/environment/variable.spec.ts +190 -0
- package/tests/unit/event/class-event-proxy.spec.ts +225 -0
- package/tests/unit/event/event-manager.spec.ts +246 -0
- package/tests/unit/event/instance-event-proxy.spec.ts +187 -0
- package/tests/unit/exception/browser.spec.ts +213 -0
- package/tests/unit/exception/nodejs.spec.ts +144 -0
- package/tests/unit/exception/normalize.spec.ts +57 -0
- package/tests/unit/form/inputor-controller/base.spec.ts +458 -0
- package/tests/unit/form/inputor-controller/boolean.spec.ts +30 -0
- package/tests/unit/form/inputor-controller/file.spec.ts +27 -0
- package/tests/unit/form/inputor-controller/form.spec.ts +120 -0
- package/tests/unit/form/inputor-controller/helper.spec.ts +67 -0
- package/tests/unit/form/inputor-controller/multi-select.spec.ts +34 -0
- package/tests/unit/form/inputor-controller/number.spec.ts +36 -0
- package/tests/unit/form/inputor-controller/select.spec.ts +49 -0
- package/tests/unit/form/inputor-controller/text.spec.ts +34 -0
- package/tests/unit/http/api/api-core-host.spec.ts +207 -0
- package/tests/unit/http/api/api-schema.spec.ts +120 -0
- package/tests/unit/http/api/api-server.spec.ts +363 -0
- package/tests/unit/http/api/api-test.spec.ts +117 -0
- package/tests/unit/http/api/api.spec.ts +121 -0
- package/tests/unit/http/api-adapter/node-http.spec.ts +191 -0
- package/tests/unit/identifier/id.spec.ts +71 -0
- package/tests/unit/identifier/uuid.spec.ts +85 -0
- package/tests/unit/json/repair.spec.ts +11 -0
- package/tests/unit/log/log-emitter.spec.ts +33 -0
- package/tests/unit/log/log-scheduler.spec.ts +40 -0
- package/tests/unit/log/log-type.spec.ts +7 -0
- package/tests/unit/log/logger.spec.ts +237 -0
- package/tests/unit/openai/openai.spec.ts +64 -0
- package/tests/unit/orchestration/coordination/barrier.spec.ts +96 -0
- package/tests/unit/orchestration/coordination/count-down-latch.spec.ts +63 -0
- package/tests/unit/orchestration/coordination/errors.spec.ts +29 -0
- package/tests/unit/orchestration/coordination/keyed-lock.spec.ts +109 -0
- package/tests/unit/orchestration/coordination/mutex.spec.ts +132 -0
- package/tests/unit/orchestration/coordination/permit.spec.ts +43 -0
- package/tests/unit/orchestration/coordination/read-write-lock.spec.ts +154 -0
- package/tests/unit/orchestration/coordination/semaphore.spec.ts +135 -0
- package/tests/unit/orchestration/dispatching/dispatcher.spec.ts +41 -0
- package/tests/unit/orchestration/dispatching/selector/down-count-selector.spec.ts +81 -0
- package/tests/unit/orchestration/scheduling/scheduler.spec.ts +103 -0
- package/tests/unit/random/base.spec.ts +58 -0
- package/tests/unit/random/random-boolean.spec.ts +25 -0
- package/tests/unit/random/random-integer.spec.ts +32 -0
- package/tests/unit/random/random-number.spec.ts +33 -0
- package/tests/unit/random/random-string.spec.ts +22 -0
- package/tests/unit/reactor/alien-signals-effect.spec.ts +11 -10
- package/tests/unit/reactor/preact-signal.spec.ts +1 -2
- package/tests/unit/request/fetch/browser.spec.ts +222 -0
- package/tests/unit/request/fetch/general.spec.ts +43 -0
- package/tests/unit/request/fetch/nodejs.spec.ts +225 -0
- package/tests/unit/request/request/base.spec.ts +385 -0
- package/tests/unit/request/request/general.spec.ts +161 -0
- package/tests/unit/route/router/route.spec.ts +431 -0
- package/tests/unit/route/router/router.spec.ts +407 -0
- package/tests/unit/route/uri/hash.spec.ts +72 -0
- package/tests/unit/route/uri/pathname.spec.ts +147 -0
- package/tests/unit/route/uri/search.spec.ts +107 -0
- package/tests/unit/singleton/singleton.spec.ts +49 -0
- package/tests/unit/socket/client.spec.ts +208 -0
- package/tests/unit/socket/server.spec.ts +135 -0
- package/tests/unit/socket/socket-unit-heartbeat.spec.ts +214 -0
- package/tests/unit/storage/table.spec.ts +620 -0
- package/tests/unit/timer/expiration/expiration-manager.spec.ts +464 -0
- package/tests/unit/timer/expiration/min-heap.spec.ts +71 -0
- package/tests/unit/timer/expiration/remaining-manager.spec.ts +234 -0
- package/tests/unit/tube/helper.spec.ts +139 -0
- package/tests/unit/tube/tube.spec.ts +501 -0
- package/.oxlintrc.json +0 -5
- package/src/random/uuid.ts +0 -103
- package/tests/unit/random/uuid.spec.ts +0 -37
|
@@ -0,0 +1,159 @@
|
|
|
1
|
+
import { fetch } from "undici"
|
|
2
|
+
|
|
3
|
+
export interface GetAuthAccessTokenOptions {
|
|
4
|
+
appId: string
|
|
5
|
+
appSecret: string
|
|
6
|
+
code: string
|
|
7
|
+
}
|
|
8
|
+
export interface GetAuthAccessTokenResult {
|
|
9
|
+
accessToken: string
|
|
10
|
+
expiresAt: number
|
|
11
|
+
refreshToken: string
|
|
12
|
+
openid: string
|
|
13
|
+
scope: string
|
|
14
|
+
isSnapshotUser: boolean
|
|
15
|
+
unionid?: string | undefined
|
|
16
|
+
}
|
|
17
|
+
export const getAuthAccessToken = async (
|
|
18
|
+
options: GetAuthAccessTokenOptions
|
|
19
|
+
): Promise<GetAuthAccessTokenResult> => {
|
|
20
|
+
const { appId, appSecret, code } = options
|
|
21
|
+
|
|
22
|
+
interface AccessTokenSuccessResponse {
|
|
23
|
+
access_token: string
|
|
24
|
+
expires_in: number
|
|
25
|
+
refresh_token: string
|
|
26
|
+
openid: string
|
|
27
|
+
scope: string
|
|
28
|
+
is_snapshotuser?: 1
|
|
29
|
+
unionid?: string
|
|
30
|
+
}
|
|
31
|
+
interface AccessTokenErrorResponse {
|
|
32
|
+
errcode: number
|
|
33
|
+
errmsg: string
|
|
34
|
+
}
|
|
35
|
+
const url = `https://api.weixin.qq.com/sns/oauth2/access_token?appid=${appId}&secret=${appSecret}&code=${code}&grant_type=authorization_code`
|
|
36
|
+
|
|
37
|
+
try {
|
|
38
|
+
const now = Date.now()
|
|
39
|
+
const result = await fetch(
|
|
40
|
+
url,
|
|
41
|
+
{
|
|
42
|
+
method: "get",
|
|
43
|
+
},
|
|
44
|
+
)
|
|
45
|
+
|
|
46
|
+
// oxlint-disable-next-line typescript/no-unsafe-type-assertion
|
|
47
|
+
const json = await result.json() as AccessTokenSuccessResponse | AccessTokenErrorResponse
|
|
48
|
+
|
|
49
|
+
if ("errcode" in json) {
|
|
50
|
+
throw new Error(`${json.errcode}: ${json.errmsg}`)
|
|
51
|
+
}
|
|
52
|
+
|
|
53
|
+
return {
|
|
54
|
+
accessToken: json.access_token,
|
|
55
|
+
expiresAt: now + json.expires_in * 1_000,
|
|
56
|
+
refreshToken: json.refresh_token,
|
|
57
|
+
openid: json.openid,
|
|
58
|
+
scope: json.scope,
|
|
59
|
+
isSnapshotUser: json.is_snapshotuser === 1,
|
|
60
|
+
unionid: json.unionid,
|
|
61
|
+
}
|
|
62
|
+
}
|
|
63
|
+
catch (exception) {
|
|
64
|
+
console.error("Error getting access token:", exception)
|
|
65
|
+
throw exception
|
|
66
|
+
}
|
|
67
|
+
}
|
|
68
|
+
|
|
69
|
+
export interface GetUserInfoOptions {
|
|
70
|
+
accessToken: string
|
|
71
|
+
openId: string
|
|
72
|
+
}
|
|
73
|
+
export interface GetUserInfoResult {
|
|
74
|
+
openid: string
|
|
75
|
+
nickname: string
|
|
76
|
+
sex: number
|
|
77
|
+
province: string
|
|
78
|
+
city: string
|
|
79
|
+
country: string
|
|
80
|
+
headimgurl: string
|
|
81
|
+
privilege: string[]
|
|
82
|
+
unionid: string
|
|
83
|
+
}
|
|
84
|
+
export const getUserInfo = async (
|
|
85
|
+
options: GetUserInfoOptions
|
|
86
|
+
): Promise<GetUserInfoResult> => {
|
|
87
|
+
const { accessToken, openId } = options
|
|
88
|
+
|
|
89
|
+
interface UserInfoSuccessResponse {
|
|
90
|
+
openid: string
|
|
91
|
+
nickname: string
|
|
92
|
+
sex: number
|
|
93
|
+
province: string
|
|
94
|
+
city: string
|
|
95
|
+
country: string
|
|
96
|
+
headimgurl: string
|
|
97
|
+
privilege: string[]
|
|
98
|
+
unionid: string
|
|
99
|
+
}
|
|
100
|
+
interface UserInfoErrorResponse {
|
|
101
|
+
errcode: number
|
|
102
|
+
errmsg: string
|
|
103
|
+
}
|
|
104
|
+
const url = `https://api.weixin.qq.com/sns/userinfo?access_token=${accessToken}&openid=${openId}&lang=zh_CN`
|
|
105
|
+
|
|
106
|
+
try {
|
|
107
|
+
const result = await fetch(
|
|
108
|
+
url,
|
|
109
|
+
{
|
|
110
|
+
method: "get",
|
|
111
|
+
},
|
|
112
|
+
)
|
|
113
|
+
|
|
114
|
+
// oxlint-disable-next-line typescript/no-unsafe-type-assertion
|
|
115
|
+
const json = await result.json() as UserInfoSuccessResponse | UserInfoErrorResponse
|
|
116
|
+
|
|
117
|
+
if ("errcode" in json) {
|
|
118
|
+
throw new Error(`${json.errcode}: ${json.errmsg}`)
|
|
119
|
+
}
|
|
120
|
+
return json
|
|
121
|
+
}
|
|
122
|
+
catch (exception) {
|
|
123
|
+
console.error("Error getting user info:", exception)
|
|
124
|
+
throw exception
|
|
125
|
+
}
|
|
126
|
+
}
|
|
127
|
+
|
|
128
|
+
export interface WeixinOfficialAccountOauth2Options {
|
|
129
|
+
appId: string
|
|
130
|
+
appSecret: string
|
|
131
|
+
}
|
|
132
|
+
/**
|
|
133
|
+
* @see {@link https://developers.weixin.qq.com/doc/offiaccount/OA_Web_Apps/Wechat_webpage_authorization.html | 微信网页开发 / 网页授权}
|
|
134
|
+
*/
|
|
135
|
+
export class WeixinOfficialAccountOauth2 {
|
|
136
|
+
private readonly appId: string
|
|
137
|
+
private readonly appSecret: string
|
|
138
|
+
|
|
139
|
+
constructor(options: WeixinOfficialAccountOauth2Options) {
|
|
140
|
+
const { appId, appSecret } = options
|
|
141
|
+
this.appId = appId
|
|
142
|
+
this.appSecret = appSecret
|
|
143
|
+
}
|
|
144
|
+
|
|
145
|
+
async getAccessToken(code: string): Promise<GetAuthAccessTokenResult> {
|
|
146
|
+
return await getAuthAccessToken({
|
|
147
|
+
appId: this.appId,
|
|
148
|
+
appSecret: this.appSecret,
|
|
149
|
+
code,
|
|
150
|
+
})
|
|
151
|
+
}
|
|
152
|
+
|
|
153
|
+
async getUserInfo(accessToken: string, openId: string): Promise<GetUserInfoResult> {
|
|
154
|
+
return await getUserInfo({
|
|
155
|
+
accessToken,
|
|
156
|
+
openId,
|
|
157
|
+
})
|
|
158
|
+
}
|
|
159
|
+
}
|
|
@@ -0,0 +1,134 @@
|
|
|
1
|
+
import { hash } from "node:crypto"
|
|
2
|
+
|
|
3
|
+
import { fetch } from "undici"
|
|
4
|
+
|
|
5
|
+
export interface GetJsApiAccessTokenOptions {
|
|
6
|
+
appId: string
|
|
7
|
+
appSecret: string
|
|
8
|
+
}
|
|
9
|
+
export interface GetJsApiAccessTokenResult {
|
|
10
|
+
accessToken: string
|
|
11
|
+
/**
|
|
12
|
+
* in milliseconds
|
|
13
|
+
*/
|
|
14
|
+
accessTokenExpiresAt: number
|
|
15
|
+
}
|
|
16
|
+
/**
|
|
17
|
+
* @see {@link https://developers.weixin.qq.com/doc/offiaccount/Basic_Information/getStableAccessToken.html}
|
|
18
|
+
* @see {@link https://mp.weixin.qq.com/debug | 微信公众平台 - 接口调试工具}
|
|
19
|
+
*/
|
|
20
|
+
export const getJsApiAccessToken = async (
|
|
21
|
+
options: GetJsApiAccessTokenOptions
|
|
22
|
+
): Promise<GetJsApiAccessTokenResult | undefined> => {
|
|
23
|
+
const { appId, appSecret } = options
|
|
24
|
+
|
|
25
|
+
interface StableTokenResponse {
|
|
26
|
+
access_token: string
|
|
27
|
+
expires_in: number
|
|
28
|
+
}
|
|
29
|
+
try {
|
|
30
|
+
const now = Date.now()
|
|
31
|
+
const result = await fetch(
|
|
32
|
+
"https://api.weixin.qq.com/cgi-bin/stable_token",
|
|
33
|
+
{
|
|
34
|
+
method: "post",
|
|
35
|
+
body: JSON.stringify({
|
|
36
|
+
grant_type: "client_credential",
|
|
37
|
+
appid: appId,
|
|
38
|
+
secret: appSecret,
|
|
39
|
+
force_refresh: false,
|
|
40
|
+
}),
|
|
41
|
+
},
|
|
42
|
+
)
|
|
43
|
+
|
|
44
|
+
// oxlint-disable-next-line typescript/no-unsafe-type-assertion
|
|
45
|
+
const json = await result.json() as StableTokenResponse
|
|
46
|
+
|
|
47
|
+
return {
|
|
48
|
+
accessToken: json.access_token,
|
|
49
|
+
accessTokenExpiresAt: now + json.expires_in * 1_000,
|
|
50
|
+
}
|
|
51
|
+
}
|
|
52
|
+
catch (exception) {
|
|
53
|
+
console.error(exception)
|
|
54
|
+
return undefined
|
|
55
|
+
}
|
|
56
|
+
}
|
|
57
|
+
|
|
58
|
+
export interface GetJsApiTicketOptions {
|
|
59
|
+
accessToken: string
|
|
60
|
+
}
|
|
61
|
+
export interface GetJsApiTicketResult {
|
|
62
|
+
jsApiTicket: string
|
|
63
|
+
/**
|
|
64
|
+
* in milliseconds
|
|
65
|
+
*/
|
|
66
|
+
expiresAt: number
|
|
67
|
+
}
|
|
68
|
+
/**
|
|
69
|
+
* @see {@link https://developers.weixin.qq.com/doc/offiaccount/OA_Web_Apps/JS-SDK.html#62 | 附录 1 - JS-SDK 使用权限签名算法}
|
|
70
|
+
*/
|
|
71
|
+
export const getJsApiTicket = async (
|
|
72
|
+
options: GetJsApiTicketOptions
|
|
73
|
+
): Promise<GetJsApiTicketResult | undefined> => {
|
|
74
|
+
const { accessToken } = options
|
|
75
|
+
|
|
76
|
+
interface JsApiTicketResponse {
|
|
77
|
+
errcode: number
|
|
78
|
+
errmsg: string
|
|
79
|
+
ticket: string
|
|
80
|
+
expires_in: number
|
|
81
|
+
}
|
|
82
|
+
try {
|
|
83
|
+
const now = Date.now()
|
|
84
|
+
const result = await fetch(
|
|
85
|
+
`https://api.weixin.qq.com/cgi-bin/ticket/getticket?access_token=${accessToken}&type=jsapi`,
|
|
86
|
+
{
|
|
87
|
+
method: "get",
|
|
88
|
+
},
|
|
89
|
+
)
|
|
90
|
+
|
|
91
|
+
// oxlint-disable-next-line typescript/no-unsafe-type-assertion
|
|
92
|
+
const json = await result.json() as JsApiTicketResponse
|
|
93
|
+
|
|
94
|
+
return {
|
|
95
|
+
jsApiTicket: json.ticket,
|
|
96
|
+
expiresAt: now + json.expires_in * 1_000,
|
|
97
|
+
}
|
|
98
|
+
}
|
|
99
|
+
catch (exception) {
|
|
100
|
+
console.error(exception)
|
|
101
|
+
return undefined
|
|
102
|
+
}
|
|
103
|
+
}
|
|
104
|
+
|
|
105
|
+
export interface SignJsSdkConfigOptions {
|
|
106
|
+
url: string
|
|
107
|
+
jsApiTicket: string
|
|
108
|
+
}
|
|
109
|
+
export interface SignJsSdkConfigResult {
|
|
110
|
+
timestamp: number
|
|
111
|
+
nonceStr: string
|
|
112
|
+
signature: string
|
|
113
|
+
}
|
|
114
|
+
/**
|
|
115
|
+
* @see {@link https://developers.weixin.qq.com/doc/offiaccount/OA_Web_Apps/JS-SDK.html#62 | 签名算法}
|
|
116
|
+
* @see {@link https://mp.weixin.qq.com/debug/cgi-bin/sandbox?t=jsapisign | 微信公众平台 - 微信 JS 接口签名校验工具}
|
|
117
|
+
*/
|
|
118
|
+
export const signJsSdkConfig = (
|
|
119
|
+
options: SignJsSdkConfigOptions
|
|
120
|
+
): SignJsSdkConfigResult => {
|
|
121
|
+
const { url, jsApiTicket } = options
|
|
122
|
+
|
|
123
|
+
const nonceStr = Math.random().toString(36).slice(2, 17)
|
|
124
|
+
const timestamp = Math.floor(Date.now() / 1_000)
|
|
125
|
+
|
|
126
|
+
const rawString = `jsapi_ticket=${jsApiTicket}&noncestr=${nonceStr}×tamp=${timestamp}&url=${url}`
|
|
127
|
+
const signature = hash("sha1", rawString)
|
|
128
|
+
|
|
129
|
+
return {
|
|
130
|
+
timestamp,
|
|
131
|
+
nonceStr,
|
|
132
|
+
signature,
|
|
133
|
+
}
|
|
134
|
+
}
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
export * from "./oauth2.ts"
|
|
@@ -0,0 +1,133 @@
|
|
|
1
|
+
import { fetch } from "undici"
|
|
2
|
+
|
|
3
|
+
export interface WeixinAccessTokenResult {
|
|
4
|
+
accessToken: string
|
|
5
|
+
expiresAt: number
|
|
6
|
+
refreshToken: string
|
|
7
|
+
openid: string
|
|
8
|
+
scope: string
|
|
9
|
+
unionid?: string | undefined
|
|
10
|
+
}
|
|
11
|
+
|
|
12
|
+
export interface WeixinUserInfoResult {
|
|
13
|
+
openid: string
|
|
14
|
+
nickname: string
|
|
15
|
+
sex: number
|
|
16
|
+
province: string
|
|
17
|
+
city: string
|
|
18
|
+
country: string
|
|
19
|
+
headimgurl: string
|
|
20
|
+
privilege: string[]
|
|
21
|
+
unionid?: string | undefined
|
|
22
|
+
}
|
|
23
|
+
|
|
24
|
+
export interface WeixinOauth2Options {
|
|
25
|
+
appId: string
|
|
26
|
+
appSecret: string
|
|
27
|
+
}
|
|
28
|
+
|
|
29
|
+
export class WeixinOauth2 {
|
|
30
|
+
protected options: WeixinOauth2Options
|
|
31
|
+
|
|
32
|
+
constructor(options: WeixinOauth2Options) {
|
|
33
|
+
this.options = options
|
|
34
|
+
}
|
|
35
|
+
|
|
36
|
+
/**
|
|
37
|
+
* {@link https://developers.weixin.qq.com/doc/oplatform/Website_App/WeChat_Login/Wechat_Login.html | 关于微信快速登录功能的说明}
|
|
38
|
+
*/
|
|
39
|
+
public async getAccessToken(
|
|
40
|
+
code: string
|
|
41
|
+
): Promise<WeixinAccessTokenResult> {
|
|
42
|
+
interface AccessTokenSuccessResponse {
|
|
43
|
+
access_token: string
|
|
44
|
+
expires_in: number
|
|
45
|
+
refresh_token: string
|
|
46
|
+
openid: string
|
|
47
|
+
scope: string
|
|
48
|
+
unionid?: string
|
|
49
|
+
}
|
|
50
|
+
interface AccessTokenErrorResponse {
|
|
51
|
+
errcode: number
|
|
52
|
+
errmsg: string
|
|
53
|
+
}
|
|
54
|
+
const { appId, appSecret } = this.options
|
|
55
|
+
const url = `https://api.weixin.qq.com/sns/oauth2/access_token?appid=${appId}&secret=${appSecret}&code=${code}&grant_type=authorization_code`
|
|
56
|
+
|
|
57
|
+
try {
|
|
58
|
+
const now = Date.now()
|
|
59
|
+
const result = await fetch(
|
|
60
|
+
url,
|
|
61
|
+
{
|
|
62
|
+
method: "get",
|
|
63
|
+
},
|
|
64
|
+
)
|
|
65
|
+
|
|
66
|
+
// oxlint-disable-next-line typescript/no-unsafe-type-assertion
|
|
67
|
+
const json = await result.json() as AccessTokenSuccessResponse | AccessTokenErrorResponse
|
|
68
|
+
|
|
69
|
+
if ("errcode" in json) {
|
|
70
|
+
throw new Error(`${json.errcode}: ${json.errmsg}`)
|
|
71
|
+
}
|
|
72
|
+
|
|
73
|
+
return {
|
|
74
|
+
accessToken: json.access_token,
|
|
75
|
+
expiresAt: now + json.expires_in * 1_000,
|
|
76
|
+
refreshToken: json.refresh_token,
|
|
77
|
+
openid: json.openid,
|
|
78
|
+
scope: json.scope,
|
|
79
|
+
unionid: json.unionid,
|
|
80
|
+
}
|
|
81
|
+
}
|
|
82
|
+
catch (exception) {
|
|
83
|
+
console.error("Error getting access token:", exception)
|
|
84
|
+
throw exception
|
|
85
|
+
}
|
|
86
|
+
}
|
|
87
|
+
|
|
88
|
+
/**
|
|
89
|
+
* {@link https://developers.weixin.qq.com/doc/oplatform/Website_App/WeChat_Login/Authorized_Interface_Calling_UnionID.html | 获取用户个人信息(UnionID机制)}
|
|
90
|
+
*/
|
|
91
|
+
public async getUserInfo(
|
|
92
|
+
accessToken: string,
|
|
93
|
+
openId: string,
|
|
94
|
+
): Promise<WeixinUserInfoResult> {
|
|
95
|
+
interface UserInfoSuccessResponse {
|
|
96
|
+
openid: string
|
|
97
|
+
nickname: string
|
|
98
|
+
sex: number
|
|
99
|
+
province: string
|
|
100
|
+
city: string
|
|
101
|
+
country: string
|
|
102
|
+
headimgurl: string
|
|
103
|
+
privilege: string[]
|
|
104
|
+
unionid?: string
|
|
105
|
+
}
|
|
106
|
+
interface UserInfoErrorResponse {
|
|
107
|
+
errcode: number
|
|
108
|
+
errmsg: string
|
|
109
|
+
}
|
|
110
|
+
const url = `https://api.weixin.qq.com/sns/userinfo?access_token=${accessToken}&openid=${openId}&lang=zh_CN`
|
|
111
|
+
|
|
112
|
+
try {
|
|
113
|
+
const result = await fetch(
|
|
114
|
+
url,
|
|
115
|
+
{
|
|
116
|
+
method: "get",
|
|
117
|
+
},
|
|
118
|
+
)
|
|
119
|
+
|
|
120
|
+
// oxlint-disable-next-line typescript/no-unsafe-type-assertion
|
|
121
|
+
const json = await result.json() as UserInfoSuccessResponse | UserInfoErrorResponse
|
|
122
|
+
|
|
123
|
+
if ("errcode" in json) {
|
|
124
|
+
throw new Error(`${json.errcode}: ${json.errmsg}`)
|
|
125
|
+
}
|
|
126
|
+
return json
|
|
127
|
+
}
|
|
128
|
+
catch (exception) {
|
|
129
|
+
console.error("Error getting user info:", exception)
|
|
130
|
+
throw exception
|
|
131
|
+
}
|
|
132
|
+
}
|
|
133
|
+
}
|
|
@@ -0,0 +1,225 @@
|
|
|
1
|
+
import { expect, test } from "vitest"
|
|
2
|
+
|
|
3
|
+
import {
|
|
4
|
+
ABORT_MANAGER_MODE,
|
|
5
|
+
AbortManager,
|
|
6
|
+
all,
|
|
7
|
+
any,
|
|
8
|
+
fromAbortFriendlyOptions,
|
|
9
|
+
fromAbortable,
|
|
10
|
+
fromWithAbortSignal,
|
|
11
|
+
getAbortSignal,
|
|
12
|
+
isAborted,
|
|
13
|
+
} from "#Source/abort/index.ts"
|
|
14
|
+
|
|
15
|
+
test("getAbortSignal resolves AbortSignal from supported abortables", () => {
|
|
16
|
+
const abortController = new AbortController()
|
|
17
|
+
const abortManager = new AbortManager({})
|
|
18
|
+
|
|
19
|
+
expect(getAbortSignal(abortController.signal)).toBe(abortController.signal)
|
|
20
|
+
expect(getAbortSignal(abortController)).toBe(abortController.signal)
|
|
21
|
+
expect(getAbortSignal(abortManager)).toBe(abortManager.abortSignal)
|
|
22
|
+
})
|
|
23
|
+
|
|
24
|
+
test("isAborted reflects abort state from abortables", () => {
|
|
25
|
+
const abortController = new AbortController()
|
|
26
|
+
|
|
27
|
+
expect(isAborted(abortController.signal)).toBe(false)
|
|
28
|
+
expect(isAborted(abortController)).toBe(false)
|
|
29
|
+
|
|
30
|
+
abortController.abort("stop")
|
|
31
|
+
|
|
32
|
+
expect(isAborted(abortController.signal)).toBe(true)
|
|
33
|
+
expect(isAborted(abortController)).toBe(true)
|
|
34
|
+
})
|
|
35
|
+
|
|
36
|
+
test("AbortManager constructor links upstream abortManager from options", () => {
|
|
37
|
+
const upstream = new AbortManager({})
|
|
38
|
+
const abortManager = new AbortManager({ abortManager: upstream })
|
|
39
|
+
|
|
40
|
+
expect(abortManager.isAborted()).toBe(false)
|
|
41
|
+
|
|
42
|
+
upstream.abort("upstream")
|
|
43
|
+
|
|
44
|
+
expect(abortManager.isAborted()).toBe(true)
|
|
45
|
+
})
|
|
46
|
+
|
|
47
|
+
test("AbortManager.isAborted mirrors internal abortSignal", () => {
|
|
48
|
+
const abortManager = new AbortManager({})
|
|
49
|
+
|
|
50
|
+
expect(abortManager.isAborted()).toBe(false)
|
|
51
|
+
|
|
52
|
+
abortManager.abort("done")
|
|
53
|
+
|
|
54
|
+
expect(abortManager.isAborted()).toBe(true)
|
|
55
|
+
})
|
|
56
|
+
|
|
57
|
+
test("AbortManager.setMode sets mode and supports chaining", () => {
|
|
58
|
+
const abortManager = new AbortManager({})
|
|
59
|
+
const upstream1 = new AbortController()
|
|
60
|
+
const upstream2 = new AbortController()
|
|
61
|
+
|
|
62
|
+
const returned = abortManager
|
|
63
|
+
.setMode(ABORT_MANAGER_MODE.ANY)
|
|
64
|
+
.addUpstreams([upstream1.signal, upstream2.signal])
|
|
65
|
+
|
|
66
|
+
expect(returned).toBe(abortManager)
|
|
67
|
+
|
|
68
|
+
upstream1.abort("one")
|
|
69
|
+
|
|
70
|
+
expect(abortManager.isAborted()).toBe(true)
|
|
71
|
+
})
|
|
72
|
+
|
|
73
|
+
test("AbortManager.addUpstreams makes manager abort when upstream condition is met", () => {
|
|
74
|
+
const abortManager = new AbortManager({})
|
|
75
|
+
const upstream = new AbortController()
|
|
76
|
+
|
|
77
|
+
abortManager.addUpstreams([upstream.signal])
|
|
78
|
+
|
|
79
|
+
expect(abortManager.isAborted()).toBe(false)
|
|
80
|
+
|
|
81
|
+
upstream.abort("upstream")
|
|
82
|
+
|
|
83
|
+
expect(abortManager.isAborted()).toBe(true)
|
|
84
|
+
})
|
|
85
|
+
|
|
86
|
+
test("AbortManager.removeUpstreams detaches selected upstreams", () => {
|
|
87
|
+
const abortManager = new AbortManager({})
|
|
88
|
+
const upstream1 = new AbortController()
|
|
89
|
+
const upstream2 = new AbortController()
|
|
90
|
+
|
|
91
|
+
abortManager
|
|
92
|
+
.setMode(ABORT_MANAGER_MODE.ANY)
|
|
93
|
+
.addUpstreams([upstream1.signal, upstream2.signal])
|
|
94
|
+
.removeUpstreams([upstream1.signal])
|
|
95
|
+
|
|
96
|
+
upstream1.abort("ignored")
|
|
97
|
+
|
|
98
|
+
expect(abortManager.isAborted()).toBe(false)
|
|
99
|
+
|
|
100
|
+
upstream2.abort("active")
|
|
101
|
+
|
|
102
|
+
expect(abortManager.isAborted()).toBe(true)
|
|
103
|
+
})
|
|
104
|
+
|
|
105
|
+
test("AbortManager.removeAllUpstreams detaches all upstreams", () => {
|
|
106
|
+
const abortManager = new AbortManager({})
|
|
107
|
+
const upstream1 = new AbortController()
|
|
108
|
+
const upstream2 = new AbortController()
|
|
109
|
+
|
|
110
|
+
abortManager
|
|
111
|
+
.setMode(ABORT_MANAGER_MODE.ANY)
|
|
112
|
+
.addUpstreams([upstream1.signal, upstream2.signal])
|
|
113
|
+
.removeAllUpstreams()
|
|
114
|
+
|
|
115
|
+
upstream1.abort("ignored")
|
|
116
|
+
upstream2.abort("ignored")
|
|
117
|
+
|
|
118
|
+
expect(abortManager.isAborted()).toBe(false)
|
|
119
|
+
})
|
|
120
|
+
|
|
121
|
+
test("AbortManager.tryToAbort evaluates mode conditions", () => {
|
|
122
|
+
const abortManager = new AbortManager({})
|
|
123
|
+
const upstream1 = new AbortController()
|
|
124
|
+
const upstream2 = new AbortController()
|
|
125
|
+
|
|
126
|
+
abortManager
|
|
127
|
+
.setMode(ABORT_MANAGER_MODE.ALL)
|
|
128
|
+
.addUpstreams([upstream1.signal, upstream2.signal])
|
|
129
|
+
|
|
130
|
+
upstream1.abort("first")
|
|
131
|
+
abortManager.tryToAbort()
|
|
132
|
+
|
|
133
|
+
expect(abortManager.isAborted()).toBe(false)
|
|
134
|
+
|
|
135
|
+
upstream2.abort("second")
|
|
136
|
+
abortManager.tryToAbort()
|
|
137
|
+
|
|
138
|
+
expect(abortManager.isAborted()).toBe(true)
|
|
139
|
+
})
|
|
140
|
+
|
|
141
|
+
test("AbortManager.abort aborts and applies auto-remove policy", () => {
|
|
142
|
+
class TestAbortManager extends AbortManager {
|
|
143
|
+
removeAllUpstreamsCalled = 0
|
|
144
|
+
|
|
145
|
+
override removeAllUpstreams(): this {
|
|
146
|
+
this.removeAllUpstreamsCalled = this.removeAllUpstreamsCalled + 1
|
|
147
|
+
return super.removeAllUpstreams()
|
|
148
|
+
}
|
|
149
|
+
}
|
|
150
|
+
|
|
151
|
+
const enabled = new TestAbortManager({ autoRemoveUpstreamsAfterAbort: true })
|
|
152
|
+
enabled.addUpstreams([new AbortController().signal])
|
|
153
|
+
enabled.abort("enabled")
|
|
154
|
+
|
|
155
|
+
const disabled = new TestAbortManager({ autoRemoveUpstreamsAfterAbort: false })
|
|
156
|
+
disabled.addUpstreams([new AbortController().signal])
|
|
157
|
+
disabled.abort("disabled")
|
|
158
|
+
|
|
159
|
+
expect(enabled.isAborted()).toBe(true)
|
|
160
|
+
expect(enabled.removeAllUpstreamsCalled).toBe(1)
|
|
161
|
+
expect(disabled.isAborted()).toBe(true)
|
|
162
|
+
expect(disabled.removeAllUpstreamsCalled).toBe(0)
|
|
163
|
+
})
|
|
164
|
+
|
|
165
|
+
test("fromAbortable creates manager from a single upstream abortable", () => {
|
|
166
|
+
const upstream = new AbortController()
|
|
167
|
+
const abortManager = fromAbortable(upstream)
|
|
168
|
+
|
|
169
|
+
expect(abortManager.isAborted()).toBe(false)
|
|
170
|
+
|
|
171
|
+
upstream.abort("stop")
|
|
172
|
+
|
|
173
|
+
expect(abortManager.isAborted()).toBe(true)
|
|
174
|
+
})
|
|
175
|
+
|
|
176
|
+
test("any creates manager that aborts when any upstream aborts", () => {
|
|
177
|
+
const upstream1 = new AbortController()
|
|
178
|
+
const upstream2 = new AbortController()
|
|
179
|
+
const abortManager = any([upstream1.signal, null, undefined, upstream2.signal])
|
|
180
|
+
|
|
181
|
+
expect(abortManager.isAborted()).toBe(false)
|
|
182
|
+
|
|
183
|
+
upstream1.abort("first")
|
|
184
|
+
|
|
185
|
+
expect(abortManager.isAborted()).toBe(true)
|
|
186
|
+
})
|
|
187
|
+
|
|
188
|
+
test("all creates manager that aborts only when all upstreams abort", () => {
|
|
189
|
+
const upstream1 = new AbortController()
|
|
190
|
+
const upstream2 = new AbortController()
|
|
191
|
+
const abortManager = all([upstream1.signal, null, undefined, upstream2.signal])
|
|
192
|
+
|
|
193
|
+
upstream1.abort("first")
|
|
194
|
+
|
|
195
|
+
expect(abortManager.isAborted()).toBe(false)
|
|
196
|
+
|
|
197
|
+
upstream2.abort("second")
|
|
198
|
+
|
|
199
|
+
expect(abortManager.isAborted()).toBe(true)
|
|
200
|
+
})
|
|
201
|
+
|
|
202
|
+
test("fromWithAbortSignal creates manager from options.abortSignal", () => {
|
|
203
|
+
const upstream = new AbortController()
|
|
204
|
+
const withSignal = fromWithAbortSignal({ abortSignal: upstream.signal })
|
|
205
|
+
const withoutSignal = fromWithAbortSignal({})
|
|
206
|
+
|
|
207
|
+
expect(withSignal.isAborted()).toBe(false)
|
|
208
|
+
expect(withoutSignal.isAborted()).toBe(false)
|
|
209
|
+
|
|
210
|
+
upstream.abort("stop")
|
|
211
|
+
|
|
212
|
+
expect(withSignal.isAborted()).toBe(true)
|
|
213
|
+
expect(withoutSignal.isAborted()).toBe(false)
|
|
214
|
+
})
|
|
215
|
+
|
|
216
|
+
test("fromAbortFriendlyOptions creates manager using abort-friendly options", () => {
|
|
217
|
+
const upstream = new AbortManager({})
|
|
218
|
+
const abortManager = fromAbortFriendlyOptions({ abortManager: upstream })
|
|
219
|
+
|
|
220
|
+
expect(abortManager.isAborted()).toBe(false)
|
|
221
|
+
|
|
222
|
+
upstream.abort("stop")
|
|
223
|
+
|
|
224
|
+
expect(abortManager.isAborted()).toBe(true)
|
|
225
|
+
})
|