@voltro/web 0.1.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.
@@ -0,0 +1,596 @@
1
+ import { AppClientsContext as e } from "./hooks.js";
2
+ import { c as t, l as n, r, s as i } from "./defaultFallbacks-Bg_X-9Wv.js";
3
+ import { createContext as a, useCallback as o, useContext as s, useEffect as c, useRef as l, useState as u, useSyncExternalStore as d } from "react";
4
+ import { Context as f, Layer as p, ManagedRuntime as m } from "effect";
5
+ import * as h from "@effect/platform/Socket";
6
+ import * as g from "@effect/platform/Headers";
7
+ import { RpcClient as _, RpcSerialization as v } from "@effect/rpc";
8
+ import { FrameworkRuntimesProvider as y, RpcErrorBus as b, SubscriptionCache as ee, ssrClientProxy as te, ssrStubHandle as ne, subscribeClientTraces as re } from "@voltro/client";
9
+ import { Fragment as x, jsx as S, jsxs as C } from "react/jsx-runtime";
10
+ //#region src/reconnect.ts
11
+ var w = a(null), ie = () => s(w) ?? (() => {}), ae = 150, T = 220, E = () => {
12
+ let e = d(n, i, i).some((e) => e.kind === "loading" || e.kind === "reconnecting"), [t, r] = u(!1);
13
+ return c(() => {
14
+ if (!e) {
15
+ r(!1);
16
+ return;
17
+ }
18
+ let t = setTimeout(() => r(!0), ae);
19
+ return () => clearTimeout(t);
20
+ }, [e]), /* @__PURE__ */ C("div", {
21
+ "aria-hidden": "true",
22
+ "data-voltro-nav-indicator": "",
23
+ style: {
24
+ position: "fixed",
25
+ right: 18,
26
+ bottom: 18,
27
+ zIndex: 2147483646,
28
+ pointerEvents: "none",
29
+ opacity: +!!t,
30
+ transform: t ? "translateY(0) scale(1)" : "translateY(4px) scale(0.96)",
31
+ transition: `opacity ${T}ms ease, transform ${T}ms ease`,
32
+ display: "grid",
33
+ placeItems: "center",
34
+ width: 34,
35
+ height: 34,
36
+ borderRadius: 999,
37
+ background: "color-mix(in oklch, canvas 78%, transparent)",
38
+ backdropFilter: "blur(6px)",
39
+ WebkitBackdropFilter: "blur(6px)",
40
+ border: "1px solid color-mix(in oklch, canvastext 12%, transparent)",
41
+ boxShadow: "0 4px 14px color-mix(in oklch, canvastext 16%, transparent)"
42
+ },
43
+ children: [/* @__PURE__ */ S("span", { "data-voltro-nav-spinner": "" }), /* @__PURE__ */ S("style", { children: oe })]
44
+ });
45
+ }, oe = "\n@keyframes voltroNavSpin { to { transform: rotate(360deg); } }\n[data-voltro-nav-spinner] {\n width: 16px;\n height: 16px;\n border-radius: 50%;\n border: 2px solid color-mix(in oklch, canvastext 22%, transparent);\n border-top-color: color-mix(in oklch, canvastext 78%, transparent);\n animation: voltroNavSpin 0.7s linear infinite;\n}\n@media (prefers-reduced-motion: reduce) {\n [data-voltro-nav-spinner] { animation-duration: 1.6s; }\n}\n", se = (e) => Math.min(500 * 2 ** Math.min(e - 1, 4), 5e3), ce = 2, D = 2e3, O = () => typeof window < "u" && !1, le = () => typeof window > "u" ? null : `${window.location.origin}/`, ue = 2e4, k = "voltro:wedge-reload-at", de = () => {
46
+ try {
47
+ let e = Number(window.sessionStorage.getItem(k) ?? "0"), t = Date.now();
48
+ if (t - e < ue) return;
49
+ window.sessionStorage.setItem(k, String(t));
50
+ } catch {}
51
+ window.location.reload();
52
+ }, fe = () => ({
53
+ resolved: null,
54
+ retryToken: 0,
55
+ failureCount: 0,
56
+ generation: 0,
57
+ reconnectStatusDispose: null,
58
+ everOpened: !1,
59
+ healthPollHandle: null
60
+ }), A = (e) => {
61
+ e.healthPollHandle !== null && (clearInterval(e.healthPollHandle), e.healthPollHandle = null);
62
+ }, j = (e) => {
63
+ e.cache.destroy(e.runtime), e.runtime.dispose();
64
+ }, pe = (e) => {
65
+ let n = e.apis, r = e.buildClient, i = e.onChange, a = e.retryDelayMs ?? se, o = e.stableWindowMs ?? 5e3, s = e.scheduler?.setTimeout ?? ((e, t) => setTimeout(e, t)), c = e.scheduler?.clearTimeout ?? ((e) => {
66
+ clearTimeout(e);
67
+ }), l = e.scheduler?.queueMicrotask ?? queueMicrotask, u = /* @__PURE__ */ new Map();
68
+ for (let e of n) u.set(e.name, fe());
69
+ let d = !1, f = /* @__PURE__ */ new Set(), p = (e, t) => {
70
+ let n = s(() => {
71
+ f.delete(n), e();
72
+ }, t);
73
+ return f.add(n), n;
74
+ }, m = () => {
75
+ if (d) return;
76
+ let e = /* @__PURE__ */ new Map();
77
+ for (let [t, n] of u) n.resolved && e.set(t, n.resolved);
78
+ i(e, n.every((t) => e.has(t.name)));
79
+ }, h = (e) => {
80
+ if (d) return;
81
+ let n = u.get(e.name);
82
+ if (!n) return;
83
+ n.failureCount += 1;
84
+ let r = a(n.failureCount), i = ++n.retryToken;
85
+ if (n.reconnectStatusDispose ||= t({
86
+ id: `voltro:supervisor:${e.name}`,
87
+ kind: "reconnecting",
88
+ label: "Reconnecting…"
89
+ }), O() && n.everOpened && n.failureCount >= ce && n.healthPollHandle === null) {
90
+ let e = le();
91
+ e && (n.healthPollHandle = setInterval(() => {
92
+ fetch(e, {
93
+ method: "GET",
94
+ cache: "no-store",
95
+ signal: AbortSignal.timeout(D)
96
+ }).then((e) => {
97
+ e.status < 500 && de();
98
+ }).catch(() => {});
99
+ }, D));
100
+ }
101
+ p(() => {
102
+ d || n.retryToken === i && (n.generation += 1, g(e));
103
+ }, r);
104
+ }, g = async (e) => {
105
+ if (d) return;
106
+ let t = u.get(e.name);
107
+ if (!t) return;
108
+ let n = t.generation, i = () => {
109
+ if (d || t.generation !== n) return;
110
+ t.everOpened = !0, A(t), t.retryToken++;
111
+ let e = t.failureCount;
112
+ p(() => {
113
+ d || t.failureCount === e && (t.failureCount = 0);
114
+ }, o);
115
+ }, a = (r) => {
116
+ d || t.generation !== n || h(e);
117
+ };
118
+ try {
119
+ let o = await r(e, n, i, a);
120
+ if (d || t.generation !== n) {
121
+ j(o);
122
+ return;
123
+ }
124
+ let s = t.resolved;
125
+ t.resolved = o, t.reconnectStatusDispose &&= (t.reconnectStatusDispose(), null), m(), s && j(s);
126
+ } catch {
127
+ if (d || t.generation !== n) return;
128
+ h(e);
129
+ }
130
+ };
131
+ return n.length === 0 ? (i(/* @__PURE__ */ new Map(), !0), {
132
+ dispose: () => {
133
+ d = !0;
134
+ },
135
+ reconnect: () => {}
136
+ }) : (l(() => {
137
+ if (!d) for (let e of n) g(e);
138
+ }), {
139
+ dispose: () => {
140
+ if (!d) {
141
+ d = !0;
142
+ for (let e of f) c(e);
143
+ f.clear();
144
+ for (let [, e] of u) e.resolved && j(e.resolved), e.reconnectStatusDispose && e.reconnectStatusDispose(), A(e);
145
+ u.clear();
146
+ }
147
+ },
148
+ reconnect: () => {
149
+ if (!d) for (let e of n) {
150
+ let t = u.get(e.name);
151
+ t && (t.retryToken += 1, t.generation += 1, t.failureCount = 0, A(t), g(e));
152
+ }
153
+ }
154
+ });
155
+ }, M = {
156
+ log: console.log.bind(console),
157
+ info: console.info.bind(console),
158
+ warn: console.warn.bind(console),
159
+ error: console.error.bind(console),
160
+ debug: console.debug.bind(console)
161
+ }, me = 200, he = 400, N = 20, P = 1e3, F = (e) => {
162
+ if (typeof e == "string") return e;
163
+ if (e === void 0) return "undefined";
164
+ if (e === null) return "null";
165
+ if (e instanceof Error) return e.stack ?? e.message;
166
+ if (typeof e == "object") try {
167
+ return JSON.stringify(e, I());
168
+ } catch {
169
+ return Object.prototype.toString.call(e);
170
+ }
171
+ return String(e);
172
+ }, I = () => {
173
+ let e = /* @__PURE__ */ new WeakSet();
174
+ return (t, n) => {
175
+ if (typeof n == "object" && n) {
176
+ if (e.has(n)) return "[Circular]";
177
+ e.add(n);
178
+ }
179
+ return n;
180
+ };
181
+ }, L = (e, t) => e.length > t ? `${e.slice(0, t)}…` : e, R = /%[sdifoOc]/g, z = (e) => {
182
+ if (e.length === 0) return {
183
+ message: "",
184
+ rest: []
185
+ };
186
+ let t = e[0];
187
+ if (typeof t != "string" || !R.test(t)) return {
188
+ message: F(t),
189
+ rest: e.slice(1)
190
+ };
191
+ R.lastIndex = 0;
192
+ let n = 1;
193
+ return {
194
+ message: t.replace(R, (t) => {
195
+ if (t === "%c") return n++, "";
196
+ if (n >= e.length) return t;
197
+ let r = e[n++];
198
+ switch (t) {
199
+ case "%s": return r === void 0 ? "undefined" : r === null ? "null" : String(r);
200
+ case "%d":
201
+ case "%i": {
202
+ let e = typeof r == "number" ? Math.trunc(r) : parseInt(String(r), 10);
203
+ return Number.isFinite(e) ? String(e) : "NaN";
204
+ }
205
+ case "%f": {
206
+ let e = typeof r == "number" ? r : parseFloat(String(r));
207
+ return Number.isFinite(e) ? String(e) : "NaN";
208
+ }
209
+ case "%o":
210
+ case "%O": return F(r);
211
+ default: return t;
212
+ }
213
+ }),
214
+ rest: e.slice(n)
215
+ };
216
+ }, B = (e) => {
217
+ let t = e.flushAfterMs ?? he, n = `${e.baseUrl.replace(/\/+$/, "")}/_voltro/inspect/clientLog`, r = [], i = null, a = !1, o = () => {
218
+ if (i !== null && (clearTimeout(i), i = null), r.length === 0) return;
219
+ let t = r;
220
+ r = [];
221
+ let a = {
222
+ app: e.appName,
223
+ page: typeof window < "u" ? window.location.pathname : void 0,
224
+ ua: typeof navigator < "u" ? L(navigator.userAgent, 200) : void 0,
225
+ entries: t
226
+ };
227
+ try {
228
+ fetch(n, {
229
+ method: "POST",
230
+ headers: { "content-type": "application/json" },
231
+ body: JSON.stringify(a),
232
+ keepalive: !0,
233
+ credentials: "omit"
234
+ }).catch(() => {});
235
+ } catch {}
236
+ }, s = () => {
237
+ i === null && (i = setTimeout(o, t));
238
+ }, c = (e, t) => {
239
+ if (a) return;
240
+ r.length >= me && r.shift();
241
+ let n = t.find((e) => e instanceof Error), i = t.find((e) => typeof e == "object" && !!e && "componentStack" in e), c = typeof i?.componentStack == "string" ? i.componentStack : void 0, l = t[0] instanceof Error ? {
242
+ message: t[0].message,
243
+ rest: t.slice(1)
244
+ } : z(t), u = L(l.message, P), d = l.rest.filter((e) => e !== n && e !== i).map((e) => L(F(e), P)), f;
245
+ n ? (f = n.stack ?? n.message, c && (f += `\n\nComponent stack:${c}`)) : e === "error" && (f = (/* @__PURE__ */ Error()).stack);
246
+ let p = {
247
+ ts: Date.now(),
248
+ level: e,
249
+ message: u,
250
+ ...d.length > 0 ? { args: d } : {},
251
+ ...f === void 0 ? {} : { stack: f }
252
+ };
253
+ r.push(p), r.length >= N ? o() : s();
254
+ }, l = (e) => (...t) => {
255
+ M[e](...t), c(e, t);
256
+ };
257
+ console.log = l("log"), console.info = l("info"), console.warn = l("warn"), console.error = l("error"), console.debug = l("debug");
258
+ let u = () => {
259
+ o();
260
+ };
261
+ return typeof window < "u" && (window.addEventListener("beforeunload", u), window.addEventListener("pagehide", u)), { dispose: () => {
262
+ a = !0, o(), i !== null && (clearTimeout(i), i = null), console.log = M.log, console.info = M.info, console.warn = M.warn, console.error = M.error, console.debug = M.debug, typeof window < "u" && (window.removeEventListener("beforeunload", u), window.removeEventListener("pagehide", u));
263
+ } };
264
+ }, ge = 500, V = /* @__PURE__ */ new Set(), H = (e) => {
265
+ if (!V.has(e) && (V.add(e), V.size > ge)) {
266
+ let e = V.values().next().value;
267
+ e !== void 0 && V.delete(e);
268
+ }
269
+ }, U = /* @__PURE__ */ new Set(), W = (e) => (U.add(e), () => {
270
+ U.delete(e);
271
+ }), _e = (e) => {
272
+ for (let t of U) try {
273
+ t(e);
274
+ } catch {}
275
+ }, ve = {
276
+ log: "log",
277
+ info: "info",
278
+ warn: "warn",
279
+ error: "error",
280
+ debug: "debug"
281
+ }, G = {
282
+ log: "color: #888;",
283
+ info: "color: #2563eb;",
284
+ warn: "color: #c2410c;",
285
+ error: "color: #b91c1c; font-weight: 600;",
286
+ debug: "color: #6b7280;"
287
+ }, K = (e) => {
288
+ if (typeof EventSource > "u") return { dispose: () => {} };
289
+ let t = `${e.baseUrl.replace(/\/+$/, "")}/_voltro/inspect/stream?live=1`, n = null, r = !1, i = null, a = () => {
290
+ r || (n = new EventSource(t), n.addEventListener("log", (t) => {
291
+ try {
292
+ let n = JSON.parse(t.data).payload;
293
+ if (!n || typeof n.message != "string" || n.scope === "client") return;
294
+ let r = n.level === void 0 ? "log" : ve[n.level], i = n.scope ? ` ${n.scope}` : "";
295
+ M[r](`%c[server ${e.originLabel}${i}]%c ${n.message}`, G[r], "", ...n.fields ? [n.fields] : []);
296
+ } catch {}
297
+ }), n.addEventListener("trace", (t) => {
298
+ try {
299
+ let n = JSON.parse(t.data).payload;
300
+ if (!n || n.status !== "error" || typeof n.traceId != "string" || !V.has(n.traceId)) return;
301
+ let r = n.name ?? "span", i = n.statusMessage && n.statusMessage.length > 0 ? n.statusMessage : `${r} failed`;
302
+ _e({
303
+ traceId: n.traceId,
304
+ spanName: r,
305
+ api: e.originLabel,
306
+ message: i,
307
+ ts: Date.now()
308
+ }), M.error(`%c[trace ${e.originLabel}]%c ${r} failed — ${i} (trace ${n.traceId})`, G.error, "");
309
+ } catch {}
310
+ }), n.addEventListener("error", () => {
311
+ n && n.readyState === EventSource.CLOSED && (n = null, !r && i === null && (i = setTimeout(() => {
312
+ i = null, a();
313
+ }, 2e3)));
314
+ }));
315
+ };
316
+ return a(), { dispose: () => {
317
+ r = !0, i !== null && (clearTimeout(i), i = null), n?.close(), n = null;
318
+ } };
319
+ }, q = {
320
+ card: "oklch(0.21 0.006 285)",
321
+ cardRaised: "oklch(0.25 0.007 285)",
322
+ border: "oklch(1 0 0 / 14%)",
323
+ fg: "oklch(0.98 0.005 285)",
324
+ muted: "oklch(0.65 0.012 285)",
325
+ danger: "oklch(0.7 0.21 22)",
326
+ dangerDim: "oklch(0.5 0.18 22 / 25%)"
327
+ }, J = "ui-monospace, SFMono-Regular, Menlo, Monaco, Consolas, 'Liberation Mono', monospace", ye = "ui-sans-serif, system-ui, -apple-system, 'Segoe UI', Roboto, sans-serif", be = 0, xe = () => {
328
+ let [e, t] = u([]);
329
+ if (c(() => W((e) => {
330
+ t((t) => {
331
+ if (t.some((t) => t.traceId === e.traceId && t.spanName === e.spanName)) return t;
332
+ let n = [...t, {
333
+ ...e,
334
+ id: ++be
335
+ }];
336
+ return n.length > 4 ? n.slice(n.length - 4) : n;
337
+ });
338
+ }), []), e.length === 0) return null;
339
+ let n = (e) => t((t) => t.filter((t) => t.id !== e));
340
+ return /* @__PURE__ */ S("div", {
341
+ style: {
342
+ position: "fixed",
343
+ right: 16,
344
+ bottom: 16,
345
+ zIndex: 2147483646,
346
+ display: "flex",
347
+ flexDirection: "column",
348
+ gap: 10,
349
+ maxWidth: 380,
350
+ fontFamily: ye,
351
+ pointerEvents: "none"
352
+ },
353
+ children: e.map((e) => /* @__PURE__ */ S(Se, {
354
+ toast: e,
355
+ onDismiss: () => n(e.id)
356
+ }, e.id))
357
+ });
358
+ }, Se = ({ toast: e, onDismiss: t }) => {
359
+ let [n, i] = u(!1), a = `voltro logs --trace ${e.traceId}`;
360
+ return /* @__PURE__ */ C("div", {
361
+ style: {
362
+ pointerEvents: "auto",
363
+ background: q.card,
364
+ border: `1px solid ${q.danger}`,
365
+ borderLeft: `3px solid ${q.danger}`,
366
+ borderRadius: 10,
367
+ padding: "12px 14px",
368
+ boxShadow: "0 8px 28px rgba(0,0,0,0.45)",
369
+ color: q.fg,
370
+ fontSize: 13,
371
+ lineHeight: 1.45
372
+ },
373
+ children: [
374
+ /* @__PURE__ */ C("div", {
375
+ style: {
376
+ display: "flex",
377
+ alignItems: "center",
378
+ justifyContent: "space-between",
379
+ gap: 8
380
+ },
381
+ children: [/* @__PURE__ */ S("span", {
382
+ style: {
383
+ color: q.danger,
384
+ fontWeight: 600,
385
+ fontSize: 12,
386
+ letterSpacing: .3
387
+ },
388
+ children: "⚠ Backend error"
389
+ }), /* @__PURE__ */ S("button", {
390
+ onClick: t,
391
+ "aria-label": "Dismiss",
392
+ style: {
393
+ background: "transparent",
394
+ border: "none",
395
+ color: q.muted,
396
+ cursor: "pointer",
397
+ fontSize: 16,
398
+ lineHeight: 1,
399
+ padding: 0
400
+ },
401
+ children: "×"
402
+ })]
403
+ }),
404
+ /* @__PURE__ */ C("div", {
405
+ style: {
406
+ marginTop: 6,
407
+ color: q.muted,
408
+ fontSize: 11.5
409
+ },
410
+ children: [
411
+ /* @__PURE__ */ S("span", {
412
+ style: {
413
+ fontFamily: J,
414
+ color: q.fg
415
+ },
416
+ children: e.api
417
+ }),
418
+ " · ",
419
+ /* @__PURE__ */ S("span", {
420
+ style: { fontFamily: J },
421
+ children: e.spanName
422
+ })
423
+ ]
424
+ }),
425
+ /* @__PURE__ */ S("div", {
426
+ style: {
427
+ marginTop: 4,
428
+ color: q.fg,
429
+ wordBreak: "break-word"
430
+ },
431
+ children: e.message
432
+ }),
433
+ /* @__PURE__ */ S("button", {
434
+ onClick: () => {
435
+ r(a).then((e) => {
436
+ e !== "failed" && (i(!0), setTimeout(() => i(!1), 1500));
437
+ });
438
+ },
439
+ title: "Copy command",
440
+ style: {
441
+ marginTop: 10,
442
+ display: "block",
443
+ width: "100%",
444
+ textAlign: "left",
445
+ background: q.cardRaised,
446
+ border: `1px solid ${q.border}`,
447
+ borderRadius: 6,
448
+ padding: "6px 8px",
449
+ color: q.muted,
450
+ fontFamily: J,
451
+ fontSize: 11,
452
+ cursor: "pointer"
453
+ },
454
+ children: n ? "✓ copied" : a
455
+ })
456
+ ]
457
+ });
458
+ }, Ce = (e) => {
459
+ try {
460
+ let t = new URL(e);
461
+ return `${t.protocol === "wss:" ? "https:" : "http:"}//${t.host}`;
462
+ } catch {
463
+ return "";
464
+ }
465
+ }, Y = (e, t) => /^wss?:\/\//i.test(e) || /^https?:\/\//i.test(e) ? Ce(e) : `/_voltro/api/${t}`, we = typeof performance < "u" ? performance.now() : Date.now(), X = () => {
466
+ if (typeof window > "u") return !1;
467
+ try {
468
+ if (window.localStorage?.getItem("framework_debug") === "1") return !0;
469
+ } catch {}
470
+ return {
471
+ BASE_URL: "/",
472
+ DEV: !1,
473
+ MODE: "production",
474
+ PROD: !0,
475
+ SSR: !1
476
+ }.DEV === !0;
477
+ }, Z = (e, ...t) => {
478
+ if (!X()) return;
479
+ let n = ((typeof performance < "u" ? performance.now() : Date.now()) - we).toFixed(0).padStart(6, " ");
480
+ console.log(`[fw ${e} +${n}ms]`, ...t);
481
+ }, Q = 3e3, Te = 0, Ee = (e, t, n, r) => p.succeed(h.WebSocketConstructor, (i, a) => {
482
+ let o = ++Te;
483
+ Z(e, `ws#${o} create gen=${t} url=${i}`);
484
+ let s = new globalThis.WebSocket(i, a), c = !1, l = !1, u = (e) => {
485
+ l || (l = !0, r(e));
486
+ }, d = (t) => (n) => {
487
+ let r = t === "close" ? `code=${n.code}` : "type=error";
488
+ Z(e, `ws#${o} ${t} opened=${c} issued=${l} ${r}`), u(t);
489
+ };
490
+ return s.addEventListener("open", () => {
491
+ c = !0, Z(e, `ws#${o} open gen=${t}`), n();
492
+ }), s.addEventListener("close", d("close")), s.addEventListener("error", d("error")), setTimeout(() => {
493
+ if (!c && !l) {
494
+ Z(e, `ws#${o} connect-timeout gen=${t} (no open within ${Q}ms)`), u("connect-timeout");
495
+ try {
496
+ s.close();
497
+ } catch {}
498
+ }
499
+ }, Q), s;
500
+ }), De = async (e, t, n, r) => {
501
+ class i extends f.Tag(`@voltro/web/AppClient/${e.name}`)() {}
502
+ let a = _.layerProtocolSocket().pipe(p.provide(v.layerJson), p.provide(h.layerWebSocket(e.wsUrl)), p.provide(Ee(e.name, t, n, r))), o = typeof e.headers == "function" ? await e.headers() : e.headers, s = p.scoped(i, _.make(e.group)).pipe(p.provide(a)), c = o ? p.locallyScoped(_.currentHeaders, g.fromInput(o)) : p.empty;
503
+ Z(e.name, `build gen=${t}: making runtime`);
504
+ let l = m.make(p.merge(s, c));
505
+ try {
506
+ let n = await l.runPromise(i);
507
+ Z(e.name, `build gen=${t}: runtime resolved`);
508
+ let r = new b();
509
+ return {
510
+ runtime: l,
511
+ client: n,
512
+ cache: new ee({ errorBus: r }),
513
+ errorBus: r
514
+ };
515
+ } catch (n) {
516
+ throw Z(e.name, `build gen=${t}: runtime FAILED, disposing`, n.message ?? n), l.dispose(), n;
517
+ }
518
+ }, $ = ({ apis: t, children: n, chrome: r }) => {
519
+ let [i, a] = u(() => ({
520
+ initialized: t.length === 0,
521
+ clients: /* @__PURE__ */ new Map()
522
+ })), s = l(null), d = o(() => {
523
+ s.current?.reconnect();
524
+ }, []), [f, p] = u(!1);
525
+ c(() => {
526
+ p(!0);
527
+ }, []), c(() => {
528
+ let e = pe({
529
+ apis: t,
530
+ buildClient: De,
531
+ onChange: (e, t) => {
532
+ a({
533
+ clients: e,
534
+ initialized: t
535
+ });
536
+ }
537
+ });
538
+ return s.current = e, () => {
539
+ e.dispose(), s.current === e && (s.current = null);
540
+ };
541
+ }, [t]), c(() => {
542
+ if (!X() || typeof window > "u") return;
543
+ let e = [], n = [], r = t[0]?.name ?? "web";
544
+ e.push(B({
545
+ baseUrl: window.location.origin,
546
+ appName: r
547
+ }));
548
+ for (let e of t) {
549
+ let t = Y(e.wsUrl, e.name);
550
+ t.length !== 0 && n.push(K({
551
+ baseUrl: t,
552
+ originLabel: e.name
553
+ }));
554
+ }
555
+ let i = re((e) => H(e.traceId));
556
+ return () => {
557
+ for (let t of e) t.dispose();
558
+ for (let e of n) e.dispose();
559
+ i();
560
+ };
561
+ }, [t]);
562
+ let m = new Map(t.map((e) => [e.name, i.clients.get(e.name)?.client ?? te])), h = new Map(t.map((e) => {
563
+ let t = i.clients.get(e.name);
564
+ return t ? [e.name, {
565
+ runtime: t.runtime,
566
+ cache: t.cache,
567
+ client: t.client,
568
+ descriptors: e.descriptors,
569
+ inspectBaseUrl: Y(e.wsUrl, e.name),
570
+ errorBus: t.errorBus
571
+ }] : [e.name, {
572
+ ...ne,
573
+ descriptors: e.descriptors
574
+ }];
575
+ }));
576
+ return /* @__PURE__ */ S(w.Provider, {
577
+ value: d,
578
+ children: /* @__PURE__ */ S(y, {
579
+ apis: h,
580
+ children: /* @__PURE__ */ C(e.Provider, {
581
+ value: m,
582
+ children: [n, f ? /* @__PURE__ */ C(x, { children: [
583
+ /* @__PURE__ */ S(E, {}),
584
+ r,
585
+ X() ? /* @__PURE__ */ S(xe, {}) : null
586
+ ] }) : null]
587
+ })
588
+ })
589
+ });
590
+ }, Oe = ({ App: e, apis: t, Devtools: n }) => /* @__PURE__ */ S($, {
591
+ apis: t,
592
+ chrome: n ? /* @__PURE__ */ S(n, {}) : null,
593
+ children: /* @__PURE__ */ S(e, {})
594
+ });
595
+ //#endregion
596
+ export { K as a, E as c, B as i, w as l, $ as n, H as o, z as r, W as s, Oe as t, ie as u };
@@ -0,0 +1,64 @@
1
+ import { ComponentType } from 'react';
2
+ import { ReactNode } from 'react';
3
+ import { Rpc } from '@effect/rpc';
4
+ import { RpcGroup } from '@effect/rpc';
5
+
6
+ export declare interface ClientDescriptorMap {
7
+ readonly [rpcTag: string]: {
8
+ readonly kind: 'query' | 'mutation' | 'action' | 'stream' | 'workflow';
9
+ readonly source?: string;
10
+ readonly targets?: ReadonlyArray<{
11
+ readonly table: string;
12
+ readonly op: 'insert' | 'update' | 'delete';
13
+ readonly order?: 'prepend' | 'append';
14
+ }>;
15
+ };
16
+ }
17
+
18
+ export declare const FrameworkBoot: ({ App, apis, Devtools }: FrameworkBootProps) => ReactNode;
19
+
20
+ export declare interface FrameworkBootProps {
21
+ readonly App: ComponentType;
22
+ readonly apis: ReadonlyArray<MountedApi>;
23
+ /** Optional devtools overlay. Rendered as a sibling to <App/>
24
+ * inside the FrameworkRuntimesProvider tree so its hooks
25
+ * (useFrameworkRuntimes etc.) resolve. PascalCase because it is a
26
+ * React component reference rendered as <Devtools/>. */
27
+ readonly Devtools?: ComponentType;
28
+ }
29
+
30
+ export declare interface MountedApi {
31
+ readonly name: string;
32
+ readonly group: RpcGroup.RpcGroup<Rpc.Any>;
33
+ readonly descriptors: ClientDescriptorMap;
34
+ readonly wsUrl: string;
35
+ readonly headers?: ResolvableHeaders | undefined;
36
+ }
37
+
38
+ /**
39
+ * Auth headers for an api's WS rpc client. @effect/rpc sends these in the
40
+ * per-request MESSAGE frame (NOT the WS upgrade — a browser can't set upgrade
41
+ * headers), so the server's AuthMiddleware sees them on every call; this is
42
+ * what lets a cross-origin api authenticate WS subscriptions. A thunk is
43
+ * resolved fresh on every (re)connect, so a rotating token (e.g. a Supabase
44
+ * access token) is pulled anew per connect instead of freezing at first mount.
45
+ */
46
+ export declare type ResolvableHeaders = Record<string, string> | (() => Record<string, string> | Promise<Record<string, string>>);
47
+
48
+ export declare const VoltroRuntimeProvider: ({ apis, children, chrome }: VoltroRuntimeProviderProps) => ReactNode;
49
+
50
+ export declare interface VoltroRuntimeProviderProps {
51
+ /** The apis to mount (name, group, descriptors, wsUrl, headers). */
52
+ readonly apis: ReadonlyArray<MountedApi>;
53
+ /** Rendered inside the resolved runtime contexts — the host's tree. */
54
+ readonly children: ReactNode;
55
+ /** Optional extra chrome rendered (post-hydration only) inside the
56
+ * runtime contexts, alongside the framework's own NavigationIndicator
57
+ * + trace-error overlay. The framework's own web bootstrap passes its
58
+ * Devtools overlay here (see `FrameworkBoot`); foreign hosts leave it
59
+ * unset. Gated behind the same post-mount flag as the rest of the
60
+ * chrome so it never trips a hydration mismatch. */
61
+ readonly chrome?: ReactNode;
62
+ }
63
+
64
+ export { }
@@ -0,0 +1,2 @@
1
+ import { n as e, t } from "./frameworkBoot-DBOFujAI.js";
2
+ export { t as FrameworkBoot, e as VoltroRuntimeProvider };
@@ -0,0 +1,28 @@
1
+ import { Context } from 'react';
2
+
3
+ /**
4
+ * Map of api name → resolved typed rpc client. Installed by the
5
+ * framework's mount() bootstrap. Consumers read it via useAppClient().
6
+ */
7
+ export declare type AppClients = ReadonlyMap<string, unknown>;
8
+
9
+ export declare const AppClientsContext: Context<AppClients | null>;
10
+
11
+ /**
12
+ * Returns the typed rpc client mounted under `apiName`. Generic narrows
13
+ * the result to the caller's group; pass `typeof appGroup` from the api's
14
+ * generated rpcGroup module:
15
+ *
16
+ * import type { appGroup } from '@app/api/rpcGroup'
17
+ * import type { RpcClient, RpcGroup } from '@effect/rpc'
18
+ * type ApiClient = RpcClient.RpcClient<RpcGroup.Rpcs<typeof appGroup>>
19
+ *
20
+ * const client = useAppClient<ApiClient>('api')
21
+ * const { data } = useSubscription('api', () => client.todos.list({}), [])
22
+ *
23
+ * Throws if no api is mounted under `apiName` (typo, missing entry in
24
+ * app.config.ts, or app not mounted yet).
25
+ */
26
+ export declare const useAppClient: <Client>(apiName: string) => Client;
27
+
28
+ export { }