@statewalker/webrun-http-browser 0.4.2 → 0.6.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/LICENSE +21 -0
- package/README.md +207 -12
- package/dist/core/deadline.d.ts +7 -0
- package/dist/core/deadline.d.ts.map +1 -0
- package/dist/core/index.d.ts +1 -0
- package/dist/core/index.d.ts.map +1 -1
- package/dist/core/service-worker-control.d.ts +72 -0
- package/dist/core/service-worker-control.d.ts.map +1 -0
- package/dist/index.js +328 -67
- package/dist/relay/index-sw.d.ts +86 -1
- package/dist/relay/index-sw.d.ts.map +1 -1
- package/dist/relay/index.d.ts +32 -8
- package/dist/relay/index.d.ts.map +1 -1
- package/dist/relay/mount-table.d.ts +48 -0
- package/dist/relay/mount-table.d.ts.map +1 -0
- package/dist/relay/split-service-url.d.ts.map +1 -1
- package/dist/relay-sw.js +293 -50
- package/dist/relay-worker.d.ts +20 -0
- package/dist/relay-worker.d.ts.map +1 -0
- package/dist/relay-worker.js +1899 -0
- package/dist/sw/sw-dispatcher.d.ts +22 -0
- package/dist/sw/sw-dispatcher.d.ts.map +1 -1
- package/dist/sw-worker.js +23 -2
- package/dist/sw.js +219 -36
- package/package.json +9 -1
- package/src/core/deadline.ts +31 -0
- package/src/core/index.ts +1 -0
- package/src/core/service-worker-control.ts +243 -0
- package/src/relay/index-sw.ts +293 -37
- package/src/relay/index.ts +125 -51
- package/src/relay/mount-table.ts +115 -0
- package/src/relay/split-service-url.ts +73 -13
- package/src/relay-sw.ts +11 -3
- package/src/relay-worker.ts +20 -0
- package/src/sw/sw-dispatcher.ts +72 -45
- package/public-relay/heartbeat.js +0 -31
package/dist/index.js
CHANGED
|
@@ -1125,6 +1125,192 @@ function newRegistry(onError = console.error) {
|
|
|
1125
1125
|
});
|
|
1126
1126
|
}
|
|
1127
1127
|
//#endregion
|
|
1128
|
+
//#region src/core/deadline.ts
|
|
1129
|
+
/**
|
|
1130
|
+
* Settles like `promise` if it settles before `deadline` (a `Date.now()`
|
|
1131
|
+
* value). Otherwise calls `onTimeout`: an `Error` it returns rejects, any
|
|
1132
|
+
* other value resolves. Internal; not re-exported.
|
|
1133
|
+
*/
|
|
1134
|
+
function withDeadline(deadline, promise, onTimeout) {
|
|
1135
|
+
return new Promise((resolve, reject) => {
|
|
1136
|
+
const timer = setTimeout(() => {
|
|
1137
|
+
const outcome = onTimeout();
|
|
1138
|
+
if (outcome instanceof Error) reject(outcome);
|
|
1139
|
+
else resolve(outcome);
|
|
1140
|
+
}, Math.max(0, deadline - Date.now()));
|
|
1141
|
+
promise.then((value) => {
|
|
1142
|
+
clearTimeout(timer);
|
|
1143
|
+
resolve(value);
|
|
1144
|
+
}, (error) => {
|
|
1145
|
+
clearTimeout(timer);
|
|
1146
|
+
reject(error);
|
|
1147
|
+
});
|
|
1148
|
+
});
|
|
1149
|
+
}
|
|
1150
|
+
//#endregion
|
|
1151
|
+
//#region src/core/service-worker-control.ts
|
|
1152
|
+
/**
|
|
1153
|
+
* How long, by default, the page waits for its ServiceWorker to activate and
|
|
1154
|
+
* to take control before giving up. Generous: a first install downloads and
|
|
1155
|
+
* evaluates the worker script, which on a slow link takes seconds.
|
|
1156
|
+
*/
|
|
1157
|
+
const DEFAULT_SERVICE_WORKER_TIMEOUT = 3e4;
|
|
1158
|
+
/**
|
|
1159
|
+
* How long the page waits for `controllerchange` once the worker has
|
|
1160
|
+
* answered the `CLAIM` request. `clients.claim()` resolves only after the
|
|
1161
|
+
* browser has queued that event, so this is a grace period for delivery, not
|
|
1162
|
+
* a second budget.
|
|
1163
|
+
*/
|
|
1164
|
+
const CLAIM_GRACE_MS = 1e3;
|
|
1165
|
+
/** Channel call a page sends to ask its ServiceWorker to `clients.claim()` it. */
|
|
1166
|
+
const CLAIM_CALL = "CLAIM";
|
|
1167
|
+
/**
|
|
1168
|
+
* Why a page could not get a working ServiceWorker. `reason` says which wait
|
|
1169
|
+
* failed; check it (or `name`) rather than `instanceof`, because each of this
|
|
1170
|
+
* package's bundles carries its own copy of this class.
|
|
1171
|
+
*/
|
|
1172
|
+
var ServiceWorkerControlError = class extends Error {
|
|
1173
|
+
reason;
|
|
1174
|
+
constructor(reason, message) {
|
|
1175
|
+
super(message);
|
|
1176
|
+
this.name = "ServiceWorkerControlError";
|
|
1177
|
+
this.reason = reason;
|
|
1178
|
+
}
|
|
1179
|
+
};
|
|
1180
|
+
/**
|
|
1181
|
+
* Resolves with the registration's worker once it is `activated`. Rejects
|
|
1182
|
+
* with a `ServiceWorkerControlError` (`reason: "activation-timeout"`) if that
|
|
1183
|
+
* takes longer than `timeout` — an install that throws or never finishes
|
|
1184
|
+
* would otherwise leave the caller waiting forever.
|
|
1185
|
+
*/
|
|
1186
|
+
async function awaitActiveServiceWorker(registration, { timeout = DEFAULT_SERVICE_WORKER_TIMEOUT } = {}) {
|
|
1187
|
+
return await withDeadline(Date.now() + timeout, waitForActivated(registration), () => {
|
|
1188
|
+
const worker = registration.installing ?? registration.waiting ?? registration.active;
|
|
1189
|
+
return new ServiceWorkerControlError("activation-timeout", `ServiceWorker ${scriptUrl(worker)} (scope ${registration.scope}) did not activate within ${timeout} ms` + (worker ? `; it is "${worker.state}"` : "") + ". Check the worker script for errors during install (DevTools → Application → Service Workers), or raise the `timeout` option.");
|
|
1190
|
+
});
|
|
1191
|
+
}
|
|
1192
|
+
/**
|
|
1193
|
+
* Resolves with the ServiceWorker that controls this page, once `registration`
|
|
1194
|
+
* has an activated worker and the page is controlled by it.
|
|
1195
|
+
*
|
|
1196
|
+
* A page can stay uncontrolled while its worker is active, and then no
|
|
1197
|
+
* `controllerchange` ever fires on its own:
|
|
1198
|
+
* - a hard reload (Ctrl+Shift+R) bypasses the worker for that load, and the
|
|
1199
|
+
* worker's `clients.claim()` already ran when it activated;
|
|
1200
|
+
* - Firefox can leave a page loaded while the worker is running uncontrolled.
|
|
1201
|
+
*
|
|
1202
|
+
* So when the page is uncontrolled, this asks the active worker to claim it
|
|
1203
|
+
* again (a `CLAIM` channel call — this package's workers answer it) and waits
|
|
1204
|
+
* for `controllerchange`. Every wait is bounded by `timeout`. If control never
|
|
1205
|
+
* comes it reloads once (`reloadIfUncontrolled`) or rejects with a
|
|
1206
|
+
* `ServiceWorkerControlError` (`reason: "uncontrolled"`) that says what
|
|
1207
|
+
* happened and what to do.
|
|
1208
|
+
*/
|
|
1209
|
+
async function awaitServiceWorkerControl(registration, { timeout = DEFAULT_SERVICE_WORKER_TIMEOUT, reloadIfUncontrolled = false, container = navigator.serviceWorker } = {}) {
|
|
1210
|
+
const deadline = Date.now() + timeout;
|
|
1211
|
+
const controlled = waitForController(container);
|
|
1212
|
+
try {
|
|
1213
|
+
const active = await awaitActiveServiceWorker(registration, { timeout });
|
|
1214
|
+
let controller = container.controller;
|
|
1215
|
+
if (!controller) controller = await withDeadline(deadline, (async () => {
|
|
1216
|
+
await Promise.race([callChannel(active, CLAIM_CALL, {}), controlled.promise]);
|
|
1217
|
+
return await Promise.race([controlled.promise, delay(CLAIM_GRACE_MS, null)]);
|
|
1218
|
+
})(), () => null);
|
|
1219
|
+
if (controller) {
|
|
1220
|
+
forgetReload(registration);
|
|
1221
|
+
return controller;
|
|
1222
|
+
}
|
|
1223
|
+
if (reloadIfUncontrolled && markReload(registration)) {
|
|
1224
|
+
location.reload();
|
|
1225
|
+
return await new Promise(() => {});
|
|
1226
|
+
}
|
|
1227
|
+
forgetReload(registration);
|
|
1228
|
+
throw new ServiceWorkerControlError("uncontrolled", `This page is not controlled by its ServiceWorker ${scriptUrl(active)} (scope ${registration.scope}), although the worker is active, and the worker did not take control when asked (clients.claim()) within ${timeout} ms. This happens after a hard reload (Ctrl+Shift+R / Cmd+Shift+R), which bypasses ServiceWorkers for that load, and in Firefox for some pages opened while the worker was already running. Requests from this page would not reach the worker. Reload the page normally, pass \`reloadIfUncontrolled: true\` to do that automatically, check that the page is inside the worker's scope, and that the worker answers the "${CLAIM_CALL}" request (this package's workers do).`);
|
|
1229
|
+
} finally {
|
|
1230
|
+
controlled.cancel();
|
|
1231
|
+
}
|
|
1232
|
+
}
|
|
1233
|
+
/**
|
|
1234
|
+
* ServiceWorker side: answers the page's `CLAIM` request with
|
|
1235
|
+
* `clients.claim()`, which takes over every uncontrolled client in scope.
|
|
1236
|
+
* Returns a function that stops answering.
|
|
1237
|
+
*/
|
|
1238
|
+
function handleClaimRequests(self) {
|
|
1239
|
+
return handleChannelCalls(self, CLAIM_CALL, (event) => {
|
|
1240
|
+
const claimed = self.clients.claim().then(() => true);
|
|
1241
|
+
event.waitUntil?.(claimed);
|
|
1242
|
+
return claimed;
|
|
1243
|
+
});
|
|
1244
|
+
}
|
|
1245
|
+
function waitForActivated(registration) {
|
|
1246
|
+
return new Promise((resolve) => {
|
|
1247
|
+
const watched = /* @__PURE__ */ new Set();
|
|
1248
|
+
const check = () => {
|
|
1249
|
+
const active = registration.active;
|
|
1250
|
+
if (active?.state === "activated") {
|
|
1251
|
+
registration.removeEventListener("updatefound", watch);
|
|
1252
|
+
for (const worker of watched) worker.removeEventListener("statechange", check);
|
|
1253
|
+
resolve(active);
|
|
1254
|
+
return;
|
|
1255
|
+
}
|
|
1256
|
+
watch();
|
|
1257
|
+
};
|
|
1258
|
+
function watch() {
|
|
1259
|
+
for (const worker of [
|
|
1260
|
+
registration.installing,
|
|
1261
|
+
registration.waiting,
|
|
1262
|
+
registration.active
|
|
1263
|
+
]) {
|
|
1264
|
+
if (!worker || watched.has(worker)) continue;
|
|
1265
|
+
watched.add(worker);
|
|
1266
|
+
worker.addEventListener("statechange", check);
|
|
1267
|
+
}
|
|
1268
|
+
}
|
|
1269
|
+
registration.addEventListener("updatefound", watch);
|
|
1270
|
+
check();
|
|
1271
|
+
});
|
|
1272
|
+
}
|
|
1273
|
+
function waitForController(container) {
|
|
1274
|
+
let cancel = () => {};
|
|
1275
|
+
return {
|
|
1276
|
+
promise: new Promise((resolve) => {
|
|
1277
|
+
const onChange = () => {
|
|
1278
|
+
if (!container.controller) return;
|
|
1279
|
+
cancel();
|
|
1280
|
+
resolve(container.controller);
|
|
1281
|
+
};
|
|
1282
|
+
cancel = () => container.removeEventListener("controllerchange", onChange);
|
|
1283
|
+
container.addEventListener("controllerchange", onChange);
|
|
1284
|
+
}),
|
|
1285
|
+
cancel
|
|
1286
|
+
};
|
|
1287
|
+
}
|
|
1288
|
+
function delay(ms, value) {
|
|
1289
|
+
return new Promise((resolve) => setTimeout(() => resolve(value), ms));
|
|
1290
|
+
}
|
|
1291
|
+
function scriptUrl(worker) {
|
|
1292
|
+
return worker?.scriptURL ? `"${worker.scriptURL}"` : "(no worker)";
|
|
1293
|
+
}
|
|
1294
|
+
function reloadKey(registration) {
|
|
1295
|
+
return `webrun-http-browser:reloaded-uncontrolled:${registration.scope}`;
|
|
1296
|
+
}
|
|
1297
|
+
/** Records the reload about to happen. `false` if one already happened, or if it cannot be recorded. */
|
|
1298
|
+
function markReload(registration) {
|
|
1299
|
+
try {
|
|
1300
|
+
const key = reloadKey(registration);
|
|
1301
|
+
if (sessionStorage.getItem(key)) return false;
|
|
1302
|
+
sessionStorage.setItem(key, "1");
|
|
1303
|
+
return true;
|
|
1304
|
+
} catch {
|
|
1305
|
+
return false;
|
|
1306
|
+
}
|
|
1307
|
+
}
|
|
1308
|
+
function forgetReload(registration) {
|
|
1309
|
+
try {
|
|
1310
|
+
sessionStorage.removeItem(reloadKey(registration));
|
|
1311
|
+
} catch {}
|
|
1312
|
+
}
|
|
1313
|
+
//#endregion
|
|
1128
1314
|
//#region ../webrun-http-streams/dist/index.js
|
|
1129
1315
|
const CR = 13;
|
|
1130
1316
|
const LF = 10;
|
|
@@ -2474,37 +2660,78 @@ async function sendHttpRequest(communicationPort, request) {
|
|
|
2474
2660
|
*/
|
|
2475
2661
|
function splitServiceUrl(url, separator = "~") {
|
|
2476
2662
|
const str = `${url}`;
|
|
2477
|
-
const
|
|
2478
|
-
|
|
2479
|
-
|
|
2480
|
-
|
|
2481
|
-
|
|
2482
|
-
|
|
2483
|
-
|
|
2484
|
-
|
|
2485
|
-
|
|
2486
|
-
|
|
2487
|
-
|
|
2488
|
-
|
|
2489
|
-
|
|
2490
|
-
|
|
2663
|
+
const empty = {
|
|
2664
|
+
url: str,
|
|
2665
|
+
key: "",
|
|
2666
|
+
baseUrl: "",
|
|
2667
|
+
path: ""
|
|
2668
|
+
};
|
|
2669
|
+
const hashIdx = str.indexOf("#");
|
|
2670
|
+
const queryIdx = str.indexOf("?");
|
|
2671
|
+
let strippedEnd = str.length;
|
|
2672
|
+
if (hashIdx >= 0) strippedEnd = Math.min(strippedEnd, hashIdx);
|
|
2673
|
+
if (queryIdx >= 0) strippedEnd = Math.min(strippedEnd, queryIdx);
|
|
2674
|
+
const stripped = str.slice(0, strippedEnd);
|
|
2675
|
+
let prefixEnd = 0;
|
|
2676
|
+
const schemeMatch = stripped.match(/^[a-zA-Z][a-zA-Z0-9+\-.]*:\/\//);
|
|
2677
|
+
if (schemeMatch) {
|
|
2678
|
+
prefixEnd = schemeMatch[0].length;
|
|
2679
|
+
const slashIdx = stripped.indexOf("/", prefixEnd);
|
|
2680
|
+
if (slashIdx >= 0) prefixEnd = slashIdx;
|
|
2681
|
+
else return empty;
|
|
2682
|
+
} else if (stripped.startsWith("//")) {
|
|
2683
|
+
prefixEnd = 2;
|
|
2684
|
+
const slashIdx = stripped.indexOf("/", prefixEnd);
|
|
2685
|
+
if (slashIdx >= 0) prefixEnd = slashIdx;
|
|
2686
|
+
else return empty;
|
|
2687
|
+
}
|
|
2688
|
+
const prefix = stripped.slice(0, prefixEnd);
|
|
2689
|
+
const pathPart = stripped.slice(prefixEnd);
|
|
2690
|
+
let keyStart;
|
|
2691
|
+
let rooted = false;
|
|
2692
|
+
if (prefix === "") {
|
|
2693
|
+
if (pathPart.startsWith(`/${separator}`)) {
|
|
2694
|
+
rooted = true;
|
|
2695
|
+
keyStart = separator.length + 1;
|
|
2696
|
+
} else if (pathPart.startsWith(separator)) keyStart = separator.length;
|
|
2697
|
+
else return empty;
|
|
2698
|
+
} else {
|
|
2699
|
+
if (!pathPart.startsWith(`/${separator}`)) return empty;
|
|
2700
|
+
keyStart = separator.length + 1;
|
|
2701
|
+
}
|
|
2702
|
+
const rest = pathPart.slice(keyStart);
|
|
2703
|
+
const slash = rest.indexOf("/");
|
|
2704
|
+
const key = slash < 0 ? rest : rest.slice(0, slash);
|
|
2705
|
+
if (key === "") return empty;
|
|
2491
2706
|
return {
|
|
2492
2707
|
url: str,
|
|
2493
2708
|
key,
|
|
2494
|
-
baseUrl
|
|
2495
|
-
path
|
|
2709
|
+
baseUrl: `${prefix === "" ? rooted ? "/" : "" : `${prefix}/`}${separator}${key}${slash < 0 ? "" : "/"}`,
|
|
2710
|
+
path: slash < 0 ? "" : rest.slice(slash + 1)
|
|
2496
2711
|
};
|
|
2497
2712
|
}
|
|
2498
2713
|
//#endregion
|
|
2499
2714
|
//#region src/relay/index.ts
|
|
2500
2715
|
/**
|
|
2716
|
+
* The URL of this module, kept in a variable on purpose. Bundlers (Vite
|
|
2717
|
+
* among them) rewrite every literal `new URL("<path>", import.meta.url)` into
|
|
2718
|
+
* an emitted asset at build time, before tree-shaking — so the defaults below
|
|
2719
|
+
* made every Vite consumer of this entry emit a dead copy of the package's
|
|
2720
|
+
* own `dist/index.js` (`"../"` resolves to the package, hence to its `main`).
|
|
2721
|
+
* Resolving against a variable is the same URL at run time and invisible to
|
|
2722
|
+
* that transform.
|
|
2723
|
+
*/
|
|
2724
|
+
const moduleUrl = import.meta.url;
|
|
2725
|
+
/**
|
|
2501
2726
|
* Returns a MessagePort that transparently bridges messages to/from the
|
|
2502
|
-
* ServiceWorker controlling
|
|
2727
|
+
* page's ServiceWorker: the one controlling the page, or — when the page is
|
|
2728
|
+
* not controlled (a hard reload, or a page Firefox left uncontrolled) — the
|
|
2729
|
+
* active worker of `registration`, which answers messages all the same.
|
|
2503
2730
|
*/
|
|
2504
|
-
function newServiceWorkerPort() {
|
|
2731
|
+
function newServiceWorkerPort(registration) {
|
|
2505
2732
|
const channel = new MessageChannel();
|
|
2506
2733
|
channel.port1.onmessage = (event) => {
|
|
2507
|
-
navigator.serviceWorker.controller?.postMessage(event.data, [...event.ports]);
|
|
2734
|
+
(navigator.serviceWorker.controller ?? registration?.active)?.postMessage(event.data, [...event.ports]);
|
|
2508
2735
|
};
|
|
2509
2736
|
navigator.serviceWorker.addEventListener("message", (event) => {
|
|
2510
2737
|
channel.port1.postMessage(event.data, [...event.ports]);
|
|
@@ -2512,53 +2739,35 @@ function newServiceWorkerPort() {
|
|
|
2512
2739
|
return channel.port2;
|
|
2513
2740
|
}
|
|
2514
2741
|
/**
|
|
2515
|
-
* Registers a ServiceWorker and resolves once it
|
|
2742
|
+
* Registers a ServiceWorker and resolves with it once it is activated: the
|
|
2743
|
+
* worker controlling the page, or the registration's active worker when the
|
|
2744
|
+
* page is not controlled. Messaging works either way, which is all the relay
|
|
2745
|
+
* needs; nothing here waits for control, because an uncontrolled page (hard
|
|
2746
|
+
* reload; Firefox) may never get it. Rejects with a
|
|
2747
|
+
* `ServiceWorkerControlError` if activation takes longer than `timeout`.
|
|
2516
2748
|
*/
|
|
2517
|
-
async function initServiceWorker(
|
|
2518
|
-
await
|
|
2749
|
+
async function initServiceWorker(options) {
|
|
2750
|
+
return (await registerServiceWorker(options)).worker;
|
|
2751
|
+
}
|
|
2752
|
+
async function registerServiceWorker({ swUrl, scopeUrl, type, timeout = DEFAULT_SERVICE_WORKER_TIMEOUT }) {
|
|
2753
|
+
const registration = await navigator.serviceWorker.register(swUrl, {
|
|
2519
2754
|
type,
|
|
2520
2755
|
scope: scopeUrl
|
|
2521
2756
|
});
|
|
2522
|
-
const
|
|
2523
|
-
|
|
2524
|
-
|
|
2525
|
-
|
|
2526
|
-
|
|
2527
|
-
return new Promise((resolve) => {
|
|
2528
|
-
const container = navigator.serviceWorker;
|
|
2529
|
-
if (container.controller) {
|
|
2530
|
-
resolve(container.controller);
|
|
2531
|
-
return;
|
|
2532
|
-
}
|
|
2533
|
-
const onChange = () => {
|
|
2534
|
-
if (!container.controller) return;
|
|
2535
|
-
resolve(container.controller);
|
|
2536
|
-
container.removeEventListener("controllerchange", onChange);
|
|
2537
|
-
};
|
|
2538
|
-
container.addEventListener("controllerchange", onChange);
|
|
2539
|
-
});
|
|
2540
|
-
}
|
|
2541
|
-
function awaitServiceWorkerActivation(worker) {
|
|
2542
|
-
return new Promise((resolve) => {
|
|
2543
|
-
if (worker.state === "activated") {
|
|
2544
|
-
resolve();
|
|
2545
|
-
return;
|
|
2546
|
-
}
|
|
2547
|
-
const onStateChange = () => {
|
|
2548
|
-
if (worker.state !== "activated") return;
|
|
2549
|
-
worker.removeEventListener("statechange", onStateChange);
|
|
2550
|
-
resolve();
|
|
2551
|
-
};
|
|
2552
|
-
worker.addEventListener("statechange", onStateChange);
|
|
2553
|
-
});
|
|
2757
|
+
const active = await awaitActiveServiceWorker(registration, { timeout });
|
|
2758
|
+
return {
|
|
2759
|
+
registration,
|
|
2760
|
+
worker: navigator.serviceWorker.controller ?? active
|
|
2761
|
+
};
|
|
2554
2762
|
}
|
|
2555
2763
|
/**
|
|
2556
2764
|
* Registers `handler` as the server for the given service `key` on the relay.
|
|
2557
2765
|
* Returns a cleanup function that unregisters the service.
|
|
2558
2766
|
*/
|
|
2559
|
-
async function initHttpService(handler, { key, port }) {
|
|
2767
|
+
async function initHttpService(handler, { key, path, port }) {
|
|
2560
2768
|
return await registerConnectionsHandler({
|
|
2561
2769
|
key,
|
|
2770
|
+
path,
|
|
2562
2771
|
communicationPort: port,
|
|
2563
2772
|
handler: async (_event, _data, callPort) => {
|
|
2564
2773
|
handleHttpRequests(callPort, handler);
|
|
@@ -2581,9 +2790,11 @@ async function callHttpService(request, { key, port }) {
|
|
|
2581
2790
|
/**
|
|
2582
2791
|
* Returns a `window.onmessage` handler for use inside the relay iframe:
|
|
2583
2792
|
* it accepts a CONNECT message, starts the relay ServiceWorker, and bridges
|
|
2584
|
-
* the parent's MessagePort with the SW.
|
|
2793
|
+
* the parent's MessagePort with the SW. If the worker cannot be started, every
|
|
2794
|
+
* call the parent makes on that port is answered with the error, so the
|
|
2795
|
+
* parent's `initHttpService` / `callHttpService` reject instead of waiting.
|
|
2585
2796
|
*/
|
|
2586
|
-
function getRelayWindowMessageHandler({ swUrl = `${new URL("./index-sw.js",
|
|
2797
|
+
function getRelayWindowMessageHandler({ swUrl = `${new URL("./index-sw.js", moduleUrl)}`, scopeUrl = `${new URL("../", moduleUrl)}`, timeout } = {}) {
|
|
2587
2798
|
let externalPort;
|
|
2588
2799
|
return async (ev) => {
|
|
2589
2800
|
if (ev.data?.type !== "CONNECT") return;
|
|
@@ -2594,11 +2805,19 @@ function getRelayWindowMessageHandler({ swUrl = `${new URL("./index-sw.js", impo
|
|
|
2594
2805
|
return;
|
|
2595
2806
|
}
|
|
2596
2807
|
externalPort = newExternalPort;
|
|
2597
|
-
|
|
2598
|
-
|
|
2599
|
-
|
|
2600
|
-
|
|
2601
|
-
|
|
2808
|
+
let registration;
|
|
2809
|
+
try {
|
|
2810
|
+
({registration} = await registerServiceWorker({
|
|
2811
|
+
swUrl,
|
|
2812
|
+
scopeUrl,
|
|
2813
|
+
timeout
|
|
2814
|
+
}));
|
|
2815
|
+
} catch (error) {
|
|
2816
|
+
const serialized = serializeError(error);
|
|
2817
|
+
externalPort.onmessage = (event) => event.ports[0]?.postMessage({ error: serialized });
|
|
2818
|
+
throw error;
|
|
2819
|
+
}
|
|
2820
|
+
const serviceWorkerPort = newServiceWorkerPort(registration);
|
|
2602
2821
|
serviceWorkerPort.onmessage = (event) => {
|
|
2603
2822
|
externalPort?.postMessage(event.data, [...event.ports]);
|
|
2604
2823
|
};
|
|
@@ -2611,7 +2830,7 @@ function getRelayWindowMessageHandler({ swUrl = `${new URL("./index-sw.js", impo
|
|
|
2611
2830
|
* Embeds a hidden relay iframe, establishes a MessageChannel with it, and
|
|
2612
2831
|
* returns the port to be used with `initHttpService` / `callHttpService`.
|
|
2613
2832
|
*/
|
|
2614
|
-
async function newRemoteRelayChannel({ baseUrl = new URL("../public-relay/",
|
|
2833
|
+
async function newRemoteRelayChannel({ baseUrl = new URL("../public-relay/", moduleUrl), url = new URL("relay.html", baseUrl), container = document.body } = {}) {
|
|
2615
2834
|
const messageChannel = new MessageChannel();
|
|
2616
2835
|
const { iframe, promise } = newIFrame(url);
|
|
2617
2836
|
Object.assign(iframe.style, {
|
|
@@ -2670,14 +2889,56 @@ async function initializeConnection({ key, communicationPort, ...options }) {
|
|
|
2670
2889
|
}
|
|
2671
2890
|
return channel.port1;
|
|
2672
2891
|
}
|
|
2673
|
-
async function registerConnectionsHandler({ key, handler, communicationPort }) {
|
|
2892
|
+
async function registerConnectionsHandler({ key, path, handler, communicationPort }) {
|
|
2674
2893
|
const [register, cleanup] = newRegistry();
|
|
2675
|
-
await callChannel(communicationPort, "REGISTER", { key }
|
|
2894
|
+
await callChannel(communicationPort, "REGISTER", path == null ? { key } : {
|
|
2895
|
+
key,
|
|
2896
|
+
path
|
|
2897
|
+
});
|
|
2676
2898
|
register(() => callChannel(communicationPort, "UNREGISTER", { key }));
|
|
2677
|
-
register(
|
|
2899
|
+
register(handleKeyedChannelCalls(communicationPort, "CONNECT", key, async (event, data, port) => {
|
|
2678
2900
|
return await handler(event, data, port);
|
|
2679
2901
|
}));
|
|
2680
2902
|
return cleanup;
|
|
2681
2903
|
}
|
|
2904
|
+
/**
|
|
2905
|
+
* `handleChannelCalls`, but only for calls whose `params.key` is `key`.
|
|
2906
|
+
*
|
|
2907
|
+
* ONE CONNECTION CARRIES SEVERAL SERVICES — an app at `/` and a mesh gateway
|
|
2908
|
+
* at `/peers/` over one relay iframe is the shape mounts exist for. Plain
|
|
2909
|
+
* `handleChannelCalls` cannot do that: every listener it has for a call type
|
|
2910
|
+
* runs on every message, and each is handed the SAME reply port and the SAME
|
|
2911
|
+
* transferred stream port. Two services then both serve the one channel the
|
|
2912
|
+
* worker is reading, and its response comes back with both bodies in it.
|
|
2913
|
+
*
|
|
2914
|
+
* WHY NOT A FILTER INSIDE THE HANDLER. Returning `false` for a foreign key
|
|
2915
|
+
* does not help: `handleChannelCalls` still replies, `callChannel` resolves on
|
|
2916
|
+
* the FIRST reply it receives, and the loser's `false` reaches the worker as
|
|
2917
|
+
* "the client refused" — a 403, non-deterministically. A service that is not
|
|
2918
|
+
* the addressee must stay SILENT and leave the transferred port untouched.
|
|
2919
|
+
*
|
|
2920
|
+
* Local to this module on purpose. `handleChannelCalls` is also used where a
|
|
2921
|
+
* call carries no key (REGISTER/UNREGISTER, and the worker's own CONNECT in
|
|
2922
|
+
* `index-sw.ts`, which is the other direction), so its semantics must not
|
|
2923
|
+
* change.
|
|
2924
|
+
*/
|
|
2925
|
+
function handleKeyedChannelCalls(target, callType, key, handler) {
|
|
2926
|
+
const listener = async (event) => {
|
|
2927
|
+
const data = event.data;
|
|
2928
|
+
if (!data || data.type !== callType) return;
|
|
2929
|
+
if (data.params?.key !== key) return;
|
|
2930
|
+
const [port, ...transfers] = event.ports ?? [];
|
|
2931
|
+
const response = {};
|
|
2932
|
+
try {
|
|
2933
|
+
response.result = await handler(event, data.params, ...transfers);
|
|
2934
|
+
} catch (error) {
|
|
2935
|
+
response.error = serializeError(error);
|
|
2936
|
+
}
|
|
2937
|
+
port?.postMessage(response);
|
|
2938
|
+
};
|
|
2939
|
+
target.addEventListener("message", listener);
|
|
2940
|
+
target.start?.();
|
|
2941
|
+
return () => target.removeEventListener("message", listener);
|
|
2942
|
+
}
|
|
2682
2943
|
//#endregion
|
|
2683
|
-
export { DuplexSiteBuilder, HttpError, HttpParseError, PEER_ERROR_HEADER, TransportClosedError, callChannel, callHttpService, collect, collectBytes, collectString, decodeJsonl, decodeMessage, decodeText, defaultCodec, deserializeError, emulateMux, encodeJsonl, encodeMessage, encodeText, fetchOverDuplex, fromReadableStream, getRelayWindowMessageHandler, handleChannelCalls, handleHttpRequests, handleStreams, httpCodec, httpFetch, httpServe, initHttpService, initServiceWorker, initializeConnection, joinLines, jsonEnvelopeCodec, map, newAsyncGenerator, newCreditGrantor, newCreditLedger, newHttpClientStub, newHttpCodec, newHttpServerStub, newInvokationChannel, newRegistry, newRemoteRelayChannel, newServiceWorkerPort, newSniffingCodec, normalizeToUint8Array, recieveIterator, registerConnectionsHandler, sendHttpRequest, sendIterator, sendStream, serializeError, serveFetchOverDuplex, splitLines, splitServiceUrl, toChunks, toReadableStream };
|
|
2944
|
+
export { CLAIM_CALL, DEFAULT_SERVICE_WORKER_TIMEOUT, DuplexSiteBuilder, HttpError, HttpParseError, PEER_ERROR_HEADER, ServiceWorkerControlError, TransportClosedError, awaitActiveServiceWorker, awaitServiceWorkerControl, callChannel, callHttpService, collect, collectBytes, collectString, decodeJsonl, decodeMessage, decodeText, defaultCodec, deserializeError, emulateMux, encodeJsonl, encodeMessage, encodeText, fetchOverDuplex, fromReadableStream, getRelayWindowMessageHandler, handleChannelCalls, handleClaimRequests, handleHttpRequests, handleStreams, httpCodec, httpFetch, httpServe, initHttpService, initServiceWorker, initializeConnection, joinLines, jsonEnvelopeCodec, map, newAsyncGenerator, newCreditGrantor, newCreditLedger, newHttpClientStub, newHttpCodec, newHttpServerStub, newInvokationChannel, newRegistry, newRemoteRelayChannel, newServiceWorkerPort, newSniffingCodec, normalizeToUint8Array, recieveIterator, registerConnectionsHandler, sendHttpRequest, sendIterator, sendStream, serializeError, serveFetchOverDuplex, splitLines, splitServiceUrl, toChunks, toReadableStream };
|
package/dist/relay/index-sw.d.ts
CHANGED
|
@@ -1,7 +1,92 @@
|
|
|
1
|
+
import { type MountSpec, type MountTable } from "./mount-table.js";
|
|
2
|
+
/** What the registry keeps per service key. */
|
|
3
|
+
export interface RegisteredClient {
|
|
4
|
+
clientId: string;
|
|
5
|
+
/** Where the service is mounted. Absent means `/~<key>/`, as before mounts. */
|
|
6
|
+
path?: string;
|
|
7
|
+
}
|
|
8
|
+
/**
|
|
9
|
+
* One stored registry entry, whatever shape it is on disk.
|
|
10
|
+
*
|
|
11
|
+
* BEFORE MOUNTS THE VALUE WAS A BARE CLIENT ID. A browser that ran the earlier
|
|
12
|
+
* worker still holds that shape, and reading it as an object would drop the id
|
|
13
|
+
* and quietly unregister every service the visitor had.
|
|
14
|
+
*/
|
|
15
|
+
export declare function readStoredEntry(value: unknown): RegisteredClient | undefined;
|
|
16
|
+
/**
|
|
17
|
+
* Which service, if any, should answer `url`.
|
|
18
|
+
*
|
|
19
|
+
* `undefined` means NOT THE RELAY'S, and the caller must not call
|
|
20
|
+
* `respondWith`: the request then goes to the network, which is how a host
|
|
21
|
+
* keeps serving its own files from its own origin. Answering 404 here instead
|
|
22
|
+
* would make a root mount fatal.
|
|
23
|
+
*/
|
|
24
|
+
export declare function resolveServiceKey(url: URL, table: MountTable, selfOrigin: string): string | undefined;
|
|
25
|
+
/**
|
|
26
|
+
* Waits for the mount table to be restored from the registry before routing
|
|
27
|
+
* `url` — but a restore failure must never wedge every fetch. `restored`
|
|
28
|
+
* rejecting (blocked storage, quota, private-mode edge cases) would otherwise
|
|
29
|
+
* propagate straight to `respondWith` on every request, including ones that
|
|
30
|
+
* should reach the network, which breaks the one rule this file exists to
|
|
31
|
+
* uphold. So: log the failure and route with whatever the in-memory table
|
|
32
|
+
* already holds — possibly empty, never fatal.
|
|
33
|
+
*/
|
|
34
|
+
export declare function resolveAfterRestore(restored: Promise<void>, url: URL, table: MountTable, selfOrigin: string): Promise<string | undefined>;
|
|
35
|
+
/**
|
|
36
|
+
* What REGISTER does to the mount table: set it when `path` is given, or
|
|
37
|
+
* remove any earlier mount when it is not. A path-less re-registration
|
|
38
|
+
* reverts a service to `/~<key>/` addressing, and a stale prefix left behind
|
|
39
|
+
* would keep routing requests to a mount that no longer exists.
|
|
40
|
+
*
|
|
41
|
+
* A REGISTRATION ONLY TOUCHES WHAT A REGISTRATION MADE. `hostKeys` names the
|
|
42
|
+
* mounts the host declared itself, in `options.mounts`. Those are the host's
|
|
43
|
+
* build-time decision and a page may not undo it: the documented static flow
|
|
44
|
+
* -- host declares `{ key: "app", path: "/" }`, page calls `initHttpService(h,
|
|
45
|
+
* { key: "app", port })` with no path -- would otherwise have its very first
|
|
46
|
+
* registration delete the host's own mount and leave the origin unmounted. A
|
|
47
|
+
* path-ful REGISTER naming a host key is ignored for the same reason (it would
|
|
48
|
+
* replace a `match` predicate with a prefix of the page's choosing).
|
|
49
|
+
*/
|
|
50
|
+
export declare function applyRegisteredMount(table: MountTable, key: string, path: string | undefined, hostKeys?: ReadonlySet<string>): void;
|
|
51
|
+
/**
|
|
52
|
+
* What UNREGISTER does to the mount table: drop the mount a registration
|
|
53
|
+
* made. A host-declared mount stays, for the reason `applyRegisteredMount`
|
|
54
|
+
* gives -- a page tearing down its service must not take the host's table
|
|
55
|
+
* with it.
|
|
56
|
+
*/
|
|
57
|
+
export declare function removeRegisteredMount(table: MountTable, key: string, hostKeys?: ReadonlySet<string>): void;
|
|
58
|
+
export interface RelayServiceWorkerOptions {
|
|
59
|
+
/** A fixed table, for a host that knows its services at build time. */
|
|
60
|
+
mounts?: Array<{
|
|
61
|
+
key: string;
|
|
62
|
+
} & MountSpec>;
|
|
63
|
+
/** Paths the relay never claims. Checked before the table. */
|
|
64
|
+
exclude?: (url: URL) => boolean;
|
|
65
|
+
/** Refuse a registration from the wrong client. Default: everyone may. */
|
|
66
|
+
canRegister?: (client: Client, key: string) => boolean | Promise<boolean>;
|
|
67
|
+
/** Default `"last-wins"`, the behaviour before this option existed. */
|
|
68
|
+
takeover?: "first-wins" | "last-wins";
|
|
69
|
+
/** Stamp headers on responses the relay makes. Not applied to network fetches. */
|
|
70
|
+
decorateResponse?: (response: Response, request: Request) => Response;
|
|
71
|
+
}
|
|
72
|
+
/**
|
|
73
|
+
* May `candidateId` take the key?
|
|
74
|
+
*
|
|
75
|
+
* `last-wins` is what the relay has always done and stays the default. With
|
|
76
|
+
* `first-wins`, a LIVE holder keeps its key: on an origin whose name is
|
|
77
|
+
* guessable, a second page proves nothing by existing. A holder that reloaded
|
|
78
|
+
* is no longer live, so a host's own re-registration is never blocked.
|
|
79
|
+
*/
|
|
80
|
+
export declare function mayRegister(args: {
|
|
81
|
+
current?: RegisteredClient;
|
|
82
|
+
candidateId: string;
|
|
83
|
+
isCurrentLive: boolean;
|
|
84
|
+
takeover: "first-wins" | "last-wins";
|
|
85
|
+
}): boolean;
|
|
1
86
|
/**
|
|
2
87
|
* Boots the relay ServiceWorker: routes fetches shaped `<origin>/~<key>/…` to
|
|
3
88
|
* the client that registered `key`, and exposes REGISTER/UNREGISTER/CONNECT
|
|
4
89
|
* channel calls used by the page-side relay client.
|
|
5
90
|
*/
|
|
6
|
-
export declare function startRelayServiceWorker(self: ServiceWorkerGlobalScope): () => void;
|
|
91
|
+
export declare function startRelayServiceWorker(self: ServiceWorkerGlobalScope, options?: RelayServiceWorkerOptions): () => void;
|
|
7
92
|
//# sourceMappingURL=index-sw.d.ts.map
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"index-sw.d.ts","sourceRoot":"","sources":["../../src/relay/index-sw.ts"],"names":[],"mappings":"
|
|
1
|
+
{"version":3,"file":"index-sw.d.ts","sourceRoot":"","sources":["../../src/relay/index-sw.ts"],"names":[],"mappings":"AAMA,OAAO,EAAE,KAAK,SAAS,EAAE,KAAK,UAAU,EAAiB,MAAM,kBAAkB,CAAC;AAGlF,+CAA+C;AAC/C,MAAM,WAAW,gBAAgB;IAC/B,QAAQ,EAAE,MAAM,CAAC;IACjB,+EAA+E;IAC/E,IAAI,CAAC,EAAE,MAAM,CAAC;CACf;AAED;;;;;;GAMG;AACH,wBAAgB,eAAe,CAAC,KAAK,EAAE,OAAO,GAAG,gBAAgB,GAAG,SAAS,CAM5E;AAED;;;;;;;GAOG;AACH,wBAAgB,iBAAiB,CAC/B,GAAG,EAAE,GAAG,EACR,KAAK,EAAE,UAAU,EACjB,UAAU,EAAE,MAAM,GACjB,MAAM,GAAG,SAAS,CAUpB;AAED;;;;;;;;GAQG;AACH,wBAAsB,mBAAmB,CACvC,QAAQ,EAAE,OAAO,CAAC,IAAI,CAAC,EACvB,GAAG,EAAE,GAAG,EACR,KAAK,EAAE,UAAU,EACjB,UAAU,EAAE,MAAM,GACjB,OAAO,CAAC,MAAM,GAAG,SAAS,CAAC,CAO7B;AAED;;;;;;;;;;;;;;GAcG;AACH,wBAAgB,oBAAoB,CAClC,KAAK,EAAE,UAAU,EACjB,GAAG,EAAE,MAAM,EACX,IAAI,EAAE,MAAM,GAAG,SAAS,EACxB,QAAQ,GAAE,WAAW,CAAC,MAAM,CAAa,GACxC,IAAI,CAON;AAED;;;;;GAKG;AACH,wBAAgB,qBAAqB,CACnC,KAAK,EAAE,UAAU,EACjB,GAAG,EAAE,MAAM,EACX,QAAQ,GAAE,WAAW,CAAC,MAAM,CAAa,GACxC,IAAI,CAGN;AAED,MAAM,WAAW,yBAAyB;IACxC,uEAAuE;IACvE,MAAM,CAAC,EAAE,KAAK,CAAC;QAAE,GAAG,EAAE,MAAM,CAAA;KAAE,GAAG,SAAS,CAAC,CAAC;IAC5C,8DAA8D;IAC9D,OAAO,CAAC,EAAE,CAAC,GAAG,EAAE,GAAG,KAAK,OAAO,CAAC;IAChC,0EAA0E;IAC1E,WAAW,CAAC,EAAE,CAAC,MAAM,EAAE,MAAM,EAAE,GAAG,EAAE,MAAM,KAAK,OAAO,GAAG,OAAO,CAAC,OAAO,CAAC,CAAC;IAC1E,uEAAuE;IACvE,QAAQ,CAAC,EAAE,YAAY,GAAG,WAAW,CAAC;IACtC,kFAAkF;IAClF,gBAAgB,CAAC,EAAE,CAAC,QAAQ,EAAE,QAAQ,EAAE,OAAO,EAAE,OAAO,KAAK,QAAQ,CAAC;CACvE;AAED;;;;;;;GAOG;AACH,wBAAgB,WAAW,CAAC,IAAI,EAAE;IAChC,OAAO,CAAC,EAAE,gBAAgB,CAAC;IAC3B,WAAW,EAAE,MAAM,CAAC;IACpB,aAAa,EAAE,OAAO,CAAC;IACvB,QAAQ,EAAE,YAAY,GAAG,WAAW,CAAC;CACtC,GAAG,OAAO,CAIV;AAED;;;;GAIG;AACH,wBAAgB,uBAAuB,CACrC,IAAI,EAAE,wBAAwB,EAC9B,OAAO,GAAE,yBAA8B,GACtC,MAAM,IAAI,CAwJZ"}
|
package/dist/relay/index.d.ts
CHANGED
|
@@ -3,27 +3,45 @@ import type { MessageTarget } from "../core/message-target.js";
|
|
|
3
3
|
export * from "./split-service-url.js";
|
|
4
4
|
/**
|
|
5
5
|
* Returns a MessagePort that transparently bridges messages to/from the
|
|
6
|
-
* ServiceWorker controlling
|
|
6
|
+
* page's ServiceWorker: the one controlling the page, or — when the page is
|
|
7
|
+
* not controlled (a hard reload, or a page Firefox left uncontrolled) — the
|
|
8
|
+
* active worker of `registration`, which answers messages all the same.
|
|
7
9
|
*/
|
|
8
|
-
export declare function newServiceWorkerPort(): MessagePort;
|
|
10
|
+
export declare function newServiceWorkerPort(registration?: ServiceWorkerRegistration): MessagePort;
|
|
9
11
|
export interface InitServiceWorkerOptions {
|
|
10
12
|
swUrl: string;
|
|
11
13
|
scopeUrl?: string;
|
|
12
14
|
type?: WorkerType;
|
|
15
|
+
/**
|
|
16
|
+
* Upper bound, in ms, for the wait for the worker to activate; past it the
|
|
17
|
+
* promise rejects with a `ServiceWorkerControlError`. Default
|
|
18
|
+
* `DEFAULT_SERVICE_WORKER_TIMEOUT` (30 s).
|
|
19
|
+
*/
|
|
20
|
+
timeout?: number;
|
|
13
21
|
}
|
|
14
22
|
/**
|
|
15
|
-
* Registers a ServiceWorker and resolves once it
|
|
23
|
+
* Registers a ServiceWorker and resolves with it once it is activated: the
|
|
24
|
+
* worker controlling the page, or the registration's active worker when the
|
|
25
|
+
* page is not controlled. Messaging works either way, which is all the relay
|
|
26
|
+
* needs; nothing here waits for control, because an uncontrolled page (hard
|
|
27
|
+
* reload; Firefox) may never get it. Rejects with a
|
|
28
|
+
* `ServiceWorkerControlError` if activation takes longer than `timeout`.
|
|
16
29
|
*/
|
|
17
|
-
export declare function initServiceWorker(
|
|
30
|
+
export declare function initServiceWorker(options: InitServiceWorkerOptions): Promise<ServiceWorker>;
|
|
18
31
|
export interface ServiceOptions {
|
|
19
32
|
key: string;
|
|
33
|
+
/**
|
|
34
|
+
* Where this service is mounted on the relay origin, e.g. `/` or `/peers/`.
|
|
35
|
+
* Omitted, the service stays reachable at `/~<key>/`, as before mounts.
|
|
36
|
+
*/
|
|
37
|
+
path?: string;
|
|
20
38
|
port: MessageTarget;
|
|
21
39
|
}
|
|
22
40
|
/**
|
|
23
41
|
* Registers `handler` as the server for the given service `key` on the relay.
|
|
24
42
|
* Returns a cleanup function that unregisters the service.
|
|
25
43
|
*/
|
|
26
|
-
export declare function initHttpService(handler: HttpHandler, { key, port }: ServiceOptions): Promise<() => void>;
|
|
44
|
+
export declare function initHttpService(handler: HttpHandler, { key, path, port }: ServiceOptions): Promise<() => void>;
|
|
27
45
|
/**
|
|
28
46
|
* Sends a `Request` to the service registered under `key` on the relay and
|
|
29
47
|
* resolves with the corresponding `Response`.
|
|
@@ -32,13 +50,17 @@ export declare function callHttpService(request: Request, { key, port }: Service
|
|
|
32
50
|
export interface RelayWindowHandlerOptions {
|
|
33
51
|
swUrl?: string;
|
|
34
52
|
scopeUrl?: string;
|
|
53
|
+
/** Passed to `initServiceWorker`: how long to wait for the relay worker to activate. */
|
|
54
|
+
timeout?: number;
|
|
35
55
|
}
|
|
36
56
|
/**
|
|
37
57
|
* Returns a `window.onmessage` handler for use inside the relay iframe:
|
|
38
58
|
* it accepts a CONNECT message, starts the relay ServiceWorker, and bridges
|
|
39
|
-
* the parent's MessagePort with the SW.
|
|
59
|
+
* the parent's MessagePort with the SW. If the worker cannot be started, every
|
|
60
|
+
* call the parent makes on that port is answered with the error, so the
|
|
61
|
+
* parent's `initHttpService` / `callHttpService` reject instead of waiting.
|
|
40
62
|
*/
|
|
41
|
-
export declare function getRelayWindowMessageHandler({ swUrl, scopeUrl, }?: RelayWindowHandlerOptions): (ev: MessageEvent) => Promise<void>;
|
|
63
|
+
export declare function getRelayWindowMessageHandler({ swUrl, scopeUrl, timeout, }?: RelayWindowHandlerOptions): (ev: MessageEvent) => Promise<void>;
|
|
42
64
|
export interface RemoteRelayChannelOptions {
|
|
43
65
|
baseUrl?: URL;
|
|
44
66
|
url?: URL;
|
|
@@ -62,8 +84,10 @@ export interface InitializeConnectionOptions {
|
|
|
62
84
|
export declare function initializeConnection({ key, communicationPort, ...options }: InitializeConnectionOptions): Promise<MessagePort | null>;
|
|
63
85
|
export interface RegisterConnectionsHandlerOptions {
|
|
64
86
|
key: string;
|
|
87
|
+
/** Where this service is mounted; see `ServiceOptions.path`. */
|
|
88
|
+
path?: string;
|
|
65
89
|
handler: (event: MessageEvent, data: unknown, port: MessagePort) => boolean | Promise<boolean>;
|
|
66
90
|
communicationPort: MessageTarget;
|
|
67
91
|
}
|
|
68
|
-
export declare function registerConnectionsHandler({ key, handler, communicationPort, }: RegisterConnectionsHandlerOptions): Promise<() => void>;
|
|
92
|
+
export declare function registerConnectionsHandler({ key, path, handler, communicationPort, }: RegisterConnectionsHandlerOptions): Promise<() => void>;
|
|
69
93
|
//# sourceMappingURL=index.d.ts.map
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../../src/relay/index.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,WAAW,EAAE,MAAM,kCAAkC,CAAC;
|
|
1
|
+
{"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../../src/relay/index.ts"],"names":[],"mappings":"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"}
|