@restless-stream/react 0.1.0 → 0.1.1

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (2) hide show
  1. package/README.md +263 -0
  2. package/package.json +23 -2
package/README.md ADDED
@@ -0,0 +1,263 @@
1
+ # @restless-stream/react
2
+
3
+ Lightweight React bindings for Restless Stream: <https://restlessapi.stream>
4
+
5
+ This package provides a `RestlessProvider`, access to the core Restless Stream client through context, and hooks for consuming SSE stream URLs in React components.
6
+
7
+ Use this package when a React app already has a Restless Stream SSE URL, managed stream object, or direct-session response. Use `@restless-stream/core` or `@restless-stream/node` on a trusted backend to create streams or sessions when you do not want to expose API keys to the browser.
8
+
9
+ ## Requirements
10
+
11
+ - React `>=18.2 <20`.
12
+ - A Restless Stream account and API key when creating a client in the provider.
13
+ - An SSE URL from a managed stream or direct session.
14
+
15
+ Do not put long-lived API keys in public browser bundles. For browser applications, prefer generating stream URLs or direct sessions on your backend and passing only the runtime URL to React.
16
+
17
+ ## Installation
18
+
19
+ ```bash
20
+ npm install @restless-stream/react @restless-stream/core
21
+ ```
22
+
23
+ ```bash
24
+ pnpm add @restless-stream/react @restless-stream/core
25
+ ```
26
+
27
+ ```bash
28
+ yarn add @restless-stream/react @restless-stream/core
29
+ ```
30
+
31
+ `@restless-stream/core` is installed as a dependency by package managers, but adding it explicitly can make shared client types easier to import in your application.
32
+
33
+ ## Getting Started
34
+
35
+ Wrap your app in `RestlessProvider`, then subscribe with `useStreamSubscription`.
36
+
37
+ ```tsx
38
+ import { RestlessProvider, useStreamSubscription } from '@restless-stream/react';
39
+
40
+ function StreamEvents({ sseUrl }: { sseUrl: string }) {
41
+ const { error, events, status } = useStreamSubscription({
42
+ enabled: Boolean(sseUrl),
43
+ maxEvents: 100,
44
+ sseUrl,
45
+ });
46
+
47
+ if (error) {
48
+ return <p>{error.message}</p>;
49
+ }
50
+
51
+ return <pre>{JSON.stringify({ status, events }, null, 2)}</pre>;
52
+ }
53
+
54
+ export function App({ apiKey, sseUrl }: { apiKey: string; sseUrl: string }) {
55
+ return (
56
+ <RestlessProvider apiKey={apiKey}>
57
+ <StreamEvents sseUrl={sseUrl} />
58
+ </RestlessProvider>
59
+ );
60
+ }
61
+ ```
62
+
63
+ If you do not want to use context, pass an explicit core client to the hook.
64
+
65
+ ```tsx
66
+ import { createRestlessClient } from '@restless-stream/core';
67
+ import { useStreamSubscription } from '@restless-stream/react';
68
+
69
+ const client = createRestlessClient({ apiKey: 'rs_server_or_private_runtime_key' });
70
+
71
+ function StreamEvents({ sseUrl }: { sseUrl: string }) {
72
+ const subscription = useStreamSubscription({ client, sseUrl });
73
+ return <pre>{JSON.stringify(subscription.latestEvent, null, 2)}</pre>;
74
+ }
75
+ ```
76
+
77
+ ## Provider API
78
+
79
+ `RestlessProvider` creates or provides a core Restless Stream client.
80
+
81
+ ```tsx
82
+ <RestlessProvider
83
+ apiKey={apiKey}
84
+ apiBaseUrl="https://api.restlessapi.stream"
85
+ streamBaseUrl="https://stream.restlessapi.stream"
86
+ headers={{ 'X-App': 'dashboard' }}
87
+ >
88
+ <App />
89
+ </RestlessProvider>
90
+ ```
91
+
92
+ Provider props:
93
+
94
+ | Prop | Description |
95
+ | --- | --- |
96
+ | `client` | Existing `RestlessClient`. When provided, config props are ignored. |
97
+ | `config` | Full core client config object. |
98
+ | `apiKey` | API key passed to `createRestlessClient`. |
99
+ | `apiBaseUrl` | REST API base URL. |
100
+ | `streamBaseUrl` | Runtime stream base URL. |
101
+ | `fetch` | Custom fetch implementation. |
102
+ | `headers` | Default REST headers. |
103
+ | `children` | React children. |
104
+
105
+ Use `useRestlessClient()` to read the client from context.
106
+
107
+ ```tsx
108
+ import { useRestlessClient } from '@restless-stream/react';
109
+
110
+ function StreamCount() {
111
+ const client = useRestlessClient();
112
+ // Use the client in effects, event handlers, or data loading code.
113
+ return <button onClick={() => void client.streams.list()}>Refresh</button>;
114
+ }
115
+ ```
116
+
117
+ `useRestlessClient` throws when used outside `RestlessProvider`.
118
+
119
+ ## `useStreamSubscription`
120
+
121
+ `useStreamSubscription(options)` subscribes to an SSE URL through the core client's `streams.subscribeSse` method.
122
+
123
+ ```tsx
124
+ const {
125
+ connect,
126
+ disconnect,
127
+ error,
128
+ events,
129
+ isConnected,
130
+ isConnecting,
131
+ latestEvent,
132
+ reset,
133
+ status,
134
+ } = useStreamSubscription({
135
+ sseUrl,
136
+ enabled: true,
137
+ maxEvents: 100,
138
+ reconnect: true,
139
+ maxReconnectAttempts: 3,
140
+ reconnectDelayMs: (attempt) => attempt * 1000,
141
+ onEvent: (event) => console.log(event),
142
+ onError: (error) => console.error(error),
143
+ });
144
+ ```
145
+
146
+ Options:
147
+
148
+ | Option | Description |
149
+ | --- | --- |
150
+ | `sseUrl` | Runtime SSE URL to subscribe to. |
151
+ | `client` | Explicit core `RestlessClient`. Uses provider context when omitted. |
152
+ | `enabled` | Starts the subscription automatically. Defaults to `true`. |
153
+ | `maxEvents` | Maximum number of events kept in state. Defaults to `100`. Use `0` to keep none. |
154
+ | `maxReconnectAttempts` | Hook-level retry count after subscription failures. Defaults to `0`. |
155
+ | `onEvent` | Callback fired for each parsed Restless Stream event. |
156
+ | `onError` | Callback fired when the subscription throws. |
157
+ | `reconnect` | Enables hook-level reconnect attempts. Defaults to `false`. |
158
+ | `reconnectDelayMs` | Number or function returning the delay for each reconnect attempt. Defaults to `1000`. |
159
+ | `headers` | Additional SSE request headers. |
160
+ | `allowApiKeyInUrl` | Opts into API key query-parameter auth for runtime URLs. Use carefully. |
161
+ | `cursor` | Initial cursor or event ID. |
162
+ | `since` | Initial timestamp or cursor. |
163
+
164
+ Result fields:
165
+
166
+ | Field | Description |
167
+ | --- | --- |
168
+ | `events` | Bounded array of received events. |
169
+ | `latestEvent` | Most recent event, or `null`. |
170
+ | `error` | Last normalized `Error`, or `null`. |
171
+ | `status` | `idle`, `connecting`, `open`, `reconnecting`, `closed`, or `error`. |
172
+ | `isConnected` | `true` when `status === 'open'`. |
173
+ | `isConnecting` | `true` when `status` is `connecting` or `reconnecting`. |
174
+ | `connect()` | Starts or restarts the subscription. |
175
+ | `disconnect()` | Aborts the active subscription and sets status to `closed`. |
176
+ | `reset()` | Clears buffered events and error state. |
177
+
178
+ Manual connection example:
179
+
180
+ ```tsx
181
+ function ManualStream({ sseUrl }: { sseUrl: string }) {
182
+ const stream = useStreamSubscription({
183
+ enabled: false,
184
+ sseUrl,
185
+ });
186
+
187
+ return (
188
+ <section>
189
+ <p>Status: {stream.status}</p>
190
+ <button onClick={stream.connect}>Connect</button>
191
+ <button onClick={stream.disconnect}>Disconnect</button>
192
+ <button onClick={stream.reset}>Clear events</button>
193
+ </section>
194
+ );
195
+ }
196
+ ```
197
+
198
+ ## `useManagedStream`
199
+
200
+ `useManagedStream` is a convenience wrapper for managed stream objects. It accepts either `sseUrl` directly or a `stream` object with an `sseUrl` field.
201
+
202
+ ```tsx
203
+ function ManagedStream({ stream }: { stream: { sseUrl?: string | null } | null }) {
204
+ const { latestEvent, status } = useManagedStream({
205
+ stream,
206
+ maxEvents: 25,
207
+ });
208
+
209
+ return <pre>{JSON.stringify({ latestEvent, status }, null, 2)}</pre>;
210
+ }
211
+ ```
212
+
213
+ The hook auto-enables only when a non-empty URL is available, unless you pass `enabled` explicitly.
214
+
215
+ ## `useDirectStream`
216
+
217
+ `useDirectStream` is a convenience wrapper for direct stream URLs or direct-session responses. It accepts `directUrl`, `sseUrl`, or `session.sseUrl`.
218
+
219
+ ```tsx
220
+ function DirectSessionEvents({ session }: { session: { sseUrl?: string | null } | null }) {
221
+ const { latestEvent, status } = useDirectStream({
222
+ session,
223
+ reconnect: true,
224
+ maxReconnectAttempts: 3,
225
+ });
226
+
227
+ return <pre>{JSON.stringify({ latestEvent, status }, null, 2)}</pre>;
228
+ }
229
+ ```
230
+
231
+ `useDirectStream` does not create direct sessions. Create sessions with a trusted backend or the core SDK, then pass the returned `sseUrl` into React.
232
+
233
+ ## Browser Auth Notes
234
+
235
+ `allowApiKeyInUrl` is supported by the underlying core client, but URLs can appear in logs, analytics, browser history, and referrer headers. Prefer header-based auth from trusted server runtimes or backend-created runtime URLs.
236
+
237
+ ## Public Exports
238
+
239
+ | Export | Purpose |
240
+ | --- | --- |
241
+ | `RestlessProvider` | React context provider for a core Restless client. |
242
+ | `RestlessProviderProps` | Provider props type. |
243
+ | `useRestlessClient` | Reads the client from provider context. |
244
+ | `useStreamSubscription` | Main SSE subscription hook. |
245
+ | `useManagedStream` | Hook wrapper for managed stream objects or managed SSE URLs. |
246
+ | `useDirectStream` | Hook wrapper for direct URLs or direct-session responses. |
247
+ | `DEFAULT_MAX_EVENTS` | Default event buffer size, `100`. |
248
+ | `StreamSubscriptionStatus` | Subscription status union. |
249
+ | `StreamSubscriptionControls` | `connect`, `disconnect`, and `reset` controls. |
250
+ | `UseStreamSubscriptionOptions` | Main hook options type. |
251
+ | `UseStreamSubscriptionResult` | Main hook result type. |
252
+ | `UseManagedStreamOptions` | Managed stream hook options type. |
253
+ | `UseDirectStreamOptions` | Direct stream hook options type. |
254
+
255
+ ## Development
256
+
257
+ ```bash
258
+ cd packages/typescript
259
+ pnpm install
260
+ pnpm --filter @restless-stream/react typecheck
261
+ pnpm --filter @restless-stream/react test
262
+ pnpm --filter @restless-stream/react build
263
+ ```
package/package.json CHANGED
@@ -1,7 +1,25 @@
1
1
  {
2
2
  "name": "@restless-stream/react",
3
- "version": "0.1.0",
3
+ "version": "0.1.1",
4
4
  "description": "Lightweight React bindings for the Restless Stream SDK.",
5
+ "license": "MIT",
6
+ "repository": {
7
+ "type": "git",
8
+ "url": "git+https://github.com/restless-stream/sdk.git",
9
+ "directory": "packages/typescript/react"
10
+ },
11
+ "homepage": "https://github.com/restless-stream/sdk/tree/main/packages/typescript/react#readme",
12
+ "bugs": {
13
+ "url": "https://github.com/restless-stream/sdk/issues"
14
+ },
15
+ "keywords": [
16
+ "restless-stream",
17
+ "sdk",
18
+ "sse",
19
+ "streaming",
20
+ "react",
21
+ "hooks"
22
+ ],
5
23
  "type": "module",
6
24
  "sideEffects": false,
7
25
  "main": "./dist/index.cjs",
@@ -17,11 +35,14 @@
17
35
  "files": [
18
36
  "dist"
19
37
  ],
38
+ "publishConfig": {
39
+ "access": "public"
40
+ },
20
41
  "peerDependencies": {
21
42
  "react": ">=18.2 <20"
22
43
  },
23
44
  "dependencies": {
24
- "@restless-stream/core": "0.1.0"
45
+ "@restless-stream/core": "0.1.1"
25
46
  },
26
47
  "devDependencies": {
27
48
  "@testing-library/react": "^16.3.0",