diff --git a/incubation-js.md b/incubation-js.md index 557d845..1a4e60c 100644 --- a/incubation-js.md +++ b/incubation-js.md @@ -13,3 +13,7 @@ This document captures the formal architectural decisions and API designs specif * `resolvedStream` is a `ReadableStream` yielding `String` chunks. * `mapStream` is a `ReadableStream` yielding JS objects (the Index Shift Map with `hydrated-start`, `original-start`, etc.). * This avoids anti-patterns like attaching custom subfields to a single stream object and makes downstream consumer routing trivial via destructuring. +* **Synchronous Stream Composition & Detached Processing** + * **Synchronous Return (Early Return):** The core `hydrate` function must be entirely synchronous (i.e., drop the `async` keyword from the main signature). It must immediately instantiate the `ReadableStream` objects and return the `{ resolvedStream, mapStream, bodyStream }` object before any data is actually read. This is the gold standard for stream pipelines, allowing downstream consumers to synchronously wire up their entire pipeline (e.g., `.pipeTo()`) in a single execution tick without blocking `await` calls. + * **Detached Background Worker:** The actual stream consumption, chunk processing, and state machine logic must be pushed into a detached, background asynchronous function. This function is invoked by the main `hydrate` function but **never awaited**. + * **Fail-Fast Error Propagation:** Because the background worker is detached, any unhandled rejections would normally be swallowed or crash the process. The worker must wrap its logic in a `try/catch` (or append `.catch()`) so that if the source stream fails, or a template syntax error occurs, it instantly propagates the error down the pipes using `resolvedController.error(err)` and `mapController.error(err)`. This safely and immediately aborts any downstream readers.