@sandprivacy/sandgate 0.1.5 → 0.1.6

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.
@@ -38,8 +38,14 @@ export function pwaManifest(opts) {
38
38
  export const PWA_SW = `
39
39
  self.addEventListener("install", function () { self.skipWaiting(); });
40
40
  self.addEventListener("activate", function (e) { e.waitUntil(self.clients.claim()); });
41
- // A fetch handler is required for Chrome's install prompt; plain passthrough.
42
- self.addEventListener("fetch", function (e) { e.respondWith(fetch(e.request)); });
41
+ // A fetch handler is required for Chrome's install prompt. Handle ONLY
42
+ // same-origin GETs: on iOS 16.4+, respondWith(fetch(request)) on POSTs
43
+ // (bodies) throws Internal error and silently kills subscribe/decision
44
+ // calls — anything we return from lets the browser handle natively.
45
+ self.addEventListener("fetch", function (e) {
46
+ if (e.request.method !== "GET") return;
47
+ e.respondWith(fetch(e.request));
48
+ });
43
49
  self.addEventListener("push", function (e) {
44
50
  e.waitUntil((async function () {
45
51
  await self.registration.showNotification("sandgate", {
@@ -193,7 +199,8 @@ export const PWA_HTML = `<!doctype html>
193
199
  .setup input {
194
200
  width: 100%; padding: 12px 14px; margin: 14px 0 10px;
195
201
  background: var(--panel); border: 1px solid var(--line); border-radius: 10px;
196
- color: var(--ink); font: 14px ui-monospace, monospace;
202
+ /* 16px minimum: below that, iOS Safari auto-zooms into focused inputs. */
203
+ color: var(--ink); font: 16px ui-monospace, monospace;
197
204
  }
198
205
  .setup input:focus { outline: 2px solid var(--accent); outline-offset: -1px; }
199
206
 
@@ -442,11 +449,20 @@ export const PWA_HTML = `<!doctype html>
442
449
  return true;
443
450
  }
444
451
 
452
+ function showPushError(err) {
453
+ setStatus("push error", "err");
454
+ alert(
455
+ "Notifications could not be enabled: " +
456
+ (err && err.message ? err.name + " — " + err.message : err) +
457
+ "\\n\\nOn iPhone this requires iOS 16.4+, the app installed on the home screen, and Lockdown Mode off."
458
+ );
459
+ }
460
+
445
461
  function offerPush() {
446
462
  if (!("Notification" in window) || !("PushManager" in window)) return;
447
463
  if (isIOS && !standalone) return; // impossible in Safari tabs; banner handles install
448
464
  if (Notification.permission === "granted") {
449
- enablePush().catch(function () {});
465
+ enablePush().catch(showPushError);
450
466
  return;
451
467
  }
452
468
  if (Notification.permission === "denied") return;
@@ -457,7 +473,7 @@ export const PWA_HTML = `<!doctype html>
457
473
  '<button class="act" id="pushBtn">Enable notifications</button>';
458
474
  bannerEl.appendChild(b);
459
475
  document.getElementById("pushBtn").addEventListener("click", function () {
460
- enablePush().catch(function () {});
476
+ enablePush().catch(showPushError);
461
477
  });
462
478
  }
463
479
  offerPush();
@@ -624,22 +640,28 @@ export const PWA_HTML = `<!doctype html>
624
640
  var c = cards[id];
625
641
  if (!c || c.done) return;
626
642
  b.disabled = true;
627
- var payload = await sealPayload(
628
- c.pair,
629
- { requestId: c.requestId, approved: cls === "ok", ts: Date.now() },
630
- "dec:" + c.requestId
631
- );
632
- await fetch("/api/decision", {
633
- method: "POST",
634
- headers: { "Content-Type": "application/json" },
635
- body: JSON.stringify({ pairId: c.pair.pairId, requestId: c.requestId, payload: payload }),
636
- });
637
- if (cards[id]) {
638
- recordHist(histLabel(c), cls === "ok" ? "approved" : "denied");
639
- cards[id].el.remove();
640
- delete cards[id];
643
+ try {
644
+ var payload = await sealPayload(
645
+ c.pair,
646
+ { requestId: c.requestId, approved: cls === "ok", ts: Date.now() },
647
+ "dec:" + c.requestId
648
+ );
649
+ var res = await fetch("/api/decision", {
650
+ method: "POST",
651
+ headers: { "Content-Type": "application/json" },
652
+ body: JSON.stringify({ pairId: c.pair.pairId, requestId: c.requestId, payload: payload }),
653
+ });
654
+ if (!res.ok) throw new Error("relay answered HTTP " + res.status);
655
+ if (cards[id]) {
656
+ recordHist(histLabel(c), cls === "ok" ? "approved" : "denied");
657
+ cards[id].el.remove();
658
+ delete cards[id];
659
+ }
660
+ ensureEmpty(Object.keys(cards).length === 0);
661
+ } catch (err) {
662
+ b.disabled = false;
663
+ alert("Could not send your decision: " + (err && err.message ? err.message : err));
641
664
  }
642
- ensureEmpty(Object.keys(cards).length === 0);
643
665
  };
644
666
  return b;
645
667
  }
@@ -681,7 +703,7 @@ export const PWA_HTML = `<!doctype html>
681
703
  input.id = "addPaste";
682
704
  input.placeholder = "Paste a pairing link (sandgate pair)";
683
705
  input.autocomplete = "off";
684
- input.style.cssText = "width:100%;padding:10px 12px;margin-top:8px;background:var(--panel);border:1px solid var(--line);border-radius:8px;color:var(--ink);font:13px ui-monospace,monospace;";
706
+ input.style.cssText = "width:100%;padding:10px 12px;margin-top:8px;background:var(--panel);border:1px solid var(--line);border-radius:8px;color:var(--ink);font:16px ui-monospace,monospace;box-sizing:border-box;";
685
707
  input.addEventListener("input", function (e) {
686
708
  var parsed = parsePairing(e.target.value);
687
709
  if (parsed && addPairing(parsed)) location.reload();
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@sandprivacy/sandgate",
3
- "version": "0.1.5",
3
+ "version": "0.1.6",
4
4
  "description": "The human gateway for AI agents — approvals, 2FA codes and email verification, self-hosted. Your agent asks; you decide; secrets never touch the LLM.",
5
5
  "license": "AGPL-3.0-only",
6
6
  "type": "module",