diff --git a/server/public/home.html b/server/public/home.html
index ce7dfba..4445df7 100644
--- a/server/public/home.html
+++ b/server/public/home.html
@@ -2977,7 +2977,6 @@ async function nativeSaveFile(url, name, meta){
if(ph.ok) toast('Saved to Photos · Connect album');
else if(isMedia && ph.reason==='denied') toast('Saved to Files. Allow Photos access in Settings to also save to your gallery.');
else toast('Saved to Biz Connect · '+bzLibFolder(mime));
- if(isMedia && !ph.ok && ph.reason!=='off'){ try{ pdbg('photos-fail', { reason:ph.reason, err:ph.err||'' }); }catch(_){} } // telemetry: why Photos save failed
}catch(e){ toast("Couldn't save the file"); }
finally{ bzDlHide(box); }
return true; // handled either way — never fall through to navigation
@@ -3779,28 +3778,22 @@ function reportInstall(){
}catch(_){}
}
let _nativeTok=null;
-// TEMP push diagnostics: mirror each step to the server so we can see where iOS registration fails
-// without a Mac/device console. Remove once native push is confirmed working end-to-end.
-function pdbg(step, extra){ try{ postJSON('/api/v1/push-debug', Object.assign({ step, t: Date.now() }, extra||{})).catch(()=>{}); }catch(_){}
- try{ console.log('[push]', step, extra||''); }catch(_){} }
async function setupNativePush(){
const PN=capPlugin('PushNotifications'); const plat=nativePlatform();
- const C=window.Capacitor;
- pdbg('native-setup-enter', { plat, hasPlugin: !!PN, isNative: !!(C&&C.isNativePlatform&&C.isNativePlatform()), plugins: (C&&C.Plugins)?Object.keys(C.Plugins).join(','):'' });
- if(!PN || (plat!=='ios' && plat!=='android')){ pdbg('native-setup-skip', { plat, hasPlugin: !!PN }); return false; } // not a mobile native app
+ if(!PN || (plat!=='ios' && plat!=='android')) return false; // not a mobile native app
try{
- PN.addListener('registration', async (t)=>{ const token=t&&t.value; pdbg('registration-event', { tokenLen: token?token.length:0 }); if(!token) return; _nativeTok=token;
- try{ await postJSON('/api/v1/devices',{ platform:plat, token }); pushActive=true; pdbg('device-post-ok', { plat }); console.log('[push] native device registered'); }
- catch(e){ pdbg('device-post-fail', { err:String((e&&e.message)||e) }); console.warn('[push] device register failed:', e); } });
- PN.addListener('registrationError', (e)=>{ pdbg('registration-error', { err:(e&&(e.error||e.message))||JSON.stringify(e) }); console.warn('[push] native registration error:', e); });
+ PN.addListener('registration', async (t)=>{ const token=t&&t.value; if(!token) return; _nativeTok=token;
+ try{ await postJSON('/api/v1/devices',{ platform:plat, token }); pushActive=true; console.log('[push] native device registered'); }
+ catch(e){ console.warn('[push] device register failed:', e); } });
+ PN.addListener('registrationError', (e)=>{ console.warn('[push] native registration error:', e); });
// Tapping an OS notification opens the relevant chat (payload carries kind+id).
PN.addListener('pushNotificationActionPerformed', (a)=>{ try{ const d=(a&&a.notification&&a.notification.data)||{}; if(d.id) selectChat(d.kind||'dm', d.id); }catch(_){} });
- let perm=await PN.checkPermissions(); pdbg('perm-check', { receive: perm&&perm.receive });
- if(perm.receive!=='granted'){ perm=await PN.requestPermissions(); pdbg('perm-after-request', { receive: perm&&perm.receive }); }
- if(perm.receive!=='granted'){ pdbg('perm-not-granted', { receive: perm&&perm.receive }); console.log('[push] native permission not granted'); return true; }
- await PN.register(); pdbg('register-called');
+ let perm=await PN.checkPermissions();
+ if(perm.receive!=='granted'){ perm=await PN.requestPermissions(); }
+ if(perm.receive!=='granted'){ console.log('[push] native permission not granted'); return true; }
+ await PN.register();
console.log('[push] native push registered');
- }catch(e){ pdbg('native-setup-exception', { err:String((e&&e.message)||e) }); console.warn('[push] native push setup failed:', e); }
+ }catch(e){ console.warn('[push] native push setup failed:', e); }
return true; // handled the native path (skip Web Push regardless of outcome)
}
async function setupPush(){
@@ -3865,7 +3858,6 @@ async function setupNativeCall(){
// the call was answered (native media bypasses our WS, so the server can't learn it otherwise) and clear
// the in-app invite. Track answered rooms so end vs decline is signalled correctly.
NC.addListener('answerCall', (d)=>{ try{
- pdbg('nc-answer', { room:(d&&d.room)||'', hasUrl:!!(d&&d.livekitUrl), hasToken:!!(d&&d.livekitToken) });
if(!d||!d.room) return;
_nativeAnswered.add(d.room);
dismissCallInvite(d.room);
@@ -3875,18 +3867,17 @@ async function setupNativeCall(){
const isGroup=(d.kind==='group');
meetReturn = isGroup ? { kind:'group', id:d.groupId } : { kind:'dm', id:d.callerId };
switchTab('meeting'); enterMeeting(d.room, false, { native:true, uuid:d.callUUID });
- }catch(e){ pdbg('nc-answer-err', { err:String((e&&e.message)||e) }); } });
+ }catch(e){ console.warn('[callkit] answerCall failed:', e); } });
// Enforce the muted-by-default rule against the plugin's actual mic once the room connects (belt-and-braces
// for builds whose plugin still connects the mic live). meetMic is the source of truth for the mic button.
- NC.addListener('callConnected', ()=>{ pdbg('nc-connected'); if(meetNative){ try{ NC.setMuted({ muted:!meetMic }); }catch(_){} } });
- NC.addListener('audioActivated', (e)=>{ pdbg('nc-audio', { ok:!!(e&&e.ok), err:(e&&e.error)||'', route:(e&&e.route)||'' }); }); // CallKit audio-session activation + output route (debug audio)
- NC.addListener('callError', (e)=>{ pdbg('nc-error', { err:(e&&e.error)||'' }); });
+ NC.addListener('callConnected', ()=>{ if(meetNative){ try{ NC.setMuted({ muted:!meetMic }); }catch(_){} } });
+ NC.addListener('callError', (e)=>{ console.warn('[callkit] call error:', (e&&e.error)||''); });
// Muted from the CallKit system UI → reflect it in the meeting window's mic button.
NC.addListener('setMuted', (e)=>{ if(!e||meetState!=='call'||!meetNative) return; meetMic=!e.muted; try{ updateMicBtn(); setTileMute('__local', !meetMic); meetSend({type:'meeting-state', muted:!meetMic, camOff:!meetCam}); }catch(_){} });
// Ended on the CallKit system screen / plugin ended on remote hang-up. Leave the meeting window too (guarded
// so our own in-app hang-up, which already called the plugin, doesn't loop). Then tell the server.
NC.addListener('endCall', (d)=>{ try{
- const room=d&&d.room; pdbg('nc-end', { room:room||'', answered:_nativeAnswered.has(room) });
+ const room=d&&d.room;
if(!room) return;
dismissCallInvite(room);
if(_ncEnding){ _ncEnding=false; }
@@ -3901,7 +3892,6 @@ async function setupNativeCall(){
async function callkitReportOutgoing(uuid, room, kind, peerName, hasVideo){
const NC=nativeCallPlugin(); if(!NC||!uuid) return;
let tk={}; try{ tk=await postJSON('/api/meetings/token',{ room }); }catch(_){}
- pdbg('nc-outgoing', { room, hasUrl:!!(tk&&tk.url), hasToken:!!(tk&&tk.token) });
try{ NC.reportOutgoingCall({ callUUID:uuid, room, kind:kind||'dm', peerName:peerName||'Call', hasVideo:!!hasVideo, url:tk.url||'', token:tk.token||'' }); }catch(_){}
}
// End the CallKit call (remote hung up / we left / call ended). Safe no-op off-CallKit.
diff --git a/server/routes.js b/server/routes.js
index 55fd644..9949b9e 100644
--- a/server/routes.js
+++ b/server/routes.js
@@ -412,18 +412,6 @@ route('POST', '/api/devices/remove', async (req, res) => {
json(res, 200, { ok: true });
});
-// --- Push diagnostics (temporary): the native app reports each step of push setup here so we can see
-// WHERE iOS registration fails without a Mac/device console. Best-effort; logs and returns 200. ---
-route('POST', '/api/push-debug', async (req, res) => {
- try {
- const b = await readBody(req);
- let uid = 'anon'; try { const u = await currentUser(req); if (u) uid = u.id; } catch (_) {}
- const line = (typeof b === 'object' ? JSON.stringify(b) : String(b)).slice(0, 800);
- console.log('[push-debug] user=' + uid + ' ' + line);
- } catch (_) {}
- json(res, 200, { ok: true });
-});
-
// --- App install telemetry: records each install and, once the user signs in, who's using it. ---
route('POST', '/api/telemetry/install', async (req, res) => {
const { installId, platform, appVersion, os } = await readBody(req);