@weft-js/realtime-nats 0.1.0 → 0.1.3
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.
- package/README.md +271 -3
- package/package.json +13 -4
- package/plugin.mjs +17 -4
- package/src/index.ts +29 -14
package/README.md
CHANGED
|
@@ -1,9 +1,277 @@
|
|
|
1
|
-
|
|
1
|
+
<p align="center">
|
|
2
|
+
<a href="https://github.com/Ravonus/weft">
|
|
3
|
+
<img src="https://raw.githubusercontent.com/Ravonus/weft/main/site/public/logo.svg" width="88" height="88" alt="Weft">
|
|
4
|
+
</a>
|
|
5
|
+
</p>
|
|
2
6
|
|
|
3
|
-
>
|
|
7
|
+
<h1 align="center">@weft-js/realtime-nats</h1>
|
|
4
8
|
|
|
5
|
-
|
|
9
|
+
<p align="center">
|
|
10
|
+
<strong>Core NATS as Weft's realtime bus, so live data reaches every instance of your app.</strong><br>
|
|
11
|
+
One line in <code>weft.config.ts</code>, one <code>NATS_URL</code>, and no change to your pages or server functions.
|
|
12
|
+
</p>
|
|
13
|
+
|
|
14
|
+
<p align="center">
|
|
15
|
+
<a href="https://www.npmjs.com/package/@weft-js/realtime-nats"><img src="https://img.shields.io/npm/v/@weft-js/realtime-nats?color=145c3c&label=npm" alt="npm version"></a>
|
|
16
|
+
<a href="https://github.com/Ravonus/weft/blob/main/LICENSE"><img src="https://img.shields.io/badge/license-MIT-145c3c" alt="MIT license"></a>
|
|
17
|
+
<a href="https://github.com/Ravonus/weft/actions"><img src="https://img.shields.io/github/actions/workflow/status/Ravonus/weft/quality.yml?branch=main&label=checks" alt="checks"></a>
|
|
18
|
+
</p>
|
|
19
|
+
|
|
20
|
+
<p align="center">
|
|
21
|
+
<a href="#quick-start">Quick start</a> ·
|
|
22
|
+
<a href="https://github.com/Ravonus/weft/tree/main/docs">Docs</a> ·
|
|
23
|
+
<a href="https://github.com/Ravonus/weft/tree/main/examples">Examples</a> ·
|
|
24
|
+
<a href="https://github.com/Ravonus/weft/blob/main/CHANGELOG.md">Changelog</a> ·
|
|
25
|
+
<a href="https://github.com/Ravonus/weft">GitHub</a>
|
|
26
|
+
</p>
|
|
27
|
+
|
|
28
|
+
> [!IMPORTANT]
|
|
29
|
+
> **Early release (0.1.x).** APIs can change between minor versions. Pin the version and read the
|
|
30
|
+
> [changelog](https://github.com/Ravonus/weft/blob/main/CHANGELOG.md) before you upgrade.
|
|
31
|
+
|
|
32
|
+
On one server, Weft's realtime needs nothing: messages, `.live()` pokes, channels and shared state go through a memory
|
|
33
|
+
bus inside the process. Run two instances and each one only reaches its own sockets, so a mutation on one never
|
|
34
|
+
refreshes a page connected to the other. This package fills the `realtime.bus` slot with core NATS, so every instance
|
|
35
|
+
hears every publish. It's for apps that already run NATS, or want a small message server between instances.
|
|
36
|
+
|
|
37
|
+
## Highlights
|
|
38
|
+
|
|
39
|
+
- **A plugin, not code.** `nats()` in `plugins` replaces the memory bus. Nothing in `src/` changes.
|
|
40
|
+
- **Reads `NATS_URL`.** The servers come from the environment unless you pass `servers`.
|
|
41
|
+
- **Token or user/password auth.** Pass `token`, or `user` and `pass`, when the server asks for them.
|
|
42
|
+
- **Any channel name is safe.** Weft's channel names come from tags and keys, which can hold characters a NATS subject
|
|
43
|
+
can't (`*`, `>`, spaces). Each channel becomes `weft.<base64url of the name>`.
|
|
44
|
+
- **Lazy.** It connects on the first publish or subscribe, and `weft build` never connects.
|
|
45
|
+
- **Reconnects on its own.** It retries without limit, every 500 ms. A reconnect is reported to the hub as a gap, so
|
|
46
|
+
clients know that messages may be missing.
|
|
47
|
+
- **Tested against a real server.** The test suite runs the shared `realtime.bus@1` conformance checks against a
|
|
48
|
+
`nats-server` it starts, then kills and restarts.
|
|
49
|
+
|
|
50
|
+
## Install
|
|
6
51
|
|
|
7
52
|
```bash
|
|
53
|
+
# npm
|
|
8
54
|
npm install @weft-js/realtime-nats
|
|
55
|
+
|
|
56
|
+
# pnpm
|
|
57
|
+
pnpm add @weft-js/realtime-nats
|
|
58
|
+
|
|
59
|
+
# bun
|
|
60
|
+
bun add @weft-js/realtime-nats
|
|
61
|
+
```
|
|
62
|
+
|
|
63
|
+
Or let the `weft` CLI install it and add it to `weft.config.ts` in one step:
|
|
64
|
+
|
|
65
|
+
```bash
|
|
66
|
+
npx weft add nats
|
|
67
|
+
```
|
|
68
|
+
|
|
69
|
+
`weft add` installs the package and adds the plugin to `weft.config.ts`.
|
|
70
|
+
|
|
71
|
+
## Quick start
|
|
72
|
+
|
|
73
|
+
1. Run a NATS server. For local work:
|
|
74
|
+
|
|
75
|
+
```bash
|
|
76
|
+
docker run --rm -p 4222:4222 nats
|
|
77
|
+
```
|
|
78
|
+
|
|
79
|
+
2. Add the plugin. `weft add nats` writes this for you:
|
|
80
|
+
|
|
81
|
+
```ts
|
|
82
|
+
// weft.config.ts
|
|
83
|
+
import { defineConfig } from '@weft-js/core/config'
|
|
84
|
+
import realtimeNats from '@weft-js/realtime-nats/plugin'
|
|
85
|
+
|
|
86
|
+
export default defineConfig({
|
|
87
|
+
plugins: [realtimeNats()],
|
|
88
|
+
})
|
|
89
|
+
```
|
|
90
|
+
|
|
91
|
+
`import { nats } from '@weft-js/realtime-nats/plugin'` is the same function under its own name.
|
|
92
|
+
|
|
93
|
+
3. Set the server in the app's environment:
|
|
94
|
+
|
|
95
|
+
```bash
|
|
96
|
+
# .env
|
|
97
|
+
NATS_URL=nats://localhost:4222
|
|
98
|
+
```
|
|
99
|
+
|
|
100
|
+
4. Start two instances on different ports and open a page that reads a query with `.live()` on each. A mutation through
|
|
101
|
+
one refreshes the page on the other.
|
|
102
|
+
|
|
103
|
+
## How it plugs into Weft
|
|
104
|
+
|
|
105
|
+
Weft's realtime hub keeps everything that has state (tags, topics, replay rings, cursors, presence) and hands the bus
|
|
106
|
+
three things to do: publish a string to a channel, subscribe to a channel, and close. That is the `Bus` interface in
|
|
107
|
+
[`@weft-js/start/bus`](https://github.com/Ravonus/weft/blob/main/packages/start/src/bus.ts). A bus is at-most-once and
|
|
108
|
+
ordered per publisher; core NATS is both.
|
|
109
|
+
|
|
110
|
+
The plugin provides the `realtime.bus` slot (version 1, one provider, server side). At build time Weft writes the slot
|
|
111
|
+
binding to `.weft/slots/realtime.bus.ts`, and the server entry wraps it in a bus that loads this package on the first
|
|
112
|
+
publish or subscribe. The order of precedence is:
|
|
113
|
+
|
|
114
|
+
| Where the bus comes from | Wins over |
|
|
115
|
+
| --- | --- |
|
|
116
|
+
| `bus` in `src/realtime.server.ts` | everything: an explicit choice beats a plugin |
|
|
117
|
+
| a `realtime.bus` plugin in `weft.config.ts` (this one, or `@weft-js/realtime-redis`) | the memory bus |
|
|
118
|
+
| nothing | the memory bus, one process only |
|
|
119
|
+
|
|
120
|
+
### Using it without the plugin
|
|
121
|
+
|
|
122
|
+
`natsBus()` is a plain function, so you can set it in `src/realtime.server.ts` instead:
|
|
123
|
+
|
|
124
|
+
```ts
|
|
125
|
+
// src/realtime.server.ts
|
|
126
|
+
import { realtime } from '@weft-js/start'
|
|
127
|
+
import { natsBus } from '@weft-js/realtime-nats'
|
|
128
|
+
|
|
129
|
+
export default realtime({
|
|
130
|
+
bus: natsBus({
|
|
131
|
+
servers: ['nats://nats-1:4222', 'nats://nats-2:4222'],
|
|
132
|
+
token: process.env.NATS_TOKEN,
|
|
133
|
+
}),
|
|
134
|
+
})
|
|
9
135
|
```
|
|
136
|
+
|
|
137
|
+
Use this form when you want the bus next to `origins`, `limits` or `changes`, or read credentials from variables of
|
|
138
|
+
your own. The package still has to be installed.
|
|
139
|
+
|
|
140
|
+
## Options
|
|
141
|
+
|
|
142
|
+
`nats(options)` in `weft.config.ts` and `natsBus(options)` take the same options. The plugin passes them through to
|
|
143
|
+
`bus()`, which fills `servers` from `NATS_URL` when it's missing.
|
|
144
|
+
|
|
145
|
+
| Option | Type | Default | What it does |
|
|
146
|
+
| --- | --- | --- | --- |
|
|
147
|
+
| `servers` | `string \| string[]` | `process.env.NATS_URL` (plugin and `bus()` only) | `nats://host:4222`, or several. Required for `natsBus()`. |
|
|
148
|
+
| `token` | `string` | none | Token auth. |
|
|
149
|
+
| `user` | `string` | none | User for user/password auth. |
|
|
150
|
+
| `pass` | `string` | none | Password for user/password auth. |
|
|
151
|
+
|
|
152
|
+
The options are passed to the NATS client's `connect()`, with `maxReconnectAttempts: -1` (retry forever) and
|
|
153
|
+
`reconnectTimeWait: 500` (ms) added. The plugin's options end up in generated code, so keep secrets out of them: set
|
|
154
|
+
credentials in `src/realtime.server.ts` from the environment, as in the example above.
|
|
155
|
+
|
|
156
|
+
### Environment
|
|
157
|
+
|
|
158
|
+
| Variable | Read by | Needed |
|
|
159
|
+
| --- | --- | --- |
|
|
160
|
+
| `NATS_URL` | the plugin and `bus()` | At run time, unless `servers` is given. One URL; pass `servers` for several. |
|
|
161
|
+
| `WEFT_BUILD` | `natsBus()` | Set by `weft build`. While it's set, missing `servers` is not an error, since a build never connects. |
|
|
162
|
+
|
|
163
|
+
### What the plugin declares
|
|
164
|
+
|
|
165
|
+
| Permission | Value |
|
|
166
|
+
| --- | --- |
|
|
167
|
+
| `net` | `env:NATS_URL`, the host in that variable |
|
|
168
|
+
| `env` | `NATS_URL`, `WEFT_BUILD` |
|
|
169
|
+
|
|
170
|
+
## How it behaves
|
|
171
|
+
|
|
172
|
+
- **One connection** per bus, opened on first use. If it fails, the next publish or subscribe tries again.
|
|
173
|
+
- **Subjects.** A channel `c` is published on `weft.` followed by `c` in base64url, so any string works and nothing
|
|
174
|
+
collides with your own subjects outside `weft.`.
|
|
175
|
+
- **`subscribe` waits for the server.** It flushes after subscribing, so a publish made after `subscribe` resolves is
|
|
176
|
+
delivered.
|
|
177
|
+
- **A reconnect is a gap.** Core NATS keeps nothing for a subscriber that was away. On each `reconnect` status the bus
|
|
178
|
+
calls the hub's `gap`, and the hub treats everything before it as outside the resume window.
|
|
179
|
+
- **`close()`** closes the connection. The next use connects again.
|
|
180
|
+
|
|
181
|
+
## API reference
|
|
182
|
+
|
|
183
|
+
| Export | From | What it is |
|
|
184
|
+
| --- | --- | --- |
|
|
185
|
+
| `natsBus(options)` | `@weft-js/realtime-nats` | A `Bus` over core NATS, connecting on first use. Throws Q013 without `servers`, except during a build. |
|
|
186
|
+
| `bus(options?)` | `@weft-js/realtime-nats` | The `realtime.bus` provider the plugin loads: `natsBus` with `servers` defaulting to `NATS_URL`. |
|
|
187
|
+
| `NatsBusOptions` | `@weft-js/realtime-nats` | Type: `{ servers: string \| string[]; token?: string; user?: string; pass?: string }`. |
|
|
188
|
+
| default export, `nats` | `@weft-js/realtime-nats/plugin` | The plugin for `weft.config.ts`. Takes the same options as `bus()`. |
|
|
189
|
+
|
|
190
|
+
The returned bus has `name: 'nats'`, `publish(channel, message)`, `subscribe(channel, on, gap?)` and `close()`.
|
|
191
|
+
|
|
192
|
+
## Recipes
|
|
193
|
+
|
|
194
|
+
### A cluster
|
|
195
|
+
|
|
196
|
+
```ts
|
|
197
|
+
// src/realtime.server.ts
|
|
198
|
+
import { realtime } from '@weft-js/start'
|
|
199
|
+
import { natsBus } from '@weft-js/realtime-nats'
|
|
200
|
+
|
|
201
|
+
export default realtime({
|
|
202
|
+
bus: natsBus({
|
|
203
|
+
servers: (process.env.NATS_SERVERS ?? '').split(','),
|
|
204
|
+
}),
|
|
205
|
+
})
|
|
206
|
+
```
|
|
207
|
+
|
|
208
|
+
### User and password from the environment
|
|
209
|
+
|
|
210
|
+
```ts
|
|
211
|
+
// src/realtime.server.ts
|
|
212
|
+
import { realtime } from '@weft-js/start'
|
|
213
|
+
import { natsBus } from '@weft-js/realtime-nats'
|
|
214
|
+
|
|
215
|
+
export default realtime({
|
|
216
|
+
bus: natsBus({
|
|
217
|
+
servers: process.env.NATS_URL ?? '',
|
|
218
|
+
user: process.env.NATS_USER,
|
|
219
|
+
pass: process.env.NATS_PASS,
|
|
220
|
+
}),
|
|
221
|
+
})
|
|
222
|
+
```
|
|
223
|
+
|
|
224
|
+
### Watching Weft's traffic
|
|
225
|
+
|
|
226
|
+
Every subject starts with `weft.`, so the NATS CLI can show it: `nats sub 'weft.>'`. The rest of each subject is the
|
|
227
|
+
channel name in base64url.
|
|
228
|
+
|
|
229
|
+
## Limits
|
|
230
|
+
|
|
231
|
+
- **Core NATS only.** No JetStream, so there's no history or replay: a message published while an instance is
|
|
232
|
+
disconnected is gone for that instance, which gets a gap instead.
|
|
233
|
+
- **No TLS, NKey or creds-file options.** Only `servers`, `token`, `user` and `pass` are typed.
|
|
234
|
+
- **Messages are strings.** The hub serializes; the bus never parses.
|
|
235
|
+
- **Sizes are the hub's.** A message over 1 MiB is refused by the hub (R008). The NATS server's own `max_payload`
|
|
236
|
+
setting also applies.
|
|
237
|
+
|
|
238
|
+
## Troubleshooting
|
|
239
|
+
|
|
240
|
+
| Symptom | Cause | Fix |
|
|
241
|
+
| --- | --- | --- |
|
|
242
|
+
| `Q013` "`natsBus` needs `servers`" at startup | `NATS_URL` is unset and no `servers` was passed | Set `NATS_URL`, or pass `servers`. |
|
|
243
|
+
| `R002` from `weft build` | The preset runs many instances and the app is still on the memory bus | Add this plugin, `@weft-js/realtime-redis`, or `postgresBus` in `src/realtime.server.ts`. |
|
|
244
|
+
| `E009` from `weft deploy` | The same problem, found for a deploy target | As above. |
|
|
245
|
+
| The plugin is listed but nothing crosses instances | `src/realtime.server.ts` sets its own `bus`, which wins | Remove that `bus`, or set `natsBus()` there. |
|
|
246
|
+
| Authorization errors in the server log | The server wants credentials | Pass `token`, or `user` and `pass`. |
|
|
247
|
+
| Messages published while NATS was down never arrived | Core NATS keeps nothing; the reconnect was reported as a gap | Expected. Put what must survive in a mutation, and refetch after a gap. |
|
|
248
|
+
|
|
249
|
+
## Related packages
|
|
250
|
+
|
|
251
|
+
| Package | What it is |
|
|
252
|
+
| --- | --- |
|
|
253
|
+
| [`@weft-js/start`](https://www.npmjs.com/package/@weft-js/start) | The full-stack runtime: the realtime hub, `realtime()`, `memoryBus` and `postgresBus` (`@weft-js/start/bus/postgres`). |
|
|
254
|
+
| [`@weft-js/realtime-redis`](https://www.npmjs.com/package/@weft-js/realtime-redis) | The same slot on Redis pub/sub. |
|
|
255
|
+
| [`@weft-js/realtime-durable-object`](https://www.npmjs.com/package/@weft-js/realtime-durable-object) | The bus for Cloudflare, on Durable Objects. |
|
|
256
|
+
| [`@weft-js/multiplayer`](https://www.npmjs.com/package/@weft-js/multiplayer) | Presence, cursors and a relay on `channel`. Its traffic crosses instances through this bus. |
|
|
257
|
+
| [`@weft-js/core`](https://www.npmjs.com/package/@weft-js/core) | The plugin system (`definePlugin`, slots) and `busSuite`, the conformance checks a bus must pass. |
|
|
258
|
+
|
|
259
|
+
## Contributing
|
|
260
|
+
|
|
261
|
+
See [CONTRIBUTING.md](https://github.com/Ravonus/weft/blob/main/CONTRIBUTING.md). To test this package:
|
|
262
|
+
|
|
263
|
+
```bash
|
|
264
|
+
pnpm --filter @weft-js/realtime-nats test
|
|
265
|
+
```
|
|
266
|
+
|
|
267
|
+
The test against a real server needs a `nats-server` binary. Name it in `WEFT_TEST_NATS`; without it that test is
|
|
268
|
+
skipped and says so:
|
|
269
|
+
|
|
270
|
+
```bash
|
|
271
|
+
WEFT_TEST_NATS=$(command -v nats-server) \
|
|
272
|
+
pnpm --filter @weft-js/realtime-nats test
|
|
273
|
+
```
|
|
274
|
+
|
|
275
|
+
## License
|
|
276
|
+
|
|
277
|
+
[MIT](https://github.com/Ravonus/weft/blob/main/LICENSE)
|
package/package.json
CHANGED
|
@@ -1,8 +1,17 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@weft-js/realtime-nats",
|
|
3
|
-
"version": "0.1.
|
|
3
|
+
"version": "0.1.3",
|
|
4
4
|
"description": "@weft-js/realtime-nats: the realtime.bus provider for core NATS",
|
|
5
5
|
"license": "MIT",
|
|
6
|
+
"repository": {
|
|
7
|
+
"type": "git",
|
|
8
|
+
"url": "git+https://github.com/Ravonus/weft.git",
|
|
9
|
+
"directory": "packages/realtime-nats"
|
|
10
|
+
},
|
|
11
|
+
"homepage": "https://github.com/Ravonus/weft/tree/main/packages/realtime-nats#readme",
|
|
12
|
+
"bugs": {
|
|
13
|
+
"url": "https://github.com/Ravonus/weft/issues"
|
|
14
|
+
},
|
|
6
15
|
"type": "module",
|
|
7
16
|
"exports": {
|
|
8
17
|
".": "./src/index.ts",
|
|
@@ -12,8 +21,8 @@
|
|
|
12
21
|
"@nats-io/transport-node": "3.4.0"
|
|
13
22
|
},
|
|
14
23
|
"peerDependencies": {
|
|
15
|
-
"@weft-js/start": "^0.1.
|
|
16
|
-
"@weft-js/core": "^0.1.
|
|
24
|
+
"@weft-js/start": "^0.1.3",
|
|
25
|
+
"@weft-js/core": "^0.1.3"
|
|
17
26
|
},
|
|
18
27
|
"engines": {
|
|
19
28
|
"node": ">=26"
|
|
@@ -31,4 +40,4 @@
|
|
|
31
40
|
"publishConfig": {
|
|
32
41
|
"access": "public"
|
|
33
42
|
}
|
|
34
|
-
}
|
|
43
|
+
}
|
package/plugin.mjs
CHANGED
|
@@ -9,10 +9,23 @@ export const nats = definePlugin({
|
|
|
9
9
|
version: '0.1.0',
|
|
10
10
|
weft: '*',
|
|
11
11
|
permissions: { net: ['env:NATS_URL'], env: ['NATS_URL', 'WEFT_BUILD'] },
|
|
12
|
-
contribute: options => ({
|
|
13
|
-
provides: [
|
|
14
|
-
|
|
15
|
-
|
|
12
|
+
contribute: (options) => ({
|
|
13
|
+
provides: [
|
|
14
|
+
provide(slot, {
|
|
15
|
+
sides: { server: { module: '@weft-js/realtime-nats', export: 'bus', options } },
|
|
16
|
+
}),
|
|
17
|
+
],
|
|
18
|
+
agents: {
|
|
19
|
+
title: 'Realtime bus (NATS)',
|
|
20
|
+
text: '`realtime.bus` is NATS, at `NATS_URL`. Rooms, shared state, `.live` and streams reach every instance. It is at-most-once: anything that must survive is a mutation, and `collect` plus a query covers a gap.',
|
|
21
|
+
},
|
|
22
|
+
map: [
|
|
23
|
+
{
|
|
24
|
+
want: 'Change the realtime bus',
|
|
25
|
+
call: 'replace this plugin in `plugins`, or set `bus` in `src/realtime.server.ts`',
|
|
26
|
+
have: 'NATS',
|
|
27
|
+
},
|
|
28
|
+
],
|
|
16
29
|
}),
|
|
17
30
|
})
|
|
18
31
|
|
package/src/index.ts
CHANGED
|
@@ -18,28 +18,42 @@ const subject = (channel: string) => `weft.${Buffer.from(channel).toString('base
|
|
|
18
18
|
|
|
19
19
|
/** A `Bus` over core NATS, connecting on first use. Throws Q013 without `servers`, except during a build. */
|
|
20
20
|
export function natsBus(options: NatsBusOptions): Bus {
|
|
21
|
-
if (!options.servers?.length && process.env.WEFT_BUILD)
|
|
21
|
+
if (!options.servers?.length && process.env.WEFT_BUILD)
|
|
22
|
+
options = { ...options, servers: 'nats://localhost:4222' } // a build never connects
|
|
22
23
|
if (!options.servers?.length)
|
|
23
|
-
throw new StartError(
|
|
24
|
+
throw new StartError(
|
|
25
|
+
'Q013',
|
|
26
|
+
'`natsBus` needs `servers`',
|
|
27
|
+
'set the URL, or leave `bus` out for the memory bus on one instance',
|
|
28
|
+
)
|
|
24
29
|
let nc: Promise<NatsConnection> | undefined
|
|
25
30
|
const gaps = new Set<() => void>()
|
|
26
|
-
const client = () =>
|
|
27
|
-
|
|
28
|
-
|
|
29
|
-
|
|
30
|
-
|
|
31
|
-
|
|
32
|
-
|
|
33
|
-
|
|
34
|
-
|
|
31
|
+
const client = () =>
|
|
32
|
+
(nc ??= connect({ ...options, maxReconnectAttempts: -1, reconnectTimeWait: 500 }).then(
|
|
33
|
+
(c) => {
|
|
34
|
+
void (async () => {
|
|
35
|
+
for await (const s of c.status())
|
|
36
|
+
if (s.type === 'reconnect') for (const gap of gaps) gap()
|
|
37
|
+
})()
|
|
38
|
+
return c
|
|
39
|
+
},
|
|
40
|
+
(e) => {
|
|
41
|
+
nc = undefined // the next use tries again
|
|
42
|
+
throw e
|
|
43
|
+
},
|
|
44
|
+
))
|
|
35
45
|
return {
|
|
36
46
|
name: 'nats',
|
|
37
47
|
async publish(channel, message) {
|
|
38
|
-
(await client()).publish(subject(channel), message)
|
|
48
|
+
;(await client()).publish(subject(channel), message)
|
|
39
49
|
},
|
|
40
50
|
async subscribe(channel, on, gap) {
|
|
41
51
|
const c = await client()
|
|
42
|
-
const sub = c.subscribe(subject(channel), {
|
|
52
|
+
const sub = c.subscribe(subject(channel), {
|
|
53
|
+
callback: (e, m) => {
|
|
54
|
+
if (!e) on(m.string())
|
|
55
|
+
},
|
|
56
|
+
})
|
|
43
57
|
await c.flush() // the server has the subscription: a publish after this resolves is delivered
|
|
44
58
|
if (gap) gaps.add(gap)
|
|
45
59
|
return () => {
|
|
@@ -56,4 +70,5 @@ export function natsBus(options: NatsBusOptions): Bus {
|
|
|
56
70
|
}
|
|
57
71
|
|
|
58
72
|
/** The `realtime.bus` provider: `NATS_URL` unless the plugin was given `servers`. */
|
|
59
|
-
export const bus = (options: Partial<NatsBusOptions> = {}) =>
|
|
73
|
+
export const bus = (options: Partial<NatsBusOptions> = {}) =>
|
|
74
|
+
natsBus({ ...options, servers: options.servers ?? process.env.NATS_URL ?? '' })
|