@planet-matrix/mobius-model 0.6.0 → 0.10.1
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/CHANGELOG.md +50 -0
- package/oxlint.config.ts +1 -2
- package/package.json +29 -17
- package/scripts/build.ts +2 -52
- 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 +20 -15
- package/src/basic/error.ts +19 -5
- package/src/basic/function.ts +2 -2
- package/src/basic/index.ts +1 -0
- package/src/basic/promise.ts +141 -71
- package/src/basic/schedule.ts +111 -0
- package/src/basic/stream.ts +135 -25
- 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/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 +198 -0
- package/src/email/README.md +1 -0
- package/src/email/index.ts +1 -0
- package/src/email/resend.ts +25 -0
- package/src/event/class-event-proxy.ts +5 -6
- package/src/event/common.ts +13 -3
- package/src/event/event-manager.ts +3 -3
- package/src/event/instance-event-proxy.ts +5 -6
- package/src/event/internal.ts +4 -4
- package/src/exception/README.md +28 -19
- package/src/exception/error/error.ts +123 -0
- package/src/exception/error/index.ts +2 -0
- package/src/exception/error/match.ts +38 -0
- package/src/exception/error/must-fix.ts +17 -0
- package/src/exception/index.ts +2 -0
- package/src/file-system/find.ts +53 -0
- package/src/file-system/index.ts +2 -0
- package/src/file-system/path.ts +76 -0
- package/src/file-system/resolve.ts +22 -0
- package/src/form/README.md +25 -0
- package/src/form/index.ts +1 -0
- package/src/form/inputor-controller/base.ts +861 -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 +179 -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 +34 -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 +294 -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/index.ts +21 -2
- package/src/json/README.md +92 -0
- package/src/json/index.ts +1 -0
- package/src/json/repair.ts +18 -0
- package/src/log/logger.ts +15 -4
- package/src/openai/README.md +1 -0
- package/src/openai/index.ts +1 -0
- package/src/openai/openai.ts +509 -0
- package/src/orchestration/README.md +9 -7
- 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 +2 -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 +8 -7
- 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/request/README.md +108 -0
- package/src/request/fetch/base.ts +108 -0
- package/src/request/fetch/browser.ts +280 -0
- package/src/request/fetch/general.ts +20 -0
- package/src/request/fetch/index.ts +4 -0
- package/src/request/fetch/nodejs.ts +280 -0
- package/src/request/index.ts +2 -0
- package/src/request/request/base.ts +246 -0
- package/src/request/request/general.ts +63 -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 +58 -0
- package/src/result/either.ts +363 -0
- package/src/result/generator.ts +168 -0
- package/src/result/index.ts +3 -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 +1641 -0
- package/src/route/uri/hash.ts +307 -0
- package/src/route/uri/index.ts +7 -0
- package/src/route/uri/pathname.ts +376 -0
- package/src/route/uri/search.ts +412 -0
- package/src/service/README.md +1 -0
- package/src/service/index.ts +1 -0
- package/src/service/service.ts +110 -0
- package/src/socket/README.md +105 -0
- package/src/socket/client/index.ts +2 -0
- package/src/socket/client/socket-unit.ts +658 -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 +448 -0
- package/src/socket/server/socket.ts +264 -0
- package/src/storage/table.ts +3 -3
- package/src/timer/expiration/expiration-manager.ts +3 -3
- package/src/timer/expiration/remaining-manager.ts +3 -3
- package/src/tube/README.md +99 -0
- package/src/tube/helper.ts +137 -0
- package/src/tube/index.ts +2 -0
- package/src/tube/tube.ts +880 -0
- package/src/weixin/README.md +1 -0
- package/src/weixin/index.ts +2 -0
- package/src/weixin/official-account/authorization.ts +157 -0
- package/src/weixin/official-account/index.ts +2 -0
- package/src/weixin/official-account/js-api.ts +132 -0
- package/src/weixin/open/index.ts +1 -0
- package/src/weixin/open/oauth2.ts +131 -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 +146 -0
- package/tests/unit/aio/prompt.spec.ts +111 -0
- package/tests/unit/basic/error.spec.ts +16 -4
- package/tests/unit/basic/promise.spec.ts +158 -50
- package/tests/unit/basic/schedule.spec.ts +74 -0
- package/tests/unit/basic/stream.spec.ts +90 -37
- package/tests/unit/credential/api-key.spec.ts +36 -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 +40 -0
- package/tests/unit/cron/cron.spec.ts +84 -0
- package/tests/unit/event/class-event-proxy.spec.ts +3 -3
- package/tests/unit/event/event-manager.spec.ts +3 -3
- package/tests/unit/event/instance-event-proxy.spec.ts +3 -3
- package/tests/unit/exception/error/error.spec.ts +83 -0
- package/tests/unit/exception/error/match.spec.ts +81 -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 +187 -0
- package/tests/unit/identifier/uuid.spec.ts +0 -1
- package/tests/unit/json/repair.spec.ts +11 -0
- package/tests/unit/log/logger.spec.ts +19 -4
- package/tests/unit/openai/openai.spec.ts +64 -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/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 +382 -0
- package/tests/unit/request/request/general.spec.ts +160 -0
- package/tests/unit/result/controller.spec.ts +82 -0
- package/tests/unit/result/either.spec.ts +377 -0
- package/tests/unit/result/generator.spec.ts +273 -0
- package/tests/unit/route/router/route.spec.ts +430 -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 +146 -0
- package/tests/unit/route/uri/search.spec.ts +107 -0
- package/tests/unit/socket/client.spec.ts +208 -0
- package/tests/unit/socket/server.spec.ts +133 -0
- package/tests/unit/socket/socket-unit-heartbeat.spec.ts +214 -0
- package/tests/unit/tube/helper.spec.ts +139 -0
- package/tests/unit/tube/tube.spec.ts +501 -0
- package/vite.config.ts +2 -1
- package/dist/index.js +0 -50
- package/dist/index.js.map +0 -209
- package/src/random/string.ts +0 -35
- package/tests/unit/random/string.spec.ts +0 -11
|
@@ -0,0 +1,246 @@
|
|
|
1
|
+
import type { BuildEvents } from "#Source/event/index.ts"
|
|
2
|
+
import { EventManager } from "#Source/event/index.ts"
|
|
3
|
+
import { isError, errorIsNetworkError, errorStringify } from "#Source/basic/index.ts"
|
|
4
|
+
|
|
5
|
+
import type { BaseFetch, FetchResponseType, FetchFactory } from "../fetch/index.ts"
|
|
6
|
+
import { generalFetch } from "../fetch/index.ts"
|
|
7
|
+
import type {
|
|
8
|
+
Resource,
|
|
9
|
+
ResourceOutput,
|
|
10
|
+
ResourceSuccessOutput,
|
|
11
|
+
ResourceErrorOutput,
|
|
12
|
+
ResourceSuccessData,
|
|
13
|
+
ResourceErrorData,
|
|
14
|
+
ResourcePatchOutput,
|
|
15
|
+
} from "./resource.ts"
|
|
16
|
+
|
|
17
|
+
/**
|
|
18
|
+
* 描述请求执行过程中会派发的标准事件集合。
|
|
19
|
+
*/
|
|
20
|
+
export type BaseRequestEvents<R extends Resource> = BuildEvents<{
|
|
21
|
+
output: (output: ResourceOutput<R>) => void
|
|
22
|
+
successOutput: (successOutput: ResourceSuccessOutput<R>) => void
|
|
23
|
+
successData: (successData: ResourceSuccessData<R>) => void
|
|
24
|
+
errorOutput: (errorOutput: ResourceErrorOutput<R>) => void
|
|
25
|
+
errorData: (errorData: ResourceErrorData<R>) => void
|
|
26
|
+
patchOutput: (patchOutput: ResourcePatchOutput<R>) => void
|
|
27
|
+
}>
|
|
28
|
+
|
|
29
|
+
/**
|
|
30
|
+
* 实际执行请求动作的选项。
|
|
31
|
+
*
|
|
32
|
+
* 该类型会根据资源声明中 `input.query` 与 `input.body` 是否可选,
|
|
33
|
+
* 自动收紧当前路径对应请求选项里的必填性。
|
|
34
|
+
*/
|
|
35
|
+
export type RequestOptions<Path, R extends Resource>
|
|
36
|
+
= {
|
|
37
|
+
baseUrl: Extract<R, { path: Path }>["baseUrl"]
|
|
38
|
+
path: Extract<R, { path: Path }>["path"]
|
|
39
|
+
method: Extract<R, { path: Path }>["method"]
|
|
40
|
+
headers?: Record<string, string> | undefined
|
|
41
|
+
responseType?: FetchResponseType | undefined
|
|
42
|
+
timeout?: number | undefined
|
|
43
|
+
abortSignal?: AbortSignal | undefined
|
|
44
|
+
} & (
|
|
45
|
+
undefined extends Extract<R, { path: Path }>["input"]["query"]
|
|
46
|
+
? { query?: Extract<R, { path: Path }>["input"]["query"] | undefined }
|
|
47
|
+
: { query: Extract<R, { path: Path }>["input"]["query"] }
|
|
48
|
+
) & (
|
|
49
|
+
undefined extends Extract<R, { path: Path }>["input"]["body"]
|
|
50
|
+
? { body?: Extract<R, { path: Path }>["input"]["body"] | undefined }
|
|
51
|
+
: { body: Extract<R, { path: Path }>["input"]["body"] }
|
|
52
|
+
) & {
|
|
53
|
+
onOutput?: ((output: ResourceOutput<Extract<R, { path: Path }>>) => void) | undefined
|
|
54
|
+
onSuccessOutput?: ((successOutput: ResourceSuccessOutput<Extract<R, { path: Path }>>) => void) | undefined
|
|
55
|
+
onSuccessData?: ((successData: ResourceSuccessData<Extract<R, { path: Path }>>) => void) | undefined
|
|
56
|
+
onErrorOutput?: ((errorOutput: ResourceErrorOutput<Extract<R, { path: Path }>>) => void) | undefined
|
|
57
|
+
onErrorData?: ((errorData: ResourceErrorData<Extract<R, { path: Path }>>) => void) | undefined
|
|
58
|
+
onPatchOutput?: ((patchOutput: ResourcePatchOutput<Extract<R, { path: Path }>>) => void) | undefined
|
|
59
|
+
}
|
|
60
|
+
|
|
61
|
+
/**
|
|
62
|
+
* 实际执行请求动作的结果。
|
|
63
|
+
*/
|
|
64
|
+
export type RequestResult<Path, R extends Resource>
|
|
65
|
+
= ResourceOutput<Extract<R, { path: Path }>>
|
|
66
|
+
| ResourcePatchOutput<Extract<R, { path: Path }>>
|
|
67
|
+
|
|
68
|
+
/**
|
|
69
|
+
* 表示请求失败时的错误归类。
|
|
70
|
+
*/
|
|
71
|
+
export type ErrorKind = "network" | "unknown"
|
|
72
|
+
|
|
73
|
+
/**
|
|
74
|
+
* 生成补丁输出时可使用的上下文。
|
|
75
|
+
*/
|
|
76
|
+
export type GeneratePatchOutputContext = {
|
|
77
|
+
type: "error"
|
|
78
|
+
errorKind: ErrorKind
|
|
79
|
+
error: Error
|
|
80
|
+
}
|
|
81
|
+
|
|
82
|
+
/**
|
|
83
|
+
* 构造专用请求类的选项。
|
|
84
|
+
*/
|
|
85
|
+
export interface BaseRequestOptions<R extends Resource> {
|
|
86
|
+
/**
|
|
87
|
+
* 自定义请求执行器工厂;未提供时使用默认的通用运行时分派实现。
|
|
88
|
+
*/
|
|
89
|
+
fetchFactory?: FetchFactory | undefined
|
|
90
|
+
|
|
91
|
+
/**
|
|
92
|
+
* 在真正发起请求前,对标准化请求选项做最后一次统一调整。
|
|
93
|
+
*/
|
|
94
|
+
modifyRequestOptions?: ((options: RequestOptions<R["path"], R>) => RequestOptions<R["path"], R>) | undefined
|
|
95
|
+
|
|
96
|
+
/**
|
|
97
|
+
* 在请求失败时生成仍可被上层继续消费的补丁输出。
|
|
98
|
+
*/
|
|
99
|
+
generatePatchOutput: (context: GeneratePatchOutputContext) => ResourcePatchOutput<R>
|
|
100
|
+
}
|
|
101
|
+
|
|
102
|
+
/**
|
|
103
|
+
* 基于资源声明组织请求、输出分类与失败补丁的抽象请求类。
|
|
104
|
+
*
|
|
105
|
+
* `Resource` 类型参数应传入资源声明的联合类型或元组成员联合。
|
|
106
|
+
* 默认实现假定 JSON 输出可通过 `status` 字段区分为 `success` 与 `error`,
|
|
107
|
+
* 并通过 `data` 字段提取真正的成功数据或错误数据;若资源输出不满足这组约定,
|
|
108
|
+
* 则应由子类覆写对应的分类与提取方法。
|
|
109
|
+
*/
|
|
110
|
+
export abstract class BaseRequest<R extends Resource = Resource> {
|
|
111
|
+
protected options: BaseRequestOptions<R>
|
|
112
|
+
|
|
113
|
+
/**
|
|
114
|
+
* 对外暴露请求生命周期事件的事件管理器。
|
|
115
|
+
*/
|
|
116
|
+
event: EventManager<BaseRequestEvents<R>>
|
|
117
|
+
|
|
118
|
+
constructor(options: BaseRequestOptions<R>) {
|
|
119
|
+
this.options = options
|
|
120
|
+
this.event = new EventManager()
|
|
121
|
+
}
|
|
122
|
+
|
|
123
|
+
/**
|
|
124
|
+
* 判断当前输出是否应被视为成功输出。
|
|
125
|
+
*/
|
|
126
|
+
protected isSuccessDataResponse(response: ResourceOutput<R>): boolean {
|
|
127
|
+
return response['status'] === "success"
|
|
128
|
+
}
|
|
129
|
+
|
|
130
|
+
/**
|
|
131
|
+
* 从成功输出中提取成功数据。
|
|
132
|
+
*/
|
|
133
|
+
protected extractSuccessData(response: ResourceSuccessOutput<R>): ResourceSuccessData<R> {
|
|
134
|
+
return response['data'] as ResourceSuccessData<R>
|
|
135
|
+
}
|
|
136
|
+
|
|
137
|
+
/**
|
|
138
|
+
* 判断当前输出是否应被视为错误输出。
|
|
139
|
+
*/
|
|
140
|
+
protected isErrorDataResponse(response: ResourceOutput<R>): boolean {
|
|
141
|
+
return response['status'] === "error"
|
|
142
|
+
}
|
|
143
|
+
|
|
144
|
+
/**
|
|
145
|
+
* 从错误输出中提取错误数据。
|
|
146
|
+
*/
|
|
147
|
+
protected extractErrorData(response: ResourceErrorOutput<R>): ResourceErrorData<R> {
|
|
148
|
+
return response['data'] as ResourceErrorData<R>
|
|
149
|
+
}
|
|
150
|
+
|
|
151
|
+
/**
|
|
152
|
+
* 按资源路径约束执行一次请求,并在成功或失败时派发对应事件。
|
|
153
|
+
*/
|
|
154
|
+
async request<Path extends R["path"]>(
|
|
155
|
+
options: RequestOptions<Path, R>,
|
|
156
|
+
): Promise<RequestResult<Path, R>> {
|
|
157
|
+
const { fetchFactory, modifyRequestOptions } = this.options
|
|
158
|
+
|
|
159
|
+
const preparedOptions = modifyRequestOptions !== undefined
|
|
160
|
+
? modifyRequestOptions(options as RequestOptions<R["path"], R>)
|
|
161
|
+
: options
|
|
162
|
+
|
|
163
|
+
const {
|
|
164
|
+
responseType = "json",
|
|
165
|
+
onOutput,
|
|
166
|
+
onSuccessOutput,
|
|
167
|
+
onSuccessData,
|
|
168
|
+
onErrorOutput,
|
|
169
|
+
onErrorData,
|
|
170
|
+
onPatchOutput,
|
|
171
|
+
} = preparedOptions
|
|
172
|
+
|
|
173
|
+
try {
|
|
174
|
+
type FetchInput = {
|
|
175
|
+
query: Extract<R, { path: Path }>["input"]["query"]
|
|
176
|
+
body: Extract<R, { path: Path }>["input"]["body"]
|
|
177
|
+
}
|
|
178
|
+
type FetchOutput = {
|
|
179
|
+
[K in typeof responseType]: {
|
|
180
|
+
type: K
|
|
181
|
+
data: ResourceOutput<Extract<R, { path: Path }>>
|
|
182
|
+
}
|
|
183
|
+
}[typeof responseType]
|
|
184
|
+
const preparedFetch = (fetchFactory ?? generalFetch)(preparedOptions) as BaseFetch<FetchInput, FetchOutput>
|
|
185
|
+
|
|
186
|
+
if (responseType === "json") {
|
|
187
|
+
const json = await preparedFetch.getJson()
|
|
188
|
+
onOutput?.(json)
|
|
189
|
+
this.event.emit("output", json)
|
|
190
|
+
|
|
191
|
+
// do we have a better way to consume the success data?
|
|
192
|
+
if (this.isSuccessDataResponse(json)) {
|
|
193
|
+
onSuccessOutput?.(json)
|
|
194
|
+
this.event.emit("successOutput", json)
|
|
195
|
+
const successData = this.extractSuccessData(json)
|
|
196
|
+
onSuccessData?.(successData)
|
|
197
|
+
this.event.emit("successData", successData)
|
|
198
|
+
}
|
|
199
|
+
|
|
200
|
+
if (this.isErrorDataResponse(json)) {
|
|
201
|
+
onErrorOutput?.(json)
|
|
202
|
+
this.event.emit("errorOutput", json)
|
|
203
|
+
const errorData = this.extractErrorData(json)
|
|
204
|
+
onErrorData?.(errorData)
|
|
205
|
+
this.event.emit("errorData", errorData)
|
|
206
|
+
}
|
|
207
|
+
|
|
208
|
+
return json
|
|
209
|
+
}
|
|
210
|
+
|
|
211
|
+
throw new Error("Unsupported response type, please use \"json\" or improve implementation of BaseRequest.")
|
|
212
|
+
}
|
|
213
|
+
catch (exception) {
|
|
214
|
+
if (errorIsNetworkError(exception)) {
|
|
215
|
+
const patchOutput = this.options.generatePatchOutput({
|
|
216
|
+
type: "error",
|
|
217
|
+
errorKind: "network",
|
|
218
|
+
error: exception
|
|
219
|
+
})
|
|
220
|
+
onPatchOutput?.(patchOutput)
|
|
221
|
+
this.event.emit("patchOutput", patchOutput)
|
|
222
|
+
return patchOutput
|
|
223
|
+
}
|
|
224
|
+
else if (isError(exception)) {
|
|
225
|
+
const patchOutput = this.options.generatePatchOutput({
|
|
226
|
+
type: "error",
|
|
227
|
+
errorKind: "unknown",
|
|
228
|
+
error: exception
|
|
229
|
+
})
|
|
230
|
+
onPatchOutput?.(patchOutput)
|
|
231
|
+
this.event.emit("patchOutput", patchOutput)
|
|
232
|
+
return patchOutput
|
|
233
|
+
}
|
|
234
|
+
else {
|
|
235
|
+
const patchOutput = this.options.generatePatchOutput({
|
|
236
|
+
type: "error",
|
|
237
|
+
errorKind: "unknown",
|
|
238
|
+
error: new Error(errorStringify(exception))
|
|
239
|
+
})
|
|
240
|
+
onPatchOutput?.(patchOutput)
|
|
241
|
+
this.event.emit("patchOutput", patchOutput)
|
|
242
|
+
return patchOutput
|
|
243
|
+
}
|
|
244
|
+
}
|
|
245
|
+
}
|
|
246
|
+
}
|
|
@@ -0,0 +1,63 @@
|
|
|
1
|
+
import type { ResourcePatchOutput } from "./resource.ts"
|
|
2
|
+
import type { BaseRequestOptions, GeneratePatchOutputContext } from "./base.ts"
|
|
3
|
+
import { BaseRequest } from "./base.ts"
|
|
4
|
+
|
|
5
|
+
/**
|
|
6
|
+
* 描述适用于通用 `{ status, data }` 输出结构的资源声明。
|
|
7
|
+
*/
|
|
8
|
+
export interface GeneralResource {
|
|
9
|
+
baseUrl: string
|
|
10
|
+
path: string
|
|
11
|
+
method: "get" | "post"
|
|
12
|
+
input: {
|
|
13
|
+
query?: Record<string, unknown> | undefined
|
|
14
|
+
body?: Record<string, unknown> | undefined
|
|
15
|
+
}
|
|
16
|
+
successData: Record<string, unknown>
|
|
17
|
+
errorData: Record<string, unknown>
|
|
18
|
+
}
|
|
19
|
+
|
|
20
|
+
/**
|
|
21
|
+
* 把通用资源声明补齐为 `BaseRequest` 可直接消费的完整资源契约。
|
|
22
|
+
*/
|
|
23
|
+
export type GeneralResourceToResource<R extends GeneralResource> = R & {
|
|
24
|
+
output: { status: "success", data: R["successData"] } | { status: "error", data: R["errorData"] }
|
|
25
|
+
successOutput: { status: "success", data: R["successData"] }
|
|
26
|
+
errorOutput: { status: "error", data: R["errorData"] }
|
|
27
|
+
patchOutput: { status: "unknown", data: GeneratePatchOutputContext }
|
|
28
|
+
}
|
|
29
|
+
|
|
30
|
+
/**
|
|
31
|
+
* 构造通用请求类的选项。
|
|
32
|
+
*
|
|
33
|
+
* 该类型会沿用 `BaseRequestOptions` 的配置能力,只是由 `GeneralRequest`
|
|
34
|
+
* 自动补齐失败时的补丁输出生成逻辑。
|
|
35
|
+
*/
|
|
36
|
+
export interface GeneralRequestOptions<R extends GeneralResource>
|
|
37
|
+
extends Omit<BaseRequestOptions<GeneralResourceToResource<R>>, "generatePatchOutput"> {
|
|
38
|
+
}
|
|
39
|
+
|
|
40
|
+
/**
|
|
41
|
+
* 面向通用 `{ status, data }` 输出结构的请求实现。
|
|
42
|
+
*
|
|
43
|
+
* `GeneralRequest` 仅适用于返回结构严格符合特定情况的目标资源,特定情况指:
|
|
44
|
+
*
|
|
45
|
+
* 1. 业务结果仅包含成功(success)和错误(error)两种状态。
|
|
46
|
+
* 2. 业务结果通过一个名为 `status` 的字段区分状态,并通过一个名为 `data` 的字段承载数据:
|
|
47
|
+
* `{ status: "success" | "error", data: Record<string, unknown> }`。
|
|
48
|
+
*/
|
|
49
|
+
export class GeneralRequest<R extends GeneralResource = GeneralResource>
|
|
50
|
+
extends BaseRequest<GeneralResourceToResource<R>> {
|
|
51
|
+
constructor(options: GeneralRequestOptions<R>) {
|
|
52
|
+
const generatePatchOutput = (context: GeneratePatchOutputContext): ResourcePatchOutput<GeneralResourceToResource<R>> => {
|
|
53
|
+
return {
|
|
54
|
+
status: "unknown",
|
|
55
|
+
data: context
|
|
56
|
+
} as ResourcePatchOutput<GeneralResourceToResource<R>>
|
|
57
|
+
}
|
|
58
|
+
super({
|
|
59
|
+
...options,
|
|
60
|
+
generatePatchOutput
|
|
61
|
+
})
|
|
62
|
+
}
|
|
63
|
+
}
|
|
@@ -0,0 +1,68 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* 描述一个远程资源契约。
|
|
3
|
+
*
|
|
4
|
+
* 这个接口用于把某一路径、方法、输入、输出、成功数据、错误数据与失败补丁输出
|
|
5
|
+
* 收束为一份可长期维护的类型层声明,供 `BaseRequest` 及其派生实现消费。
|
|
6
|
+
*/
|
|
7
|
+
export interface Resource {
|
|
8
|
+
baseUrl: string
|
|
9
|
+
path: string
|
|
10
|
+
method: "get" | "post"
|
|
11
|
+
input: {
|
|
12
|
+
query?: Record<string, unknown> | undefined
|
|
13
|
+
body?: Record<string, unknown> | undefined
|
|
14
|
+
}
|
|
15
|
+
output: Record<string, unknown>
|
|
16
|
+
|
|
17
|
+
successOutput: Record<string, unknown>
|
|
18
|
+
successData: Record<string, unknown>
|
|
19
|
+
errorOutput: Record<string, unknown>
|
|
20
|
+
errorData: Record<string, unknown>
|
|
21
|
+
|
|
22
|
+
patchOutput: Record<string, unknown>
|
|
23
|
+
}
|
|
24
|
+
|
|
25
|
+
/**
|
|
26
|
+
* 提取资源声明中的基础 URL 类型。
|
|
27
|
+
*/
|
|
28
|
+
export type ResourceBaseUrl<R extends Resource> = R["baseUrl"]
|
|
29
|
+
|
|
30
|
+
/**
|
|
31
|
+
* 提取资源声明中的路径类型。
|
|
32
|
+
*/
|
|
33
|
+
export type ResourcePath<R extends Resource> = R["path"]
|
|
34
|
+
|
|
35
|
+
/**
|
|
36
|
+
* 提取资源声明中的请求方法类型。
|
|
37
|
+
*/
|
|
38
|
+
export type ResourceMethod<R extends Resource> = R["method"]
|
|
39
|
+
|
|
40
|
+
/**
|
|
41
|
+
* 提取资源声明中的完整输出类型。
|
|
42
|
+
*/
|
|
43
|
+
export type ResourceOutput<R extends Resource> = R["output"]
|
|
44
|
+
|
|
45
|
+
/**
|
|
46
|
+
* 提取资源声明中的成功输出类型。
|
|
47
|
+
*/
|
|
48
|
+
export type ResourceSuccessOutput<R extends Resource> = R["successOutput"]
|
|
49
|
+
|
|
50
|
+
/**
|
|
51
|
+
* 提取资源声明中的错误输出类型。
|
|
52
|
+
*/
|
|
53
|
+
export type ResourceErrorOutput<R extends Resource> = R["errorOutput"]
|
|
54
|
+
|
|
55
|
+
/**
|
|
56
|
+
* 提取资源声明中的成功数据类型。
|
|
57
|
+
*/
|
|
58
|
+
export type ResourceSuccessData<R extends Resource> = R["successData"]
|
|
59
|
+
|
|
60
|
+
/**
|
|
61
|
+
* 提取资源声明中的错误数据类型。
|
|
62
|
+
*/
|
|
63
|
+
export type ResourceErrorData<R extends Resource> = R["errorData"]
|
|
64
|
+
|
|
65
|
+
/**
|
|
66
|
+
* 提取资源声明中的补丁输出类型。
|
|
67
|
+
*/
|
|
68
|
+
export type ResourcePatchOutput<R extends Resource> = R["patchOutput"]
|
|
@@ -0,0 +1,58 @@
|
|
|
1
|
+
import type { Either } from "./either.ts"
|
|
2
|
+
import { Left, Right } from "./either.ts"
|
|
3
|
+
|
|
4
|
+
export class Controller<L, R> {
|
|
5
|
+
static isLeft<L, R>(target: unknown): target is Left<L, R> {
|
|
6
|
+
return Left.isLeft(target)
|
|
7
|
+
}
|
|
8
|
+
|
|
9
|
+
static isRight<L, R>(target: unknown): target is Right<L, R> {
|
|
10
|
+
return Right.isRight(target)
|
|
11
|
+
}
|
|
12
|
+
|
|
13
|
+
protected promise: Promise<Either<L, R>>
|
|
14
|
+
protected resolve: (value: Either<L, R>) => void
|
|
15
|
+
protected reject: (value: L) => void
|
|
16
|
+
|
|
17
|
+
constructor() {
|
|
18
|
+
let _resolve: (value: Either<L, R>) => void
|
|
19
|
+
let _reject: (value: L) => void
|
|
20
|
+
this.promise = new Promise((resolve, reject) => {
|
|
21
|
+
_resolve = resolve
|
|
22
|
+
_reject = reject
|
|
23
|
+
})
|
|
24
|
+
this.resolve = _resolve!
|
|
25
|
+
this.reject = _reject!
|
|
26
|
+
}
|
|
27
|
+
|
|
28
|
+
get value(): Promise<Either<L, R>> {
|
|
29
|
+
return this.promise
|
|
30
|
+
}
|
|
31
|
+
|
|
32
|
+
async returnRight(value: R): Promise<Right<L, R>> {
|
|
33
|
+
const right = new Right<L, R>(value)
|
|
34
|
+
this.resolve(right)
|
|
35
|
+
return await Promise.resolve(right)
|
|
36
|
+
}
|
|
37
|
+
|
|
38
|
+
async returnLeft(value: L): Promise<Left<L, R>> {
|
|
39
|
+
const left = new Left<L, R>(value)
|
|
40
|
+
this.resolve(left)
|
|
41
|
+
return await Promise.resolve(left)
|
|
42
|
+
}
|
|
43
|
+
|
|
44
|
+
// oxlint-disable-next-line require-await
|
|
45
|
+
async throw(value: L): Promise<void> {
|
|
46
|
+
const left = new Left<L, R>(value)
|
|
47
|
+
this.resolve(left)
|
|
48
|
+
// oxlint-disable-next-line typescript/only-throw-error
|
|
49
|
+
throw left
|
|
50
|
+
}
|
|
51
|
+
}
|
|
52
|
+
|
|
53
|
+
type GetLeft<E> = E extends Either<infer L, infer _> ? L : never
|
|
54
|
+
type GetRight<E> = E extends Either<infer _, infer R> ? R : never
|
|
55
|
+
export const controllerFromEitherType = <E extends Either<unknown, unknown>>(
|
|
56
|
+
): Controller<GetLeft<E>, GetRight<E>> => {
|
|
57
|
+
return new Controller<GetLeft<E>, GetRight<E>>()
|
|
58
|
+
}
|