@planet-matrix/mobius-model 0.6.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 +37 -0
- package/dist/index.js +706 -36
- package/dist/index.js.map +855 -59
- package/package.json +28 -16
- 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/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 +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/event/class-event-proxy.ts +6 -5
- package/src/event/common.ts +13 -3
- package/src/event/event-manager.ts +3 -3
- package/src/event/instance-event-proxy.ts +6 -5
- package/src/event/internal.ts +4 -4
- 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/index.ts +19 -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 +510 -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 +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/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/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 +138 -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 +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/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/error.spec.ts +16 -4
- 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 +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/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/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/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 +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/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/tube/helper.spec.ts +139 -0
- package/tests/unit/tube/tube.spec.ts +501 -0
- package/src/random/string.ts +0 -35
- package/tests/unit/random/string.spec.ts +0 -11
|
@@ -0,0 +1,156 @@
|
|
|
1
|
+
import type { IncomingMessage, Server, ServerResponse } from "node:http"
|
|
2
|
+
import { createServer } from "node:http"
|
|
3
|
+
import { networkInterfaces } from "node:os"
|
|
4
|
+
|
|
5
|
+
import type { ApiCoreHandler, ApiHostStartResult, ApiHostOptions } from "../api/api-host.ts"
|
|
6
|
+
import { ApiHost } from "../api/api-host.ts"
|
|
7
|
+
|
|
8
|
+
import { ApiCoreNodeHttp } from "./api-core-node-http.ts"
|
|
9
|
+
|
|
10
|
+
const internalGetListeningPort = (server: Server): number => {
|
|
11
|
+
const address = server.address()
|
|
12
|
+
|
|
13
|
+
if (address === null) {
|
|
14
|
+
throw new Error("Server is not running.")
|
|
15
|
+
}
|
|
16
|
+
|
|
17
|
+
if (typeof address === "string") {
|
|
18
|
+
throw new TypeError("HTTP server is not listening on a TCP port.")
|
|
19
|
+
}
|
|
20
|
+
|
|
21
|
+
return address.port
|
|
22
|
+
}
|
|
23
|
+
const internalFormatHttpHost = (address: string): string => {
|
|
24
|
+
const normalizedAddress = address.replaceAll("%", "%25")
|
|
25
|
+
|
|
26
|
+
if (normalizedAddress.includes(":")) {
|
|
27
|
+
return `[${normalizedAddress}]`
|
|
28
|
+
}
|
|
29
|
+
|
|
30
|
+
return normalizedAddress
|
|
31
|
+
}
|
|
32
|
+
const internalBuildHttpUrlList = (port: number): string[] => {
|
|
33
|
+
const urlSet = new Set<string>([
|
|
34
|
+
`http://127.0.0.1:${port}`,
|
|
35
|
+
`http://localhost:${port}`,
|
|
36
|
+
`http://[::1]:${port}`,
|
|
37
|
+
])
|
|
38
|
+
|
|
39
|
+
for (const networkInterfaceInfo of Object.values(networkInterfaces()).flat()) {
|
|
40
|
+
if (
|
|
41
|
+
networkInterfaceInfo === undefined
|
|
42
|
+
|| networkInterfaceInfo.address.length === 0
|
|
43
|
+
|| networkInterfaceInfo.internal === true
|
|
44
|
+
|| networkInterfaceInfo.address === "0.0.0.0"
|
|
45
|
+
|| networkInterfaceInfo.address === "::"
|
|
46
|
+
) {
|
|
47
|
+
continue
|
|
48
|
+
}
|
|
49
|
+
|
|
50
|
+
const address = internalFormatHttpHost(networkInterfaceInfo.address)
|
|
51
|
+
urlSet.add(`http://${address}:${port}`)
|
|
52
|
+
}
|
|
53
|
+
|
|
54
|
+
return [...urlSet]
|
|
55
|
+
}
|
|
56
|
+
|
|
57
|
+
export interface ApiHostNodeHttpOptions extends ApiHostOptions {
|
|
58
|
+
}
|
|
59
|
+
export class ApiHostNodeHttp extends ApiHost<Server> {
|
|
60
|
+
protected apiCoreHandler: ApiCoreHandler | undefined
|
|
61
|
+
|
|
62
|
+
constructor(options: ApiHostNodeHttpOptions) {
|
|
63
|
+
super(options)
|
|
64
|
+
|
|
65
|
+
this.apiCoreHandler = undefined
|
|
66
|
+
}
|
|
67
|
+
|
|
68
|
+
attachApiCoreHandler(apiCoreHandler: ApiCoreHandler): void {
|
|
69
|
+
this.apiCoreHandler = apiCoreHandler
|
|
70
|
+
}
|
|
71
|
+
|
|
72
|
+
async start(): Promise<ApiHostStartResult> {
|
|
73
|
+
if (this.server !== undefined) {
|
|
74
|
+
throw new Error("Server is already running.")
|
|
75
|
+
}
|
|
76
|
+
|
|
77
|
+
const server = createServer((request, response) => {
|
|
78
|
+
void this.handleRequest(request, response)
|
|
79
|
+
})
|
|
80
|
+
|
|
81
|
+
const result = await new Promise<ApiHostStartResult>((resolve, reject) => {
|
|
82
|
+
const handleError = (error: Error): void => {
|
|
83
|
+
server.off("listening", handleListening)
|
|
84
|
+
this.server = undefined
|
|
85
|
+
reject(error)
|
|
86
|
+
}
|
|
87
|
+
|
|
88
|
+
const handleListening = (): void => {
|
|
89
|
+
server.off("error", handleError)
|
|
90
|
+
this.server = server
|
|
91
|
+
|
|
92
|
+
server.once("close", () => {
|
|
93
|
+
if (this.server === server) {
|
|
94
|
+
this.server = undefined
|
|
95
|
+
}
|
|
96
|
+
})
|
|
97
|
+
|
|
98
|
+
const port = internalGetListeningPort(server)
|
|
99
|
+
resolve({
|
|
100
|
+
urlList: internalBuildHttpUrlList(port),
|
|
101
|
+
})
|
|
102
|
+
}
|
|
103
|
+
|
|
104
|
+
server.once("error", handleError)
|
|
105
|
+
server.once("listening", handleListening)
|
|
106
|
+
server.listen(this.options.port)
|
|
107
|
+
})
|
|
108
|
+
|
|
109
|
+
return result
|
|
110
|
+
}
|
|
111
|
+
|
|
112
|
+
async close(): Promise<void> {
|
|
113
|
+
if (this.isRunning() === false) {
|
|
114
|
+
return
|
|
115
|
+
}
|
|
116
|
+
|
|
117
|
+
const server = this.safeGetServer()
|
|
118
|
+
|
|
119
|
+
await new Promise<void>((resolve, reject) => {
|
|
120
|
+
server.close((error) => {
|
|
121
|
+
if (error !== undefined) {
|
|
122
|
+
reject(error)
|
|
123
|
+
return
|
|
124
|
+
}
|
|
125
|
+
|
|
126
|
+
resolve()
|
|
127
|
+
})
|
|
128
|
+
})
|
|
129
|
+
}
|
|
130
|
+
|
|
131
|
+
protected async handleRequest(
|
|
132
|
+
request: IncomingMessage,
|
|
133
|
+
response: ServerResponse<IncomingMessage>,
|
|
134
|
+
): Promise<void> {
|
|
135
|
+
const apiCore = new ApiCoreNodeHttp({ request, response })
|
|
136
|
+
const apiCoreHandler = this.apiCoreHandler
|
|
137
|
+
|
|
138
|
+
if (apiCoreHandler === undefined) {
|
|
139
|
+
this.logger.error("Request handling skipped because no ApiCore handler is attached.")
|
|
140
|
+
await apiCore.error()
|
|
141
|
+
return
|
|
142
|
+
}
|
|
143
|
+
|
|
144
|
+
try {
|
|
145
|
+
await apiCoreHandler(apiCore)
|
|
146
|
+
}
|
|
147
|
+
catch (exception) {
|
|
148
|
+
this.logger.error(`Request handling failed, exception: ${String(exception)}`)
|
|
149
|
+
await apiCore.error()
|
|
150
|
+
}
|
|
151
|
+
}
|
|
152
|
+
}
|
|
153
|
+
|
|
154
|
+
export const createApiHostNodeHttp = (options: ApiHostNodeHttpOptions): ApiHostNodeHttp => {
|
|
155
|
+
return new ApiHostNodeHttp(options)
|
|
156
|
+
}
|
|
@@ -0,0 +1,297 @@
|
|
|
1
|
+
import type { Type } from "arktype"
|
|
2
|
+
import { type } from "arktype"
|
|
3
|
+
|
|
4
|
+
import { generateUuidV4 } from "#Source/identifier/uuid.ts"
|
|
5
|
+
|
|
6
|
+
import type { ApiCore, ApiCoreStream } from "../api/api-core.ts"
|
|
7
|
+
import type { SuccessResultOptions, ErrorResultOptions } from "../api/api-result.ts"
|
|
8
|
+
import type { ApiHandlerContext } from "../api/api-handler.ts"
|
|
9
|
+
|
|
10
|
+
import { SuccessResult, ErrorResult } from "../api/api-result.ts"
|
|
11
|
+
|
|
12
|
+
export interface JsonSuccessResultOptions<Data> extends SuccessResultOptions<Data> {
|
|
13
|
+
data: Data
|
|
14
|
+
}
|
|
15
|
+
export class JsonSuccessResult<Data> extends SuccessResult<Data> {
|
|
16
|
+
protected declare options: JsonSuccessResultOptions<Data>
|
|
17
|
+
|
|
18
|
+
constructor(options: JsonSuccessResultOptions<Data>) {
|
|
19
|
+
super(options)
|
|
20
|
+
this.logger.setDefaultName("JsonSuccessResult")
|
|
21
|
+
}
|
|
22
|
+
|
|
23
|
+
async handle(apiCore: ApiCore): Promise<void> {
|
|
24
|
+
const { data } = this.options
|
|
25
|
+
|
|
26
|
+
this.logger.log(`send, ${JSON.stringify(data, null, 2)}`)
|
|
27
|
+
await apiCore.json(data)
|
|
28
|
+
this.logger.log(`end`)
|
|
29
|
+
}
|
|
30
|
+
}
|
|
31
|
+
|
|
32
|
+
export interface CommonSuccessJson<Data> {
|
|
33
|
+
status: "success"
|
|
34
|
+
data: Data
|
|
35
|
+
}
|
|
36
|
+
export interface CommonJsonSuccessResultOptions<Data> extends
|
|
37
|
+
Omit<JsonSuccessResultOptions<CommonSuccessJson<Data>>, "data"> {
|
|
38
|
+
data: Data
|
|
39
|
+
}
|
|
40
|
+
export class CommonJsonSuccessResult<Data>
|
|
41
|
+
extends JsonSuccessResult<CommonSuccessJson<Data>> {
|
|
42
|
+
protected declare options: JsonSuccessResultOptions<CommonSuccessJson<Data>>
|
|
43
|
+
|
|
44
|
+
constructor(options: CommonJsonSuccessResultOptions<Data>) {
|
|
45
|
+
super({
|
|
46
|
+
...options,
|
|
47
|
+
data: {
|
|
48
|
+
status: "success",
|
|
49
|
+
data: options.data,
|
|
50
|
+
},
|
|
51
|
+
})
|
|
52
|
+
this.logger.setDefaultName("CommonJsonSuccessResult")
|
|
53
|
+
}
|
|
54
|
+
}
|
|
55
|
+
export const commonJsonSuccessResult = <Data>(
|
|
56
|
+
options: CommonJsonSuccessResultOptions<Data>
|
|
57
|
+
): CommonJsonSuccessResult<Data> => {
|
|
58
|
+
return new CommonJsonSuccessResult<Data>(options)
|
|
59
|
+
}
|
|
60
|
+
|
|
61
|
+
export type CommonJsonSuccessResultSchema<Data> = Type<{
|
|
62
|
+
status: "success"
|
|
63
|
+
data: Data
|
|
64
|
+
}>
|
|
65
|
+
export type GetDataSchemaFromCommonJsonSuccessResultSchema<Schema extends Type>
|
|
66
|
+
= Schema extends CommonJsonSuccessResultSchema<infer Data> ? Type<Data> : never
|
|
67
|
+
export type GetDataFromCommonJsonSuccessResultSchema<Schema extends Type>
|
|
68
|
+
= Schema extends CommonJsonSuccessResultSchema<infer Data> ? Data : never
|
|
69
|
+
export const commonJsonSuccessResultSchema = <Data extends Record<string, unknown>>(
|
|
70
|
+
dataSchema: Type<Data>
|
|
71
|
+
): CommonJsonSuccessResultSchema<Data> => {
|
|
72
|
+
// arktype's instantiated object schema is compatible here but
|
|
73
|
+
// not assignable through its generic facade
|
|
74
|
+
// oxlint-disable-next-line typescript/no-unsafe-type-assertion
|
|
75
|
+
return type({
|
|
76
|
+
status: "'success'",
|
|
77
|
+
data: dataSchema,
|
|
78
|
+
}) as CommonJsonSuccessResultSchema<Data>
|
|
79
|
+
}
|
|
80
|
+
|
|
81
|
+
export type StreamWrite = (chunk: Buffer | string, encoding: BufferEncoding) => void | Promise<void>
|
|
82
|
+
export type StreamEnd = () => void | Promise<void>
|
|
83
|
+
export interface StreamSuccessResultOptions extends SuccessResultOptions<unknown> {
|
|
84
|
+
writeHandler: (write: StreamWrite) => Promise<void>
|
|
85
|
+
}
|
|
86
|
+
export class StreamSuccessResult extends SuccessResult<unknown> {
|
|
87
|
+
protected declare options: StreamSuccessResultOptions
|
|
88
|
+
|
|
89
|
+
protected streamId: string
|
|
90
|
+
|
|
91
|
+
constructor(options: StreamSuccessResultOptions) {
|
|
92
|
+
super(options)
|
|
93
|
+
this.logger.setDefaultName("StreamSuccessResult")
|
|
94
|
+
this.streamId = generateUuidV4()
|
|
95
|
+
}
|
|
96
|
+
|
|
97
|
+
async handle(apiCore: ApiCore): Promise<void> {
|
|
98
|
+
const apiCoreStream = await apiCore.stream()
|
|
99
|
+
|
|
100
|
+
const write = this.wrapWrite(apiCoreStream)
|
|
101
|
+
await this.options.writeHandler(write)
|
|
102
|
+
const end = this.wrapEnd(apiCoreStream)
|
|
103
|
+
await end()
|
|
104
|
+
}
|
|
105
|
+
|
|
106
|
+
/**
|
|
107
|
+
* 把 write 方法包装一下,以达到注入日志等目的。
|
|
108
|
+
*/
|
|
109
|
+
protected wrapWrite(apiCoreStream: ApiCoreStream): StreamWrite {
|
|
110
|
+
return async (chunk, encoding): Promise<void> => {
|
|
111
|
+
this.logger.log(`send, id: ${this.streamId}, data: ${String(chunk)}`)
|
|
112
|
+
await apiCoreStream.write(chunk, encoding)
|
|
113
|
+
}
|
|
114
|
+
}
|
|
115
|
+
|
|
116
|
+
/**
|
|
117
|
+
* 把 end 方法包装一下,以达到注入日志等目的。
|
|
118
|
+
*/
|
|
119
|
+
protected wrapEnd(apiCoreStream: ApiCoreStream): StreamEnd {
|
|
120
|
+
const end = async (): Promise<void> => {
|
|
121
|
+
this.logger.log(`end, id: ${this.streamId}`)
|
|
122
|
+
await apiCoreStream.end()
|
|
123
|
+
}
|
|
124
|
+
return end
|
|
125
|
+
}
|
|
126
|
+
}
|
|
127
|
+
|
|
128
|
+
export type CustomHandler = (apiCore: ApiCore) => Promise<void>
|
|
129
|
+
export interface CustomSuccessResultOptions extends SuccessResultOptions<unknown> {
|
|
130
|
+
customHandler: CustomHandler
|
|
131
|
+
}
|
|
132
|
+
export class CustomSuccessResult extends SuccessResult<unknown> {
|
|
133
|
+
protected declare options: CustomSuccessResultOptions
|
|
134
|
+
|
|
135
|
+
constructor(options: CustomSuccessResultOptions) {
|
|
136
|
+
super(options)
|
|
137
|
+
this.logger.setDefaultName("CustomSuccessResult")
|
|
138
|
+
}
|
|
139
|
+
|
|
140
|
+
async handle(apiCore: ApiCore): Promise<void> {
|
|
141
|
+
this.logger.log(`send`)
|
|
142
|
+
await this.options.customHandler(apiCore)
|
|
143
|
+
this.logger.log(`end`)
|
|
144
|
+
}
|
|
145
|
+
}
|
|
146
|
+
|
|
147
|
+
// ======================
|
|
148
|
+
|
|
149
|
+
export interface JsonErrorResultOptions<Data> extends ErrorResultOptions<Data> {
|
|
150
|
+
data: Data
|
|
151
|
+
}
|
|
152
|
+
export class JsonErrorResult<Data> extends ErrorResult<Data> {
|
|
153
|
+
protected declare options: JsonErrorResultOptions<Data>
|
|
154
|
+
|
|
155
|
+
constructor(options: JsonErrorResultOptions<Data>) {
|
|
156
|
+
super(options)
|
|
157
|
+
this.logger.setDefaultName("JsonErrorResult")
|
|
158
|
+
}
|
|
159
|
+
|
|
160
|
+
async handle(apiCore: ApiCore): Promise<void> {
|
|
161
|
+
const { data } = this.options
|
|
162
|
+
|
|
163
|
+
this.logger.log(`send, ${JSON.stringify(data, null, 2)}`)
|
|
164
|
+
await apiCore.json(data)
|
|
165
|
+
this.logger.log(`end`)
|
|
166
|
+
}
|
|
167
|
+
}
|
|
168
|
+
|
|
169
|
+
export interface CommonErrorJsonData<Reason extends string> {
|
|
170
|
+
reason: Reason
|
|
171
|
+
reasonDetail?: string | undefined
|
|
172
|
+
}
|
|
173
|
+
export interface CommonErrorJson<Reason extends string> {
|
|
174
|
+
status: "error"
|
|
175
|
+
data: CommonErrorJsonData<Reason>
|
|
176
|
+
}
|
|
177
|
+
export interface CommonJsonErrorResultOptions<Reason extends string>
|
|
178
|
+
extends Omit<JsonErrorResultOptions<CommonErrorJson<Reason>>, "data">,
|
|
179
|
+
CommonErrorJsonData<Reason> {
|
|
180
|
+
}
|
|
181
|
+
export class CommonJsonErrorResult<const Reason extends string>
|
|
182
|
+
extends JsonErrorResult<CommonErrorJson<Reason>> {
|
|
183
|
+
protected declare options: JsonErrorResultOptions<CommonErrorJson<Reason>>
|
|
184
|
+
|
|
185
|
+
constructor(options: CommonJsonErrorResultOptions<Reason>) {
|
|
186
|
+
super({
|
|
187
|
+
...options,
|
|
188
|
+
data: {
|
|
189
|
+
status: "error",
|
|
190
|
+
data: {
|
|
191
|
+
reason: options.reason,
|
|
192
|
+
reasonDetail: options.reasonDetail,
|
|
193
|
+
},
|
|
194
|
+
},
|
|
195
|
+
})
|
|
196
|
+
this.logger.setDefaultName("CommonJsonErrorResult")
|
|
197
|
+
}
|
|
198
|
+
}
|
|
199
|
+
export const commonJsonErrorResult = <const Reason extends string>(
|
|
200
|
+
options: CommonJsonErrorResultOptions<Reason>
|
|
201
|
+
): CommonJsonErrorResult<Reason> => {
|
|
202
|
+
return new CommonJsonErrorResult<Reason>(options)
|
|
203
|
+
}
|
|
204
|
+
|
|
205
|
+
export type CommonJsonErrorResultSchema<
|
|
206
|
+
Data extends {
|
|
207
|
+
reason: string
|
|
208
|
+
reasonDetail?: string | undefined
|
|
209
|
+
}
|
|
210
|
+
> = Type<{
|
|
211
|
+
status: "error"
|
|
212
|
+
data: Data & {
|
|
213
|
+
reasonDetail: string | undefined
|
|
214
|
+
}
|
|
215
|
+
}>
|
|
216
|
+
export type GetDataSchemaFromCommonJsonErrorResultSchema<Schema extends Type>
|
|
217
|
+
= Schema extends CommonJsonErrorResultSchema<infer Data> ? Type<Data> : never
|
|
218
|
+
export type GetDataFromCommonJsonErrorResultSchema<Schema extends Type>
|
|
219
|
+
= Schema extends CommonJsonErrorResultSchema<infer Data> ? Data : never
|
|
220
|
+
export type GetReasonFromCommonJsonErrorResultSchema<Schema extends Type>
|
|
221
|
+
= Schema extends CommonJsonErrorResultSchema<infer Data>
|
|
222
|
+
? Data extends { reason: infer Reason } ? Reason : never
|
|
223
|
+
: never
|
|
224
|
+
export const commonJsonErrorResultSchema = <
|
|
225
|
+
Data extends {
|
|
226
|
+
reason: string
|
|
227
|
+
reasonDetail?: string | undefined
|
|
228
|
+
}
|
|
229
|
+
>(
|
|
230
|
+
dataSchema: Type<Data>
|
|
231
|
+
): CommonJsonErrorResultSchema<Data> => {
|
|
232
|
+
// oxlint-disable-next-line typescript/no-unsafe-type-assertion
|
|
233
|
+
return type({
|
|
234
|
+
status: "'error'",
|
|
235
|
+
data: type.and(
|
|
236
|
+
// oxlint-disable-next-line typescript/no-unsafe-type-assertion
|
|
237
|
+
dataSchema as Type<{
|
|
238
|
+
reason: string
|
|
239
|
+
reasonDetail?: string | undefined
|
|
240
|
+
}>,
|
|
241
|
+
{
|
|
242
|
+
reasonDetail: type.string
|
|
243
|
+
}
|
|
244
|
+
),
|
|
245
|
+
}) as CommonJsonErrorResultSchema<Data>
|
|
246
|
+
}
|
|
247
|
+
|
|
248
|
+
// ======================
|
|
249
|
+
|
|
250
|
+
export type ContextWithResultHandler<
|
|
251
|
+
Path extends string,
|
|
252
|
+
Method extends "get" | "post",
|
|
253
|
+
InputQuerySchema extends Type,
|
|
254
|
+
InputBodySchema extends Type,
|
|
255
|
+
OutputSuccessSchema extends Type,
|
|
256
|
+
OutputErrorSchema extends Type,
|
|
257
|
+
>
|
|
258
|
+
= ApiHandlerContext<Path, Method, InputQuerySchema, InputBodySchema, OutputSuccessSchema, OutputErrorSchema>
|
|
259
|
+
& {
|
|
260
|
+
commonJsonSuccessResult: (
|
|
261
|
+
options: CommonJsonSuccessResultOptions<GetDataFromCommonJsonSuccessResultSchema<OutputSuccessSchema>>
|
|
262
|
+
) => CommonJsonSuccessResult<GetDataFromCommonJsonSuccessResultSchema<OutputSuccessSchema>>
|
|
263
|
+
commonJsonErrorResult: (
|
|
264
|
+
options: CommonJsonErrorResultOptions<GetReasonFromCommonJsonErrorResultSchema<OutputErrorSchema>>
|
|
265
|
+
) => CommonJsonErrorResult<GetReasonFromCommonJsonErrorResultSchema<OutputErrorSchema>>
|
|
266
|
+
}
|
|
267
|
+
|
|
268
|
+
export const withResultHandler = <
|
|
269
|
+
Path extends string,
|
|
270
|
+
Method extends "get" | "post",
|
|
271
|
+
InputQuerySchema extends Type,
|
|
272
|
+
InputBodySchema extends Type,
|
|
273
|
+
OutputSuccessSchema extends Type,
|
|
274
|
+
OutputErrorSchema extends Type,
|
|
275
|
+
>(
|
|
276
|
+
context: ApiHandlerContext<Path, Method, InputQuerySchema, InputBodySchema, OutputSuccessSchema, OutputErrorSchema>,
|
|
277
|
+
): ContextWithResultHandler<Path, Method, InputQuerySchema, InputBodySchema, OutputSuccessSchema, OutputErrorSchema> => {
|
|
278
|
+
return {
|
|
279
|
+
...context,
|
|
280
|
+
commonJsonSuccessResult: (
|
|
281
|
+
options: CommonJsonSuccessResultOptions<GetDataFromCommonJsonSuccessResultSchema<OutputSuccessSchema>>,
|
|
282
|
+
) => {
|
|
283
|
+
return commonJsonSuccessResult({
|
|
284
|
+
logger: context.logger,
|
|
285
|
+
...options,
|
|
286
|
+
})
|
|
287
|
+
},
|
|
288
|
+
commonJsonErrorResult: (
|
|
289
|
+
options: CommonJsonErrorResultOptions<GetReasonFromCommonJsonErrorResultSchema<OutputErrorSchema>>,
|
|
290
|
+
) => {
|
|
291
|
+
return commonJsonErrorResult<GetReasonFromCommonJsonErrorResultSchema<OutputErrorSchema>>({
|
|
292
|
+
logger: context.logger,
|
|
293
|
+
...options,
|
|
294
|
+
})
|
|
295
|
+
},
|
|
296
|
+
}
|
|
297
|
+
}
|