[![Actions Status](https://github.com/bigeasy/staccato/workflows/Node%20CI/badge.svg)](https://github.com/bigeasy/staccato/actions)
[![codecov](https://codecov.io/gh/bigeasy/staccato/branch/master/graph/badge.svg)](https://codecov.io/gh/bigeasy/staccato)
[![License: MIT](https://img.shields.io/badge/License-MIT-yellow.svg)](https://opensource.org/licenses/MIT)

Write to a Node.js stream using `async`/`await`.

| What          | Where                                         |
| --- | --- |
| Discussion    | https://github.com/bigeasy/staccato/issues/1  |
| Documentation | https://bigeasy.github.io/staccato            |
| Source        | https://github.com/bigeasy/staccato           |
| Issues        | https://github.com/bigeasy/staccato/issues    |
| CI            | https://travis-ci.org/bigeasy/staccato        |
| Coverage:     | https://codecov.io/gh/bigeasy/staccato        |
| License:      | MIT                                           |

```
npm install staccato
```

```
stream.on('error', (error) => {
    console.log(error.stack)
})

const writable = new Staccato.Writable(socket)
const readable = new Staccato.Readable(socket)

const read = Buffer.alloc(0), write = Buffer.from('begin')
while (read != null && await writable.write([ write ])) {
    write = consume(read)
    read = await readable.read()
}
```

The above shows the motivation behind this library. Writing to a socket in
Node.js is relatively undocumented. The documentation says that when `write`
returns `false` you're supposed to wait for a `"drain"` event before continuing
to `write`. Staccato will do this for you in the `write` method. There hasn't
been mention that `write` will also return false when an error destroys the
stream. When the stream is destroyed there will be no `"drain"` event so waiting
on a drain will cause the program to hang. Staccato encapsulates the
drain-or-error logic.

In lieu of raising an exception, on error `Staccato.Writable.write()` will
return `false`. This is because I've found that with sockets, error management
ought to be a separate concern. The error should be handled the moment it
occurs. We should not wait until the next write to raise an exception based on
the error we detected. The error detection merely marks the `Staccato.Writable`
as destroyed. Reporting the error reporting is supposed be handled in a separate
`stream.on("error", [function])` handler that can shutdown the writing process
altogether, preventing a failed write.

The associated `Staccato.Readable` class is provided to facilitate error
handling as a separate concern. It swallows errors and returns them into
end-of-stream messages. In my code, for the most part, I'm always looking for a
truncated stream in my buffer processing, so whether the stream ends prematurely
due to a detectable file or network error, or whether it ends prematurely
because it was only partially written by the other side is doesn't matter.

More to the point in regards to `Staccato.Writable`, when a duplex stream failed
I'd find that I'd be detecting errors on both read and write, so once again it
makes more sense to have error handling be a separate concern that shuts down
the duplex stream processing from the outside of the stream processing logic.
