ts-procedures 5.3.0 → 5.4.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 +90 -0
- package/agent_config/claude-code/agents/ts-procedures-architect.md +15 -0
- package/agent_config/claude-code/skills/guide/anti-patterns.md +106 -0
- package/agent_config/claude-code/skills/guide/api-reference.md +150 -4
- package/agent_config/claude-code/skills/guide/patterns.md +155 -0
- package/agent_config/claude-code/skills/review/checklist.md +22 -0
- package/agent_config/claude-code/skills/scaffold/SKILL.md +3 -1
- package/agent_config/claude-code/skills/scaffold/templates/hono-api.md +169 -0
- package/agent_config/copilot/copilot-instructions.md +35 -0
- package/agent_config/cursor/cursorrules +35 -0
- package/build/implementations/http/hono-api/index.d.ts +102 -0
- package/build/implementations/http/hono-api/index.js +339 -0
- package/build/implementations/http/hono-api/index.js.map +1 -0
- package/build/implementations/http/hono-api/index.test.d.ts +1 -0
- package/build/implementations/http/hono-api/index.test.js +983 -0
- package/build/implementations/http/hono-api/index.test.js.map +1 -0
- package/build/implementations/http/hono-api/types.d.ts +13 -0
- package/build/implementations/http/hono-api/types.js +2 -0
- package/build/implementations/http/hono-api/types.js.map +1 -0
- package/build/implementations/types.d.ts +44 -0
- package/build/index.d.ts +28 -6
- package/build/index.js +28 -0
- package/build/index.js.map +1 -1
- package/build/schema/compute-schema.d.ts +5 -0
- package/build/schema/compute-schema.js +8 -1
- package/build/schema/compute-schema.js.map +1 -1
- package/build/schema/parser.d.ts +6 -5
- package/build/schema/parser.js +54 -0
- package/build/schema/parser.js.map +1 -1
- package/package.json +8 -3
- package/src/implementations/http/README.md +45 -2
- package/src/implementations/http/hono-api/index.test.ts +1328 -0
- package/src/implementations/http/hono-api/index.ts +461 -0
- package/src/implementations/http/hono-api/types.ts +16 -0
- package/src/implementations/types.ts +52 -0
- package/src/index.ts +87 -10
- package/src/schema/compute-schema.ts +23 -2
- package/src/schema/parser.ts +70 -3
package/src/index.ts
CHANGED
|
@@ -26,9 +26,11 @@ export type TProcedureRegistration<TContext = unknown, TExtendedConfig = unknown
|
|
|
26
26
|
schema?: {
|
|
27
27
|
params?: TJSONSchema
|
|
28
28
|
returnType?: TJSONSchema
|
|
29
|
+
input?: Record<string, TJSONSchema>
|
|
29
30
|
}
|
|
30
31
|
validation?: {
|
|
31
32
|
params?: (params: any) => { errors?: any[] }
|
|
33
|
+
input?: Record<string, (value: any) => { errors?: any[] }>
|
|
32
34
|
}
|
|
33
35
|
} & TExtendedConfig
|
|
34
36
|
|
|
@@ -44,10 +46,12 @@ export type TStreamProcedureRegistration<TContext = unknown, TExtendedConfig = u
|
|
|
44
46
|
params?: TJSONSchema
|
|
45
47
|
yieldType?: TJSONSchema
|
|
46
48
|
returnType?: TJSONSchema
|
|
49
|
+
input?: Record<string, TJSONSchema>
|
|
47
50
|
}
|
|
48
51
|
validation?: {
|
|
49
52
|
params?: (params: any) => { errors?: any[] }
|
|
50
53
|
yield?: (value: any) => { errors?: any[] }
|
|
54
|
+
input?: Record<string, (value: any) => { errors?: any[] }>
|
|
51
55
|
}
|
|
52
56
|
} & TExtendedConfig
|
|
53
57
|
|
|
@@ -73,10 +77,12 @@ export function Procedures<TContext = TNoContextProvided, TExtendedConfig = unkn
|
|
|
73
77
|
params?: TJSONSchema
|
|
74
78
|
yieldType?: TJSONSchema
|
|
75
79
|
returnType?: TJSONSchema
|
|
80
|
+
input?: Record<string, TJSONSchema>
|
|
76
81
|
}
|
|
77
82
|
validation?: {
|
|
78
83
|
params?: (params: any) => { errors?: any[] }
|
|
79
84
|
yield?: (value: any) => { errors?: any[] }
|
|
85
|
+
input?: Record<string, (value: any) => { errors?: any[] }>
|
|
80
86
|
}
|
|
81
87
|
} & TExtendedConfig
|
|
82
88
|
>
|
|
@@ -90,18 +96,26 @@ export function Procedures<TContext = TNoContextProvided, TExtendedConfig = unkn
|
|
|
90
96
|
| TStreamProcedureRegistration<TContext, TExtendedConfig>
|
|
91
97
|
> = new Map()
|
|
92
98
|
|
|
93
|
-
function Create<
|
|
99
|
+
function Create<
|
|
100
|
+
TName extends string,
|
|
101
|
+
TParams,
|
|
102
|
+
TReturnType,
|
|
103
|
+
TInput extends Record<string, unknown> | undefined = undefined,
|
|
104
|
+
>(
|
|
94
105
|
name: TName,
|
|
95
106
|
config: {
|
|
96
107
|
description?: string
|
|
97
108
|
schema?: {
|
|
98
109
|
params?: TParams
|
|
99
110
|
returnType?: TReturnType
|
|
111
|
+
input?: TInput
|
|
100
112
|
}
|
|
101
113
|
} & TExtendedConfig,
|
|
102
114
|
handler: (
|
|
103
115
|
ctx: Prettify<TContext & TLocalContext & { isPrevalidated?: boolean }>,
|
|
104
|
-
params:
|
|
116
|
+
params: TInput extends Record<string, unknown>
|
|
117
|
+
? Prettify<{ [K in keyof TInput]: TSchemaLib<TInput[K]> }>
|
|
118
|
+
: TSchemaLib<TParams>
|
|
105
119
|
) => Promise<TSchemaLib<TReturnType>>
|
|
106
120
|
) {
|
|
107
121
|
// Capture definition location as first action
|
|
@@ -128,6 +142,7 @@ export function Procedures<TContext = TNoContextProvided, TExtendedConfig = unkn
|
|
|
128
142
|
schema: jsonSchema,
|
|
129
143
|
validation: {
|
|
130
144
|
params: validations.params,
|
|
145
|
+
...(validations.input && { input: validations.input }),
|
|
131
146
|
},
|
|
132
147
|
},
|
|
133
148
|
|
|
@@ -148,16 +163,37 @@ export function Procedures<TContext = TNoContextProvided, TExtendedConfig = unkn
|
|
|
148
163
|
}
|
|
149
164
|
}
|
|
150
165
|
|
|
166
|
+
// Validate each input channel independently for better error messages.
|
|
167
|
+
// Double validation (per-channel + merged) is intentional for developer experience;
|
|
168
|
+
// the cost is negligible — revisit if validation becomes a performance bottleneck.
|
|
169
|
+
if (validations?.input && !isPrevalidated) {
|
|
170
|
+
for (const [channel, validator] of Object.entries(validations.input)) {
|
|
171
|
+
const channelValue = (params as Record<string, unknown>)?.[channel]
|
|
172
|
+
const { errors } = validator(channelValue)
|
|
173
|
+
|
|
174
|
+
if (errors) {
|
|
175
|
+
throw new ProcedureValidationError(
|
|
176
|
+
name,
|
|
177
|
+
`Validation error for ${name} in input.${channel}`,
|
|
178
|
+
errors,
|
|
179
|
+
definitionInfo
|
|
180
|
+
)
|
|
181
|
+
}
|
|
182
|
+
}
|
|
183
|
+
}
|
|
184
|
+
|
|
151
185
|
const localCtx: TLocalContext = {
|
|
152
186
|
error: errorFactory, // Reuse pre-created factory
|
|
153
187
|
}
|
|
154
188
|
|
|
189
|
+
// params is correctly typed at the public API boundary via conditional type;
|
|
190
|
+
// cast here because TS cannot narrow conditional generics inside implementations
|
|
155
191
|
return await handler(
|
|
156
192
|
{
|
|
157
193
|
...ctx,
|
|
158
194
|
...localCtx,
|
|
159
195
|
} as Prettify<TContext & TLocalContext & { isPrevalidated?: boolean }>,
|
|
160
|
-
params
|
|
196
|
+
params as any
|
|
161
197
|
)
|
|
162
198
|
} catch (error: any) {
|
|
163
199
|
if (error instanceof ProcedureError) {
|
|
@@ -204,12 +240,16 @@ export function Procedures<TContext = TNoContextProvided, TExtendedConfig = unkn
|
|
|
204
240
|
} as {
|
|
205
241
|
[K in TName]: (
|
|
206
242
|
ctx: Prettify<TContext>,
|
|
207
|
-
params:
|
|
243
|
+
params: TInput extends Record<string, unknown>
|
|
244
|
+
? Prettify<{ [K in keyof TInput]: TSchemaLib<TInput[K]> }>
|
|
245
|
+
: TSchemaLib<TParams>
|
|
208
246
|
) => Promise<TSchemaLib<TReturnType>>
|
|
209
247
|
} & {
|
|
210
248
|
procedure: (
|
|
211
249
|
ctx: Prettify<TContext>,
|
|
212
|
-
params:
|
|
250
|
+
params: TInput extends Record<string, unknown>
|
|
251
|
+
? Prettify<{ [K in keyof TInput]: TSchemaLib<TInput[K]> }>
|
|
252
|
+
: TSchemaLib<TParams>
|
|
213
253
|
) => Promise<TSchemaLib<TReturnType>>
|
|
214
254
|
info: {
|
|
215
255
|
name: TName
|
|
@@ -217,15 +257,23 @@ export function Procedures<TContext = TNoContextProvided, TExtendedConfig = unkn
|
|
|
217
257
|
schema: {
|
|
218
258
|
params?: TParams
|
|
219
259
|
returnType?: TReturnType
|
|
260
|
+
input?: TInput
|
|
220
261
|
}
|
|
221
262
|
validation?: {
|
|
222
263
|
params?: (params: any) => { errors?: any[] }
|
|
264
|
+
input?: Record<string, (value: any) => { errors?: any[] }>
|
|
223
265
|
}
|
|
224
266
|
} & TExtendedConfig
|
|
225
267
|
}
|
|
226
268
|
}
|
|
227
269
|
|
|
228
|
-
function CreateStream<
|
|
270
|
+
function CreateStream<
|
|
271
|
+
TName extends string,
|
|
272
|
+
TParams,
|
|
273
|
+
TYieldType,
|
|
274
|
+
TReturnType = void,
|
|
275
|
+
TInput extends Record<string, unknown> | undefined = undefined,
|
|
276
|
+
>(
|
|
229
277
|
name: TName,
|
|
230
278
|
config: {
|
|
231
279
|
description?: string
|
|
@@ -233,12 +281,15 @@ export function Procedures<TContext = TNoContextProvided, TExtendedConfig = unkn
|
|
|
233
281
|
params?: TParams
|
|
234
282
|
yieldType?: TYieldType
|
|
235
283
|
returnType?: TReturnType
|
|
284
|
+
input?: TInput
|
|
236
285
|
}
|
|
237
286
|
validateYields?: boolean
|
|
238
287
|
} & TExtendedConfig,
|
|
239
288
|
handler: (
|
|
240
289
|
ctx: Prettify<TContext & TStreamContext & { isPrevalidated?: boolean }>,
|
|
241
|
-
params:
|
|
290
|
+
params: TInput extends Record<string, unknown>
|
|
291
|
+
? Prettify<{ [K in keyof TInput]: TSchemaLib<TInput[K]> }>
|
|
292
|
+
: TSchemaLib<TParams>
|
|
242
293
|
) => AsyncGenerator<TSchemaLib<TYieldType>, TSchemaLib<TReturnType> | void, unknown>
|
|
243
294
|
) {
|
|
244
295
|
// Capture definition location as first action
|
|
@@ -268,6 +319,7 @@ export function Procedures<TContext = TNoContextProvided, TExtendedConfig = unkn
|
|
|
268
319
|
validation: {
|
|
269
320
|
params: validations.params,
|
|
270
321
|
yield: validations.yield,
|
|
322
|
+
...(validations.input && { input: validations.input }),
|
|
271
323
|
},
|
|
272
324
|
},
|
|
273
325
|
|
|
@@ -293,6 +345,23 @@ export function Procedures<TContext = TNoContextProvided, TExtendedConfig = unkn
|
|
|
293
345
|
}
|
|
294
346
|
}
|
|
295
347
|
|
|
348
|
+
// Validate each input channel independently (see Create for rationale)
|
|
349
|
+
if (validations?.input && !isPrevalidated) {
|
|
350
|
+
for (const [channel, validator] of Object.entries(validations.input)) {
|
|
351
|
+
const channelValue = (params as Record<string, unknown>)?.[channel]
|
|
352
|
+
const { errors } = validator(channelValue)
|
|
353
|
+
|
|
354
|
+
if (errors) {
|
|
355
|
+
throw new ProcedureValidationError(
|
|
356
|
+
name,
|
|
357
|
+
`Validation error for ${name} in input.${channel}`,
|
|
358
|
+
errors,
|
|
359
|
+
definitionInfo
|
|
360
|
+
)
|
|
361
|
+
}
|
|
362
|
+
}
|
|
363
|
+
}
|
|
364
|
+
|
|
296
365
|
// Combine with external signal (e.g., from HTTP request) if provided
|
|
297
366
|
const incomingSignal = (ctx as { signal?: AbortSignal }).signal
|
|
298
367
|
const signal = incomingSignal
|
|
@@ -304,12 +373,14 @@ export function Procedures<TContext = TNoContextProvided, TExtendedConfig = unkn
|
|
|
304
373
|
signal,
|
|
305
374
|
}
|
|
306
375
|
|
|
376
|
+
// params is correctly typed at the public API boundary via conditional type;
|
|
377
|
+
// cast here because TS cannot narrow conditional generics inside implementations
|
|
307
378
|
const userGenerator = handler(
|
|
308
379
|
{
|
|
309
380
|
...ctx,
|
|
310
381
|
...streamCtx,
|
|
311
382
|
} as Prettify<TContext & TStreamContext & { isPrevalidated?: boolean }>,
|
|
312
|
-
params
|
|
383
|
+
params as any
|
|
313
384
|
)
|
|
314
385
|
|
|
315
386
|
try {
|
|
@@ -376,12 +447,16 @@ export function Procedures<TContext = TNoContextProvided, TExtendedConfig = unkn
|
|
|
376
447
|
} as {
|
|
377
448
|
[K in TName]: (
|
|
378
449
|
ctx: Prettify<TContext>,
|
|
379
|
-
params:
|
|
450
|
+
params: TInput extends Record<string, unknown>
|
|
451
|
+
? Prettify<{ [K in keyof TInput]: TSchemaLib<TInput[K]> }>
|
|
452
|
+
: TSchemaLib<TParams>
|
|
380
453
|
) => AsyncGenerator<TSchemaLib<TYieldType>, TSchemaLib<TReturnType> | void, unknown>
|
|
381
454
|
} & {
|
|
382
455
|
procedure: (
|
|
383
456
|
ctx: Prettify<TContext>,
|
|
384
|
-
params:
|
|
457
|
+
params: TInput extends Record<string, unknown>
|
|
458
|
+
? Prettify<{ [K in keyof TInput]: TSchemaLib<TInput[K]> }>
|
|
459
|
+
: TSchemaLib<TParams>
|
|
385
460
|
) => AsyncGenerator<TSchemaLib<TYieldType>, TSchemaLib<TReturnType> | void, unknown>
|
|
386
461
|
info: {
|
|
387
462
|
name: TName
|
|
@@ -391,10 +466,12 @@ export function Procedures<TContext = TNoContextProvided, TExtendedConfig = unkn
|
|
|
391
466
|
params?: TParams
|
|
392
467
|
yieldType?: TYieldType
|
|
393
468
|
returnType?: TReturnType
|
|
469
|
+
input?: TInput
|
|
394
470
|
}
|
|
395
471
|
validation?: {
|
|
396
472
|
params?: (params: any) => { errors?: any[] }
|
|
397
473
|
yield?: (value: any) => { errors?: any[] }
|
|
474
|
+
input?: Record<string, (value: any) => { errors?: any[] }>
|
|
398
475
|
}
|
|
399
476
|
} & TExtendedConfig
|
|
400
477
|
}
|
|
@@ -17,6 +17,7 @@ export function computeSchema<TParamsSchemaType, TReturnTypeSchemaType, TYieldTy
|
|
|
17
17
|
params?: TParamsSchemaType
|
|
18
18
|
returnType?: TReturnTypeSchemaType
|
|
19
19
|
yieldType?: TYieldTypeSchemaType
|
|
20
|
+
input?: Record<string, unknown>
|
|
20
21
|
},
|
|
21
22
|
// Used for error stack trace details
|
|
22
23
|
definitionInfo?: DefinitionInfo
|
|
@@ -25,26 +26,44 @@ export function computeSchema<TParamsSchemaType, TReturnTypeSchemaType, TYieldTy
|
|
|
25
26
|
params?: TJSONSchema
|
|
26
27
|
returnType?: TJSONSchema
|
|
27
28
|
yieldType?: TJSONSchema
|
|
29
|
+
input?: Record<string, TJSONSchema>
|
|
28
30
|
}
|
|
29
31
|
validations: {
|
|
30
32
|
params?: (params?: any) => { errors?: TSchemaValidationError[] }
|
|
31
33
|
yield?: (value?: any) => { errors?: TSchemaValidationError[] }
|
|
34
|
+
input?: Record<string, (value?: any) => { errors?: TSchemaValidationError[] }>
|
|
32
35
|
}
|
|
33
36
|
} {
|
|
34
|
-
const jsonSchema: {
|
|
37
|
+
const jsonSchema: {
|
|
38
|
+
params?: TJSONSchema
|
|
39
|
+
returnType?: TJSONSchema
|
|
40
|
+
yieldType?: TJSONSchema
|
|
41
|
+
input?: Record<string, TJSONSchema>
|
|
42
|
+
} = {
|
|
35
43
|
params: undefined,
|
|
36
44
|
returnType: undefined,
|
|
37
45
|
yieldType: undefined,
|
|
46
|
+
input: undefined,
|
|
38
47
|
}
|
|
39
48
|
|
|
40
49
|
const validations: {
|
|
41
50
|
params?: (params?: any) => { errors?: TSchemaValidationError[] }
|
|
42
51
|
yield?: (value?: any) => { errors?: TSchemaValidationError[] }
|
|
52
|
+
input?: Record<string, (value?: any) => { errors?: TSchemaValidationError[] }>
|
|
43
53
|
} = {}
|
|
44
54
|
|
|
55
|
+
// Mutual exclusivity: params and input cannot both be defined
|
|
56
|
+
if (schema?.params && schema?.input) {
|
|
57
|
+
throw new ProcedureRegistrationError(
|
|
58
|
+
name,
|
|
59
|
+
`schema.params and schema.input are mutually exclusive for procedure "${name}". Use schema.params for flat input or schema.input for structured multi-channel input.`,
|
|
60
|
+
definitionInfo
|
|
61
|
+
)
|
|
62
|
+
}
|
|
63
|
+
|
|
45
64
|
if (schema) {
|
|
46
65
|
const {
|
|
47
|
-
jsonSchema: { params, returnType, yieldType },
|
|
66
|
+
jsonSchema: { params, returnType, yieldType, input },
|
|
48
67
|
validation,
|
|
49
68
|
} = schemaParser(schema, (errors) => {
|
|
50
69
|
throw new ProcedureRegistrationError(
|
|
@@ -59,8 +78,10 @@ export function computeSchema<TParamsSchemaType, TReturnTypeSchemaType, TYieldTy
|
|
|
59
78
|
jsonSchema.params = params
|
|
60
79
|
jsonSchema.returnType = returnType
|
|
61
80
|
jsonSchema.yieldType = yieldType
|
|
81
|
+
jsonSchema.input = input
|
|
62
82
|
validations.params = validation.params
|
|
63
83
|
validations.yield = validation.yield
|
|
84
|
+
validations.input = validation.input
|
|
64
85
|
}
|
|
65
86
|
|
|
66
87
|
return { jsonSchema, validations }
|
package/src/schema/parser.ts
CHANGED
|
@@ -4,10 +4,16 @@ import { extractJsonSchema } from './extract-json-schema.js'
|
|
|
4
4
|
import { TJSONSchema } from './types.js'
|
|
5
5
|
|
|
6
6
|
export type TSchemaParsed = {
|
|
7
|
-
jsonSchema: {
|
|
7
|
+
jsonSchema: {
|
|
8
|
+
params?: TJSONSchema
|
|
9
|
+
returnType?: TJSONSchema
|
|
10
|
+
yieldType?: TJSONSchema
|
|
11
|
+
input?: Record<string, TJSONSchema>
|
|
12
|
+
}
|
|
8
13
|
validation: {
|
|
9
14
|
params?: (params: any) => { errors?: TSchemaValidationError[] }
|
|
10
15
|
yield?: (value: any) => { errors?: TSchemaValidationError[] }
|
|
16
|
+
input?: Record<string, (value: any) => { errors?: TSchemaValidationError[] }>
|
|
11
17
|
}
|
|
12
18
|
}
|
|
13
19
|
|
|
@@ -24,8 +30,8 @@ const ajv = addFormats(
|
|
|
24
30
|
)
|
|
25
31
|
|
|
26
32
|
export function schemaParser(
|
|
27
|
-
schema: { params?: unknown; returnType?: unknown; yieldType?: unknown },
|
|
28
|
-
onParseError: (errors:
|
|
33
|
+
schema: { params?: unknown; returnType?: unknown; yieldType?: unknown; input?: Record<string, unknown> },
|
|
34
|
+
onParseError: (errors: Record<string, string>) => void
|
|
29
35
|
): TSchemaParsed {
|
|
30
36
|
const jsonSchema: TSchemaParsed['jsonSchema'] = {}
|
|
31
37
|
const validation: TSchemaParsed['validation'] = {}
|
|
@@ -144,5 +150,66 @@ export function schemaParser(
|
|
|
144
150
|
}
|
|
145
151
|
}
|
|
146
152
|
|
|
153
|
+
if (schema.input) {
|
|
154
|
+
jsonSchema.input = {}
|
|
155
|
+
validation.input = {}
|
|
156
|
+
|
|
157
|
+
for (const [channelName, channelSchema] of Object.entries(schema.input)) {
|
|
158
|
+
if (!channelSchema) continue
|
|
159
|
+
|
|
160
|
+
let channelJsonSchema: TJSONSchema | undefined
|
|
161
|
+
|
|
162
|
+
try {
|
|
163
|
+
const extracted = extractJsonSchema(channelSchema as TJSONSchema)
|
|
164
|
+
if (extracted) {
|
|
165
|
+
channelJsonSchema = extracted
|
|
166
|
+
jsonSchema.input[channelName] = extracted
|
|
167
|
+
}
|
|
168
|
+
} catch (e: any) {
|
|
169
|
+
onParseError({
|
|
170
|
+
[`input.${channelName}`]: `Error extracting json schema schema.input.${channelName} - ${e.message}`,
|
|
171
|
+
})
|
|
172
|
+
}
|
|
173
|
+
|
|
174
|
+
if (!channelJsonSchema) {
|
|
175
|
+
onParseError({
|
|
176
|
+
[`input.${channelName}`]: `Error extracting json schema schema.input.${channelName} - might be empty or not a valid suretype or typebox type`,
|
|
177
|
+
})
|
|
178
|
+
} else {
|
|
179
|
+
let channelValidator: AJV.ValidateFunction | undefined
|
|
180
|
+
|
|
181
|
+
try {
|
|
182
|
+
channelValidator = ajv.compile(channelJsonSchema as TJSONSchema)
|
|
183
|
+
} catch (e: any) {
|
|
184
|
+
onParseError({
|
|
185
|
+
[`input.${channelName}`]: `Error compiling schema.input.${channelName} for validator - ${e.message}`,
|
|
186
|
+
})
|
|
187
|
+
}
|
|
188
|
+
|
|
189
|
+
validation.input[channelName] = (value: any) => {
|
|
190
|
+
if (!channelValidator) {
|
|
191
|
+
return {
|
|
192
|
+
errors: [
|
|
193
|
+
{ message: 'Validator not initialized', keyword: 'internal' } as TSchemaValidationError,
|
|
194
|
+
],
|
|
195
|
+
}
|
|
196
|
+
}
|
|
197
|
+
|
|
198
|
+
const valid = channelValidator(value)
|
|
199
|
+
|
|
200
|
+
if (!valid) {
|
|
201
|
+
const errors = channelValidator.errors
|
|
202
|
+
|
|
203
|
+
return {
|
|
204
|
+
errors: errors?.length ? errors : undefined,
|
|
205
|
+
}
|
|
206
|
+
}
|
|
207
|
+
|
|
208
|
+
return {}
|
|
209
|
+
}
|
|
210
|
+
}
|
|
211
|
+
}
|
|
212
|
+
}
|
|
213
|
+
|
|
147
214
|
return { jsonSchema, validation }
|
|
148
215
|
}
|