botschat 0.1.16 → 0.1.17

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 (37) hide show
  1. package/package.json +4 -1
  2. package/packages/api/src/index.ts +10 -2
  3. package/packages/plugin/dist/src/ws-client.d.ts.map +1 -1
  4. package/packages/plugin/dist/src/ws-client.js +11 -6
  5. package/packages/plugin/dist/src/ws-client.js.map +1 -1
  6. package/packages/plugin/package.json +1 -1
  7. package/packages/web/dist/assets/{index-CLKSdbmx.css → index-B5GU1yVt.css} +1 -1
  8. package/packages/web/dist/assets/index-CO9YgLst.js +2 -0
  9. package/packages/web/dist/assets/index-ClDrCe_c.js +1 -0
  10. package/packages/web/dist/assets/{index--A7c71kf.js → index-D3T7sc-R.js} +1 -1
  11. package/packages/web/dist/assets/index-DPEosppm.js +2 -0
  12. package/packages/web/dist/assets/{index-Cd5GHqU6.js → index-DzYqprDN.js} +1 -1
  13. package/packages/web/dist/assets/index-IVUdSd9w.js +1516 -0
  14. package/packages/web/dist/assets/{index.esm-Dc_1yrX1.js → index.esm-COzWPkKi.js} +1 -1
  15. package/packages/web/dist/assets/{web-CDcVasbM.js → web-CxXbaApe.js} +1 -1
  16. package/packages/web/dist/assets/{web-D_QoLpUi.js → web-DFQypSd0.js} +1 -1
  17. package/packages/web/dist/index.html +2 -2
  18. package/packages/web/dist/sw.js +9 -1
  19. package/packages/web/src/App.tsx +10 -1
  20. package/packages/web/src/api.ts +5 -3
  21. package/packages/web/src/components/ChatWindow.tsx +5 -1
  22. package/packages/web/src/components/CronSidebar.tsx +5 -1
  23. package/packages/web/src/components/LoginPage.tsx +3 -1
  24. package/packages/web/src/components/OnboardingPage.tsx +3 -1
  25. package/packages/web/src/components/SessionTabs.tsx +5 -1
  26. package/packages/web/src/components/Sidebar.tsx +8 -2
  27. package/packages/web/src/components/TaskBar.tsx +5 -1
  28. package/packages/web/src/components/ThreadPanel.tsx +5 -1
  29. package/packages/web/src/firebase.ts +3 -2
  30. package/packages/web/src/hooks/useIMEComposition.ts +36 -0
  31. package/packages/web/src/main.tsx +3 -2
  32. package/packages/web/src/push.ts +88 -1
  33. package/packages/web/src/ws.ts +4 -3
  34. package/packages/web/dist/assets/index-CEStVU9o.js +0 -1516
  35. package/packages/web/dist/assets/index-D3Vfl8Ll.js +0 -2
  36. package/packages/web/dist/assets/index-DUpmW4Ay.js +0 -2
  37. package/packages/web/dist/assets/index-DfBArjKG.js +0 -1
@@ -96,11 +96,96 @@ export async function clearE2eKeyFromSW(): Promise<void> {
96
96
  }
97
97
  }
98
98
 
