Skip to content

Commit 89df9be

Browse files
authored
fix: propagate duplex transform sink errors (#8)
Sink errors were either getting smothered or causing unhandled promise rejections depending on your platform. This breaks on Chrome when creating an abortable-iterator from a duplex transform stream that you then try to abort. Instead if the sink of a duplex stream being used as a transform returns a promise, propagate errors thrown by the sink into it's source so they can be caught and handled by the consumer.
1 parent 45859d3 commit 89df9be

File tree

3 files changed

+40
-2
lines changed

3 files changed

+40
-2
lines changed

package.json

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -120,11 +120,14 @@
120120
"license": "MIT",
121121
"devDependencies": {
122122
"aegir": "^36.1.3",
123+
"delay": "^5.0.0",
123124
"it-all": "^1.0.6",
124125
"it-drain": "^1.0.5",
125126
"streaming-iterables": "^6.0.0"
126127
},
127128
"dependencies": {
129+
"it-merge": "^1.0.4",
130+
"it-pushable": "^2.0.0",
128131
"it-stream-types": "^1.0.3"
129132
},
130133
"repository": {

src/index.ts

Lines changed: 15 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,3 +1,5 @@
1+
import { pushable } from 'it-pushable'
2+
import merge from 'it-merge'
13
import type * as it from 'it-stream-types'
24

35
export const rawPipe = (...fns: any) => {
@@ -22,7 +24,19 @@ export const isDuplex = <TSource, TSink = TSource, RSink = Promise<void>> (obj:
2224

2325
const duplexPipelineFn = <TSource> (duplex: any) => {
2426
return (source: any): it.Source<TSource> => {
25-
duplex.sink(source) // TODO: error on sink side is unhandled rejection - this is the same as pull streams
27+
const p = duplex.sink(source)
28+
29+
if (p.then != null) {
30+
const stream = pushable<TSource>()
31+
p.then(() => {
32+
stream.end()
33+
}, (err: Error) => {
34+
stream.end(err)
35+
})
36+
37+
return merge(stream, duplex.source)
38+
}
39+
2640
return duplex.source
2741
}
2842
}

test/index.spec.ts

Lines changed: 22 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -3,7 +3,8 @@ import { pipe } from '../src/index.js'
33
import all from 'it-all'
44
import drain from 'it-drain'
55
import { filter, collect, consume } from 'streaming-iterables'
6-
import type { Duplex } from 'it-stream-types'
6+
import delay from 'delay'
7+
import type { Duplex, Source } from 'it-stream-types'
78

89
const oneTwoThree = () => [1, 2, 3]
910

@@ -116,4 +117,24 @@ describe('it-pipe', () => {
116117

117118
expect(result).to.be.undefined()
118119
})
120+
121+
it('should propagate duplex transform sink errors', async () => {
122+
const err = new Error('Aaargh')
123+
124+
await expect(
125+
pipe(
126+
oneTwoThree, {
127+
source: (async function * () {
128+
await delay(1000)
129+
yield 5
130+
}()),
131+
sink: async (source: Source<number>) => {
132+
await delay(20)
133+
throw err
134+
}
135+
},
136+
async (source) => await drain(source)
137+
)
138+
).to.eventually.be.rejected.with.property('message', err.message)
139+
})
119140
})

0 commit comments

Comments
 (0)