@rvettori/elysia-broadcast 0.2.0 → 0.3.0
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 +45 -1
- package/dist/client.js +8 -0
- package/dist/index.js +21 -3
- package/package.json +1 -1
- package/src/client.js +8 -0
package/README.md
CHANGED
|
@@ -8,6 +8,7 @@ Broadcast and Server-Sent Events (SSE) system for Elysia with multi-channel per-
|
|
|
8
8
|
- ✅ **Type-safe** - Fully typed with TypeScript
|
|
9
9
|
- ✅ **SSE out-of-the-box** - Ready-to-use Server-Sent Events plugin with client library
|
|
10
10
|
- ✅ **Alpine.js compatible** - Works seamlessly with Alpine.morph and x-sync
|
|
11
|
+
- ✅ **JSON events** - Dispatches native `CustomEvent` on `document` for JSON-only broadcasts
|
|
11
12
|
- ✅ **Flexible** - Use `BroadcastManager` standalone or as an Elysia plugin
|
|
12
13
|
- ✅ **Lightweight** - Zero dependencies besides Elysia
|
|
13
14
|
- ✅ **Tested** - Complete test coverage
|
|
@@ -227,7 +228,7 @@ Removes all connections.
|
|
|
227
228
|
// Basic connection
|
|
228
229
|
ElysiaSSE.connect('notifications');
|
|
229
230
|
|
|
230
|
-
// With custom handler
|
|
231
|
+
// With custom handler (receives the full event object)
|
|
231
232
|
ElysiaSSE.connect('messages', {
|
|
232
233
|
onUpdate: (data) => {
|
|
233
234
|
console.log('New message:', data);
|
|
@@ -239,6 +240,49 @@ Removes all connections.
|
|
|
239
240
|
</script>
|
|
240
241
|
```
|
|
241
242
|
|
|
243
|
+
### JSON Events (CustomEvent)
|
|
244
|
+
|
|
245
|
+
When a broadcast includes a `data` payload, the client automatically dispatches a native `CustomEvent` on `document` with the name `sse:<type>`. This works regardless of whether `html` is also present.
|
|
246
|
+
|
|
247
|
+
**Server:**
|
|
248
|
+
```typescript
|
|
249
|
+
store.broadcast.broadcast('notifications', userId, {
|
|
250
|
+
type: 'notification.new',
|
|
251
|
+
data: { title: 'New comment', message: 'Someone replied to your post' }
|
|
252
|
+
});
|
|
253
|
+
```
|
|
254
|
+
|
|
255
|
+
**Client — Vanilla JS:**
|
|
256
|
+
```html
|
|
257
|
+
<script src="/vendor/elysia-sse.js"></script>
|
|
258
|
+
<script>
|
|
259
|
+
ElysiaSSE.connect('notifications');
|
|
260
|
+
|
|
261
|
+
document.addEventListener('sse:notification.new', (e) => {
|
|
262
|
+
const { title, message } = e.detail.data;
|
|
263
|
+
console.log(title, message);
|
|
264
|
+
});
|
|
265
|
+
</script>
|
|
266
|
+
```
|
|
267
|
+
|
|
268
|
+
**Client — Alpine.js:**
|
|
269
|
+
```html
|
|
270
|
+
<div x-data="{ count: 0 }" @sse:notification.new.document="count++">
|
|
271
|
+
<span x-text="count"></span> unread
|
|
272
|
+
</div>
|
|
273
|
+
```
|
|
274
|
+
|
|
275
|
+
When `html` and `data` are sent together, both are processed: the DOM is updated via Alpine.morph **and** the `CustomEvent` is dispatched.
|
|
276
|
+
|
|
277
|
+
```typescript
|
|
278
|
+
// Both html update and CustomEvent will fire
|
|
279
|
+
store.broadcast.broadcast('todos', userId, {
|
|
280
|
+
type: 'todo.created',
|
|
281
|
+
data: { id: 1, task: 'New task' },
|
|
282
|
+
html: '<div x-sync id="todo-list">...</div>'
|
|
283
|
+
});
|
|
284
|
+
```
|
|
285
|
+
|
|
242
286
|
### HTMX + SSE
|
|
243
287
|
|
|
244
288
|
```html
|
package/dist/client.js
CHANGED
|
@@ -112,6 +112,14 @@ window.ElysiaSSE = {
|
|
|
112
112
|
console.error('❌ [SSE] Erros:', errors.join(', '));
|
|
113
113
|
}
|
|
114
114
|
}
|
|
115
|
+
|
|
116
|
+
// Dispatch native CustomEvent whenever data payload is present
|
|
117
|
+
if (data.data !== undefined) {
|
|
118
|
+
document.dispatchEvent(new CustomEvent('sse:' + data.type, {
|
|
119
|
+
detail: data,
|
|
120
|
+
bubbles: true
|
|
121
|
+
}));
|
|
122
|
+
}
|
|
115
123
|
} catch (error) {
|
|
116
124
|
console.error('❌ [SSE] Erro ao processar evento:', error);
|
|
117
125
|
}
|
package/dist/index.js
CHANGED
|
@@ -4,25 +4,43 @@ var __getProtoOf = Object.getPrototypeOf;
|
|
|
4
4
|
var __defProp = Object.defineProperty;
|
|
5
5
|
var __getOwnPropNames = Object.getOwnPropertyNames;
|
|
6
6
|
var __hasOwnProp = Object.prototype.hasOwnProperty;
|
|
7
|
+
function __accessProp(key) {
|
|
8
|
+
return this[key];
|
|
9
|
+
}
|
|
10
|
+
var __toESMCache_node;
|
|
11
|
+
var __toESMCache_esm;
|
|
7
12
|
var __toESM = (mod, isNodeMode, target) => {
|
|
13
|
+
var canCache = mod != null && typeof mod === "object";
|
|
14
|
+
if (canCache) {
|
|
15
|
+
var cache = isNodeMode ? __toESMCache_node ??= new WeakMap : __toESMCache_esm ??= new WeakMap;
|
|
16
|
+
var cached = cache.get(mod);
|
|
17
|
+
if (cached)
|
|
18
|
+
return cached;
|
|
19
|
+
}
|
|
8
20
|
target = mod != null ? __create(__getProtoOf(mod)) : {};
|
|
9
21
|
const to = isNodeMode || !mod || !mod.__esModule ? __defProp(target, "default", { value: mod, enumerable: true }) : target;
|
|
10
22
|
for (let key of __getOwnPropNames(mod))
|
|
11
23
|
if (!__hasOwnProp.call(to, key))
|
|
12
24
|
__defProp(to, key, {
|
|
13
|
-
get: (
|
|
25
|
+
get: __accessProp.bind(mod, key),
|
|
14
26
|
enumerable: true
|
|
15
27
|
});
|
|
28
|
+
if (canCache)
|
|
29
|
+
cache.set(mod, to);
|
|
16
30
|
return to;
|
|
17
31
|
};
|
|
18
32
|
var __commonJS = (cb, mod) => () => (mod || cb((mod = { exports: {} }).exports, mod), mod.exports);
|
|
33
|
+
var __returnValue = (v) => v;
|
|
34
|
+
function __exportSetter(name, newValue) {
|
|
35
|
+
this[name] = __returnValue.bind(null, newValue);
|
|
36
|
+
}
|
|
19
37
|
var __export = (target, all) => {
|
|
20
38
|
for (var name in all)
|
|
21
39
|
__defProp(target, name, {
|
|
22
40
|
get: all[name],
|
|
23
41
|
enumerable: true,
|
|
24
42
|
configurable: true,
|
|
25
|
-
set: (
|
|
43
|
+
set: __exportSetter.bind(all, name)
|
|
26
44
|
});
|
|
27
45
|
};
|
|
28
46
|
var __esm = (fn, res) => () => (fn && (res = fn(fn = 0)), res);
|
|
@@ -6631,7 +6649,6 @@ __export(exports_type3, {
|
|
|
6631
6649
|
|
|
6632
6650
|
// node_modules/@sinclair/typebox/build/esm/type/type/index.mjs
|
|
6633
6651
|
var Type = exports_type3;
|
|
6634
|
-
|
|
6635
6652
|
// node_modules/@sinclair/typebox/build/esm/errors/function.mjs
|
|
6636
6653
|
function DefaultErrorFunction(error) {
|
|
6637
6654
|
switch (error.errorType) {
|
|
@@ -7909,6 +7926,7 @@ function Errors(...args) {
|
|
|
7909
7926
|
const iterator = args.length === 3 ? Visit6(args[0], args[1], "", args[2]) : Visit6(args[0], [], "", args[1]);
|
|
7910
7927
|
return new ValueErrorIterator(iterator);
|
|
7911
7928
|
}
|
|
7929
|
+
|
|
7912
7930
|
// node_modules/@sinclair/typebox/build/esm/value/assert/assert.mjs
|
|
7913
7931
|
var __classPrivateFieldSet = function(receiver, state, value, kind, f) {
|
|
7914
7932
|
if (kind === "m")
|
package/package.json
CHANGED
package/src/client.js
CHANGED
|
@@ -112,6 +112,14 @@ window.ElysiaSSE = {
|
|
|
112
112
|
console.error('❌ [SSE] Erros:', errors.join(', '));
|
|
113
113
|
}
|
|
114
114
|
}
|
|
115
|
+
|
|
116
|
+
// Dispatch native CustomEvent whenever data payload is present
|
|
117
|
+
if (data.data !== undefined) {
|
|
118
|
+
document.dispatchEvent(new CustomEvent('sse:' + data.type, {
|
|
119
|
+
detail: data,
|
|
120
|
+
bubbles: true
|
|
121
|
+
}));
|
|
122
|
+
}
|
|
115
123
|
} catch (error) {
|
|
116
124
|
console.error('❌ [SSE] Erro ao processar evento:', error);
|
|
117
125
|
}
|