@voltro/plugin-broadcast 0.86.0 → 0.87.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/CHANGELOG.md +5321 -0
- package/THIRD-PARTY-NOTICES.md +46 -214
- package/dist/index.d.ts +28 -82
- package/dist/plugin.js +34 -21
- package/dist/providers.js +36 -107
- package/dist/resolve.js +64 -47
- package/package.json +4 -7
package/dist/providers.js
CHANGED
|
@@ -50,117 +50,46 @@ var n = (t, n, r) => new e({
|
|
|
50
50
|
for (let e of n) e();
|
|
51
51
|
})
|
|
52
52
|
};
|
|
53
|
-
}, l = (e) => {
|
|
54
|
-
let
|
|
55
|
-
|
|
56
|
-
if (
|
|
57
|
-
|
|
58
|
-
|
|
59
|
-
|
|
60
|
-
|
|
61
|
-
} catch (e) {
|
|
62
|
-
throw r("redis", "the 'redis' broadcast provider requires the 'ioredis' optional dependency. Install it to enable it.", e);
|
|
63
|
-
}
|
|
64
|
-
t = new n(e.url);
|
|
65
|
-
}
|
|
66
|
-
let n = t.duplicate();
|
|
67
|
-
return t.on("error", () => {}), n.on("error", () => {}), n.on("reconnecting", () => {
|
|
68
|
-
s && (s = !1, o.emit({
|
|
69
|
-
kind: "disconnected",
|
|
70
|
-
detail: "ioredis is re-dialling"
|
|
71
|
-
}));
|
|
72
|
-
}), n.on("ready", () => {
|
|
73
|
-
s || (s = !0, o.emit({ kind: "reconnected" }));
|
|
74
|
-
}), {
|
|
75
|
-
pub: t,
|
|
76
|
-
sub: n
|
|
77
|
-
};
|
|
78
|
-
})().catch((e) => {
|
|
79
|
-
throw a = null, e;
|
|
80
|
-
}), a);
|
|
81
|
-
return {
|
|
82
|
-
name: "redis",
|
|
83
|
-
onTransportEvent: o.subscribe,
|
|
84
|
-
publish: (e, r) => t.tryPromise({
|
|
85
|
-
try: async () => {
|
|
86
|
-
let { pub: t } = await c();
|
|
87
|
-
await t.publish(e, r);
|
|
88
|
-
},
|
|
89
|
-
catch: (e) => n("redis", `publish failed: ${String(e?.message ?? e)}`, e)
|
|
90
|
-
}),
|
|
91
|
-
subscribe: (e, r) => t.tryPromise({
|
|
92
|
-
try: async () => {
|
|
93
|
-
let { sub: t } = await c(), n = (t, n) => {
|
|
94
|
-
t === e && r(n);
|
|
95
|
-
};
|
|
96
|
-
return t.on("message", n), await t.subscribe(e), () => {
|
|
97
|
-
t.off("message", n), t.unsubscribe(e).catch(() => void 0);
|
|
98
|
-
};
|
|
99
|
-
},
|
|
100
|
-
catch: (e) => n("redis", `subscribe failed: ${String(e?.message ?? e)}`, e)
|
|
101
|
-
}),
|
|
102
|
-
close: () => t.promise(async () => {
|
|
103
|
-
if (a) try {
|
|
104
|
-
let { pub: t, sub: n } = await a;
|
|
105
|
-
await n.quit(), e.client || await t.quit();
|
|
106
|
-
} catch {}
|
|
107
|
-
})
|
|
53
|
+
}, l = (e, a) => {
|
|
54
|
+
let o = i(), s = /* @__PURE__ */ new Set(), c, l, u = !1, d, f = (e) => (s.add(e), e.then(() => s.delete(e), () => s.delete(e)), e), p = (n) => {
|
|
55
|
+
if (u) return Promise.reject(r(e, "Broadcast consumer is closed"));
|
|
56
|
+
if (c !== void 0) return c;
|
|
57
|
+
let i = t.runPromiseWith(n)(a.pubsub).then((e) => (l = e.onTransportEvent(o.emit), e));
|
|
58
|
+
return c = i, i.catch(() => {
|
|
59
|
+
c === i && (c = void 0);
|
|
60
|
+
}), i;
|
|
108
61
|
};
|
|
109
|
-
}, u = new TextEncoder(), d = new TextDecoder(), f = (e) => {
|
|
110
|
-
let a = null, o = i(), s = !0, c = (e) => {
|
|
111
|
-
(async () => {
|
|
112
|
-
try {
|
|
113
|
-
for await (let t of e.status()) t.type === "disconnect" && s ? (s = !1, o.emit({
|
|
114
|
-
kind: "disconnected",
|
|
115
|
-
detail: "nats disconnected"
|
|
116
|
-
})) : t.type === "reconnect" && !s && (s = !0, o.emit({ kind: "reconnected" }));
|
|
117
|
-
} catch {}
|
|
118
|
-
})();
|
|
119
|
-
}, l = () => import("@nats-io/transport-node").catch((e) => {
|
|
120
|
-
throw r("nats", "the 'nats' broadcast provider requires the '@nats-io/transport-node' optional dependency. Install it to enable it.", e);
|
|
121
|
-
}), f = () => a || (a = (async () => {
|
|
122
|
-
if (e.connection) return e.connection;
|
|
123
|
-
let t = await (await l()).connect({
|
|
124
|
-
servers: e.url,
|
|
125
|
-
maxReconnectAttempts: -1,
|
|
126
|
-
waitOnFirstConnect: !0,
|
|
127
|
-
reconnectTimeWait: 2e3
|
|
128
|
-
});
|
|
129
|
-
return c(t), t;
|
|
130
|
-
})().catch((e) => {
|
|
131
|
-
throw a = null, e;
|
|
132
|
-
}), a);
|
|
133
62
|
return {
|
|
134
|
-
name:
|
|
63
|
+
name: e,
|
|
135
64
|
onTransportEvent: o.subscribe,
|
|
136
|
-
publish: (
|
|
137
|
-
try: async () => {
|
|
138
|
-
|
|
139
|
-
|
|
140
|
-
|
|
141
|
-
|
|
142
|
-
|
|
143
|
-
|
|
144
|
-
|
|
145
|
-
|
|
146
|
-
|
|
147
|
-
|
|
148
|
-
|
|
149
|
-
|
|
150
|
-
|
|
151
|
-
|
|
152
|
-
|
|
65
|
+
publish: (i, a) => t.flatMap(t.context(), (o) => t.tryPromise({
|
|
66
|
+
try: () => f((async () => {
|
|
67
|
+
let n = await p(o);
|
|
68
|
+
if (u) throw r(e, "Broadcast consumer is closed");
|
|
69
|
+
await t.runPromiseWith(o)(n.publish(i, a));
|
|
70
|
+
})()),
|
|
71
|
+
catch: () => n(e, `${e} publication failed`)
|
|
72
|
+
})),
|
|
73
|
+
subscribe: (i, a) => t.flatMap(t.context(), (o) => t.tryPromise({
|
|
74
|
+
try: () => f((async () => {
|
|
75
|
+
let n = await p(o);
|
|
76
|
+
if (u) throw r(e, "Broadcast consumer is closed");
|
|
77
|
+
let s = !0, c = await t.runPromiseWith(o)(n.subscribe(i, (e) => {
|
|
78
|
+
s && !u && a(e);
|
|
79
|
+
}));
|
|
80
|
+
if (u) throw s = !1, await t.runPromiseWith(o)(c), r(e, "Broadcast consumer is closed");
|
|
81
|
+
return () => {
|
|
82
|
+
s && (s = !1, f(t.runPromiseWith(o)(c)).catch(() => void 0));
|
|
153
83
|
};
|
|
154
|
-
},
|
|
155
|
-
catch: (
|
|
156
|
-
}),
|
|
157
|
-
close: () => t.promise(async () => {
|
|
158
|
-
if (
|
|
159
|
-
|
|
160
|
-
e.connection || await t.drain();
|
|
84
|
+
})()),
|
|
85
|
+
catch: () => n(e, `${e} subscription failed`)
|
|
86
|
+
})),
|
|
87
|
+
close: () => t.flatMap(t.context(), (e) => t.promise(() => d ??= (async () => {
|
|
88
|
+
if (u = !0, await Promise.allSettled([...s]), l?.(), c !== void 0) try {
|
|
89
|
+
await t.runPromiseWith(e)((await c).close);
|
|
161
90
|
} catch {}
|
|
162
|
-
})
|
|
91
|
+
})()))
|
|
163
92
|
};
|
|
164
|
-
};
|
|
93
|
+
}, u = (e) => l("redis", e), d = (e) => l("nats", e);
|
|
165
94
|
//#endregion
|
|
166
|
-
export { c as memoryProvider,
|
|
95
|
+
export { c as memoryProvider, d as natsProvider, u as redisProvider, s as resetMemoryBus };
|
package/dist/resolve.js
CHANGED
|
@@ -1,53 +1,70 @@
|
|
|
1
1
|
import { memoryProvider as e, natsProvider as t, redisProvider as n } from "./providers.js";
|
|
2
|
+
import { Effect as r } from "effect";
|
|
2
3
|
//#region src/resolve.ts
|
|
3
|
-
var
|
|
4
|
-
if (
|
|
5
|
-
|
|
6
|
-
|
|
7
|
-
|
|
8
|
-
|
|
9
|
-
|
|
10
|
-
|
|
4
|
+
var i = (e) => {
|
|
5
|
+
if (!/^(redis|nats):[A-Za-z][A-Za-z0-9_-]*$/.test(e)) throw Error("Broadcast connections require redis:name or nats:name references");
|
|
6
|
+
return e.startsWith("nats:") ? "nats" : "redis";
|
|
7
|
+
}, a = (a, o, s = () => r.fail(/* @__PURE__ */ Error("Broadcast requires the app connection registry"))) => {
|
|
8
|
+
let c = [], l = (e, i, a) => {
|
|
9
|
+
c.push({
|
|
10
|
+
kind: e,
|
|
11
|
+
role: i,
|
|
12
|
+
...a === void 0 ? {} : { reference: a }
|
|
13
|
+
});
|
|
14
|
+
let o = r.suspend(() => s(i));
|
|
15
|
+
return e === "nats" ? t({ pubsub: o }) : n({ pubsub: o });
|
|
16
|
+
}, u;
|
|
17
|
+
if (typeof a.provider == "object") {
|
|
18
|
+
if (a.connection !== void 0) throw Error("A custom Broadcast provider cannot also select a registry connection");
|
|
19
|
+
u = a.provider;
|
|
20
|
+
} else {
|
|
21
|
+
let t = a.provider ?? o.BROADCAST_PROVIDER;
|
|
22
|
+
if (t !== void 0 && ![
|
|
23
|
+
"redis",
|
|
24
|
+
"nats",
|
|
25
|
+
"memory"
|
|
26
|
+
].includes(t)) throw Error("Broadcast provider must be redis, nats or memory");
|
|
27
|
+
let n = a.connection === void 0 ? void 0 : i(a.connection), r = t ?? n ?? (o.BROADCAST_NATS_URL || o.NATS_URL ? "nats" : o.BROADCAST_REDIS_URL || o.REDIS_URL ? "redis" : "memory");
|
|
28
|
+
if (n !== void 0 && r !== n) throw Error("Broadcast provider must match its connection kind");
|
|
29
|
+
u = r === "memory" ? e() : l(r === "nats" ? "nats" : "redis", "broadcast", a.connection);
|
|
11
30
|
}
|
|
12
|
-
let
|
|
13
|
-
|
|
14
|
-
|
|
15
|
-
|
|
16
|
-
|
|
17
|
-
|
|
18
|
-
|
|
19
|
-
|
|
20
|
-
|
|
21
|
-
return {
|
|
22
|
-
provider: e(),
|
|
23
|
-
url: null,
|
|
24
|
-
crossReplica: !1
|
|
25
|
-
};
|
|
26
|
-
}
|
|
27
|
-
return {
|
|
28
|
-
provider: n({ url: t }),
|
|
29
|
-
url: t,
|
|
30
|
-
crossReplica: !0
|
|
31
|
-
};
|
|
32
|
-
}
|
|
33
|
-
case "nats": {
|
|
34
|
-
let n = o ?? a.NATS_URL;
|
|
35
|
-
return n ? {
|
|
36
|
-
provider: t({ url: n }),
|
|
37
|
-
url: n,
|
|
38
|
-
crossReplica: !0
|
|
39
|
-
} : {
|
|
40
|
-
provider: e(),
|
|
41
|
-
url: null,
|
|
42
|
-
crossReplica: !1
|
|
43
|
-
};
|
|
44
|
-
}
|
|
45
|
-
default: return {
|
|
46
|
-
provider: e(),
|
|
47
|
-
url: null,
|
|
48
|
-
crossReplica: !1
|
|
49
|
-
};
|
|
31
|
+
let d = /* @__PURE__ */ new Map();
|
|
32
|
+
for (let e of [
|
|
33
|
+
"events",
|
|
34
|
+
"members",
|
|
35
|
+
"presence",
|
|
36
|
+
"revalidate"
|
|
37
|
+
]) {
|
|
38
|
+
let t = a[e];
|
|
39
|
+
t !== void 0 && d.set(e, l(i(t), e, t));
|
|
50
40
|
}
|
|
41
|
+
if (d.size === 0) return {
|
|
42
|
+
provider: u,
|
|
43
|
+
crossReplica: u.name !== "memory",
|
|
44
|
+
selections: c
|
|
45
|
+
};
|
|
46
|
+
let f = [.../* @__PURE__ */ new Set([u, ...d.values()])], p = (e) => {
|
|
47
|
+
let t = e.slice(e.indexOf(":") + 1).split(":")[0];
|
|
48
|
+
return d.get(t) ?? u;
|
|
49
|
+
};
|
|
50
|
+
return {
|
|
51
|
+
provider: {
|
|
52
|
+
name: [...new Set(f.map((e) => e.name))].join("+"),
|
|
53
|
+
publish: (e, t) => p(e).publish(e, t),
|
|
54
|
+
subscribe: (e, t) => p(e).subscribe(e, t),
|
|
55
|
+
onTransportEvent: (e) => {
|
|
56
|
+
let t = /* @__PURE__ */ new WeakSet(), n = f.flatMap((n) => n.onTransportEvent === void 0 ? [] : [n.onTransportEvent((n) => {
|
|
57
|
+
t.has(n) || (t.add(n), e(n));
|
|
58
|
+
})]);
|
|
59
|
+
return () => {
|
|
60
|
+
for (let e of n) e();
|
|
61
|
+
};
|
|
62
|
+
},
|
|
63
|
+
close: () => r.forEach(f, (e) => e.close(), { discard: !0 }).pipe(r.asVoid)
|
|
64
|
+
},
|
|
65
|
+
crossReplica: f.some((e) => e.name !== "memory"),
|
|
66
|
+
selections: c
|
|
67
|
+
};
|
|
51
68
|
};
|
|
52
69
|
//#endregion
|
|
53
|
-
export {
|
|
70
|
+
export { a as resolveBroadcastProvider };
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@voltro/plugin-broadcast",
|
|
3
|
-
"version": "0.
|
|
3
|
+
"version": "0.87.0",
|
|
4
4
|
"description": "Cross-replica reactivity — a pub/sub message bus (Redis / NATS / memory) that fans out app-mutation ChangeEvents to every replica behind a load balancer. ADDITIVE to inline emit: local reactivity survives a broker outage; cross-replica degrades gracefully. Closes the single-instance gap for every non-postgres dialect (postgres keeps native LISTEN/NOTIFY).",
|
|
5
5
|
"keywords": [
|
|
6
6
|
"voltro",
|
|
@@ -33,12 +33,9 @@
|
|
|
33
33
|
"node": ">=24.0.0"
|
|
34
34
|
},
|
|
35
35
|
"dependencies": {
|
|
36
|
-
"@voltro/database": "0.
|
|
37
|
-
"@voltro/protocol": "0.
|
|
38
|
-
|
|
39
|
-
"optionalDependencies": {
|
|
40
|
-
"@nats-io/transport-node": "^3.4.0",
|
|
41
|
-
"ioredis": "^5.11.1"
|
|
36
|
+
"@voltro/database": "0.87.0",
|
|
37
|
+
"@voltro/protocol": "0.87.0",
|
|
38
|
+
"@voltro/kv": "0.87.0"
|
|
42
39
|
},
|
|
43
40
|
"peerDependencies": {
|
|
44
41
|
"effect": "4.0.1"
|