@banou/ripple 0.0.14 → 0.0.16
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/README.md +71 -0
- package/api-DIgTslNb-BSzu7eku.js +374 -0
- package/api-d5i206BT.js +2 -0
- package/assets/worker-1qEVNJrZ.js +23 -0
- package/fkn.json +1 -1
- package/index.js +10338 -10295
- package/package.json +3 -2
- package/sw.js +2 -2
- package/api-Jq4OSTp1-BGG3ivUc.js +0 -338
- package/assets/worker-cT83ESx9.js +0 -23
package/README.md
CHANGED
|
@@ -136,6 +136,77 @@ instead.
|
|
|
136
136
|
| `npx vp lint` | oxlint, type aware | ~1s |
|
|
137
137
|
| `npm run test:download` | the download page against a real torrent, end to end | ~30s |
|
|
138
138
|
| `npm run test:e2e` | the engine against real swarms | minutes, headful |
|
|
139
|
+
| `npm run test:e2e:rig` | the whole chain against a local swarm, see below | ~90s, headful under Xvfb |
|
|
139
140
|
|
|
140
141
|
The playwright suites run headful on purpose: headless Chromium stalls the engine at a flat 0 B/s in
|
|
141
142
|
every topology, which makes anything torrent-shaped unmeasurable rather than merely slow.
|
|
143
|
+
|
|
144
|
+
### The swarm rig
|
|
145
|
+
|
|
146
|
+
`e2e:rig` downloads a torrent that exists only on this machine. The seeders are transmission daemons
|
|
147
|
+
on `127.0.0.2` and up, the relay is a local webvpn build, and the broker is a local fkn-client web
|
|
148
|
+
build, so the only source of a byte is the fleet the magnet names. The public swarm cannot give that:
|
|
149
|
+
byte-identical code measured 14.7 s to 73.4 s to first frame there.
|
|
150
|
+
|
|
151
|
+
| piece | where | port |
|
|
152
|
+
| --- | --- | --- |
|
|
153
|
+
| broker (fkn-client `web`, development build) | `http://localhost:5234/api` | 5234 |
|
|
154
|
+
| relay (webvpn release build) | WebTransport, HTTP, WebSocket on `127.0.0.1` | 5433, 5434, 5443 |
|
|
155
|
+
| ripple (`build/`, served) | `http://localhost:5460` | 5460 |
|
|
156
|
+
| seeders (transmission 4) | `127.0.0.2:52600` and up, rpc `9400` and up | |
|
|
157
|
+
|
|
158
|
+
None of it overlaps fkn/local's rig (1234, 3000, 4433, 4560, 8443), so the two run side by side. The
|
|
159
|
+
ports live in `tests/swarm-rig/topology.json`.
|
|
160
|
+
|
|
161
|
+
It needs three checkouts, and an fkn-client worktree of its own, because the rig rewrites that
|
|
162
|
+
checkout's `.env.local` files and build output:
|
|
163
|
+
|
|
164
|
+
```sh
|
|
165
|
+
git -C ~/dev/horionsoftware/fkn-client worktree add --detach ~/dev/fkn-client-rig origin/main
|
|
166
|
+
(cd ~/dev/horionsoftware/webvpn && cargo build --release)
|
|
167
|
+
|
|
168
|
+
export RIPPLE_RIG_FKN_CLIENT=~/dev/fkn-client-rig
|
|
169
|
+
export RIPPLE_RIG_WEBVPN=~/dev/horionsoftware/webvpn
|
|
170
|
+
export RIPPLE_RIG_LOCAL=~/dev/horionsoftware/local
|
|
171
|
+
export RIPPLE_CHROME=$(command -v google-chrome-stable)
|
|
172
|
+
export RIG_TRANSMISSION=$(nix build --no-link --print-out-paths 'nixpkgs#transmission_4')
|
|
173
|
+
|
|
174
|
+
nix shell nixpkgs#xvfb-run -c env -u WAYLAND_DISPLAY -u NIXOS_OZONE_WL \
|
|
175
|
+
xvfb-run -a -s "-screen 0 1280x720x24" npm run test:e2e:rig
|
|
176
|
+
```
|
|
177
|
+
|
|
178
|
+
`test:e2e:rig` runs three steps:
|
|
179
|
+
|
|
180
|
+
1. `scripts/rig-prepare.mjs` builds `@fkn/lib` with `VITE_WEB_ORIGIN=http://localhost:5234` and the
|
|
181
|
+
web app as the broker, then checks what each build baked in. It refuses a main worktree.
|
|
182
|
+
2. `npm run build`, which sees `RIPPLE_RIG_FKN_CLIENT` and resolves `@fkn/lib` to that local build
|
|
183
|
+
(the published lib has `https://fkn.app` baked in, and no setting of ripple's can move it). The
|
|
184
|
+
build warns when it does this. Afterwards `build/` points at the rig's broker, so rebuild without
|
|
185
|
+
the variable before serving it for anything else.
|
|
186
|
+
3. `playwright.rig.config.ts` starts the relay (the environment `byo.sh webvpn --export` prints, moved
|
|
187
|
+
to the rig's ports, with a fresh certificate and `FREE_RATE_BYTES_PER_SEC` at 1 GiB/s), the broker
|
|
188
|
+
and ripple, then runs `tests/swarm-rig.spec.ts`.
|
|
189
|
+
|
|
190
|
+
The spec has three tests, run in order:
|
|
191
|
+
|
|
192
|
+
- **Configuration.** The relay answers. The RUNNING relay's environment allows private targets and
|
|
193
|
+
carries the raised rate. `/api` serves the broker's own document, not the SPA fallback.
|
|
194
|
+
- **The swarm arm.** It makes a 60 s 720p fixture with ffmpeg (no private flag, which would stop
|
|
195
|
+
seeders serving metadata to a magnet). It starts N seeders with staggered adds and opens `/watch`
|
|
196
|
+
for the magnet in a fresh regular profile. It then asserts that the engine held the whole file,
|
|
197
|
+
that OPFS holds it piece for piece and by SHA-256, that a frame was painted, and that the seeders
|
|
198
|
+
uploaded at least the file. It prints time to first byte, first frame and completion from the add.
|
|
199
|
+
- **The control.** The same fleet comes up and goes down, and the same visit runs for 30 s. It must
|
|
200
|
+
see 0 bytes in the engine and in OPFS, and the swarm arm's own assertion must FAIL on it.
|
|
201
|
+
|
|
202
|
+
The seeders run under a shell that kills them when the test process is gone, so a run killed
|
|
203
|
+
outright leaves nothing on their addresses. Without that shell, all four outlived a SIGKILL.
|
|
204
|
+
|
|
205
|
+
Knobs: `RIPPLE_RIG_SEEDERS` (default 4), `RIPPLE_RIG_BUDGET_MS` (swarm arm, 120000),
|
|
206
|
+
`RIPPLE_RIG_CONTROL_MS` (30000), `RIPPLE_RIG_STATE` (fixture and seeder state, default
|
|
207
|
+
`$TMPDIR/ripple-swarm-rig`). The config refuses to start when `WAYLAND_DISPLAY` or `NIXOS_OZONE_WL`
|
|
208
|
+
is set, because the Nix Chrome wrapper then opens a real window even under `xvfb-run`.
|
|
209
|
+
|
|
210
|
+
The engine's DHT is on, and it announces the infohash through the relay. So the control can see a
|
|
211
|
+
stray peer (1 peer in two of three runs, 0 bytes each time). This is why the seeders' own upload
|
|
212
|
+
count is part of the claim.
|
|
@@ -0,0 +1,374 @@
|
|
|
1
|
+
import { a as e } from "./build-JdIfVZn7.js";
|
|
2
|
+
//#region node_modules/@fkn/lib/api-DIgTslNb.js
|
|
3
|
+
var t = 1e4, n = 16, r = (e) => {
|
|
4
|
+
let t;
|
|
5
|
+
try {
|
|
6
|
+
t = e.contentWindow;
|
|
7
|
+
} catch {
|
|
8
|
+
return !0;
|
|
9
|
+
}
|
|
10
|
+
if (!t) return !0;
|
|
11
|
+
try {
|
|
12
|
+
let e = t.location.href;
|
|
13
|
+
return e !== "" && e !== "about:blank";
|
|
14
|
+
} catch {
|
|
15
|
+
return !0;
|
|
16
|
+
}
|
|
17
|
+
}, i = (e, i = t) => new Promise((t) => {
|
|
18
|
+
if (r(e)) return t();
|
|
19
|
+
let a = () => {
|
|
20
|
+
clearInterval(o), clearTimeout(s), e.removeEventListener("load", a), t();
|
|
21
|
+
}, o = setInterval(() => {
|
|
22
|
+
r(e) && a();
|
|
23
|
+
}, n), s = setTimeout(a, i);
|
|
24
|
+
e.addEventListener("load", a);
|
|
25
|
+
}), a = 32, o = 8, s = 120, c = typeof CSS < "u" && CSS.supports("clip-path", "path('M0 0H1V1H0Z')"), l = typeof CSS < "u" && CSS.supports("clip-path", "polygon(nonzero, 0px 0px, 1px 0px, 1px 1px)"), u = (e) => {
|
|
26
|
+
let t = e.style;
|
|
27
|
+
t.setProperty("display", "block", "important"), t.setProperty("position", "fixed", "important"), t.setProperty("top", "0", "important"), t.setProperty("left", "0", "important"), t.setProperty("width", "100%", "important"), t.setProperty("height", "100%", "important"), t.setProperty("border", "none", "important"), t.setProperty("padding", "0", "important"), t.setProperty("box-sizing", "border-box", "important"), t.setProperty("clip-path", "inset(100%)", "important"), t.setProperty("background", "transparent"), t.setProperty("color-scheme", "normal"), t.setProperty("z-index", "2147483647"), e.setAttribute("title", "FKN");
|
|
28
|
+
}, d = ({ x: e, y: t, width: n, height: r, radius: i }) => {
|
|
29
|
+
if (!i) return `M${e} ${t}h${n}v${r}h${-n}Z`;
|
|
30
|
+
let a = Math.min(n, r) / 2, [o, s, c, l] = i.map((e) => Math.max(0, Math.min(e, a)));
|
|
31
|
+
return `M${e + o} ${t}h${n - o - s}a${s} ${s} 0 0 1 ${s} ${s}v${r - s - c}a${c} ${c} 0 0 1 ${-c} ${c}h${-(n - c - l)}a${l} ${l} 0 0 1 ${-l} ${-l}v${-(r - l - o)}a${o} ${o} 0 0 1 ${o} ${-o}Z`;
|
|
32
|
+
}, f = () => c && l, p = ({ x: e, y: t, width: n, height: r }) => [
|
|
33
|
+
[e, t],
|
|
34
|
+
[e + n, t],
|
|
35
|
+
[e + n, t + r],
|
|
36
|
+
[e, t + r],
|
|
37
|
+
[e, t]
|
|
38
|
+
], m = (e) => {
|
|
39
|
+
let t = e[0];
|
|
40
|
+
if (!t) return [];
|
|
41
|
+
let n = p(t)[0], r = [];
|
|
42
|
+
return e.forEach((t, i) => {
|
|
43
|
+
r.push(...p(t)), i > 0 && i < e.length - 1 && r.push(n);
|
|
44
|
+
}), r;
|
|
45
|
+
}, h = (e) => `polygon(nonzero, ${m(e).map(([e, t]) => `${e}px ${t}px`).join(", ")})`, g = ({ x: e, y: t, width: n, height: r, radius: i }, a) => {
|
|
46
|
+
let o = `${t}px ${a.width - e - n}px ${a.height - t - r}px ${e}px`;
|
|
47
|
+
return i ? `inset(${o} round ${i.map((e) => `${e}px`).join(" ")})` : `inset(${o})`;
|
|
48
|
+
}, ee = (e, t, n) => {
|
|
49
|
+
if (t) return "none";
|
|
50
|
+
if (e.length === 0) return "inset(100%)";
|
|
51
|
+
let r = e.length === 1 ? e[0] : void 0;
|
|
52
|
+
return r ? g(r, n) : l && e.length <= 5 && !e.some((e) => e.radius) ? h(e) : `path('${e.map(d).join("")}')`;
|
|
53
|
+
}, te = (e) => {
|
|
54
|
+
if (e.length < 2) return null;
|
|
55
|
+
let t = Math.min(...e.map((e) => e.x)), n = Math.min(...e.map((e) => e.y));
|
|
56
|
+
return {
|
|
57
|
+
x: t,
|
|
58
|
+
y: n,
|
|
59
|
+
width: Math.max(...e.map((e) => e.x + e.width)) - t,
|
|
60
|
+
height: Math.max(...e.map((e) => e.y + e.height)) - n
|
|
61
|
+
};
|
|
62
|
+
}, ne = (e, t, n) => t >= e.x && t < e.x + e.width && n >= e.y && n < e.y + e.height, re = 16, _ = (e, t, n) => t === 1 ? e * re : t === 2 ? e * n : e, ie = (e, t, n) => {
|
|
63
|
+
let r = getComputedStyle(e);
|
|
64
|
+
return n !== 0 && /auto|scroll/.test(r.overflowY) && e.scrollHeight > e.clientHeight ? !0 : t !== 0 && /auto|scroll/.test(r.overflowX) && e.scrollWidth > e.clientWidth;
|
|
65
|
+
}, v = (e, t, n) => {
|
|
66
|
+
for (let r = e; r; r = r.parentElement) if (ie(r, t, n)) return r;
|
|
67
|
+
return document.scrollingElement;
|
|
68
|
+
}, y = null, b = null, x = (e) => ({
|
|
69
|
+
width: e.offsetWidth || window.innerWidth,
|
|
70
|
+
height: e.offsetHeight || window.innerHeight
|
|
71
|
+
}), S = (e) => {
|
|
72
|
+
if (!b || !y || !ne(b, e.clientX, e.clientY)) return;
|
|
73
|
+
let t = document.elementFromPoint(e.clientX, e.clientY);
|
|
74
|
+
if (!t || t === y) return;
|
|
75
|
+
let n = _(e.deltaX, e.deltaMode, window.innerWidth), r = _(e.deltaY, e.deltaMode, window.innerHeight), i = v(t, n, r);
|
|
76
|
+
i && (i.scrollBy({
|
|
77
|
+
left: n,
|
|
78
|
+
top: r,
|
|
79
|
+
behavior: "instant"
|
|
80
|
+
}), e.cancelable && e.preventDefault());
|
|
81
|
+
}, ae = (e) => {
|
|
82
|
+
let t = b !== null;
|
|
83
|
+
b = e, t !== (e !== null) && (e ? window.addEventListener("wheel", S, {
|
|
84
|
+
capture: !0,
|
|
85
|
+
passive: !1
|
|
86
|
+
}) : window.removeEventListener("wheel", S, { capture: !0 }));
|
|
87
|
+
}, C = 0, w = (e) => {
|
|
88
|
+
if (e === C) return;
|
|
89
|
+
C = e;
|
|
90
|
+
let t = document.documentElement.style;
|
|
91
|
+
e > 0 ? (t.setProperty("margin-top", `${e}px`, "important"), t.setProperty("--fkn-inset-top", `${e}px`)) : (t.removeProperty("margin-top"), t.removeProperty("--fkn-inset-top"));
|
|
92
|
+
}, T = (e, { modal: t, rects: n, inset: r }, i) => {
|
|
93
|
+
if (w(r), !c) {
|
|
94
|
+
let r = t || n.length > 0;
|
|
95
|
+
e.style.setProperty("pointer-events", r ? "auto" : "none", "important"), e.style.setProperty("visibility", r ? "visible" : "hidden", "important");
|
|
96
|
+
return;
|
|
97
|
+
}
|
|
98
|
+
let a = ee(n, t, i), o = a === "none" || CSS.supports("clip-path", a) ? a : "inset(100%)";
|
|
99
|
+
e.style.setProperty("clip-path", o, "important"), ae(t || o !== a ? null : te(n));
|
|
100
|
+
}, oe = (e) => {
|
|
101
|
+
if (typeof e != "object" || !e) return 0;
|
|
102
|
+
let { top: t } = e;
|
|
103
|
+
return typeof t != "number" || !Number.isFinite(t) || t <= 0 ? 0 : Math.min(Math.round(t), s);
|
|
104
|
+
}, se = (e) => {
|
|
105
|
+
if (Array.isArray(e) && e.length === 4 && e.every((e) => typeof e == "number" && Number.isFinite(e) && e >= 0)) return e.some((e) => e > 0) ? e : void 0;
|
|
106
|
+
}, ce = (e, t) => {
|
|
107
|
+
if (typeof e != "object" || !e) return null;
|
|
108
|
+
let { x: n, y: r, width: i, height: a } = e;
|
|
109
|
+
if (![
|
|
110
|
+
n,
|
|
111
|
+
r,
|
|
112
|
+
i,
|
|
113
|
+
a
|
|
114
|
+
].every((e) => typeof e == "number" && Number.isFinite(e))) return null;
|
|
115
|
+
let o = t.width, s = t.height, c = Math.max(0, Math.min(Math.round(n), o)), l = Math.max(0, Math.min(Math.round(r), s)), u = Math.max(c, Math.min(Math.round(n + i), o)), d = Math.max(l, Math.min(Math.round(r + a), s)), f = se(e.radius);
|
|
116
|
+
return {
|
|
117
|
+
x: c,
|
|
118
|
+
y: l,
|
|
119
|
+
width: u - c,
|
|
120
|
+
height: d - l,
|
|
121
|
+
...f ? { radius: f } : {}
|
|
122
|
+
};
|
|
123
|
+
}, E = {
|
|
124
|
+
"not-rendered": "this page is not painting it at all, so it or an ancestor is display:none, or the frame was moved out of the layout",
|
|
125
|
+
clipped: "it is clipped away or positioned outside the viewport",
|
|
126
|
+
"not-shown": "it is rendered but would not be seen, so either something is drawn over it, or it or an ancestor has opacity below 1, visibility:hidden, or a filter"
|
|
127
|
+
}, D = (e) => Array.isArray(e) ? e.slice(0, o).flatMap((e) => {
|
|
128
|
+
if (typeof e != "object" || !e) return [];
|
|
129
|
+
let { kind: t, cause: n, level: r } = e;
|
|
130
|
+
return typeof t != "string" || t.length > 40 || typeof n != "string" || !(n in E) || r !== "full" && r !== "liveness" ? [] : [{
|
|
131
|
+
kind: t,
|
|
132
|
+
cause: n,
|
|
133
|
+
level: r
|
|
134
|
+
}];
|
|
135
|
+
}) : [], O = /* @__PURE__ */ new Set(), le = (e) => {
|
|
136
|
+
for (let { kind: t, cause: n, level: r } of e) O.has(t) || (O.add(t), console.error(`[FKN] The FKN ${JSON.stringify(t)} is not visible on this page: ${E[n]}. Nobody using this page can see or answer it.
|
|
137
|
+
@fkn/lib draws its UI inside <iframe title="FKN"> and sets display, position, top, left, width, height, border, padding, box-sizing, clip-path and z-index on that element. Leave those as they are, then check for an ancestor with opacity, visibility, display or a clipping transform, and for an element stacked above it.` + (r === "liveness" ? "\nThis browser reports limited detail, so the cause above is a best guess." : "")));
|
|
138
|
+
}, k = (e, t) => {
|
|
139
|
+
if (typeof e != "object" || !e) return null;
|
|
140
|
+
let n = e, r = (Array.isArray(n.rects) ? n.rects.slice(0, a) : []).map((e) => ce(e, t)).filter((e) => e !== null && e.width > 0 && e.height > 0);
|
|
141
|
+
return {
|
|
142
|
+
modal: n.modal === !0,
|
|
143
|
+
rects: r,
|
|
144
|
+
hidden: D(n.hidden),
|
|
145
|
+
inset: oe(n.inset)
|
|
146
|
+
};
|
|
147
|
+
}, ue = () => y !== null, A = null, j = null, de = () => {
|
|
148
|
+
if (!y || A === null) return;
|
|
149
|
+
let e = x(y), t = k(A, e);
|
|
150
|
+
t && T(y, t, e);
|
|
151
|
+
}, fe = (e) => {
|
|
152
|
+
typeof ResizeObserver < "u" && (j ??= new ResizeObserver(de), j.disconnect(), j.observe(e));
|
|
153
|
+
}, pe = (e) => {
|
|
154
|
+
u(e), T(e, {
|
|
155
|
+
modal: !1,
|
|
156
|
+
rects: [],
|
|
157
|
+
hidden: [],
|
|
158
|
+
inset: 0
|
|
159
|
+
}, x(e)), y = e, fe(e);
|
|
160
|
+
}, me = (e) => {
|
|
161
|
+
if (!y) return;
|
|
162
|
+
let t = x(y), n = k(e, t);
|
|
163
|
+
n && (A = e, T(y, n, t), le(n.hidden));
|
|
164
|
+
}, he = [
|
|
165
|
+
"fkn.app",
|
|
166
|
+
"fkn.dev",
|
|
167
|
+
"sdbx.app"
|
|
168
|
+
], ge = (e) => e.replace(/\.+$/, ""), _e = (e) => {
|
|
169
|
+
let t = ge(e);
|
|
170
|
+
return he.some((e) => t === e || t.endsWith(`.${e}`));
|
|
171
|
+
}, M = (e) => {
|
|
172
|
+
let t = typeof e == "string" ? e : e instanceof URL ? e.href : e.url, n;
|
|
173
|
+
try {
|
|
174
|
+
n = new URL(t);
|
|
175
|
+
} catch {
|
|
176
|
+
return;
|
|
177
|
+
}
|
|
178
|
+
if (_e(n.hostname)) throw Error(`fetch refuses FKN platform domains (${n.hostname})`);
|
|
179
|
+
}, N = /* @__PURE__ */ "autoplay.fullscreen.picture-in-picture.encrypted-media.screen-wake-lock.speaker-selection.captured-surface-control.camera.microphone.display-capture.geolocation.midi.usb.serial.hid.bluetooth.gamepad.keyboard-map.xr-spatial-tracking.accelerometer.gyroscope.magnetometer.ambient-light-sensor.compute-pressure.clipboard-read.clipboard-write.storage-access.window-management.local-fonts.idle-detection.web-share.sync-xhr.unload.payment.publickey-credentials-get.publickey-credentials-create.otp-credentials.identity-credentials-get.digital-credentials-get.local-network.local-network-access.loopback-network".split("."), P = () => {
|
|
180
|
+
try {
|
|
181
|
+
let e = globalThis.document?.featurePolicy?.features?.();
|
|
182
|
+
return e === void 0 ? void 0 : new Set(e);
|
|
183
|
+
} catch {
|
|
184
|
+
return;
|
|
185
|
+
}
|
|
186
|
+
}, F = (e = !0, t = P()) => [...N, ...e ? ["cross-origin-isolated"] : []].filter((e) => t === void 0 || t.has(e)).join("; "), I = "https://fkn.app", L = typeof globalThis < "u" && globalThis.document ? globalThis.document : void 0, R = typeof globalThis < "u" && globalThis.crossOriginIsolated === !0, z = `${I}/api${R ? "?coi=1" : ""}`, ve = "fkn-api-port", ye = "fkn-api-port-ack", be = 2e3, xe = () => {
|
|
187
|
+
if (!L || typeof window > "u" || window.parent === window) return Promise.resolve(void 0);
|
|
188
|
+
let e;
|
|
189
|
+
try {
|
|
190
|
+
e = window.parent;
|
|
191
|
+
} catch {
|
|
192
|
+
return Promise.resolve(void 0);
|
|
193
|
+
}
|
|
194
|
+
let t = new MessageChannel();
|
|
195
|
+
return new Promise((n) => {
|
|
196
|
+
let r = (e) => {
|
|
197
|
+
if (clearTimeout(a), t.port1.removeEventListener("message", i), !e) try {
|
|
198
|
+
t.port1.close();
|
|
199
|
+
} catch {}
|
|
200
|
+
n(e);
|
|
201
|
+
}, i = (e) => {
|
|
202
|
+
e.data?.type === ye && r(t.port1);
|
|
203
|
+
}, a = setTimeout(() => r(void 0), be);
|
|
204
|
+
t.port1.addEventListener("message", i), t.port1.start();
|
|
205
|
+
try {
|
|
206
|
+
e.postMessage({ type: ve }, I, [t.port2]);
|
|
207
|
+
} catch {
|
|
208
|
+
r(void 0);
|
|
209
|
+
}
|
|
210
|
+
});
|
|
211
|
+
}, B, Se = () => {
|
|
212
|
+
if (B || !L) return B;
|
|
213
|
+
let e = L.querySelector(`iframe[src="${z}"]`);
|
|
214
|
+
if (e) B = e;
|
|
215
|
+
else {
|
|
216
|
+
let e = L.createElement("iframe");
|
|
217
|
+
e.setAttribute("allow", F(R)), e.src = z, L.body.appendChild(e), B = e;
|
|
218
|
+
}
|
|
219
|
+
return pe(B), B;
|
|
220
|
+
}, V = (async () => {
|
|
221
|
+
if (!L) return;
|
|
222
|
+
let e = await xe();
|
|
223
|
+
if (e) return {
|
|
224
|
+
receive: e,
|
|
225
|
+
emit: e
|
|
226
|
+
};
|
|
227
|
+
let t = Se();
|
|
228
|
+
if (!t) return;
|
|
229
|
+
await i(t);
|
|
230
|
+
let n = t.contentWindow;
|
|
231
|
+
return n ? {
|
|
232
|
+
receive: window,
|
|
233
|
+
emit: n
|
|
234
|
+
} : void 0;
|
|
235
|
+
})(), Ce = (e, { boundRetired: t = (e) => e } = {}) => {
|
|
236
|
+
let n, r = 0, i = !1, a = () => {}, o = () => new Promise((e) => {
|
|
237
|
+
a = e;
|
|
238
|
+
}), s = o(), c = s, l = /* @__PURE__ */ new Set(), u = /* @__PURE__ */ new Set(), d = 0, f = 0, p = () => {
|
|
239
|
+
let e = [...u];
|
|
240
|
+
u.clear();
|
|
241
|
+
let t = /* @__PURE__ */ Error("FKN: the broker was replaced while this call was pending; retry it");
|
|
242
|
+
for (let n of e) try {
|
|
243
|
+
n(t);
|
|
244
|
+
} catch {}
|
|
245
|
+
};
|
|
246
|
+
(async () => {
|
|
247
|
+
for await (let t of e) {
|
|
248
|
+
let e = ++r;
|
|
249
|
+
n = {
|
|
250
|
+
remote: t,
|
|
251
|
+
epoch: e
|
|
252
|
+
};
|
|
253
|
+
let i = a;
|
|
254
|
+
s = o(), i(t), p();
|
|
255
|
+
for (let n of [...l]) try {
|
|
256
|
+
n(t, e);
|
|
257
|
+
} catch {}
|
|
258
|
+
}
|
|
259
|
+
})().catch(() => {});
|
|
260
|
+
let m = async (e, r) => {
|
|
261
|
+
let a = n?.remote ?? await (i ? t(s) : s);
|
|
262
|
+
for (let t of e.slice(0, -1)) a = a[t];
|
|
263
|
+
let o = a[e[e.length - 1] ?? ""];
|
|
264
|
+
d = Date.now(), f += 1;
|
|
265
|
+
let c = () => {}, l = new Promise((e, t) => {
|
|
266
|
+
c = t;
|
|
267
|
+
});
|
|
268
|
+
u.add(c);
|
|
269
|
+
try {
|
|
270
|
+
return await Promise.race([Promise.resolve(o.apply(a, r)), l]);
|
|
271
|
+
} finally {
|
|
272
|
+
--f, u.delete(c), d = Date.now();
|
|
273
|
+
}
|
|
274
|
+
}, h = /* @__PURE__ */ new Map(), g = (e) => {
|
|
275
|
+
let t = e.join("\0"), r = h.get(t);
|
|
276
|
+
if (r) return r;
|
|
277
|
+
let i = new Proxy(function() {}, {
|
|
278
|
+
get: (t, r) => {
|
|
279
|
+
if (typeof r != "string" || r === "then") return;
|
|
280
|
+
let i = n;
|
|
281
|
+
if (i) {
|
|
282
|
+
let t = i.remote;
|
|
283
|
+
for (let n of e) t = t?.[n];
|
|
284
|
+
if (t?.[r] === void 0) return;
|
|
285
|
+
}
|
|
286
|
+
return g([...e, r]);
|
|
287
|
+
},
|
|
288
|
+
apply: (t, n, r) => m(e, r)
|
|
289
|
+
});
|
|
290
|
+
return h.set(t, i), i;
|
|
291
|
+
};
|
|
292
|
+
return {
|
|
293
|
+
facade: g([]),
|
|
294
|
+
first: c.then(() => {}),
|
|
295
|
+
current: () => n,
|
|
296
|
+
onEpoch: (e) => {
|
|
297
|
+
if (l.add(e), n) try {
|
|
298
|
+
e(n.remote, n.epoch);
|
|
299
|
+
} catch {}
|
|
300
|
+
return () => {
|
|
301
|
+
l.delete(e);
|
|
302
|
+
};
|
|
303
|
+
},
|
|
304
|
+
lastCall: () => d,
|
|
305
|
+
inFlight: () => f,
|
|
306
|
+
routable: () => n ? Promise.resolve() : s.then(() => {}),
|
|
307
|
+
retire: () => {
|
|
308
|
+
i = !0, n = void 0, p();
|
|
309
|
+
}
|
|
310
|
+
};
|
|
311
|
+
}, H = !1, U = /* @__PURE__ */ new Set(), W = () => H, we = () => {
|
|
312
|
+
if (!H) {
|
|
313
|
+
H = !0;
|
|
314
|
+
for (let e of [...U]) try {
|
|
315
|
+
e();
|
|
316
|
+
} catch {}
|
|
317
|
+
U.clear();
|
|
318
|
+
}
|
|
319
|
+
}, G = (e) => {
|
|
320
|
+
H ? e() : U.add(e);
|
|
321
|
+
}, Te = typeof window < "u" || typeof self < "u", Ee = async () => {
|
|
322
|
+
if (typeof window < "u") return V;
|
|
323
|
+
if (typeof self < "u") return {
|
|
324
|
+
receive: self,
|
|
325
|
+
emit: self
|
|
326
|
+
};
|
|
327
|
+
}, De = "fkn-api", Oe = "fkn-api-window", K = Ce({ async *[Symbol.asyncIterator]() {
|
|
328
|
+
let t = await Ee();
|
|
329
|
+
if (!t) {
|
|
330
|
+
await new Promise(() => {});
|
|
331
|
+
return;
|
|
332
|
+
}
|
|
333
|
+
if (!W()) {
|
|
334
|
+
let n = new AbortController();
|
|
335
|
+
G(() => n.abort());
|
|
336
|
+
for await (let r of e({}, {
|
|
337
|
+
key: De,
|
|
338
|
+
transport: t,
|
|
339
|
+
unregisterSignal: n.signal
|
|
340
|
+
})) {
|
|
341
|
+
if (n.signal.aborted) break;
|
|
342
|
+
yield r;
|
|
343
|
+
}
|
|
344
|
+
}
|
|
345
|
+
yield* e({}, {
|
|
346
|
+
key: Oe,
|
|
347
|
+
transport: t
|
|
348
|
+
});
|
|
349
|
+
} }, { boundRetired: (e) => Q(e, () => new Z()) });
|
|
350
|
+
G(() => K.retire());
|
|
351
|
+
var q = Promise.race([K.first, new Promise((e) => G(e))]).then(() => K.facade), J = 8e3, ke = 1e3, Y = !1, X = class extends Error {
|
|
352
|
+
constructor(e, t) {
|
|
353
|
+
super(`@fkn/lib: no broker connection within ${t}ms, so ${e} could not be requested`), this.name = "BrokerUnreachableError";
|
|
354
|
+
}
|
|
355
|
+
}, Z = class extends Error {
|
|
356
|
+
constructor() {
|
|
357
|
+
super("FKN @fkn/lib: this page relays its FKN channel to a worker, and the FKN page it reached predates a channel of the page's own; reload"), this.name = "OwnChannelUnavailableError";
|
|
358
|
+
}
|
|
359
|
+
}, Q = (e, t) => {
|
|
360
|
+
let n = Y ? ke : J;
|
|
361
|
+
return Promise.race([e, new Promise((e, r) => setTimeout(() => {
|
|
362
|
+
Y = !0, r(t(n));
|
|
363
|
+
}, n))]);
|
|
364
|
+
}, Ae = (e) => W() ? Q(K.routable().then(() => K.facade), () => new Z()) : Q(q, (t) => new X(e, t));
|
|
365
|
+
G(() => {
|
|
366
|
+
let e = setTimeout(() => console.error(new Z()), J);
|
|
367
|
+
K.routable().then(() => clearTimeout(e));
|
|
368
|
+
});
|
|
369
|
+
var $ = K.onEpoch, je = K.current;
|
|
370
|
+
K.lastCall, K.inFlight, $((e) => {
|
|
371
|
+
ue() && e.overlay.setHost(me, { exactClips: f() }).catch(() => {});
|
|
372
|
+
});
|
|
373
|
+
//#endregion
|
|
374
|
+
export { M as a, X as c, q as d, we as f, J as i, Z as l, Ae as n, Te as o, F as r, V as s, $ as t, je as u };
|
package/api-d5i206BT.js
ADDED