@tiaforge-ui/sinter 0.3.1 → 0.3.2
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/dist/sse.js +28 -22
- package/package.json +1 -1
package/dist/sse.js
CHANGED
|
@@ -34,25 +34,21 @@ export function eventSourceTransport() {
|
|
|
34
34
|
close() { es?.close(); es = null; },
|
|
35
35
|
};
|
|
36
36
|
}
|
|
37
|
+
/** One stream URL's connection, shared by every `<sn-sync>` on the page that resolves to it. */
|
|
37
38
|
class Connection {
|
|
38
39
|
app;
|
|
39
|
-
|
|
40
|
+
url;
|
|
40
41
|
t = null;
|
|
41
42
|
backoff = MIN_BACKOFF;
|
|
42
43
|
timer = null;
|
|
43
44
|
closed = false;
|
|
44
45
|
hidden = false;
|
|
45
46
|
everOpen = false;
|
|
46
|
-
|
|
47
|
-
|
|
48
|
-
|
|
49
|
-
base;
|
|
50
|
-
constructor(app, def) {
|
|
47
|
+
/** each mapped event with the scope its expressions are evaluated in: its `<sn-sync>`'s state, or the page */
|
|
48
|
+
subs = [];
|
|
49
|
+
constructor(app, url) {
|
|
51
50
|
this.app = app;
|
|
52
|
-
this.
|
|
53
|
-
this.base = app.scopeOf(def.scope ?? -1);
|
|
54
|
-
this.url = app.url(def.src, this.base);
|
|
55
|
-
this.fed = [...new Set(def.events.map((e) => e.resource))];
|
|
51
|
+
this.url = url;
|
|
56
52
|
}
|
|
57
53
|
start() {
|
|
58
54
|
const env = this.app.env;
|
|
@@ -68,9 +64,6 @@ class Connection {
|
|
|
68
64
|
this.app.addCleanup(() => { this.closed = true; this.stop(); });
|
|
69
65
|
this.open();
|
|
70
66
|
}
|
|
71
|
-
names() {
|
|
72
|
-
return [...new Set(this.def.events.map((e) => e.name))];
|
|
73
|
-
}
|
|
74
67
|
open() {
|
|
75
68
|
if (this.closed && !this.hidden)
|
|
76
69
|
return;
|
|
@@ -78,6 +71,7 @@ class Connection {
|
|
|
78
71
|
const t = custom ?? eventSourceTransport();
|
|
79
72
|
this.t = t;
|
|
80
73
|
const reconnect = this.everOpen;
|
|
74
|
+
const subs = this.subs.map(([e]) => e);
|
|
81
75
|
t.connect(this.url, (name, data) => this.event(name, data), (state) => {
|
|
82
76
|
if (this.t !== t)
|
|
83
77
|
return;
|
|
@@ -88,7 +82,7 @@ class Connection {
|
|
|
88
82
|
this.app.streamOpened?.(this.url);
|
|
89
83
|
// events sent while disconnected are lost: refetch everything this stream feeds
|
|
90
84
|
if (reconnect)
|
|
91
|
-
for (const name of
|
|
85
|
+
for (const name of new Set(subs.map((e) => e.resource)))
|
|
92
86
|
void this.app.resource(name).refetch();
|
|
93
87
|
}
|
|
94
88
|
else {
|
|
@@ -96,7 +90,7 @@ class Connection {
|
|
|
96
90
|
this.t = null;
|
|
97
91
|
void this.probe();
|
|
98
92
|
}
|
|
99
|
-
},
|
|
93
|
+
}, [...new Set(subs.map((e) => e.name))]);
|
|
100
94
|
}
|
|
101
95
|
stop() {
|
|
102
96
|
this.t?.close();
|
|
@@ -135,14 +129,14 @@ class Connection {
|
|
|
135
129
|
this.timer = this.app.env.setTimeout(() => { this.timer = null; fn(); }, delay, 'backoff');
|
|
136
130
|
}
|
|
137
131
|
event(name, payload) {
|
|
138
|
-
for (const def of this.
|
|
132
|
+
for (const [def, base] of this.subs)
|
|
139
133
|
if (def.name === name)
|
|
140
|
-
this.apply(def, payload);
|
|
134
|
+
this.apply(def, base, payload);
|
|
141
135
|
this.app.serverEvent(name, payload);
|
|
142
136
|
}
|
|
143
|
-
apply(def, payload) {
|
|
137
|
+
apply(def, base, payload) {
|
|
144
138
|
const app = this.app;
|
|
145
|
-
const scope = Object.create(
|
|
139
|
+
const scope = Object.create(base);
|
|
146
140
|
scope.$p = payload && typeof payload === 'object' ? payload : {};
|
|
147
141
|
const r = app.resource(def.resource);
|
|
148
142
|
try {
|
|
@@ -203,9 +197,21 @@ const sse = {
|
|
|
203
197
|
let alive = true;
|
|
204
198
|
app.addCleanup(() => { alive = false; });
|
|
205
199
|
app.env.queueMicrotask(() => {
|
|
206
|
-
if (alive)
|
|
207
|
-
|
|
208
|
-
|
|
200
|
+
if (!alive)
|
|
201
|
+
return;
|
|
202
|
+
// one connection per resolved stream URL, however many <sn-sync> elements use it
|
|
203
|
+
const conns = new Map();
|
|
204
|
+
for (const def of app.ir.syncs) {
|
|
205
|
+
const base = app.scopeOf(def.scope ?? -1);
|
|
206
|
+
const url = app.url(def.src, base);
|
|
207
|
+
let c = conns.get(url);
|
|
208
|
+
if (!c)
|
|
209
|
+
conns.set(url, c = new Connection(app, url));
|
|
210
|
+
for (const e of def.events)
|
|
211
|
+
c.subs.push([e, base]);
|
|
212
|
+
}
|
|
213
|
+
for (const c of conns.values())
|
|
214
|
+
c.start();
|
|
209
215
|
});
|
|
210
216
|
},
|
|
211
217
|
};
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@tiaforge-ui/sinter",
|
|
3
|
-
"version": "0.3.
|
|
3
|
+
"version": "0.3.2",
|
|
4
4
|
"description": "Bind JSON APIs to plain HTML: keyed resources, SSE sync, template bindings and optimistic mutations, compiled at build time.",
|
|
5
5
|
"license": "MIT",
|
|
6
6
|
"author": "Tia Heinrich",
|