octiqflow-linux-x64 0.1.52

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.
Files changed (143) hide show
  1. package/README.md +3 -0
  2. package/bin/octiq-server +0 -0
  3. package/bin/v2/apple-touch-icon.png +0 -0
  4. package/bin/v2/assets/clike-B9uivgTg.js +1 -0
  5. package/bin/v2/assets/diff-DbItnlRl.js +1 -0
  6. package/bin/v2/assets/dockerfile-ZL4hHokT.js +1 -0
  7. package/bin/v2/assets/go-CTD25R5P.js +1 -0
  8. package/bin/v2/assets/index-B3amz3YD.js +3 -0
  9. package/bin/v2/assets/index-B6nZyhSd.js +1 -0
  10. package/bin/v2/assets/index-BJPOH430.js +1 -0
  11. package/bin/v2/assets/index-BkI_sJNx.js +6 -0
  12. package/bin/v2/assets/index-C3qkbCLt.js +1 -0
  13. package/bin/v2/assets/index-CAT3p_Ey.js +1 -0
  14. package/bin/v2/assets/index-CkSsGSUZ.js +13 -0
  15. package/bin/v2/assets/index-CrP4aOLs.js +1 -0
  16. package/bin/v2/assets/index-Czi1vLYr.js +1 -0
  17. package/bin/v2/assets/index-DecdvRvX.js +1 -0
  18. package/bin/v2/assets/index-DpgjZUbN.css +1 -0
  19. package/bin/v2/assets/index-MhXUMNK1.js +291 -0
  20. package/bin/v2/assets/index-nLNkR2xP.js +2 -0
  21. package/bin/v2/assets/inter-cyrillic-ext-wght-normal-BOeWTOD4.woff2 +0 -0
  22. package/bin/v2/assets/inter-cyrillic-wght-normal-DqGufNeO.woff2 +0 -0
  23. package/bin/v2/assets/inter-greek-ext-wght-normal-DlzME5K_.woff2 +0 -0
  24. package/bin/v2/assets/inter-greek-wght-normal-CkhJZR-_.woff2 +0 -0
  25. package/bin/v2/assets/inter-latin-ext-wght-normal-DO1Apj_S.woff2 +0 -0
  26. package/bin/v2/assets/inter-latin-wght-normal-Dx4kXJAl.woff2 +0 -0
  27. package/bin/v2/assets/inter-vietnamese-wght-normal-CBcvBZtf.woff2 +0 -0
  28. package/bin/v2/assets/lua-VAEuO923.js +1 -0
  29. package/bin/v2/assets/lxgwwenkaiscreen-subset-100-DLPe7tEt.woff2 +0 -0
  30. package/bin/v2/assets/lxgwwenkaiscreen-subset-101-d3VsZKWT.woff2 +0 -0
  31. package/bin/v2/assets/lxgwwenkaiscreen-subset-102-ClzJuLq6.woff2 +0 -0
  32. package/bin/v2/assets/lxgwwenkaiscreen-subset-103-DuDnQ6K-.woff2 +0 -0
  33. package/bin/v2/assets/lxgwwenkaiscreen-subset-104-kPGW3Eem.woff2 +0 -0
  34. package/bin/v2/assets/lxgwwenkaiscreen-subset-105-BzD54h-0.woff2 +0 -0
  35. package/bin/v2/assets/lxgwwenkaiscreen-subset-106-BQ7fIzlx.woff2 +0 -0
  36. package/bin/v2/assets/lxgwwenkaiscreen-subset-107-D8tDfFHI.woff2 +0 -0
  37. package/bin/v2/assets/lxgwwenkaiscreen-subset-108-tGhkpwep.woff2 +0 -0
  38. package/bin/v2/assets/lxgwwenkaiscreen-subset-109-7SMVSrly.woff2 +0 -0
  39. package/bin/v2/assets/lxgwwenkaiscreen-subset-110-_uDKrFed.woff2 +0 -0
  40. package/bin/v2/assets/lxgwwenkaiscreen-subset-111-Bio825RE.woff2 +0 -0
  41. package/bin/v2/assets/lxgwwenkaiscreen-subset-112-D2ee0i-C.woff2 +0 -0
  42. package/bin/v2/assets/lxgwwenkaiscreen-subset-113-JPFVDrga.woff2 +0 -0
  43. package/bin/v2/assets/lxgwwenkaiscreen-subset-114-BcfxYA4w.woff2 +0 -0
  44. package/bin/v2/assets/lxgwwenkaiscreen-subset-115-B1HeeOsd.woff2 +0 -0
  45. package/bin/v2/assets/lxgwwenkaiscreen-subset-116-hY12tXpq.woff2 +0 -0
  46. package/bin/v2/assets/lxgwwenkaiscreen-subset-117-BvuZwmre.woff2 +0 -0
  47. package/bin/v2/assets/lxgwwenkaiscreen-subset-118-tzvs_H7j.woff2 +0 -0
  48. package/bin/v2/assets/lxgwwenkaiscreen-subset-119-J2DWuYDN.woff2 +0 -0
  49. package/bin/v2/assets/lxgwwenkaiscreen-subset-21-pDubCJV5.woff2 +0 -0
  50. package/bin/v2/assets/lxgwwenkaiscreen-subset-22-ChAPMpqp.woff2 +0 -0
  51. package/bin/v2/assets/lxgwwenkaiscreen-subset-23-BBx3oNpT.woff2 +0 -0
  52. package/bin/v2/assets/lxgwwenkaiscreen-subset-24-CYt-Oagk.woff2 +0 -0
  53. package/bin/v2/assets/lxgwwenkaiscreen-subset-25-Cx3j-ZUv.woff2 +0 -0
  54. package/bin/v2/assets/lxgwwenkaiscreen-subset-26-B9AfZ3LL.woff2 +0 -0
  55. package/bin/v2/assets/lxgwwenkaiscreen-subset-27-Bh2s9MNE.woff2 +0 -0
  56. package/bin/v2/assets/lxgwwenkaiscreen-subset-28-C02JPoKP.woff2 +0 -0
  57. package/bin/v2/assets/lxgwwenkaiscreen-subset-29-T_tbUGhk.woff2 +0 -0
  58. package/bin/v2/assets/lxgwwenkaiscreen-subset-30-DMfyNzhz.woff2 +0 -0
  59. package/bin/v2/assets/lxgwwenkaiscreen-subset-31-DFfdzbkg.woff2 +0 -0
  60. package/bin/v2/assets/lxgwwenkaiscreen-subset-32-Bs1fz2iW.woff2 +0 -0
  61. package/bin/v2/assets/lxgwwenkaiscreen-subset-33-cpB96OkZ.woff2 +0 -0
  62. package/bin/v2/assets/lxgwwenkaiscreen-subset-34-BhinPYWX.woff2 +0 -0
  63. package/bin/v2/assets/lxgwwenkaiscreen-subset-35-D_njRQqA.woff2 +0 -0
  64. package/bin/v2/assets/lxgwwenkaiscreen-subset-36-DqXlLE3t.woff2 +0 -0
  65. package/bin/v2/assets/lxgwwenkaiscreen-subset-37-j5LbvMph.woff2 +0 -0
  66. package/bin/v2/assets/lxgwwenkaiscreen-subset-38-oO4jWdKm.woff2 +0 -0
  67. package/bin/v2/assets/lxgwwenkaiscreen-subset-39-CabsX4rw.woff2 +0 -0
  68. package/bin/v2/assets/lxgwwenkaiscreen-subset-4-PatS3YHh.woff2 +0 -0
  69. package/bin/v2/assets/lxgwwenkaiscreen-subset-40-yrLg3C3e.woff2 +0 -0
  70. package/bin/v2/assets/lxgwwenkaiscreen-subset-41-DBXmCQhc.woff2 +0 -0
  71. package/bin/v2/assets/lxgwwenkaiscreen-subset-42-Bqij_UiQ.woff2 +0 -0
  72. package/bin/v2/assets/lxgwwenkaiscreen-subset-43-D3kp0Ntc.woff2 +0 -0
  73. package/bin/v2/assets/lxgwwenkaiscreen-subset-44-B_BNGvK4.woff2 +0 -0
  74. package/bin/v2/assets/lxgwwenkaiscreen-subset-45-CZc0cQWs.woff2 +0 -0
  75. package/bin/v2/assets/lxgwwenkaiscreen-subset-46-CHQX5Kd9.woff2 +0 -0
  76. package/bin/v2/assets/lxgwwenkaiscreen-subset-47-Ci8gLrHA.woff2 +0 -0
  77. package/bin/v2/assets/lxgwwenkaiscreen-subset-48-run3ugD3.woff2 +0 -0
  78. package/bin/v2/assets/lxgwwenkaiscreen-subset-49-DgfiUb6u.woff2 +0 -0
  79. package/bin/v2/assets/lxgwwenkaiscreen-subset-5-B0CtGbX_.woff2 +0 -0
  80. package/bin/v2/assets/lxgwwenkaiscreen-subset-50-CdCG-POr.woff2 +0 -0
  81. package/bin/v2/assets/lxgwwenkaiscreen-subset-51-L2okeQZ2.woff2 +0 -0
  82. package/bin/v2/assets/lxgwwenkaiscreen-subset-52-BZAqyGJW.woff2 +0 -0
  83. package/bin/v2/assets/lxgwwenkaiscreen-subset-53-B0xWqLeU.woff2 +0 -0
  84. package/bin/v2/assets/lxgwwenkaiscreen-subset-54-BZVQX-EA.woff2 +0 -0
  85. package/bin/v2/assets/lxgwwenkaiscreen-subset-55-093mkIUJ.woff2 +0 -0
  86. package/bin/v2/assets/lxgwwenkaiscreen-subset-56-CbhWG8G-.woff2 +0 -0
  87. package/bin/v2/assets/lxgwwenkaiscreen-subset-57-pLQuvo6c.woff2 +0 -0
  88. package/bin/v2/assets/lxgwwenkaiscreen-subset-58-BHhoY50x.woff2 +0 -0
  89. package/bin/v2/assets/lxgwwenkaiscreen-subset-59-D1_6DuIQ.woff2 +0 -0
  90. package/bin/v2/assets/lxgwwenkaiscreen-subset-6-BnAelmYU.woff2 +0 -0
  91. package/bin/v2/assets/lxgwwenkaiscreen-subset-60-HDBIuLTZ.woff2 +0 -0
  92. package/bin/v2/assets/lxgwwenkaiscreen-subset-61-C-c13SeU.woff2 +0 -0
  93. package/bin/v2/assets/lxgwwenkaiscreen-subset-62-kHRVOhZ2.woff2 +0 -0
  94. package/bin/v2/assets/lxgwwenkaiscreen-subset-63-C0MCsvFv.woff2 +0 -0
  95. package/bin/v2/assets/lxgwwenkaiscreen-subset-64-DZekguCj.woff2 +0 -0
  96. package/bin/v2/assets/lxgwwenkaiscreen-subset-65-CtP6c3IU.woff2 +0 -0
  97. package/bin/v2/assets/lxgwwenkaiscreen-subset-66-DLVWoMSf.woff2 +0 -0
  98. package/bin/v2/assets/lxgwwenkaiscreen-subset-67-BVuOnayH.woff2 +0 -0
  99. package/bin/v2/assets/lxgwwenkaiscreen-subset-68-DpxQ6Mnx.woff2 +0 -0
  100. package/bin/v2/assets/lxgwwenkaiscreen-subset-69-qesBxLmC.woff2 +0 -0
  101. package/bin/v2/assets/lxgwwenkaiscreen-subset-70-BBt1xN7h.woff2 +0 -0
  102. package/bin/v2/assets/lxgwwenkaiscreen-subset-71-BWqZacwB.woff2 +0 -0
  103. package/bin/v2/assets/lxgwwenkaiscreen-subset-72-B1wP_Yst.woff2 +0 -0
  104. package/bin/v2/assets/lxgwwenkaiscreen-subset-73-C99T7jNZ.woff2 +0 -0
  105. package/bin/v2/assets/lxgwwenkaiscreen-subset-74-DrUTsWBe.woff2 +0 -0
  106. package/bin/v2/assets/lxgwwenkaiscreen-subset-75-C4M5XXQe.woff2 +0 -0
  107. package/bin/v2/assets/lxgwwenkaiscreen-subset-76-Bq8spVWF.woff2 +0 -0
  108. package/bin/v2/assets/lxgwwenkaiscreen-subset-77-D9vNupE2.woff2 +0 -0
  109. package/bin/v2/assets/lxgwwenkaiscreen-subset-78-D6th7Gnu.woff2 +0 -0
  110. package/bin/v2/assets/lxgwwenkaiscreen-subset-79-bezM85cS.woff2 +0 -0
  111. package/bin/v2/assets/lxgwwenkaiscreen-subset-80-DD8pnhG2.woff2 +0 -0
  112. package/bin/v2/assets/lxgwwenkaiscreen-subset-81-N6jtSyBs.woff2 +0 -0
  113. package/bin/v2/assets/lxgwwenkaiscreen-subset-82-D6c180bZ.woff2 +0 -0
  114. package/bin/v2/assets/lxgwwenkaiscreen-subset-83-em17AadM.woff2 +0 -0
  115. package/bin/v2/assets/lxgwwenkaiscreen-subset-84-CJ8gdrMK.woff2 +0 -0
  116. package/bin/v2/assets/lxgwwenkaiscreen-subset-85-9PPGO1eB.woff2 +0 -0
  117. package/bin/v2/assets/lxgwwenkaiscreen-subset-86-CjWPf-u5.woff2 +0 -0
  118. package/bin/v2/assets/lxgwwenkaiscreen-subset-87-8D_X_yOC.woff2 +0 -0
  119. package/bin/v2/assets/lxgwwenkaiscreen-subset-88-9vtKFPBx.woff2 +0 -0
  120. package/bin/v2/assets/lxgwwenkaiscreen-subset-89-BhE5jAKX.woff2 +0 -0
  121. package/bin/v2/assets/lxgwwenkaiscreen-subset-90-D2Npfm5E.woff2 +0 -0
  122. package/bin/v2/assets/lxgwwenkaiscreen-subset-91-C6Ft1-Eu.woff2 +0 -0
  123. package/bin/v2/assets/lxgwwenkaiscreen-subset-97-CaExyQP9.woff2 +0 -0
  124. package/bin/v2/assets/lxgwwenkaiscreen-subset-98-CPoVbsUd.woff2 +0 -0
  125. package/bin/v2/assets/lxgwwenkaiscreen-subset-99-ZUQZGVgH.woff2 +0 -0
  126. package/bin/v2/assets/powershell-CFHJl5sT.js +1 -0
  127. package/bin/v2/assets/properties-C78fOPTZ.js +1 -0
  128. package/bin/v2/assets/ruby-B2Rjki9n.js +1 -0
  129. package/bin/v2/assets/shell-CjFT_Tl9.js +1 -0
  130. package/bin/v2/assets/swift-BzpIVaGY.js +1 -0
  131. package/bin/v2/assets/toml-Bm5Em-hy.js +1 -0
  132. package/bin/v2/assets/xml-BQQZnNBQ.js +1 -0
  133. package/bin/v2/favicon.ico +0 -0
  134. package/bin/v2/fonts/lxgw-wenkai-screen/LICENSE +21 -0
  135. package/bin/v2/fonts/lxgw-wenkai-screen/OFL.txt +91 -0
  136. package/bin/v2/fonts/lxgw-wenkai-screen/README.md +11 -0
  137. package/bin/v2/icon-192.png +0 -0
  138. package/bin/v2/icon-32.png +0 -0
  139. package/bin/v2/icon-512.png +0 -0
  140. package/bin/v2/index.html +54 -0
  141. package/bin/v2/manifest.webmanifest +15 -0
  142. package/bin/v2/sw.js +189 -0
  143. package/package.json +23 -0
