@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.
Files changed (258) hide show
  1. package/CHANGELOG.md +50 -0
  2. package/oxlint.config.ts +1 -2
  3. package/package.json +29 -17
  4. package/scripts/build.ts +2 -52
  5. package/src/ai/README.md +1 -0
  6. package/src/ai/ai.ts +107 -0
  7. package/src/ai/chat-completion-ai/aihubmix-chat-completion.ts +78 -0
  8. package/src/ai/chat-completion-ai/chat-completion-ai.ts +270 -0
  9. package/src/ai/chat-completion-ai/chat-completion.ts +189 -0
  10. package/src/ai/chat-completion-ai/index.ts +7 -0
  11. package/src/ai/chat-completion-ai/lingyiwanwu-chat-completion.ts +78 -0
  12. package/src/ai/chat-completion-ai/ohmygpt-chat-completion.ts +78 -0
  13. package/src/ai/chat-completion-ai/openai-next-chat-completion.ts +78 -0
  14. package/src/ai/embedding-ai/embedding-ai.ts +63 -0
  15. package/src/ai/embedding-ai/embedding.ts +50 -0
  16. package/src/ai/embedding-ai/index.ts +4 -0
  17. package/src/ai/embedding-ai/openai-next-embedding.ts +23 -0
  18. package/src/ai/index.ts +4 -0
  19. package/src/aio/README.md +100 -0
  20. package/src/aio/content.ts +141 -0
  21. package/src/aio/index.ts +3 -0
  22. package/src/aio/json.ts +127 -0
  23. package/src/aio/prompt.ts +246 -0
  24. package/src/basic/README.md +20 -15
  25. package/src/basic/error.ts +19 -5
  26. package/src/basic/function.ts +2 -2
  27. package/src/basic/index.ts +1 -0
  28. package/src/basic/promise.ts +141 -71
  29. package/src/basic/schedule.ts +111 -0
  30. package/src/basic/stream.ts +135 -25
  31. package/src/credential/README.md +107 -0
  32. package/src/credential/api-key.ts +158 -0
  33. package/src/credential/bearer.ts +73 -0
  34. package/src/credential/index.ts +4 -0
  35. package/src/credential/json-web-token.ts +96 -0
  36. package/src/credential/password.ts +170 -0
  37. package/src/cron/README.md +86 -0
  38. package/src/cron/cron.ts +87 -0
  39. package/src/cron/index.ts +1 -0
  40. package/src/drizzle/README.md +1 -0
  41. package/src/drizzle/drizzle.ts +1 -0
  42. package/src/drizzle/helper.ts +47 -0
  43. package/src/drizzle/index.ts +5 -0
  44. package/src/drizzle/infer.ts +52 -0
  45. package/src/drizzle/kysely.ts +8 -0
  46. package/src/drizzle/pagination.ts +198 -0
  47. package/src/email/README.md +1 -0
  48. package/src/email/index.ts +1 -0
  49. package/src/email/resend.ts +25 -0
  50. package/src/event/class-event-proxy.ts +5 -6
  51. package/src/event/common.ts +13 -3
  52. package/src/event/event-manager.ts +3 -3
  53. package/src/event/instance-event-proxy.ts +5 -6
  54. package/src/event/internal.ts +4 -4
  55. package/src/exception/README.md +28 -19
  56. package/src/exception/error/error.ts +123 -0
  57. package/src/exception/error/index.ts +2 -0
  58. package/src/exception/error/match.ts +38 -0
  59. package/src/exception/error/must-fix.ts +17 -0
  60. package/src/exception/index.ts +2 -0
  61. package/src/file-system/find.ts +53 -0
  62. package/src/file-system/index.ts +2 -0
  63. package/src/file-system/path.ts +76 -0
  64. package/src/file-system/resolve.ts +22 -0
  65. package/src/form/README.md +25 -0
  66. package/src/form/index.ts +1 -0
  67. package/src/form/inputor-controller/base.ts +861 -0
  68. package/src/form/inputor-controller/boolean.ts +39 -0
  69. package/src/form/inputor-controller/file.ts +39 -0
  70. package/src/form/inputor-controller/form.ts +179 -0
  71. package/src/form/inputor-controller/helper.ts +117 -0
  72. package/src/form/inputor-controller/index.ts +17 -0
  73. package/src/form/inputor-controller/multi-select.ts +99 -0
  74. package/src/form/inputor-controller/number.ts +116 -0
  75. package/src/form/inputor-controller/select.ts +109 -0
  76. package/src/form/inputor-controller/text.ts +82 -0
  77. package/src/http/READMD.md +1 -0
  78. package/src/http/api/api-core.ts +84 -0
  79. package/src/http/api/api-handler.ts +79 -0
  80. package/src/http/api/api-host.ts +47 -0
  81. package/src/http/api/api-result.ts +56 -0
  82. package/src/http/api/api-schema.ts +154 -0
  83. package/src/http/api/api-server.ts +130 -0
  84. package/src/http/api/api-test.ts +142 -0
  85. package/src/http/api/api-type.ts +34 -0
  86. package/src/http/api/api.ts +81 -0
  87. package/src/http/api/index.ts +11 -0
  88. package/src/http/api-adapter/api-core-node-http.ts +260 -0
  89. package/src/http/api-adapter/api-host-node-http.ts +156 -0
  90. package/src/http/api-adapter/api-result-arktype.ts +294 -0
  91. package/src/http/api-adapter/api-result-zod.ts +286 -0
  92. package/src/http/api-adapter/index.ts +5 -0
  93. package/src/http/bin/gen-api-list/gen-api-list.ts +126 -0
  94. package/src/http/bin/gen-api-list/index.ts +1 -0
  95. package/src/http/bin/gen-api-test/gen-api-test.ts +136 -0
  96. package/src/http/bin/gen-api-test/index.ts +1 -0
  97. package/src/http/bin/gen-api-type/calc-code.ts +25 -0
  98. package/src/http/bin/gen-api-type/gen-api-type.ts +127 -0
  99. package/src/http/bin/gen-api-type/index.ts +2 -0
  100. package/src/http/bin/index.ts +2 -0
  101. package/src/http/index.ts +3 -0
  102. package/src/huawei/README.md +1 -0
  103. package/src/huawei/index.ts +2 -0
  104. package/src/huawei/moderation/index.ts +1 -0
  105. package/src/huawei/moderation/moderation.ts +355 -0
  106. package/src/huawei/obs/esdk-obs-nodejs.d.ts +87 -0
  107. package/src/huawei/obs/index.ts +1 -0
  108. package/src/huawei/obs/obs.ts +42 -0
  109. package/src/index.ts +21 -2
  110. package/src/json/README.md +92 -0
  111. package/src/json/index.ts +1 -0
  112. package/src/json/repair.ts +18 -0
  113. package/src/log/logger.ts +15 -4
  114. package/src/openai/README.md +1 -0
  115. package/src/openai/index.ts +1 -0
  116. package/src/openai/openai.ts +509 -0
  117. package/src/orchestration/README.md +9 -7
  118. package/src/orchestration/dispatching/dispatcher.ts +83 -0
  119. package/src/orchestration/dispatching/index.ts +2 -0
  120. package/src/orchestration/dispatching/selector/base-selector.ts +39 -0
  121. package/src/orchestration/dispatching/selector/down-count-selector.ts +119 -0
  122. package/src/orchestration/dispatching/selector/index.ts +2 -0
  123. package/src/orchestration/index.ts +2 -0
  124. package/src/orchestration/scheduling/index.ts +2 -0
  125. package/src/orchestration/scheduling/scheduler.ts +103 -0
  126. package/src/orchestration/scheduling/task.ts +32 -0
  127. package/src/random/README.md +8 -7
  128. package/src/random/base.ts +66 -0
  129. package/src/random/index.ts +5 -1
  130. package/src/random/random-boolean.ts +40 -0
  131. package/src/random/random-integer.ts +60 -0
  132. package/src/random/random-number.ts +72 -0
  133. package/src/random/random-string.ts +66 -0
  134. package/src/request/README.md +108 -0
  135. package/src/request/fetch/base.ts +108 -0
  136. package/src/request/fetch/browser.ts +280 -0
  137. package/src/request/fetch/general.ts +20 -0
  138. package/src/request/fetch/index.ts +4 -0
  139. package/src/request/fetch/nodejs.ts +280 -0
  140. package/src/request/index.ts +2 -0
  141. package/src/request/request/base.ts +246 -0
  142. package/src/request/request/general.ts +63 -0
  143. package/src/request/request/index.ts +3 -0
  144. package/src/request/request/resource.ts +68 -0
  145. package/src/result/README.md +4 -0
  146. package/src/result/controller.ts +58 -0
  147. package/src/result/either.ts +363 -0
  148. package/src/result/generator.ts +168 -0
  149. package/src/result/index.ts +3 -0
  150. package/src/route/README.md +105 -0
  151. package/src/route/adapter/browser.ts +122 -0
  152. package/src/route/adapter/driver.ts +56 -0
  153. package/src/route/adapter/index.ts +2 -0
  154. package/src/route/index.ts +3 -0
  155. package/src/route/router/index.ts +2 -0
  156. package/src/route/router/route.ts +630 -0
  157. package/src/route/router/router.ts +1641 -0
  158. package/src/route/uri/hash.ts +307 -0
  159. package/src/route/uri/index.ts +7 -0
  160. package/src/route/uri/pathname.ts +376 -0
  161. package/src/route/uri/search.ts +412 -0
  162. package/src/service/README.md +1 -0
  163. package/src/service/index.ts +1 -0
  164. package/src/service/service.ts +110 -0
  165. package/src/socket/README.md +105 -0
  166. package/src/socket/client/index.ts +2 -0
  167. package/src/socket/client/socket-unit.ts +658 -0
  168. package/src/socket/client/socket.ts +203 -0
  169. package/src/socket/common/index.ts +2 -0
  170. package/src/socket/common/socket-unit-common.ts +23 -0
  171. package/src/socket/common/socket-unit-heartbeat.ts +427 -0
  172. package/src/socket/index.ts +3 -0
  173. package/src/socket/server/index.ts +3 -0
  174. package/src/socket/server/server.ts +183 -0
  175. package/src/socket/server/socket-unit.ts +448 -0
  176. package/src/socket/server/socket.ts +264 -0
  177. package/src/storage/table.ts +3 -3
  178. package/src/timer/expiration/expiration-manager.ts +3 -3
  179. package/src/timer/expiration/remaining-manager.ts +3 -3
  180. package/src/tube/README.md +99 -0
  181. package/src/tube/helper.ts +137 -0
  182. package/src/tube/index.ts +2 -0
  183. package/src/tube/tube.ts +880 -0
  184. package/src/weixin/README.md +1 -0
  185. package/src/weixin/index.ts +2 -0
  186. package/src/weixin/official-account/authorization.ts +157 -0
  187. package/src/weixin/official-account/index.ts +2 -0
  188. package/src/weixin/official-account/js-api.ts +132 -0
  189. package/src/weixin/open/index.ts +1 -0
  190. package/src/weixin/open/oauth2.ts +131 -0
  191. package/tests/unit/ai/ai.spec.ts +85 -0
  192. package/tests/unit/aio/content.spec.ts +105 -0
  193. package/tests/unit/aio/json.spec.ts +146 -0
  194. package/tests/unit/aio/prompt.spec.ts +111 -0
  195. package/tests/unit/basic/error.spec.ts +16 -4
  196. package/tests/unit/basic/promise.spec.ts +158 -50
  197. package/tests/unit/basic/schedule.spec.ts +74 -0
  198. package/tests/unit/basic/stream.spec.ts +90 -37
  199. package/tests/unit/credential/api-key.spec.ts +36 -0
  200. package/tests/unit/credential/bearer.spec.ts +23 -0
  201. package/tests/unit/credential/json-web-token.spec.ts +23 -0
  202. package/tests/unit/credential/password.spec.ts +40 -0
  203. package/tests/unit/cron/cron.spec.ts +84 -0
  204. package/tests/unit/event/class-event-proxy.spec.ts +3 -3
  205. package/tests/unit/event/event-manager.spec.ts +3 -3
  206. package/tests/unit/event/instance-event-proxy.spec.ts +3 -3
  207. package/tests/unit/exception/error/error.spec.ts +83 -0
  208. package/tests/unit/exception/error/match.spec.ts +81 -0
  209. package/tests/unit/form/inputor-controller/base.spec.ts +458 -0
  210. package/tests/unit/form/inputor-controller/boolean.spec.ts +30 -0
  211. package/tests/unit/form/inputor-controller/file.spec.ts +27 -0
  212. package/tests/unit/form/inputor-controller/form.spec.ts +120 -0
  213. package/tests/unit/form/inputor-controller/helper.spec.ts +67 -0
  214. package/tests/unit/form/inputor-controller/multi-select.spec.ts +34 -0
  215. package/tests/unit/form/inputor-controller/number.spec.ts +36 -0
  216. package/tests/unit/form/inputor-controller/select.spec.ts +49 -0
  217. package/tests/unit/form/inputor-controller/text.spec.ts +34 -0
  218. package/tests/unit/http/api/api-core-host.spec.ts +207 -0
  219. package/tests/unit/http/api/api-schema.spec.ts +120 -0
  220. package/tests/unit/http/api/api-server.spec.ts +363 -0
  221. package/tests/unit/http/api/api-test.spec.ts +117 -0
  222. package/tests/unit/http/api/api.spec.ts +121 -0
  223. package/tests/unit/http/api-adapter/node-http.spec.ts +187 -0
  224. package/tests/unit/identifier/uuid.spec.ts +0 -1
  225. package/tests/unit/json/repair.spec.ts +11 -0
  226. package/tests/unit/log/logger.spec.ts +19 -4
  227. package/tests/unit/openai/openai.spec.ts +64 -0
  228. package/tests/unit/orchestration/dispatching/dispatcher.spec.ts +41 -0
  229. package/tests/unit/orchestration/dispatching/selector/down-count-selector.spec.ts +81 -0
  230. package/tests/unit/orchestration/scheduling/scheduler.spec.ts +103 -0
  231. package/tests/unit/random/base.spec.ts +58 -0
  232. package/tests/unit/random/random-boolean.spec.ts +25 -0
  233. package/tests/unit/random/random-integer.spec.ts +32 -0
  234. package/tests/unit/random/random-number.spec.ts +33 -0
  235. package/tests/unit/random/random-string.spec.ts +22 -0
  236. package/tests/unit/request/fetch/browser.spec.ts +222 -0
  237. package/tests/unit/request/fetch/general.spec.ts +43 -0
  238. package/tests/unit/request/fetch/nodejs.spec.ts +225 -0
  239. package/tests/unit/request/request/base.spec.ts +382 -0
  240. package/tests/unit/request/request/general.spec.ts +160 -0
  241. package/tests/unit/result/controller.spec.ts +82 -0
  242. package/tests/unit/result/either.spec.ts +377 -0
  243. package/tests/unit/result/generator.spec.ts +273 -0
  244. package/tests/unit/route/router/route.spec.ts +430 -0
  245. package/tests/unit/route/router/router.spec.ts +407 -0
  246. package/tests/unit/route/uri/hash.spec.ts +72 -0
  247. package/tests/unit/route/uri/pathname.spec.ts +146 -0
  248. package/tests/unit/route/uri/search.spec.ts +107 -0
  249. package/tests/unit/socket/client.spec.ts +208 -0
  250. package/tests/unit/socket/server.spec.ts +133 -0
  251. package/tests/unit/socket/socket-unit-heartbeat.spec.ts +214 -0
  252. package/tests/unit/tube/helper.spec.ts +139 -0
  253. package/tests/unit/tube/tube.spec.ts +501 -0
  254. package/vite.config.ts +2 -1
  255. package/dist/index.js +0 -50
  256. package/dist/index.js.map +0 -209
  257. package/src/random/string.ts +0 -35
  258. 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,294 @@
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
+ return type({
75
+ status: "'success'",
76
+ data: dataSchema,
77
+ }) as CommonJsonSuccessResultSchema<Data>
78
+ }
79
+
80
+ export type StreamWrite = (chunk: Buffer | string, encoding: BufferEncoding) => void | Promise<void>
81
+ export type StreamEnd = () => void | Promise<void>
82
+ export interface StreamSuccessResultOptions extends SuccessResultOptions<unknown> {
83
+ writeHandler: (write: StreamWrite) => Promise<void>
84
+ }
85
+ export class StreamSuccessResult extends SuccessResult<unknown> {
86
+ protected declare options: StreamSuccessResultOptions
87
+
88
+ protected streamId: string
89
+
90
+ constructor(options: StreamSuccessResultOptions) {
91
+ super(options)
92
+ this.logger.setDefaultName("StreamSuccessResult")
93
+ this.streamId = generateUuidV4()
94
+ }
95
+
96
+ async handle(apiCore: ApiCore): Promise<void> {
97
+ const apiCoreStream = await apiCore.stream()
98
+
99
+ const write = this.wrapWrite(apiCoreStream)
100
+ await this.options.writeHandler(write)
101
+ const end = this.wrapEnd(apiCoreStream)
102
+ await end()
103
+ }
104
+
105
+ /**
106
+ * 把 write 方法包装一下,以达到注入日志等目的。
107
+ */
108
+ protected wrapWrite(apiCoreStream: ApiCoreStream): StreamWrite {
109
+ return async (chunk, encoding): Promise<void> => {
110
+ this.logger.log(`send, id: ${this.streamId}, data: ${String(chunk)}`)
111
+ await apiCoreStream.write(chunk, encoding)
112
+ }
113
+ }
114
+
115
+ /**
116
+ * 把 end 方法包装一下,以达到注入日志等目的。
117
+ */
118
+ protected wrapEnd(apiCoreStream: ApiCoreStream): StreamEnd {
119
+ const end = async (): Promise<void> => {
120
+ this.logger.log(`end, id: ${this.streamId}`)
121
+ await apiCoreStream.end()
122
+ }
123
+ return end
124
+ }
125
+ }
126
+
127
+ export type CustomHandler = (apiCore: ApiCore) => Promise<void>
128
+ export interface CustomSuccessResultOptions extends SuccessResultOptions<unknown> {
129
+ customHandler: CustomHandler
130
+ }
131
+ export class CustomSuccessResult extends SuccessResult<unknown> {
132
+ protected declare options: CustomSuccessResultOptions
133
+
134
+ constructor(options: CustomSuccessResultOptions) {
135
+ super(options)
136
+ this.logger.setDefaultName("CustomSuccessResult")
137
+ }
138
+
139
+ async handle(apiCore: ApiCore): Promise<void> {
140
+ this.logger.log(`send`)
141
+ await this.options.customHandler(apiCore)
142
+ this.logger.log(`end`)
143
+ }
144
+ }
145
+
146
+ // ======================
147
+
148
+ export interface JsonErrorResultOptions<Data> extends ErrorResultOptions<Data> {
149
+ data: Data
150
+ }
151
+ export class JsonErrorResult<Data> extends ErrorResult<Data> {
152
+ protected declare options: JsonErrorResultOptions<Data>
153
+
154
+ constructor(options: JsonErrorResultOptions<Data>) {
155
+ super(options)
156
+ this.logger.setDefaultName("JsonErrorResult")
157
+ }
158
+
159
+ async handle(apiCore: ApiCore): Promise<void> {
160
+ const { data } = this.options
161
+
162
+ this.logger.log(`send, ${JSON.stringify(data, null, 2)}`)
163
+ await apiCore.json(data)
164
+ this.logger.log(`end`)
165
+ }
166
+ }
167
+
168
+ export interface CommonErrorJsonData<Reason extends string> {
169
+ reason: Reason
170
+ reasonDetail?: string | undefined
171
+ }
172
+ export interface CommonErrorJson<Reason extends string> {
173
+ status: "error"
174
+ data: CommonErrorJsonData<Reason>
175
+ }
176
+ export interface CommonJsonErrorResultOptions<Reason extends string>
177
+ extends Omit<JsonErrorResultOptions<CommonErrorJson<Reason>>, "data">,
178
+ CommonErrorJsonData<Reason> {
179
+ }
180
+ export class CommonJsonErrorResult<const Reason extends string>
181
+ extends JsonErrorResult<CommonErrorJson<Reason>> {
182
+ protected declare options: JsonErrorResultOptions<CommonErrorJson<Reason>>
183
+
184
+ constructor(options: CommonJsonErrorResultOptions<Reason>) {
185
+ super({
186
+ ...options,
187
+ data: {
188
+ status: "error",
189
+ data: {
190
+ reason: options.reason,
191
+ reasonDetail: options.reasonDetail,
192
+ },
193
+ },
194
+ })
195
+ this.logger.setDefaultName("CommonJsonErrorResult")
196
+ }
197
+ }
198
+ export const commonJsonErrorResult = <const Reason extends string>(
199
+ options: CommonJsonErrorResultOptions<Reason>
200
+ ): CommonJsonErrorResult<Reason> => {
201
+ return new CommonJsonErrorResult<Reason>(options)
202
+ }
203
+
204
+ export type CommonJsonErrorResultSchema<
205
+ Data extends {
206
+ reason: string
207
+ reasonDetail?: string | undefined
208
+ }
209
+ > = Type<{
210
+ status: "error"
211
+ data: Data & {
212
+ reasonDetail: string | undefined
213
+ }
214
+ }>
215
+ export type GetDataSchemaFromCommonJsonErrorResultSchema<Schema extends Type>
216
+ = Schema extends CommonJsonErrorResultSchema<infer Data> ? Type<Data> : never
217
+ export type GetDataFromCommonJsonErrorResultSchema<Schema extends Type>
218
+ = Schema extends CommonJsonErrorResultSchema<infer Data> ? Data : never
219
+ export type GetReasonFromCommonJsonErrorResultSchema<Schema extends Type>
220
+ = Schema extends CommonJsonErrorResultSchema<infer Data>
221
+ ? Data extends { reason: infer Reason } ? Reason : never
222
+ : never
223
+ export const commonJsonErrorResultSchema = <
224
+ Data extends {
225
+ reason: string
226
+ reasonDetail?: string | undefined
227
+ }
228
+ >(
229
+ dataSchema: Type<Data>
230
+ ): CommonJsonErrorResultSchema<Data> => {
231
+ return type({
232
+ status: "'error'",
233
+ data: type.and(
234
+ dataSchema as Type<{
235
+ reason: string
236
+ reasonDetail?: string | undefined
237
+ }>,
238
+ {
239
+ reasonDetail: type.string
240
+ }
241
+ ),
242
+ }) as CommonJsonErrorResultSchema<Data>
243
+ }
244
+
245
+ // ======================
246
+
247
+ export type ContextWithResultHandler<
248
+ Path extends string,
249
+ Method extends "get" | "post",
250
+ InputQuerySchema extends Type,
251
+ InputBodySchema extends Type,
252
+ OutputSuccessSchema extends Type,
253
+ OutputErrorSchema extends Type,
254
+ >
255
+ = ApiHandlerContext<Path, Method, InputQuerySchema, InputBodySchema, OutputSuccessSchema, OutputErrorSchema>
256
+ & {
257
+ commonJsonSuccessResult: (
258
+ options: CommonJsonSuccessResultOptions<GetDataFromCommonJsonSuccessResultSchema<OutputSuccessSchema>>
259
+ ) => CommonJsonSuccessResult<GetDataFromCommonJsonSuccessResultSchema<OutputSuccessSchema>>
260
+ commonJsonErrorResult: (
261
+ options: CommonJsonErrorResultOptions<GetReasonFromCommonJsonErrorResultSchema<OutputErrorSchema>>
262
+ ) => CommonJsonErrorResult<GetReasonFromCommonJsonErrorResultSchema<OutputErrorSchema>>
263
+ }
264
+
265
+ export const withResultHandler = <
266
+ Path extends string,
267
+ Method extends "get" | "post",
268
+ InputQuerySchema extends Type,
269
+ InputBodySchema extends Type,
270
+ OutputSuccessSchema extends Type,
271
+ OutputErrorSchema extends Type,
272
+ >(
273
+ context: ApiHandlerContext<Path, Method, InputQuerySchema, InputBodySchema, OutputSuccessSchema, OutputErrorSchema>,
274
+ ): ContextWithResultHandler<Path, Method, InputQuerySchema, InputBodySchema, OutputSuccessSchema, OutputErrorSchema> => {
275
+ return {
276
+ ...context,
277
+ commonJsonSuccessResult: (
278
+ options: CommonJsonSuccessResultOptions<GetDataFromCommonJsonSuccessResultSchema<OutputSuccessSchema>>,
279
+ ) => {
280
+ return commonJsonSuccessResult({
281
+ logger: context.logger,
282
+ ...options,
283
+ })
284
+ },
285
+ commonJsonErrorResult: (
286
+ options: CommonJsonErrorResultOptions<GetReasonFromCommonJsonErrorResultSchema<OutputErrorSchema>>,
287
+ ) => {
288
+ return commonJsonErrorResult<GetReasonFromCommonJsonErrorResultSchema<OutputErrorSchema>>({
289
+ logger: context.logger,
290
+ ...options,
291
+ })
292
+ },
293
+ }
294
+ }