@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,286 @@
|
|
|
1
|
+
import { z } from "zod"
|
|
2
|
+
|
|
3
|
+
import { generateUuidV4 } from "#Source/identifier/uuid.ts"
|
|
4
|
+
|
|
5
|
+
import type { ApiCore, ApiCoreStream } from "../api/api-core.ts"
|
|
6
|
+
import type { SuccessResultOptions, ErrorResultOptions } from "../api/api-result.ts"
|
|
7
|
+
import type { ApiHandlerContext } from "../api/api-handler.ts"
|
|
8
|
+
|
|
9
|
+
import { SuccessResult, ErrorResult } from "../api/api-result.ts"
|
|
10
|
+
|
|
11
|
+
export interface JsonSuccessResultOptions<Data> extends SuccessResultOptions<Data> {
|
|
12
|
+
data: Data
|
|
13
|
+
}
|
|
14
|
+
export class JsonSuccessResult<Data> extends SuccessResult<Data> {
|
|
15
|
+
protected declare options: JsonSuccessResultOptions<Data>
|
|
16
|
+
|
|
17
|
+
constructor(options: JsonSuccessResultOptions<Data>) {
|
|
18
|
+
super(options)
|
|
19
|
+
this.logger.setDefaultName("JsonSuccessResult")
|
|
20
|
+
}
|
|
21
|
+
|
|
22
|
+
async handle(apiCore: ApiCore): Promise<void> {
|
|
23
|
+
const { data } = this.options
|
|
24
|
+
|
|
25
|
+
this.logger.log(`send, ${JSON.stringify(data, null, 2)}`)
|
|
26
|
+
await apiCore.json(data)
|
|
27
|
+
this.logger.log(`end`)
|
|
28
|
+
}
|
|
29
|
+
}
|
|
30
|
+
|
|
31
|
+
export interface CommonSuccessJson<Data> {
|
|
32
|
+
status: "success"
|
|
33
|
+
data: Data
|
|
34
|
+
}
|
|
35
|
+
export interface CommonJsonSuccessResultOptions<Data>
|
|
36
|
+
extends Omit<JsonSuccessResultOptions<CommonSuccessJson<Data>>, "data"> {
|
|
37
|
+
data: Data
|
|
38
|
+
}
|
|
39
|
+
export class CommonJsonSuccessResult<Data>
|
|
40
|
+
extends JsonSuccessResult<CommonSuccessJson<Data>> {
|
|
41
|
+
protected declare options: JsonSuccessResultOptions<CommonSuccessJson<Data>>
|
|
42
|
+
|
|
43
|
+
constructor(options: CommonJsonSuccessResultOptions<Data>) {
|
|
44
|
+
super({
|
|
45
|
+
...options,
|
|
46
|
+
data: {
|
|
47
|
+
status: "success",
|
|
48
|
+
data: options.data,
|
|
49
|
+
},
|
|
50
|
+
})
|
|
51
|
+
this.logger.setDefaultName("CommonJsonSuccessResult")
|
|
52
|
+
}
|
|
53
|
+
}
|
|
54
|
+
export const commonJsonSuccessResult = <Data>(
|
|
55
|
+
options: CommonJsonSuccessResultOptions<Data>
|
|
56
|
+
): CommonJsonSuccessResult<Data> => {
|
|
57
|
+
return new CommonJsonSuccessResult<Data>(options)
|
|
58
|
+
}
|
|
59
|
+
|
|
60
|
+
export type CommonJsonSuccessResultSchema<DataSchema extends z.ZodObject> = z.ZodObject<{
|
|
61
|
+
status: z.ZodLiteral<"success">
|
|
62
|
+
data: DataSchema
|
|
63
|
+
}>
|
|
64
|
+
export type GetDataSchemaFromCommonJsonSuccessResultSchema<Schema extends z.ZodType>
|
|
65
|
+
= Schema extends CommonJsonSuccessResultSchema<infer DataSchema> ? DataSchema : never
|
|
66
|
+
export type GetDataFromCommonJsonSuccessResultSchema<Schema extends z.ZodType>
|
|
67
|
+
= Schema extends CommonJsonSuccessResultSchema<infer DataSchema> ? z.infer<DataSchema> : never
|
|
68
|
+
export const commonJsonSuccessResultSchema = <DataSchema extends z.ZodObject>(
|
|
69
|
+
dataSchema: DataSchema,
|
|
70
|
+
): CommonJsonSuccessResultSchema<DataSchema> => {
|
|
71
|
+
return z.object({
|
|
72
|
+
status: z.literal("success"),
|
|
73
|
+
data: dataSchema,
|
|
74
|
+
})
|
|
75
|
+
}
|
|
76
|
+
|
|
77
|
+
export type StreamWrite = (chunk: Buffer | string, encoding: BufferEncoding) => void | Promise<void>
|
|
78
|
+
export type StreamEnd = () => void | Promise<void>
|
|
79
|
+
export interface StreamSuccessResultOptions extends SuccessResultOptions<unknown> {
|
|
80
|
+
writeHandler: (write: StreamWrite) => Promise<void>
|
|
81
|
+
}
|
|
82
|
+
export class StreamSuccessResult extends SuccessResult<unknown> {
|
|
83
|
+
protected declare options: StreamSuccessResultOptions
|
|
84
|
+
|
|
85
|
+
protected streamId: string
|
|
86
|
+
|
|
87
|
+
constructor(options: StreamSuccessResultOptions) {
|
|
88
|
+
super(options)
|
|
89
|
+
this.logger.setDefaultName("StreamSuccessResult")
|
|
90
|
+
this.streamId = generateUuidV4()
|
|
91
|
+
}
|
|
92
|
+
|
|
93
|
+
async handle(apiCore: ApiCore): Promise<void> {
|
|
94
|
+
const apiCoreStream = await apiCore.stream()
|
|
95
|
+
|
|
96
|
+
const write = this.wrapWrite(apiCoreStream)
|
|
97
|
+
await this.options.writeHandler(write)
|
|
98
|
+
const end = this.wrapEnd(apiCoreStream)
|
|
99
|
+
await end()
|
|
100
|
+
}
|
|
101
|
+
|
|
102
|
+
/**
|
|
103
|
+
* 把 write 方法包装一下,以达到注入日志等目的。
|
|
104
|
+
*/
|
|
105
|
+
protected wrapWrite(apiCoreStream: ApiCoreStream): StreamWrite {
|
|
106
|
+
return async (chunk, encoding): Promise<void> => {
|
|
107
|
+
this.logger.log(`send, id: ${this.streamId}, data: ${String(chunk)}`)
|
|
108
|
+
await apiCoreStream.write(chunk, encoding)
|
|
109
|
+
}
|
|
110
|
+
}
|
|
111
|
+
|
|
112
|
+
/**
|
|
113
|
+
* 把 end 方法包装一下,以达到注入日志等目的。
|
|
114
|
+
*/
|
|
115
|
+
protected wrapEnd(apiCoreStream: ApiCoreStream): StreamEnd {
|
|
116
|
+
const end = async (): Promise<void> => {
|
|
117
|
+
this.logger.log(`end, id: ${this.streamId}`)
|
|
118
|
+
await apiCoreStream.end()
|
|
119
|
+
}
|
|
120
|
+
return end
|
|
121
|
+
}
|
|
122
|
+
}
|
|
123
|
+
|
|
124
|
+
export type CustomHandler = (apiCore: ApiCore) => Promise<void>
|
|
125
|
+
export interface CustomSuccessResultOptions extends SuccessResultOptions<unknown> {
|
|
126
|
+
customHandler: CustomHandler
|
|
127
|
+
}
|
|
128
|
+
export class CustomSuccessResult extends SuccessResult<unknown> {
|
|
129
|
+
protected declare options: CustomSuccessResultOptions
|
|
130
|
+
|
|
131
|
+
constructor(options: CustomSuccessResultOptions) {
|
|
132
|
+
super(options)
|
|
133
|
+
this.logger.setDefaultName("CustomSuccessResult")
|
|
134
|
+
}
|
|
135
|
+
|
|
136
|
+
async handle(apiCore: ApiCore): Promise<void> {
|
|
137
|
+
this.logger.log(`send`)
|
|
138
|
+
await this.options.customHandler(apiCore)
|
|
139
|
+
this.logger.log(`end`)
|
|
140
|
+
}
|
|
141
|
+
}
|
|
142
|
+
|
|
143
|
+
// ======================
|
|
144
|
+
|
|
145
|
+
export interface JsonErrorResultOptions<Data> extends ErrorResultOptions<Data> {
|
|
146
|
+
data: Data
|
|
147
|
+
}
|
|
148
|
+
export class JsonErrorResult<Data> extends ErrorResult<Data> {
|
|
149
|
+
protected declare options: JsonErrorResultOptions<Data>
|
|
150
|
+
|
|
151
|
+
constructor(options: JsonErrorResultOptions<Data>) {
|
|
152
|
+
super(options)
|
|
153
|
+
this.logger.setDefaultName("JsonErrorResult")
|
|
154
|
+
}
|
|
155
|
+
|
|
156
|
+
async handle(apiCore: ApiCore): Promise<void> {
|
|
157
|
+
const { data } = this.options
|
|
158
|
+
|
|
159
|
+
this.logger.log(`send, ${JSON.stringify(data, null, 2)}`)
|
|
160
|
+
await apiCore.json(data)
|
|
161
|
+
this.logger.log(`end`)
|
|
162
|
+
}
|
|
163
|
+
}
|
|
164
|
+
|
|
165
|
+
export interface CommonErrorJsonData<Reason> {
|
|
166
|
+
reason: Reason
|
|
167
|
+
reasonDetail?: string | undefined
|
|
168
|
+
}
|
|
169
|
+
export interface CommonErrorJson<Reason> {
|
|
170
|
+
status: "error"
|
|
171
|
+
data: CommonErrorJsonData<Reason>
|
|
172
|
+
}
|
|
173
|
+
export interface CommonJsonErrorResultOptions<Reason>
|
|
174
|
+
extends Omit<JsonErrorResultOptions<CommonErrorJson<Reason>>, "data">,
|
|
175
|
+
CommonErrorJsonData<Reason> {
|
|
176
|
+
}
|
|
177
|
+
export class CommonJsonErrorResult<const Reason>
|
|
178
|
+
extends JsonErrorResult<CommonErrorJson<Reason>> {
|
|
179
|
+
protected declare options: JsonErrorResultOptions<CommonErrorJson<Reason>>
|
|
180
|
+
|
|
181
|
+
constructor(options: CommonJsonErrorResultOptions<Reason>) {
|
|
182
|
+
super({
|
|
183
|
+
...options,
|
|
184
|
+
data: {
|
|
185
|
+
status: "error",
|
|
186
|
+
data: {
|
|
187
|
+
reason: options.reason,
|
|
188
|
+
reasonDetail: options.reasonDetail,
|
|
189
|
+
},
|
|
190
|
+
},
|
|
191
|
+
})
|
|
192
|
+
this.logger.setDefaultName("CommonJsonErrorResult")
|
|
193
|
+
}
|
|
194
|
+
}
|
|
195
|
+
export const commonJsonErrorResult = <const Reason>(
|
|
196
|
+
options: CommonJsonErrorResultOptions<Reason>
|
|
197
|
+
): CommonJsonErrorResult<Reason> => {
|
|
198
|
+
return new CommonJsonErrorResult<Reason>(options)
|
|
199
|
+
}
|
|
200
|
+
|
|
201
|
+
export type CommonJsonErrorResultSchema<
|
|
202
|
+
DataSchema extends z.ZodObject<{
|
|
203
|
+
reason: z.ZodEnum<Readonly<Record<string, string>>>
|
|
204
|
+
reasonDetail?: z.ZodString | z.ZodNull | z.ZodUndefined
|
|
205
|
+
}>
|
|
206
|
+
> = z.ZodObject<{
|
|
207
|
+
status: z.ZodLiteral<"error">
|
|
208
|
+
data: z.ZodObject<DataSchema["shape"] & {
|
|
209
|
+
reasonDetail: z.ZodString | z.ZodNull | z.ZodUndefined
|
|
210
|
+
}>
|
|
211
|
+
}>
|
|
212
|
+
export type GetDataSchemaFromCommonJsonErrorResultSchema<Schema extends z.ZodType>
|
|
213
|
+
= Schema extends CommonJsonErrorResultSchema<infer DataSchema> ? DataSchema : never
|
|
214
|
+
export type GetDataFromCommonJsonErrorResultSchema<Schema extends z.ZodType>
|
|
215
|
+
= Schema extends CommonJsonErrorResultSchema<infer DataSchema> ? z.infer<DataSchema> : never
|
|
216
|
+
export type GetReasonFromCommonJsonErrorResultSchema<Schema extends z.ZodType>
|
|
217
|
+
= Schema extends CommonJsonErrorResultSchema<infer DataSchema>
|
|
218
|
+
? z.infer<DataSchema> extends { reason: infer Reason } ? Reason : never
|
|
219
|
+
: never
|
|
220
|
+
export const commonJsonErrorResultSchema = <
|
|
221
|
+
DataSchema extends z.ZodObject<{
|
|
222
|
+
reason: z.ZodEnum<Readonly<Record<string, string>>>
|
|
223
|
+
reasonDetail?: z.ZodString | z.ZodNull | z.ZodUndefined
|
|
224
|
+
}>
|
|
225
|
+
>(
|
|
226
|
+
dataSchema: DataSchema
|
|
227
|
+
): CommonJsonErrorResultSchema<DataSchema> => {
|
|
228
|
+
const newOutputErrorSchema = z.object({
|
|
229
|
+
status: z.literal("error"),
|
|
230
|
+
data: dataSchema.extend({
|
|
231
|
+
reasonDetail: z.string(),
|
|
232
|
+
}),
|
|
233
|
+
})
|
|
234
|
+
return newOutputErrorSchema
|
|
235
|
+
}
|
|
236
|
+
|
|
237
|
+
// ======================
|
|
238
|
+
|
|
239
|
+
export type ContextWithResultHandler<
|
|
240
|
+
Path extends string,
|
|
241
|
+
Method extends "get" | "post",
|
|
242
|
+
InputQuerySchema extends z.ZodType,
|
|
243
|
+
InputBodySchema extends z.ZodType,
|
|
244
|
+
OutputSuccessSchema extends z.ZodType,
|
|
245
|
+
OutputErrorSchema extends z.ZodType,
|
|
246
|
+
>
|
|
247
|
+
= ApiHandlerContext<Path, Method, InputQuerySchema, InputBodySchema, OutputSuccessSchema, OutputErrorSchema>
|
|
248
|
+
& {
|
|
249
|
+
commonJsonSuccessResult: (
|
|
250
|
+
options: CommonJsonSuccessResultOptions<GetDataFromCommonJsonSuccessResultSchema<OutputSuccessSchema>>
|
|
251
|
+
) => CommonJsonSuccessResult<GetDataFromCommonJsonSuccessResultSchema<OutputSuccessSchema>>
|
|
252
|
+
commonJsonErrorResult: (
|
|
253
|
+
options: CommonJsonErrorResultOptions<GetReasonFromCommonJsonErrorResultSchema<OutputErrorSchema>>
|
|
254
|
+
) => CommonJsonErrorResult<GetReasonFromCommonJsonErrorResultSchema<OutputErrorSchema>>
|
|
255
|
+
}
|
|
256
|
+
|
|
257
|
+
export const withResultHandler = <
|
|
258
|
+
Path extends string,
|
|
259
|
+
Method extends "get" | "post",
|
|
260
|
+
InputQuerySchema extends z.ZodType,
|
|
261
|
+
InputBodySchema extends z.ZodType,
|
|
262
|
+
OutputSuccessSchema extends z.ZodType,
|
|
263
|
+
OutputErrorSchema extends z.ZodType,
|
|
264
|
+
>(
|
|
265
|
+
context: ApiHandlerContext<Path, Method, InputQuerySchema, InputBodySchema, OutputSuccessSchema, OutputErrorSchema>,
|
|
266
|
+
): ContextWithResultHandler<Path, Method, InputQuerySchema, InputBodySchema, OutputSuccessSchema, OutputErrorSchema> => {
|
|
267
|
+
return {
|
|
268
|
+
...context,
|
|
269
|
+
commonJsonSuccessResult: (
|
|
270
|
+
options: CommonJsonSuccessResultOptions<GetDataFromCommonJsonSuccessResultSchema<OutputSuccessSchema>>,
|
|
271
|
+
) => {
|
|
272
|
+
return commonJsonSuccessResult({
|
|
273
|
+
logger: context.logger,
|
|
274
|
+
...options,
|
|
275
|
+
})
|
|
276
|
+
},
|
|
277
|
+
commonJsonErrorResult: (
|
|
278
|
+
options: CommonJsonErrorResultOptions<GetReasonFromCommonJsonErrorResultSchema<OutputErrorSchema>>,
|
|
279
|
+
) => {
|
|
280
|
+
return commonJsonErrorResult<GetReasonFromCommonJsonErrorResultSchema<OutputErrorSchema>>({
|
|
281
|
+
logger: context.logger,
|
|
282
|
+
...options,
|
|
283
|
+
})
|
|
284
|
+
},
|
|
285
|
+
}
|
|
286
|
+
}
|
|
@@ -0,0 +1,126 @@
|
|
|
1
|
+
import fs, { existsSync, mkdirSync, writeFileSync } from "node:fs"
|
|
2
|
+
import path from "node:path"
|
|
3
|
+
import ts from "typescript"
|
|
4
|
+
|
|
5
|
+
import { getGlobalLogger } from "#Source/log/index.ts"
|
|
6
|
+
|
|
7
|
+
export interface GenerateApiListOptions {
|
|
8
|
+
importFrom: string
|
|
9
|
+
/**
|
|
10
|
+
* Path to tsconfig.json file.
|
|
11
|
+
*/
|
|
12
|
+
tsconfigFilePath: string
|
|
13
|
+
/**
|
|
14
|
+
* Path to Api folder.
|
|
15
|
+
*/
|
|
16
|
+
apiFolderPath: string
|
|
17
|
+
/**
|
|
18
|
+
* Path to output file.
|
|
19
|
+
*/
|
|
20
|
+
outputFilePath: string
|
|
21
|
+
}
|
|
22
|
+
const toAbsolutePath = (options: GenerateApiListOptions): GenerateApiListOptions => {
|
|
23
|
+
const { tsconfigFilePath, apiFolderPath, outputFilePath } = options
|
|
24
|
+
const absoluteTsconfigFilePath = path.resolve(tsconfigFilePath)
|
|
25
|
+
const absoluteApiFolderPath = path.resolve(apiFolderPath)
|
|
26
|
+
const absoluteOutputFilePath = path.resolve(outputFilePath)
|
|
27
|
+
console.log("tsconfigFilePath:", absoluteTsconfigFilePath)
|
|
28
|
+
console.log("apiFolderPath:", absoluteApiFolderPath)
|
|
29
|
+
console.log("outputFilePath:", absoluteOutputFilePath)
|
|
30
|
+
return {
|
|
31
|
+
...options,
|
|
32
|
+
tsconfigFilePath: absoluteTsconfigFilePath,
|
|
33
|
+
apiFolderPath: absoluteApiFolderPath,
|
|
34
|
+
outputFilePath: absoluteOutputFilePath,
|
|
35
|
+
}
|
|
36
|
+
}
|
|
37
|
+
export const generateApiList = (options: GenerateApiListOptions): void => {
|
|
38
|
+
const {
|
|
39
|
+
importFrom,
|
|
40
|
+
tsconfigFilePath,
|
|
41
|
+
apiFolderPath,
|
|
42
|
+
outputFilePath,
|
|
43
|
+
} = toAbsolutePath(options)
|
|
44
|
+
const logger = getGlobalLogger()
|
|
45
|
+
|
|
46
|
+
// const _projectRootPath = path.dirname(tsconfigFilePath)
|
|
47
|
+
|
|
48
|
+
const tsconfigJson = ts.parseConfigFileTextToJson(tsconfigFilePath, fs.readFileSync(tsconfigFilePath, "utf8"))
|
|
49
|
+
if (tsconfigJson.error) {
|
|
50
|
+
throw new Error("无法解析 tsconfig.json")
|
|
51
|
+
}
|
|
52
|
+
const parsedTsconfig = ts.parseJsonConfigFileContent(tsconfigJson.config, ts.sys, path.resolve(tsconfigFilePath, ".."))
|
|
53
|
+
logger.debug("成功解析 tsconfig 文件...")
|
|
54
|
+
|
|
55
|
+
const projectHost = ts.createCompilerHost(parsedTsconfig.options)
|
|
56
|
+
const project = ts.createProgram(parsedTsconfig.fileNames, parsedTsconfig.options, projectHost)
|
|
57
|
+
logger.debug("成功读取项目...")
|
|
58
|
+
|
|
59
|
+
// 不可以删除, 否则会变得不幸
|
|
60
|
+
// NOTE: Gets a type checker that can be used to semantically analyze source files in the program.
|
|
61
|
+
// const _check = project.getTypeChecker()
|
|
62
|
+
|
|
63
|
+
const allSourceFiles = project.getSourceFiles()
|
|
64
|
+
const apiSourceFiles = allSourceFiles.filter((sourceFile) => {
|
|
65
|
+
// 我们约定接口实现必须名为 index.ts
|
|
66
|
+
// oxlint-disable-next-line no-useless-escape unicorn/prefer-string-raw
|
|
67
|
+
return new RegExp(`${apiFolderPath.replaceAll("\\", "\\\\")}.*index\.ts`).test(path.resolve(sourceFile.fileName))
|
|
68
|
+
})
|
|
69
|
+
|
|
70
|
+
logger.debug(`找到 ${apiSourceFiles.length} 个接口`)
|
|
71
|
+
|
|
72
|
+
const importArea: string[] = []
|
|
73
|
+
const codeArea: string[] = []
|
|
74
|
+
apiSourceFiles.forEach((apiSourceFile, index) => {
|
|
75
|
+
// For example:
|
|
76
|
+
// - apiFolderPath: C:\Users\xxx\Desktop\Codespace\web-core\test\test-project\src\interface
|
|
77
|
+
// - apiSourceFile.fileName: C:/Users/xxx/Desktop/Codespace/web-core/test/test-project/src/interface/add/index.ts
|
|
78
|
+
// - filenameRelativeToApiFolder: add/index.ts
|
|
79
|
+
// - filenameRelativeToApiFolder: ./add/index.ts --- sometimes
|
|
80
|
+
const filenameRelativeToApiFolder = path.relative(apiFolderPath, apiSourceFile.fileName).replaceAll("\\", "/")
|
|
81
|
+
// For example:
|
|
82
|
+
// - importName: add -- from add/index.ts
|
|
83
|
+
// - importName: user_get_user_info -- from user/get-user-info.ts
|
|
84
|
+
const importName = filenameRelativeToApiFolder.replaceAll("/", "_").replaceAll(".ts", "").replaceAll("./", "").replaceAll("-", "_")
|
|
85
|
+
// For example:
|
|
86
|
+
// - outputFilePath: C:\Users\xxx\Desktop\Codespace\web-core\test\test-project\interface\api-list.ts
|
|
87
|
+
// - outputFolderRelativeToApiFolder: ''
|
|
88
|
+
const outputFolderRelativeToApiFolder = path.relative(path.dirname(outputFilePath), apiFolderPath).replaceAll("\\", "/")
|
|
89
|
+
// For example:
|
|
90
|
+
// - importPath: ./add/index
|
|
91
|
+
const importPath = outputFolderRelativeToApiFolder === ""
|
|
92
|
+
? `./${filenameRelativeToApiFolder}`.replaceAll("\\", "/").replaceAll(".ts", "")
|
|
93
|
+
: path.join(outputFolderRelativeToApiFolder, filenameRelativeToApiFolder).replaceAll("\\", "/").replaceAll(".ts", "")
|
|
94
|
+
|
|
95
|
+
logger.info(`处理(${index + 1} / ${apiSourceFiles.length}):${filenameRelativeToApiFolder}`)
|
|
96
|
+
|
|
97
|
+
for (const node of apiSourceFile.statements) {
|
|
98
|
+
if (ts.isExportAssignment(node) && node.isExportEquals === undefined) {
|
|
99
|
+
const expression = node.expression
|
|
100
|
+
if (ts.isNewExpression(expression) && expression.expression.getText() === "Api") {
|
|
101
|
+
break
|
|
102
|
+
}
|
|
103
|
+
throw new Error(`${apiSourceFile.fileName}:不是 Api`)
|
|
104
|
+
}
|
|
105
|
+
}
|
|
106
|
+
|
|
107
|
+
importArea.push(`import ${importName} from '${importPath}'`)
|
|
108
|
+
codeArea.push(`${String(importName)}`)
|
|
109
|
+
})
|
|
110
|
+
|
|
111
|
+
const finalTestFile = [
|
|
112
|
+
`import type { AnyApi } from '${importFrom}'`,
|
|
113
|
+
"",
|
|
114
|
+
...importArea,
|
|
115
|
+
"",
|
|
116
|
+
`export const apiList: AnyApi[] = [\n${codeArea.map(a => ` ${String(a)}`).join(",\n")}\n]`,
|
|
117
|
+
"",
|
|
118
|
+
].join("\n")
|
|
119
|
+
|
|
120
|
+
const outDir = path.dirname(outputFilePath)
|
|
121
|
+
if (existsSync(outDir) === false) {
|
|
122
|
+
mkdirSync(outDir, { recursive: true })
|
|
123
|
+
}
|
|
124
|
+
|
|
125
|
+
writeFileSync(outputFilePath, finalTestFile)
|
|
126
|
+
}
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
export * from "./gen-api-list.ts"
|
|
@@ -0,0 +1,136 @@
|
|
|
1
|
+
import fs, { existsSync, mkdirSync, writeFileSync } from "node:fs"
|
|
2
|
+
import path from "node:path"
|
|
3
|
+
import ts from "typescript"
|
|
4
|
+
|
|
5
|
+
import { getGlobalLogger } from "#Source/log/index.ts"
|
|
6
|
+
|
|
7
|
+
export interface GenerateApiTestOptions {
|
|
8
|
+
importFrom: string
|
|
9
|
+
tsconfigFilePath: string
|
|
10
|
+
apiFolderPath: string
|
|
11
|
+
outputFilePath: string
|
|
12
|
+
apiFileFilter: string
|
|
13
|
+
}
|
|
14
|
+
const toAbsolutePath = (options: GenerateApiTestOptions): GenerateApiTestOptions => {
|
|
15
|
+
const { tsconfigFilePath, apiFolderPath, outputFilePath } = options
|
|
16
|
+
const absoluteTsconfigFilePath = path.resolve(tsconfigFilePath)
|
|
17
|
+
const absoluteApiFolderPath = path.resolve(apiFolderPath)
|
|
18
|
+
const absoluteOutputFilePath = path.resolve(outputFilePath)
|
|
19
|
+
console.log("tsconfigFilePath:", absoluteTsconfigFilePath)
|
|
20
|
+
console.log("apiFolderPath:", absoluteApiFolderPath)
|
|
21
|
+
console.log("outputFilePath:", absoluteOutputFilePath)
|
|
22
|
+
return {
|
|
23
|
+
...options,
|
|
24
|
+
tsconfigFilePath: absoluteTsconfigFilePath,
|
|
25
|
+
apiFolderPath: absoluteApiFolderPath,
|
|
26
|
+
outputFilePath: absoluteOutputFilePath,
|
|
27
|
+
}
|
|
28
|
+
}
|
|
29
|
+
export const generateApiText = (options: GenerateApiTestOptions): void => {
|
|
30
|
+
const {
|
|
31
|
+
importFrom,
|
|
32
|
+
tsconfigFilePath,
|
|
33
|
+
apiFolderPath,
|
|
34
|
+
outputFilePath,
|
|
35
|
+
apiFileFilter,
|
|
36
|
+
} = toAbsolutePath(options)
|
|
37
|
+
const logger = getGlobalLogger()
|
|
38
|
+
|
|
39
|
+
const projectRootPath = path.dirname(tsconfigFilePath)
|
|
40
|
+
|
|
41
|
+
const tsconfigJson = ts.parseConfigFileTextToJson(tsconfigFilePath, fs.readFileSync(tsconfigFilePath, "utf8"))
|
|
42
|
+
if (tsconfigJson.error) {
|
|
43
|
+
throw new Error("无法解析 tsconfig.json")
|
|
44
|
+
}
|
|
45
|
+
const parsedTsconfig = ts.parseJsonConfigFileContent(tsconfigJson.config, ts.sys, path.resolve(tsconfigFilePath, ".."))
|
|
46
|
+
logger.debug("成功解析 tsconfig 文件...")
|
|
47
|
+
|
|
48
|
+
const projectHost = ts.createCompilerHost(parsedTsconfig.options)
|
|
49
|
+
const project = ts.createProgram(parsedTsconfig.fileNames, parsedTsconfig.options, projectHost)
|
|
50
|
+
logger.debug("成功读取项目...")
|
|
51
|
+
|
|
52
|
+
// 不可以删除, 否则会变得不幸
|
|
53
|
+
// NOTE: Gets a type checker that can be used to semantically analyze source files in the program.
|
|
54
|
+
// const _check = project.getTypeChecker()
|
|
55
|
+
|
|
56
|
+
const allSourceFiles = project.getSourceFiles()
|
|
57
|
+
const typeSourceFiles = allSourceFiles.filter((sourceFile) => {
|
|
58
|
+
// 我们约定接口蓝图必须名为 type.ts
|
|
59
|
+
// oxlint-disable-next-line no-useless-escape unicorn/prefer-string-raw
|
|
60
|
+
return new RegExp(`${apiFolderPath.replaceAll("\\", "\\\\")}.*type\.ts`).test(path.resolve(sourceFile.fileName))
|
|
61
|
+
})
|
|
62
|
+
const testSourceFiles = allSourceFiles.filter((sourceFile) => {
|
|
63
|
+
// oxlint-disable-next-line no-useless-escape unicorn/prefer-string-raw
|
|
64
|
+
return new RegExp(`${apiFolderPath.replaceAll("\\", "\\\\")}.*\.test\.ts`).test(path.resolve(sourceFile.fileName))
|
|
65
|
+
})
|
|
66
|
+
|
|
67
|
+
const testSourceFilesFilter = testSourceFiles.filter((sourceFile) => {
|
|
68
|
+
return new RegExp(apiFileFilter).test(path.resolve(sourceFile.fileName))
|
|
69
|
+
})
|
|
70
|
+
// TODO: 这里可以明确打印出来谁有测试,谁没有测试。
|
|
71
|
+
logger.debug(`找到 ${typeSourceFiles.length} 个接口,其中有 ${testSourceFiles.length} 个测试,筛选后还剩 ${testSourceFilesFilter.length} 个...`)
|
|
72
|
+
|
|
73
|
+
const importCode: string[] = []
|
|
74
|
+
const testCode: string[] = []
|
|
75
|
+
testSourceFilesFilter.forEach((testSourceFile, index) => {
|
|
76
|
+
// For example:
|
|
77
|
+
// - apiFolderPath: C:\Users\xxx\Desktop\Codespace\web-core\test\test-project\src\interface
|
|
78
|
+
// - testSourceFile.fileName: C:/Users/xxx/Desktop/Codespace/web-core/test/test-project/src/interface/add/t01.test.ts
|
|
79
|
+
// - filenameRelativeToApiFolder: add/t01.test.ts
|
|
80
|
+
// - filenameRelativeToApiFolder: ./add/t01.test.ts --- sometimes
|
|
81
|
+
const filenameRelativeToApiFolder = path.relative(apiFolderPath, testSourceFile.fileName).replaceAll("\\", "/")
|
|
82
|
+
// For example:
|
|
83
|
+
// - importName: add_t01 -- from add/t01.test.ts
|
|
84
|
+
// - importName: get_user_info -- from get-user-info.test.ts
|
|
85
|
+
const importName = filenameRelativeToApiFolder.replaceAll("/", "_").replaceAll(".test.ts", "").replaceAll("./", "").replaceAll("-", "_")
|
|
86
|
+
// For example:
|
|
87
|
+
// - projectRootPath: C:\Users\xxx\Desktop\Codespace\web-core\test\test-project
|
|
88
|
+
// - filenameRelativeToProjectRoot: src/interface/add/t01.test
|
|
89
|
+
const filenameRelativeToProjectRoot = path.relative(projectRootPath, testSourceFile.fileName).replaceAll("\\", "/").replaceAll(".ts", "")
|
|
90
|
+
// For example:
|
|
91
|
+
// - outputPath: C:\Users\xxx\Desktop\Codespace\web-core\test\test-project\test\test.ts
|
|
92
|
+
// - outputFolderRelativeToProjectRoot: ../
|
|
93
|
+
const outputFolderRelativeToProjectRoot = path.relative(path.dirname(outputFilePath), projectRootPath).replaceAll("\\", "/")
|
|
94
|
+
// For example:
|
|
95
|
+
// - importPath: ../src/interface/add/t01.test
|
|
96
|
+
const importPath = path.join(outputFolderRelativeToProjectRoot, filenameRelativeToProjectRoot).replaceAll("\\", "/")
|
|
97
|
+
|
|
98
|
+
logger.info(`处理(${index + 1} / ${testSourceFilesFilter.length}):${filenameRelativeToApiFolder}`)
|
|
99
|
+
|
|
100
|
+
for (const node of testSourceFile.statements) {
|
|
101
|
+
if (ts.isExportAssignment(node) && node.isExportEquals === undefined) {
|
|
102
|
+
const expression = node.expression
|
|
103
|
+
if (ts.isNewExpression(expression) && expression.expression.getText() === "ApiTestSchema") {
|
|
104
|
+
break
|
|
105
|
+
}
|
|
106
|
+
throw new Error(`${testSourceFile.fileName}:不是 ApiTestSchema`)
|
|
107
|
+
}
|
|
108
|
+
}
|
|
109
|
+
|
|
110
|
+
importCode.push(`import ${importName} from '${importPath}'`)
|
|
111
|
+
testCode.push(generateTestCode(importName, importName))
|
|
112
|
+
})
|
|
113
|
+
|
|
114
|
+
const finalTestFile = [
|
|
115
|
+
"import { test } from 'vitest'",
|
|
116
|
+
`import { testApi } from '${importFrom}'`,
|
|
117
|
+
"",
|
|
118
|
+
"import './unit-test-prefix'",
|
|
119
|
+
"",
|
|
120
|
+
...importCode,
|
|
121
|
+
"",
|
|
122
|
+
...testCode,
|
|
123
|
+
"",
|
|
124
|
+
].join("\n")
|
|
125
|
+
|
|
126
|
+
const outDir = path.dirname(outputFilePath)
|
|
127
|
+
if (existsSync(outDir) === false) {
|
|
128
|
+
mkdirSync(outDir, { recursive: true })
|
|
129
|
+
}
|
|
130
|
+
|
|
131
|
+
writeFileSync(outputFilePath, finalTestFile)
|
|
132
|
+
}
|
|
133
|
+
|
|
134
|
+
const generateTestCode = (testCaseName: string, importName: string): string => {
|
|
135
|
+
return `test('${testCaseName}', async () => await testApi({ apiTest: ${importName} }))`
|
|
136
|
+
}
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
export * from "./gen-api-test.ts"
|
|
@@ -0,0 +1,25 @@
|
|
|
1
|
+
export interface GetCalcCodeOptions {
|
|
2
|
+
importFrom: string
|
|
3
|
+
}
|
|
4
|
+
export const getCalcCode = (options: GetCalcCodeOptions): string => {
|
|
5
|
+
const { importFrom } = options
|
|
6
|
+
return `
|
|
7
|
+
import type { StandardSchemaV1 } from "@standard-schema/spec"
|
|
8
|
+
import type { ApiSchema } from "${importFrom}"
|
|
9
|
+
|
|
10
|
+
import exportedApiSchema from "./type"
|
|
11
|
+
|
|
12
|
+
type Api = (typeof exportedApiSchema) extends ApiSchema<infer Path, infer Method, infer InputQuerySchema, infer InputBodySchema, infer OutputSuccessSchema, infer OutputErrorSchema>
|
|
13
|
+
? {
|
|
14
|
+
path: Path,
|
|
15
|
+
method: Method,
|
|
16
|
+
inputQuery: StandardSchemaV1.InferOutput<InputQuerySchema>,
|
|
17
|
+
inputBody: StandardSchemaV1.InferOutput<InputBodySchema>,
|
|
18
|
+
outputSuccess: StandardSchemaV1.InferOutput<OutputSuccessSchema>,
|
|
19
|
+
outputError: StandardSchemaV1.InferOutput<OutputErrorSchema>,
|
|
20
|
+
}
|
|
21
|
+
: never
|
|
22
|
+
|
|
23
|
+
export default Api
|
|
24
|
+
`
|
|
25
|
+
}
|