summaryrefslogtreecommitdiffstats
path: root/packages/meshbay-hub/src
diff options
context:
space:
mode:
Diffstat (limited to 'packages/meshbay-hub/src')
-rw-r--r--packages/meshbay-hub/src/meshbay_hub/static/app.js4
-rw-r--r--packages/meshbay-hub/src/meshbay_hub/static/platform.js45
-rw-r--r--packages/meshbay-hub/src/meshbay_hub/static/transport.js8
3 files changed, 53 insertions, 4 deletions
diff --git a/packages/meshbay-hub/src/meshbay_hub/static/app.js b/packages/meshbay-hub/src/meshbay_hub/static/app.js
index abb3374..24ef43f 100644
--- a/packages/meshbay-hub/src/meshbay_hub/static/app.js
+++ b/packages/meshbay-hub/src/meshbay_hub/static/app.js
@@ -237,7 +237,7 @@ async function refreshAccessToken() {
if (_refreshing) return _refreshing;
_refreshing = (async () => {
try {
- const r = await fetch(HUB + '/v1/users/token/refresh', {
+ const r = await platform.apiFetch(HUB + '/v1/users/token/refresh', {
method: 'POST',
headers: { 'Content-Type': 'application/json' },
body: JSON.stringify({ refresh_token: _auth.refreshToken }),
@@ -299,7 +299,7 @@ async function hubFetch(path, { method = 'GET', body, token, _retried } = {}) {
if (bearer) headers['Authorization'] = `Bearer ${bearer}`;
const opts = { method, headers };
if (body) opts.body = JSON.stringify(body);
- const r = await fetch(HUB + path, opts);
+ const r = await platform.apiFetch(HUB + path, opts);
if (r.status === 401 && bearer && !_retried) {
// The one case worth a second attempt: the access token aged out while
// nothing was talking to the hub. Renew once and replay. If the renewal
diff --git a/packages/meshbay-hub/src/meshbay_hub/static/platform.js b/packages/meshbay-hub/src/meshbay_hub/static/platform.js
index 0663a42..fcc866e 100644
--- a/packages/meshbay-hub/src/meshbay_hub/static/platform.js
+++ b/packages/meshbay-hub/src/meshbay_hub/static/platform.js
@@ -88,6 +88,40 @@ export const secrets = {
};
/**
+ * Call the hub.
+ *
+ * In a browser this is `fetch`, unchanged — the page came from the hub, so the
+ * request is same-origin and nothing is in the way.
+ *
+ * In the application the page's origin is `app://meshbay`, and a browser fetch
+ * from it is refused by CORS. The hub has **no CORS middleware at all**, and
+ * that is worth keeping: its API is reachable from no web origin whatever.
+ * Widening it for `app://meshbay` would be worse than it appears, because that
+ * origin is not a credential — any Electron application can claim the same
+ * scheme and host name.
+ *
+ * So the main process makes the call. It returns a small object rather than a
+ * Response, and this shapes it back into something with `.ok`, `.status` and
+ * `.json()`, so callers do not have to know which one they got.
+ */
+export async function apiFetch(url, init) {
+ if (!bridge || !bridge.fetch) return fetch(url, init);
+ const raw = await bridge.fetch(String(url), init && {
+ method: init.method,
+ headers: init.headers,
+ body: init.body,
+ });
+ return {
+ ok: raw.ok,
+ status: raw.status,
+ statusText: String(raw.status),
+ headers: new Headers(raw.headers || {}),
+ text: async () => raw.body,
+ json: async () => JSON.parse(raw.body),
+ };
+}
+
+/**
* Save a decrypted file to disk.
*
* Returns null when there is no native path, so the caller keeps today's
@@ -100,4 +134,13 @@ export async function nativeSave(suggestedName, size) {
return bridge.saveFile(suggestedName, size);
}
-export default { isNative, hubBase, capabilities, secrets, nativeSave };
+export default { isNative, hubBase, capabilities, secrets, nativeSave, apiFetch };
+
+// Also a global, because `transport.js` is loaded as a classic script — it
+// predates the module graph and exposes `MeshBayTransport` the same way. The
+// alternative was a second fetch path there, which is how two callers of one
+// hub end up disagreeing about how to reach it.
+if (typeof window !== 'undefined') {
+ window.MeshBayPlatform = { isNative, hubBase, capabilities, secrets,
+ nativeSave, apiFetch };
+}
diff --git a/packages/meshbay-hub/src/meshbay_hub/static/transport.js b/packages/meshbay-hub/src/meshbay_hub/static/transport.js
index 769114e..1a63e23 100644
--- a/packages/meshbay-hub/src/meshbay_hub/static/transport.js
+++ b/packages/meshbay-hub/src/meshbay_hub/static/transport.js
@@ -162,7 +162,13 @@ class MeshBayTransport {
};
});
- const resp = await fetch(`${this._hubUrl}/v1/nodes/${nodeId}/webrtc/offer`, {
+ // Signaling is a hub call like any other, so it goes the same way — in the
+ // application that means through the main process, because the renderer's
+ // app:// origin is refused by CORS.
+ const call = (window.MeshBayPlatform && window.MeshBayPlatform.apiFetch)
+ || fetch;
+ const resp = await call(
+ `${this._hubUrl}/v1/nodes/${nodeId}/webrtc/offer`, {
method: 'POST',
headers: {
'Content-Type': 'application/json',