|
1 | | -# TypeScript SDK for Datastar |
2 | 1 |
|
3 | | -Implements the [SDK spec](../README.md) and exposes an abstract |
4 | | -ServerSentEventGenerator class that can be used to implement runtime specific |
5 | | -classes. NodeJS and web standard runtimes are currently implemented. |
| 2 | +<p align="center"><img width="200" height="200" src="https://data-star.dev/static/images/rocket-512x512.png"></p> |
6 | 3 |
|
7 | | -Currently it only exposes an http1 server, if you want http2 I recommend you use |
8 | | -a reverse proxy until http2 support is added. |
| 4 | +# Datastar TypeScript SDK |
9 | 5 |
|
10 | | -Deno is used for building the npm package: `deno run -A build.ts VERSION` |
| 6 | +[](https://github.com/starfederation/datastar/releases)    |
11 | 7 |
|
12 | | -Usage is straightforward: |
| 8 | +A TypeScript SDK for building reactive web applications with [Datastar](https://github.com/starfederation/datastar). |
| 9 | + |
| 10 | +Implements the [SDK spec](../README.md) and exposes an abstract ServerSentEventGenerator class that can be used to implement runtime specific classes. NodeJS and web standard runtimes are currently implemented. |
| 11 | + |
| 12 | +Currently it only exposes an http1 server, if you want http2 I recommend you use a reverse proxy until http2 support is added. |
| 13 | + |
| 14 | +## Features |
| 15 | + |
| 16 | +- **Multi-runtime support**: Works with Node.js, Deno, and Bun |
| 17 | +- **TypeScript support**: Full type safety and IntelliSense |
| 18 | + |
| 19 | +## Quick Start |
| 20 | + |
| 21 | +### Installation & Import |
| 22 | + |
| 23 | +**Node.js:** |
| 24 | +```bash |
| 25 | +npm install datastar-sdk |
| 26 | +``` |
| 27 | +```javascript |
| 28 | +import { ServerSentEventGenerator } from "datastar-sdk/node"; |
| 29 | +``` |
| 30 | + |
| 31 | +**Deno:** |
| 32 | +```typescript |
| 33 | +// No installation needed, import directly from npm |
| 34 | +import { ServerSentEventGenerator } from "npm:datastar-sdk/web"; |
| 35 | +``` |
| 36 | + |
| 37 | +**Bun:** |
| 38 | +```bash |
| 39 | +bun add datastar-sdk |
| 40 | +``` |
| 41 | +```javascript |
| 42 | +import { ServerSentEventGenerator } from "datastar-sdk/web"; |
| 43 | +``` |
| 44 | + |
| 45 | +### Basic Usage |
| 46 | + |
| 47 | +Here's a simple example in Node showing how to read client signals and send back element patches: |
13 | 48 |
|
14 | 49 | ```javascript |
15 | | -// this example is for node |
| 50 | +import { ServerSentEventGenerator } from "datastar-sdk/node"; |
| 51 | + |
| 52 | +// Read signals from the client request |
16 | 53 | const reader = await ServerSentEventGenerator.readSignals(req); |
17 | 54 |
|
18 | 55 | if (!reader.success) { |
19 | | - console.error('Error while reading signals', reader.error); |
20 | | - res.end('Error while reading signals`); |
21 | | - return; |
22 | | -} |
23 | | -
|
24 | | -if (!('foo' in reader.signals)) { |
25 | | - console.error('The foo signal is not present'); |
26 | | - res.end('The foo signal is not present'); |
| 56 | + console.error('Error reading signals:', reader.error); |
27 | 57 | return; |
28 | 58 | } |
29 | 59 |
|
| 60 | +// Stream updates back to the client |
30 | 61 | ServerSentEventGenerator.stream(req, res, (stream) => { |
31 | | - stream.mergeSignals({ foo: reader.signals.foo }); |
32 | | - stream.mergeFragments(`<div id="toMerge">Hello <span data-text="$foo">${reader.signals.foo}</span></div>`); |
| 62 | + // Patch signals |
| 63 | + stream.patchSignals(JSON.stringify({ foo: reader.signals.foo })); |
| 64 | + |
| 65 | + // Patch DOM elements |
| 66 | + stream.patchElements(`<div id="toMerge">Hello <span data-text="$foo">${reader.signals.foo}</span></div>`); |
33 | 67 | }); |
34 | 68 | ``` |
35 | 69 |
|
36 | | -The stream static method can receive an extra `options` object that can contain |
37 | | -onError and onAbort callbacks as well as the keepalive option. The keepalive |
38 | | -option will stop the stream from being closed once the onStart callback is |
39 | | -finished. That means the user is responsible for ending the stream with |
40 | | -`this.close()`. |
| 70 | +See examples for other runtimes below. |
41 | 71 |
|
42 | 72 | ## Examples |
43 | 73 |
|
44 | | -Follow the links for more complete (and executable) examples |
| 74 | +### Runtime-Specific Examples |
| 75 | + |
| 76 | +| Runtime | Example Location | How to Run | Try Online | |
| 77 | +|---------|-----------------|------------|------------| |
| 78 | +| **Node.js** | `examples/node/node.js` | [Instructions](examples/node/README.md) | [StackBlitz](https://stackblitz.com/edit/node-datastar) | |
| 79 | +| **Deno** | `examples/deno/deno.ts` | [Instructions](examples/deno/README.md) | [Val.town](https://www.val.town/x/eduwass/datastar-deno/code/main.tsx) | |
| 80 | +| **Bun** | `examples/bun/bun.ts` | [Instructions](examples/bun/README.md) | [Replit](https://replit.com/@eduwass/Bun-Datastar) | |
45 | 81 |
|
46 | | -- [NodeJS](./examples/node.js) |
47 | | -- [Deno](./examples/deno.ts) |
| 82 | +Each example creates a simple web server demonstrating: |
| 83 | +- Signal handling from client requests |
| 84 | +- Element patching for DOM updates |
| 85 | +- Real-time communication via Server-Sent Events |
48 | 86 |
|
49 | | -## Frameworks / Alternate runtimes |
| 87 | +### Running Examples |
50 | 88 |
|
51 | | -If you can't simply use the node / web versions, then you can extend the |
52 | | -abstract class in `./src/abstractServerSentEventGenerator.ts`. You will need to |
53 | | -provide implementations of the `constructor`, `readSignals`, `stream` and `send` |
54 | | -methods. |
| 89 | +1. Clone the repository |
| 90 | +2. Navigate to the specific example directory (e.g., `examples/node/`) |
| 91 | +3. Follow the instructions in the example's README file |
| 92 | +4. Visit `http://localhost:3000` in your browser |
55 | 93 |
|
56 | | -## Testing |
| 94 | +> [!NOTE] |
| 95 | +> The `npm run serve-*` and `deno task serve-*` commands in the root directory are for SDK development and testing, not for running the user examples. |
57 | 96 |
|
58 | | -A shell based testing suite is provided; see the [readme](../test/README.md) for |
59 | | -more information. |
| 97 | +## API Reference |
60 | 98 |
|
61 | | -### Testing node |
| 99 | +### ServerSentEventGenerator |
62 | 100 |
|
63 | | -Start by building and running the node server |
| 101 | +The main class for handling Datastar communication. |
64 | 102 |
|
65 | | -```shell |
66 | | -$ deno run -A build.ts xxx |
67 | | -$ node ./npm/esm/node/node.js |
| 103 | +#### Static Methods |
| 104 | + |
| 105 | +##### `readSignals(request)` |
| 106 | +Reads signals from a client request. |
| 107 | + |
| 108 | +**Parameters:** |
| 109 | +- `request`: HTTP request object |
| 110 | + |
| 111 | +**Returns:** |
| 112 | +```typescript |
| 113 | +{ |
| 114 | + success: boolean; |
| 115 | + signals?: Record<string, any>; |
| 116 | + error?: string; |
| 117 | +} |
68 | 118 | ``` |
69 | 119 |
|
70 | | -Then run the test suite |
| 120 | +##### `stream(request, response, callback, options?)` |
| 121 | +Creates a Server-Sent Event stream for real-time communication. |
71 | 122 |
|
72 | | -```shell |
73 | | -$ cd ../test |
74 | | -$ ./test-all.sh http://127.0.0.1:3000 |
75 | | -Running tests with argument: http://127.0.0.1:3000 |
76 | | -Processing GET cases... |
77 | | -Processing POST cases... |
| 123 | +**Parameters:** |
| 124 | +- `request`: HTTP request object |
| 125 | +- `response`: HTTP response object |
| 126 | +- `callback`: Function that receives a stream instance |
| 127 | +- `options`: Optional configuration object |
| 128 | + |
| 129 | +**Options:** |
| 130 | +```typescript |
| 131 | +{ |
| 132 | + onError?: (error: Error) => void; |
| 133 | + onAbort?: () => void; |
| 134 | + keepalive?: boolean; |
| 135 | +} |
78 | 136 | ``` |
79 | 137 |
|
80 | | -### Testing deno |
| 138 | +> [!IMPORTANT] |
| 139 | +> When `keepalive: true` is set, the stream will not be closed automatically after the callback finishes. You are responsible for calling `stream.close()` to end the stream. |
| 140 | +
|
| 141 | +#### Stream Instance Methods |
| 142 | + |
| 143 | +##### `patchSignals(signals, options?)` |
| 144 | +Patches signals into the client signal store. |
81 | 145 |
|
82 | | -Start by running the deno server |
| 146 | +**Parameters:** |
| 147 | +- `signals`: JSON string containing signal data to patch |
| 148 | +- `options`: Optional configuration object with `onlyIfMissing` boolean |
83 | 149 |
|
84 | | -```shell |
85 | | -$ deno --allow-net ./src/web/deno.ts |
| 150 | +**Example:** |
| 151 | +```javascript |
| 152 | +stream.patchSignals(JSON.stringify({ foo: "bar", count: 42 })); |
86 | 153 | ``` |
87 | 154 |
|
88 | | -Then run the test suite |
| 155 | +##### `patchElements(elements, options?)` |
| 156 | +Patches HTML elements into the client DOM. |
| 157 | + |
| 158 | +**Parameters:** |
| 159 | +- `elements`: HTML string containing elements to patch |
| 160 | +- `options`: Optional configuration object with `mode` and `selector` |
89 | 161 |
|
90 | | -```shell |
91 | | -$ cd ../test |
92 | | -$ ./test-all.sh http://localhost:8000/ |
93 | | -Running tests with argument: http://localhost:8000/ |
94 | | -Processing GET cases... |
95 | | -Processing POST cases... |
| 162 | +**Options:** |
| 163 | +- `mode`: Patch mode - "outer", "inner", "replace", "prepend", "append", "before", "after", "remove" |
| 164 | +- `selector`: CSS selector for targeting elements (required for some modes) |
| 165 | +- `useViewTransition`: Whether to use View Transition API |
| 166 | + |
| 167 | +**Example:** |
| 168 | +```javascript |
| 169 | +stream.patchElements('<div id="myDiv">Updated content</div>'); |
96 | 170 | ``` |
| 171 | + |
| 172 | +## Development |
| 173 | + |
| 174 | +### Prerequisites |
| 175 | + |
| 176 | +To develop or contribute to this SDK, you'll need: |
| 177 | +- [Deno](https://deno.land/) (primary development environment) |
| 178 | +- [Node.js](https://nodejs.org/) (for Node.js compatibility testing) |
| 179 | +- [Bun](https://bun.sh/) (for Bun compatibility testing) |
| 180 | + |
| 181 | +### Building |
| 182 | + |
| 183 | +Build the npm package: |
| 184 | +```bash |
| 185 | +deno run -A build.ts |
| 186 | +``` |
| 187 | + |
| 188 | +The above will pick the version from the [src/consts.ts](src/consts.ts) file. If you want to specify the version, use: |
| 189 | +```bash |
| 190 | +deno run -A build.ts VERSION |
| 191 | +``` |
| 192 | + |
| 193 | +> [!NOTE] |
| 194 | +> **For Developers:** The build process includes test files in the `npm/` directory for local testing, but they are excluded from the published npm package via `.npmignore`. Test files are built into `npm/esm/test/` and `npm/script/test/` directories to support the test scripts (`npm run test-node`, etc.), but these directories are not included when publishing to the npm registry. |
| 195 | +
|
| 196 | +### Testing |
| 197 | + |
| 198 | +#### Automated Testing |
| 199 | + |
| 200 | +Run tests for all runtimes: |
| 201 | +```bash |
| 202 | +# Node.js |
| 203 | +npm run test-node |
| 204 | + |
| 205 | +# Deno |
| 206 | +deno task test-deno |
| 207 | + |
| 208 | +# Bun |
| 209 | +bun run test-bun |
| 210 | +``` |
| 211 | + |
| 212 | +#### Manual Testing |
| 213 | + |
| 214 | +Start a development server: |
| 215 | +```bash |
| 216 | +# Node.js |
| 217 | +npm run serve-node |
| 218 | + |
| 219 | +# Deno |
| 220 | +deno task serve-deno |
| 221 | + |
| 222 | +# Bun |
| 223 | +bun run serve-bun |
| 224 | +``` |
| 225 | + |
| 226 | +Then run the test suite manually: |
| 227 | +```bash |
| 228 | +cd ../test |
| 229 | +./test-all.sh http://127.0.0.1:3000 |
| 230 | +``` |
| 231 | + |
| 232 | +### Project Structure |
| 233 | + |
| 234 | +``` |
| 235 | +typescript/ |
| 236 | +├── src/ |
| 237 | +│ ├── node/ # Node.js-specific implementation |
| 238 | +│ ├── web/ # Web standards implementation (Deno/Bun) |
| 239 | +│ └── abstract/ # Abstract base classes |
| 240 | +├── examples/ |
| 241 | +│ ├── node/ # Node.js example |
| 242 | +│ ├── deno/ # Deno example |
| 243 | +│ └── bun/ # Bun example |
| 244 | +└── test/ # Test suite |
| 245 | +``` |
| 246 | + |
| 247 | +## Runtime Support |
| 248 | + |
| 249 | +### Node.js |
| 250 | +- Import: `datastar-sdk/node` |
| 251 | +- Requires: Node.js 18+ |
| 252 | +- Uses Node.js-specific HTTP APIs |
| 253 | + |
| 254 | +### Deno |
| 255 | +- Import: `npm:datastar-sdk/web` |
| 256 | +- Requires: Deno 1.30+ |
| 257 | +- Uses Web Standards APIs |
| 258 | + |
| 259 | +### Bun |
| 260 | +- Import: `datastar-sdk/web` |
| 261 | +- Requires: Bun 1.0+ |
| 262 | +- Uses Web Standards APIs |
| 263 | + |
| 264 | +## Custom Implementations |
| 265 | + |
| 266 | +To support additional runtimes or frameworks, extend the abstract `ServerSentEventGenerator` class from `./src/abstractServerSentEventGenerator.ts`. |
| 267 | + |
| 268 | +You'll need to implement: |
| 269 | +- `constructor`: Initialize runtime-specific components |
| 270 | +- `readSignals`: Parse signals from requests |
| 271 | +- `stream`: Create SSE streams |
| 272 | +- `send`: Send data to clients |
| 273 | + |
| 274 | +The abstract class provides these public methods: |
| 275 | +- `patchElements(elements, options?)`: Patch HTML elements |
| 276 | +- `patchSignals(signals, options?)`: Patch signal data |
0 commit comments