@voltro/kv 0.85.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.
Files changed (61) hide show
  1. package/CHANGELOG.md +5987 -0
  2. package/README.md +110 -0
  3. package/THIRD-PARTY-NOTICES.md +865 -2
  4. package/dist/Kv.js +19 -0
  5. package/dist/KvStore.js +5 -0
  6. package/dist/analytics.d.ts +337 -0
  7. package/dist/analytics.js +16 -0
  8. package/dist/backendMemory.js +36 -0
  9. package/dist/backendRedis.js +48 -0
  10. package/dist/cacheAtomicProtocol.js +247 -0
  11. package/dist/cacheAtomicScript.js +309 -0
  12. package/dist/cacheAtomicState.js +141 -0
  13. package/dist/connection.d.ts +990 -9
  14. package/dist/connection.js +361 -2
  15. package/dist/connectionAnalyticsConfig.js +153 -0
  16. package/dist/connectionConfigProvider.js +111 -0
  17. package/dist/connectionDefinitions.js +285 -0
  18. package/dist/connectionMemory.js +207 -0
  19. package/dist/connectionMetrics.js +79 -0
  20. package/dist/connectionNamespace.js +19 -0
  21. package/dist/connectionNats.js +148 -0
  22. package/dist/connectionNatsConfig.js +87 -0
  23. package/dist/connectionNatsSubjects.js +16 -0
  24. package/dist/connectionOwner.js +44 -0
  25. package/dist/connectionPool.js +738 -0
  26. package/dist/connectionPrefix.js +37 -0
  27. package/dist/connectionScripts.js +4 -0
  28. package/dist/connectionSqlConfig.js +119 -0
  29. package/dist/connectionStorageConfig.js +190 -0
  30. package/dist/connectionStorageFacade.js +78 -0
  31. package/dist/connectionSubscriber.js +130 -0
  32. package/dist/errors.js +13 -0
  33. package/dist/expirySweep.js +26 -0
  34. package/dist/hot-contract.d.ts +297 -0
  35. package/dist/hot-contract.js +18 -0
  36. package/dist/hot-testing.d.ts +229 -0
  37. package/dist/hot-testing.js +1 -0
  38. package/dist/hot.d.ts +936 -0
  39. package/dist/hot.js +7 -0
  40. package/dist/hotMemory.js +46 -0
  41. package/dist/hotOperations.js +223 -0
  42. package/dist/hotRateLimit.js +103 -0
  43. package/dist/hotReadAvailability.js +19 -0
  44. package/dist/hotRedis.js +139 -0
  45. package/dist/hotRedisScript.js +4 -0
  46. package/dist/hotRouting.js +78 -0
  47. package/dist/hotState.js +182 -0
  48. package/dist/hotStoreConformance.js +367 -0
  49. package/dist/index.d.ts +113 -9
  50. package/dist/index.js +7 -115
  51. package/dist/nativeRedisReads.js +78 -0
  52. package/dist/nativeRedisTopology.js +221 -0
  53. package/dist/redisDiagnostics.js +27 -0
  54. package/dist/redisReadPolicy.js +39 -0
  55. package/dist/sql.d.ts +77 -0
  56. package/dist/sql.js +0 -0
  57. package/dist/storage.d.ts +166 -0
  58. package/dist/storage.js +48 -0
  59. package/dist/storageAddress.js +20 -0
  60. package/package.json +43 -3
  61. package/dist/connection-Dsn5fgcH.js +0 -84
