@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.
Files changed (2) hide show
  1. package/dist/sse.js +28 -22
  2. 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
- def;
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
- url;
47
- fed;
48
- /** where `src` and the events' expressions are evaluated: the enclosing state's scope, or the page */
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.def = def;
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 this.fed)
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
- }, this.names());
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.def.events)
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(this.base);
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
- for (const def of app.ir.syncs)
208
- new Connection(app, def).start();
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.1",
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",