Skip to content
Merged
Show file tree
Hide file tree
Changes from 7 commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
4 changes: 2 additions & 2 deletions apps/content/.vitepress/config.ts
Original file line number Diff line number Diff line change
Expand Up @@ -88,7 +88,7 @@ export default withMermaid(defineConfig({
{ text: 'Context', link: '/docs/context' },
{ text: 'Error Handling', link: '/docs/error-handling' },
{ text: 'Binary Data', link: '/docs/binary-data' },
{ text: 'Event Iterator (SSE)', link: '/docs/event-iterator' },
{ text: 'AsyncIteratorObject (SSE)', link: '/docs/async-iterator-object' },
{ text: 'Metadata', link: '/docs/metadata' },
{ text: 'Playgrounds', link: '/docs/playgrounds' },
{
Expand Down Expand Up @@ -131,7 +131,7 @@ export default withMermaid(defineConfig({
{ text: 'Server-Side', link: '/docs/client/server-side' },
{ text: 'Client-Side', link: '/docs/client/client-side' },
{ text: 'Error Handling', link: '/docs/client/error-handling' },
{ text: 'Event Iterator', link: '/docs/client/event-iterator' },
{ text: 'AsyncIteratorObject (SSE)', link: '/docs/client/async-iterator-object' },
{ text: 'Dynamic Link', link: '/docs/client/dynamic-link' },
],
},
Expand Down
4 changes: 2 additions & 2 deletions apps/content/docs/adapters/fetch-api.md
Original file line number Diff line number Diff line change
Expand Up @@ -155,7 +155,7 @@ The examples above only show how to configure the link. For examples of creating

## Event Stream Options

You can configure how [event iterators](/docs/event-iterator) are streamed to the client using the `toFetchResponse.eventStream` options when creating the handler.
You can configure how an [AsyncIteratorObject](/docs/async-iterator-object) is streamed to the client using the `toFetchResponse.eventStream` options when creating the handler.

```ts
const handler = new OpenAPIHandler(router, {
Expand Down Expand Up @@ -209,5 +209,5 @@ const handler = new OpenAPIHandler(router, {
```

::: info
You can also configure how [event iterators](/docs/event-iterator) are streamed from client to server using `toFetchRequest.eventStream` options when creating the link. However, this is rarely used because streaming requests are not widely supported in browsers and may require manually overriding the `fetch` function with `duplex`.
You can also configure how an [AsyncIteratorObject](/docs/async-iterator-object) is streamed from client to server using `toFetchRequest.eventStream` options when creating the link. However, this is rarely used because streaming requests are not widely supported in browsers and may require manually overriding the `fetch` function with `duplex`.
:::
2 changes: 1 addition & 1 deletion apps/content/docs/adapters/node-http.md
Original file line number Diff line number Diff line change
Expand Up @@ -80,7 +80,7 @@ server.listen(3000, '127.0.0.1', () => console.log('Listening on 127.0.0.1:3000'

## Event Stream Options

You can configure how [event iterators](/docs/event-iterator) are streamed to the client using the `sendStandardResponse.eventStream` options when creating the handler.
You can configure how an [AsyncIteratorObject](/docs/async-iterator-object) is streamed to the client using the `sendStandardResponse.eventStream` options when creating the handler.

```ts
const handler = new OpenAPIHandler(router, {
Expand Down
Original file line number Diff line number Diff line change
@@ -1,10 +1,10 @@
# Event Iterator (SSE)
# AsyncIteratorObject (SSE)

Event Iterator enables **typesafe**, **realtime data streaming**. It is the recommended approach for building features like live notifications, chat messages, progress updates, and data feeds.
AsyncIteratorObject enables **typesafe**, **realtime data streaming**. It is the recommended approach for building features like live notifications, chat messages, progress updates, and data feeds.

## Overview

An event iterator is implemented as an [asynchronous generator function](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Statements/async_function*) (or a compatible implementation). In the example below, the handler emits a new event every second:
An `AsyncIteratorObject` is implemented as an [asynchronous generator function](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Statements/async_function*) (or a compatible implementation). In the example below, the handler emits a new event every second:

```ts
const example = os
Expand All @@ -18,18 +18,18 @@ const example = os
```

::: info
Learn how to consume event iterators from the client in the [client guide](/docs/client/event-iterator).
Learn how to consume an `AsyncIteratorObject` from the client in the [client guide](/docs/client/async-iterator-object).
:::

## Validating Events

Use the built‑in `eventIterator` helper that works with any [Standard Schema](https://standardschema.dev/schema#what-schema-libraries-implement-the-spec) library to validate events.
Use the built‑in `asyncIteratorObject` schema that works with any [Standard Schema](https://standardschema.dev/schema#what-schema-libraries-implement-the-spec) library to validate events.

```ts
import { eventIterator } from '@orpc/server'
import { asyncIteratorObject } from '@orpc/server'

const example = os
.output(eventIterator(z.object({ message: z.string() })))
.output(asyncIteratorObject(z.object({ message: z.string() })))
.handler(async function* ({ input, signal, lastEventId }) {
while (true) {
signal?.throwIfAborted()
Expand Down Expand Up @@ -68,7 +68,7 @@ const example = os
})
```

## Stop Event Iterator
## Stop AsyncIteratorObject

To end the stream, use either a `return` or `throw` statement. oRPC marks the stream as completed when the handler returns.

Expand Down Expand Up @@ -114,7 +114,7 @@ const example = os

## Publisher Helper

You can combine the event iterator with the [Publisher Helper](/docs/helpers/publisher) to build real-time features like chat, notifications, or live updates with resume support.
You can combine the [AsyncIteratorObject](/docs/async-iterator-object) with the [Publisher Helper](/docs/helpers/publisher) to build real-time features like chat, notifications, or live updates with resume support.

```ts
const publisher = new MemoryPublisher<{
Expand Down
2 changes: 1 addition & 1 deletion apps/content/docs/binary-data.md
Original file line number Diff line number Diff line change
Expand Up @@ -30,7 +30,7 @@ const example = os
})
```

## `ReadableStream<Uint8Array>`
## ReadableStream\<Uint8Array\>

Procedures can return `ReadableStream<Uint8Array>` to stream binary responses. The example below uses the [Response Headers Plugin](/docs/plugins/response-headers) to set the appropriate `Content-Type` header.

Expand Down
Original file line number Diff line number Diff line change
@@ -1,15 +1,15 @@
# Event Iterator in Client
# AsyncIteratorObject in Client

Consume an [Event Iterator](/docs/event-iterator) like an [AsyncGenerator](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/AsyncGenerator). Await the call, then iterate over events as they arrive.
Consume an [AsyncIteratorObject](/docs/async-iterator-object) like an [AsyncGenerator](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/AsyncGenerator). Await the call, then iterate over events as they arrive.

## Basic Usage

```ts twoslash
import { eventIterator, oc, RouterContractClient } from '@orpc/contract'
import { asyncIteratorObject, oc, RouterContractClient } from '@orpc/contract'
import { z } from 'zod'

const contract = {
streaming: oc.output(eventIterator(z.object({ message: z.string() })))
streaming: oc.output(asyncIteratorObject(z.object({ message: z.string() })))
}

declare const client: RouterContractClient<typeof contract>
Expand Down Expand Up @@ -44,7 +44,7 @@ for await (const event of iterator) {
## Error Handling

::: info
Unlike traditional SSE, Event Iterators do not retry automatically after an error. To add retries, use the [Retry Plugin](/docs/plugins/retry#event-source-simulation).
Unlike traditional SSE, AsyncIteratorObjects do not retry automatically after an error. To add retries, use the [Retry Plugin](/docs/plugins/retry#event-source-simulation).
:::

```ts
Expand Down Expand Up @@ -77,14 +77,14 @@ for await (const event of iterator) {
}
```

## Using `consumeEventIterator`
## Using `consumeAsyncIterator`

Use `consumeEventIterator` to consume an event iterator with lifecycle callbacks. It accepts either an event iterator or a promise that resolves to one.
Use `consumeAsyncIterator` to consume an `AsyncIterator` with lifecycle callbacks. It accepts either an iterator or a promise that resolves to one.

```ts
import { consumeEventIterator } from '@orpc/client'
import { consumeAsyncIterator } from '@orpc/client'

const cancel = consumeEventIterator(client.streaming(), {
const cancel = consumeAsyncIterator(client.streaming(), {
onEvent: (event) => {
console.log(event.message)
},
Expand Down
2 changes: 1 addition & 1 deletion apps/content/docs/integrations/nest.md
Original file line number Diff line number Diff line change
Expand Up @@ -221,7 +221,7 @@ Procedures run only when a matching NestJS controller method is called. If no ro

### Event Stream Options

Configure how [event iterators](/docs/event-iterator) are streamed to the client using the `toNestResponse.eventStream` options.
Configure how an [AsyncIteratorObject](/docs/async-iterator-object) is streamed to the client using the `toNestResponse.eventStream` options.

```ts
@Module({
Expand Down
2 changes: 1 addition & 1 deletion apps/content/docs/integrations/opentelemetry.md
Original file line number Diff line number Diff line change
Expand Up @@ -120,7 +120,7 @@ Define the `name` property on your middleware to improve span naming and make tr

## Capture Abort Signals

If your application heavily uses [Event Iterator](/docs/event-iterator) or similar streaming patterns, we recommend capturing an event when the `signal` is aborted to properly track and detach unexpected long-running operations:
If your application heavily uses [AsyncIteratorObject](/docs/async-iterator-object) or similar streaming patterns, we recommend capturing an event when the `signal` is aborted to properly track and detach unexpected long-running operations:

```ts
import { trace } from '@opentelemetry/api'
Expand Down
4 changes: 2 additions & 2 deletions apps/content/docs/integrations/tanstack-query.md
Original file line number Diff line number Diff line change
Expand Up @@ -89,7 +89,7 @@ const query = useQuery(orpc.planet.find.queryOptions({

## Streamed Query Options

Use `.streamedOptions` to build streamed query options for [Event Iterator](/docs/event-iterator). The resulting data is an array of events, and each new event is appended as it arrives.
Use `.streamedOptions` to build streamed query options for an [AsyncIteratorObject](/docs/async-iterator-object). The resulting data is an array of events, and each new event is appended as it arrives.

It works with `useQuery`, `useSuspenseQuery`, and `prefetchQuery`, and any other API that accepts query options.

Expand Down Expand Up @@ -117,7 +117,7 @@ const query = useQuery(orpc.streamed.streamedOptions({

## Live Query Options

Use `.liveOptions` to build live query options for [Event Iterator](/docs/event-iterator). The data always reflects the latest event, replacing the previous value whenever a new one arrives.
Use `.liveOptions` to build live query options for an [AsyncIteratorObject](/docs/async-iterator-object). The data always reflects the latest event, replacing the previous value whenever a new one arrives.

It works with `useQuery`, `useSuspenseQuery`, and `prefetchQuery`, and any other API that accepts query options.

Expand Down
2 changes: 1 addition & 1 deletion apps/content/docs/openapi/handler.md
Original file line number Diff line number Diff line change
Expand Up @@ -223,7 +223,7 @@ If you use `OpenAPILink` with a custom server-side error format, make sure to co

## Event Stream Options

Configure how [event iterators](/docs/event-iterator) are streamed to the client. Available options depend on the adapter. For example, the fetch adapter supports:
Configure how an [AsyncIteratorObject](/docs/async-iterator-object) is streamed to the client. Available options depend on the adapter. For example, the fetch adapter supports:

```ts
const handler = new OpenAPIHandler(router, {
Expand Down
18 changes: 9 additions & 9 deletions apps/content/docs/openapi/input-and-output-mapping.md
Original file line number Diff line number Diff line change
Expand Up @@ -218,15 +218,15 @@ const uploadLargeFile = os

Supported body hints:

| Hint | Parsed Result |
| ------------------- | --------------------------------------------------------------------------------- |
| `json` | JSON value |
| `form-data` | `FormData` decoded with [bracket notation](/docs/openapi/bracket-notation) |
| `url-search-params` | `URLSearchParams` decoded with [bracket notation](/docs/openapi/bracket-notation) |
| `event-stream` | [Event Iterator](/docs/event-iterator) |
| `octet-stream` | `ReadableStream<Uint8Array>` for streamed binary data |
| `file` | `File` for binary data |
| `none` | `undefined` |
| Hint | Parsed Result |
| ------------------- | --------------------------------------------------------------------------------------------------- |
| `json` | JSON value |
| `form-data` | `FormData` decoded with [bracket notation](/docs/openapi/bracket-notation) |
| `url-search-params` | `URLSearchParams` decoded with [bracket notation](/docs/openapi/bracket-notation) |
| `event-stream` | [AsyncIteratorObject](/docs/async-iterator-object) |
| `octet-stream` | [ReadableStream\<Uint8Array\>](/docs/binary-data#readablestreamuint8array) for streamed binary data |
| `file` | `File` for binary data |
| `none` | `undefined` |

::: info
Learn more about body hints in the [Standard Server documentation](https://github.com/middleapi/standardserver#standard-body)
Expand Down
2 changes: 1 addition & 1 deletion apps/content/docs/openapi/link.md
Original file line number Diff line number Diff line change
Expand Up @@ -258,7 +258,7 @@ const link = new OpenAPILink(contract, {

## Event Stream Options

Configure how [event iterators](/docs/event-iterator) are streamed to the server. Available options depend on the adapter. For example, the fetch adapter supports:
Configure how an [AsyncIteratorObject](/docs/async-iterator-object) is streamed to the server. Available options depend on the adapter. For example, the fetch adapter supports:

```ts
const link = new OpenAPILink(contract, {
Expand Down
44 changes: 22 additions & 22 deletions apps/content/docs/openapi/serializer.md
Original file line number Diff line number Diff line change
Expand Up @@ -6,26 +6,26 @@ OpenAPI Serializers handle one-way serialization to JSON-friendly formats. They

`OpenAPISerializer` supports the following types by default:

| Type | Handler key | Serialized | Notes |
| ---------------------------------------- | ----------- | ------------------ | ----------------------------- |
| **string** | | | |
| **number** | | | |
| **NaN** | `nan` | `null` | |
| **boolean** | | | |
| **null** | | | |
| **undefined** | `undefined` | `null` | Ignore `undefined` properties |
| **Date** | `date` | ISO String, `null` | |
| **BigInt** | `bigint` | string | |
| **RegExp** | `regexp` | string | |
| **URL** | `url` | string | |
| **Record (object)** | | | `toJSON` methods are ignored |
| **Array** | | | |
| **Set** | `set` | array | |
| **Map** | `map` | array | |
| **Blob** | | | Unsupported in Event Iterator |
| **File** | | | Unsupported in Event Iterator |
| **Event Iterator (AsyncIteratorObject)** | | | Only at the root level |
| **ReadableStream\<Uint8Array\>** | | | Only at the root level |
| Type | Handler key | Serialized | Notes |
| -------------------------------- | ----------- | ------------------ | ------------------------------------ |
| **string** | | | |
| **number** | | | |
| **NaN** | `nan` | `null` | |
| **boolean** | | | |
| **null** | | | |
| **undefined** | `undefined` | `null` | Ignore `undefined` properties |
| **Date** | `date` | ISO String, `null` | |
| **BigInt** | `bigint` | string | |
| **RegExp** | `regexp` | string | |
| **URL** | `url` | string | |
| **Record (object)** | | | `toJSON` methods are ignored |
| **Array** | | | |
| **Set** | `set` | array | |
| **Map** | `map` | array | |
| **Blob** | | | Unsupported in `AsyncIteratorObject` |
| **File** | | | Unsupported in `AsyncIteratorObject` |
| **AsyncIteratorObject** | | | Only at the root level |
| **ReadableStream\<Uint8Array\>** | | | Only at the root level |

<!--@include: @/shared/standard-server-cors-warning.md -->

Expand Down Expand Up @@ -128,9 +128,9 @@ Standard-Server: file
If the receiver mistakenly handles this payload as a regular (non-file) body, set the `standard-server` header to help the receiver detect the actual data type and handle it correctly. Learn more about this header in the [Standard Server Documentation](https://github.com/middleapi/standardserver#resolving-body).
:::

### Event Iterator (AsyncIteratorObject)
### AsyncIteratorObject

When the output is an event iterator (`AsyncIteratorObject`), it is sent as a [Server-Sent Events](https://developer.mozilla.org/en-US/docs/Web/API/Server-sent_events) stream. Each event contains one serialized chunk of data.
When the output is an `AsyncIteratorObject`, it is sent as a [Server-Sent Events](https://developer.mozilla.org/en-US/docs/Web/API/Server-sent_events) stream. Each event contains one serialized chunk of data.

```http
HTTP/1.1 200 OK
Expand Down
2 changes: 1 addition & 1 deletion apps/content/docs/plugins/retry.md
Original file line number Diff line number Diff line change
Expand Up @@ -76,7 +76,7 @@ const link = new RPCLink<ClientContext>({

## Event Source Simulation

To replicate the behavior of [EventSource](https://developer.mozilla.org/en-US/docs/Web/API/EventSource) for [Event Iterator](/docs/event-iterator), use the following configuration:
To replicate the behavior of [EventSource](https://developer.mozilla.org/en-US/docs/Web/API/EventSource) for an [AsyncIteratorObject](/docs/async-iterator-object), use the following configuration:

```ts
const streaming = await client.streaming('the input', {
Expand Down
Loading
Loading