@@ -0,0 +1,738 @@
1
+ import { KvError as e } from "./errors.js";
2
+ import { withRespKeyPrefix as t } from "./connectionPrefix.js";
3
+ import { sqlConfigProblem as n, sqlConnectionConfig as r, sqlConnectionName as i } from "./connectionSqlConfig.js";
4
+ import { analyticsConfigProblem as a, analyticsConnectionConfig as o, analyticsConnectionName as s } from "./connectionAnalyticsConfig.js";
5
+ import { connectionDefinitionsProblem as c, natsConnectionName as l, redisConnectionName as u } from "./connectionDefinitions.js";
6
+ import { makeConnectionOwner as d } from "./connectionOwner.js";
7
+ import { applyConnectionNamespace as f, connectionNamespace as p } from "./connectionNamespace.js";
8
+ import { connectRedisSubscriber as m } from "./connectionSubscriber.js";
9
+ import { assertNatsSubject as ee, withNatsSubjectPrefix as te } from "./connectionNatsSubjects.js";
10
+ import { connectNats as ne } from "./connectionNats.js";
11
+ import { natsConnectionConfig as re } from "./connectionNatsConfig.js";
12
+ import { StorageError as h } from "./storage.js";
13
+ import { storageConfigProblem as ie, storageConnectionConfig as ae, storageConnectionName as oe } from "./connectionStorageConfig.js";
14
+ import { makeStorageFacade as se } from "./connectionStorageFacade.js";
15
+ import { CONNECTION_PUBLISH_SCRIPT as ce } from "./connectionScripts.js";
16
+ import { AnalyticsCapabilityNotSupported as g, AnalyticsError as _ } from "./analytics.js";
17
+ import { makeConnectionMetrics as le } from "./connectionMetrics.js";
18
+ import { withConnectionRegistryConfigProvider as v } from "./connectionConfigProvider.js";
19
+ import { RedisConnections as ue, connect as de, connectionConfig as fe } from "./connection.js";
20
+ import { Cause as y, Clock as b, Config as x, ConfigProvider as S, Context as C, Deferred as pe, Effect as w, Layer as T, Pull as me, Scope as he, Stream as E, SynchronizedRef as D } from "effect";
21
+ import { CircuitBreaker as ge, CircuitOpen as _e } from "@voltro/shared";
22
+ //#region src/connectionPool.ts
23
+ var O = class extends C.Service()("@voltro/ConnectionRegistry") {}, k = (v = {}) => w.gen(function* () {
24
+ let ue = 0, C = v.connections === void 0 ? {} : v.connections;
25
+ if (v.requirements !== void 0 && !Array.isArray(v.requirements)) return yield* w.fail(new x.ConfigError(new S.SourceError({ message: "Connection requirements must be an array" })));
26
+ let T = (v.requirements ?? []).map((e) => Object.freeze({ ...e }));
27
+ for (let e of T) if (e.onUnavailable !== void 0 && e.onUnavailable !== "degrade" && e.onUnavailable !== "fail" || typeof e.consumer != "string" || !e.consumer.trim() || typeof e.role != "string" || !/^[A-Za-z][A-Za-z0-9_-]*$/.test(e.role) || e.reference !== "" && (typeof e.reference != "string" || !/^(redis|nats|storage|analytics|sql):[A-Za-z][A-Za-z0-9_-]*$/.test(e.reference)) || [
28
+ "crossNode",
29
+ "pubsub",
30
+ "atomicMulti"
31
+ ].some((t) => {
32
+ let n = e[t];
33
+ return n !== void 0 && typeof n != "boolean";
34
+ })) return yield* w.fail(new x.ConfigError(new S.SourceError({ message: "Connection requirements need consumer, role, a typed reference, boolean capabilities and a degrade/fail unavailable policy" })));
35
+ v.namespaceIdentity !== void 0 && (yield* w.try({
36
+ try: () => p(v.namespaceIdentity),
37
+ catch: () => new x.ConfigError(new S.SourceError({ message: "Connection namespace requires a nonempty app name and environment" }))
38
+ }));
39
+ let O = le(v.namespaceIdentity === void 0 ? "unscoped" : p(v.namespaceIdentity)), k = c(C);
40
+ if (k) return yield* w.fail(new x.ConfigError(new S.SourceError({ message: k })));
41
+ let A = C.maxDynamicPools ?? 128, ve = C.rotationGraceMs ?? 3e4, ye = v.failureThreshold ?? 5, be = v.resetTimeoutMs ?? 3e4;
42
+ for (let [e, t, n] of [
43
+ [
44
+ "maxDynamicPools",
45
+ A,
46
+ !1
47
+ ],
48
+ [
49
+ "rotationGraceMs",
50
+ ve,
51
+ !0
52
+ ],
53
+ [
54
+ "failureThreshold",
55
+ ye,
56
+ !1
57
+ ],
58
+ [
59
+ "resetTimeoutMs",
60
+ be,
61
+ !1
62
+ ]
63
+ ]) if (!Number.isSafeInteger(t) || t < +!n) return yield* w.fail(new x.ConfigError(new S.SourceError({ message: `${e} must be a ${n ? "nonnegative" : "positive"} safe integer` })));
64
+ let j = yield* w.context(), xe = w.runPromiseWith(j), M = yield* D.make(/* @__PURE__ */ new Map()), N = /* @__PURE__ */ new Map(), P = /* @__PURE__ */ new Map(), F = /* @__PURE__ */ new Map(), I = /* @__PURE__ */ new Map(), L = /* @__PURE__ */ new Map(), R = /* @__PURE__ */ new Map(), z = (e) => {
65
+ if (e.startsWith("sql:")) return `sql:${i(e, C)}`;
66
+ if (e.startsWith("analytics:")) return `analytics:${s(e, C)}`;
67
+ if (e.startsWith("storage:")) return `storage:${oe(e, C)}`;
68
+ if (e.startsWith("nats:")) return `nats:${l(e, C)}`;
69
+ let t = u(e, C);
70
+ return C.redis?.[t] === void 0 ? e.startsWith("redis:") ? t : e : `redis:${t}`;
71
+ }, B = (e, t) => JSON.stringify([z(e), V(e) ? t?.tenantId ?? null : null]), Se = (e) => e.startsWith("sql:") ? C.sql?.[i(e, C)] : e.startsWith("analytics:") ? C.analytics?.[s(e, C)] : e.startsWith("storage:") ? C.storage?.[oe(e, C)] : e.startsWith("nats:") ? C.nats?.[l(e, C)] : C.redis?.[u(e, C)], V = (e) => {
72
+ let t = Se(e);
73
+ return t !== void 0 && "_tag" in t && (t._tag === "DynamicRedisConnection" || t._tag === "DynamicNatsConnection" || t._tag === "DynamicStorageConnection" || t._tag === "DynamicAnalyticsConnection" || t._tag === "DynamicSqlConnection");
74
+ }, Ce = (e) => w.suspend(() => {
75
+ if (e !== "" && !/^(redis|nats|storage|analytics|sql):[A-Za-z][A-Za-z0-9_-]*$/.test(e)) return w.fail(new x.ConfigError(new S.SourceError({ message: "A connection reference must use redis:name, nats:name, storage:name, analytics:name or sql:name" })));
76
+ let t = V(e), n = {
77
+ reference: z(e),
78
+ tenantScoped: t
79
+ };
80
+ return t ? w.succeed(n) : Oe(e).pipe(w.as(n));
81
+ }), H = (e, t) => fe(e, C, t).pipe(w.flatMap((e) => v.namespaceIdentity === void 0 ? w.succeed(e) : w.try({
82
+ try: () => f(e, v.namespaceIdentity),
83
+ catch: (e) => new x.ConfigError(new S.SourceError({ message: e instanceof Error ? e.message : "Connection namespace admission failed" }))
84
+ })), w.flatMap((t) => {
85
+ let n = z(e);
86
+ for (let e of T) if (z(e.reference) === n) {
87
+ if (t.driver === "memory" && e.crossNode) return w.fail(new x.ConfigError(new S.SourceError({ message: `Plugin ${e.consumer} role ${e.role} requires a network Redis connection; memory is local` })));
88
+ if (t.driver === "http" && (e.pubsub || e.atomicMulti)) {
89
+ let t = e.pubsub ? "Pub/Sub" : "atomic MULTI";
90
+ return w.fail(new x.ConfigError(new S.SourceError({ message: `Plugin ${e.consumer} role ${e.role} requires ${t}; its selected Redis connection requires the RESP driver` })));
91
+ }
92
+ }
93
+ return w.succeed(t);
94
+ }), w.mapError((e) => e instanceof x.ConfigError ? e : new x.ConfigError(new S.SourceError({ message: "Dynamic connection credentials could not be resolved" })))), we = (e, t) => re(e, C, t).pipe(w.flatMap((e) => v.namespaceIdentity === void 0 ? w.succeed(e) : w.try({
95
+ try: () => f(e, v.namespaceIdentity),
96
+ catch: () => new x.ConfigError(new S.SourceError({ message: "Connection namespace admission failed" }))
97
+ })), w.mapError((e) => e instanceof x.ConfigError ? e : new x.ConfigError(new S.SourceError({ message: "Dynamic connection credentials could not be resolved" })))), Te = (e, t) => ae(e, C, t).pipe(w.flatMap((t) => {
98
+ if (v.namespaceIdentity?.environment === "production" && (t = {
99
+ ...t,
100
+ tls: "required"
101
+ }), v.namespaceIdentity !== void 0 && t.keyPrefix === void 0 && (t = {
102
+ ...t,
103
+ keyPrefix: `${p(v.namespaceIdentity)}/`
104
+ }), v.namespaceIdentity?.environment === "production" && t.keyPrefix !== `${p(v.namespaceIdentity)}/` && !t.allowSharedNamespace) return w.fail(new x.ConfigError(new S.SourceError({ message: "A custom production storage namespace requires allowSharedNamespace" })));
105
+ for (let n of T) if (z(n.reference) === z(e)) {
106
+ if (n.pubsub || n.atomicMulti) return w.fail(new x.ConfigError(new S.SourceError({ message: "Storage cannot provide Pub/Sub or atomic MULTI" })));
107
+ if (n.crossNode && [
108
+ "memory",
109
+ "filesystem",
110
+ "database"
111
+ ].includes(t.provider)) return w.fail(new x.ConfigError(new S.SourceError({ message: "Cross-node storage requires a declared object-storage service" })));
112
+ }
113
+ let n = ie(t);
114
+ return n ? w.fail(new x.ConfigError(new S.SourceError({ message: n }))) : w.succeed(t);
115
+ }), w.mapError((e) => e instanceof x.ConfigError ? e : new x.ConfigError(new S.SourceError({ message: "Dynamic storage credentials could not be resolved" })))), Ee = (e, t) => o(e, C, t).pipe(w.flatMap((t) => {
116
+ v.namespaceIdentity?.environment === "production" && (t = {
117
+ ...t,
118
+ tls: "required"
119
+ });
120
+ let n = a(t);
121
+ if (n) return w.fail(new x.ConfigError(new S.SourceError({ message: n })));
122
+ for (let n of T) if (z(n.reference) === z(e)) {
123
+ if (n.pubsub || n.atomicMulti) return w.fail(new x.ConfigError(new S.SourceError({ message: "Analytics cannot provide Redis Pub/Sub or atomic MULTI" })));
124
+ if (n.crossNode && t.provider === "duckdb") return w.fail(new x.ConfigError(new S.SourceError({ message: "Cross-node analytics requires a network provider; DuckDB is local" })));
125
+ }
126
+ return w.succeed(t);
127
+ }), w.mapError((e) => e instanceof x.ConfigError ? e : new x.ConfigError(new S.SourceError({ message: "Dynamic analytics credentials could not be resolved" })))), De = (e, t) => r(e, C, t).pipe(w.flatMap((t) => {
128
+ v.namespaceIdentity?.environment === "production" && !["sqlite", "turso"].includes(t.dialect) && (t = {
129
+ ...t,
130
+ tls: "required"
131
+ });
132
+ let r = n(t);
133
+ if (r) return w.fail(new x.ConfigError(new S.SourceError({ message: r })));
134
+ for (let n of T) if (z(n.reference) === z(e)) {
135
+ if (n.pubsub || n.atomicMulti) return w.fail(new x.ConfigError(new S.SourceError({ message: "SQL cannot provide Redis Pub/Sub or atomic MULTI" })));
136
+ if (n.crossNode && ["sqlite", "turso"].includes(t.dialect)) return w.fail(new x.ConfigError(new S.SourceError({ message: "Cross-node SQL requires a network SQL dialect" })));
137
+ }
138
+ return w.succeed(t);
139
+ }), w.mapError((e) => e instanceof x.ConfigError ? e : new x.ConfigError(new S.SourceError({ message: "Dynamic SQL credentials could not be resolved" }))));
140
+ function Oe(e, t) {
141
+ return e.startsWith("sql:") ? De(e, t) : e.startsWith("analytics:") ? Ee(e, t) : e.startsWith("storage:") ? Te(e, t) : e.startsWith("nats:") ? we(e, t) : H(e, t);
142
+ }
143
+ for (let e of T) if ((e.reference.startsWith("nats:") || e.reference.startsWith("storage:") || e.reference.startsWith("analytics:") || e.reference.startsWith("sql:")) && e.atomicMulti) return yield* w.fail(new x.ConfigError(new S.SourceError({ message: `Plugin ${e.consumer} role ${e.role} requires atomic MULTI; NATS cannot provide Redis commands` })));
144
+ let U = yield* d({
145
+ rotationGraceMs: ve,
146
+ onStopping: () => {
147
+ N.clear();
148
+ },
149
+ onStopped: () => {
150
+ for (let e of P.values()) e.channels.clear(), e.listeners.clear();
151
+ P.clear();
152
+ for (let e of R.values()) e.dispose();
153
+ R.clear();
154
+ for (let e of F.values()) e.clear();
155
+ F.clear(), L.clear(), I.clear();
156
+ },
157
+ dispose: (e) => w.gen(function* () {
158
+ e.detachCommandReconnect?.(), e.binding?.current === e && delete e.binding.current, e.kind === "sql" || e.kind === "storage" || e.kind === "analytics" ? yield* e.transport.close : e.kind === "nats" ? yield* w.promise(() => e.transport.close().catch(() => void 0)) : (yield* w.promise(() => e.subscriber?.close().catch(() => void 0) ?? Promise.resolve()), yield* w.promise(() => e.client.close().catch(() => void 0)));
159
+ }).pipe(w.ensuring(w.sync(() => O.close(e))))
160
+ }), { close: W, trackOpen: ke } = U, G = (e) => {
161
+ U.register(e), O.register(e, e.reference);
162
+ }, Ae = (e) => w.sync(() => O.retire(e)).pipe(w.andThen(U.retire(e))), K = (e) => w.sync(() => O.release(e)).pipe(w.andThen(U.release(e))), q = (e) => {
163
+ e.errors++, O.error(e.reference);
164
+ }, J = (e) => (t) => y.hasInterruptsOnly(t) ? w.void : w.sync(() => {
165
+ q(e);
166
+ }), Y = (e, t) => b.currentTimeNanos.pipe(w.flatMap((n) => e.breaker.state.pipe(w.tap((r) => w.sync(() => {
167
+ e.latencyMs = Number(n - t) / 1e6, O.completed(e.reference, e.latencyMs), r === "open" && O.available(e, !1);
168
+ }))))), je = (e, t) => {
169
+ for (let n of e.listeners) try {
170
+ n(t);
171
+ } catch {}
172
+ }, Me = (t, n) => w.gen(function* () {
173
+ if (t.kind === "sql" || t.kind === "storage" || t.kind === "analytics") return yield* w.fail(new e({
174
+ operation: "subscribe",
175
+ key: "",
176
+ cause: "Selected connection has no Pub/Sub transport"
177
+ }));
178
+ if (t.subscriber !== void 0) return;
179
+ if (t.kind === "redis" && t.config.driver === "http") return yield* w.fail(new e({
180
+ operation: "subscribe",
181
+ key: "",
182
+ cause: "Redis Pub/Sub requires the RESP driver"
183
+ }));
184
+ let r = yield* (t.kind === "nats" ? w.succeed(te(t.transport, t.config.keyPrefix)) : t.memory === void 0 ? (v.connectSubscriber ?? m)(t.config) : w.sync(() => t.memory.subscriber())).pipe(w.mapError(() => new e({
185
+ operation: "subscribe",
186
+ key: "",
187
+ cause: "Redis subscriber could not be opened"
188
+ })));
189
+ t.subscriber = r, t.binding = n, r.onMessage((e, n) => {
190
+ let r = t.binding;
191
+ if (!(U.stopped || r?.current !== t || t.closed)) for (let t of r.channels.get(e) ?? []) try {
192
+ t(n);
193
+ } catch {}
194
+ }), r.onTransportEvent((e) => {
195
+ let n = t.binding;
196
+ !U.stopped && n?.current === t && !t.closed && je(n, e);
197
+ }), yield* w.forEach([...n.channels.keys()], (t) => w.tryPromise({
198
+ try: () => r.subscribe(t),
199
+ catch: () => new e({
200
+ operation: "subscribe",
201
+ key: "",
202
+ cause: "Redis subscription could not be registered"
203
+ })
204
+ }), { discard: !0 });
205
+ }), Ne = (e, t) => ke(Me(e, t)), X = (e) => {
206
+ O.activate(e), e.kind === "storage" && I.set(B(e.reference, e.context), e.config);
207
+ let t = e.binding;
208
+ if (t === void 0) return;
209
+ let n = t.current;
210
+ t.current = e, n !== void 0 && n !== e && t.channels.size > 0 && (je(t, { kind: "disconnected" }), je(t, { kind: "reconnected" }));
211
+ }, Pe = (n, r, i, a) => w.uninterruptibleMask((o) => w.gen(function* () {
212
+ let s = yield* o((n.startsWith("sql:") ? De(n, r).pipe(w.map((e) => ({
213
+ kind: "sql",
214
+ config: e
215
+ }))) : n.startsWith("analytics:") ? Ee(n, r).pipe(w.map((e) => ({
216
+ kind: "analytics",
217
+ config: e
218
+ }))) : n.startsWith("storage:") ? Te(n, r).pipe(w.map((e) => ({
219
+ kind: "storage",
220
+ config: e
221
+ }))) : n.startsWith("nats:") ? we(n, r).pipe(w.map((e) => ({
222
+ kind: "nats",
223
+ config: e
224
+ }))) : H(n, r).pipe(w.map((e) => ({
225
+ kind: "redis",
226
+ config: e
227
+ })))).pipe(w.interruptible)), c = yield* b.currentTimeMillis, l = Se(n), u = V(n), d = yield* ge.make({
228
+ name: n,
229
+ failureThreshold: ye,
230
+ resetTimeout: be,
231
+ ...s.kind === "sql" ? { isFailure: (t) => t instanceof e || t instanceof _ || typeof t == "object" && !!t && "_tag" in t && t._tag === "HotError" && "reason" in t && t.reason === "unavailable" } : {}
232
+ }), f = yield* pe.make(), p = {
233
+ reference: z(n),
234
+ context: r,
235
+ breaker: d,
236
+ dynamic: u,
237
+ closedSignal: f,
238
+ expiresAt: l !== void 0 && "_tag" in l && "ttlMs" in l ? c + l.ttlMs : Infinity,
239
+ active: 0,
240
+ lastUsed: c,
241
+ commands: 0,
242
+ errors: 0,
243
+ latencyMs: null,
244
+ retired: !1,
245
+ closed: !1
246
+ }, m;
247
+ if (s.kind === "sql") {
248
+ if (v.connectSql === void 0) return yield* w.fail(new x.ConfigError(new S.SourceError({ message: "SQL requires an app-owned SQL connector" })));
249
+ if (a !== void 0 && (a.kind !== "sql" || a.config.dialect !== s.config.dialect)) return yield* w.fail(new x.ConfigError(new S.SourceError({ message: "SQL rotation must preserve the dialect contract" })));
250
+ let t = yield* v.connectSql(s.config).pipe(w.mapError(() => new e({
251
+ operation: "connect",
252
+ key: "",
253
+ cause: "SQL transport could not be constructed"
254
+ })));
255
+ m = {
256
+ ...p,
257
+ kind: "sql",
258
+ drainUntilReleased: !0,
259
+ transport: t,
260
+ config: s.config
261
+ }, G(m), yield* o(t.probe.pipe(w.interruptible, w.timeout("5 seconds"), w.mapError(() => new e({
262
+ operation: "connect",
263
+ key: "",
264
+ cause: "SQL readiness failed"
265
+ })))).pipe(w.onError(() => W(m)));
266
+ } else if (s.kind === "analytics") {
267
+ if (v.connectAnalytics === void 0) return yield* w.fail(new x.ConfigError(new S.SourceError({ message: "Analytics requires an app-owned analytics connector" })));
268
+ let t = yield* v.connectAnalytics(s.config).pipe(w.mapError(() => new e({
269
+ operation: "connect",
270
+ key: "",
271
+ cause: "Analytics transport could not be constructed"
272
+ })));
273
+ if (m = {
274
+ ...p,
275
+ kind: "analytics",
276
+ transport: t,
277
+ config: s.config
278
+ }, G(m), a !== void 0) {
279
+ if (a.kind !== "analytics" || a.config.provider !== s.config.provider) return yield* W(m), yield* w.fail(new x.ConfigError(new S.SourceError({ message: "Analytics rotation must preserve the provider contract" })));
280
+ let e = a.transport.sink, n = t.sink;
281
+ if (JSON.stringify(e.info.capabilities) !== JSON.stringify(n.info.capabilities) || JSON.stringify(e.mirror?.tables ?? []) !== JSON.stringify(n.mirror?.tables ?? []) || e.mirror?.primaryKey !== n.mirror?.primaryKey) return yield* W(m), yield* w.fail(new x.ConfigError(new S.SourceError({ message: "Analytics rotation must preserve capabilities and mirror schema" })));
282
+ }
283
+ yield* o(t.probe.pipe(w.interruptible, w.timeout("5 seconds"), w.mapError(() => new e({
284
+ operation: "connect",
285
+ key: "",
286
+ cause: a === void 0 ? "Analytics readiness failed" : "Replacement analytics readiness failed"
287
+ })))).pipe(w.onError(() => W(m)));
288
+ } else if (s.kind === "storage") {
289
+ if (v.connectStorage === void 0) return yield* w.fail(new x.ConfigError(new S.SourceError({ message: "Storage requires an app-owned storage connector" })));
290
+ let t;
291
+ if (s.config.provider === "memory") {
292
+ let e = B(n, r);
293
+ t = F.get(e), t === void 0 && (t = /* @__PURE__ */ new Map(), F.set(e, t));
294
+ }
295
+ let i = yield* v.connectStorage(s.config, t === void 0 ? {} : { memory: t }).pipe(w.mapError(() => new e({
296
+ operation: "connect",
297
+ key: "",
298
+ cause: "Storage transport could not be constructed"
299
+ })));
300
+ m = {
301
+ ...p,
302
+ kind: "storage",
303
+ transport: i,
304
+ config: s.config
305
+ }, G(m);
306
+ let o = L.get(B(n, r));
307
+ o !== void 0 && i.provider.bindDataStore?.(o), a !== void 0 && (yield* i.probe.pipe(w.timeout("5 seconds"), w.mapError(() => new e({
308
+ operation: "connect",
309
+ key: "",
310
+ cause: "Replacement storage readiness failed"
311
+ })), w.onError(() => W(m))));
312
+ } else if (s.kind === "nats") {
313
+ let t = s.config, n = yield* (v.connectNats === void 0 ? ne(t).pipe(w.timeout("5 seconds"), w.interruptible) : v.connectNats(t)).pipe(w.mapError(() => new e({
314
+ operation: "connect",
315
+ key: "",
316
+ cause: "NATS driver could not be opened"
317
+ })));
318
+ m = {
319
+ ...p,
320
+ kind: "nats",
321
+ transport: n,
322
+ config: t
323
+ }, G(m);
324
+ let r = m;
325
+ m.detachCommandReconnect = n.onTransportEvent((e) => {
326
+ e.kind === "reconnected" && !U.stopped && !r.closed && !r.retired && w.runSyncWith(j)(r.breaker.reset);
327
+ });
328
+ } else {
329
+ let i = s.config, { keyPrefix: a, ...o } = i, c;
330
+ if (i.driver === "memory") {
331
+ let e = B(n, r);
332
+ if (c = R.get(e), c === void 0) {
333
+ let { makeMemoryConnectionState: t } = yield* w.promise(() => import("./connectionMemory.js"));
334
+ c = t(i.memoryClock), R.set(e, c);
335
+ }
336
+ }
337
+ let l = yield* (c === void 0 ? v.connect === void 0 ? de(o).pipe(w.interruptible) : v.connect(o) : w.sync(() => c.command())).pipe(w.map((e) => t(e, a)), w.mapError(() => new e({
338
+ operation: "connect",
339
+ key: "",
340
+ cause: "Connection driver could not be opened"
341
+ })));
342
+ m = {
343
+ ...p,
344
+ kind: "redis",
345
+ client: l,
346
+ config: i,
347
+ ...c === void 0 ? {} : { memory: c }
348
+ }, G(m);
349
+ let u = m, d = l.onReconnect?.(() => {
350
+ !U.stopped && !u.closed && !u.retired && w.runSyncWith(j)(u.breaker.reset);
351
+ });
352
+ d !== void 0 && (m.detachCommandReconnect = d);
353
+ }
354
+ return O.available(m, m.kind !== "storage" || a !== void 0), i?.(m), a?.binding !== void 0 && (m.binding = a.binding, a.binding.channels.size > 0 && (yield* Ne(m, a.binding).pipe(w.onError(() => W(m))))), i === void 0 && X(m), m;
355
+ })), Fe = (e, t, n, r) => ke(Pe(e, t, n, r)).pipe(w.tapCause((t) => y.hasInterruptsOnly(t) ? w.void : w.sync(() => {
356
+ let t = z(e);
357
+ /^(redis|nats|storage|analytics|sql):[A-Za-z][A-Za-z0-9_-]*$/.test(t) && O.error(t);
358
+ }))), Z = (t, n) => D.modifyEffect(M, (r) => w.gen(function* () {
359
+ if (U.stopped) return yield* w.fail(new e({
360
+ operation: "connect",
361
+ key: "",
362
+ cause: "Connection registry is closed"
363
+ }));
364
+ let i = B(t, n), a = yield* b.currentTimeMillis, o = r.get(i);
365
+ if (o && o.expiresAt > a) return o.active++, O.acquire(o), o.lastUsed = a, [o, r];
366
+ let s = new Map(r);
367
+ if (!o && V(t)) {
368
+ let r = [...s.entries()].filter(([, e]) => e.dynamic);
369
+ if (r.length >= A) {
370
+ let a = r.filter(([, e]) => e.active === 0 && (e.binding?.channels.size ?? 0) === 0).sort((e, t) => e[1].lastUsed - t[1].lastUsed)[0];
371
+ if (!a) return yield* w.fail(new e({
372
+ operation: "connect",
373
+ key: "",
374
+ cause: "All dynamic connection pools are busy; maxDynamicPools reached"
375
+ }));
376
+ let c = yield* Fe(t, n, void 0, o);
377
+ return s.delete(a[0]), yield* Ae(a[1]), c.active++, O.acquire(c), s.set(i, c), [c, s];
378
+ }
379
+ }
380
+ let c = yield* Fe(t, n, void 0, o);
381
+ return o && (yield* Ae(o)), c.active++, O.acquire(c), s.set(i, c), [c, s];
382
+ })), Q = (t, n, r, i) => w.acquireUseRelease(Z(t, n), (t) => w.gen(function* () {
383
+ let n = yield* b.currentTimeNanos;
384
+ return t.commands++, O.command(t.reference), yield* t.breaker(i(t)).pipe(w.tap(() => w.sync(() => O.available(t, !0))), w.tapCause(J(t)), w.mapError((t) => t instanceof _e ? new e({
385
+ operation: r,
386
+ key: "",
387
+ cause: `Connection circuit is open; retry after ${t.retryAfterMs} ms`
388
+ }) : t), w.ensuring(Y(t, n)));
389
+ }), K), Ie = (t, n, r, i) => xe(Q(t, n, r, (t) => w.tryPromise({
390
+ try: () => i(t),
391
+ catch: () => new e({
392
+ operation: r,
393
+ key: "",
394
+ cause: "Connection command failed"
395
+ })
396
+ }))), Le = (t, n) => Q(t, n, "probe", (t) => t.kind === "sql" ? t.transport.probe : t.kind === "analytics" ? t.transport.probe.pipe(w.mapError(() => new e({
397
+ operation: "probe",
398
+ key: "",
399
+ cause: "Analytics readiness probe failed"
400
+ }))) : t.kind === "storage" ? t.transport.probe.pipe(w.mapError(() => new e({
401
+ operation: "probe",
402
+ key: "",
403
+ cause: "Storage readiness probe failed"
404
+ }))) : w.tryPromise({
405
+ try: async () => {
406
+ if (t.kind === "nats") return t.transport.flush();
407
+ if (t.client.ping === void 0 || await t.client.ping() !== "PONG") throw Error("Redis readiness requires PONG");
408
+ },
409
+ catch: () => new e({
410
+ operation: "probe",
411
+ key: "",
412
+ cause: "Connection readiness probe failed"
413
+ })
414
+ })), $ = (e, t, n, r) => Ie(e, t, n, (e) => {
415
+ if (e.kind !== "redis") throw Error("Redis commands require a Redis connection");
416
+ return r(e.client);
417
+ }), Re = (e, t) => w.gen(function* () {
418
+ if (e.includes(":") && !e.startsWith("redis:")) return yield* w.fail(new x.ConfigError(new S.SourceError({ message: "Redis commands require a redis:name reference" })));
419
+ let n = t === void 0 ? void 0 : Object.freeze({ tenantId: t.tenantId }), r = yield* w.acquireUseRelease(Z(e, n), (e) => e.kind === "redis" ? w.succeed({
420
+ ping: e.client.ping !== void 0,
421
+ crossNode: e.client.crossNode
422
+ }) : w.fail(new x.ConfigError(new S.SourceError({ message: "Redis commands require a redis:name reference" }))), K), i = B(e, n), a = N.get(i);
423
+ if (a) return a;
424
+ let o = (t, r) => $(e, n, t, (e) => {
425
+ if (e.readOnly === void 0) throw Error("Connection has no read-only transport");
426
+ return r(e.readOnly);
427
+ }), s = {
428
+ readOnly: {
429
+ get: (e) => o("read.get", (t) => t.get(e)),
430
+ exists: (e) => o("read.exists", (t) => t.exists(e)),
431
+ zrange: (e) => o("read.zrange", (t) => t.zrange(e)),
432
+ eval: (e, t, ...n) => o("read.eval", (r) => r.eval(e, t, ...n))
433
+ },
434
+ ...r.crossNode === void 0 ? {} : { crossNode: r.crossNode },
435
+ ...r.ping ? { ping: () => $(e, n, "ping", (e) => {
436
+ if (e.ping === void 0) throw Error("Connection driver has no PING probe");
437
+ return e.ping();
438
+ }) } : {},
439
+ diagnostics: () => $(e, n, "diagnostics", (e) => e.diagnostics?.() ?? Promise.resolve({ nodes: [] })),
440
+ get: (t) => $(e, n, "get", (e) => e.get(t)),
441
+ set: (t, r) => $(e, n, "set", (e) => e.set(t, r)),
442
+ psetex: (t, r, i) => $(e, n, "psetex", (e) => e.psetex(t, r, i)),
443
+ del: (t) => $(e, n, "del", (e) => e.del(t)),
444
+ exists: (t) => $(e, n, "exists", (e) => e.exists(t)),
445
+ eval: (t, r, ...i) => $(e, n, "eval", (e) => e.eval(t, r, ...i)),
446
+ zrange: (t) => $(e, n, "zrange", (e) => e.zrange(t)),
447
+ scan: (t, r, i) => $(e, n, "scan", (e) => e.scan(t, r, i)),
448
+ close: () => Promise.resolve()
449
+ };
450
+ return V(e) || N.set(i, s), s;
451
+ });
452
+ return {
453
+ client: Re,
454
+ config: Oe,
455
+ validate: Ce,
456
+ storage: (e, t) => w.gen(function* () {
457
+ if (!e.startsWith("storage:")) return yield* w.fail(new x.ConfigError(new S.SourceError({ message: "Storage requires a storage:name reference" })));
458
+ let n = t === void 0 ? void 0 : Object.freeze({ tenantId: t.tenantId }), r = yield* w.acquireUseRelease(Z(e, n), (e) => e.kind === "storage" ? w.succeed(e.config) : w.fail(new x.ConfigError(new S.SourceError({ message: "Storage requires a storage:name reference" }))), K), i = B(e, n), a = (e) => new h({
459
+ provider: r.provider,
460
+ message: "Storage connection operation failed",
461
+ transient: e instanceof h ? e.transient : !0,
462
+ ...e instanceof h && e.outcome !== void 0 ? { outcome: e.outcome } : {},
463
+ ...e instanceof h && e.status !== void 0 ? { status: e.status } : {}
464
+ });
465
+ return se({
466
+ config: () => I.get(i) ?? r,
467
+ command: (t, r) => w.acquireUseRelease(Z(e, n).pipe(w.mapError(a)), (e) => w.gen(function* () {
468
+ if (e.kind !== "storage") return yield* w.fail(a(void 0));
469
+ let t = yield* b.currentTimeNanos;
470
+ return e.commands++, O.command(e.reference), yield* e.breaker(r(e.transport.provider)).pipe(w.tap(() => w.sync(() => O.available(e, !0))), w.tapCause(J(e)), w.mapError(a), w.ensuring(Y(e, t)));
471
+ }), K),
472
+ stream: (t, r) => E.unwrap(w.acquireRelease(Z(e, n).pipe(w.mapError(a)), K).pipe(w.flatMap((e) => w.gen(function* () {
473
+ if (e.kind !== "storage") return yield* w.fail(a(void 0));
474
+ let n = yield* b.currentTimeNanos;
475
+ e.commands++, O.command(e.reference), yield* w.addFinalizer(() => Y(e, n));
476
+ let i = e.transport.provider, o = i.getStream === void 0 ? i.get(t).pipe(w.flatMap((t) => t.bytes.byteLength !== r.size || t.contentType !== (r.contentType ?? "application/octet-stream") ? w.fail(new h({
477
+ provider: e.config.provider,
478
+ message: "Storage metadata changed before stream consumption",
479
+ transient: !0
480
+ })) : w.succeed(E.succeed(t.bytes)))) : w.acquireRelease(i.getStream(t), (e) => e.close ?? w.void).pipe(w.flatMap((t) => t.size !== void 0 && t.size !== r.size || t.contentType !== (r.contentType ?? "application/octet-stream") ? w.fail(new h({
481
+ provider: e.config.provider,
482
+ message: "Storage metadata changed before stream consumption",
483
+ transient: !0
484
+ })) : w.succeed(t.stream)));
485
+ return yield* e.breaker(o).pipe(w.tap(() => w.sync(() => O.available(e, !0))), w.tapCause(J(e)), w.mapError(a), w.map((t) => t.pipe(E.mapError(a), E.tapCause((t) => J(e)(t)))));
486
+ })))),
487
+ bind: (e) => {
488
+ if (U.stopped) throw Error("Connection registry is closed");
489
+ L.set(i, e);
490
+ for (let t of w.runSyncWith(j)(D.get(M)).values()) t.kind === "storage" && B(t.reference, t.context) === i && t.transport.provider.bindDataStore?.(e);
491
+ }
492
+ });
493
+ }),
494
+ analytics: (e, t) => w.gen(function* () {
495
+ if (!e.startsWith("analytics:")) return yield* w.fail(new x.ConfigError(new S.SourceError({ message: "Analytics requires an analytics:name reference" })));
496
+ let n = t === void 0 ? void 0 : Object.freeze({ tenantId: t.tenantId }), r = yield* w.acquireUseRelease(Z(e, n), (e) => e.kind === "analytics" ? w.succeed(e.transport.sink) : w.fail(new x.ConfigError(new S.SourceError({ message: "Analytics requires an analytics:name reference" }))), K), i = Object.freeze({
497
+ provider: r.info.provider,
498
+ capabilities: Object.freeze({ ...r.info.capabilities })
499
+ }), a = (t, r) => Q(e, n, t, (e) => e.kind === "analytics" ? w.suspend(() => r(e.transport.sink)).pipe(w.mapError((e) => e instanceof g ? e : new _({
500
+ provider: i.provider,
501
+ operation: t,
502
+ cause: "Analytics connection operation failed"
503
+ }))) : w.fail(new _({
504
+ provider: i.provider,
505
+ operation: t,
506
+ cause: "Selected connection is not analytics"
507
+ }))).pipe(w.mapError((e) => e instanceof g ? e : new _({
508
+ provider: i.provider,
509
+ operation: t,
510
+ cause: "Analytics connection operation failed"
511
+ })));
512
+ return {
513
+ info: i,
514
+ track: (e) => a("track", (t) => t.track(e)),
515
+ aggregate: (e) => a("aggregate", (t) => t.aggregate(e)),
516
+ timeseries: (e) => a("timeseries", (t) => t.timeseries(e)),
517
+ topN: (e) => a("topN", (t) => t.topN(e)),
518
+ ...r.mirror === void 0 ? {} : { mirror: {
519
+ tables: Object.freeze([...r.mirror.tables]),
520
+ ...r.mirror.primaryKey === void 0 ? {} : { primaryKey: r.mirror.primaryKey },
521
+ upsert: (e) => a("mirror.upsert", (t) => t.mirror === void 0 ? w.fail(new g({
522
+ provider: i.provider,
523
+ capability: "mirror"
524
+ })) : t.mirror.upsert(e)),
525
+ remove: (e) => a("mirror.remove", (t) => t.mirror === void 0 ? w.fail(new g({
526
+ provider: i.provider,
527
+ capability: "mirror"
528
+ })) : t.mirror.remove(e)),
529
+ maxVersion: (e) => a("mirror.maxVersion", (t) => t.mirror === void 0 ? w.fail(new g({
530
+ provider: i.provider,
531
+ capability: "mirror"
532
+ })) : t.mirror.maxVersion(e))
533
+ } }
534
+ };
535
+ }),
536
+ sql: (t, n) => w.gen(function* () {
537
+ if (!/^sql:[A-Za-z][A-Za-z0-9_-]*$/.test(t)) return yield* w.fail(new x.ConfigError(new S.SourceError({ message: "SQL requires a sql:name reference" })));
538
+ let r = n === void 0 ? void 0 : Object.freeze({ tenantId: n.tenantId }), i = yield* w.acquireUseRelease(Z(t, r), (e) => e.kind === "sql" ? w.succeed(e.config.dialect) : w.fail(new x.ConfigError(new S.SourceError({ message: "SQL requires a sql:name reference" }))), K), a = () => new e({
539
+ operation: "sql",
540
+ key: "",
541
+ cause: "SQL connection operation failed"
542
+ }), o = (e) => typeof e == "object" && e && "_tag" in e && e._tag === "SqlError" ? a() : e;
543
+ return {
544
+ dialect: i,
545
+ use: (e) => Q(t, r, "sql", (t) => t.kind === "sql" ? w.suspend(() => e(t.transport.client)).pipe(w.mapError(o)) : w.fail(a())),
546
+ stream: (n) => E.unwrap(w.gen(function* () {
547
+ let i = yield* w.acquireRelease(Z(t, r), K);
548
+ if (i.kind !== "sql") return E.fail(a());
549
+ let s = yield* b.currentTimeNanos;
550
+ i.commands++, O.command(i.reference), yield* w.addFinalizer(() => Y(i, s));
551
+ let c = yield* w.scope, l = yield* w.cached(E.toPull(E.suspend(() => n(i.transport.client))).pipe(w.provideService(he.Scope, c))), u = w.flatMap(l, (e) => e);
552
+ return E.fromPull(w.succeed(i.breaker(u.pipe(w.mapError(o), me.catchDone(() => w.succeed(null)))).pipe(w.tap(() => w.sync(() => O.available(i, !0))), w.tapCause(J(i)), w.mapError((t) => t instanceof _e ? new e({
553
+ operation: "sql",
554
+ key: "",
555
+ cause: `Connection circuit is open; retry after ${t.retryAfterMs} ms`
556
+ }) : t), w.flatMap((e) => e === null ? y.done() : w.succeed(e)))));
557
+ }))
558
+ };
559
+ }),
560
+ pubsub: (t, n) => w.gen(function* () {
561
+ if (t.includes(":") && !/^(redis|nats):/.test(t)) return yield* w.fail(new x.ConfigError(new S.SourceError({ message: "Pub/Sub requires a Redis or NATS reference" })));
562
+ if (U.stopped) return yield* w.fail(new e({
563
+ operation: "subscribe",
564
+ key: "",
565
+ cause: "Connection registry is closed"
566
+ }));
567
+ let r = n === void 0 ? void 0 : Object.freeze({ tenantId: n.tenantId }), i = yield* t.startsWith("nats:") ? we(t, r) : H(t, r);
568
+ if (U.stopped) return yield* w.fail(new e({
569
+ operation: "subscribe",
570
+ key: "",
571
+ cause: "Connection registry is closed"
572
+ }));
573
+ if ("driver" in i && i.driver === "http") return yield* w.fail(new e({
574
+ operation: "subscribe",
575
+ key: "",
576
+ cause: "Redis Pub/Sub requires the RESP driver"
577
+ }));
578
+ let a = B(t, r), o = P.get(a);
579
+ o === void 0 && (o = {
580
+ channels: /* @__PURE__ */ new Map(),
581
+ listeners: /* @__PURE__ */ new Set(),
582
+ consumers: 0
583
+ }, P.set(a, o));
584
+ let s = o;
585
+ s.consumers++;
586
+ let c = !1, l = /* @__PURE__ */ new Set(), u = /* @__PURE__ */ new Set(), d = (e) => D.updateEffect(M, (t) => w.gen(function* () {
587
+ if (e.released) return t;
588
+ e.released = !0, l.delete(e);
589
+ let n = s.channels.get(e.channel);
590
+ if (n?.delete(e.handler), n?.size === 0) {
591
+ s.channels.delete(e.channel);
592
+ let t = s.current;
593
+ t?.subscriber !== void 0 && !t.closed && (yield* w.promise(() => t.subscriber.unsubscribe(e.channel).catch(() => {
594
+ q(t);
595
+ })));
596
+ }
597
+ return t;
598
+ })).pipe(w.uninterruptible), f = yield* w.cached(w.gen(function* () {
599
+ c = !0, yield* D.update(M, (e) => e);
600
+ for (let e of u) s.listeners.delete(e);
601
+ u.clear(), yield* w.forEach([...l], d, { discard: !0 }), s.consumers--, s.consumers === 0 && P.get(a) === s && P.delete(a);
602
+ }).pipe(w.uninterruptible)), p = (n) => t.startsWith("nats:") ? w.try({
603
+ try: () => ee(`${i.keyPrefix ?? ""}${n}`),
604
+ catch: () => new e({
605
+ operation: "subscribe",
606
+ key: "",
607
+ cause: "NATS channels must be exact nonempty subjects"
608
+ })
609
+ }) : w.void;
610
+ return {
611
+ publish: (n, i) => w.suspend(() => c || U.stopped ? w.fail(new e({
612
+ operation: "publish",
613
+ key: "",
614
+ cause: "Pub/Sub consumer is closed"
615
+ })) : p(n).pipe(w.andThen(w.tryPromise({
616
+ try: () => Ie(t, r, "publish", (e) => e.kind === "nats" ? e.transport.publish(`${e.config.keyPrefix ?? ""}${n}`, i) : e.kind === "redis" ? e.client.eval(ce, 0, n, i) : Promise.reject(/* @__PURE__ */ Error("Storage has no Pub/Sub"))),
617
+ catch: () => new e({
618
+ operation: "publish",
619
+ key: "",
620
+ cause: "Pub/Sub publication failed"
621
+ })
622
+ }))).pipe(w.asVoid)),
623
+ subscribe: (n, i) => p(n).pipe(w.andThen(w.uninterruptibleMask(() => w.acquireUseRelease(Z(t, r), () => D.modifyEffect(M, (t) => w.gen(function* () {
624
+ if (c || U.stopped) return yield* w.fail(new e({
625
+ operation: "subscribe",
626
+ key: "",
627
+ cause: "Pub/Sub consumer is closed"
628
+ }));
629
+ let r = t.get(a);
630
+ if (r === void 0) return yield* w.fail(new e({
631
+ operation: "subscribe",
632
+ key: "",
633
+ cause: "Connection generation is unavailable"
634
+ }));
635
+ let o = {
636
+ channel: n,
637
+ handler: (e) => {
638
+ c || i(e);
639
+ },
640
+ released: !1
641
+ }, u = s.channels.get(n) ?? /* @__PURE__ */ new Set(), f = u.size === 0;
642
+ u.add(o.handler), s.channels.set(n, u), r.binding = s, X(r);
643
+ let p = r.subscriber !== void 0;
644
+ return yield* w.gen(function* () {
645
+ if (yield* Ne(r, s), p && f && (yield* w.tryPromise({
646
+ try: () => r.subscriber.subscribe(n),
647
+ catch: () => new e({
648
+ operation: "subscribe",
649
+ key: "",
650
+ cause: "Redis subscription could not be registered"
651
+ })
652
+ })), c || U.stopped) return yield* w.fail(new e({
653
+ operation: "subscribe",
654
+ key: "",
655
+ cause: "Pub/Sub consumer is closed"
656
+ }));
657
+ }).pipe(w.onError(() => w.gen(function* () {
658
+ if (q(r), u.delete(o.handler), u.size === 0) {
659
+ s.channels.delete(n);
660
+ let e = r.subscriber;
661
+ e !== void 0 && !r.closed && (yield* w.promise(() => e.unsubscribe(n).catch(() => {
662
+ q(r);
663
+ })));
664
+ }
665
+ }))), l.add(o), [yield* w.cached(d(o)), t];
666
+ })), K)).pipe(ke, w.mapError(() => new e({
667
+ operation: "subscribe",
668
+ key: "",
669
+ cause: "Pub/Sub subscription could not be registered"
670
+ }))))),
671
+ onTransportEvent: (e) => {
672
+ if (c || U.stopped) throw Error("Pub/Sub consumer is closed");
673
+ let t = (t) => {
674
+ c || e(t);
675
+ };
676
+ return s.listeners.add(t), u.add(t), () => {
677
+ s.listeners.delete(t), u.delete(t);
678
+ };
679
+ },
680
+ close: f
681
+ };
682
+ }),
683
+ probe: Le,
684
+ reload: w.uninterruptibleMask((t) => w.gen(function* () {
685
+ if (U.stopped) return yield* w.fail(new e({
686
+ operation: "reload",
687
+ key: "",
688
+ cause: "Connection registry is closed"
689
+ }));
690
+ let n = yield* b.currentTimeMillis, r = yield* b.currentTimeNanos, i = yield* t(D.updateEffect(M, (e) => w.uninterruptibleMask((t) => w.gen(function* () {
691
+ let n = /* @__PURE__ */ new Map(), r = yield* t(w.forEach([...e], ([e, t]) => Fe(t.reference, t.context, (t) => {
692
+ n.set(e, t);
693
+ }, t))).pipe(w.exit);
694
+ if (r._tag === "Failure") return yield* w.forEach([...n.values()], W, { discard: !0 }), yield* w.failCause(r.cause);
695
+ for (let e of n.values()) X(e);
696
+ return yield* w.forEach([...e.values()], Ae, { discard: !0 }), n;
697
+ })))).pipe(w.exit), a = yield* b.currentTimeNanos, o = Object.freeze({
698
+ sequence: ++ue,
699
+ startedAt: n,
700
+ durationMs: Number(a - r) / 1e6,
701
+ outcome: i._tag === "Success" ? "succeeded" : "failed"
702
+ });
703
+ if (yield* w.sync(() => {
704
+ O.rotated(o.outcome, o.durationMs);
705
+ try {
706
+ v.onRotation?.(o);
707
+ } catch {}
708
+ }), i._tag === "Failure") return yield* w.failCause(i.cause);
709
+ })),
710
+ inspect: D.get(M).pipe(w.flatMap((e) => w.forEach([...e.values()], (e) => w.gen(function* () {
711
+ let t = e.config;
712
+ return {
713
+ reference: e.reference,
714
+ dynamic: e.dynamic,
715
+ activeCommands: e.active,
716
+ activeSubscriptions: [...e.binding?.channels.values() ?? []].reduce((e, t) => e + t.size, 0),
717
+ subscribedChannels: e.binding?.channels.size ?? 0,
718
+ commands: e.commands,
719
+ errors: e.errors,
720
+ latencyMs: e.latencyMs,
721
+ state: yield* e.breaker.state,
722
+ source: t.source ?? (C.redis && Object.keys(C.redis).length > 0 ? "config" : "environment"),
723
+ ...t.label === void 0 ? {} : { label: t.label },
724
+ ...t.region === void 0 ? {} : { region: t.region },
725
+ ..."persistence" in t && t.persistence !== void 0 ? { persistence: t.persistence } : {}
726
+ };
727
+ })))),
728
+ redis: {
729
+ client: (e) => Re(e),
730
+ config: (e) => H(e)
731
+ }
732
+ };
733
+ }), A = (e = {}) => T.effectContext(w.gen(function* () {
734
+ let t = yield* S.ConfigProvider, n = v(yield* k(e), t);
735
+ return C.make(O, n).pipe(C.add(ue, n.redis));
736
+ }));
737
+ //#endregion
738
+ export { O as ConnectionRegistry, A as layerConfiguredConnections, k as makeConnectionRegistry };