@hydra-acp/browser 0.1.25 → 0.1.27

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/dist/ui/sw.js ADDED
@@ -0,0 +1,71 @@
1
+ // Service worker. Two jobs: exist so registration.showNotification() is
2
+ // available (Safari, desktop and iOS, requires notifications go through
3
+ // a service worker rather than the plain `new Notification()`
4
+ // constructor), and handle real Web Push deliveries so a turn-end
5
+ // notification can reach the user even when the app isn't running at
6
+ // all (see notifications.ts's subscribeForPush and the server-side
7
+ // turn-notify-callback.ts). No offline caching — the fetch handler
8
+ // below is a pure passthrough, kept only because Chrome's install
9
+ // prompt won't show without one. Kept as plain JS, not bundled with the
10
+ // rest of the app — it must be servable at its own URL for registration
11
+ // to work.
12
+ self.addEventListener("install", () => {
13
+ self.skipWaiting();
14
+ });
15
+
16
+ self.addEventListener("activate", (event) => {
17
+ event.waitUntil(self.clients.claim());
18
+ });
19
+
20
+ // A no-op passthrough. Chrome's install-eligibility check wants a
21
+ // fetch handler present, even though this worker does no offline
22
+ // caching; without one, the install prompt doesn't show.
23
+ self.addEventListener("fetch", (event) => {
24
+ event.respondWith(fetch(event.request));
25
+ });
26
+
27
+ // Payload shape is whatever turn-notify-callback.ts's sendPushToAll
28
+ // sends: { title, body, url, tag }. No push subscription rides through
29
+ // here without going through that server-side path first, so the
30
+ // shape is trusted rather than re-validated field by field.
31
+ self.addEventListener("push", (event) => {
32
+ let data = {};
33
+ try {
34
+ data = event.data ? event.data.json() : {};
35
+ } catch {
36
+ // Non-JSON payload; fall through to the defaults below.
37
+ }
38
+ event.waitUntil(
39
+ self.registration.showNotification(data.title || "Hydra", {
40
+ body: data.body || "Turn finished.",
41
+ tag: data.tag,
42
+ data: { url: data.url || "/" },
43
+ }),
44
+ );
45
+ });
46
+
47
+ // A notification is owned by the worker, not the page that created it,
48
+ // so bringing the tab to front on click has to happen here rather than
49
+ // via a plain onclick back in page script.
50
+ self.addEventListener("notificationclick", (event) => {
51
+ event.notification.close();
52
+ const url = (event.notification.data && event.notification.data.url) || "/";
53
+ event.waitUntil(
54
+ self.clients
55
+ .matchAll({ type: "window", includeUncontrolled: true })
56
+ .then((clients) => {
57
+ for (const client of clients) {
58
+ if ("focus" in client) {
59
+ if ("navigate" in client) {
60
+ client.navigate(url).catch(() => {});
61
+ }
62
+ return client.focus();
63
+ }
64
+ }
65
+ if (self.clients.openWindow) {
66
+ return self.clients.openWindow(url);
67
+ }
68
+ return undefined;
69
+ }),
70
+ );
71
+ });
@@ -17,6 +17,9 @@ export const paths = {
17
17
  linkFile() {
18
18
  return `${HOME_DIR}/link`;
19
19
  },
20
+ pushFile() {
21
+ return `${HOME_DIR}/push.json`;
22
+ },
20
23
  configFile() {
21
24
  if (existsSync(PRIMARY_CONF)) {
22
25
  return PRIMARY_CONF;
@@ -1 +1 @@
1
- {"version":3,"file":"paths.js","sourceRoot":"","sources":["../../src/util/paths.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,UAAU,EAAE,MAAM,SAAS,CAAC;AACrC,OAAO,EAAE,OAAO,EAAE,MAAM,SAAS,CAAC;AAClC,OAAO,EAAE,OAAO,EAAE,MAAM,WAAW,CAAC;AAEpC,MAAM,QAAQ,GAAG,OAAO,CAAC,OAAO,EAAE,EAAE,YAAY,EAAE,SAAS,CAAC,CAAC;AAC7D,MAAM,YAAY,GAAG,OAAO,CAAC,OAAO,EAAE,EAAE,YAAY,EAAE,cAAc,CAAC,CAAC;AACtE,MAAM,WAAW,GAAG,OAAO,CAAC,OAAO,EAAE,EAAE,yBAAyB,CAAC,CAAC;AAElE,MAAM,UAAU,UAAU,CAAC,CAAS;IAClC,IAAI,CAAC,CAAC,UAAU,CAAC,IAAI,CAAC,EAAE,CAAC;QACvB,OAAO,OAAO,CAAC,OAAO,EAAE,EAAE,CAAC,CAAC,KAAK,CAAC,CAAC,CAAC,CAAC,CAAC;IACxC,CAAC;IACD,OAAO,CAAC,CAAC;AACX,CAAC;AAED,MAAM,CAAC,MAAM,KAAK,GAAG;IACnB,IAAI;QACF,OAAO,QAAQ,CAAC;IAClB,CAAC;IACD,QAAQ;QACN,OAAO,GAAG,QAAQ,OAAO,CAAC;IAC5B,CAAC;IACD,UAAU;QACR,IAAI,UAAU,CAAC,YAAY,CAAC,EAAE,CAAC;YAC7B,OAAO,YAAY,CAAC;QACtB,CAAC;QACD,IAAI,UAAU,CAAC,WAAW,CAAC,EAAE,CAAC;YAC5B,OAAO,WAAW,CAAC;QACrB,CAAC;QACD,OAAO,YAAY,CAAC;IACtB,CAAC;CACF,CAAC"}
1
+ {"version":3,"file":"paths.js","sourceRoot":"","sources":["../../src/util/paths.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,UAAU,EAAE,MAAM,SAAS,CAAC;AACrC,OAAO,EAAE,OAAO,EAAE,MAAM,SAAS,CAAC;AAClC,OAAO,EAAE,OAAO,EAAE,MAAM,WAAW,CAAC;AAEpC,MAAM,QAAQ,GAAG,OAAO,CAAC,OAAO,EAAE,EAAE,YAAY,EAAE,SAAS,CAAC,CAAC;AAC7D,MAAM,YAAY,GAAG,OAAO,CAAC,OAAO,EAAE,EAAE,YAAY,EAAE,cAAc,CAAC,CAAC;AACtE,MAAM,WAAW,GAAG,OAAO,CAAC,OAAO,EAAE,EAAE,yBAAyB,CAAC,CAAC;AAElE,MAAM,UAAU,UAAU,CAAC,CAAS;IAClC,IAAI,CAAC,CAAC,UAAU,CAAC,IAAI,CAAC,EAAE,CAAC;QACvB,OAAO,OAAO,CAAC,OAAO,EAAE,EAAE,CAAC,CAAC,KAAK,CAAC,CAAC,CAAC,CAAC,CAAC;IACxC,CAAC;IACD,OAAO,CAAC,CAAC;AACX,CAAC;AAED,MAAM,CAAC,MAAM,KAAK,GAAG;IACnB,IAAI;QACF,OAAO,QAAQ,CAAC;IAClB,CAAC;IACD,QAAQ;QACN,OAAO,GAAG,QAAQ,OAAO,CAAC;IAC5B,CAAC;IACD,QAAQ;QACN,OAAO,GAAG,QAAQ,YAAY,CAAC;IACjC,CAAC;IACD,UAAU;QACR,IAAI,UAAU,CAAC,YAAY,CAAC,EAAE,CAAC;YAC7B,OAAO,YAAY,CAAC;QACtB,CAAC;QACD,IAAI,UAAU,CAAC,WAAW,CAAC,EAAE,CAAC;YAC5B,OAAO,WAAW,CAAC;QACrB,CAAC;QACD,OAAO,YAAY,CAAC;IACtB,CAAC;CACF,CAAC"}
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@hydra-acp/browser",
3
- "version": "0.1.25",
3
+ "version": "0.1.27",
4
4
  "description": "Browser-based UI for hydra-acp sessions.",
5
5
  "license": "MIT",
6
6
  "type": "module",
@@ -52,10 +52,12 @@
52
52
  "@fastify/cookie": "^11.0.2",
53
53
  "fastify": "^5.0.0",
54
54
  "highlight.js": "^11.11.1",
55
+ "web-push": "^3.6.7",
55
56
  "ws": "^8.20.0"
56
57
  },
57
58
  "devDependencies": {
58
59
  "@types/node": "^22.10.0",
60
+ "@types/web-push": "^3.6.4",
59
61
  "@types/ws": "^8.18.1",
60
62
  "esbuild": "^0.28.0",
61
63
  "tsx": "^4.20.0",