99
+ // ---- macOS native notification bridge ----
100
+
101
+ declare global {
102
+ interface Window {
103
+ __BOTSCHAT_NATIVE__?: boolean;
104
+ __BOTSCHAT_PLATFORM__?: string;
105
+ __BOTSCHAT_NATIVE_NOTIFY__?: (payload: {
106
+ title: string;
107
+ body: string;
108
+ sessionKey?: string;
109
+ }) => void;
110
+ __BOTSCHAT_NATIVE_REQUEST_PERMISSION__?: () => void;
111
+ }
112
+ }
113
+
114
+ function isMacOSNative(): boolean {
115
+ return !!(window.__BOTSCHAT_NATIVE__ && window.__BOTSCHAT_PLATFORM__ === "macos");
116
+ }
117
+
118
+ async function initMacOSPush(): Promise<void> {
119
+ try {
120
+ window.__BOTSCHAT_NATIVE_REQUEST_PERMISSION__?.();
121
+ dlog.info("Push", "macOS native notification permission requested");
122
+ } catch (err) {
123
+ dlog.error("Push", "macOS notification init failed", err);
124
+ }
125
+ }
126
+
127
+ /**
128
+ * Show a native macOS notification when a message arrives via WS and
129
+ * the window is not focused. Call this from the WS message handler.
130
+ */
131
+ export function notifyIfBackground(msg: {
132
+ type: string;
133
+ text?: string;
134
+ caption?: string;
135
+ sessionKey?: string;
136
+ agentName?: string;
137
+ }): void {
138
+ if (!isMacOSNative()) return;
139
+ if (!document.hidden && document.hasFocus()) return;
140
+ if (!window.__BOTSCHAT_NATIVE_NOTIFY__) return;
141
+
142
+ let body = "";
143
+ const title = msg.agentName || "BotsChat";
144
+
145
+ if (msg.type === "agent.text" && msg.text) {
146
+ body = msg.text.length > 200 ? msg.text.slice(0, 200) + "…" : msg.text;
147
+ } else if (msg.type === "agent.media") {
148
+ body = msg.caption || "Sent a media file";
149
+ } else {
150
+ return;
151
+ }
152
+
153
+ window.__BOTSCHAT_NATIVE_NOTIFY__({ title, body, sessionKey: msg.sessionKey });
154
+ }
155
+
156
+ // ---- Service Worker message listener (notification click → navigation) ----
157
+
158
+ function setupSWMessageListener(): void {
159
+ if (!("serviceWorker" in navigator)) return;
160
+ navigator.serviceWorker.addEventListener("message", (event) => {
161
+ if (event.data?.type === "push-nav" && event.data.sessionKey) {
162
+ dlog.info("Push", `SW postMessage push-nav: ${event.data.sessionKey}`);
163
+ firePushNav(event.data.sessionKey);
164
+ }
165
+ });
166
+
167
+ // Also check URL for push_session param (when SW opens a new window)
168
+ const params = new URLSearchParams(window.location.search);
169
+ const pushSession = params.get("push_session");
170
+ if (pushSession) {
171
+ dlog.info("Push", `URL push_session param: ${pushSession}`);
172
+ firePushNav(pushSession);
173
+ // Clean up the URL parameter
174
+ params.delete("push_session");
175
+ const clean = params.toString();
176
+ const newUrl = window.location.pathname + (clean ? "?" + clean : "") + window.location.hash;
177
+ window.history.replaceState({}, "", newUrl);
178
+ }
179
+ }
180
+
99
181
  // ---- Push initialization ----
100
182
 
101
183
  export async function initPushNotifications(): Promise<void> {
102
184
  if (initialized) return;
103
185
 
186
+ // Listen for SW notification-click messages (must be before any early return)
187
+ setupSWMessageListener();
188
+
104
189
  // Sync E2E key so push notifications can be decrypted
105
190
  await syncE2eKeyToSW();
106
191
 
@@ -109,7 +194,9 @@ export async function initPushNotifications(): Promise<void> {
109
194
  syncE2eKeyToSW().catch(() => {});
110
195
  });
111
196
 
112
- if (Capacitor.isNativePlatform()) {
197
+ if (isMacOSNative()) {
198
+ await initMacOSPush();
199
+ } else if (Capacitor.isNativePlatform()) {
113
200
  await initNativePush();
114
201
  } else {
115
202
  await initWebPush();
@@ -35,10 +35,11 @@ export class BotsChatWSClient {
35
35
  connect(): void {
36
36
  this.intentionalClose = false;
37
37
 
38
- // In Capacitor (native app), WebView runs from capacitor:// so we must
39
- // use the full production WebSocket URL.
38
+ // In native apps (Capacitor or macOS), the WebView runs from a custom
39
+ // scheme so we must use the full production WebSocket URL.
40
+ const isNative = Capacitor.isNativePlatform() || !!(window as any).__BOTSCHAT_NATIVE__;
40
41
  let url: string;
41
- if (Capacitor.isNativePlatform()) {
42
+ if (isNative) {
42
43
  url = `wss://console.botschat.app/api/ws/${this.opts.userId}/${this.opts.sessionId}`;
43
44
  } else {
44
45
  const protocol = window.location.protocol === "https:" ? "wss:" : "ws:";