From acba3cb3afd6e39e987486039937c3fd18dcf550 Mon Sep 17 00:00:00 2001 From: "E. Cooper" Date: Fri, 25 Oct 2024 09:59:37 -0700 Subject: [PATCH] Update remaining README and doc string changes --- .github/workflows/pr_validate.yml | 4 - README.md | 274 +++++++++++++++--------------- package.json | 4 +- src/client-configuration.ts | 2 +- src/values/stream.ts | 2 +- 5 files changed, 140 insertions(+), 146 deletions(-) diff --git a/.github/workflows/pr_validate.yml b/.github/workflows/pr_validate.yml index 7a94dd9d..a85e9a82 100644 --- a/.github/workflows/pr_validate.yml +++ b/.github/workflows/pr_validate.yml @@ -11,14 +11,10 @@ jobs: image: fauna/faunadb:latest ports: - 8443:8443 - env: - FLAG_ACCOUNT_CHANGE_FEEDS: "true" alt_core: image: fauna/faunadb:latest ports: - 7443:8443 - env: - FLAG_ACCOUNT_CHANGE_FEEDS: "true" strategy: matrix: node: ["18", "20"] diff --git a/README.md b/README.md index f9d6f7c8..67ffecd7 100644 --- a/README.md +++ b/README.md @@ -29,16 +29,16 @@ See the [Fauna Documentation](https://docs.fauna.com/fauna/current/) for additio - [Query timeout](#query-timeout) - [Client timeout](#client-timeout) - [HTTP/2 session idle timeout](#http2-session-idle-timeout) - - [Event Streaming](#event-streaming) - - [Start a stream](#start-a-stream) - - [Iterate on a stream](#iterate-on-a-stream) - - [Close a stream](#close-a-stream) - - [Stream options](#stream-options) - [Event Feeds](#event-feeds) - [Request an Event Feed](#request-a-event-feed) - [Iterate on an Event Feed](#iterate-on-a-event-feed) - [Error handling](#error-handling) - [Event Feed options](#event-feed-options) + - [Event Streaming](#event-streaming) + - [Start a stream](#start-a-stream) + - [Iterate on a stream](#iterate-on-a-stream) + - [Close a stream](#close-a-stream) + - [Stream options](#stream-options) - [Contributing](#contributing) - [Set up the repo](#set-up-the-repo) - [Run tests](#run-tests) @@ -469,20 +469,142 @@ const client = new Client({ http2_session_idle_ms: 6000 }); > **Warning** > Setting `http2_session_idle_ms` to small values can lead to a race condition where requests cannot be transmitted before the session is closed, yielding `ERR_HTTP2_GOAWAY_SESSION` errors. +## Event Feeds + +The driver supports [Event Feeds](https://docs.fauna.com/fauna/current/learn/cdc/#event-feeds). + +### Request an Event Feed + +An Event Feed asynchronously polls an [event source](https://docs.fauna.com/fauna/current/learn/cdc/#create-an-event-source) for events. + +To get an event source, append `eventSource()` or `eventsOn()` to a set from a +[supported Set](https://docs.fauna.com/fauna/current/reference/streaming_reference/#sets). + +To get paginated events, pass the event source to `feed()`: + +```javascript +const response = await client.query(fql` + let set = Product.all() + + { + initialPage: set.pageSize(10), + eventSource: set.eventSource() + } +`); +const { initialPage, eventSource } = response.data; + +const feed = client.feed(eventSource); +``` + +You can also pass a query that produces an event source directly to `feed()`: + +```javascript +const query = fql`Product.all().eventsOn(.price, .stock)`; + +const feed = client.feed(query); +``` + +### Iterate on a Event Feed + +`feed()` returns a `FeedClient` instance that can act as an `AsyncIterator`. You can use `for await...of` to iterate through all the pages: + +```ts +const query = fql`Product.all().eventsOn(.price, .stock)`; +const feed = client.feed(query); + +for await (const page of feed) { + console.log("Page stats", page.stats); + + for (event in page.events) { + switch (event.type) { + case "update": + case "add": + case "remove": + console.log("Event:", event); + // ... + break; + } + } +} +``` + +Alternatively, use `flatten()` to get paginated results as a single, flat array: + +```ts +const query = fql`Product.all().eventsOn(.price, .stock)`; +const feed = client.feed(query); + +for await (const event of feed.flatten()) { + console.log("Event:", event); +} +``` + +### Error handling + +Exceptions can be raised at two different places: + +1. While fetching a page +1. While iterating a page's events + +This distinction allows for you to ignore errors originating from event processing. +For example: + +```ts +const feed = client.feed(fql` + Product.all().map(.details.toUpperCase()).eventSource() +`); + +try { + for await (const page of feed) { + // Pages will stop at the first error encountered. + // Therefore, its safe to handle an event failures + // and then pull more pages. + try { + for (const event of page.events) { + console.log("Event: ", event); + } + } catch (error: unknown) { + console.log("Feed event error: ", error); + } + } +} catch (error: unknown) { + console.log("Non-retryable error: ", error); +} +``` + +### Event Feed options + +The client configuration sets the default options for `feed()`. You can pass a `FeedClientConfiguration` object to override these defaults: + +```ts +const options: FeedClientConfiguration = { + long_type: "number", + max_attempts: 5, + max_backoff: 1000, + query_timeout_ms: 5000, + client_timeout_buffer_ms: 5000, + secret: "FAUNA_SECRET", + cursor: undefined, + start_ts: undefined, +}; + +client.feed(fql`Product.all().eventSource()`, options); +``` + ## Event Streaming The driver supports [Event Streaming](https://docs.fauna.com/fauna/current/learn/streaming). ### Start a stream -To get a stream token, append +To get an event source, append [`eventSource()`](https://docs.fauna.com/fauna/current/reference/reference/schema_entities/set/eventsource) or [`eventsOn()`](https://docs.fauna.com/fauna/current/reference/reference/schema_entities/set/eventson) to a set from a [supported source](https://docs.fauna.com/fauna/current/reference/streaming_reference/#sets). -To start and subscribe to the stream, pass the stream token to `stream()`: +To start and subscribe to the stream, pass the event source to `stream()`: ```javascript const response = await client.query(fql` @@ -490,15 +612,15 @@ const response = await client.query(fql` { initialPage: set.pageSize(10), - streamToken: set.eventSource() + eventSource: set.eventSource() } `); -const { initialPage, streamToken } = response.data; +const { initialPage, eventSource } = response.data; -client.stream(streamToken); +client.stream(eventSource); ``` -You can also pass a query that produces a stream token directly to `stream()`: +You can also pass a query that produces an event source directly to `stream()`: ```javascript const query = fql`Product.all().eventsOn(.price, .stock)`; @@ -517,7 +639,7 @@ try { case "update": case "add": case "remove": - console.log("Stream event:", event); + console.log("Event:", event); // ... break; } @@ -539,7 +661,7 @@ stream.start( case "update": case "add": case "remove": - console.log("Stream event:", event); + console.log("Event:", event); // ... break; } @@ -562,7 +684,7 @@ const stream = await client.stream(fql`Product.all().eventSource()`); let count = 0; for await (const event of stream) { - console.log("Stream event:", event); + console.log("Event:", event); // ... count++; @@ -598,130 +720,6 @@ For supported properties, see [StreamClientConfiguration](https://fauna.github.io/fauna-js/latest/types/StreamClientConfiguration.html) in the API reference. -## Event Feeds - -The driver supports [Event Feeds](https://docs.fauna.com/fauna/current/learn/cdc/#event-feeds). - -### Request a Event Feed - -An Event Feed asynchronously polls an [event stream](https://docs.fauna.com/fauna/current/learn/cdc/#event-feeds), -represented by a stream token, for events. - -To get a stream token, append `eventSource()` or `eventsOn()` to a set from a -[supported source](https://docs.fauna.com/fauna/current/reference/streaming_reference/#supported-sources). - -To get paginated events for the stream, pass the stream token to -`feed()`: - -```javascript -const response = await client.query(fql` - let set = Product.all() - - { - initialPage: set.pageSize(10), - streamToken: set.eventSource() - } -`); -const { initialPage, streamToken } = response.data; - -const feed = client.feed(streamToken); -``` - -You can also pass a query that produces a stream token directly to `feed()`: - -```javascript -const query = fql`Product.all().eventsOn(.price, .stock)`; - -const feed = client.feed(query); -``` - -### Iterate on a Event Feed - -`feed()` returns a `FeedClient` instance that can act as an `AsyncIterator`. You can use `for await...of` to iterate through all the pages: - -```ts -const query = fql`Product.all().eventsOn(.price, .stock)`; -const feed = client.feed(query); - -for await (const page of feed) { - console.log("Page stats", page.stats); - - for (event in page.events) { - switch (event.type) { - case "update": - case "add": - case "remove": - console.log("Stream event:", event); - // ... - break; - } - } -} -``` - -Alternatively, use `flatten()` to get paginated results as a single, flat array: - -```ts -const query = fql`Product.all().eventsOn(.price, .stock)`; -const feed = client.feed(query); - -for await (const event of feed.flatten()) { - console.log("Stream event:", event); -} -``` - -### Error handling - -Exceptions can be raised at two different places: - -1. While fetching a page -1. While iterating a page's events - -This distinction allows for you to ignore errors originating from event processing. -For example: - -```ts -const feed = client.feed(fql` - Product.all().map(.details.toUpperCase()).eventSource() -`); - -try { - for await (const page of feed) { - // Pages will stop at the first error encountered. - // Therefore, its safe to handle an event failures - // and then pull more pages. - try { - for (const event of page.events) { - console.log("Stream event:", event); - } - } catch (error: unknown) { - console.log("Stream event error:", error); - } - } -} catch (error: unknown) { - console.log("Non-retryable error:", error); -} -``` - -### Event Feed options - -The client configuration sets the default options for `feed()`. You can pass a `FeedClientConfiguration` object to override these defaults: - -```ts -const options: FeedClientConfiguration = { - long_type: "number", - max_attempts: 5, - max_backoff: 1000, - query_timeout_ms: 5000, - client_timeout_buffer_ms: 5000, - secret: "FAUNA_SECRET", - cursor: undefined, - start_ts: undefined, -}; - -client.feed(fql`Product.all().eventSource()`, options); -``` - ## Contributing Any contributions from the community are greatly appreciated! diff --git a/package.json b/package.json index bdc0fa47..00cf70ef 100644 --- a/package.json +++ b/package.json @@ -44,8 +44,8 @@ "build:types": "tsc -emitDeclarationOnly --declaration true", "doc": "typedoc", "lint": "eslint -f unix \"src/**/*.{ts,tsx}\"", - "fauna-local": "docker start faunadb-local || docker run --rm -d --name faunadb-local -p 8443:8443 -p 8084:8084 -e FLAG_ACCOUNT_CHANGE_FEEDS=true fauna/faunadb", - "fauna-local-alt-port": "docker start faunadb-local-alt-port || docker run --rm -d --name faunadb-local-alt-port -p 7443:8443 -p 7084:8084 -e FLAG_ACCOUNT_CHANGE_FEEDS=true fauna/faunadb", + "fauna-local": "docker start faunadb-local || docker run --rm -d --name faunadb-local -p 8443:8443 -p 8084:8084 fauna/faunadb", + "fauna-local-alt-port": "docker start faunadb-local-alt-port || docker run --rm -d --name faunadb-local-alt-port -p 7443:8443 -p 7084:8084 fauna/faunadb", "prepare": "husky install", "test": "yarn fauna-local; yarn fauna-local-alt-port; ./prepare-test-env.sh; jest", "test:ci": "yarn install; jest --ci --reporters=default --reporters=jest-junit", diff --git a/src/client-configuration.ts b/src/client-configuration.ts index 6092309d..e237d931 100644 --- a/src/client-configuration.ts +++ b/src/client-configuration.ts @@ -205,7 +205,7 @@ export type StreamClientConfiguration = { }; /** - * Configuration for a event feed client. + * Configuration for an event feed client. */ export type FeedClientConfiguration = Required< Pick< diff --git a/src/values/stream.ts b/src/values/stream.ts index 5c0883b1..092ff84d 100644 --- a/src/values/stream.ts +++ b/src/values/stream.ts @@ -37,7 +37,7 @@ export function isEventSource(value: any): value is EventSource { return false; } -export class StreamToken { +export class StreamToken implements EventSource { readonly token: string; constructor(token: string) {