spiceflow 0.0.6 → 1.0.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/README.md +1 -171
- package/dist/client/errors.d.ts +7 -0
- package/dist/client/errors.d.ts.map +1 -0
- package/dist/client/errors.js +18 -0
- package/dist/client/errors.js.map +1 -0
- package/dist/client/index.d.ts +14 -0
- package/dist/client/index.d.ts.map +1 -0
- package/dist/client/index.js +376 -0
- package/dist/client/index.js.map +1 -0
- package/dist/client/types.d.ts +87 -0
- package/dist/client/types.d.ts.map +1 -0
- package/dist/client/types.js +2 -0
- package/dist/client/types.js.map +1 -0
- package/dist/client/utils.d.ts +2 -0
- package/dist/client/utils.d.ts.map +1 -0
- package/dist/client/utils.js +9 -0
- package/dist/client/utils.js.map +1 -0
- package/dist/client/ws.d.ts +15 -0
- package/dist/client/ws.d.ts.map +1 -0
- package/dist/client/ws.js +51 -0
- package/dist/client/ws.js.map +1 -0
- package/dist/client.test.d.ts +2 -0
- package/dist/client.test.d.ts.map +1 -0
- package/dist/client.test.js +237 -0
- package/dist/client.test.js.map +1 -0
- package/dist/elysia-fork/context.d.ts +87 -0
- package/dist/elysia-fork/context.d.ts.map +1 -0
- package/dist/elysia-fork/context.js +2 -0
- package/dist/elysia-fork/context.js.map +1 -0
- package/dist/elysia-fork/error.d.ts +246 -0
- package/dist/elysia-fork/error.d.ts.map +1 -0
- package/dist/elysia-fork/error.js +195 -0
- package/dist/elysia-fork/error.js.map +1 -0
- package/dist/elysia-fork/types.d.ts +652 -0
- package/dist/elysia-fork/types.d.ts.map +1 -0
- package/dist/elysia-fork/types.js +3 -0
- package/dist/elysia-fork/types.js.map +1 -0
- package/dist/elysia-fork/utils.d.ts +134 -0
- package/dist/elysia-fork/utils.d.ts.map +1 -0
- package/dist/elysia-fork/utils.js +70 -0
- package/dist/elysia-fork/utils.js.map +1 -0
- package/dist/spiceflow.d.ts +253 -0
- package/dist/spiceflow.d.ts.map +1 -0
- package/dist/spiceflow.js +500 -0
- package/dist/spiceflow.js.map +1 -0
- package/dist/spiceflow.test.d.ts +2 -0
- package/dist/spiceflow.test.d.ts.map +1 -0
- package/dist/spiceflow.test.js +225 -0
- package/dist/spiceflow.test.js.map +1 -0
- package/dist/stream.test.d.ts +2 -0
- package/dist/stream.test.d.ts.map +1 -0
- package/dist/stream.test.js +286 -0
- package/dist/stream.test.js.map +1 -0
- package/dist/types.d.ts +1 -0
- package/dist/types.d.ts.map +1 -0
- package/dist/types.js +2 -0
- package/dist/types.js.map +1 -0
- package/dist/utils.d.ts +4 -20
- package/dist/utils.d.ts.map +1 -1
- package/dist/utils.js +17 -46
- package/dist/utils.js.map +1 -1
- package/package.json +12 -36
- package/src/client/errors.ts +21 -0
- package/src/client/index.ts +539 -0
- package/src/client/types.ts +233 -0
- package/src/client/utils.ts +7 -0
- package/src/client/ws.ts +99 -0
- package/src/client.test.ts +235 -0
- package/src/elysia-fork/context.ts +196 -0
- package/src/elysia-fork/error.ts +293 -0
- package/src/elysia-fork/types.ts +1454 -0
- package/src/elysia-fork/utils.ts +85 -0
- package/src/spiceflow.test.ts +290 -0
- package/src/spiceflow.ts +1266 -0
- package/src/stream.test.ts +342 -0
- package/src/types.ts +0 -0
- package/src/utils.ts +21 -70
- package/context.d.ts +0 -2
- package/context.js +0 -1
- package/dist/babel.test.d.ts +0 -2
- package/dist/babel.test.d.ts.map +0 -1
- package/dist/babel.test.js +0 -27
- package/dist/babel.test.js.map +0 -1
- package/dist/babelDebugOutputs.d.ts +0 -9
- package/dist/babelDebugOutputs.d.ts.map +0 -1
- package/dist/babelDebugOutputs.js +0 -34
- package/dist/babelDebugOutputs.js.map +0 -1
- package/dist/babelTransformRpc.d.ts +0 -19
- package/dist/babelTransformRpc.d.ts.map +0 -1
- package/dist/babelTransformRpc.js +0 -285
- package/dist/babelTransformRpc.js.map +0 -1
- package/dist/browser.d.ts +0 -8
- package/dist/browser.d.ts.map +0 -1
- package/dist/browser.js +0 -126
- package/dist/browser.js.map +0 -1
- package/dist/build.d.ts +0 -13
- package/dist/build.d.ts.map +0 -1
- package/dist/build.js +0 -230
- package/dist/build.js.map +0 -1
- package/dist/cli.d.ts +0 -3
- package/dist/cli.d.ts.map +0 -1
- package/dist/cli.js +0 -111
- package/dist/cli.js.map +0 -1
- package/dist/context-internal.d.ts +0 -20
- package/dist/context-internal.d.ts.map +0 -1
- package/dist/context-internal.js +0 -16
- package/dist/context-internal.js.map +0 -1
- package/dist/context.d.ts +0 -2
- package/dist/context.d.ts.map +0 -1
- package/dist/context.js +0 -2
- package/dist/context.js.map +0 -1
- package/dist/expose.d.ts +0 -6
- package/dist/expose.d.ts.map +0 -1
- package/dist/expose.js +0 -32
- package/dist/expose.js.map +0 -1
- package/dist/headers.d.ts +0 -2
- package/dist/headers.d.ts.map +0 -1
- package/dist/headers.js +0 -18
- package/dist/headers.js.map +0 -1
- package/dist/index.d.ts +0 -8
- package/dist/index.d.ts.map +0 -1
- package/dist/index.js +0 -23
- package/dist/index.js.map +0 -1
- package/dist/jsonRpc.d.ts +0 -32
- package/dist/jsonRpc.d.ts.map +0 -1
- package/dist/jsonRpc.js +0 -3
- package/dist/jsonRpc.js.map +0 -1
- package/dist/server.d.ts +0 -32
- package/dist/server.d.ts.map +0 -1
- package/dist/server.js +0 -292
- package/dist/server.js.map +0 -1
- package/headers.d.ts +0 -2
- package/headers.js +0 -1
- package/sdk-template/package.json +0 -22
- package/sdk-template/src/index.ts +0 -2
- package/sdk-template/src/v1/example.ts +0 -5
- package/sdk-template/src/v1/generator.ts +0 -12
- package/sdk-template/tsconfig.json +0 -16
- package/src/babel.test.ts +0 -35
- package/src/babelDebugOutputs.ts +0 -56
- package/src/babelTransformRpc.ts +0 -394
- package/src/browser.ts +0 -141
- package/src/build.ts +0 -298
- package/src/cli.ts +0 -132
- package/src/context-internal.ts +0 -36
- package/src/context.ts +0 -5
- package/src/expose.ts +0 -34
- package/src/headers.ts +0 -19
- package/src/index.ts +0 -34
- package/src/jsonRpc.ts +0 -43
- package/src/server.ts +0 -384
|
@@ -0,0 +1,196 @@
|
|
|
1
|
+
import type {
|
|
2
|
+
StatusMap,
|
|
3
|
+
InvertedStatusMap,
|
|
4
|
+
redirect as Redirect
|
|
5
|
+
} from './utils.js'
|
|
6
|
+
|
|
7
|
+
import type {
|
|
8
|
+
RouteSchema,
|
|
9
|
+
Prettify,
|
|
10
|
+
ResolvePath,
|
|
11
|
+
SingletonBase,
|
|
12
|
+
HTTPHeaders
|
|
13
|
+
} from './types.js'
|
|
14
|
+
import { error } from './error.js'
|
|
15
|
+
|
|
16
|
+
type InvertedStatusMapKey = keyof InvertedStatusMap
|
|
17
|
+
|
|
18
|
+
// type WithoutNullableKeys<Type> = {
|
|
19
|
+
// [Key in keyof Type]-?: NonNullable<Type[Key]>
|
|
20
|
+
// }
|
|
21
|
+
|
|
22
|
+
export type ErrorContext<
|
|
23
|
+
in out Route extends RouteSchema = {},
|
|
24
|
+
in out Singleton extends SingletonBase = {
|
|
25
|
+
decorator: {}
|
|
26
|
+
store: {}
|
|
27
|
+
derive: {}
|
|
28
|
+
resolve: {}
|
|
29
|
+
},
|
|
30
|
+
Path extends string = ''
|
|
31
|
+
> = Prettify<
|
|
32
|
+
{
|
|
33
|
+
body: Route['body']
|
|
34
|
+
query: undefined extends Route['query']
|
|
35
|
+
? Record<string, string | undefined>
|
|
36
|
+
: Route['query']
|
|
37
|
+
params: undefined extends Route['params']
|
|
38
|
+
? Path extends `${string}/${':' | '*'}${string}`
|
|
39
|
+
? ResolvePath<Path>
|
|
40
|
+
: { [key in string]: string }
|
|
41
|
+
: Route['params']
|
|
42
|
+
|
|
43
|
+
// server: Server | null
|
|
44
|
+
redirect: Redirect
|
|
45
|
+
|
|
46
|
+
/**
|
|
47
|
+
* Path extracted from incoming URL
|
|
48
|
+
*
|
|
49
|
+
* Represent a value extracted from URL
|
|
50
|
+
*
|
|
51
|
+
* @example '/id/9'
|
|
52
|
+
*/
|
|
53
|
+
path: string
|
|
54
|
+
/**
|
|
55
|
+
* Path as registered to router
|
|
56
|
+
*
|
|
57
|
+
* Represent a path registered to a router, not a URL
|
|
58
|
+
*
|
|
59
|
+
* @example '/id/:id'
|
|
60
|
+
*/
|
|
61
|
+
route: string
|
|
62
|
+
request: Request
|
|
63
|
+
store: Singleton['store']
|
|
64
|
+
response: Route['response']
|
|
65
|
+
} & Singleton['decorator'] &
|
|
66
|
+
Singleton['derive'] &
|
|
67
|
+
Singleton['resolve']
|
|
68
|
+
>
|
|
69
|
+
|
|
70
|
+
export type Context<
|
|
71
|
+
in out Route extends RouteSchema = {},
|
|
72
|
+
in out Singleton extends SingletonBase = {
|
|
73
|
+
decorator: {}
|
|
74
|
+
store: {}
|
|
75
|
+
derive: {}
|
|
76
|
+
resolve: {}
|
|
77
|
+
},
|
|
78
|
+
Path extends string = ''
|
|
79
|
+
> = Prettify<
|
|
80
|
+
{
|
|
81
|
+
body: Route['body']
|
|
82
|
+
|
|
83
|
+
params: undefined extends Route['params']
|
|
84
|
+
? Path extends `${string}/${':' | '*'}${string}`
|
|
85
|
+
? ResolvePath<Path>
|
|
86
|
+
: never
|
|
87
|
+
: Route['params']
|
|
88
|
+
|
|
89
|
+
// server: Server | null
|
|
90
|
+
redirect: Redirect
|
|
91
|
+
|
|
92
|
+
// set: {
|
|
93
|
+
// headers: HTTPHeaders
|
|
94
|
+
// status?: number | keyof StatusMap
|
|
95
|
+
// /**
|
|
96
|
+
// * @deprecated Use inline redirect instead
|
|
97
|
+
// *
|
|
98
|
+
// * Will be removed in 1.2.0
|
|
99
|
+
// *
|
|
100
|
+
// * @example Migration example
|
|
101
|
+
// * ```ts
|
|
102
|
+
// * new Elysia()
|
|
103
|
+
// * .get(({ redirect }) => redirect('/'))
|
|
104
|
+
// * ```
|
|
105
|
+
// */
|
|
106
|
+
// redirect?: string
|
|
107
|
+
// /**
|
|
108
|
+
// * ! Internal Property
|
|
109
|
+
// *
|
|
110
|
+
// * Use `Context.cookie` instead
|
|
111
|
+
// */
|
|
112
|
+
// cookie?: Record<string, ElysiaCookie>
|
|
113
|
+
// }
|
|
114
|
+
|
|
115
|
+
/**
|
|
116
|
+
* Path extracted from incoming URL
|
|
117
|
+
*
|
|
118
|
+
* Represent a value extracted from URL
|
|
119
|
+
*
|
|
120
|
+
* @example '/id/9'
|
|
121
|
+
*/
|
|
122
|
+
path: string
|
|
123
|
+
/**
|
|
124
|
+
* Path as registered to router
|
|
125
|
+
*
|
|
126
|
+
* Represent a path registered to a router, not a URL
|
|
127
|
+
*
|
|
128
|
+
* @example '/id/:id'
|
|
129
|
+
*/
|
|
130
|
+
route: string
|
|
131
|
+
request: Request
|
|
132
|
+
store: Singleton['store']
|
|
133
|
+
response?: Route['response']
|
|
134
|
+
} & ({} extends Route['response']
|
|
135
|
+
? {
|
|
136
|
+
error: typeof error
|
|
137
|
+
}
|
|
138
|
+
: {
|
|
139
|
+
error: <
|
|
140
|
+
const Code extends
|
|
141
|
+
| keyof Route['response']
|
|
142
|
+
| InvertedStatusMap[Extract<
|
|
143
|
+
InvertedStatusMapKey,
|
|
144
|
+
keyof Route['response']
|
|
145
|
+
>],
|
|
146
|
+
const T extends Code extends keyof Route['response']
|
|
147
|
+
? Route['response'][Code]
|
|
148
|
+
: Code extends keyof StatusMap
|
|
149
|
+
? // @ts-ignore StatusMap[Code] always valid because Code generic check
|
|
150
|
+
Route['response'][StatusMap[Code]]
|
|
151
|
+
: never
|
|
152
|
+
>(
|
|
153
|
+
code: Code,
|
|
154
|
+
response: T
|
|
155
|
+
) => {
|
|
156
|
+
// [ELYSIA_RESPONSE]: Code extends keyof StatusMap
|
|
157
|
+
// ? StatusMap[Code]
|
|
158
|
+
// : Code
|
|
159
|
+
response: T
|
|
160
|
+
_type: {
|
|
161
|
+
[ERROR_CODE in Code extends keyof StatusMap
|
|
162
|
+
? StatusMap[Code]
|
|
163
|
+
: Code]: T
|
|
164
|
+
}
|
|
165
|
+
}
|
|
166
|
+
}) &
|
|
167
|
+
Singleton['decorator'] &
|
|
168
|
+
Singleton['derive'] &
|
|
169
|
+
Singleton['resolve']
|
|
170
|
+
>
|
|
171
|
+
|
|
172
|
+
// Use to mimic request before mapping route
|
|
173
|
+
export type PreContext<
|
|
174
|
+
in out Singleton extends SingletonBase = {
|
|
175
|
+
decorator: {}
|
|
176
|
+
store: {}
|
|
177
|
+
derive: {}
|
|
178
|
+
resolve: {}
|
|
179
|
+
}
|
|
180
|
+
> = Prettify<
|
|
181
|
+
{
|
|
182
|
+
store: Singleton['store']
|
|
183
|
+
request: Request
|
|
184
|
+
|
|
185
|
+
redirect: Redirect
|
|
186
|
+
// server: Server | null
|
|
187
|
+
|
|
188
|
+
// set: {
|
|
189
|
+
// headers: HTTPHeaders
|
|
190
|
+
// status?: number
|
|
191
|
+
// redirect?: string
|
|
192
|
+
// }
|
|
193
|
+
|
|
194
|
+
error: typeof error
|
|
195
|
+
} & Singleton['decorator']
|
|
196
|
+
>
|
|
@@ -0,0 +1,293 @@
|
|
|
1
|
+
import type { TSchema } from '@sinclair/typebox'
|
|
2
|
+
import { Value } from '@sinclair/typebox/value'
|
|
3
|
+
import type { TypeCheck, ValueError } from '@sinclair/typebox/compiler'
|
|
4
|
+
|
|
5
|
+
import { StatusMap, InvertedStatusMap } from './utils'
|
|
6
|
+
|
|
7
|
+
// ? Cloudflare worker support
|
|
8
|
+
const env =
|
|
9
|
+
// @ts-ignore
|
|
10
|
+
typeof Bun !== 'undefined'
|
|
11
|
+
? // @ts-ignore
|
|
12
|
+
Bun.env
|
|
13
|
+
: typeof process !== 'undefined'
|
|
14
|
+
? process?.env
|
|
15
|
+
: undefined
|
|
16
|
+
|
|
17
|
+
export const ERROR_CODE = Symbol('ElysiaErrorCode')
|
|
18
|
+
export type ERROR_CODE = typeof ERROR_CODE
|
|
19
|
+
|
|
20
|
+
export const ELYSIA_RESPONSE = Symbol('ElysiaResponse')
|
|
21
|
+
export type ELYSIA_RESPONSE = typeof ELYSIA_RESPONSE
|
|
22
|
+
|
|
23
|
+
export const isProduction = (env?.NODE_ENV ?? env?.ENV) === 'production'
|
|
24
|
+
|
|
25
|
+
export type ElysiaErrors =
|
|
26
|
+
| InternalServerError
|
|
27
|
+
| NotFoundError
|
|
28
|
+
| ParseError
|
|
29
|
+
| ValidationError
|
|
30
|
+
| InvalidCookieSignature
|
|
31
|
+
|
|
32
|
+
export const error = <
|
|
33
|
+
const Code extends number | keyof StatusMap,
|
|
34
|
+
const T = Code extends keyof InvertedStatusMap
|
|
35
|
+
? InvertedStatusMap[Code]
|
|
36
|
+
: Code,
|
|
37
|
+
const Status extends Code extends keyof StatusMap
|
|
38
|
+
? StatusMap[Code]
|
|
39
|
+
: Code = Code extends keyof StatusMap ? StatusMap[Code] : Code
|
|
40
|
+
>(
|
|
41
|
+
code: Code,
|
|
42
|
+
response?: T
|
|
43
|
+
): {
|
|
44
|
+
[ELYSIA_RESPONSE]: Status
|
|
45
|
+
response: T
|
|
46
|
+
_type: {
|
|
47
|
+
[ERROR_CODE in Status]: T
|
|
48
|
+
}
|
|
49
|
+
error: Error
|
|
50
|
+
} => {
|
|
51
|
+
const res =
|
|
52
|
+
response ??
|
|
53
|
+
(code in InvertedStatusMap
|
|
54
|
+
? // @ts-expect-error Always correct
|
|
55
|
+
InvertedStatusMap[code]
|
|
56
|
+
: code)
|
|
57
|
+
|
|
58
|
+
return {
|
|
59
|
+
// @ts-expect-error trust me bro
|
|
60
|
+
[ELYSIA_RESPONSE]: StatusMap[code] ?? code,
|
|
61
|
+
response: res,
|
|
62
|
+
_type: undefined as any,
|
|
63
|
+
error: new Error(res)
|
|
64
|
+
} as const
|
|
65
|
+
}
|
|
66
|
+
|
|
67
|
+
export class InternalServerError extends Error {
|
|
68
|
+
code = 'INTERNAL_SERVER_ERROR'
|
|
69
|
+
status = 500
|
|
70
|
+
|
|
71
|
+
constructor(message?: string) {
|
|
72
|
+
super(message ?? 'INTERNAL_SERVER_ERROR')
|
|
73
|
+
}
|
|
74
|
+
}
|
|
75
|
+
|
|
76
|
+
export class NotFoundError extends Error {
|
|
77
|
+
code = 'NOT_FOUND'
|
|
78
|
+
status = 404
|
|
79
|
+
|
|
80
|
+
constructor(message?: string) {
|
|
81
|
+
super(message ?? 'NOT_FOUND')
|
|
82
|
+
}
|
|
83
|
+
}
|
|
84
|
+
|
|
85
|
+
export class ParseError extends Error {
|
|
86
|
+
code = 'PARSE'
|
|
87
|
+
status = 400
|
|
88
|
+
|
|
89
|
+
constructor() {
|
|
90
|
+
super('Failed to parse body')
|
|
91
|
+
}
|
|
92
|
+
}
|
|
93
|
+
|
|
94
|
+
export class InvalidCookieSignature extends Error {
|
|
95
|
+
code = 'INVALID_COOKIE_SIGNATURE'
|
|
96
|
+
status = 400
|
|
97
|
+
|
|
98
|
+
constructor(public key: string, message?: string) {
|
|
99
|
+
super(message ?? `"${key}" has invalid cookie signature`)
|
|
100
|
+
}
|
|
101
|
+
}
|
|
102
|
+
|
|
103
|
+
export const mapValueError = (error: ValueError) => {
|
|
104
|
+
const { message, path, value, type } = error
|
|
105
|
+
|
|
106
|
+
const property = path.slice(1).replaceAll('/', '.')
|
|
107
|
+
const isRoot = path === ''
|
|
108
|
+
|
|
109
|
+
switch (type) {
|
|
110
|
+
case 42:
|
|
111
|
+
return {
|
|
112
|
+
...error,
|
|
113
|
+
summary: isRoot
|
|
114
|
+
? `Value should not be provided`
|
|
115
|
+
: `Property '${property}' should not be provided`
|
|
116
|
+
}
|
|
117
|
+
|
|
118
|
+
case 45:
|
|
119
|
+
return {
|
|
120
|
+
...error,
|
|
121
|
+
summary: isRoot
|
|
122
|
+
? `Value is missing`
|
|
123
|
+
: `Property '${property}' is missing`
|
|
124
|
+
}
|
|
125
|
+
|
|
126
|
+
case 50:
|
|
127
|
+
// Expected string to match 'email' format
|
|
128
|
+
const quoteIndex = message.indexOf("'")!
|
|
129
|
+
const format = message.slice(
|
|
130
|
+
quoteIndex + 1,
|
|
131
|
+
message.indexOf("'", quoteIndex + 1)
|
|
132
|
+
)
|
|
133
|
+
|
|
134
|
+
return {
|
|
135
|
+
...error,
|
|
136
|
+
summary: isRoot
|
|
137
|
+
? `Value should be an email`
|
|
138
|
+
: `Property '${property}' should be ${format}`
|
|
139
|
+
}
|
|
140
|
+
|
|
141
|
+
case 54:
|
|
142
|
+
return {
|
|
143
|
+
...error,
|
|
144
|
+
summary: `${message.slice(
|
|
145
|
+
0,
|
|
146
|
+
9
|
|
147
|
+
)} property '${property}' to be ${message.slice(
|
|
148
|
+
8
|
|
149
|
+
)} but found: ${value}`
|
|
150
|
+
}
|
|
151
|
+
|
|
152
|
+
case 62:
|
|
153
|
+
const union = error.schema.anyOf
|
|
154
|
+
.map((x: Record<string, unknown>) => `'${x?.format ?? x.type}'`)
|
|
155
|
+
.join(', ')
|
|
156
|
+
|
|
157
|
+
return {
|
|
158
|
+
...error,
|
|
159
|
+
summary: isRoot
|
|
160
|
+
? `Value should be one of ${union}`
|
|
161
|
+
: `Property '${property}' should be one of: ${union}`
|
|
162
|
+
}
|
|
163
|
+
|
|
164
|
+
default:
|
|
165
|
+
return { summary: message, ...error }
|
|
166
|
+
}
|
|
167
|
+
}
|
|
168
|
+
|
|
169
|
+
export class ValidationError extends Error {
|
|
170
|
+
code = 'VALIDATION'
|
|
171
|
+
status = 422
|
|
172
|
+
|
|
173
|
+
constructor(
|
|
174
|
+
public type: string,
|
|
175
|
+
public validator: TSchema | TypeCheck<any>,
|
|
176
|
+
public value: unknown
|
|
177
|
+
) {
|
|
178
|
+
if (value && typeof value === 'object' && ELYSIA_RESPONSE in value)
|
|
179
|
+
// @ts-expect-error
|
|
180
|
+
value = value.response
|
|
181
|
+
|
|
182
|
+
const error = isProduction
|
|
183
|
+
? undefined
|
|
184
|
+
: 'Errors' in validator
|
|
185
|
+
? validator.Errors(value).First()
|
|
186
|
+
: Value.Errors(validator, value).First()
|
|
187
|
+
|
|
188
|
+
const customError =
|
|
189
|
+
error?.schema.error !== undefined
|
|
190
|
+
? typeof error.schema.error === 'function'
|
|
191
|
+
? error.schema.error({
|
|
192
|
+
type,
|
|
193
|
+
validator,
|
|
194
|
+
value,
|
|
195
|
+
get errors() {
|
|
196
|
+
return [...validator.Errors(value)].map(
|
|
197
|
+
mapValueError
|
|
198
|
+
)
|
|
199
|
+
}
|
|
200
|
+
})
|
|
201
|
+
: error.schema.error
|
|
202
|
+
: undefined
|
|
203
|
+
|
|
204
|
+
const accessor = error?.path || 'root'
|
|
205
|
+
let message = ''
|
|
206
|
+
|
|
207
|
+
if (customError !== undefined) {
|
|
208
|
+
message =
|
|
209
|
+
typeof customError === 'object'
|
|
210
|
+
? JSON.stringify(customError)
|
|
211
|
+
: customError + ''
|
|
212
|
+
} else if (isProduction) {
|
|
213
|
+
message = JSON.stringify({
|
|
214
|
+
type: 'validation',
|
|
215
|
+
on: type,
|
|
216
|
+
summary: mapValueError(error).summary,
|
|
217
|
+
message: error?.message,
|
|
218
|
+
found: value
|
|
219
|
+
})
|
|
220
|
+
} else {
|
|
221
|
+
// @ts-ignore private field
|
|
222
|
+
const schema = validator?.schema ?? validator
|
|
223
|
+
const errors =
|
|
224
|
+
'Errors' in validator
|
|
225
|
+
? [...validator.Errors(value)].map(mapValueError)
|
|
226
|
+
: [...Value.Errors(validator, value)].map(mapValueError)
|
|
227
|
+
|
|
228
|
+
let expected
|
|
229
|
+
|
|
230
|
+
try {
|
|
231
|
+
expected = Value.Create(schema)
|
|
232
|
+
} catch (error) {
|
|
233
|
+
expected = {
|
|
234
|
+
type: 'Could not create expected value',
|
|
235
|
+
// @ts-expect-error
|
|
236
|
+
message: error?.message,
|
|
237
|
+
error
|
|
238
|
+
}
|
|
239
|
+
}
|
|
240
|
+
|
|
241
|
+
message = JSON.stringify(
|
|
242
|
+
{
|
|
243
|
+
type: 'validation',
|
|
244
|
+
on: type,
|
|
245
|
+
summary: errors[0]?.summary,
|
|
246
|
+
property: accessor,
|
|
247
|
+
message: error?.message,
|
|
248
|
+
expected,
|
|
249
|
+
found: value,
|
|
250
|
+
errors
|
|
251
|
+
},
|
|
252
|
+
null,
|
|
253
|
+
2
|
|
254
|
+
)
|
|
255
|
+
}
|
|
256
|
+
|
|
257
|
+
super(message)
|
|
258
|
+
|
|
259
|
+
Object.setPrototypeOf(this, ValidationError.prototype)
|
|
260
|
+
}
|
|
261
|
+
|
|
262
|
+
get all() {
|
|
263
|
+
return 'Errors' in this.validator
|
|
264
|
+
? [...this.validator.Errors(this.value)].map(mapValueError)
|
|
265
|
+
: // @ts-ignore
|
|
266
|
+
[...Value.Errors(this.validator, this.value)].map(mapValueError)
|
|
267
|
+
}
|
|
268
|
+
|
|
269
|
+
static simplifyModel(validator: TSchema | TypeCheck<any>) {
|
|
270
|
+
// @ts-ignore
|
|
271
|
+
const model = 'schema' in validator ? validator.schema : validator
|
|
272
|
+
|
|
273
|
+
try {
|
|
274
|
+
return Value.Create(model)
|
|
275
|
+
} catch {
|
|
276
|
+
return model
|
|
277
|
+
}
|
|
278
|
+
}
|
|
279
|
+
|
|
280
|
+
get model() {
|
|
281
|
+
return ValidationError.simplifyModel(this.validator)
|
|
282
|
+
}
|
|
283
|
+
|
|
284
|
+
toResponse(headers?: Record<string, any>) {
|
|
285
|
+
return new Response(this.message, {
|
|
286
|
+
status: 400,
|
|
287
|
+
headers: {
|
|
288
|
+
...headers,
|
|
289
|
+
'content-type': 'application/json'
|
|
290
|
+
}
|
|
291
|
+
})
|
|
292
|
+
}
|
|
293
|
+
}
|