spiceflow 1.1.7 → 1.1.9
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 +177 -92
- package/dist/benchmark.benchmark.js.map +1 -1
- package/dist/client/errors.d.ts.map +1 -1
- package/dist/client/errors.js.map +1 -1
- package/dist/client/index.d.ts.map +1 -1
- package/dist/client/index.js +8 -12
- package/dist/client/index.js.map +1 -1
- package/dist/client/types.d.ts.map +1 -1
- package/dist/client/utils.js.map +1 -1
- package/dist/client/ws.d.ts.map +1 -1
- package/dist/client/ws.js +1 -3
- package/dist/client/ws.js.map +1 -1
- package/dist/client.test.js.map +1 -1
- package/dist/context.d.ts.map +1 -1
- package/dist/cors.d.ts.map +1 -1
- package/dist/cors.js.map +1 -1
- package/dist/cors.test.js.map +1 -1
- package/dist/error.d.ts.map +1 -1
- package/dist/error.js.map +1 -1
- package/dist/middleware.test.js +65 -0
- package/dist/middleware.test.js.map +1 -1
- package/dist/openapi.d.ts.map +1 -1
- package/dist/openapi.js +1 -1
- package/dist/openapi.js.map +1 -1
- package/dist/openapi.test.js.map +1 -1
- package/dist/spiceflow.d.ts.map +1 -1
- package/dist/spiceflow.js +12 -5
- package/dist/spiceflow.js.map +1 -1
- package/dist/spiceflow.test.js.map +1 -1
- package/dist/stream.test.js +6 -6
- package/dist/stream.test.js.map +1 -1
- package/dist/types.d.ts +1 -1
- package/dist/types.d.ts.map +1 -1
- package/dist/types.js.map +1 -1
- package/dist/types.test.js +56 -6
- package/dist/types.test.js.map +1 -1
- package/dist/utils.d.ts.map +1 -1
- package/dist/utils.js.map +1 -1
- package/dist/zod.test.js.map +1 -1
- package/package.json +1 -1
- package/src/benchmark.benchmark.ts +8 -8
- package/src/client/errors.ts +17 -17
- package/src/client/index.ts +437 -469
- package/src/client/types.ts +168 -191
- package/src/client/utils.ts +5 -5
- package/src/client/ws.ts +87 -89
- package/src/client.test.ts +176 -183
- package/src/context.ts +82 -82
- package/src/cors.test.ts +38 -38
- package/src/cors.ts +87 -92
- package/src/error.ts +13 -13
- package/src/middleware.test.ts +221 -149
- package/src/openapi.test.ts +97 -97
- package/src/openapi.ts +365 -365
- package/src/spiceflow.test.ts +461 -467
- package/src/spiceflow.ts +1117 -1157
- package/src/stream.test.ts +310 -310
- package/src/types.test.ts +59 -39
- package/src/types.ts +698 -701
- package/src/utils.ts +79 -79
- package/src/zod.test.ts +64 -64
package/src/stream.test.ts
CHANGED
|
@@ -7,336 +7,336 @@ import { Spiceflow } from './spiceflow.js'
|
|
|
7
7
|
import { req, sleep } from './utils.js'
|
|
8
8
|
|
|
9
9
|
function textEventStream(items: string[]) {
|
|
10
|
-
|
|
11
|
-
|
|
12
|
-
|
|
10
|
+
return items
|
|
11
|
+
.map((item) => `event: message\ndata: ${JSON.stringify(item)}\n\n`)
|
|
12
|
+
.join('')
|
|
13
13
|
}
|
|
14
14
|
|
|
15
15
|
function parseTextEventStreamItem(item: string) {
|
|
16
|
-
|
|
17
|
-
|
|
16
|
+
const data = item.split('data: ')[1].split('\n')[0]
|
|
17
|
+
return JSON.parse(data)
|
|
18
18
|
}
|
|
19
19
|
|
|
20
20
|
describe('Stream', () => {
|
|
21
|
-
|
|
22
|
-
|
|
21
|
+
it('handle stream', async () => {
|
|
22
|
+
const expected = ['a', 'b', 'c']
|
|
23
23
|
|
|
24
|
-
|
|
25
|
-
|
|
26
|
-
|
|
24
|
+
const app = new Spiceflow().get('/', async function* () {
|
|
25
|
+
yield 'a'
|
|
26
|
+
await sleep(10)
|
|
27
27
|
|
|
28
|
-
|
|
29
|
-
|
|
28
|
+
yield 'b'
|
|
29
|
+
await sleep(10)
|
|
30
30
|
|
|
31
|
-
|
|
32
|
-
|
|
31
|
+
yield 'c'
|
|
32
|
+
})
|
|
33
33
|
|
|
34
|
-
|
|
35
|
-
|
|
36
|
-
|
|
37
|
-
|
|
38
|
-
|
|
34
|
+
const response = await app
|
|
35
|
+
.handle(req('/'))
|
|
36
|
+
.then((x) => x.body)
|
|
37
|
+
.then((x) => {
|
|
38
|
+
if (!x) return
|
|
39
39
|
|
|
40
|
-
|
|
40
|
+
const reader = x?.getReader()
|
|
41
41
|
|
|
42
|
-
|
|
43
|
-
|
|
44
|
-
|
|
45
|
-
|
|
46
|
-
|
|
47
|
-
|
|
48
|
-
|
|
49
|
-
|
|
50
|
-
|
|
42
|
+
let acc = ''
|
|
43
|
+
const { promise, resolve } = Promise.withResolvers()
|
|
44
|
+
|
|
45
|
+
reader.read().then(function pump({ done, value }): unknown {
|
|
46
|
+
if (done) return resolve(acc)
|
|
47
|
+
|
|
48
|
+
expect(parseTextEventStreamItem(value.toString())).toBe(
|
|
49
|
+
expected.shift()!,
|
|
50
|
+
)
|
|
51
51
|
|
|
52
|
-
|
|
53
|
-
|
|
54
|
-
|
|
52
|
+
acc += value.toString()
|
|
53
|
+
return reader.read().then(pump)
|
|
54
|
+
})
|
|
55
55
|
|
|
56
|
-
|
|
57
|
-
|
|
56
|
+
return promise
|
|
57
|
+
})
|
|
58
58
|
|
|
59
|
-
|
|
60
|
-
|
|
61
|
-
|
|
62
|
-
|
|
63
|
-
|
|
64
|
-
|
|
65
|
-
|
|
59
|
+
expect(expected).toHaveLength(0)
|
|
60
|
+
expect(response).toBe(textEventStream(['a', 'b', 'c']))
|
|
61
|
+
})
|
|
62
|
+
it('handle errors after yield', async () => {
|
|
63
|
+
const app = new Spiceflow().get('/', async function* () {
|
|
64
|
+
yield 'a'
|
|
65
|
+
await sleep(10)
|
|
66
66
|
|
|
67
|
-
|
|
68
|
-
|
|
67
|
+
throw new Error('an error')
|
|
68
|
+
})
|
|
69
69
|
|
|
70
|
-
|
|
70
|
+
const response = await app.handle(req('/')).then((x) => x.text())
|
|
71
71
|
|
|
72
|
-
|
|
73
|
-
|
|
74
|
-
|
|
75
|
-
|
|
72
|
+
expect(response).toBe(
|
|
73
|
+
'event: message\ndata: "a"\n\nevent: error\ndata: "an error"\n\n',
|
|
74
|
+
)
|
|
75
|
+
})
|
|
76
76
|
|
|
77
|
-
|
|
78
|
-
|
|
79
|
-
|
|
80
|
-
|
|
81
|
-
|
|
82
|
-
|
|
83
|
-
|
|
84
|
-
|
|
77
|
+
it('handle errors before yield when aot is false', async () => {
|
|
78
|
+
const app = new Spiceflow()
|
|
79
|
+
.onError(({ error }) => {
|
|
80
|
+
return new Response(error.message)
|
|
81
|
+
})
|
|
82
|
+
.get('/', async function* () {
|
|
83
|
+
throw new Error('an error xxxx')
|
|
84
|
+
})
|
|
85
85
|
|
|
86
|
-
|
|
86
|
+
const response = await app.handle(req('/')).then((x) => x.text())
|
|
87
87
|
|
|
88
|
-
|
|
89
|
-
|
|
88
|
+
expect(response).toContain('an error')
|
|
89
|
+
})
|
|
90
90
|
|
|
91
|
-
|
|
92
|
-
|
|
93
|
-
|
|
94
|
-
|
|
95
|
-
|
|
96
|
-
|
|
97
|
-
|
|
98
|
-
|
|
99
|
-
|
|
100
|
-
|
|
101
|
-
|
|
102
|
-
|
|
103
|
-
|
|
104
|
-
|
|
105
|
-
|
|
106
|
-
|
|
107
|
-
|
|
108
|
-
|
|
109
|
-
|
|
110
|
-
|
|
111
|
-
|
|
112
|
-
|
|
113
|
-
|
|
114
|
-
|
|
115
|
-
|
|
116
|
-
|
|
117
|
-
|
|
118
|
-
|
|
119
|
-
|
|
120
|
-
|
|
121
|
-
|
|
122
|
-
|
|
123
|
-
|
|
124
|
-
|
|
125
|
-
|
|
126
|
-
|
|
127
|
-
|
|
128
|
-
|
|
129
|
-
|
|
130
|
-
|
|
131
|
-
|
|
132
|
-
|
|
133
|
-
|
|
134
|
-
|
|
135
|
-
|
|
136
|
-
|
|
137
|
-
|
|
138
|
-
|
|
139
|
-
|
|
140
|
-
|
|
141
|
-
|
|
142
|
-
|
|
143
|
-
|
|
144
|
-
|
|
145
|
-
|
|
146
|
-
|
|
147
|
-
|
|
148
|
-
|
|
149
|
-
|
|
150
|
-
|
|
151
|
-
|
|
152
|
-
|
|
153
|
-
|
|
154
|
-
|
|
155
|
-
|
|
156
|
-
|
|
157
|
-
|
|
158
|
-
|
|
159
|
-
|
|
160
|
-
|
|
161
|
-
|
|
162
|
-
|
|
163
|
-
|
|
164
|
-
|
|
165
|
-
|
|
166
|
-
|
|
167
|
-
|
|
168
|
-
|
|
169
|
-
|
|
170
|
-
|
|
171
|
-
|
|
172
|
-
|
|
173
|
-
|
|
174
|
-
|
|
175
|
-
|
|
176
|
-
|
|
177
|
-
|
|
178
|
-
|
|
179
|
-
|
|
180
|
-
|
|
181
|
-
|
|
182
|
-
|
|
183
|
-
|
|
184
|
-
|
|
185
|
-
|
|
186
|
-
|
|
187
|
-
|
|
188
|
-
|
|
189
|
-
|
|
190
|
-
|
|
191
|
-
|
|
192
|
-
|
|
193
|
-
|
|
194
|
-
|
|
195
|
-
|
|
196
|
-
|
|
197
|
-
|
|
198
|
-
|
|
199
|
-
|
|
200
|
-
|
|
201
|
-
|
|
202
|
-
|
|
203
|
-
|
|
204
|
-
|
|
205
|
-
|
|
206
|
-
|
|
207
|
-
|
|
208
|
-
|
|
209
|
-
|
|
210
|
-
|
|
211
|
-
|
|
212
|
-
|
|
213
|
-
|
|
214
|
-
|
|
215
|
-
|
|
216
|
-
|
|
217
|
-
|
|
218
|
-
|
|
219
|
-
|
|
220
|
-
|
|
221
|
-
|
|
222
|
-
|
|
223
|
-
|
|
224
|
-
|
|
225
|
-
|
|
226
|
-
|
|
227
|
-
|
|
228
|
-
|
|
229
|
-
|
|
230
|
-
|
|
231
|
-
|
|
232
|
-
|
|
233
|
-
|
|
234
|
-
|
|
235
|
-
|
|
236
|
-
|
|
237
|
-
|
|
238
|
-
|
|
239
|
-
|
|
240
|
-
|
|
241
|
-
|
|
242
|
-
|
|
243
|
-
|
|
244
|
-
|
|
245
|
-
|
|
246
|
-
|
|
247
|
-
|
|
248
|
-
|
|
249
|
-
|
|
250
|
-
|
|
251
|
-
|
|
252
|
-
|
|
253
|
-
|
|
254
|
-
|
|
255
|
-
|
|
256
|
-
|
|
257
|
-
|
|
258
|
-
|
|
259
|
-
|
|
260
|
-
|
|
261
|
-
|
|
262
|
-
|
|
263
|
-
|
|
264
|
-
|
|
265
|
-
|
|
266
|
-
|
|
267
|
-
|
|
268
|
-
|
|
269
|
-
|
|
270
|
-
|
|
271
|
-
|
|
272
|
-
|
|
273
|
-
|
|
274
|
-
|
|
275
|
-
|
|
276
|
-
|
|
277
|
-
|
|
278
|
-
|
|
279
|
-
|
|
280
|
-
|
|
281
|
-
|
|
282
|
-
|
|
283
|
-
|
|
284
|
-
|
|
285
|
-
|
|
286
|
-
|
|
287
|
-
|
|
288
|
-
|
|
289
|
-
|
|
290
|
-
|
|
291
|
-
|
|
292
|
-
|
|
293
|
-
|
|
294
|
-
|
|
295
|
-
|
|
296
|
-
|
|
297
|
-
|
|
298
|
-
|
|
299
|
-
|
|
300
|
-
|
|
301
|
-
|
|
302
|
-
|
|
303
|
-
|
|
304
|
-
|
|
305
|
-
|
|
306
|
-
|
|
307
|
-
|
|
308
|
-
|
|
309
|
-
|
|
310
|
-
|
|
311
|
-
|
|
312
|
-
|
|
313
|
-
|
|
314
|
-
|
|
315
|
-
|
|
316
|
-
|
|
317
|
-
|
|
318
|
-
|
|
319
|
-
|
|
320
|
-
|
|
321
|
-
|
|
322
|
-
|
|
323
|
-
|
|
324
|
-
|
|
325
|
-
|
|
326
|
-
|
|
327
|
-
|
|
328
|
-
|
|
329
|
-
|
|
330
|
-
|
|
331
|
-
|
|
332
|
-
|
|
333
|
-
|
|
334
|
-
|
|
335
|
-
|
|
336
|
-
|
|
337
|
-
|
|
338
|
-
|
|
339
|
-
|
|
340
|
-
|
|
341
|
-
|
|
91
|
+
it.todo('handle errors before yield when aot is true', async () => {
|
|
92
|
+
const app = new Spiceflow()
|
|
93
|
+
.onError(({ error }) => {
|
|
94
|
+
return new Response(error.message)
|
|
95
|
+
})
|
|
96
|
+
.get('/', async function* () {
|
|
97
|
+
throw new Error('an error')
|
|
98
|
+
})
|
|
99
|
+
|
|
100
|
+
const response = await app.handle(req('/')).then((x) => x.text())
|
|
101
|
+
|
|
102
|
+
expect(response).toContain('an error')
|
|
103
|
+
})
|
|
104
|
+
|
|
105
|
+
it.todo('handle errors before yield with onError', async () => {
|
|
106
|
+
const expected = 'error expected'
|
|
107
|
+
const app = new Spiceflow()
|
|
108
|
+
.onError(({}) => {
|
|
109
|
+
return new Response(expected)
|
|
110
|
+
})
|
|
111
|
+
.get('/', async function* () {
|
|
112
|
+
throw new Error('an error')
|
|
113
|
+
})
|
|
114
|
+
|
|
115
|
+
const response = await app.handle(req('/')).then((x) => x.text())
|
|
116
|
+
|
|
117
|
+
expect(response).toBe(expected)
|
|
118
|
+
})
|
|
119
|
+
|
|
120
|
+
it('stop stream on canceled request', async () => {
|
|
121
|
+
const expected = ['a', 'b']
|
|
122
|
+
|
|
123
|
+
const app = new Spiceflow().get('/', async function* () {
|
|
124
|
+
yield 'a'
|
|
125
|
+
await sleep(10)
|
|
126
|
+
|
|
127
|
+
yield 'b'
|
|
128
|
+
await sleep(10)
|
|
129
|
+
|
|
130
|
+
yield 'c'
|
|
131
|
+
})
|
|
132
|
+
|
|
133
|
+
const controller = new AbortController()
|
|
134
|
+
|
|
135
|
+
setTimeout(() => {
|
|
136
|
+
controller.abort()
|
|
137
|
+
}, 15)
|
|
138
|
+
|
|
139
|
+
const response = await app
|
|
140
|
+
.handle(
|
|
141
|
+
new Request('http://e.ly', {
|
|
142
|
+
signal: controller.signal,
|
|
143
|
+
}),
|
|
144
|
+
)
|
|
145
|
+
.then((x) => x.body)
|
|
146
|
+
.then((x) => {
|
|
147
|
+
if (!x) return
|
|
148
|
+
|
|
149
|
+
const reader = x?.getReader()
|
|
150
|
+
|
|
151
|
+
let acc = ''
|
|
152
|
+
const { promise, resolve } = Promise.withResolvers()
|
|
153
|
+
|
|
154
|
+
reader.read().then(function pump({ done, value }): unknown {
|
|
155
|
+
if (done) {
|
|
156
|
+
return resolve(acc)
|
|
157
|
+
}
|
|
158
|
+
|
|
159
|
+
expect(parseTextEventStreamItem(value.toString())).toBe(
|
|
160
|
+
expected.shift()!,
|
|
161
|
+
)
|
|
162
|
+
|
|
163
|
+
acc += value.toString()
|
|
164
|
+
return reader.read().then(pump)
|
|
165
|
+
})
|
|
166
|
+
|
|
167
|
+
return promise
|
|
168
|
+
})
|
|
169
|
+
|
|
170
|
+
expect(expected).toHaveLength(0)
|
|
171
|
+
expect(response).toBe(textEventStream(['a', 'b']))
|
|
172
|
+
})
|
|
173
|
+
|
|
174
|
+
// it('mutate set before yield is called', async () => {
|
|
175
|
+
// const expected = ['a', 'b', 'c']
|
|
176
|
+
|
|
177
|
+
// const app = new Spiceflow().get('/', function* () {
|
|
178
|
+
// set.headers['access-control-allow-origin'] = 'http://saltyaom.com'
|
|
179
|
+
|
|
180
|
+
// yield 'a'
|
|
181
|
+
// yield 'b'
|
|
182
|
+
// yield 'c'
|
|
183
|
+
// })
|
|
184
|
+
|
|
185
|
+
// const response = await app.handle(req('/')).then((x) => x.headers)
|
|
186
|
+
|
|
187
|
+
// expect(response.get('access-control-allow-origin')).toBe(
|
|
188
|
+
// 'http://saltyaom.com'
|
|
189
|
+
// )
|
|
190
|
+
// })
|
|
191
|
+
it('handle stream with objects', async () => {
|
|
192
|
+
const objects = [
|
|
193
|
+
{ message: 'hello' },
|
|
194
|
+
{ response: 'world' },
|
|
195
|
+
{ data: [1, 2, 3] },
|
|
196
|
+
{ result: [4, 5, 6] },
|
|
197
|
+
]
|
|
198
|
+
const app = new Spiceflow().get('/', async function* ({}) {
|
|
199
|
+
for (const obj of objects) {
|
|
200
|
+
yield obj
|
|
201
|
+
}
|
|
202
|
+
})
|
|
203
|
+
|
|
204
|
+
const body = await app.handle(req('/')).then((x) => x.body)
|
|
205
|
+
|
|
206
|
+
let events = [] as any[]
|
|
207
|
+
const parser = createParser((event) => {
|
|
208
|
+
events.push(event)
|
|
209
|
+
})
|
|
210
|
+
const { promise, resolve } = Promise.withResolvers<void>()
|
|
211
|
+
const reader = body?.getReader()!
|
|
212
|
+
|
|
213
|
+
reader.read().then(function pump({ done, value }): unknown {
|
|
214
|
+
if (done) {
|
|
215
|
+
return resolve()
|
|
216
|
+
}
|
|
217
|
+
const text = value.toString()
|
|
218
|
+
parser.feed(text)
|
|
219
|
+
return reader.read().then(pump)
|
|
220
|
+
})
|
|
221
|
+
await promise
|
|
222
|
+
|
|
223
|
+
expect(events.map((x) => x.data)).toEqual(
|
|
224
|
+
objects.map((x) => JSON.stringify(x)),
|
|
225
|
+
)
|
|
226
|
+
})
|
|
227
|
+
|
|
228
|
+
// it('mutate set before yield is called', async () => {
|
|
229
|
+
// const expected = ['a', 'b', 'c']
|
|
230
|
+
|
|
231
|
+
// const app = new Spiceflow().get('/', function* () {
|
|
232
|
+
// set.headers['access-control-allow-origin'] = 'http://saltyaom.com'
|
|
233
|
+
|
|
234
|
+
// yield 'a'
|
|
235
|
+
// yield 'b'
|
|
236
|
+
// yield 'c'
|
|
237
|
+
// })
|
|
238
|
+
|
|
239
|
+
// const response = await app.handle(req('/')).then((x) => x.headers)
|
|
240
|
+
|
|
241
|
+
// expect(response.get('access-control-allow-origin')).toBe(
|
|
242
|
+
// 'http://saltyaom.com'
|
|
243
|
+
// )
|
|
244
|
+
// })
|
|
245
|
+
|
|
246
|
+
// it('async mutate set before yield is called', async () => {
|
|
247
|
+
// const expected = ['a', 'b', 'c']
|
|
248
|
+
|
|
249
|
+
// const app = new Spiceflow().get('/', async function* () {
|
|
250
|
+
// set.headers['access-control-allow-origin'] = 'http://saltyaom.com'
|
|
251
|
+
|
|
252
|
+
// yield 'a'
|
|
253
|
+
// yield 'b'
|
|
254
|
+
// yield 'c'
|
|
255
|
+
// })
|
|
256
|
+
|
|
257
|
+
// const response = await app.handle(req('/')).then((x) => x.headers)
|
|
258
|
+
|
|
259
|
+
// expect(response.get('access-control-allow-origin')).toBe(
|
|
260
|
+
// 'http://saltyaom.com'
|
|
261
|
+
// )
|
|
262
|
+
// })
|
|
263
|
+
|
|
264
|
+
it('return value if not yield', async () => {
|
|
265
|
+
const app = new Spiceflow()
|
|
266
|
+
.get('/', function* () {
|
|
267
|
+
return 'hello'
|
|
268
|
+
})
|
|
269
|
+
.get('/json', function* () {
|
|
270
|
+
return { hello: 'world' }
|
|
271
|
+
})
|
|
272
|
+
|
|
273
|
+
const response = await Promise.all([
|
|
274
|
+
app.handle(req('/')),
|
|
275
|
+
app.handle(req('/json')),
|
|
276
|
+
])
|
|
277
|
+
|
|
278
|
+
expect(await response[0].text()).toBe('"hello"')
|
|
279
|
+
expect(await response[1].json()).toEqual({
|
|
280
|
+
hello: 'world',
|
|
281
|
+
})
|
|
282
|
+
})
|
|
283
|
+
|
|
284
|
+
it('return async value if not yield', async () => {
|
|
285
|
+
const app = new Spiceflow()
|
|
286
|
+
.get('/', function* () {
|
|
287
|
+
return 'hello'
|
|
288
|
+
})
|
|
289
|
+
.get('/json', function* () {
|
|
290
|
+
return { hello: 'world' }
|
|
291
|
+
})
|
|
292
|
+
|
|
293
|
+
const response = await Promise.all([
|
|
294
|
+
app.handle(req('/')),
|
|
295
|
+
app.handle(req('/json')),
|
|
296
|
+
])
|
|
297
|
+
|
|
298
|
+
expect(await response[0].text()).toBe('"hello"')
|
|
299
|
+
expect(await response[1].json()).toEqual({
|
|
300
|
+
hello: 'world',
|
|
301
|
+
})
|
|
302
|
+
})
|
|
303
|
+
|
|
304
|
+
it('handle object and array', async () => {
|
|
305
|
+
const expected = [{ a: 'b' }, ['a'], ['a', 1, { a: 'b' }]]
|
|
306
|
+
const expectedResponse = JSON.stringify([...expected])
|
|
307
|
+
let i = 0
|
|
308
|
+
|
|
309
|
+
const app = new Spiceflow().get('/', async function* () {
|
|
310
|
+
yield expected[0]
|
|
311
|
+
await sleep(10)
|
|
312
|
+
|
|
313
|
+
yield expected[1]
|
|
314
|
+
await sleep(10)
|
|
315
|
+
|
|
316
|
+
yield expected[2]
|
|
317
|
+
})
|
|
318
|
+
|
|
319
|
+
const response = await app
|
|
320
|
+
.handle(req('/'))
|
|
321
|
+
.then((x) => x.body)
|
|
322
|
+
.then((x) => {
|
|
323
|
+
if (!x) return
|
|
324
|
+
|
|
325
|
+
const reader = x?.getReader()
|
|
326
|
+
|
|
327
|
+
const { promise, resolve } = Promise.withResolvers<void>()
|
|
328
|
+
|
|
329
|
+
reader.read().then(function pump({ done, value }): unknown {
|
|
330
|
+
if (done) return resolve()
|
|
331
|
+
|
|
332
|
+
expect(parseTextEventStreamItem(value.toString())).toEqual(
|
|
333
|
+
expected[i++],
|
|
334
|
+
)
|
|
335
|
+
|
|
336
|
+
return reader.read().then(pump)
|
|
337
|
+
})
|
|
338
|
+
|
|
339
|
+
return promise
|
|
340
|
+
})
|
|
341
|
+
})
|
|
342
342
|
})
|