Instead of generators you can return StreamResponse object in order to get more control over your stream code.
1import type { StreamResponse } from 'vovk';
2
3export type Token = { message: string };
4
5export default class StreamService {
6 static async streamTokens(resp: StreamResponse<Token>) {
7 const tokens: Token[] = [
8 { message: 'Hello,' },
9 { message: ' World' },
10 { message: ' from' },
11 { message: ' Stream' },
12 { message: '!' },
13 ];
14
15 for (const token of tokens) {
16 resp.send(token);
17 await new Promise((resolve) => setTimeout(resolve, 300));
18 }
19
20 await resp.close();
21 }
22}
1import type { StreamResponse } from 'vovk';
2
3export type Token = { message: string };
4
5export default class StreamService {
6 static async streamTokens(resp: StreamResponse<Token>) {
7 const tokens: Token[] = [
8 { message: 'Hello,' },
9 { message: ' World' },
10 { message: ' from' },
11 { message: ' Stream' },
12 { message: '!' },
13 ];
14
15 for (const token of tokens) {
16 resp.send(token);
17 await new Promise((resolve) => setTimeout(resolve, 300));
18 }
19
20 await resp.close();
21 }
22}
1import type { StreamResponse } from 'vovk';
2
3export type Token = { message: string };
4
5export default class StreamService {
6 static async streamTokens(resp: StreamResponse<Token>) {
7 const tokens: Token[] = [
8 { message: 'Hello,' },
9 { message: ' World' },
10 { message: ' from' },
11 { message: ' Stream' },
12 { message: '!' },
13 ];
14
15 for (const token of tokens) {
16 resp.send(token);
17 await new Promise((resolve) => setTimeout(resolve, 300));
18 }
19
20 await resp.close();
21 }
22}
1import type { StreamResponse } from 'vovk';
2
3export type Token = { message: string };
4
5export default class StreamService {
6 static async streamTokens(resp: StreamResponse<Token>) {
7 const tokens: Token[] = [
8 { message: 'Hello,' },
9 { message: ' World' },
10 { message: ' from' },
11 { message: ' Stream' },
12 { message: '!' },
13 ];
14
15 for (const token of tokens) {
16 resp.send(token);
17 await new Promise((resolve) => setTimeout(resolve, 300));
18 }
19
20 await resp.close();
21 }
22}
1import { prefix, get, StreamResponse } from 'vovk';
2import StreamService, { type Token } from './StreamService';
3
4@prefix('stream-with-object')
5export default class StreamResponseObjectController {
6 @get('tokens')
7 static async streamTokens() {
8 // need to define CORS headers manually when returning Response instance
9 const response = new StreamResponse<Token>({
10 headers: {
11 ...StreamResponse.defaultHeaders,
12 'Access-Control-Allow-Origin': '*',
13 'Access-Control-Allow-Methods': 'GET, POST, PUT, DELETE, OPTIONS, HEAD',
14 'Access-Control-Allow-Headers': 'Content-Type, Authorization',
15 },
16 });
17
18 void StreamService.streamTokens(response);
19
20 return response;
21 }
22}
1import { prefix, get, StreamResponse } from 'vovk';
2import StreamService, { type Token } from './StreamService';
3
4@prefix('stream-with-object')
5export default class StreamResponseObjectController {
6 @get('tokens')
7 static async streamTokens() {
8 // need to define CORS headers manually when returning Response instance
9 const response = new StreamResponse<Token>({
10 headers: {
11 ...StreamResponse.defaultHeaders,
12 'Access-Control-Allow-Origin': '*',
13 'Access-Control-Allow-Methods': 'GET, POST, PUT, DELETE, OPTIONS, HEAD',
14 'Access-Control-Allow-Headers': 'Content-Type, Authorization',
15 },
16 });
17
18 void StreamService.streamTokens(response);
19
20 return response;
21 }
22}
1import { prefix, get, StreamResponse } from 'vovk';
2import StreamService, { type Token } from './StreamService';
3
4@prefix('stream-with-object')
5export default class StreamResponseObjectController {
6 @get('tokens')
7 static async streamTokens() {
8 // need to define CORS headers manually when returning Response instance
9 const response = new StreamResponse<Token>({
10 headers: {
11 ...StreamResponse.defaultHeaders,
12 'Access-Control-Allow-Origin': '*',
13 'Access-Control-Allow-Methods': 'GET, POST, PUT, DELETE, OPTIONS, HEAD',
14 'Access-Control-Allow-Headers': 'Content-Type, Authorization',
15 },
16 });
17
18 void StreamService.streamTokens(response);
19
20 return response;
21 }
22}
1import { prefix, get, StreamResponse } from 'vovk';
2import StreamService, { type Token } from './StreamService';
3
4@prefix('stream-with-object')
5export default class StreamResponseObjectController {
6 @get('tokens')
7 static async streamTokens() {
8 // need to define CORS headers manually when returning Response instance
9 const response = new StreamResponse<Token>({
10 headers: {
11 ...StreamResponse.defaultHeaders,
12 'Access-Control-Allow-Origin': '*',
13 'Access-Control-Allow-Methods': 'GET, POST, PUT, DELETE, OPTIONS, HEAD',
14 'Access-Control-Allow-Headers': 'Content-Type, Authorization',
15 },
16 });
17
18 void StreamService.streamTokens(response);
19
20 return response;
21 }
22}
1'use client';
2import { useState } from 'react';
3import { StreamResponseObjectController } from 'vovk-client';
4import type { VovkYieldType } from 'vovk';
5
6export default function StreamExample() {
7 const [tokens, setTokens] = useState<VovkYieldType<typeof StreamResponseObjectController.streamTokens>[]>([]);
8
9 return (
10 <>
11 <button
12 onClick={async () => {
13 setTokens([]);
14 using stream = await StreamResponseObjectController.streamTokens();
15 for await (const token of stream) {
16 setTokens((tokens) => [...tokens, token]);
17 }
18 }}
19 >
20 Get Streamed Greeting from Server
21 </button>
22 <div>
23 {tokens.map(({ message }, i) => (
24 <span key={i}>{message}</span>
25 ))}
26 </div>
27 </>
28 );
29}
1'use client';
2import { useState } from 'react';
3import { StreamResponseObjectController } from 'vovk-client';
4import type { VovkYieldType } from 'vovk';
5
6export default function StreamExample() {
7 const [tokens, setTokens] = useState<VovkYieldType<typeof StreamResponseObjectController.streamTokens>[]>([]);
8
9 return (
10 <>
11 <button
12 onClick={async () => {
13 setTokens([]);
14 using stream = await StreamResponseObjectController.streamTokens();
15 for await (const token of stream) {
16 setTokens((tokens) => [...tokens, token]);
17 }
18 }}
19 >
20 Get Streamed Greeting from Server
21 </button>
22 <div>
23 {tokens.map(({ message }, i) => (
24 <span key={i}>{message}</span>
25 ))}
26 </div>
27 </>
28 );
29}
1'use client';
2import { useState } from 'react';
3import { StreamResponseObjectController } from 'vovk-client';
4import type { VovkYieldType } from 'vovk';
5
6export default function StreamExample() {
7 const [tokens, setTokens] = useState<VovkYieldType<typeof StreamResponseObjectController.streamTokens>[]>([]);
8
9 return (
10 <>
11 <button
12 onClick={async () => {
13 setTokens([]);
14 using stream = await StreamResponseObjectController.streamTokens();
15 for await (const token of stream) {
16 setTokens((tokens) => [...tokens, token]);
17 }
18 }}
19 >
20 Get Streamed Greeting from Server
21 </button>
22 <div>
23 {tokens.map(({ message }, i) => (
24 <span key={i}>{message}</span>
25 ))}
26 </div>
27 </>
28 );
29}
1'use client';
2import { useState } from 'react';
3import { StreamResponseObjectController } from 'vovk-client';
4import type { VovkYieldType } from 'vovk';
5
6export default function StreamExample() {
7 const [tokens, setTokens] = useState<VovkYieldType<typeof StreamResponseObjectController.streamTokens>[]>([]);
8
9 return (
10 <>
11 <button
12 onClick={async () => {
13 setTokens([]);
14 using stream = await StreamResponseObjectController.streamTokens();
15 for await (const token of stream) {
16 setTokens((tokens) => [...tokens, token]);
17 }
18 }}
19 >
20 Get Streamed Greeting from Server
21 </button>
22 <div>
23 {tokens.map(({ message }, i) => (
24 <span key={i}>{message}</span>
25 ))}
26 </div>
27 </>
28 );
29}