@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.
- package/CHANGELOG.md +52 -0
- package/LICENSE +57 -0
- package/README.md +26 -0
- package/SECURITY.md +56 -0
- package/THIRD-PARTY-NOTICES.md +347 -0
- package/dist/defaultFallbacks-Bg_X-9Wv.js +541 -0
- package/dist/frameworkBoot-DBOFujAI.js +596 -0
- package/dist/frameworkBoot.d.ts +64 -0
- package/dist/frameworkBoot.js +2 -0
- package/dist/hooks.d.ts +28 -0
- package/dist/hooks.js +14 -0
- package/dist/index.d.ts +1077 -0
- package/dist/index.js +141 -0
- package/dist/mount-BuFzlw1e.js +74 -0
- package/dist/mount.d.ts +70 -0
- package/dist/mount.js +2 -0
- package/dist/serverContext-D5-Dmh8d.js +741 -0
- package/dist/ssr.d.ts +322 -0
- package/dist/ssr.js +76 -0
- package/package.json +68 -0
|
@@ -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 { }
|
package/dist/hooks.d.ts
ADDED
|
@@ -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 { }
|