ts-procedures 5.0.0 → 5.1.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/build/implementations/http/express-rpc/index.js.map +1 -1
- package/build/implementations/http/hono-rpc/index.js.map +1 -1
- package/build/implementations/http/hono-stream/index.d.ts +14 -15
- package/build/implementations/http/hono-stream/index.js +7 -5
- package/build/implementations/http/hono-stream/index.js.map +1 -1
- package/build/implementations/http/hono-stream/index.test.js +166 -2
- package/build/implementations/http/hono-stream/index.test.js.map +1 -1
- package/build/implementations/http/hono-stream/types.d.ts +3 -3
- package/build/implementations/types.d.ts +5 -5
- package/package.json +1 -1
- package/src/implementations/http/express-rpc/index.ts +1 -1
- package/src/implementations/http/hono-rpc/index.ts +1 -1
- package/src/implementations/http/hono-stream/README.md +95 -38
- package/src/implementations/http/hono-stream/index.test.ts +213 -4
- package/src/implementations/http/hono-stream/index.ts +23 -22
- package/src/implementations/http/hono-stream/types.ts +3 -3
- package/src/implementations/types.ts +5 -5
|
@@ -3,8 +3,9 @@ import { describe, expect, test, vi, beforeEach } from 'vitest'
|
|
|
3
3
|
import { Hono } from 'hono'
|
|
4
4
|
import { v } from 'suretype'
|
|
5
5
|
import { Procedures } from '../../../index.js'
|
|
6
|
-
import { HonoStreamAppBuilder, sse } from './index.js'
|
|
7
|
-
import { RPCConfig } from '../../types.js'
|
|
6
|
+
import { HonoStreamAppBuilder, sse, MidStreamErrorResult } from './index.js'
|
|
7
|
+
import { RPCConfig, StreamMode } from '../../types.js'
|
|
8
|
+
import { ProcedureValidationError } from '../../../errors.js'
|
|
8
9
|
|
|
9
10
|
/**
|
|
10
11
|
* HonoStreamAppBuilder Test Suite
|
|
@@ -349,7 +350,7 @@ describe('HonoStreamAppBuilder', () => {
|
|
|
349
350
|
expect(onRequestEnd.mock.calls[0]![0]).toHaveProperty('req')
|
|
350
351
|
})
|
|
351
352
|
|
|
352
|
-
test('onStreamStart is called before streaming begins', async () => {
|
|
353
|
+
test('onStreamStart is called before streaming begins with streamMode', async () => {
|
|
353
354
|
const onStreamStart = vi.fn()
|
|
354
355
|
const builder = new HonoStreamAppBuilder({ onStreamStart })
|
|
355
356
|
const RPC = Procedures<{}, RPCConfig>()
|
|
@@ -365,9 +366,10 @@ describe('HonoStreamAppBuilder', () => {
|
|
|
365
366
|
|
|
366
367
|
expect(onStreamStart).toHaveBeenCalledTimes(1)
|
|
367
368
|
expect(onStreamStart.mock.calls[0]![0]).toHaveProperty('name', 'Test')
|
|
369
|
+
expect(onStreamStart.mock.calls[0]![2]).toBe('sse')
|
|
368
370
|
})
|
|
369
371
|
|
|
370
|
-
test('onStreamEnd is called after stream completes', async () => {
|
|
372
|
+
test('onStreamEnd is called after stream completes with streamMode', async () => {
|
|
371
373
|
const onStreamEnd = vi.fn()
|
|
372
374
|
const builder = new HonoStreamAppBuilder({ onStreamEnd })
|
|
373
375
|
const RPC = Procedures<{}, RPCConfig>()
|
|
@@ -385,6 +387,7 @@ describe('HonoStreamAppBuilder', () => {
|
|
|
385
387
|
|
|
386
388
|
expect(onStreamEnd).toHaveBeenCalledTimes(1)
|
|
387
389
|
expect(onStreamEnd.mock.calls[0]![0]).toHaveProperty('name', 'Test')
|
|
390
|
+
expect(onStreamEnd.mock.calls[0]![2]).toBe('sse')
|
|
388
391
|
})
|
|
389
392
|
|
|
390
393
|
test('hooks execute in correct order', async () => {
|
|
@@ -1387,6 +1390,212 @@ describe('HonoStreamAppBuilder', () => {
|
|
|
1387
1390
|
})
|
|
1388
1391
|
})
|
|
1389
1392
|
|
|
1393
|
+
// --------------------------------------------------------------------------
|
|
1394
|
+
// streamMode in Lifecycle Hooks
|
|
1395
|
+
// --------------------------------------------------------------------------
|
|
1396
|
+
describe('streamMode in lifecycle hooks', () => {
|
|
1397
|
+
test('onStreamStart receives sse streamMode', async () => {
|
|
1398
|
+
const onStreamStart = vi.fn()
|
|
1399
|
+
const builder = new HonoStreamAppBuilder({ onStreamStart })
|
|
1400
|
+
const RPC = Procedures<{}, RPCConfig>()
|
|
1401
|
+
|
|
1402
|
+
RPC.CreateStream('Test', { scope: 'test', version: 1 }, async function* () {
|
|
1403
|
+
yield { ok: true }
|
|
1404
|
+
})
|
|
1405
|
+
|
|
1406
|
+
builder.register(RPC, () => ({}))
|
|
1407
|
+
const app = builder.build()
|
|
1408
|
+
|
|
1409
|
+
await app.request('/test/test/1')
|
|
1410
|
+
|
|
1411
|
+
expect(onStreamStart).toHaveBeenCalledTimes(1)
|
|
1412
|
+
const [, , streamMode] = onStreamStart.mock.calls[0]!
|
|
1413
|
+
expect(streamMode).toBe('sse')
|
|
1414
|
+
})
|
|
1415
|
+
|
|
1416
|
+
test('onStreamEnd receives text streamMode', async () => {
|
|
1417
|
+
const onStreamEnd = vi.fn()
|
|
1418
|
+
const builder = new HonoStreamAppBuilder({ defaultStreamMode: 'text', onStreamEnd })
|
|
1419
|
+
const RPC = Procedures<{}, RPCConfig>()
|
|
1420
|
+
|
|
1421
|
+
RPC.CreateStream('Test', { scope: 'test', version: 1 }, async function* () {
|
|
1422
|
+
yield { ok: true }
|
|
1423
|
+
})
|
|
1424
|
+
|
|
1425
|
+
builder.register(RPC, () => ({}))
|
|
1426
|
+
const app = builder.build()
|
|
1427
|
+
|
|
1428
|
+
const res = await app.request('/test/test/1')
|
|
1429
|
+
await res.text()
|
|
1430
|
+
|
|
1431
|
+
expect(onStreamEnd).toHaveBeenCalledTimes(1)
|
|
1432
|
+
const [, , streamMode] = onStreamEnd.mock.calls[0]!
|
|
1433
|
+
expect(streamMode).toBe('text')
|
|
1434
|
+
})
|
|
1435
|
+
|
|
1436
|
+
test('onStreamStart and onStreamEnd receive matching streamMode', async () => {
|
|
1437
|
+
const modes: { start?: StreamMode; end?: StreamMode } = {}
|
|
1438
|
+
const builder = new HonoStreamAppBuilder({
|
|
1439
|
+
defaultStreamMode: 'text',
|
|
1440
|
+
onStreamStart: (_proc, _c, mode) => { modes.start = mode },
|
|
1441
|
+
onStreamEnd: (_proc, _c, mode) => { modes.end = mode },
|
|
1442
|
+
})
|
|
1443
|
+
const RPC = Procedures<{}, RPCConfig>()
|
|
1444
|
+
|
|
1445
|
+
RPC.CreateStream('Test', { scope: 'test', version: 1 }, async function* () {
|
|
1446
|
+
yield { ok: true }
|
|
1447
|
+
})
|
|
1448
|
+
|
|
1449
|
+
builder.register(RPC, () => ({}))
|
|
1450
|
+
const app = builder.build()
|
|
1451
|
+
|
|
1452
|
+
const res = await app.request('/test/test/1')
|
|
1453
|
+
await res.text()
|
|
1454
|
+
|
|
1455
|
+
expect(modes.start).toBe('text')
|
|
1456
|
+
expect(modes.end).toBe('text')
|
|
1457
|
+
})
|
|
1458
|
+
})
|
|
1459
|
+
|
|
1460
|
+
// --------------------------------------------------------------------------
|
|
1461
|
+
// sse() in onMidStreamError
|
|
1462
|
+
// --------------------------------------------------------------------------
|
|
1463
|
+
describe('sse() in onMidStreamError', () => {
|
|
1464
|
+
test('sse() wraps error data with custom event and id', async () => {
|
|
1465
|
+
const builder = new HonoStreamAppBuilder({
|
|
1466
|
+
onMidStreamError: (procedure, c, error) => {
|
|
1467
|
+
return {
|
|
1468
|
+
data: sse(
|
|
1469
|
+
{ type: 'error', message: error.message },
|
|
1470
|
+
{ event: 'custom-error', id: 'err-1' }
|
|
1471
|
+
),
|
|
1472
|
+
}
|
|
1473
|
+
},
|
|
1474
|
+
})
|
|
1475
|
+
const RPC = Procedures<{}, RPCConfig>()
|
|
1476
|
+
|
|
1477
|
+
RPC.CreateStream('ErrorStream', { scope: 'error', version: 1 }, async function* () {
|
|
1478
|
+
yield { type: 'data', value: 1 }
|
|
1479
|
+
throw new Error('Something broke')
|
|
1480
|
+
})
|
|
1481
|
+
|
|
1482
|
+
builder.register(RPC, () => ({}))
|
|
1483
|
+
const app = builder.build()
|
|
1484
|
+
|
|
1485
|
+
const res = await app.request('/error/error-stream/1')
|
|
1486
|
+
const text = await res.text()
|
|
1487
|
+
|
|
1488
|
+
// Normal yield
|
|
1489
|
+
expect(text).toContain('data: {"type":"data","value":1}')
|
|
1490
|
+
// Error yield with sse() metadata
|
|
1491
|
+
expect(text).toContain('event: custom-error')
|
|
1492
|
+
expect(text).toContain('id: err-1')
|
|
1493
|
+
expect(text).toContain('"type":"error"')
|
|
1494
|
+
})
|
|
1495
|
+
|
|
1496
|
+
test('string error data without sse() uses default event and id', async () => {
|
|
1497
|
+
const builder = new HonoStreamAppBuilder({
|
|
1498
|
+
onMidStreamError: () => {
|
|
1499
|
+
return { data: 'plain error string' }
|
|
1500
|
+
},
|
|
1501
|
+
})
|
|
1502
|
+
const RPC = Procedures<{}, RPCConfig>()
|
|
1503
|
+
|
|
1504
|
+
RPC.CreateStream('ErrorStream', { scope: 'error', version: 1 }, async function* () {
|
|
1505
|
+
yield { count: 1 }
|
|
1506
|
+
throw new Error('fail')
|
|
1507
|
+
})
|
|
1508
|
+
|
|
1509
|
+
builder.register(RPC, () => ({}))
|
|
1510
|
+
const app = builder.build()
|
|
1511
|
+
|
|
1512
|
+
const res = await app.request('/error/error-stream/1')
|
|
1513
|
+
const text = await res.text()
|
|
1514
|
+
|
|
1515
|
+
// String data can't use sse() (not an object), so defaults apply
|
|
1516
|
+
expect(text).toContain('data: plain error string')
|
|
1517
|
+
// event defaults to procedure name when data is provided
|
|
1518
|
+
expect(text).toContain('event: ErrorStream')
|
|
1519
|
+
})
|
|
1520
|
+
})
|
|
1521
|
+
|
|
1522
|
+
// --------------------------------------------------------------------------
|
|
1523
|
+
// Generic TErrorData
|
|
1524
|
+
// --------------------------------------------------------------------------
|
|
1525
|
+
describe('generic TErrorData', () => {
|
|
1526
|
+
test('typed builder constrains onMidStreamError return type', async () => {
|
|
1527
|
+
type ErrorPayload = { type: 'error'; code: string; message: string }
|
|
1528
|
+
|
|
1529
|
+
const builder = new HonoStreamAppBuilder<ErrorPayload>({
|
|
1530
|
+
onMidStreamError: (_procedure, _c, error) => {
|
|
1531
|
+
// This satisfies MidStreamErrorResult<ErrorPayload>
|
|
1532
|
+
return {
|
|
1533
|
+
data: { type: 'error', code: 'STREAM_FAILED', message: error.message },
|
|
1534
|
+
}
|
|
1535
|
+
},
|
|
1536
|
+
})
|
|
1537
|
+
const RPC = Procedures<{}, RPCConfig>()
|
|
1538
|
+
|
|
1539
|
+
RPC.CreateStream('ErrorStream', { scope: 'error', version: 1 }, async function* () {
|
|
1540
|
+
yield { value: 1 }
|
|
1541
|
+
throw new Error('typed error')
|
|
1542
|
+
})
|
|
1543
|
+
|
|
1544
|
+
builder.register(RPC, () => ({}))
|
|
1545
|
+
const app = builder.build()
|
|
1546
|
+
|
|
1547
|
+
const res = await app.request('/error/error-stream/1')
|
|
1548
|
+
const text = await res.text()
|
|
1549
|
+
|
|
1550
|
+
expect(text).toContain('"code":"STREAM_FAILED"')
|
|
1551
|
+
// Error message may be wrapped by Procedures with prefix
|
|
1552
|
+
expect(text).toContain('typed error')
|
|
1553
|
+
})
|
|
1554
|
+
})
|
|
1555
|
+
|
|
1556
|
+
// --------------------------------------------------------------------------
|
|
1557
|
+
// ProcedureValidationError narrowing in onPreStreamError
|
|
1558
|
+
// --------------------------------------------------------------------------
|
|
1559
|
+
describe('ProcedureValidationError narrowing', () => {
|
|
1560
|
+
test('instanceof check works in onPreStreamError', async () => {
|
|
1561
|
+
let wasValidationError = false
|
|
1562
|
+
|
|
1563
|
+
const builder = new HonoStreamAppBuilder({
|
|
1564
|
+
onPreStreamError: (procedure, c, error) => {
|
|
1565
|
+
if (error instanceof ProcedureValidationError) {
|
|
1566
|
+
wasValidationError = true
|
|
1567
|
+
return c.json({ validation: true, errors: error.errors }, 422)
|
|
1568
|
+
}
|
|
1569
|
+
return c.json({ error: error.message }, 500)
|
|
1570
|
+
},
|
|
1571
|
+
})
|
|
1572
|
+
const RPC = Procedures<{}, RPCConfig>()
|
|
1573
|
+
|
|
1574
|
+
RPC.CreateStream(
|
|
1575
|
+
'Validated',
|
|
1576
|
+
{
|
|
1577
|
+
scope: 'validated',
|
|
1578
|
+
version: 1,
|
|
1579
|
+
schema: { params: v.object({ count: v.number() }) },
|
|
1580
|
+
},
|
|
1581
|
+
async function* (ctx, params) {
|
|
1582
|
+
yield { count: params.count }
|
|
1583
|
+
}
|
|
1584
|
+
)
|
|
1585
|
+
|
|
1586
|
+
builder.register(RPC, () => ({}))
|
|
1587
|
+
const app = builder.build()
|
|
1588
|
+
|
|
1589
|
+
const res = await app.request('/validated/validated/1?count=not-a-number')
|
|
1590
|
+
|
|
1591
|
+
expect(res.status).toBe(422)
|
|
1592
|
+
expect(wasValidationError).toBe(true)
|
|
1593
|
+
const body = await res.json()
|
|
1594
|
+
expect(body.validation).toBe(true)
|
|
1595
|
+
expect(body.errors).toBeDefined()
|
|
1596
|
+
})
|
|
1597
|
+
})
|
|
1598
|
+
|
|
1390
1599
|
// --------------------------------------------------------------------------
|
|
1391
1600
|
// Integration Test
|
|
1392
1601
|
// --------------------------------------------------------------------------
|
|
@@ -32,18 +32,14 @@ function getSSEMeta(value: unknown): SSEOptions | undefined {
|
|
|
32
32
|
/**
|
|
33
33
|
* Result from onMidStreamError callback.
|
|
34
34
|
* @property data - The data to write as the SSE `data:` field content (should match yieldType schema)
|
|
35
|
-
* @property event - Optional SSE event name (defaults to procedure name if data provided, 'error' otherwise)
|
|
36
|
-
* @property id - Optional SSE event id (auto-incremented if not provided)
|
|
37
35
|
* @property closeStream - Whether to close the stream after writing (defaults to true)
|
|
38
36
|
*/
|
|
39
|
-
export type MidStreamErrorResult = {
|
|
40
|
-
data:
|
|
41
|
-
event?: string
|
|
42
|
-
id?: string
|
|
37
|
+
export type MidStreamErrorResult<TErrorData = unknown> = {
|
|
38
|
+
data: TErrorData
|
|
43
39
|
closeStream?: boolean
|
|
44
40
|
}
|
|
45
41
|
|
|
46
|
-
export type HonoStreamAppBuilderConfig = {
|
|
42
|
+
export type HonoStreamAppBuilderConfig<TErrorData = unknown> = {
|
|
47
43
|
/**
|
|
48
44
|
* An existing Hono application instance to use.
|
|
49
45
|
* If not provided, a new instance will be created.
|
|
@@ -55,8 +51,8 @@ export type HonoStreamAppBuilderConfig = {
|
|
|
55
51
|
defaultStreamMode?: StreamMode
|
|
56
52
|
onRequestStart?: (c: Context) => void
|
|
57
53
|
onRequestEnd?: (c: Context) => void
|
|
58
|
-
onStreamStart?: (procedure: TStreamProcedureRegistration, c: Context) => void
|
|
59
|
-
onStreamEnd?: (procedure: TStreamProcedureRegistration, c: Context) => void
|
|
54
|
+
onStreamStart?: (procedure: TStreamProcedureRegistration, c: Context, streamMode: StreamMode) => void
|
|
55
|
+
onStreamEnd?: (procedure: TStreamProcedureRegistration, c: Context, streamMode: StreamMode) => void
|
|
60
56
|
/**
|
|
61
57
|
* Called for errors BEFORE streaming starts (validation, auth, context resolution).
|
|
62
58
|
* Return value IS used as the HTTP response.
|
|
@@ -64,7 +60,7 @@ export type HonoStreamAppBuilderConfig = {
|
|
|
64
60
|
onPreStreamError?: (
|
|
65
61
|
procedure: TStreamProcedureRegistration,
|
|
66
62
|
c: Context,
|
|
67
|
-
error: Error
|
|
63
|
+
error: ProcedureValidationError | Error
|
|
68
64
|
) => Response | Promise<Response>
|
|
69
65
|
/**
|
|
70
66
|
* Called for errors DURING streaming (generator throws).
|
|
@@ -72,13 +68,15 @@ export type HonoStreamAppBuilderConfig = {
|
|
|
72
68
|
* Should return a value matching your yieldType schema (e.g., error variant of a union).
|
|
73
69
|
* Return undefined to use default behavior (writes { error: message }).
|
|
74
70
|
*
|
|
75
|
-
*
|
|
71
|
+
* Use sse() to attach SSE metadata (event, id, retry) to the error data object.
|
|
72
|
+
*
|
|
73
|
+
* @returns { data, closeStream? } - data to yield, whether to close after (default true)
|
|
76
74
|
*/
|
|
77
75
|
onMidStreamError?: (
|
|
78
76
|
procedure: TStreamProcedureRegistration,
|
|
79
77
|
c: Context,
|
|
80
78
|
error: Error
|
|
81
|
-
) => MidStreamErrorResult | undefined
|
|
79
|
+
) => MidStreamErrorResult<TErrorData> | undefined
|
|
82
80
|
}
|
|
83
81
|
|
|
84
82
|
/**
|
|
@@ -94,11 +92,11 @@ export type HonoStreamAppBuilderConfig = {
|
|
|
94
92
|
* const app = streamApp.app; // Hono application
|
|
95
93
|
* const docs = streamApp.docs; // Stream route documentation
|
|
96
94
|
*/
|
|
97
|
-
export class HonoStreamAppBuilder {
|
|
95
|
+
export class HonoStreamAppBuilder<TErrorData = unknown> {
|
|
98
96
|
/**
|
|
99
97
|
* Constructor for HonoStreamAppBuilder.
|
|
100
98
|
*/
|
|
101
|
-
constructor(readonly config?: HonoStreamAppBuilderConfig) {
|
|
99
|
+
constructor(readonly config?: HonoStreamAppBuilderConfig<TErrorData>) {
|
|
102
100
|
if (config?.app) {
|
|
103
101
|
this._app = config.app
|
|
104
102
|
}
|
|
@@ -215,7 +213,7 @@ export class HonoStreamAppBuilder {
|
|
|
215
213
|
}
|
|
216
214
|
|
|
217
215
|
if (this.config?.onStreamStart) {
|
|
218
|
-
this.config.onStreamStart(procedure, c)
|
|
216
|
+
this.config.onStreamStart(procedure, c, streamMode)
|
|
219
217
|
}
|
|
220
218
|
|
|
221
219
|
if (streamMode === 'sse') {
|
|
@@ -272,7 +270,7 @@ export class HonoStreamAppBuilder {
|
|
|
272
270
|
}
|
|
273
271
|
} catch (error) {
|
|
274
272
|
// Get error yield value from callback (onMidStreamError)
|
|
275
|
-
let errorResult: MidStreamErrorResult | undefined
|
|
273
|
+
let errorResult: MidStreamErrorResult<TErrorData> | undefined
|
|
276
274
|
|
|
277
275
|
if (this.config?.onMidStreamError) {
|
|
278
276
|
errorResult = this.config.onMidStreamError(procedure, c, error as Error)
|
|
@@ -280,17 +278,20 @@ export class HonoStreamAppBuilder {
|
|
|
280
278
|
|
|
281
279
|
// Write error value to stream
|
|
282
280
|
const errorData = errorResult?.data ?? { error: (error as Error).message }
|
|
281
|
+
const sseMeta = getSSEMeta(errorData)
|
|
282
|
+
|
|
283
283
|
await stream.writeSSE({
|
|
284
284
|
data: typeof errorData === 'string' ? errorData : JSON.stringify(errorData),
|
|
285
|
-
event:
|
|
286
|
-
id:
|
|
285
|
+
event: sseMeta?.event ?? (errorResult?.data !== undefined ? procedure.name : 'error'),
|
|
286
|
+
id: sseMeta?.id ?? String(eventId++),
|
|
287
|
+
...(sseMeta?.retry !== undefined && { retry: sseMeta.retry }),
|
|
287
288
|
})
|
|
288
289
|
|
|
289
290
|
// closeStream defaults to true if not specified
|
|
290
291
|
// (stream closes naturally after this handler completes)
|
|
291
292
|
} finally {
|
|
292
293
|
if (this.config?.onStreamEnd) {
|
|
293
|
-
this.config.onStreamEnd(procedure, c)
|
|
294
|
+
this.config.onStreamEnd(procedure, c, 'sse')
|
|
294
295
|
}
|
|
295
296
|
if (this.config?.onRequestEnd) {
|
|
296
297
|
this.config.onRequestEnd(c)
|
|
@@ -322,7 +323,7 @@ export class HonoStreamAppBuilder {
|
|
|
322
323
|
}
|
|
323
324
|
} catch (error) {
|
|
324
325
|
// Get error yield value from callback (onMidStreamError)
|
|
325
|
-
let errorResult: MidStreamErrorResult | undefined
|
|
326
|
+
let errorResult: MidStreamErrorResult<TErrorData> | undefined
|
|
326
327
|
|
|
327
328
|
if (this.config?.onMidStreamError) {
|
|
328
329
|
errorResult = this.config.onMidStreamError(procedure, c, error as Error)
|
|
@@ -333,7 +334,7 @@ export class HonoStreamAppBuilder {
|
|
|
333
334
|
await stream.writeln(JSON.stringify(errorData))
|
|
334
335
|
} finally {
|
|
335
336
|
if (this.config?.onStreamEnd) {
|
|
336
|
-
this.config.onStreamEnd(procedure, c)
|
|
337
|
+
this.config.onStreamEnd(procedure, c, 'text')
|
|
337
338
|
}
|
|
338
339
|
if (this.config?.onRequestEnd) {
|
|
339
340
|
this.config.onRequestEnd(c)
|
|
@@ -385,7 +386,7 @@ export class HonoStreamAppBuilder {
|
|
|
385
386
|
prefix: this.config?.pathPrefix,
|
|
386
387
|
})
|
|
387
388
|
const methods = ['get', 'post'] as const
|
|
388
|
-
const jsonSchema: { params?:
|
|
389
|
+
const jsonSchema: { params?: Record<string, unknown>; yieldType?: Record<string, unknown>; returnType?: Record<string, unknown> } = {}
|
|
389
390
|
|
|
390
391
|
if (config.schema?.params) {
|
|
391
392
|
jsonSchema.params = config.schema.params
|
|
@@ -10,9 +10,9 @@ export interface StreamHttpRouteDoc extends RPCConfig {
|
|
|
10
10
|
methods: ('get' | 'post')[]
|
|
11
11
|
streamMode: StreamMode
|
|
12
12
|
jsonSchema: {
|
|
13
|
-
params?:
|
|
14
|
-
yieldType?:
|
|
15
|
-
returnType?:
|
|
13
|
+
params?: Record<string, unknown>
|
|
14
|
+
yieldType?: Record<string, unknown>
|
|
15
|
+
returnType?: Record<string, unknown>
|
|
16
16
|
}
|
|
17
17
|
}
|
|
18
18
|
|
|
@@ -16,8 +16,8 @@ export interface RPCHttpRouteDoc extends RPCConfig {
|
|
|
16
16
|
path: string
|
|
17
17
|
method: 'post'
|
|
18
18
|
jsonSchema: {
|
|
19
|
-
body?:
|
|
20
|
-
response?:
|
|
19
|
+
body?: Record<string, unknown>
|
|
20
|
+
response?: Record<string, unknown>
|
|
21
21
|
}
|
|
22
22
|
}
|
|
23
23
|
|
|
@@ -29,9 +29,9 @@ export interface StreamHttpRouteDoc extends RPCConfig {
|
|
|
29
29
|
methods: ('get' | 'post')[]
|
|
30
30
|
streamMode: StreamMode
|
|
31
31
|
jsonSchema: {
|
|
32
|
-
params?:
|
|
33
|
-
yieldType?:
|
|
34
|
-
returnType?:
|
|
32
|
+
params?: Record<string, unknown> // Query params (GET) or body (POST)
|
|
33
|
+
yieldType?: Record<string, unknown> // Schema for each streamed value
|
|
34
|
+
returnType?: Record<string, unknown> // Final return (optional)
|
|
35
35
|
}
|
|
36
36
|
}
|
|
37
37
|
|