@@ -0,0 +1,11 @@
1
+ # LXGW WenKai Screen
2
+
3
+ OctiqFlow bundles the Screen face from `lxgw-wenkai-screen-webfont@1.7.0`
4
+ (upstream font version v1.250.2), using its WOFF2 Unicode subsets for on-demand loading.
5
+
6
+ - Font project: https://github.com/lxgw/LxgwWenKai-Screen
7
+ - Webfont package: https://github.com/chawyehsu/lxgw-wenkai-webfont
8
+ - Font license: SIL Open Font License 1.1, reproduced in `OFL.txt`.
9
+ - Webfont packaging license: MIT, reproduced in `LICENSE`.
10
+
11
+ Only `lxgwwenkaiscreen.css` is imported; the package's other faces are not bundled.
Binary file
Binary file
Binary file
@@ -0,0 +1,54 @@
1
+ <!doctype html>
2
+ <html lang="en">
3
+ <head>
4
+ <meta charset="UTF-8" />
5
+ <meta
6
+ name="viewport"
7
+ content="width=device-width, initial-scale=1.0, viewport-fit=cover"
8
+ />
9
+ <meta name="theme-color" content="#1c1c1e" />
10
+
11
+ <!-- Relative hrefs, like the asset URLs: `base: "./"` in vite.config.ts
12
+ keeps the bundle working wherever it is mounted, and these follow the
13
+ same rule so nothing depends on the page sitting at the root. -->
14
+ <link rel="icon" href="./favicon.ico" sizes="any" />
15
+ <link rel="icon" type="image/png" href="./icon-32.png" sizes="32x32" />
16
+
17
+ <!-- Reached from a phone through a tunnel, so it is meant to be added to a
18
+ home screen. A tab cannot be told to shrink its own toolbar, so the
19
+ home screen is the only way the address bar comes off the screen.
20
+
21
+ `standalone` is chromeless: no address bar, and no navigation controls
22
+ either. `minimal-ui` is the mode that keeps native back/reload, and it
23
+ was tried here — iOS did not give the controls, so the reload lives in
24
+ our own top bar instead (`InstalledReload`). Do not reach for
25
+ `minimal-ui` again without testing it on a real phone; and note that
26
+ iOS caches the manifest at INSTALL time, so testing it means deleting
27
+ the home-screen icon and adding it again, not reloading.
28
+
29
+ The status-bar-style is not part of that choice and must not be
30
+ removed with it: it is what puts the page UNDER the status bar. The
31
+ top bar is sized `48px + env(safe-area-inset-top)` (styles.css), so
32
+ dropping it moves the inset out from under the layout and the bar
33
+ comes out wrong.
34
+
35
+ iOS reads none of the manifest for the ICON: it wants its own, and it
36
+ composites transparency onto black, so this one is already flattened
37
+ onto the app's own background. -->
38
+ <link rel="apple-touch-icon" href="./apple-touch-icon.png" />
39
+ <meta name="apple-mobile-web-app-capable" content="yes" />
40
+ <!-- The same thing, un-prefixed. Chrome/Android warns on the Apple name
41
+ alone, and reads this one. -->
42
+ <meta name="mobile-web-app-capable" content="yes" />
43
+ <meta name="apple-mobile-web-app-title" content="OctiqFlow" />
44
+ <meta name="apple-mobile-web-app-status-bar-style" content="black-translucent" />
45
+ <link rel="manifest" href="./manifest.webmanifest" />
46
+
47
+ <title>OctiqFlow</title>
48
+ <script type="module" crossorigin src="./assets/index-MhXUMNK1.js"></script>
49
+ <link rel="stylesheet" crossorigin href="./assets/index-DpgjZUbN.css">
50
+ </head>
51
+ <body>
52
+ <div id="root"></div>
53
+ </body>
54
+ </html>
@@ -0,0 +1,15 @@
1
+ {
2
+ "name": "OctiqFlow",
3
+ "short_name": "OctiqFlow",
4
+ "description": "Drive Claude Code and Codex from anywhere.",
5
+ "start_url": "./",
6
+ "scope": "./",
7
+ "display": "standalone",
8
+ "background_color": "#1c1c1e",
9
+ "theme_color": "#1c1c1e",
10
+ "icons": [
11
+ { "src": "./icon-192.png", "sizes": "192x192", "type": "image/png" },
12
+ { "src": "./icon-512.png", "sizes": "512x512", "type": "image/png" },
13
+ { "src": "./icon-512.png", "sizes": "512x512", "type": "image/png", "purpose": "maskable" }
14
+ ]
15
+ }
package/bin/v2/sw.js ADDED
@@ -0,0 +1,189 @@
1
+ // The part of OctiqFlow that runs when OctiqFlow does not.
2
+ //
3
+ // A service worker outlives the page. The phone's OS wakes it on a push with
4
+ // nothing of ours open — no tab, no home-screen app, a locked screen — draws
5
+ // the banner, and lets it go again. That is the whole reason this file exists,
6
+ // and it is why the notification path moved to the server: `lib/notify.ts` can
7
+ // only raise a banner while the page is running, which on a phone is almost
8
+ // never.
9
+ //
10
+ // Deliberately not a cache. Every offline-first instinct is wrong here: the app
11
+ // is a window onto a machine at the end of a tunnel, and a cached shell that
12
+ // loads while the backend is unreachable is worse than a page that fails
13
+ // honestly. `fetch` is not handled at all, so the network is always the answer.
14
+
15
+ /** Where the reader is, as the last open page described it.
16
+ *
17
+ * The rule "say nothing about the chat you are already looking at" needs to
18
+ * know which chat that is, and only the page knows. It tells us on every
19
+ * change; we keep the latest.
20
+ *
21
+ * This is memory, and a service worker is killed and restarted freely — so it
22
+ * is routinely empty even though a page is open. That is why an empty value
23
+ * means SHOW: a banner you did not need is a smaller failure than a permission
24
+ * ask you never saw. */
25
+ let reading = null;
26
+
27
+ self.addEventListener("message", (event) => {
28
+ const data = event.data;
29
+ if (data && data.type === "reading") {
30
+ reading = data.conversationId ?? null;
31
+ }
32
+ });
33
+
34
+ self.addEventListener("install", () => {
35
+ // Take over on the first load rather than waiting for every old page to go.
36
+ // There is no old version to be careful of — nothing is cached.
37
+ self.skipWaiting();
38
+ });
39
+
40
+ self.addEventListener("activate", (event) => {
41
+ event.waitUntil(self.clients.claim());
42
+ });
43
+
44
+ /** Is a window open, focused, AND showing this chat? */
45
+ async function watching(conversationId) {
46
+ const windows = await self.clients.matchAll({
47
+ type: "window",
48
+ includeUncontrolled: true,
49
+ });
50
+ const focused = windows.some((c) => c.focused && c.visibilityState === "visible");
51
+ // Reading a DIFFERENT chat in a focused window still counts as away: the news
52
+ // is not in front of you either way. This mirrors `isWatching` in
53
+ // lib/notify.ts, which is the same rule for the other route.
54
+ return focused && reading !== null && reading === conversationId;
55
+ }
56
+
57
+ self.addEventListener("push", (event) => {
58
+ event.waitUntil(
59
+ (async () => {
60
+ let notice = null;
61
+ try {
62
+ notice = event.data ? event.data.json() : null;
63
+ } catch {
64
+ // A push whose body we cannot read still means somebody wants you.
65
+ }
66
+
67
+ const title = (notice && notice.title) || "OctiqFlow";
68
+ const body = (notice && notice.body) || "Something needs you.";
69
+ const id = notice && notice.conversationId;
70
+
71
+ // iOS revokes the permission of an app that takes pushes and shows
72
+ // nothing, so the one case we stay silent for is the one that is
73
+ // genuinely redundant: the chat is on screen in front of you.
74
+ if (id && (await watching(id))) return;
75
+
76
+ await self.registration.showNotification(title, {
77
+ body,
78
+ // One live banner per chat per kind — a later one takes the earlier
79
+ // one's place instead of stacking under it.
80
+ tag: (notice && notice.tag) || "octiq",
81
+ icon: "./icon-192.png",
82
+ badge: "./icon-192.png",
83
+ data: {
84
+ conversationId: id ?? null,
85
+ projectId: (notice && notice.projectId) || null,
86
+ },
87
+ // Work that is BLOCKED on you should sit there until it is seen; a
88
+ // turn that merely ended can go away by itself. Honoured on desktop
89
+ // Chrome, ignored elsewhere, harmless either way.
90
+ requireInteraction: !!notice && notice.kind !== "done",
91
+ });
92
+ })(),
93
+ );
94
+ });
95
+
96
+ /** Where a tap is written down for the app to find on its way in.
97
+ *
98
+ * `postMessage` only reaches a page that is RUNNING, and on a phone it usually
99
+ * is not: a home-screen app is suspended within seconds of going behind
100
+ * something, and killed outright soon after. So the chat that was asked for
101
+ * goes somewhere that outlives both the worker and the page, and whatever
102
+ * finally brings the app up reads it there — `openWindow`, the OS, or the
103
+ * person giving up on the banner and tapping the icon themselves.
104
+ *
105
+ * Cache Storage because it is the one store both halves can reach from here.
106
+ * This is a mailbox, not the cache the top of the file swears off: one entry,
107
+ * written by the worker, taken by the page, and nothing ever fetches it. */
108
+ const TAPS = "octiq-tap";
109
+ const TAPPED = "./__octiq_tapped__";
110
+
111
+ async function rememberTap(conversationId, projectId) {
112
+ if (!conversationId || !self.caches) return;
113
+ try {
114
+ const cache = await self.caches.open(TAPS);
115
+ await cache.put(
116
+ new Request(TAPPED),
117
+ new Response(
118
+ JSON.stringify({
119
+ conversationId,
120
+ projectId: projectId ?? null,
121
+ at: Date.now(),
122
+ }),
123
+ ),
124
+ );
125
+ } catch {
126
+ /* no store to write to; the message and the URL are the other two ways in */
127
+ }
128
+ }
129
+
130
+ // Tapping the banner. Bring back the window that is already open rather than
131
+ // adding a second one — on a phone a duplicate tab is how you end up with two
132
+ // copies of a chat and no idea which is live.
133
+ self.addEventListener("notificationclick", (event) => {
134
+ event.notification.close();
135
+ const data = event.notification.data || {};
136
+ const id = data.conversationId;
137
+ const project = data.projectId;
138
+ // The address, for the case where the app has to be started. It reads
139
+ // `#/p/<project>/c/<chat>`, which is why the notice carries the project as
140
+ // well as the chat; without both halves it launches and lands wherever it
141
+ // left off, which is the one thing a tapped banner must not do. The token is
142
+ // already in the page's own storage, so our own scope is enough to get back
143
+ // in.
144
+ const to =
145
+ id && project
146
+ ? `./#/p/${encodeURIComponent(project)}/c/${encodeURIComponent(id)}`
147
+ : "./";
148
+
149
+ event.waitUntil(
150
+ (async () => {
151
+ // Written down BEFORE anything is raised, because raising it is the part
152
+ // that fails.
153
+ await rememberTap(id, project);
154
+
155
+ const windows = await self.clients.matchAll({
156
+ type: "window",
157
+ includeUncontrolled: true,
158
+ });
159
+ for (const client of windows) {
160
+ // A page that is already running owns the conversation list and the
161
+ // routing, so it only needs the chat id. Sent whether or not the window
162
+ // can be brought forward: one that lands on a window the OS raised by
163
+ // itself is worth more than a tap that said nothing at all.
164
+ if (id) client.postMessage({ type: "open-chat", conversationId: id });
165
+ let raised = null;
166
+ try {
167
+ raised = await client.focus();
168
+ } catch {
169
+ /* refused — `openWindow` below is the other way to raise it */
170
+ }
171
+ if (raised && raised.focused) return;
172
+ }
173
+ // Either nothing was open, or nothing could be RAISED — and on iOS the
174
+ // second is the usual answer, which is what two earlier attempts at this
175
+ // missed. `matchAll` lists a home-screen app that is merely suspended,
176
+ // `focus()` cannot bring one of those back, and stopping at the refusal
177
+ // left the tap doing nothing whatsoever. `openWindow` is the call that
178
+ // launches it, so a window we could not raise has to fall through to
179
+ // here rather than count as handled.
180
+ if (self.clients.openWindow) {
181
+ try {
182
+ await self.clients.openWindow(to);
183
+ } catch {
184
+ /* not allowed to open one either; the note above is what is left */
185
+ }
186
+ }
187
+ })(),
188
+ );
189
+ });
package/package.json ADDED
@@ -0,0 +1,23 @@
1
+ {
2
+ "name": "octiqflow-linux-x64",
3
+ "version": "0.1.52",
4
+ "description": "Native OctiqFlow runtime for linux x64",
5
+ "os": [
6
+ "linux"
7
+ ],
8
+ "cpu": [
9
+ "x64"
10
+ ],
11
+ "files": [
12
+ "bin"
13
+ ],
14
+ "repository": {
15
+ "type": "git",
16
+ "url": "git+https://github.com/kyson8101/octiq-flow.git"
17
+ },
18
+ "homepage": "https://github.com/kyson8101/octiq-flow#readme",
19
+ "license": "UNLICENSED",
20
+ "publishConfig": {
21
+ "access": "public"
22
+ }
23
+ }