@cloudsignal/pwa-sdk 1.2.1 → 1.2.3
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/CHANGELOG.md +21 -0
- package/LICENSE +21 -0
- package/dist/index.cjs +87 -3
- package/dist/index.cjs.map +1 -1
- package/dist/index.d.mts +19 -1
- package/dist/index.d.ts +19 -1
- package/dist/index.global.js +4 -4
- package/dist/index.global.js.map +1 -1
- package/dist/index.js +87 -3
- package/dist/index.js.map +1 -1
- package/package.json +3 -4
package/dist/index.d.mts
CHANGED
|
@@ -521,7 +521,7 @@ interface NotificationAction {
|
|
|
521
521
|
/**
|
|
522
522
|
* Event types emitted by the SDK
|
|
523
523
|
*/
|
|
524
|
-
type PWAEvent = 'install:available' | 'install:accepted' | 'install:dismissed' | 'install:completed' | 'install:error' | 'push:registered' | 'push:unregistered' | 'push:updated' | 'push:error' | 'push:received' | 'push:clicked' | 'permission:granted' | 'permission:denied' | 'permission:prompt' | 'sw:registered' | 'sw:updated' | 'sw:error' | 'sw:activated' | 'config:loaded' | 'config:error' | 'heartbeat:started' | 'heartbeat:stopped' | 'heartbeat:sent' | 'heartbeat:error' | 'heartbeat:intervalChanged' | 'heartbeat:pausedForBattery' | 'heartbeat:resumedFromBattery' | 'network:online' | 'network:offline' | 'state:changed' | 'wakeLock:acquired' | 'wakeLock:released' | 'wakeLock:error' | 'offlineQueue:queued' | 'offlineQueue:processed' | 'offlineQueue:flushed' | 'iosBanner:shown' | 'iosBanner:dismissed' | 'iosBanner:installClicked' | 'auth:tokenUpdated';
|
|
524
|
+
type PWAEvent = 'install:available' | 'install:accepted' | 'install:dismissed' | 'install:completed' | 'install:registered' | 'install:error' | 'push:registered' | 'push:unregistered' | 'push:updated' | 'push:error' | 'push:received' | 'push:clicked' | 'permission:granted' | 'permission:denied' | 'permission:prompt' | 'sw:registered' | 'sw:updated' | 'sw:error' | 'sw:activated' | 'config:loaded' | 'config:error' | 'heartbeat:started' | 'heartbeat:stopped' | 'heartbeat:sent' | 'heartbeat:error' | 'heartbeat:intervalChanged' | 'heartbeat:pausedForBattery' | 'heartbeat:resumedFromBattery' | 'network:online' | 'network:offline' | 'state:changed' | 'wakeLock:acquired' | 'wakeLock:released' | 'wakeLock:error' | 'offlineQueue:queued' | 'offlineQueue:processed' | 'offlineQueue:flushed' | 'iosBanner:shown' | 'iosBanner:dismissed' | 'iosBanner:installClicked' | 'auth:tokenUpdated';
|
|
525
525
|
/**
|
|
526
526
|
* Event handler function
|
|
527
527
|
*/
|
|
@@ -1376,6 +1376,24 @@ declare class PushNotificationManager {
|
|
|
1376
1376
|
* Check registration status
|
|
1377
1377
|
*/
|
|
1378
1378
|
checkStatus(): Promise<RegistrationStatusResponse | null>;
|
|
1379
|
+
/**
|
|
1380
|
+
* Register PWA installation without push subscription.
|
|
1381
|
+
* This tracks users who installed the PWA but haven't subscribed to notifications.
|
|
1382
|
+
* Called automatically when installation is detected.
|
|
1383
|
+
*
|
|
1384
|
+
* @returns Installation registration result or null if already registered/failed
|
|
1385
|
+
*/
|
|
1386
|
+
registerInstallation(): Promise<{
|
|
1387
|
+
registrationId: string;
|
|
1388
|
+
} | null>;
|
|
1389
|
+
/**
|
|
1390
|
+
* Check if installation is already registered
|
|
1391
|
+
*/
|
|
1392
|
+
isInstallationRegistered(): boolean;
|
|
1393
|
+
/**
|
|
1394
|
+
* Get stored installation registration ID
|
|
1395
|
+
*/
|
|
1396
|
+
getInstallationId(): string | null;
|
|
1379
1397
|
/**
|
|
1380
1398
|
* Request notification permission
|
|
1381
1399
|
*/
|
package/dist/index.d.ts
CHANGED
|
@@ -521,7 +521,7 @@ interface NotificationAction {
|
|
|
521
521
|
/**
|
|
522
522
|
* Event types emitted by the SDK
|
|
523
523
|
*/
|
|
524
|
-
type PWAEvent = 'install:available' | 'install:accepted' | 'install:dismissed' | 'install:completed' | 'install:error' | 'push:registered' | 'push:unregistered' | 'push:updated' | 'push:error' | 'push:received' | 'push:clicked' | 'permission:granted' | 'permission:denied' | 'permission:prompt' | 'sw:registered' | 'sw:updated' | 'sw:error' | 'sw:activated' | 'config:loaded' | 'config:error' | 'heartbeat:started' | 'heartbeat:stopped' | 'heartbeat:sent' | 'heartbeat:error' | 'heartbeat:intervalChanged' | 'heartbeat:pausedForBattery' | 'heartbeat:resumedFromBattery' | 'network:online' | 'network:offline' | 'state:changed' | 'wakeLock:acquired' | 'wakeLock:released' | 'wakeLock:error' | 'offlineQueue:queued' | 'offlineQueue:processed' | 'offlineQueue:flushed' | 'iosBanner:shown' | 'iosBanner:dismissed' | 'iosBanner:installClicked' | 'auth:tokenUpdated';
|
|
524
|
+
type PWAEvent = 'install:available' | 'install:accepted' | 'install:dismissed' | 'install:completed' | 'install:registered' | 'install:error' | 'push:registered' | 'push:unregistered' | 'push:updated' | 'push:error' | 'push:received' | 'push:clicked' | 'permission:granted' | 'permission:denied' | 'permission:prompt' | 'sw:registered' | 'sw:updated' | 'sw:error' | 'sw:activated' | 'config:loaded' | 'config:error' | 'heartbeat:started' | 'heartbeat:stopped' | 'heartbeat:sent' | 'heartbeat:error' | 'heartbeat:intervalChanged' | 'heartbeat:pausedForBattery' | 'heartbeat:resumedFromBattery' | 'network:online' | 'network:offline' | 'state:changed' | 'wakeLock:acquired' | 'wakeLock:released' | 'wakeLock:error' | 'offlineQueue:queued' | 'offlineQueue:processed' | 'offlineQueue:flushed' | 'iosBanner:shown' | 'iosBanner:dismissed' | 'iosBanner:installClicked' | 'auth:tokenUpdated';
|
|
525
525
|
/**
|
|
526
526
|
* Event handler function
|
|
527
527
|
*/
|
|
@@ -1376,6 +1376,24 @@ declare class PushNotificationManager {
|
|
|
1376
1376
|
* Check registration status
|
|
1377
1377
|
*/
|
|
1378
1378
|
checkStatus(): Promise<RegistrationStatusResponse | null>;
|
|
1379
|
+
/**
|
|
1380
|
+
* Register PWA installation without push subscription.
|
|
1381
|
+
* This tracks users who installed the PWA but haven't subscribed to notifications.
|
|
1382
|
+
* Called automatically when installation is detected.
|
|
1383
|
+
*
|
|
1384
|
+
* @returns Installation registration result or null if already registered/failed
|
|
1385
|
+
*/
|
|
1386
|
+
registerInstallation(): Promise<{
|
|
1387
|
+
registrationId: string;
|
|
1388
|
+
} | null>;
|
|
1389
|
+
/**
|
|
1390
|
+
* Check if installation is already registered
|
|
1391
|
+
*/
|
|
1392
|
+
isInstallationRegistered(): boolean;
|
|
1393
|
+
/**
|
|
1394
|
+
* Get stored installation registration ID
|
|
1395
|
+
*/
|
|
1396
|
+
getInstallationId(): string | null;
|
|
1379
1397
|
/**
|
|
1380
1398
|
* Request notification permission
|
|
1381
1399
|
*/
|
package/dist/index.global.js
CHANGED
|
@@ -3,8 +3,8 @@ var CloudSignalPWA=(function(exports){'use strict';/**
|
|
|
3
3
|
* https://cloudsignal.io
|
|
4
4
|
* MIT License
|
|
5
5
|
*/
|
|
6
|
-
var
|
|
7
|
-
`),p=await crypto.subtle.importKey("raw",o.encode(n),{name:"HMAC",hash:"SHA-256"},false,["sign"]),S=await crypto.subtle.sign("HMAC",p,o.encode(a));return ue(S)}async function H(n,e,t,i,r){let s=Math.floor(Date.now()/1e3).toString(),o=await W(e,n,s,t,i,r||"");return {"X-CloudSignal-Organization-ID":n,"X-CloudSignal-Timestamp":s,"X-CloudSignal-Signature":o,"Content-Type":"application/json"}}async function V(n,e,t,i,r){let s=r?JSON.stringify(r):void 0,o=await H(n,e,t,i,s),l={method:t,headers:o};return s&&(l.body=s),fetch(i,l)}function v(n){return !n||typeof n!="string"?false:/^[0-9a-f]{8}-[0-9a-f]{4}-[1-5][0-9a-f]{3}-[89ab][0-9a-f]{3}-[0-9a-f]{12}$/i.test(n)}var P=ie(()=>{});async function L(){try{let n=[];n.push(`${screen.width}x${screen.height}`),n.push(`${screen.colorDepth}`),n.push(Intl.DateTimeFormat().resolvedOptions().timeZone),n.push(navigator.language),n.push(navigator.platform),navigator.hardwareConcurrency&&n.push(navigator.hardwareConcurrency.toString()),navigator.deviceMemory&&n.push(navigator.deviceMemory.toString());let e=ne();e&&n.push(e);let t=se();t&&n.push(t);let i=await oe();i&&n.push(i);let r=n.join("|");return await ae(r)}catch(n){return console.warn("Browser fingerprint generation failed:",n),null}}function ne(){try{let n=document.createElement("canvas"),e=n.getContext("2d");return e?(n.width=200,n.height=50,e.textBaseline="alphabetic",e.fillStyle="#f60",e.fillRect(125,1,62,20),e.fillStyle="#069",e.font="11pt Arial",e.fillText("CloudSignal PWA",2,15),e.fillStyle="rgba(102, 204, 0, 0.7)",e.font="18pt Arial",e.fillText("CloudSignal PWA",4,45),n.toDataURL().slice(-50)):null}catch{return null}}function se(){try{let n=document.createElement("canvas"),e=n.getContext("webgl")||n.getContext("experimental-webgl");if(!e)return null;let t=e,i=t.getExtension("WEBGL_debug_renderer_info");if(i){let o=t.getParameter(i.UNMASKED_VENDOR_WEBGL),l=t.getParameter(i.UNMASKED_RENDERER_WEBGL);return `${o}~${l}`}let r=t.getParameter(t.VENDOR),s=t.getParameter(t.RENDERER);return `${r}~${s}`}catch{return null}}async function oe(){try{let n=window.AudioContext||window.webkitAudioContext;if(!n)return null;let e=new n,t=e.createOscillator(),i=e.createAnalyser(),r=e.createGain(),s=e.createScriptProcessor(4096,1,1);r.gain.value=0,t.type="triangle",t.connect(i),i.connect(s),s.connect(r),r.connect(e.destination),t.start(0),await new Promise(c=>setTimeout(c,100));let o=new Uint8Array(i.frequencyBinCount);i.getByteFrequencyData(o);let l=0;for(let c=0;c<o.length;c++)l+=o[c];return t.stop(),await e.close(),l.toString(36)}catch{return null}}async function ae(n){let t=new TextEncoder().encode(n),i=await crypto.subtle.digest("SHA-256",t);return Array.from(new Uint8Array(i)).map(s=>s.toString(16).padStart(2,"0")).join("")}function q(n,e,t,i,r){return [n,e,t,i,r].filter(Boolean).join("_").replace(/[^a-zA-Z0-9_]/g,"_")}var f=class{constructor(){this.cachedInfo=null;}getDeviceInfo(){if(this.cachedInfo)return this.cachedInfo;let e=this.getPlatformInfo(),t=this.getScreenInfo(),i=this.getNetworkInfo(),r=this.getCapabilities(),s={os:e.os,osVersion:e.osVersion,deviceType:e.deviceType,deviceModel:e.deviceModel,isMobile:this.isMobile(),isTablet:this.isTablet(),isDesktop:this.isDesktop(),isWebView:e.isWebView,browser:e.browser,browserVersion:e.browserVersion,isIOS:e.os==="iOS",isAndroid:e.os==="Android",isMacOS:e.os==="macOS",isWindows:e.os==="Windows",isLinux:e.os==="Linux",screenWidth:t.width,screenHeight:t.height,pixelRatio:t.pixelRatio,supportLevel:r.supportLevel,hasNotificationPermission:r.notifications,hasPushManager:r.push,hasServiceWorker:r.serviceWorker,hasShareAPI:r.share,hasBadgeAPI:r.badge,notificationPermission:this.getNotificationPermission(),isOnline:i.isOnline,connectionType:i.connectionType,platformIcon:this.getPlatformIcon(e.os,e.deviceType),userAgent:e.userAgent,trackingId:q(e.os,e.osVersion,e.browser,e.browserVersion,e.deviceModel)};return this.cachedInfo=s,s}clearCache(){this.cachedInfo=null;}getPlatformInfo(){let e=navigator.userAgent,t=navigator.platform,i="Unknown",r="Unknown",s="Unknown",o="Unknown",l="Unknown",c="Unknown",d=false;if(/iPad|iPhone|iPod/.test(e)&&!window.MSStream){i="iOS";let a=e.match(/OS (\d+)_(\d+)_?(\d+)?/);a&&(r=`${a[1]}.${a[2]}${a[3]?"."+a[3]:""}`),/iPad/.test(e)?(l="iPad",c=this.detectiPadModel(e)):/iPhone/.test(e)?(l="iPhone",c=this.detectiPhoneModel(e)):/iPod/.test(e)&&(l="iPod",c="iPod Touch");}else if(/Android/.test(e)){i="Android";let a=e.match(/Android (\d+\.?\d*\.?\d*)/);a&&(r=a[1]);let p=this.detectAndroidDevice(e);l=p.type,c=p.model;}else if(/Mac/.test(t)){i="macOS";let a=e.match(/Mac OS X (\d+)[_.](\d+)[_.]?(\d+)?/);a&&(r=`${a[1]}.${a[2]}${a[3]?"."+a[3]:""}`),l="Desktop",c="Mac";}else if(/Win/.test(t)){i="Windows";let a=e.match(/Windows NT (\d+\.\d+)/);a&&(r=this.getWindowsVersion(a[1])),l="Desktop",c="PC";}else /Linux/.test(t)&&(i="Linux",l="Desktop",c="Linux PC",/Ubuntu/.test(e)?r="Ubuntu":/Fedora/.test(e)?r="Fedora":/Debian/.test(e)&&(r="Debian"));if(/Chrome/.test(e)&&!/Edg/.test(e)&&!/OPR/.test(e)){s="Chrome";let a=e.match(/Chrome\/(\d+\.?\d*\.?\d*\.?\d*)/);a&&(o=a[1]);}else if(/Safari/.test(e)&&!/Chrome/.test(e)){s="Safari";let a=e.match(/Version\/(\d+\.?\d*\.?\d*)/);a&&(o=a[1]);}else if(/Firefox/.test(e)){s="Firefox";let a=e.match(/Firefox\/(\d+\.?\d*\.?\d*)/);a&&(o=a[1]);}else if(/Edg/.test(e)){s="Edge";let a=e.match(/Edg\/(\d+\.?\d*\.?\d*\.?\d*)/);a&&(o=a[1]);}else if(/OPR/.test(e)||/Opera/.test(e)){s="Opera";let a=e.match(/(?:OPR|Opera)\/(\d+\.?\d*\.?\d*)/);a&&(o=a[1]);}else if(/SamsungBrowser/.test(e)){s="Samsung Internet";let a=e.match(/SamsungBrowser\/(\d+\.?\d*)/);a&&(o=a[1]);}return d=this.detectWebView(e),{os:i,osVersion:r,browser:s,browserVersion:o,deviceType:l,deviceModel:c,isWebView:d,userAgent:e}}getScreenInfo(){return {width:screen.width,height:screen.height,pixelRatio:window.devicePixelRatio||1,orientation:screen.width>screen.height?"landscape":"portrait"}}getNetworkInfo(){let e=navigator.connection;return {isOnline:navigator.onLine,connectionType:e?.effectiveType||"unknown",effectiveType:e?.effectiveType,downlink:e?.downlink,rtt:e?.rtt,saveData:e?.saveData}}getCapabilities(){let e={serviceWorker:"serviceWorker"in navigator,push:"PushManager"in window,notifications:"Notification"in window,backgroundSync:"serviceWorker"in navigator&&"SyncManager"in window,badge:"setAppBadge"in navigator,share:"share"in navigator,shareTarget:"launchQueue"in window,fileSystemAccess:"showOpenFilePicker"in window,contactPicker:"ContactsManager"in window,periodicSync:"serviceWorker"in navigator&&"PeriodicSyncManager"in window,supportLevel:"none"};return e.serviceWorker&&e.push&&e.notifications?e.supportLevel="full":e.serviceWorker&&e.notifications?e.supportLevel="partial":e.serviceWorker&&(e.supportLevel="basic"),e}getNotificationPermission(){return "Notification"in window?Notification.permission:"denied"}isMobile(){let e=navigator.userAgent;return /Android|webOS|iPhone|iPod|BlackBerry|IEMobile|Opera Mini/i.test(e)}isTablet(){let e=navigator.userAgent;return /iPad|Android(?!.*Mobile)|Tablet/i.test(e)}isDesktop(){return !this.isMobile()&&!this.isTablet()}getPlatformIcon(e,t){return e==="iOS"||t==="iPhone"||t==="iPad"?"\u{1F4F1}":e==="Android"?"\u{1F916}":e==="macOS"?"\u{1F4BB}":"\u{1F5A5}\uFE0F"}detectiPhoneModel(e){let t=screen.height,i=screen.width;return t===932||i===932?"iPhone 15 Pro Max/14 Pro Max":t===896||i===896?"iPhone 15 Pro/14 Pro/11 Pro Max":t===852||i===852?"iPhone 15/14":t===844||i===844?"iPhone 13/12":t===812||i===812?"iPhone X/XS/11 Pro":t===736||i===736?"iPhone 8 Plus":t===667||i===667?"iPhone 8/SE":t===568||i===568?"iPhone SE (1st)":"iPhone"}detectiPadModel(e){let t=screen.width,i=screen.height,r=window.devicePixelRatio||1;return (i===1366||t===1366)&&r===2?'iPad Pro 12.9"':(i===1194||t===1194)&&r===2?'iPad Pro 11"':(i===1180||t===1180)&&r===2?"iPad Air/10th Gen":(i===1133||t===1133)&&r===2?"iPad mini":"iPad"}detectAndroidDevice(e){let t="Phone",i="Android Device";if(/Tablet|SM-T|Tab|GT-P|MediaPad/i.test(e)&&(t="Tablet"),/SM-S9\d{2}/i.test(e))i="Samsung Galaxy S24";else if(/SM-S91\d/i.test(e))i="Samsung Galaxy S23";else if(/SM-S90\d/i.test(e))i="Samsung Galaxy S22";else if(/SM-G99\d/i.test(e))i="Samsung Galaxy S21";else if(/SM-N9\d{2}/i.test(e))i="Samsung Galaxy Note";else if(/SM-A\d{2}/i.test(e))i="Samsung Galaxy A Series";else if(/SM-/i.test(e)){let r=e.match(/SM-[A-Z]\d+/i);r&&(i=`Samsung ${r[0]}`);}if(/Pixel 8/i.test(e)?i="Google Pixel 8":/Pixel 7/i.test(e)?i="Google Pixel 7":/Pixel 6/i.test(e)?i="Google Pixel 6":/Pixel/i.test(e)&&(i="Google Pixel"),/OnePlus/i.test(e)){let r=e.match(/OnePlus[\s]?(\w+)/i);i=r?`OnePlus ${r[1]}`:"OnePlus";}return /Xiaomi|Redmi|POCO|Mi\s/i.test(e)&&(/Redmi/i.test(e)?i="Xiaomi Redmi":/POCO/i.test(e)?i="Xiaomi POCO":i="Xiaomi"),/HUAWEI|Honor/i.test(e)&&(i=/Honor/i.test(e)?"Honor":"Huawei"),/OPPO/i.test(e)&&(i="OPPO"),/vivo/i.test(e)&&(i="Vivo"),{type:t,model:i}}getWindowsVersion(e){return {"10.0":"Windows 10/11","6.3":"Windows 8.1","6.2":"Windows 8","6.1":"Windows 7","6.0":"Windows Vista","5.1":"Windows XP"}[e]||`Windows NT ${e}`}detectWebView(e){return !!(/FBAN|FBAV/i.test(e)||/Instagram/i.test(e)||/LinkedIn/i.test(e)||/Twitter/i.test(e)||/MicroMessenger/i.test(e)||/Snapchat/i.test(e)||/BytedanceWebview|TikTok/i.test(e)||/wv|WebView/i.test(e))}},le=new f;var I=class{constructor(e={}){this.registration=null;this.config={path:"/service-worker.js",scope:"/",autoRegister:true,updateBehavior:"auto",...e.config},this.debug=e.debug??false,this.onRegistered=e.onRegistered,this.onUpdated=e.onUpdated,this.onError=e.onError;}isSupported(){return "serviceWorker"in navigator}getRegistration(){return this.registration}async register(){if(!this.isSupported())return this.log("Service workers not supported"),null;try{let{path:e,scope:t}=this.getPathAndScope();this.log(`Registering service worker: ${e} with scope ${t}`);let i=await navigator.serviceWorker.register(e,{scope:t});return this.registration=i,i.addEventListener("updatefound",()=>{this.handleUpdateFound(i);}),await navigator.serviceWorker.ready,this.log("Service worker registered successfully"),this.onRegistered?.(i),i}catch(e){let t=e instanceof Error?e:new Error(String(e));return this.log(`Service worker registration failed: ${t.message}`,"error"),this.onError?.(t),null}}async unregister(){if(!this.registration)return false;try{let e=await this.registration.unregister();return e&&(this.registration=null,this.log("Service worker unregistered")),e}catch(e){return this.log(`Failed to unregister service worker: ${e}`,"error"),false}}async checkForUpdate(){if(this.registration)try{await this.registration.update(),this.log("Checked for service worker update");}catch(e){this.log(`Failed to check for update: ${e}`,"error");}}async waitForReady(e=5e3){if(!this.isSupported())return null;let t=new Promise(i=>{setTimeout(()=>i(null),e);});try{let i=await Promise.race([navigator.serviceWorker.ready,t]);return i&&(this.registration=i),i}catch{return null}}postMessage(e){if(!this.registration?.active){this.log("No active service worker to send message to","warn");return}this.registration.active.postMessage(e);}clearBadge(){this.postMessage({type:"CLEAR_BADGE"});}setBadge(e){this.postMessage({type:"SET_BADGE",count:e});}handleUpdateFound(e){let t=e.installing;t&&t.addEventListener("statechange",()=>{t.state==="installed"&&navigator.serviceWorker.controller&&(this.log("New service worker available"),this.config.updateBehavior==="auto"&&t.postMessage({type:"SKIP_WAITING"}),this.onUpdated?.(e));});}getPathAndScope(){if(this.config.path&&this.config.scope)return {path:this.config.path,scope:this.config.scope};try{let e=window.location.pathname||"/";if(e.startsWith("/version-live"))return {path:"/version-live/service-worker.js",scope:"/version-live/"};if(e.startsWith("/version-test"))return {path:"/version-test/service-worker.js",scope:"/version-test/"}}catch{}return {path:this.config.path||"/service-worker.js",scope:this.config.scope||"/"}}log(e,t="log"){if(!this.debug)return;console[t](`[CloudSignal PWA SW] ${e}`);}};var k=class{constructor(e={}){this.deferredPrompt=null;this.isInstalled=false;this.debug=e.debug??false,this.onInstallAvailable=e.onInstallAvailable,this.onInstallAccepted=e.onInstallAccepted,this.onInstallDismissed=e.onInstallDismissed,this.onInstalled=e.onInstalled,this.detectInstallationStatus();}initialize(){window.addEventListener("beforeinstallprompt",e=>{e.preventDefault(),this.deferredPrompt=e,this.log("Install prompt available"),this.onInstallAvailable?.(this.deferredPrompt);}),window.addEventListener("appinstalled",()=>{this.isInstalled=true,this.deferredPrompt=null,this.log("PWA was installed"),this.onInstalled?.();}),window.matchMedia&&window.matchMedia("(display-mode: standalone)").addEventListener("change",t=>{t.matches&&(this.isInstalled=true,this.log("App is now running in standalone mode"));});}getState(){let e=this.getDisplayMode(),t=this.isIOSDevice(),i=this.isSafariBrowser();return {isInstalled:this.isInstalled||e!=="browser",canBeInstalled:this.deferredPrompt!==null,needsManualInstall:t&&i&&!this.isInstalled,showManualInstructions:t&&i&&!this.isInstalled,installSteps:this.getInstallSteps(),displayMode:e}}async showInstallPrompt(){if(!this.deferredPrompt)return this.log("No install prompt available","warn"),{accepted:false,outcome:"dismissed"};try{await this.deferredPrompt.prompt();let{outcome:e,platform:t}=await this.deferredPrompt.userChoice,i={accepted:e==="accepted",outcome:e,platform:t};return e==="accepted"?(this.log("User accepted install prompt"),this.isInstalled=!0,this.onInstallAccepted?.(i)):(this.log("User dismissed install prompt"),this.onInstallDismissed?.(i)),this.deferredPrompt=null,i}catch(e){return this.log(`Error showing install prompt: ${e}`,"error"),{accepted:false,outcome:"dismissed"}}}canInstall(){return this.deferredPrompt!==null}isPWAInstalled(){return this.isInstalled||this.getDisplayMode()!=="browser"}getDisplayMode(){return window.matchMedia("(display-mode: standalone)").matches?"standalone":window.matchMedia("(display-mode: minimal-ui)").matches?"minimal-ui":window.matchMedia("(display-mode: fullscreen)").matches?"fullscreen":navigator.standalone===true?"standalone":"browser"}getInstallSteps(){return this.isIOSDevice()?["Tap the Share button in Safari",'Scroll down and tap "Add to Home Screen"','Tap "Add" to install the app']:this.isAndroidDevice()?["Tap the menu (three dots) in your browser",'Tap "Install App" or "Add to Home Screen"',"Follow the prompts to install"]:["Click the install icon in the address bar","Or use the browser menu to install the app",'Click "Install" when prompted']}detectInstallationStatus(){if(this.getDisplayMode()!=="browser"){this.isInstalled=true;return}if(navigator.standalone===true){this.isInstalled=true;return}"getInstalledRelatedApps"in navigator&&navigator.getInstalledRelatedApps().then(e=>{e.length>0&&(this.isInstalled=true);}).catch(()=>{});}isIOSDevice(){return /iPad|iPhone|iPod/.test(navigator.userAgent)&&!window.MSStream}isAndroidDevice(){return /Android/i.test(navigator.userAgent)}isSafariBrowser(){let e=navigator.userAgent;return /Safari/i.test(e)&&!/Chrome|CriOS|FxiOS/i.test(e)}log(e,t="log"){if(!this.debug)return;console[t](`[CloudSignal PWA Install] ${e}`);}};P();function $(n,e){return {Authorization:`Bearer ${n}`,"X-CloudSignal-Organization-ID":e,"Content-Type":"application/json"}}async function K(n,e,t,i){let r=i?JSON.stringify(i):void 0,s=$(n.token,n.organizationId),o={method:e,headers:s};r&&(o.body=r);let l=await fetch(t,o);if(l.status===401&&n.onTokenExpired)try{let c=await n.onTokenExpired();c&&(s=$(c,n.organizationId),o.headers=s,l=await fetch(t,o));}catch(c){console.warn("[CloudSignal PWA] Token refresh failed:",c);}return l}function y(n){if(n.userToken)return {mode:"jwt",organizationId:n.organizationId,userToken:n.userToken,onTokenExpired:n.onTokenExpired};if(!n.organizationSecret)throw new Error("Either userToken or organizationSecret is required");return {mode:"hmac",organizationId:n.organizationId,organizationSecret:n.organizationSecret}}async function h(n,e,t,i,r){if(n.mode==="jwt"){if(!n.userToken)throw new Error("userToken required for JWT auth mode");return K({token:n.userToken,organizationId:n.organizationId,onTokenExpired:r||n.onTokenExpired},e,t,i)}let{makeAuthenticatedRequest:s}=await Promise.resolve().then(()=>(P(),G));if(!n.organizationSecret)throw new Error("organizationSecret required for HMAC auth mode");return s(n.organizationId,n.organizationSecret,e,t,i)}function b(n,e){return n.mode!=="jwt"?{mode:"jwt",organizationId:n.organizationId,userToken:e,onTokenExpired:n.onTokenExpired}:{...n,userToken:e}}var j="cloudsignal_pwa_";function X(n,e){try{let t=`${j}${n}`,i=localStorage.getItem(t);return i===null?e??null:JSON.parse(i)}catch{return e??null}}function J(n,e){try{let t=`${j}${n}`;return localStorage.setItem(t,JSON.stringify(e)),!0}catch{return false}}function Y(n){try{let e=`${j}${n}`;return localStorage.removeItem(e),!0}catch{return false}}function Q(n,e){let t=`registration_${n}_${e}`;return X(t)}function U(n,e,t){let i=`registration_${n}_${e}`;return J(i,t)}function O(n,e){let t=`registration_${n}_${e}`;return Y(t)}var z=class{constructor(e="CloudSignalPWA",t=1){this.db=null;this.dbName=e,this.dbVersion=t;}async init(){return new Promise((e,t)=>{let i=indexedDB.open(this.dbName,this.dbVersion);i.onerror=()=>t(i.error),i.onsuccess=()=>{this.db=i.result,e(this.db);},i.onupgradeneeded=r=>{let s=r.target.result;if(s.objectStoreNames.contains("badge")||s.createObjectStore("badge"),!s.objectStoreNames.contains("notifications")){let o=s.createObjectStore("notifications",{keyPath:"id",autoIncrement:true});o.createIndex("timestamp","timestamp",{unique:false}),o.createIndex("read","read",{unique:false});}s.objectStoreNames.contains("userPreferences")||s.createObjectStore("userPreferences"),s.objectStoreNames.contains("syncQueue")||s.createObjectStore("syncQueue",{keyPath:"id",autoIncrement:true}).createIndex("timestamp","timestamp",{unique:false});};})}async ensureConnection(){this.db||await this.init();}promisifyRequest(e){return new Promise((t,i)=>{e.onsuccess=()=>t(e.result),e.onerror=()=>i(e.error);})}async getBadgeCount(){await this.ensureConnection();let t=this.db.transaction(["badge"],"readonly").objectStore("badge");return await this.promisifyRequest(t.get("count"))||0}async setBadgeCount(e){await this.ensureConnection();let i=this.db.transaction(["badge"],"readwrite").objectStore("badge");await this.promisifyRequest(i.put(e,"count"));}async incrementBadgeCount(e=1){let t=await this.getBadgeCount(),i=Math.max(0,t+e);return await this.setBadgeCount(i),i}async saveNotification(e){await this.ensureConnection();let i=this.db.transaction(["notifications"],"readwrite").objectStore("notifications"),r={...e,timestamp:Date.now(),read:false};return await this.promisifyRequest(i.add(r))}async getRecentNotifications(e=50){await this.ensureConnection();let r=this.db.transaction(["notifications"],"readonly").objectStore("notifications").index("timestamp"),s=[],o=r.openCursor(null,"prev");return new Promise((l,c)=>{o.onsuccess=d=>{let a=d.target.result;a&&s.length<e?(s.push(a.value),a.continue()):l(s);},o.onerror=()=>c(o.error);})}async markNotificationAsRead(e){await this.ensureConnection();let i=this.db.transaction(["notifications"],"readwrite").objectStore("notifications"),r=await this.promisifyRequest(i.get(e));r&&(r.read=true,await this.promisifyRequest(i.put(r)));}async getUserPreference(e){await this.ensureConnection();let i=this.db.transaction(["userPreferences"],"readonly").objectStore("userPreferences");return this.promisifyRequest(i.get(e))}async setUserPreference(e,t){await this.ensureConnection();let r=this.db.transaction(["userPreferences"],"readwrite").objectStore("userPreferences");await this.promisifyRequest(r.put(t,e));}async addToSyncQueue(e){await this.ensureConnection();let i=this.db.transaction(["syncQueue"],"readwrite").objectStore("syncQueue"),r={...e,timestamp:Date.now(),retries:0};return await this.promisifyRequest(i.add(r))}async getSyncQueue(){await this.ensureConnection();let t=this.db.transaction(["syncQueue"],"readonly").objectStore("syncQueue");return this.promisifyRequest(t.getAll())}async removeFromSyncQueue(e){await this.ensureConnection();let i=this.db.transaction(["syncQueue"],"readwrite").objectStore("syncQueue");await this.promisifyRequest(i.delete(e));}};var x=class{constructor(e){this.serviceWorkerRegistration=null;this.pushSubscription=null;this.registrationId=null;this.vapidPublicKey=null;this.serviceUrl=e.serviceUrl,this.organizationId=e.organizationId,this.serviceId=e.serviceId,this.debug=e.debug??false,this.deviceDetector=new f,this.authContext=y({organizationId:e.organizationId,organizationSecret:e.organizationSecret,userToken:e.userToken}),this.onRegistered=e.onRegistered,this.onUnregistered=e.onUnregistered,this.onError=e.onError,this.onPermissionDenied=e.onPermissionDenied,this.onTokenExpired=e.onTokenExpired,this.registrationId=Q(this.organizationId,this.serviceId);}setServiceWorkerRegistration(e){this.serviceWorkerRegistration=e;}setVapidPublicKey(e){this.vapidPublicKey=e;}getRegistrationId(){return this.registrationId}isRegistered(){return this.registrationId!==null}getAuthMode(){return this.authContext.mode}updateToken(e){this.authContext=b(this.authContext,e),this.log(`Auth mode: ${this.authContext.mode}`);}async register(e={}){try{if(!this.serviceWorkerRegistration)throw new Error("Service worker not registered");if(!this.vapidPublicKey)throw new Error("VAPID public key not set. Call downloadConfig() first.");if(await this.requestPermission()!=="granted")return this.log("Notification permission denied"),this.onPermissionDenied?.(),null;let i=await this.subscribeToPush();if(!i)throw new Error("Failed to subscribe to push notifications");this.pushSubscription=i;let r=await L(),s=this.deviceDetector.getDeviceInfo(),o=this.deviceDetector.getPlatformInfo(),l=i.toJSON(),c={serviceId:this.serviceId,userEmail:e.userEmail,userId:v(e.userId)?e.userId:void 0,endpoint:i.endpoint,keys:{p256dh:l.keys?.p256dh||"",auth:l.keys?.auth||""},browserFingerprint:r||void 0,deviceType:s.deviceType,deviceModel:s.deviceModel,browserName:o.browser,browserVersion:o.browserVersion,osName:o.os,osVersion:o.osVersion,userAgent:o.userAgent,displayMode:"standalone",isInstalled:!0,timezone:e.timezone||Intl.DateTimeFormat().resolvedOptions().timeZone,language:e.language||navigator.language||"en-US"},d=`${this.serviceUrl}/api/v1/registration/register`,a=await h(this.authContext,"POST",d,c,this.onTokenExpired);if(!a.ok){let g=await a.text();throw new Error(`Registration failed: ${a.status} - ${g}`)}let p=await a.json();this.registrationId=p.registration_id,U(this.organizationId,this.serviceId,this.registrationId);let S={registrationId:p.registration_id,status:p.status||"active",createdAt:p.created_at||new Date().toISOString(),isActive:!0};return this.log(`Push registration successful: ${S.registrationId}`),this.onRegistered?.(S),S}catch(t){let i=t instanceof Error?t:new Error(String(t));return this.log(`Push registration failed: ${i.message}`,"error"),this.onError?.(i),null}}async unregister(){try{if(!this.registrationId)return this.log("No registration to unregister"),!0;this.pushSubscription&&(await this.pushSubscription.unsubscribe(),this.pushSubscription=null);let e=`${this.serviceUrl}/api/v1/registration/unregister`,t=await h(this.authContext,"POST",e,{registration_id:this.registrationId},this.onTokenExpired);return t.ok||this.log(`Backend unregistration failed: ${t.status}`,"warn"),O(this.organizationId,this.serviceId),this.registrationId=null,this.log("Push unregistration successful"),this.onUnregistered?.(),!0}catch(e){let t=e instanceof Error?e:new Error(String(e));return this.log(`Push unregistration failed: ${t.message}`,"error"),this.onError?.(t),false}}async updatePreferences(e){try{if(!this.registrationId)throw new Error("Not registered for push notifications");let t=`${this.serviceUrl}/api/v1/registration/update`,i=await h(this.authContext,"POST",t,{registration_id:this.registrationId,notification_topics:e.topics,timezone:e.timezone,language:e.language,is_active:e.isActive},this.onTokenExpired);if(!i.ok)throw new Error(`Update failed: ${i.status}`);return this.log("Preferences updated successfully"),!0}catch(t){let i=t instanceof Error?t:new Error(String(t));return this.log(`Failed to update preferences: ${i.message}`,"error"),this.onError?.(i),false}}async checkStatus(){try{if(!this.registrationId)return null;let e=`${this.serviceUrl}/api/v1/registration/status/${this.registrationId}`,t=await h(this.authContext,"GET",e,void 0,this.onTokenExpired);if(!t.ok){if(t.status===404)return O(this.organizationId,this.serviceId),this.registrationId=null,null;throw new Error(`Status check failed: ${t.status}`)}let i=await t.json();return {registrationId:i.registration_id,status:i.status,isActive:i.is_active,isOnline:i.is_online,lastActive:i.last_active,lastSeenOnline:i.last_seen_online,lastHeartbeat:i.last_heartbeat,installationDate:i.installation_date,notificationCount:i.notification_count,deviceInfo:i.device_info}}catch(e){let t=e instanceof Error?e:new Error(String(e));return this.log(`Status check failed: ${t.message}`,"error"),null}}async requestPermission(){return "Notification"in window?Notification.permission==="granted"?"granted":Notification.permission==="denied"?"denied":await Notification.requestPermission():"denied"}async subscribeToPush(){if(!this.serviceWorkerRegistration||!this.vapidPublicKey)return null;try{let e=await this.serviceWorkerRegistration.pushManager.getSubscription();if(!e){let t=this.urlBase64ToUint8Array(this.vapidPublicKey);e=await this.serviceWorkerRegistration.pushManager.subscribe({userVisibleOnly:!0,applicationServerKey:t.buffer});}return e}catch(e){return this.log(`Push subscription failed: ${e}`,"error"),null}}urlBase64ToUint8Array(e){let t="=".repeat((4-e.length%4)%4),i=(e+t).replace(/-/g,"+").replace(/_/g,"/"),r=atob(i),s=new Uint8Array(r.length);for(let o=0;o<r.length;++o)s[o]=r.charCodeAt(o);return s}log(e,t="log"){if(!this.debug)return;console[t](`[CloudSignal PWA Push] ${e}`);}};P();var de={"4g":3e4,"3g":6e4,"2g":12e4,"slow-2g":18e4,unknown:3e4},R=class{constructor(e){this.registrationId=null;this.intervalId=null;this.isRunning=false;this.isPausedForBattery=false;this.visibilityHandler=null;this.connectionChangeHandler=null;this.batteryManager=null;this.serviceUrl=e.serviceUrl,this.organizationId=e.organizationId,this.debug=e.debug??false,this.onHeartbeatSent=e.onHeartbeatSent,this.onHeartbeatError=e.onHeartbeatError,this.onIntervalChanged=e.onIntervalChanged,this.onPausedForBattery=e.onPausedForBattery,this.onResumedFromBattery=e.onResumedFromBattery,this.onTokenExpired=e.onTokenExpired,this.authContext=y({organizationId:e.organizationId,organizationSecret:e.organizationSecret,userToken:e.userToken}),this.config={enabled:e.config?.enabled??true,interval:e.config?.interval??3e4,autoStart:e.config?.autoStart??true,stopOnHidden:e.config?.stopOnHidden??true},this.adaptiveConfig={adaptToNetwork:e.adaptiveConfig?.adaptToNetwork??true,adaptToBattery:e.adaptiveConfig?.adaptToBattery??true,batteryPauseThreshold:e.adaptiveConfig?.batteryPauseThreshold??.15,intervals:{...de,...e.adaptiveConfig?.intervals}},this.currentInterval=this.config.interval;}setRegistrationId(e){this.registrationId=e,this.config.autoStart&&!this.isRunning&&this.config.enabled&&this.start();}start(){if(this.isRunning){this.log("Heartbeat already running");return}if(!this.registrationId||!v(this.registrationId)){this.log("Cannot start heartbeat: no valid registration ID","warn");return}if(!this.config.enabled){this.log("Heartbeat is disabled");return}this.isRunning=true,this.updateIntervalForNetwork(),this.log(`Starting heartbeat with interval ${this.currentInterval}ms`),this.sendHeartbeat(),this.startInterval(),this.config.stopOnHidden&&this.setupVisibilityHandler(),this.adaptiveConfig.adaptToNetwork&&this.setupNetworkChangeHandler(),this.adaptiveConfig.adaptToBattery&&this.setupBatteryMonitoring();}stop(){if(this.isRunning){if(this.isRunning=false,this.isPausedForBattery=false,this.intervalId&&(clearInterval(this.intervalId),this.intervalId=null),this.visibilityHandler&&(document.removeEventListener("visibilitychange",this.visibilityHandler),this.visibilityHandler=null),this.connectionChangeHandler){let e=navigator.connection;e&&e.removeEventListener("change",this.connectionChangeHandler),this.connectionChangeHandler=null;}this.log("Heartbeat stopped");}}isHeartbeatRunning(){return this.isRunning}getAuthMode(){return this.authContext.mode}updateToken(e){this.authContext=b(this.authContext,e),this.log(`Auth mode: ${this.authContext.mode}`);}async sendHeartbeat(){if(!this.registrationId||!v(this.registrationId))return this.log("Cannot send heartbeat: no valid registration ID","warn"),false;try{let e=`${this.serviceUrl}/api/v1/registration/heartbeat/${this.registrationId}`,t=await h(this.authContext,"POST",e,void 0,this.onTokenExpired);if(!t.ok)throw new Error(`Heartbeat failed: ${t.status}`);return this.log("Heartbeat sent successfully"),this.onHeartbeatSent?.(),!0}catch(e){let t=e instanceof Error?e:new Error(String(e));return this.log(`Heartbeat failed: ${t.message}`,"error"),this.onHeartbeatError?.(t),false}}updateConfig(e){let t=this.isRunning;t&&this.stop(),this.config={...this.config,...e},t&&this.config.enabled&&this.start();}getNetworkInfo(){let e=navigator.connection;return e?{effectiveType:e.effectiveType,saveData:e.saveData,downlink:e.downlink,rtt:e.rtt}:{}}async getBatteryInfo(){try{if(!("getBattery"in navigator))return null;let e=await navigator.getBattery();return {level:e.level,charging:e.charging}}catch{return null}}getCurrentInterval(){return this.currentInterval}isPausedDueToBattery(){return this.isPausedForBattery}startInterval(){this.intervalId&&clearInterval(this.intervalId),this.intervalId=setInterval(()=>{this.sendHeartbeat();},this.currentInterval);}updateIntervalForNetwork(){if(!this.adaptiveConfig.adaptToNetwork){this.currentInterval=this.config.interval;return}let e=navigator.connection;if(!e){this.currentInterval=this.config.interval;return}if(e.saveData){let r=Math.max(this.currentInterval,12e4);r!==this.currentInterval&&(this.currentInterval=r,this.log(`Interval increased to ${r}ms (saveData enabled)`),this.onIntervalChanged?.(r,"saveData"));return}let t=e.effectiveType||"unknown",i=this.adaptiveConfig.intervals[t]||this.config.interval;if(i!==this.currentInterval){let r=this.currentInterval;this.currentInterval=i,this.log(`Interval changed from ${r}ms to ${i}ms (${t})`),this.onIntervalChanged?.(i,t);}}setupNetworkChangeHandler(){let e=navigator.connection;e&&(this.connectionChangeHandler=()=>{let t=this.currentInterval;this.updateIntervalForNetwork(),t!==this.currentInterval&&this.isRunning&&!this.isPausedForBattery&&this.startInterval();},e.addEventListener("change",this.connectionChangeHandler));}async setupBatteryMonitoring(){try{if(!("getBattery"in navigator))return;this.batteryManager=await navigator.getBattery();let e=()=>{if(!this.batteryManager)return;let t=this.batteryManager.level,i=this.batteryManager.charging;t<=this.adaptiveConfig.batteryPauseThreshold&&!i?!this.isPausedForBattery&&this.isRunning&&(this.isPausedForBattery=!0,this.intervalId&&(clearInterval(this.intervalId),this.intervalId=null),this.log(`Heartbeat paused (battery at ${Math.round(t*100)}%)`),this.onPausedForBattery?.()):this.isPausedForBattery&&this.isRunning&&(this.isPausedForBattery=!1,this.startInterval(),this.log(`Heartbeat resumed (battery at ${Math.round(t*100)}%)`),this.onResumedFromBattery?.());};e(),this.batteryManager.addEventListener("levelchange",e),this.batteryManager.addEventListener("chargingchange",e);}catch{}}setupVisibilityHandler(){this.visibilityHandler=()=>{document.hidden?(this.intervalId&&(clearInterval(this.intervalId),this.intervalId=null),this.log("Heartbeat paused (page hidden)")):this.isRunning&&!this.intervalId&&!this.isPausedForBattery&&(this.sendHeartbeat(),this.startInterval(),this.log("Heartbeat resumed (page visible)"));},document.addEventListener("visibilitychange",this.visibilityHandler);}log(e,t="log"){if(!this.debug)return;console[t](`[CloudSignal PWA Heartbeat] ${e}`);}};var E=class{constructor(e={}){this.wakeLock=null;this.visibilityHandler=null;this.releaseHandler=null;this.shouldReacquire=false;this.debug=e.debug??false,this.onAcquired=e.onAcquired,this.onReleased=e.onReleased,this.onError=e.onError,this.config={enabled:e.config?.enabled??true,autoReacquire:e.config?.autoReacquire??true};}isSupported(){return "wakeLock"in navigator}getState(){return {isActive:this.wakeLock!==null&&!this.wakeLock.released,isSupported:this.isSupported(),type:"screen",acquiredAt:this.wakeLock&&!this.wakeLock.released?Date.now():void 0}}async acquire(){if(!this.config.enabled)return this.log("Wake lock is disabled"),false;if(!this.isSupported())return this.log("Wake Lock API not supported"),this.onError?.({timestamp:Date.now(),error:"Wake Lock API not supported",errorName:"NotSupportedError"}),false;if(this.wakeLock&&!this.wakeLock.released)return this.log("Wake lock already active"),true;try{return this.wakeLock=await navigator.wakeLock.request("screen"),this.shouldReacquire=!0,this.releaseHandler=()=>{this.handleRelease("system");},this.wakeLock.addEventListener("release",this.releaseHandler),this.config.autoReacquire&&this.setupVisibilityHandler(),this.log("Wake lock acquired"),this.onAcquired?.({timestamp:Date.now()}),!0}catch(e){let t=e instanceof Error?e:new Error(String(e));return this.log(`Failed to acquire wake lock: ${t.message}`,"error"),this.onError?.({timestamp:Date.now(),error:t.message,errorName:t.name}),false}}async release(){if(this.shouldReacquire=false,!!this.wakeLock){try{this.releaseHandler&&(this.wakeLock.removeEventListener("release",this.releaseHandler),this.releaseHandler=null),await this.wakeLock.release(),this.wakeLock=null,this.log("Wake lock released manually"),this.onReleased?.({timestamp:Date.now(),reason:"manual"});}catch(e){let t=e instanceof Error?e:new Error(String(e));this.log(`Failed to release wake lock: ${t.message}`,"error");}this.removeVisibilityHandler();}}async toggle(){return this.wakeLock&&!this.wakeLock.released?(await this.release(),false):this.acquire()}isActive(){return this.wakeLock!==null&&!this.wakeLock.released}async destroy(){await this.release(),this.removeVisibilityHandler();}handleRelease(e){this.wakeLock=null,this.log(`Wake lock released by ${e}`),this.onReleased?.({timestamp:Date.now(),reason:e});}setupVisibilityHandler(){this.visibilityHandler||(this.visibilityHandler=async()=>{document.visibilityState==="visible"&&this.shouldReacquire?(this.log("Page visible, attempting to reacquire wake lock"),await this.acquire()):document.visibilityState==="hidden"&&this.wakeLock&&this.log("Page hidden, wake lock will be released");},document.addEventListener("visibilitychange",this.visibilityHandler));}removeVisibilityHandler(){this.visibilityHandler&&(document.removeEventListener("visibilitychange",this.visibilityHandler),this.visibilityHandler=null);}log(e,t="log"){if(!this.debug&&t==="log")return;console[t](`[CloudSignal PWA WakeLock] ${e}`);}};var ge="CloudSignalPWA";var u="offlineQueue",T=class{constructor(e={}){this.db=null;this.isProcessing=false;this.onlineHandler=null;this.debug=e.debug??false,this.onRequestQueued=e.onRequestQueued,this.onRequestProcessed=e.onRequestProcessed,this.onQueueEmpty=e.onQueueEmpty,this.onError=e.onError,this.config={enabled:e.config?.enabled??true,maxQueueSize:e.config?.maxQueueSize??100,maxAge:e.config?.maxAge??1440*60*1e3,baseRetryDelay:e.config?.baseRetryDelay??1e3,maxRetryDelay:e.config?.maxRetryDelay??6e4,defaultMaxRetries:e.config?.defaultMaxRetries??5,processOnOnline:e.config?.processOnOnline??true};}async initialize(){if(!this.config.enabled){this.log("Offline queue is disabled");return}try{await this.openDatabase(),this.config.processOnOnline&&(this.onlineHandler=()=>{this.log("Network online, processing queue"),this.processQueue();},window.addEventListener("online",this.onlineHandler)),await this.cleanupOldRequests(),this.log("Offline queue manager initialized");}catch(e){let t=e instanceof Error?e:new Error(String(e));this.log(`Failed to initialize: ${t.message}`,"error"),this.onError?.(t);}}destroy(){this.onlineHandler&&(window.removeEventListener("online",this.onlineHandler),this.onlineHandler=null),this.db&&(this.db.close(),this.db=null);}async queueRequest(e,t,i={}){if(!this.config.enabled||!this.db)return null;try{(await this.getStats()).totalQueued>=this.config.maxQueueSize&&(this.log("Queue is full, removing oldest request"),await this.removeOldestRequest());let s={url:e,method:t,headers:i.headers,body:i.body,queuedAt:Date.now(),retryCount:0,maxRetries:i.maxRetries??this.config.defaultMaxRetries,requestType:i.requestType??"custom",priority:i.priority??0,metadata:i.metadata},o=await this.addToStore(s);return s.id=o,this.log(`Queued request: ${t} ${e} (id: ${o})`),this.onRequestQueued?.(s),o}catch(r){let s=r instanceof Error?r:new Error(String(r));return this.log(`Failed to queue request: ${s.message}`,"error"),this.onError?.(s),null}}async processQueue(){if(!this.config.enabled||!this.db||this.isProcessing)return [];if(!navigator.onLine)return this.log("Offline, skipping queue processing"),[];this.isProcessing=true;let e=[];try{let t=await this.getAllRequests();t.sort((r,s)=>r.priority!==s.priority?s.priority-r.priority:r.queuedAt-s.queuedAt),this.log(`Processing ${t.length} queued requests`);for(let r of t){if(!navigator.onLine){this.log("Went offline during processing, stopping");break}let s=await this.processRequest(r);e.push(s),s.success||!s.shouldRetry?await this.removeFromStore(r.id):await this.updateRetryCount(r),this.onRequestProcessed?.(s),await this.delay(100);}let i=await this.getQueueCount();i===0&&this.onQueueEmpty?.(),this.log(`Processed ${e.length} requests, ${i} remaining`);}catch(t){let i=t instanceof Error?t:new Error(String(t));this.log(`Error processing queue: ${i.message}`,"error"),this.onError?.(i);}finally{this.isProcessing=false;}return e}async processRequest(e){let t={id:e.id,success:false,shouldRetry:false};try{let i=await fetch(e.url,{method:e.method,headers:e.headers,body:e.body});t.statusCode=i.status,t.success=i.ok,i.ok||(t.shouldRetry=this.shouldRetryStatus(i.status,e),t.error=`HTTP ${i.status}`),this.log(`Request ${e.id}: ${t.success?"success":"failed"} (${i.status})`);}catch(i){let r=i instanceof Error?i:new Error(String(i));t.error=r.message,t.shouldRetry=e.retryCount<e.maxRetries,this.log(`Request ${e.id} failed: ${r.message}`,"error");}return t}shouldRetryStatus(e,t){return t.retryCount>=t.maxRetries?false:e>=500||e===408||e===429||e===0}async updateRetryCount(e){e.retryCount++;let i=this.db.transaction([u],"readwrite").objectStore(u);await this.promisifyRequest(i.put(e));}async getStats(){let e={totalQueued:0,byType:{registration:0,heartbeat:0,analytics:0,preferences:0,unregister:0,custom:0}};if(!this.db)return e;try{let t=await this.getAllRequests();e.totalQueued=t.length;for(let i of t)e.byType[i.requestType]++,(!e.oldestRequest||i.queuedAt<e.oldestRequest)&&(e.oldestRequest=i.queuedAt),(!e.newestRequest||i.queuedAt>e.newestRequest)&&(e.newestRequest=i.queuedAt);}catch(t){this.log(`Failed to get stats: ${t}`,"error");}return e}async clearQueue(){if(!this.db)return;let t=this.db.transaction([u],"readwrite").objectStore(u);await this.promisifyRequest(t.clear()),this.log("Queue cleared");}async hasPendingRequests(){return await this.getQueueCount()>0}async getQueueCount(){if(!this.db)return 0;let t=this.db.transaction([u],"readonly").objectStore(u);return this.promisifyRequest(t.count())}async openDatabase(){return new Promise((e,t)=>{let i=indexedDB.open(ge,2);i.onerror=()=>t(i.error),i.onsuccess=()=>{this.db=i.result,e();},i.onupgradeneeded=r=>{let s=r.target.result;if(!s.objectStoreNames.contains(u)){let o=s.createObjectStore(u,{keyPath:"id",autoIncrement:true});o.createIndex("queuedAt","queuedAt",{unique:false}),o.createIndex("requestType","requestType",{unique:false}),o.createIndex("priority","priority",{unique:false});}if(s.objectStoreNames.contains("badge")||s.createObjectStore("badge"),!s.objectStoreNames.contains("notifications")){let o=s.createObjectStore("notifications",{keyPath:"id",autoIncrement:true});o.createIndex("timestamp","timestamp",{unique:false}),o.createIndex("read","read",{unique:false});}s.objectStoreNames.contains("userPreferences")||s.createObjectStore("userPreferences"),s.objectStoreNames.contains("syncQueue")||s.createObjectStore("syncQueue",{keyPath:"id",autoIncrement:true}).createIndex("timestamp","timestamp",{unique:false});};})}async addToStore(e){let i=this.db.transaction([u],"readwrite").objectStore(u);return this.promisifyRequest(i.add(e))}async removeFromStore(e){let i=this.db.transaction([u],"readwrite").objectStore(u);await this.promisifyRequest(i.delete(e));}async getAllRequests(){let t=this.db.transaction([u],"readonly").objectStore(u);return this.promisifyRequest(t.getAll())}async removeOldestRequest(){let t=this.db.transaction([u],"readwrite").objectStore(u),r=t.index("queuedAt").openCursor();return new Promise((s,o)=>{r.onsuccess=l=>{let c=l.target.result;c&&t.delete(c.primaryKey),s();},r.onerror=()=>o(r.error);})}async cleanupOldRequests(){let e=Date.now()-this.config.maxAge,i=this.db.transaction([u],"readwrite").objectStore(u),r=i.index("queuedAt"),s=IDBKeyRange.upperBound(e),o=r.openCursor(s),l=0;return new Promise(c=>{o.onsuccess=d=>{let a=d.target.result;a?(i.delete(a.primaryKey),l++,a.continue()):(l>0&&this.log(`Cleaned up ${l} old requests`),c());},o.onerror=()=>c();})}promisifyRequest(e){return new Promise((t,i)=>{e.onsuccess=()=>t(e.result),e.onerror=()=>i(e.error);})}delay(e){return new Promise(t=>setTimeout(t,e))}log(e,t="log"){if(!this.debug&&t==="log")return;console[t](`[CloudSignal PWA OfflineQueue] ${e}`);}};var A={en:{title:"Install this app",description:"Add this app to your home screen for the best experience.",buttonText:"Show me how",closeText:"Not now",step1:"Tap the Share button at the bottom of Safari",step2:'Scroll down and tap "Add to Home Screen"',step3:'Tap "Add" in the top right corner',shareIconHint:"Look for the Share icon",shareIconDescription:"It's the square with an arrow pointing up"},es:{title:"Instalar esta aplicaci\xF3n",description:"A\xF1ade esta aplicaci\xF3n a tu pantalla de inicio para una mejor experiencia.",buttonText:"Mostrar c\xF3mo",closeText:"Ahora no",step1:"Toca el bot\xF3n Compartir en la parte inferior de Safari",step2:'Despl\xE1zate hacia abajo y toca "A\xF1adir a pantalla de inicio"',step3:'Toca "A\xF1adir" en la esquina superior derecha',shareIconHint:"Busca el icono de Compartir",shareIconDescription:"Es el cuadrado con una flecha apuntando hacia arriba"},fr:{title:"Installer cette application",description:"Ajoutez cette application \xE0 votre \xE9cran d'accueil pour une meilleure exp\xE9rience.",buttonText:"Montrez-moi comment",closeText:"Pas maintenant",step1:"Appuyez sur le bouton Partager en bas de Safari",step2:`Faites d\xE9filer vers le bas et appuyez sur "Sur l'\xE9cran d'accueil"`,step3:'Appuyez sur "Ajouter" dans le coin sup\xE9rieur droit',shareIconHint:"Recherchez l'ic\xF4ne Partager",shareIconDescription:"C'est le carr\xE9 avec une fl\xE8che pointant vers le haut"},de:{title:"Diese App installieren",description:"F\xFCgen Sie diese App zu Ihrem Startbildschirm hinzu f\xFCr das beste Erlebnis.",buttonText:"Zeig mir wie",closeText:"Nicht jetzt",step1:"Tippen Sie auf die Teilen-Schaltfl\xE4che unten in Safari",step2:'Scrollen Sie nach unten und tippen Sie auf "Zum Home-Bildschirm"',step3:'Tippen Sie oben rechts auf "Hinzuf\xFCgen"',shareIconHint:"Suchen Sie das Teilen-Symbol",shareIconDescription:"Es ist das Quadrat mit einem Pfeil nach oben"},it:{title:"Installa questa app",description:"Aggiungi questa app alla schermata Home per un'esperienza migliore.",buttonText:"Mostrami come",closeText:"Non ora",step1:"Tocca il pulsante Condividi nella parte inferiore di Safari",step2:'Scorri verso il basso e tocca "Aggiungi a Home"',step3:`Tocca "Aggiungi" nell'angolo in alto a destra`,shareIconHint:"Cerca l'icona Condividi",shareIconDescription:"\xC8 il quadrato con una freccia che punta verso l'alto"},pt:{title:"Instalar este aplicativo",description:"Adicione este aplicativo \xE0 tela inicial para a melhor experi\xEAncia.",buttonText:"Mostre-me como",closeText:"Agora n\xE3o",step1:"Toque no bot\xE3o Compartilhar na parte inferior do Safari",step2:'Role para baixo e toque em "Adicionar \xE0 Tela de In\xEDcio"',step3:'Toque em "Adicionar" no canto superior direito',shareIconHint:"Procure o \xEDcone Compartilhar",shareIconDescription:"\xC9 o quadrado com uma seta apontando para cima"},nl:{title:"Installeer deze app",description:"Voeg deze app toe aan je beginscherm voor de beste ervaring.",buttonText:"Laat me zien hoe",closeText:"Niet nu",step1:"Tik op de Deel-knop onderaan Safari",step2:'Scroll naar beneden en tik op "Zet op beginscherm"',step3:'Tik rechtsboven op "Voeg toe"',shareIconHint:"Zoek het Deel-icoon",shareIconDescription:"Het is het vierkant met een pijl omhoog"},ru:{title:"\u0423\u0441\u0442\u0430\u043D\u043E\u0432\u0438\u0442\u044C \u043F\u0440\u0438\u043B\u043E\u0436\u0435\u043D\u0438\u0435",description:"\u0414\u043E\u0431\u0430\u0432\u044C\u0442\u0435 \u044D\u0442\u043E \u043F\u0440\u0438\u043B\u043E\u0436\u0435\u043D\u0438\u0435 \u043D\u0430 \u0433\u043B\u0430\u0432\u043D\u044B\u0439 \u044D\u043A\u0440\u0430\u043D \u0434\u043B\u044F \u043B\u0443\u0447\u0448\u0435\u0433\u043E \u043E\u043F\u044B\u0442\u0430.",buttonText:"\u041F\u043E\u043A\u0430\u0436\u0438\u0442\u0435 \u043A\u0430\u043A",closeText:"\u041D\u0435 \u0441\u0435\u0439\u0447\u0430\u0441",step1:'\u041D\u0430\u0436\u043C\u0438\u0442\u0435 \u043A\u043D\u043E\u043F\u043A\u0443 "\u041F\u043E\u0434\u0435\u043B\u0438\u0442\u044C\u0441\u044F" \u0432\u043D\u0438\u0437\u0443 Safari',step2:'\u041F\u0440\u043E\u043A\u0440\u0443\u0442\u0438\u0442\u0435 \u0432\u043D\u0438\u0437 \u0438 \u043D\u0430\u0436\u043C\u0438\u0442\u0435 "\u041D\u0430 \u044D\u043A\u0440\u0430\u043D \u0414\u043E\u043C\u043E\u0439"',step3:'\u041D\u0430\u0436\u043C\u0438\u0442\u0435 "\u0414\u043E\u0431\u0430\u0432\u0438\u0442\u044C" \u0432 \u043F\u0440\u0430\u0432\u043E\u043C \u0432\u0435\u0440\u0445\u043D\u0435\u043C \u0443\u0433\u043B\u0443',shareIconHint:'\u041D\u0430\u0439\u0434\u0438\u0442\u0435 \u0437\u043D\u0430\u0447\u043E\u043A "\u041F\u043E\u0434\u0435\u043B\u0438\u0442\u044C\u0441\u044F"',shareIconDescription:"\u042D\u0442\u043E \u043A\u0432\u0430\u0434\u0440\u0430\u0442 \u0441\u043E \u0441\u0442\u0440\u0435\u043B\u043A\u043E\u0439 \u0432\u0432\u0435\u0440\u0445"},zh:{title:"\u5B89\u88C5\u6B64\u5E94\u7528",description:"\u5C06\u6B64\u5E94\u7528\u6DFB\u52A0\u5230\u4E3B\u5C4F\u5E55\u4EE5\u83B7\u5F97\u6700\u4F73\u4F53\u9A8C\u3002",buttonText:"\u663E\u793A\u65B9\u6CD5",closeText:"\u6682\u65F6\u4E0D\u8981",step1:"\u70B9\u51FBSafari\u5E95\u90E8\u7684\u5206\u4EAB\u6309\u94AE",step2:'\u5411\u4E0B\u6EDA\u52A8\u5E76\u70B9\u51FB"\u6DFB\u52A0\u5230\u4E3B\u5C4F\u5E55"',step3:'\u70B9\u51FB\u53F3\u4E0A\u89D2\u7684"\u6DFB\u52A0"',shareIconHint:"\u627E\u5230\u5206\u4EAB\u56FE\u6807",shareIconDescription:"\u662F\u4E00\u4E2A\u5E26\u6709\u5411\u4E0A\u7BAD\u5934\u7684\u65B9\u6846"},ja:{title:"\u3053\u306E\u30A2\u30D7\u30EA\u3092\u30A4\u30F3\u30B9\u30C8\u30FC\u30EB",description:"\u30DB\u30FC\u30E0\u753B\u9762\u306B\u8FFD\u52A0\u3057\u3066\u6700\u9AD8\u306E\u4F53\u9A13\u3092\u3002",buttonText:"\u65B9\u6CD5\u3092\u898B\u308B",closeText:"\u4ECA\u306F\u3057\u306A\u3044",step1:"Safari\u306E\u4E0B\u90E8\u306B\u3042\u308B\u5171\u6709\u30DC\u30BF\u30F3\u3092\u30BF\u30C3\u30D7",step2:"\u4E0B\u306B\u30B9\u30AF\u30ED\u30FC\u30EB\u3057\u3066\u300C\u30DB\u30FC\u30E0\u753B\u9762\u306B\u8FFD\u52A0\u300D\u3092\u30BF\u30C3\u30D7",step3:"\u53F3\u4E0A\u306E\u300C\u8FFD\u52A0\u300D\u3092\u30BF\u30C3\u30D7",shareIconHint:"\u5171\u6709\u30A2\u30A4\u30B3\u30F3\u3092\u63A2\u3057\u3066\u304F\u3060\u3055\u3044",shareIconDescription:"\u4E0A\u5411\u304D\u77E2\u5370\u306E\u3042\u308B\u56DB\u89D2\u5F62\u3067\u3059"},ko:{title:"\uC774 \uC571 \uC124\uCE58",description:"\uCD5C\uACE0\uC758 \uACBD\u9A13\uC744 \uC704\uD574 \uD648 \uD654\uBA74\uC5D0 \uCD94\uAC00\uD558\uC138\uC694.",buttonText:"\uBC29\uBC95 \uBCF4\uAE30",closeText:"\uB098\uC911\uC5D0",step1:"Safari \uD558\uB2E8\uC758 \uACF5\uC720 \uBC84\uD2BC\uC744 \uD0ED\uD558\uC138\uC694",step2:'\uC544\uB798\uB85C \uC2A4\uD06C\uB864\uD558\uC5EC "\uD648 \uD654\uBA74\uC5D0 \uCD94\uAC00"\uB97C \uD0ED\uD558\uC138\uC694',step3:'\uC624\uB978\uCABD \uC0C1\uB2E8\uC758 "\uCD94\uAC00"\uB97C \uD0ED\uD558\uC138\uC694',shareIconHint:"\uACF5\uC720 \uC544\uC774\uCF58\uC744 \uCC3E\uC73C\uC138\uC694",shareIconDescription:"\uC704\uCABD \uD654\uC0B4\uD45C\uAC00 \uC788\uB294 \uC0AC\uAC01\uD615\uC785\uB2C8\uB2E4"},ar:{title:"\u062A\u062B\u0628\u064A\u062A \u0647\u0630\u0627 \u0627\u0644\u062A\u0637\u0628\u064A\u0642",description:"\u0623\u0636\u0641 \u0647\u0630\u0627 \u0627\u0644\u062A\u0637\u0628\u064A\u0642 \u0625\u0644\u0649 \u0627\u0644\u0634\u0627\u0634\u0629 \u0627\u0644\u0631\u0626\u064A\u0633\u064A\u0629 \u0644\u0644\u062D\u0635\u0648\u0644 \u0639\u0644\u0649 \u0623\u0641\u0636\u0644 \u062A\u062C\u0631\u0628\u0629.",buttonText:"\u0623\u0631\u0646\u064A \u0643\u064A\u0641",closeText:"\u0644\u064A\u0633 \u0627\u0644\u0622\u0646",step1:"\u0627\u0636\u063A\u0637 \u0639\u0644\u0649 \u0632\u0631 \u0627\u0644\u0645\u0634\u0627\u0631\u0643\u0629 \u0641\u064A \u0623\u0633\u0641\u0644 Safari",step2:'\u0645\u0631\u0631 \u0644\u0623\u0633\u0641\u0644 \u0648\u0627\u0636\u063A\u0637 \u0639\u0644\u0649 "\u0625\u0636\u0627\u0641\u0629 \u0625\u0644\u0649 \u0627\u0644\u0634\u0627\u0634\u0629 \u0627\u0644\u0631\u0626\u064A\u0633\u064A\u0629"',step3:'\u0627\u0636\u063A\u0637 \u0639\u0644\u0649 "\u0625\u0636\u0627\u0641\u0629" \u0641\u064A \u0627\u0644\u0632\u0627\u0648\u064A\u0629 \u0627\u0644\u0639\u0644\u0648\u064A\u0629 \u0627\u0644\u064A\u0645\u0646\u0649',shareIconHint:"\u0627\u0628\u062D\u062B \u0639\u0646 \u0623\u064A\u0642\u0648\u0646\u0629 \u0627\u0644\u0645\u0634\u0627\u0631\u0643\u0629",shareIconDescription:"\u0647\u0648 \u0645\u0631\u0628\u0639 \u0645\u0639 \u0633\u0647\u0645 \u064A\u0634\u064A\u0631 \u0644\u0623\u0639\u0644\u0649"},he:{title:"\u05D4\u05EA\u05E7\u05DF \u05D0\u05E4\u05DC\u05D9\u05E7\u05E6\u05D9\u05D4 \u05D6\u05D5",description:"\u05D4\u05D5\u05E1\u05E3 \u05D0\u05E4\u05DC\u05D9\u05E7\u05E6\u05D9\u05D4 \u05D6\u05D5 \u05DC\u05DE\u05E1\u05DA \u05D4\u05D1\u05D9\u05EA \u05DC\u05D7\u05D5\u05D5\u05D9\u05D4 \u05D4\u05D8\u05D5\u05D1\u05D4 \u05D1\u05D9\u05D5\u05EA\u05E8.",buttonText:"\u05D4\u05E8\u05D0\u05D4 \u05DC\u05D9 \u05D0\u05D9\u05DA",closeText:"\u05DC\u05D0 \u05E2\u05DB\u05E9\u05D9\u05D5",step1:"\u05D4\u05E7\u05E9 \u05E2\u05DC \u05DB\u05E4\u05EA\u05D5\u05E8 \u05D4\u05E9\u05D9\u05EA\u05D5\u05E3 \u05D1\u05EA\u05D7\u05EA\u05D9\u05EA Safari",step2:'\u05D2\u05DC\u05D5\u05DC \u05DC\u05DE\u05D8\u05D4 \u05D5\u05D4\u05E7\u05E9 \u05E2\u05DC "\u05D4\u05D5\u05E1\u05E3 \u05DC\u05DE\u05E1\u05DA \u05D4\u05D1\u05D9\u05EA"',step3:'\u05D4\u05E7\u05E9 \u05E2\u05DC "\u05D4\u05D5\u05E1\u05E3" \u05D1\u05E4\u05D9\u05E0\u05D4 \u05D4\u05D9\u05DE\u05E0\u05D9\u05EA \u05D4\u05E2\u05DC\u05D9\u05D5\u05E0\u05D4',shareIconHint:"\u05D7\u05E4\u05E9 \u05D0\u05EA \u05E1\u05DE\u05DC \u05D4\u05E9\u05D9\u05EA\u05D5\u05E3",shareIconDescription:"\u05D6\u05D4 \u05E8\u05D9\u05D1\u05D5\u05E2 \u05E2\u05DD \u05D7\u05E5 \u05DE\u05E6\u05D1\u05D9\u05E2 \u05DC\u05DE\u05E2\u05DC\u05D4"},hi:{title:"\u092F\u0939 \u0910\u092A \u0907\u0902\u0938\u094D\u091F\u0949\u0932 \u0915\u0930\u0947\u0902",description:"\u092C\u0947\u0939\u0924\u0930 \u0905\u0928\u0941\u092D\u0935 \u0915\u0947 \u0932\u093F\u090F \u0907\u0938 \u0910\u092A \u0915\u094B \u0939\u094B\u092E \u0938\u094D\u0915\u094D\u0930\u0940\u0928 \u092A\u0930 \u091C\u094B\u0921\u093C\u0947\u0902\u0964",buttonText:"\u092E\u0941\u091D\u0947 \u0926\u093F\u0916\u093E\u0913 \u0915\u0948\u0938\u0947",closeText:"\u0905\u092D\u0940 \u0928\u0939\u0940\u0902",step1:"Safari \u0915\u0947 \u0928\u0940\u091A\u0947 \u0936\u0947\u092F\u0930 \u092C\u091F\u0928 \u092A\u0930 \u091F\u0948\u092A \u0915\u0930\u0947\u0902",step2:'\u0928\u0940\u091A\u0947 \u0938\u094D\u0915\u094D\u0930\u0949\u0932 \u0915\u0930\u0947\u0902 \u0914\u0930 "\u0939\u094B\u092E \u0938\u094D\u0915\u094D\u0930\u0940\u0928 \u092E\u0947\u0902 \u091C\u094B\u0921\u093C\u0947\u0902" \u092A\u0930 \u091F\u0948\u092A \u0915\u0930\u0947\u0902',step3:'\u090A\u092A\u0930 \u0926\u093E\u090F\u0902 \u0915\u094B\u0928\u0947 \u092E\u0947\u0902 "\u091C\u094B\u0921\u093C\u0947\u0902" \u092A\u0930 \u091F\u0948\u092A \u0915\u0930\u0947\u0902',shareIconHint:"\u0936\u0947\u092F\u0930 \u0906\u0907\u0915\u0928 \u0916\u094B\u091C\u0947\u0902",shareIconDescription:"\u092F\u0939 \u090A\u092A\u0930 \u0915\u0940 \u0913\u0930 \u0924\u0940\u0930 \u0935\u093E\u0932\u093E \u0935\u0930\u094D\u0917 \u0939\u0948"},tr:{title:"Bu uygulamay\u0131 y\xFCkle",description:"En iyi deneyim i\xE7in bu uygulamay\u0131 ana ekran\u0131n\u0131za ekleyin.",buttonText:"Nas\u0131l yap\u0131l\u0131r g\xF6ster",closeText:"\u015Eimdi de\u011Fil",step1:"Safari'nin alt\u0131ndaki Payla\u015F d\xFC\u011Fmesine dokunun",step2:'A\u015Fa\u011F\u0131 kayd\u0131r\u0131n ve "Ana Ekrana Ekle"ye dokunun',step3:'Sa\u011F \xFCst k\xF6\u015Fedeki "Ekle"ye dokunun',shareIconHint:"Payla\u015F simgesini aray\u0131n",shareIconDescription:"Yukar\u0131 bakan oklu bir karedir"},pl:{title:"Zainstaluj t\u0119 aplikacj\u0119",description:"Dodaj t\u0119 aplikacj\u0119 do ekranu g\u0142\xF3wnego, aby uzyska\u0107 najlepsze wra\u017Cenia.",buttonText:"Poka\u017C mi jak",closeText:"Nie teraz",step1:"Dotknij przycisku Udost\u0119pnij na dole Safari",step2:'Przewi\u0144 w d\xF3\u0142 i dotknij "Dodaj do ekranu pocz\u0105tkowego"',step3:'Dotknij "Dodaj" w prawym g\xF3rnym rogu',shareIconHint:"Poszukaj ikony Udost\u0119pnij",shareIconDescription:"To kwadrat ze strza\u0142k\u0105 skierowan\u0105 w g\xF3r\u0119"},sv:{title:"Installera denna app",description:"L\xE4gg till denna app p\xE5 hemsk\xE4rmen f\xF6r b\xE4sta upplevelse.",buttonText:"Visa mig hur",closeText:"Inte nu",step1:"Tryck p\xE5 Dela-knappen l\xE4ngst ner i Safari",step2:'Scrolla ner och tryck p\xE5 "L\xE4gg till p\xE5 hemsk\xE4rmen"',step3:'Tryck p\xE5 "L\xE4gg till" i \xF6vre h\xF6gra h\xF6rnet',shareIconHint:"Leta efter Dela-ikonen",shareIconDescription:"Det \xE4r kvadraten med en pil som pekar upp\xE5t"},da:{title:"Installer denne app",description:"F\xF8j denne app til din startsk\xE6rm for den bedste oplevelse.",buttonText:"Vis mig hvordan",closeText:"Ikke nu",step1:"Tryk p\xE5 Del-knappen nederst i Safari",step2:'Rul ned og tryk p\xE5 "F\xF8j til hjemmesk\xE6rm"',step3:'Tryk p\xE5 "Tilf\xF8j" i \xF8verste h\xF8jre hj\xF8rne',shareIconHint:"Kig efter Del-ikonet",shareIconDescription:"Det er firkanten med en pil, der peger opad"},no:{title:"Installer denne appen",description:"Legg til denne appen p\xE5 startskjermen for best opplevelse.",buttonText:"Vis meg hvordan",closeText:"Ikke n\xE5",step1:"Trykk p\xE5 Del-knappen nederst i Safari",step2:'Rull ned og trykk p\xE5 "Legg til p\xE5 Hjem-skjerm"',step3:'Trykk p\xE5 "Legg til" \xF8verst til h\xF8yre',shareIconHint:"Se etter Del-ikonet",shareIconDescription:"Det er firkanten med en pil som peker oppover"},fi:{title:"Asenna t\xE4m\xE4 sovellus",description:"Lis\xE4\xE4 t\xE4m\xE4 sovellus aloitusn\xE4yt\xF6lle parhaan kokemuksen saamiseksi.",buttonText:"N\xE4yt\xE4 miten",closeText:"Ei nyt",step1:"Napauta Jaa-painiketta Safarin alareunassa",step2:'Vierit\xE4 alas ja napauta "Lis\xE4\xE4 Koti-valikkoon"',step3:'Napauta "Lis\xE4\xE4" oikeassa yl\xE4kulmassa',shareIconHint:"Etsi Jaa-kuvake",shareIconDescription:"Se on neli\xF6, jossa on yl\xF6sp\xE4in osoittava nuoli"}};function C(){let n=navigator.language?.toLowerCase()||"en",e=n.split("-")[0];return e in A?e:n.startsWith("zh")?"zh":n.startsWith("pt")?"pt":n.startsWith("no")||n.startsWith("nb")||n.startsWith("nn")?"no":"en"}var D="cloudsignal_pwa_ios_banner_dismissed",m="cloudsignal-ios-install-banner",he={backgroundColor:"#ffffff",textColor:"#1a1a1a",buttonBackgroundColor:"#007AFF",buttonTextColor:"#ffffff",borderRadius:"16px",boxShadow:"0 4px 24px rgba(0, 0, 0, 0.15)"},B=class{constructor(e={}){this.bannerElement=null;this.overlayElement=null;this.debug=e.debug??false,this.onShow=e.onShow,this.onDismiss=e.onDismiss,this.onInstallClick=e.onInstallClick,this.language=e.language??C();let t=A[this.language];this.strings={...t,...e.customStrings},this.config={enabled:e.config?.enabled??true,title:e.config?.title??this.strings.title,description:e.config?.description??this.strings.description,buttonText:e.config?.buttonText??this.strings.buttonText,closeText:e.config?.closeText??this.strings.closeText,iconUrl:e.config?.iconUrl,customStyles:e.config?.customStyles??{},showDelay:e.config?.showDelay??3e3,dismissalDays:e.config?.dismissalDays??7,position:e.config?.position??"bottom"},this.styles={...he,...this.config.customStyles},this.log(`Initialized with language: ${this.language}`);}getLanguage(){return this.language}getStrings(){return this.strings}setLanguage(e){this.language=e;let t=A[e];this.strings={...t},this.config.title=this.strings.title,this.config.description=this.strings.description,this.config.buttonText=this.strings.buttonText,this.config.closeText=this.strings.closeText,this.log(`Language changed to: ${e}`);}getState(){return {isVisible:this.bannerElement!==null,wasDismissed:this.wasDismissed(),isEligible:this.isEligible(),isInstalled:this.isInstalled()}}isEligible(){let e=navigator.userAgent;return !(!(/iPad|iPhone|iPod/.test(e)&&!window.MSStream)||!(/Safari/i.test(e)&&!/Chrome|CriOS|FxiOS|EdgiOS/i.test(e))||this.isInstalled())}isInstalled(){return !!(navigator.standalone===true||window.matchMedia("(display-mode: standalone)").matches)}wasDismissed(){try{let e=localStorage.getItem(D);if(!e)return !1;let t=parseInt(e,10);return (Date.now()-t)/(1e3*60*60*24)>this.config.dismissalDays?(localStorage.removeItem(D),!1):!0}catch{return false}}async show(){return this.config.enabled?this.isEligible()?this.wasDismissed()?(this.log("Banner was dismissed recently"),false):this.bannerElement?(this.log("Banner already visible"),true):(this.config.showDelay>0&&await new Promise(e=>setTimeout(e,this.config.showDelay)),!this.isEligible()||this.wasDismissed()?false:(this.createBanner(),this.log("Banner shown"),this.onShow?.(),true)):(this.log("Device not eligible for iOS install banner"),false):(this.log("Banner is disabled"),false)}hide(){this.bannerElement&&(this.bannerElement.remove(),this.bannerElement=null),this.overlayElement&&(this.overlayElement.remove(),this.overlayElement=null);}dismiss(){this.hide();try{localStorage.setItem(D,Date.now().toString());}catch{}this.log("Banner dismissed"),this.onDismiss?.();}resetDismissal(){try{localStorage.removeItem(D);}catch{}}getInstallSteps(){return [this.strings.step1,this.strings.step2,this.strings.step3]}createBanner(){this.overlayElement=document.createElement("div"),this.overlayElement.id=`${m}-overlay`,this.overlayElement.style.cssText=`
|
|
6
|
+
var re=Object.defineProperty;var ne=(n,e)=>()=>(n&&(e=n(n=0)),e);var se=(n,e)=>{for(var t in e)re(n,t,{get:e[t],enumerable:true});};var J={};se(J,{generateAuthHeaders:()=>z,generateHMACSignature:()=>H,isValidUUID:()=>v,makeAuthenticatedRequest:()=>X});function de(n){return Array.from(new Uint8Array(n)).map(e=>e.toString(16).padStart(2,"0")).join("")}function ge(n){return btoa(String.fromCharCode(...new Uint8Array(n)))}async function H(n,e,t,i,r,s=""){let o=new TextEncoder,l,c;try{let g=r.startsWith("http")?new URL(r):new URL(r,"https://pwa.cloudsignal.app");l=g.pathname,c=g.search?g.search.slice(1):"";}catch{let g=r.indexOf("?");g>-1?(l=r.slice(0,g),c=r.slice(g+1)):(l=r,c="");}let d=[i.toUpperCase(),l,c,e,t];if(s&&s.length>0){let g=await crypto.subtle.digest("SHA-256",o.encode(s)),ie=de(g);d.push(ie);}let a=d.join(`
|
|
7
|
+
`),p=await crypto.subtle.importKey("raw",o.encode(n),{name:"HMAC",hash:"SHA-256"},false,["sign"]),I=await crypto.subtle.sign("HMAC",p,o.encode(a));return ge(I)}async function z(n,e,t,i,r){let s=Math.floor(Date.now()/1e3).toString(),o=await H(e,n,s,t,i,r||"");return {"X-CloudSignal-Organization-ID":n,"X-CloudSignal-Timestamp":s,"X-CloudSignal-Signature":o,"Content-Type":"application/json"}}async function X(n,e,t,i,r){let s=r?JSON.stringify(r):void 0,o=await z(n,e,t,i,s),l={method:t,headers:o};return s&&(l.body=s),fetch(i,l)}function v(n){return !n||typeof n!="string"?false:/^[0-9a-f]{8}-[0-9a-f]{4}-[1-5][0-9a-f]{3}-[89ab][0-9a-f]{3}-[0-9a-f]{12}$/i.test(n)}var P=ne(()=>{});async function O(){try{let n=[];n.push(`${screen.width}x${screen.height}`),n.push(`${screen.colorDepth}`),n.push(Intl.DateTimeFormat().resolvedOptions().timeZone),n.push(navigator.language),n.push(navigator.platform),navigator.hardwareConcurrency&&n.push(navigator.hardwareConcurrency.toString()),navigator.deviceMemory&&n.push(navigator.deviceMemory.toString());let e=oe();e&&n.push(e);let t=ae();t&&n.push(t);let i=await le();i&&n.push(i);let r=n.join("|");return await ce(r)}catch(n){return console.warn("Browser fingerprint generation failed:",n),null}}function oe(){try{let n=document.createElement("canvas"),e=n.getContext("2d");return e?(n.width=200,n.height=50,e.textBaseline="alphabetic",e.fillStyle="#f60",e.fillRect(125,1,62,20),e.fillStyle="#069",e.font="11pt Arial",e.fillText("CloudSignal PWA",2,15),e.fillStyle="rgba(102, 204, 0, 0.7)",e.font="18pt Arial",e.fillText("CloudSignal PWA",4,45),n.toDataURL().slice(-50)):null}catch{return null}}function ae(){try{let n=document.createElement("canvas"),e=n.getContext("webgl")||n.getContext("experimental-webgl");if(!e)return null;let t=e,i=t.getExtension("WEBGL_debug_renderer_info");if(i){let o=t.getParameter(i.UNMASKED_VENDOR_WEBGL),l=t.getParameter(i.UNMASKED_RENDERER_WEBGL);return `${o}~${l}`}let r=t.getParameter(t.VENDOR),s=t.getParameter(t.RENDERER);return `${r}~${s}`}catch{return null}}async function le(){try{let n=window.AudioContext||window.webkitAudioContext;if(!n)return null;let e=new n,t=e.createOscillator(),i=e.createAnalyser(),r=e.createGain(),s=e.createScriptProcessor(4096,1,1);r.gain.value=0,t.type="triangle",t.connect(i),i.connect(s),s.connect(r),r.connect(e.destination),t.start(0),await new Promise(c=>setTimeout(c,100));let o=new Uint8Array(i.frequencyBinCount);i.getByteFrequencyData(o);let l=0;for(let c=0;c<o.length;c++)l+=o[c];return t.stop(),await e.close(),l.toString(36)}catch{return null}}async function ce(n){let t=new TextEncoder().encode(n),i=await crypto.subtle.digest("SHA-256",t);return Array.from(new Uint8Array(i)).map(s=>s.toString(16).padStart(2,"0")).join("")}function $(n,e,t,i,r){return [n,e,t,i,r].filter(Boolean).join("_").replace(/[^a-zA-Z0-9_]/g,"_")}var f=class{constructor(){this.cachedInfo=null;}getDeviceInfo(){if(this.cachedInfo)return this.cachedInfo;let e=this.getPlatformInfo(),t=this.getScreenInfo(),i=this.getNetworkInfo(),r=this.getCapabilities(),s={os:e.os,osVersion:e.osVersion,deviceType:e.deviceType,deviceModel:e.deviceModel,isMobile:this.isMobile(),isTablet:this.isTablet(),isDesktop:this.isDesktop(),isWebView:e.isWebView,browser:e.browser,browserVersion:e.browserVersion,isIOS:e.os==="iOS",isAndroid:e.os==="Android",isMacOS:e.os==="macOS",isWindows:e.os==="Windows",isLinux:e.os==="Linux",screenWidth:t.width,screenHeight:t.height,pixelRatio:t.pixelRatio,supportLevel:r.supportLevel,hasNotificationPermission:r.notifications,hasPushManager:r.push,hasServiceWorker:r.serviceWorker,hasShareAPI:r.share,hasBadgeAPI:r.badge,notificationPermission:this.getNotificationPermission(),isOnline:i.isOnline,connectionType:i.connectionType,platformIcon:this.getPlatformIcon(e.os,e.deviceType),userAgent:e.userAgent,trackingId:$(e.os,e.osVersion,e.browser,e.browserVersion,e.deviceModel)};return this.cachedInfo=s,s}clearCache(){this.cachedInfo=null;}getPlatformInfo(){let e=navigator.userAgent,t=navigator.platform,i="Unknown",r="Unknown",s="Unknown",o="Unknown",l="Unknown",c="Unknown",d=false;if(/iPad|iPhone|iPod/.test(e)&&!window.MSStream){i="iOS";let a=e.match(/OS (\d+)_(\d+)_?(\d+)?/);a&&(r=`${a[1]}.${a[2]}${a[3]?"."+a[3]:""}`),/iPad/.test(e)?(l="iPad",c=this.detectiPadModel(e)):/iPhone/.test(e)?(l="iPhone",c=this.detectiPhoneModel(e)):/iPod/.test(e)&&(l="iPod",c="iPod Touch");}else if(/Android/.test(e)){i="Android";let a=e.match(/Android (\d+\.?\d*\.?\d*)/);a&&(r=a[1]);let p=this.detectAndroidDevice(e);l=p.type,c=p.model;}else if(/Mac/.test(t)){i="macOS";let a=e.match(/Mac OS X (\d+)[_.](\d+)[_.]?(\d+)?/);a&&(r=`${a[1]}.${a[2]}${a[3]?"."+a[3]:""}`),l="Desktop",c="Mac";}else if(/Win/.test(t)){i="Windows";let a=e.match(/Windows NT (\d+\.\d+)/);a&&(r=this.getWindowsVersion(a[1])),l="Desktop",c="PC";}else /Linux/.test(t)&&(i="Linux",l="Desktop",c="Linux PC",/Ubuntu/.test(e)?r="Ubuntu":/Fedora/.test(e)?r="Fedora":/Debian/.test(e)&&(r="Debian"));if(/Chrome/.test(e)&&!/Edg/.test(e)&&!/OPR/.test(e)){s="Chrome";let a=e.match(/Chrome\/(\d+\.?\d*\.?\d*\.?\d*)/);a&&(o=a[1]);}else if(/Safari/.test(e)&&!/Chrome/.test(e)){s="Safari";let a=e.match(/Version\/(\d+\.?\d*\.?\d*)/);a&&(o=a[1]);}else if(/Firefox/.test(e)){s="Firefox";let a=e.match(/Firefox\/(\d+\.?\d*\.?\d*)/);a&&(o=a[1]);}else if(/Edg/.test(e)){s="Edge";let a=e.match(/Edg\/(\d+\.?\d*\.?\d*\.?\d*)/);a&&(o=a[1]);}else if(/OPR/.test(e)||/Opera/.test(e)){s="Opera";let a=e.match(/(?:OPR|Opera)\/(\d+\.?\d*\.?\d*)/);a&&(o=a[1]);}else if(/SamsungBrowser/.test(e)){s="Samsung Internet";let a=e.match(/SamsungBrowser\/(\d+\.?\d*)/);a&&(o=a[1]);}return d=this.detectWebView(e),{os:i,osVersion:r,browser:s,browserVersion:o,deviceType:l,deviceModel:c,isWebView:d,userAgent:e}}getScreenInfo(){return {width:screen.width,height:screen.height,pixelRatio:window.devicePixelRatio||1,orientation:screen.width>screen.height?"landscape":"portrait"}}getNetworkInfo(){let e=navigator.connection;return {isOnline:navigator.onLine,connectionType:e?.effectiveType||"unknown",effectiveType:e?.effectiveType,downlink:e?.downlink,rtt:e?.rtt,saveData:e?.saveData}}getCapabilities(){let e={serviceWorker:"serviceWorker"in navigator,push:"PushManager"in window,notifications:"Notification"in window,backgroundSync:"serviceWorker"in navigator&&"SyncManager"in window,badge:"setAppBadge"in navigator,share:"share"in navigator,shareTarget:"launchQueue"in window,fileSystemAccess:"showOpenFilePicker"in window,contactPicker:"ContactsManager"in window,periodicSync:"serviceWorker"in navigator&&"PeriodicSyncManager"in window,supportLevel:"none"};return e.serviceWorker&&e.push&&e.notifications?e.supportLevel="full":e.serviceWorker&&e.notifications?e.supportLevel="partial":e.serviceWorker&&(e.supportLevel="basic"),e}getNotificationPermission(){return "Notification"in window?Notification.permission:"denied"}isMobile(){let e=navigator.userAgent;return /Android|webOS|iPhone|iPod|BlackBerry|IEMobile|Opera Mini/i.test(e)}isTablet(){let e=navigator.userAgent;return /iPad|Android(?!.*Mobile)|Tablet/i.test(e)}isDesktop(){return !this.isMobile()&&!this.isTablet()}getPlatformIcon(e,t){return e==="iOS"||t==="iPhone"||t==="iPad"?"\u{1F4F1}":e==="Android"?"\u{1F916}":e==="macOS"?"\u{1F4BB}":"\u{1F5A5}\uFE0F"}detectiPhoneModel(e){let t=screen.height,i=screen.width;return t===932||i===932?"iPhone 15 Pro Max/14 Pro Max":t===896||i===896?"iPhone 15 Pro/14 Pro/11 Pro Max":t===852||i===852?"iPhone 15/14":t===844||i===844?"iPhone 13/12":t===812||i===812?"iPhone X/XS/11 Pro":t===736||i===736?"iPhone 8 Plus":t===667||i===667?"iPhone 8/SE":t===568||i===568?"iPhone SE (1st)":"iPhone"}detectiPadModel(e){let t=screen.width,i=screen.height,r=window.devicePixelRatio||1;return (i===1366||t===1366)&&r===2?'iPad Pro 12.9"':(i===1194||t===1194)&&r===2?'iPad Pro 11"':(i===1180||t===1180)&&r===2?"iPad Air/10th Gen":(i===1133||t===1133)&&r===2?"iPad mini":"iPad"}detectAndroidDevice(e){let t="Phone",i="Android Device";if(/Tablet|SM-T|Tab|GT-P|MediaPad/i.test(e)&&(t="Tablet"),/SM-S9\d{2}/i.test(e))i="Samsung Galaxy S24";else if(/SM-S91\d/i.test(e))i="Samsung Galaxy S23";else if(/SM-S90\d/i.test(e))i="Samsung Galaxy S22";else if(/SM-G99\d/i.test(e))i="Samsung Galaxy S21";else if(/SM-N9\d{2}/i.test(e))i="Samsung Galaxy Note";else if(/SM-A\d{2}/i.test(e))i="Samsung Galaxy A Series";else if(/SM-/i.test(e)){let r=e.match(/SM-[A-Z]\d+/i);r&&(i=`Samsung ${r[0]}`);}if(/Pixel 8/i.test(e)?i="Google Pixel 8":/Pixel 7/i.test(e)?i="Google Pixel 7":/Pixel 6/i.test(e)?i="Google Pixel 6":/Pixel/i.test(e)&&(i="Google Pixel"),/OnePlus/i.test(e)){let r=e.match(/OnePlus[\s]?(\w+)/i);i=r?`OnePlus ${r[1]}`:"OnePlus";}return /Xiaomi|Redmi|POCO|Mi\s/i.test(e)&&(/Redmi/i.test(e)?i="Xiaomi Redmi":/POCO/i.test(e)?i="Xiaomi POCO":i="Xiaomi"),/HUAWEI|Honor/i.test(e)&&(i=/Honor/i.test(e)?"Honor":"Huawei"),/OPPO/i.test(e)&&(i="OPPO"),/vivo/i.test(e)&&(i="Vivo"),{type:t,model:i}}getWindowsVersion(e){return {"10.0":"Windows 10/11","6.3":"Windows 8.1","6.2":"Windows 8","6.1":"Windows 7","6.0":"Windows Vista","5.1":"Windows XP"}[e]||`Windows NT ${e}`}detectWebView(e){return !!(/FBAN|FBAV/i.test(e)||/Instagram/i.test(e)||/LinkedIn/i.test(e)||/Twitter/i.test(e)||/MicroMessenger/i.test(e)||/Snapchat/i.test(e)||/BytedanceWebview|TikTok/i.test(e)||/wv|WebView/i.test(e))}},ue=new f;var S=class{constructor(e={}){this.registration=null;this.config={path:"/service-worker.js",scope:"/",autoRegister:true,updateBehavior:"auto",...e.config},this.debug=e.debug??false,this.onRegistered=e.onRegistered,this.onUpdated=e.onUpdated,this.onError=e.onError;}isSupported(){return "serviceWorker"in navigator}getRegistration(){return this.registration}async register(){if(!this.isSupported())return this.log("Service workers not supported"),null;try{let{path:e,scope:t}=this.getPathAndScope();this.log(`Registering service worker: ${e} with scope ${t}`);let i=await navigator.serviceWorker.register(e,{scope:t});return this.registration=i,i.addEventListener("updatefound",()=>{this.handleUpdateFound(i);}),await navigator.serviceWorker.ready,this.log("Service worker registered successfully"),this.onRegistered?.(i),i}catch(e){let t=e instanceof Error?e:new Error(String(e));return this.log(`Service worker registration failed: ${t.message}`,"error"),this.onError?.(t),null}}async unregister(){if(!this.registration)return false;try{let e=await this.registration.unregister();return e&&(this.registration=null,this.log("Service worker unregistered")),e}catch(e){return this.log(`Failed to unregister service worker: ${e}`,"error"),false}}async checkForUpdate(){if(this.registration)try{await this.registration.update(),this.log("Checked for service worker update");}catch(e){this.log(`Failed to check for update: ${e}`,"error");}}async waitForReady(e=5e3){if(!this.isSupported())return null;let t=new Promise(i=>{setTimeout(()=>i(null),e);});try{let i=await Promise.race([navigator.serviceWorker.ready,t]);return i&&(this.registration=i),i}catch{return null}}postMessage(e){if(!this.registration?.active){this.log("No active service worker to send message to","warn");return}this.registration.active.postMessage(e);}clearBadge(){this.postMessage({type:"CLEAR_BADGE"});}setBadge(e){this.postMessage({type:"SET_BADGE",count:e});}handleUpdateFound(e){let t=e.installing;t&&t.addEventListener("statechange",()=>{t.state==="installed"&&navigator.serviceWorker.controller&&(this.log("New service worker available"),this.config.updateBehavior==="auto"&&t.postMessage({type:"SKIP_WAITING"}),this.onUpdated?.(e));});}getPathAndScope(){if(this.config.path&&this.config.scope)return {path:this.config.path,scope:this.config.scope};try{let e=window.location.pathname||"/";if(e.startsWith("/version-live"))return {path:"/version-live/service-worker.js",scope:"/version-live/"};if(e.startsWith("/version-test"))return {path:"/version-test/service-worker.js",scope:"/version-test/"}}catch{}return {path:this.config.path||"/service-worker.js",scope:this.config.scope||"/"}}log(e,t="log"){if(!this.debug)return;console[t](`[CloudSignal PWA SW] ${e}`);}};var k=class{constructor(e={}){this.deferredPrompt=null;this.isInstalled=false;this.debug=e.debug??false,this.onInstallAvailable=e.onInstallAvailable,this.onInstallAccepted=e.onInstallAccepted,this.onInstallDismissed=e.onInstallDismissed,this.onInstalled=e.onInstalled,this.detectInstallationStatus();}initialize(){window.addEventListener("beforeinstallprompt",e=>{e.preventDefault(),this.deferredPrompt=e,this.log("Install prompt available"),this.onInstallAvailable?.(this.deferredPrompt);}),window.addEventListener("appinstalled",()=>{this.isInstalled=true,this.deferredPrompt=null,this.log("PWA was installed"),this.onInstalled?.();}),window.matchMedia&&window.matchMedia("(display-mode: standalone)").addEventListener("change",t=>{t.matches&&(this.isInstalled=true,this.log("App is now running in standalone mode"));});}getState(){let e=this.getDisplayMode(),t=this.isIOSDevice(),i=this.isSafariBrowser();return {isInstalled:this.isInstalled||e!=="browser",canBeInstalled:this.deferredPrompt!==null,needsManualInstall:t&&i&&!this.isInstalled,showManualInstructions:t&&i&&!this.isInstalled,installSteps:this.getInstallSteps(),displayMode:e}}async showInstallPrompt(){if(!this.deferredPrompt)return this.log("No install prompt available","warn"),{accepted:false,outcome:"dismissed"};try{await this.deferredPrompt.prompt();let{outcome:e,platform:t}=await this.deferredPrompt.userChoice,i={accepted:e==="accepted",outcome:e,platform:t};return e==="accepted"?(this.log("User accepted install prompt"),this.isInstalled=!0,this.onInstallAccepted?.(i)):(this.log("User dismissed install prompt"),this.onInstallDismissed?.(i)),this.deferredPrompt=null,i}catch(e){return this.log(`Error showing install prompt: ${e}`,"error"),{accepted:false,outcome:"dismissed"}}}canInstall(){return this.deferredPrompt!==null}isPWAInstalled(){return this.isInstalled||this.getDisplayMode()!=="browser"}getDisplayMode(){return window.matchMedia("(display-mode: standalone)").matches?"standalone":window.matchMedia("(display-mode: minimal-ui)").matches?"minimal-ui":window.matchMedia("(display-mode: fullscreen)").matches?"fullscreen":navigator.standalone===true?"standalone":"browser"}getInstallSteps(){return this.isIOSDevice()?["Tap the Share button in Safari",'Scroll down and tap "Add to Home Screen"','Tap "Add" to install the app']:this.isAndroidDevice()?["Tap the menu (three dots) in your browser",'Tap "Install App" or "Add to Home Screen"',"Follow the prompts to install"]:["Click the install icon in the address bar","Or use the browser menu to install the app",'Click "Install" when prompted']}detectInstallationStatus(){if(this.getDisplayMode()!=="browser"){this.isInstalled=true;return}if(navigator.standalone===true){this.isInstalled=true;return}"getInstalledRelatedApps"in navigator&&navigator.getInstalledRelatedApps().then(e=>{e.length>0&&(this.isInstalled=true);}).catch(()=>{});}isIOSDevice(){return /iPad|iPhone|iPod/.test(navigator.userAgent)&&!window.MSStream}isAndroidDevice(){return /Android/i.test(navigator.userAgent)}isSafariBrowser(){let e=navigator.userAgent;return /Safari/i.test(e)&&!/Chrome|CriOS|FxiOS/i.test(e)}log(e,t="log"){if(!this.debug)return;console[t](`[CloudSignal PWA Install] ${e}`);}};P();function j(n,e){return {Authorization:`Bearer ${n}`,"X-CloudSignal-Organization-ID":e,"Content-Type":"application/json"}}async function Y(n,e,t,i){let r=i?JSON.stringify(i):void 0,s=j(n.token,n.organizationId),o={method:e,headers:s};r&&(o.body=r);let l=await fetch(t,o);if(l.status===401&&n.onTokenExpired)try{let c=await n.onTokenExpired();c&&(s=j(c,n.organizationId),o.headers=s,l=await fetch(t,o));}catch(c){console.warn("[CloudSignal PWA] Token refresh failed:",c);}return l}function y(n){if(n.userToken)return {mode:"jwt",organizationId:n.organizationId,userToken:n.userToken,onTokenExpired:n.onTokenExpired};if(!n.organizationSecret)throw new Error("Either userToken or organizationSecret is required");return {mode:"hmac",organizationId:n.organizationId,organizationSecret:n.organizationSecret}}async function h(n,e,t,i,r){if(n.mode==="jwt"){if(!n.userToken)throw new Error("userToken required for JWT auth mode");return Y({token:n.userToken,organizationId:n.organizationId,onTokenExpired:r||n.onTokenExpired},e,t,i)}let{makeAuthenticatedRequest:s}=await Promise.resolve().then(()=>(P(),J));if(!n.organizationSecret)throw new Error("organizationSecret required for HMAC auth mode");return s(n.organizationId,n.organizationSecret,e,t,i)}function b(n,e){return n.mode!=="jwt"?{mode:"jwt",organizationId:n.organizationId,userToken:e,onTokenExpired:n.onTokenExpired}:{...n,userToken:e}}var U="cloudsignal_pwa_";function x(n,e){try{let t=`${U}${n}`,i=localStorage.getItem(t);return i===null?e??null:JSON.parse(i)}catch{return e??null}}function M(n,e){try{let t=`${U}${n}`;return localStorage.setItem(t,JSON.stringify(e)),!0}catch{return false}}function Z(n){try{let e=`${U}${n}`;return localStorage.removeItem(e),!0}catch{return false}}function _(n,e){let t=`registration_${n}_${e}`;return x(t)}function F(n,e,t){let i=`registration_${n}_${e}`;return M(i,t)}function N(n,e){let t=`registration_${n}_${e}`;return Z(t)}function V(n,e){let t=`install_registered_${n}_${e}`;return x(t)===true}function ee(n,e,t){let i=`install_registered_${n}_${e}`;return M(`install_id_${n}_${e}`,t),M(i,true)}var Q=class{constructor(e="CloudSignalPWA",t=1){this.db=null;this.dbName=e,this.dbVersion=t;}async init(){return new Promise((e,t)=>{let i=indexedDB.open(this.dbName,this.dbVersion);i.onerror=()=>t(i.error),i.onsuccess=()=>{this.db=i.result,e(this.db);},i.onupgradeneeded=r=>{let s=r.target.result;if(s.objectStoreNames.contains("badge")||s.createObjectStore("badge"),!s.objectStoreNames.contains("notifications")){let o=s.createObjectStore("notifications",{keyPath:"id",autoIncrement:true});o.createIndex("timestamp","timestamp",{unique:false}),o.createIndex("read","read",{unique:false});}s.objectStoreNames.contains("userPreferences")||s.createObjectStore("userPreferences"),s.objectStoreNames.contains("syncQueue")||s.createObjectStore("syncQueue",{keyPath:"id",autoIncrement:true}).createIndex("timestamp","timestamp",{unique:false});};})}async ensureConnection(){this.db||await this.init();}promisifyRequest(e){return new Promise((t,i)=>{e.onsuccess=()=>t(e.result),e.onerror=()=>i(e.error);})}async getBadgeCount(){await this.ensureConnection();let t=this.db.transaction(["badge"],"readonly").objectStore("badge");return await this.promisifyRequest(t.get("count"))||0}async setBadgeCount(e){await this.ensureConnection();let i=this.db.transaction(["badge"],"readwrite").objectStore("badge");await this.promisifyRequest(i.put(e,"count"));}async incrementBadgeCount(e=1){let t=await this.getBadgeCount(),i=Math.max(0,t+e);return await this.setBadgeCount(i),i}async saveNotification(e){await this.ensureConnection();let i=this.db.transaction(["notifications"],"readwrite").objectStore("notifications"),r={...e,timestamp:Date.now(),read:false};return await this.promisifyRequest(i.add(r))}async getRecentNotifications(e=50){await this.ensureConnection();let r=this.db.transaction(["notifications"],"readonly").objectStore("notifications").index("timestamp"),s=[],o=r.openCursor(null,"prev");return new Promise((l,c)=>{o.onsuccess=d=>{let a=d.target.result;a&&s.length<e?(s.push(a.value),a.continue()):l(s);},o.onerror=()=>c(o.error);})}async markNotificationAsRead(e){await this.ensureConnection();let i=this.db.transaction(["notifications"],"readwrite").objectStore("notifications"),r=await this.promisifyRequest(i.get(e));r&&(r.read=true,await this.promisifyRequest(i.put(r)));}async getUserPreference(e){await this.ensureConnection();let i=this.db.transaction(["userPreferences"],"readonly").objectStore("userPreferences");return this.promisifyRequest(i.get(e))}async setUserPreference(e,t){await this.ensureConnection();let r=this.db.transaction(["userPreferences"],"readwrite").objectStore("userPreferences");await this.promisifyRequest(r.put(t,e));}async addToSyncQueue(e){await this.ensureConnection();let i=this.db.transaction(["syncQueue"],"readwrite").objectStore("syncQueue"),r={...e,timestamp:Date.now(),retries:0};return await this.promisifyRequest(i.add(r))}async getSyncQueue(){await this.ensureConnection();let t=this.db.transaction(["syncQueue"],"readonly").objectStore("syncQueue");return this.promisifyRequest(t.getAll())}async removeFromSyncQueue(e){await this.ensureConnection();let i=this.db.transaction(["syncQueue"],"readwrite").objectStore("syncQueue");await this.promisifyRequest(i.delete(e));}};var R=class{constructor(e){this.serviceWorkerRegistration=null;this.pushSubscription=null;this.registrationId=null;this.vapidPublicKey=null;this.serviceUrl=e.serviceUrl,this.organizationId=e.organizationId,this.serviceId=e.serviceId,this.debug=e.debug??false,this.deviceDetector=new f,this.authContext=y({organizationId:e.organizationId,organizationSecret:e.organizationSecret,userToken:e.userToken}),this.onRegistered=e.onRegistered,this.onUnregistered=e.onUnregistered,this.onError=e.onError,this.onPermissionDenied=e.onPermissionDenied,this.onTokenExpired=e.onTokenExpired,this.registrationId=_(this.organizationId,this.serviceId);}setServiceWorkerRegistration(e){this.serviceWorkerRegistration=e;}setVapidPublicKey(e){this.vapidPublicKey=e;}getRegistrationId(){return this.registrationId}isRegistered(){return this.registrationId!==null}getAuthMode(){return this.authContext.mode}updateToken(e){this.authContext=b(this.authContext,e),this.log(`Auth mode: ${this.authContext.mode}`);}async register(e={}){try{if(!this.serviceWorkerRegistration)throw new Error("Service worker not registered");if(!this.vapidPublicKey)throw new Error("VAPID public key not set. Call downloadConfig() first.");if(await this.requestPermission()!=="granted")return this.log("Notification permission denied"),this.onPermissionDenied?.(),null;let i=await this.subscribeToPush();if(!i)throw new Error("Failed to subscribe to push notifications");this.pushSubscription=i;let r=await O(),s=this.deviceDetector.getDeviceInfo(),o=this.deviceDetector.getPlatformInfo(),l=i.toJSON(),c={serviceId:this.serviceId,userEmail:e.userEmail,userId:v(e.userId)?e.userId:void 0,endpoint:i.endpoint,keys:{p256dh:l.keys?.p256dh||"",auth:l.keys?.auth||""},browserFingerprint:r||void 0,deviceType:s.deviceType,deviceModel:s.deviceModel,browserName:o.browser,browserVersion:o.browserVersion,osName:o.os,osVersion:o.osVersion,userAgent:o.userAgent,displayMode:"standalone",isInstalled:!0,timezone:e.timezone||Intl.DateTimeFormat().resolvedOptions().timeZone,language:e.language||navigator.language||"en-US"},d=`${this.serviceUrl}/api/v1/registration/register`,a=await h(this.authContext,"POST",d,c,this.onTokenExpired);if(!a.ok){let g=await a.text();throw new Error(`Registration failed: ${a.status} - ${g}`)}let p=await a.json();this.registrationId=p.registration_id,F(this.organizationId,this.serviceId,this.registrationId);let I={registrationId:p.registration_id,status:p.status||"active",createdAt:p.created_at||new Date().toISOString(),isActive:!0};return this.log(`Push registration successful: ${I.registrationId}`),this.onRegistered?.(I),I}catch(t){let i=t instanceof Error?t:new Error(String(t));return this.log(`Push registration failed: ${i.message}`,"error"),this.onError?.(i),null}}async unregister(){try{if(!this.registrationId)return this.log("No registration to unregister"),!0;this.pushSubscription&&(await this.pushSubscription.unsubscribe(),this.pushSubscription=null);let e=`${this.serviceUrl}/api/v1/registration/unregister`,t=await h(this.authContext,"POST",e,{registration_id:this.registrationId},this.onTokenExpired);return t.ok||this.log(`Backend unregistration failed: ${t.status}`,"warn"),N(this.organizationId,this.serviceId),this.registrationId=null,this.log("Push unregistration successful"),this.onUnregistered?.(),!0}catch(e){let t=e instanceof Error?e:new Error(String(e));return this.log(`Push unregistration failed: ${t.message}`,"error"),this.onError?.(t),false}}async updatePreferences(e){try{if(!this.registrationId)throw new Error("Not registered for push notifications");let t=`${this.serviceUrl}/api/v1/registration/update`,i=await h(this.authContext,"POST",t,{registration_id:this.registrationId,notification_topics:e.topics,timezone:e.timezone,language:e.language,is_active:e.isActive},this.onTokenExpired);if(!i.ok)throw new Error(`Update failed: ${i.status}`);return this.log("Preferences updated successfully"),!0}catch(t){let i=t instanceof Error?t:new Error(String(t));return this.log(`Failed to update preferences: ${i.message}`,"error"),this.onError?.(i),false}}async checkStatus(){try{if(!this.registrationId)return null;let e=`${this.serviceUrl}/api/v1/registration/status/${this.registrationId}`,t=await h(this.authContext,"GET",e,void 0,this.onTokenExpired);if(!t.ok){if(t.status===404)return N(this.organizationId,this.serviceId),this.registrationId=null,null;throw new Error(`Status check failed: ${t.status}`)}let i=await t.json();return {registrationId:i.registration_id,status:i.status,isActive:i.is_active,isOnline:i.is_online,lastActive:i.last_active,lastSeenOnline:i.last_seen_online,lastHeartbeat:i.last_heartbeat,installationDate:i.installation_date,notificationCount:i.notification_count,deviceInfo:i.device_info}}catch(e){let t=e instanceof Error?e:new Error(String(e));return this.log(`Status check failed: ${t.message}`,"error"),null}}async registerInstallation(){try{if(V(this.organizationId,this.serviceId))return this.log("Installation already registered, skipping"),null;let e=await O(),t=this.deviceDetector.getDeviceInfo(),i=this.deviceDetector.getPlatformInfo(),r={service_id:this.serviceId,browser_fingerprint:e||void 0,device_type:t.deviceType,device_model:t.deviceModel,browser_name:i.browser,browser_version:i.browserVersion,os_name:i.os,os_version:i.osVersion,user_agent:i.userAgent,display_mode:"standalone",is_installed:!0,timezone:Intl.DateTimeFormat().resolvedOptions().timeZone,language:navigator.language||"en-US"},s=`${this.serviceUrl}/api/v1/registration/install-only`,o=await h(this.authContext,"POST",s,r,this.onTokenExpired);if(!o.ok){let c=await o.text();throw new Error(`Installation registration failed: ${o.status} - ${c}`)}let l=await o.json();return ee(this.organizationId,this.serviceId,l.registration_id),this.log(`Installation registered successfully: ${l.registration_id}`),{registrationId:l.registration_id}}catch(e){let t=e instanceof Error?e:new Error(String(e));return this.log(`Installation registration failed: ${t.message}`,"error"),this.onError?.(t),null}}isInstallationRegistered(){return V(this.organizationId,this.serviceId)}getInstallationId(){return x(`install_id_${this.organizationId}_${this.serviceId}`)}async requestPermission(){return "Notification"in window?Notification.permission==="granted"?"granted":Notification.permission==="denied"?"denied":await Notification.requestPermission():"denied"}async subscribeToPush(){if(!this.serviceWorkerRegistration||!this.vapidPublicKey)return null;try{let e=await this.serviceWorkerRegistration.pushManager.getSubscription();if(!e){let t=this.urlBase64ToUint8Array(this.vapidPublicKey);e=await this.serviceWorkerRegistration.pushManager.subscribe({userVisibleOnly:!0,applicationServerKey:t.buffer});}return e}catch(e){return this.log(`Push subscription failed: ${e}`,"error"),null}}urlBase64ToUint8Array(e){let t="=".repeat((4-e.length%4)%4),i=(e+t).replace(/-/g,"+").replace(/_/g,"/"),r=atob(i),s=new Uint8Array(r.length);for(let o=0;o<r.length;++o)s[o]=r.charCodeAt(o);return s}log(e,t="log"){if(!this.debug)return;console[t](`[CloudSignal PWA Push] ${e}`);}};P();var he={"4g":3e4,"3g":6e4,"2g":12e4,"slow-2g":18e4,unknown:3e4},E=class{constructor(e){this.registrationId=null;this.intervalId=null;this.isRunning=false;this.isPausedForBattery=false;this.visibilityHandler=null;this.connectionChangeHandler=null;this.batteryManager=null;this.serviceUrl=e.serviceUrl,this.organizationId=e.organizationId,this.debug=e.debug??false,this.onHeartbeatSent=e.onHeartbeatSent,this.onHeartbeatError=e.onHeartbeatError,this.onIntervalChanged=e.onIntervalChanged,this.onPausedForBattery=e.onPausedForBattery,this.onResumedFromBattery=e.onResumedFromBattery,this.onTokenExpired=e.onTokenExpired,this.authContext=y({organizationId:e.organizationId,organizationSecret:e.organizationSecret,userToken:e.userToken}),this.config={enabled:e.config?.enabled??true,interval:e.config?.interval??3e4,autoStart:e.config?.autoStart??true,stopOnHidden:e.config?.stopOnHidden??true},this.adaptiveConfig={adaptToNetwork:e.adaptiveConfig?.adaptToNetwork??true,adaptToBattery:e.adaptiveConfig?.adaptToBattery??true,batteryPauseThreshold:e.adaptiveConfig?.batteryPauseThreshold??.15,intervals:{...he,...e.adaptiveConfig?.intervals}},this.currentInterval=this.config.interval;}setRegistrationId(e){this.registrationId=e,this.config.autoStart&&!this.isRunning&&this.config.enabled&&this.start();}start(){if(this.isRunning){this.log("Heartbeat already running");return}if(!this.registrationId||!v(this.registrationId)){this.log("Cannot start heartbeat: no valid registration ID","warn");return}if(!this.config.enabled){this.log("Heartbeat is disabled");return}this.isRunning=true,this.updateIntervalForNetwork(),this.log(`Starting heartbeat with interval ${this.currentInterval}ms`),this.sendHeartbeat(),this.startInterval(),this.config.stopOnHidden&&this.setupVisibilityHandler(),this.adaptiveConfig.adaptToNetwork&&this.setupNetworkChangeHandler(),this.adaptiveConfig.adaptToBattery&&this.setupBatteryMonitoring();}stop(){if(this.isRunning){if(this.isRunning=false,this.isPausedForBattery=false,this.intervalId&&(clearInterval(this.intervalId),this.intervalId=null),this.visibilityHandler&&(document.removeEventListener("visibilitychange",this.visibilityHandler),this.visibilityHandler=null),this.connectionChangeHandler){let e=navigator.connection;e&&e.removeEventListener("change",this.connectionChangeHandler),this.connectionChangeHandler=null;}this.log("Heartbeat stopped");}}isHeartbeatRunning(){return this.isRunning}getAuthMode(){return this.authContext.mode}updateToken(e){this.authContext=b(this.authContext,e),this.log(`Auth mode: ${this.authContext.mode}`);}async sendHeartbeat(){if(!this.registrationId||!v(this.registrationId))return this.log("Cannot send heartbeat: no valid registration ID","warn"),false;try{let e=`${this.serviceUrl}/api/v1/registration/heartbeat/${this.registrationId}`,t=await h(this.authContext,"POST",e,void 0,this.onTokenExpired);if(!t.ok)throw new Error(`Heartbeat failed: ${t.status}`);return this.log("Heartbeat sent successfully"),this.onHeartbeatSent?.(),!0}catch(e){let t=e instanceof Error?e:new Error(String(e));return this.log(`Heartbeat failed: ${t.message}`,"error"),this.onHeartbeatError?.(t),false}}updateConfig(e){let t=this.isRunning;t&&this.stop(),this.config={...this.config,...e},t&&this.config.enabled&&this.start();}getNetworkInfo(){let e=navigator.connection;return e?{effectiveType:e.effectiveType,saveData:e.saveData,downlink:e.downlink,rtt:e.rtt}:{}}async getBatteryInfo(){try{if(!("getBattery"in navigator))return null;let e=await navigator.getBattery();return {level:e.level,charging:e.charging}}catch{return null}}getCurrentInterval(){return this.currentInterval}isPausedDueToBattery(){return this.isPausedForBattery}startInterval(){this.intervalId&&clearInterval(this.intervalId),this.intervalId=setInterval(()=>{this.sendHeartbeat();},this.currentInterval);}updateIntervalForNetwork(){if(!this.adaptiveConfig.adaptToNetwork){this.currentInterval=this.config.interval;return}let e=navigator.connection;if(!e){this.currentInterval=this.config.interval;return}if(e.saveData){let r=Math.max(this.currentInterval,12e4);r!==this.currentInterval&&(this.currentInterval=r,this.log(`Interval increased to ${r}ms (saveData enabled)`),this.onIntervalChanged?.(r,"saveData"));return}let t=e.effectiveType||"unknown",i=this.adaptiveConfig.intervals[t]||this.config.interval;if(i!==this.currentInterval){let r=this.currentInterval;this.currentInterval=i,this.log(`Interval changed from ${r}ms to ${i}ms (${t})`),this.onIntervalChanged?.(i,t);}}setupNetworkChangeHandler(){let e=navigator.connection;e&&(this.connectionChangeHandler=()=>{let t=this.currentInterval;this.updateIntervalForNetwork(),t!==this.currentInterval&&this.isRunning&&!this.isPausedForBattery&&this.startInterval();},e.addEventListener("change",this.connectionChangeHandler));}async setupBatteryMonitoring(){try{if(!("getBattery"in navigator))return;this.batteryManager=await navigator.getBattery();let e=()=>{if(!this.batteryManager)return;let t=this.batteryManager.level,i=this.batteryManager.charging;t<=this.adaptiveConfig.batteryPauseThreshold&&!i?!this.isPausedForBattery&&this.isRunning&&(this.isPausedForBattery=!0,this.intervalId&&(clearInterval(this.intervalId),this.intervalId=null),this.log(`Heartbeat paused (battery at ${Math.round(t*100)}%)`),this.onPausedForBattery?.()):this.isPausedForBattery&&this.isRunning&&(this.isPausedForBattery=!1,this.startInterval(),this.log(`Heartbeat resumed (battery at ${Math.round(t*100)}%)`),this.onResumedFromBattery?.());};e(),this.batteryManager.addEventListener("levelchange",e),this.batteryManager.addEventListener("chargingchange",e);}catch{}}setupVisibilityHandler(){this.visibilityHandler=()=>{document.hidden?(this.intervalId&&(clearInterval(this.intervalId),this.intervalId=null),this.log("Heartbeat paused (page hidden)")):this.isRunning&&!this.intervalId&&!this.isPausedForBattery&&(this.sendHeartbeat(),this.startInterval(),this.log("Heartbeat resumed (page visible)"));},document.addEventListener("visibilitychange",this.visibilityHandler);}log(e,t="log"){if(!this.debug)return;console[t](`[CloudSignal PWA Heartbeat] ${e}`);}};var T=class{constructor(e={}){this.wakeLock=null;this.visibilityHandler=null;this.releaseHandler=null;this.shouldReacquire=false;this.debug=e.debug??false,this.onAcquired=e.onAcquired,this.onReleased=e.onReleased,this.onError=e.onError,this.config={enabled:e.config?.enabled??true,autoReacquire:e.config?.autoReacquire??true};}isSupported(){return "wakeLock"in navigator}getState(){return {isActive:this.wakeLock!==null&&!this.wakeLock.released,isSupported:this.isSupported(),type:"screen",acquiredAt:this.wakeLock&&!this.wakeLock.released?Date.now():void 0}}async acquire(){if(!this.config.enabled)return this.log("Wake lock is disabled"),false;if(!this.isSupported())return this.log("Wake Lock API not supported"),this.onError?.({timestamp:Date.now(),error:"Wake Lock API not supported",errorName:"NotSupportedError"}),false;if(this.wakeLock&&!this.wakeLock.released)return this.log("Wake lock already active"),true;try{return this.wakeLock=await navigator.wakeLock.request("screen"),this.shouldReacquire=!0,this.releaseHandler=()=>{this.handleRelease("system");},this.wakeLock.addEventListener("release",this.releaseHandler),this.config.autoReacquire&&this.setupVisibilityHandler(),this.log("Wake lock acquired"),this.onAcquired?.({timestamp:Date.now()}),!0}catch(e){let t=e instanceof Error?e:new Error(String(e));return this.log(`Failed to acquire wake lock: ${t.message}`,"error"),this.onError?.({timestamp:Date.now(),error:t.message,errorName:t.name}),false}}async release(){if(this.shouldReacquire=false,!!this.wakeLock){try{this.releaseHandler&&(this.wakeLock.removeEventListener("release",this.releaseHandler),this.releaseHandler=null),await this.wakeLock.release(),this.wakeLock=null,this.log("Wake lock released manually"),this.onReleased?.({timestamp:Date.now(),reason:"manual"});}catch(e){let t=e instanceof Error?e:new Error(String(e));this.log(`Failed to release wake lock: ${t.message}`,"error");}this.removeVisibilityHandler();}}async toggle(){return this.wakeLock&&!this.wakeLock.released?(await this.release(),false):this.acquire()}isActive(){return this.wakeLock!==null&&!this.wakeLock.released}async destroy(){await this.release(),this.removeVisibilityHandler();}handleRelease(e){this.wakeLock=null,this.log(`Wake lock released by ${e}`),this.onReleased?.({timestamp:Date.now(),reason:e});}setupVisibilityHandler(){this.visibilityHandler||(this.visibilityHandler=async()=>{document.visibilityState==="visible"&&this.shouldReacquire?(this.log("Page visible, attempting to reacquire wake lock"),await this.acquire()):document.visibilityState==="hidden"&&this.wakeLock&&this.log("Page hidden, wake lock will be released");},document.addEventListener("visibilitychange",this.visibilityHandler));}removeVisibilityHandler(){this.visibilityHandler&&(document.removeEventListener("visibilitychange",this.visibilityHandler),this.visibilityHandler=null);}log(e,t="log"){if(!this.debug&&t==="log")return;console[t](`[CloudSignal PWA WakeLock] ${e}`);}};var pe="CloudSignalPWA";var u="offlineQueue",A=class{constructor(e={}){this.db=null;this.isProcessing=false;this.onlineHandler=null;this.debug=e.debug??false,this.onRequestQueued=e.onRequestQueued,this.onRequestProcessed=e.onRequestProcessed,this.onQueueEmpty=e.onQueueEmpty,this.onError=e.onError,this.config={enabled:e.config?.enabled??true,maxQueueSize:e.config?.maxQueueSize??100,maxAge:e.config?.maxAge??1440*60*1e3,baseRetryDelay:e.config?.baseRetryDelay??1e3,maxRetryDelay:e.config?.maxRetryDelay??6e4,defaultMaxRetries:e.config?.defaultMaxRetries??5,processOnOnline:e.config?.processOnOnline??true};}async initialize(){if(!this.config.enabled){this.log("Offline queue is disabled");return}try{await this.openDatabase(),this.config.processOnOnline&&(this.onlineHandler=()=>{this.log("Network online, processing queue"),this.processQueue();},window.addEventListener("online",this.onlineHandler)),await this.cleanupOldRequests(),this.log("Offline queue manager initialized");}catch(e){let t=e instanceof Error?e:new Error(String(e));this.log(`Failed to initialize: ${t.message}`,"error"),this.onError?.(t);}}destroy(){this.onlineHandler&&(window.removeEventListener("online",this.onlineHandler),this.onlineHandler=null),this.db&&(this.db.close(),this.db=null);}async queueRequest(e,t,i={}){if(!this.config.enabled||!this.db)return null;try{(await this.getStats()).totalQueued>=this.config.maxQueueSize&&(this.log("Queue is full, removing oldest request"),await this.removeOldestRequest());let s={url:e,method:t,headers:i.headers,body:i.body,queuedAt:Date.now(),retryCount:0,maxRetries:i.maxRetries??this.config.defaultMaxRetries,requestType:i.requestType??"custom",priority:i.priority??0,metadata:i.metadata},o=await this.addToStore(s);return s.id=o,this.log(`Queued request: ${t} ${e} (id: ${o})`),this.onRequestQueued?.(s),o}catch(r){let s=r instanceof Error?r:new Error(String(r));return this.log(`Failed to queue request: ${s.message}`,"error"),this.onError?.(s),null}}async processQueue(){if(!this.config.enabled||!this.db||this.isProcessing)return [];if(!navigator.onLine)return this.log("Offline, skipping queue processing"),[];this.isProcessing=true;let e=[];try{let t=await this.getAllRequests();t.sort((r,s)=>r.priority!==s.priority?s.priority-r.priority:r.queuedAt-s.queuedAt),this.log(`Processing ${t.length} queued requests`);for(let r of t){if(!navigator.onLine){this.log("Went offline during processing, stopping");break}let s=await this.processRequest(r);e.push(s),s.success||!s.shouldRetry?await this.removeFromStore(r.id):await this.updateRetryCount(r),this.onRequestProcessed?.(s),await this.delay(100);}let i=await this.getQueueCount();i===0&&this.onQueueEmpty?.(),this.log(`Processed ${e.length} requests, ${i} remaining`);}catch(t){let i=t instanceof Error?t:new Error(String(t));this.log(`Error processing queue: ${i.message}`,"error"),this.onError?.(i);}finally{this.isProcessing=false;}return e}async processRequest(e){let t={id:e.id,success:false,shouldRetry:false};try{let i=await fetch(e.url,{method:e.method,headers:e.headers,body:e.body});t.statusCode=i.status,t.success=i.ok,i.ok||(t.shouldRetry=this.shouldRetryStatus(i.status,e),t.error=`HTTP ${i.status}`),this.log(`Request ${e.id}: ${t.success?"success":"failed"} (${i.status})`);}catch(i){let r=i instanceof Error?i:new Error(String(i));t.error=r.message,t.shouldRetry=e.retryCount<e.maxRetries,this.log(`Request ${e.id} failed: ${r.message}`,"error");}return t}shouldRetryStatus(e,t){return t.retryCount>=t.maxRetries?false:e>=500||e===408||e===429||e===0}async updateRetryCount(e){e.retryCount++;let i=this.db.transaction([u],"readwrite").objectStore(u);await this.promisifyRequest(i.put(e));}async getStats(){let e={totalQueued:0,byType:{registration:0,heartbeat:0,analytics:0,preferences:0,unregister:0,custom:0}};if(!this.db)return e;try{let t=await this.getAllRequests();e.totalQueued=t.length;for(let i of t)e.byType[i.requestType]++,(!e.oldestRequest||i.queuedAt<e.oldestRequest)&&(e.oldestRequest=i.queuedAt),(!e.newestRequest||i.queuedAt>e.newestRequest)&&(e.newestRequest=i.queuedAt);}catch(t){this.log(`Failed to get stats: ${t}`,"error");}return e}async clearQueue(){if(!this.db)return;let t=this.db.transaction([u],"readwrite").objectStore(u);await this.promisifyRequest(t.clear()),this.log("Queue cleared");}async hasPendingRequests(){return await this.getQueueCount()>0}async getQueueCount(){if(!this.db)return 0;let t=this.db.transaction([u],"readonly").objectStore(u);return this.promisifyRequest(t.count())}async openDatabase(){return new Promise((e,t)=>{let i=indexedDB.open(pe,2);i.onerror=()=>t(i.error),i.onsuccess=()=>{this.db=i.result,e();},i.onupgradeneeded=r=>{let s=r.target.result;if(!s.objectStoreNames.contains(u)){let o=s.createObjectStore(u,{keyPath:"id",autoIncrement:true});o.createIndex("queuedAt","queuedAt",{unique:false}),o.createIndex("requestType","requestType",{unique:false}),o.createIndex("priority","priority",{unique:false});}if(s.objectStoreNames.contains("badge")||s.createObjectStore("badge"),!s.objectStoreNames.contains("notifications")){let o=s.createObjectStore("notifications",{keyPath:"id",autoIncrement:true});o.createIndex("timestamp","timestamp",{unique:false}),o.createIndex("read","read",{unique:false});}s.objectStoreNames.contains("userPreferences")||s.createObjectStore("userPreferences"),s.objectStoreNames.contains("syncQueue")||s.createObjectStore("syncQueue",{keyPath:"id",autoIncrement:true}).createIndex("timestamp","timestamp",{unique:false});};})}async addToStore(e){let i=this.db.transaction([u],"readwrite").objectStore(u);return this.promisifyRequest(i.add(e))}async removeFromStore(e){let i=this.db.transaction([u],"readwrite").objectStore(u);await this.promisifyRequest(i.delete(e));}async getAllRequests(){let t=this.db.transaction([u],"readonly").objectStore(u);return this.promisifyRequest(t.getAll())}async removeOldestRequest(){let t=this.db.transaction([u],"readwrite").objectStore(u),r=t.index("queuedAt").openCursor();return new Promise((s,o)=>{r.onsuccess=l=>{let c=l.target.result;c&&t.delete(c.primaryKey),s();},r.onerror=()=>o(r.error);})}async cleanupOldRequests(){let e=Date.now()-this.config.maxAge,i=this.db.transaction([u],"readwrite").objectStore(u),r=i.index("queuedAt"),s=IDBKeyRange.upperBound(e),o=r.openCursor(s),l=0;return new Promise(c=>{o.onsuccess=d=>{let a=d.target.result;a?(i.delete(a.primaryKey),l++,a.continue()):(l>0&&this.log(`Cleaned up ${l} old requests`),c());},o.onerror=()=>c();})}promisifyRequest(e){return new Promise((t,i)=>{e.onsuccess=()=>t(e.result),e.onerror=()=>i(e.error);})}delay(e){return new Promise(t=>setTimeout(t,e))}log(e,t="log"){if(!this.debug&&t==="log")return;console[t](`[CloudSignal PWA OfflineQueue] ${e}`);}};var C={en:{title:"Install this app",description:"Add this app to your home screen for the best experience.",buttonText:"Show me how",closeText:"Not now",step1:"Tap the Share button at the bottom of Safari",step2:'Scroll down and tap "Add to Home Screen"',step3:'Tap "Add" in the top right corner',shareIconHint:"Look for the Share icon",shareIconDescription:"It's the square with an arrow pointing up"},es:{title:"Instalar esta aplicaci\xF3n",description:"A\xF1ade esta aplicaci\xF3n a tu pantalla de inicio para una mejor experiencia.",buttonText:"Mostrar c\xF3mo",closeText:"Ahora no",step1:"Toca el bot\xF3n Compartir en la parte inferior de Safari",step2:'Despl\xE1zate hacia abajo y toca "A\xF1adir a pantalla de inicio"',step3:'Toca "A\xF1adir" en la esquina superior derecha',shareIconHint:"Busca el icono de Compartir",shareIconDescription:"Es el cuadrado con una flecha apuntando hacia arriba"},fr:{title:"Installer cette application",description:"Ajoutez cette application \xE0 votre \xE9cran d'accueil pour une meilleure exp\xE9rience.",buttonText:"Montrez-moi comment",closeText:"Pas maintenant",step1:"Appuyez sur le bouton Partager en bas de Safari",step2:`Faites d\xE9filer vers le bas et appuyez sur "Sur l'\xE9cran d'accueil"`,step3:'Appuyez sur "Ajouter" dans le coin sup\xE9rieur droit',shareIconHint:"Recherchez l'ic\xF4ne Partager",shareIconDescription:"C'est le carr\xE9 avec une fl\xE8che pointant vers le haut"},de:{title:"Diese App installieren",description:"F\xFCgen Sie diese App zu Ihrem Startbildschirm hinzu f\xFCr das beste Erlebnis.",buttonText:"Zeig mir wie",closeText:"Nicht jetzt",step1:"Tippen Sie auf die Teilen-Schaltfl\xE4che unten in Safari",step2:'Scrollen Sie nach unten und tippen Sie auf "Zum Home-Bildschirm"',step3:'Tippen Sie oben rechts auf "Hinzuf\xFCgen"',shareIconHint:"Suchen Sie das Teilen-Symbol",shareIconDescription:"Es ist das Quadrat mit einem Pfeil nach oben"},it:{title:"Installa questa app",description:"Aggiungi questa app alla schermata Home per un'esperienza migliore.",buttonText:"Mostrami come",closeText:"Non ora",step1:"Tocca il pulsante Condividi nella parte inferiore di Safari",step2:'Scorri verso il basso e tocca "Aggiungi a Home"',step3:`Tocca "Aggiungi" nell'angolo in alto a destra`,shareIconHint:"Cerca l'icona Condividi",shareIconDescription:"\xC8 il quadrato con una freccia che punta verso l'alto"},pt:{title:"Instalar este aplicativo",description:"Adicione este aplicativo \xE0 tela inicial para a melhor experi\xEAncia.",buttonText:"Mostre-me como",closeText:"Agora n\xE3o",step1:"Toque no bot\xE3o Compartilhar na parte inferior do Safari",step2:'Role para baixo e toque em "Adicionar \xE0 Tela de In\xEDcio"',step3:'Toque em "Adicionar" no canto superior direito',shareIconHint:"Procure o \xEDcone Compartilhar",shareIconDescription:"\xC9 o quadrado com uma seta apontando para cima"},nl:{title:"Installeer deze app",description:"Voeg deze app toe aan je beginscherm voor de beste ervaring.",buttonText:"Laat me zien hoe",closeText:"Niet nu",step1:"Tik op de Deel-knop onderaan Safari",step2:'Scroll naar beneden en tik op "Zet op beginscherm"',step3:'Tik rechtsboven op "Voeg toe"',shareIconHint:"Zoek het Deel-icoon",shareIconDescription:"Het is het vierkant met een pijl omhoog"},ru:{title:"\u0423\u0441\u0442\u0430\u043D\u043E\u0432\u0438\u0442\u044C \u043F\u0440\u0438\u043B\u043E\u0436\u0435\u043D\u0438\u0435",description:"\u0414\u043E\u0431\u0430\u0432\u044C\u0442\u0435 \u044D\u0442\u043E \u043F\u0440\u0438\u043B\u043E\u0436\u0435\u043D\u0438\u0435 \u043D\u0430 \u0433\u043B\u0430\u0432\u043D\u044B\u0439 \u044D\u043A\u0440\u0430\u043D \u0434\u043B\u044F \u043B\u0443\u0447\u0448\u0435\u0433\u043E \u043E\u043F\u044B\u0442\u0430.",buttonText:"\u041F\u043E\u043A\u0430\u0436\u0438\u0442\u0435 \u043A\u0430\u043A",closeText:"\u041D\u0435 \u0441\u0435\u0439\u0447\u0430\u0441",step1:'\u041D\u0430\u0436\u043C\u0438\u0442\u0435 \u043A\u043D\u043E\u043F\u043A\u0443 "\u041F\u043E\u0434\u0435\u043B\u0438\u0442\u044C\u0441\u044F" \u0432\u043D\u0438\u0437\u0443 Safari',step2:'\u041F\u0440\u043E\u043A\u0440\u0443\u0442\u0438\u0442\u0435 \u0432\u043D\u0438\u0437 \u0438 \u043D\u0430\u0436\u043C\u0438\u0442\u0435 "\u041D\u0430 \u044D\u043A\u0440\u0430\u043D \u0414\u043E\u043C\u043E\u0439"',step3:'\u041D\u0430\u0436\u043C\u0438\u0442\u0435 "\u0414\u043E\u0431\u0430\u0432\u0438\u0442\u044C" \u0432 \u043F\u0440\u0430\u0432\u043E\u043C \u0432\u0435\u0440\u0445\u043D\u0435\u043C \u0443\u0433\u043B\u0443',shareIconHint:'\u041D\u0430\u0439\u0434\u0438\u0442\u0435 \u0437\u043D\u0430\u0447\u043E\u043A "\u041F\u043E\u0434\u0435\u043B\u0438\u0442\u044C\u0441\u044F"',shareIconDescription:"\u042D\u0442\u043E \u043A\u0432\u0430\u0434\u0440\u0430\u0442 \u0441\u043E \u0441\u0442\u0440\u0435\u043B\u043A\u043E\u0439 \u0432\u0432\u0435\u0440\u0445"},zh:{title:"\u5B89\u88C5\u6B64\u5E94\u7528",description:"\u5C06\u6B64\u5E94\u7528\u6DFB\u52A0\u5230\u4E3B\u5C4F\u5E55\u4EE5\u83B7\u5F97\u6700\u4F73\u4F53\u9A8C\u3002",buttonText:"\u663E\u793A\u65B9\u6CD5",closeText:"\u6682\u65F6\u4E0D\u8981",step1:"\u70B9\u51FBSafari\u5E95\u90E8\u7684\u5206\u4EAB\u6309\u94AE",step2:'\u5411\u4E0B\u6EDA\u52A8\u5E76\u70B9\u51FB"\u6DFB\u52A0\u5230\u4E3B\u5C4F\u5E55"',step3:'\u70B9\u51FB\u53F3\u4E0A\u89D2\u7684"\u6DFB\u52A0"',shareIconHint:"\u627E\u5230\u5206\u4EAB\u56FE\u6807",shareIconDescription:"\u662F\u4E00\u4E2A\u5E26\u6709\u5411\u4E0A\u7BAD\u5934\u7684\u65B9\u6846"},ja:{title:"\u3053\u306E\u30A2\u30D7\u30EA\u3092\u30A4\u30F3\u30B9\u30C8\u30FC\u30EB",description:"\u30DB\u30FC\u30E0\u753B\u9762\u306B\u8FFD\u52A0\u3057\u3066\u6700\u9AD8\u306E\u4F53\u9A13\u3092\u3002",buttonText:"\u65B9\u6CD5\u3092\u898B\u308B",closeText:"\u4ECA\u306F\u3057\u306A\u3044",step1:"Safari\u306E\u4E0B\u90E8\u306B\u3042\u308B\u5171\u6709\u30DC\u30BF\u30F3\u3092\u30BF\u30C3\u30D7",step2:"\u4E0B\u306B\u30B9\u30AF\u30ED\u30FC\u30EB\u3057\u3066\u300C\u30DB\u30FC\u30E0\u753B\u9762\u306B\u8FFD\u52A0\u300D\u3092\u30BF\u30C3\u30D7",step3:"\u53F3\u4E0A\u306E\u300C\u8FFD\u52A0\u300D\u3092\u30BF\u30C3\u30D7",shareIconHint:"\u5171\u6709\u30A2\u30A4\u30B3\u30F3\u3092\u63A2\u3057\u3066\u304F\u3060\u3055\u3044",shareIconDescription:"\u4E0A\u5411\u304D\u77E2\u5370\u306E\u3042\u308B\u56DB\u89D2\u5F62\u3067\u3059"},ko:{title:"\uC774 \uC571 \uC124\uCE58",description:"\uCD5C\uACE0\uC758 \uACBD\u9A13\uC744 \uC704\uD574 \uD648 \uD654\uBA74\uC5D0 \uCD94\uAC00\uD558\uC138\uC694.",buttonText:"\uBC29\uBC95 \uBCF4\uAE30",closeText:"\uB098\uC911\uC5D0",step1:"Safari \uD558\uB2E8\uC758 \uACF5\uC720 \uBC84\uD2BC\uC744 \uD0ED\uD558\uC138\uC694",step2:'\uC544\uB798\uB85C \uC2A4\uD06C\uB864\uD558\uC5EC "\uD648 \uD654\uBA74\uC5D0 \uCD94\uAC00"\uB97C \uD0ED\uD558\uC138\uC694',step3:'\uC624\uB978\uCABD \uC0C1\uB2E8\uC758 "\uCD94\uAC00"\uB97C \uD0ED\uD558\uC138\uC694',shareIconHint:"\uACF5\uC720 \uC544\uC774\uCF58\uC744 \uCC3E\uC73C\uC138\uC694",shareIconDescription:"\uC704\uCABD \uD654\uC0B4\uD45C\uAC00 \uC788\uB294 \uC0AC\uAC01\uD615\uC785\uB2C8\uB2E4"},ar:{title:"\u062A\u062B\u0628\u064A\u062A \u0647\u0630\u0627 \u0627\u0644\u062A\u0637\u0628\u064A\u0642",description:"\u0623\u0636\u0641 \u0647\u0630\u0627 \u0627\u0644\u062A\u0637\u0628\u064A\u0642 \u0625\u0644\u0649 \u0627\u0644\u0634\u0627\u0634\u0629 \u0627\u0644\u0631\u0626\u064A\u0633\u064A\u0629 \u0644\u0644\u062D\u0635\u0648\u0644 \u0639\u0644\u0649 \u0623\u0641\u0636\u0644 \u062A\u062C\u0631\u0628\u0629.",buttonText:"\u0623\u0631\u0646\u064A \u0643\u064A\u0641",closeText:"\u0644\u064A\u0633 \u0627\u0644\u0622\u0646",step1:"\u0627\u0636\u063A\u0637 \u0639\u0644\u0649 \u0632\u0631 \u0627\u0644\u0645\u0634\u0627\u0631\u0643\u0629 \u0641\u064A \u0623\u0633\u0641\u0644 Safari",step2:'\u0645\u0631\u0631 \u0644\u0623\u0633\u0641\u0644 \u0648\u0627\u0636\u063A\u0637 \u0639\u0644\u0649 "\u0625\u0636\u0627\u0641\u0629 \u0625\u0644\u0649 \u0627\u0644\u0634\u0627\u0634\u0629 \u0627\u0644\u0631\u0626\u064A\u0633\u064A\u0629"',step3:'\u0627\u0636\u063A\u0637 \u0639\u0644\u0649 "\u0625\u0636\u0627\u0641\u0629" \u0641\u064A \u0627\u0644\u0632\u0627\u0648\u064A\u0629 \u0627\u0644\u0639\u0644\u0648\u064A\u0629 \u0627\u0644\u064A\u0645\u0646\u0649',shareIconHint:"\u0627\u0628\u062D\u062B \u0639\u0646 \u0623\u064A\u0642\u0648\u0646\u0629 \u0627\u0644\u0645\u0634\u0627\u0631\u0643\u0629",shareIconDescription:"\u0647\u0648 \u0645\u0631\u0628\u0639 \u0645\u0639 \u0633\u0647\u0645 \u064A\u0634\u064A\u0631 \u0644\u0623\u0639\u0644\u0649"},he:{title:"\u05D4\u05EA\u05E7\u05DF \u05D0\u05E4\u05DC\u05D9\u05E7\u05E6\u05D9\u05D4 \u05D6\u05D5",description:"\u05D4\u05D5\u05E1\u05E3 \u05D0\u05E4\u05DC\u05D9\u05E7\u05E6\u05D9\u05D4 \u05D6\u05D5 \u05DC\u05DE\u05E1\u05DA \u05D4\u05D1\u05D9\u05EA \u05DC\u05D7\u05D5\u05D5\u05D9\u05D4 \u05D4\u05D8\u05D5\u05D1\u05D4 \u05D1\u05D9\u05D5\u05EA\u05E8.",buttonText:"\u05D4\u05E8\u05D0\u05D4 \u05DC\u05D9 \u05D0\u05D9\u05DA",closeText:"\u05DC\u05D0 \u05E2\u05DB\u05E9\u05D9\u05D5",step1:"\u05D4\u05E7\u05E9 \u05E2\u05DC \u05DB\u05E4\u05EA\u05D5\u05E8 \u05D4\u05E9\u05D9\u05EA\u05D5\u05E3 \u05D1\u05EA\u05D7\u05EA\u05D9\u05EA Safari",step2:'\u05D2\u05DC\u05D5\u05DC \u05DC\u05DE\u05D8\u05D4 \u05D5\u05D4\u05E7\u05E9 \u05E2\u05DC "\u05D4\u05D5\u05E1\u05E3 \u05DC\u05DE\u05E1\u05DA \u05D4\u05D1\u05D9\u05EA"',step3:'\u05D4\u05E7\u05E9 \u05E2\u05DC "\u05D4\u05D5\u05E1\u05E3" \u05D1\u05E4\u05D9\u05E0\u05D4 \u05D4\u05D9\u05DE\u05E0\u05D9\u05EA \u05D4\u05E2\u05DC\u05D9\u05D5\u05E0\u05D4',shareIconHint:"\u05D7\u05E4\u05E9 \u05D0\u05EA \u05E1\u05DE\u05DC \u05D4\u05E9\u05D9\u05EA\u05D5\u05E3",shareIconDescription:"\u05D6\u05D4 \u05E8\u05D9\u05D1\u05D5\u05E2 \u05E2\u05DD \u05D7\u05E5 \u05DE\u05E6\u05D1\u05D9\u05E2 \u05DC\u05DE\u05E2\u05DC\u05D4"},hi:{title:"\u092F\u0939 \u0910\u092A \u0907\u0902\u0938\u094D\u091F\u0949\u0932 \u0915\u0930\u0947\u0902",description:"\u092C\u0947\u0939\u0924\u0930 \u0905\u0928\u0941\u092D\u0935 \u0915\u0947 \u0932\u093F\u090F \u0907\u0938 \u0910\u092A \u0915\u094B \u0939\u094B\u092E \u0938\u094D\u0915\u094D\u0930\u0940\u0928 \u092A\u0930 \u091C\u094B\u0921\u093C\u0947\u0902\u0964",buttonText:"\u092E\u0941\u091D\u0947 \u0926\u093F\u0916\u093E\u0913 \u0915\u0948\u0938\u0947",closeText:"\u0905\u092D\u0940 \u0928\u0939\u0940\u0902",step1:"Safari \u0915\u0947 \u0928\u0940\u091A\u0947 \u0936\u0947\u092F\u0930 \u092C\u091F\u0928 \u092A\u0930 \u091F\u0948\u092A \u0915\u0930\u0947\u0902",step2:'\u0928\u0940\u091A\u0947 \u0938\u094D\u0915\u094D\u0930\u0949\u0932 \u0915\u0930\u0947\u0902 \u0914\u0930 "\u0939\u094B\u092E \u0938\u094D\u0915\u094D\u0930\u0940\u0928 \u092E\u0947\u0902 \u091C\u094B\u0921\u093C\u0947\u0902" \u092A\u0930 \u091F\u0948\u092A \u0915\u0930\u0947\u0902',step3:'\u090A\u092A\u0930 \u0926\u093E\u090F\u0902 \u0915\u094B\u0928\u0947 \u092E\u0947\u0902 "\u091C\u094B\u0921\u093C\u0947\u0902" \u092A\u0930 \u091F\u0948\u092A \u0915\u0930\u0947\u0902',shareIconHint:"\u0936\u0947\u092F\u0930 \u0906\u0907\u0915\u0928 \u0916\u094B\u091C\u0947\u0902",shareIconDescription:"\u092F\u0939 \u090A\u092A\u0930 \u0915\u0940 \u0913\u0930 \u0924\u0940\u0930 \u0935\u093E\u0932\u093E \u0935\u0930\u094D\u0917 \u0939\u0948"},tr:{title:"Bu uygulamay\u0131 y\xFCkle",description:"En iyi deneyim i\xE7in bu uygulamay\u0131 ana ekran\u0131n\u0131za ekleyin.",buttonText:"Nas\u0131l yap\u0131l\u0131r g\xF6ster",closeText:"\u015Eimdi de\u011Fil",step1:"Safari'nin alt\u0131ndaki Payla\u015F d\xFC\u011Fmesine dokunun",step2:'A\u015Fa\u011F\u0131 kayd\u0131r\u0131n ve "Ana Ekrana Ekle"ye dokunun',step3:'Sa\u011F \xFCst k\xF6\u015Fedeki "Ekle"ye dokunun',shareIconHint:"Payla\u015F simgesini aray\u0131n",shareIconDescription:"Yukar\u0131 bakan oklu bir karedir"},pl:{title:"Zainstaluj t\u0119 aplikacj\u0119",description:"Dodaj t\u0119 aplikacj\u0119 do ekranu g\u0142\xF3wnego, aby uzyska\u0107 najlepsze wra\u017Cenia.",buttonText:"Poka\u017C mi jak",closeText:"Nie teraz",step1:"Dotknij przycisku Udost\u0119pnij na dole Safari",step2:'Przewi\u0144 w d\xF3\u0142 i dotknij "Dodaj do ekranu pocz\u0105tkowego"',step3:'Dotknij "Dodaj" w prawym g\xF3rnym rogu',shareIconHint:"Poszukaj ikony Udost\u0119pnij",shareIconDescription:"To kwadrat ze strza\u0142k\u0105 skierowan\u0105 w g\xF3r\u0119"},sv:{title:"Installera denna app",description:"L\xE4gg till denna app p\xE5 hemsk\xE4rmen f\xF6r b\xE4sta upplevelse.",buttonText:"Visa mig hur",closeText:"Inte nu",step1:"Tryck p\xE5 Dela-knappen l\xE4ngst ner i Safari",step2:'Scrolla ner och tryck p\xE5 "L\xE4gg till p\xE5 hemsk\xE4rmen"',step3:'Tryck p\xE5 "L\xE4gg till" i \xF6vre h\xF6gra h\xF6rnet',shareIconHint:"Leta efter Dela-ikonen",shareIconDescription:"Det \xE4r kvadraten med en pil som pekar upp\xE5t"},da:{title:"Installer denne app",description:"F\xF8j denne app til din startsk\xE6rm for den bedste oplevelse.",buttonText:"Vis mig hvordan",closeText:"Ikke nu",step1:"Tryk p\xE5 Del-knappen nederst i Safari",step2:'Rul ned og tryk p\xE5 "F\xF8j til hjemmesk\xE6rm"',step3:'Tryk p\xE5 "Tilf\xF8j" i \xF8verste h\xF8jre hj\xF8rne',shareIconHint:"Kig efter Del-ikonet",shareIconDescription:"Det er firkanten med en pil, der peger opad"},no:{title:"Installer denne appen",description:"Legg til denne appen p\xE5 startskjermen for best opplevelse.",buttonText:"Vis meg hvordan",closeText:"Ikke n\xE5",step1:"Trykk p\xE5 Del-knappen nederst i Safari",step2:'Rull ned og trykk p\xE5 "Legg til p\xE5 Hjem-skjerm"',step3:'Trykk p\xE5 "Legg til" \xF8verst til h\xF8yre',shareIconHint:"Se etter Del-ikonet",shareIconDescription:"Det er firkanten med en pil som peker oppover"},fi:{title:"Asenna t\xE4m\xE4 sovellus",description:"Lis\xE4\xE4 t\xE4m\xE4 sovellus aloitusn\xE4yt\xF6lle parhaan kokemuksen saamiseksi.",buttonText:"N\xE4yt\xE4 miten",closeText:"Ei nyt",step1:"Napauta Jaa-painiketta Safarin alareunassa",step2:'Vierit\xE4 alas ja napauta "Lis\xE4\xE4 Koti-valikkoon"',step3:'Napauta "Lis\xE4\xE4" oikeassa yl\xE4kulmassa',shareIconHint:"Etsi Jaa-kuvake",shareIconDescription:"Se on neli\xF6, jossa on yl\xF6sp\xE4in osoittava nuoli"}};function B(){let n=navigator.language?.toLowerCase()||"en",e=n.split("-")[0];return e in C?e:n.startsWith("zh")?"zh":n.startsWith("pt")?"pt":n.startsWith("no")||n.startsWith("nb")||n.startsWith("nn")?"no":"en"}var L="cloudsignal_pwa_ios_banner_dismissed",m="cloudsignal-ios-install-banner",fe={backgroundColor:"#ffffff",textColor:"#1a1a1a",buttonBackgroundColor:"#007AFF",buttonTextColor:"#ffffff",borderRadius:"16px",boxShadow:"0 4px 24px rgba(0, 0, 0, 0.15)"},D=class{constructor(e={}){this.bannerElement=null;this.overlayElement=null;this.debug=e.debug??false,this.onShow=e.onShow,this.onDismiss=e.onDismiss,this.onInstallClick=e.onInstallClick,this.language=e.language??B();let t=C[this.language];this.strings={...t,...e.customStrings},this.config={enabled:e.config?.enabled??true,title:e.config?.title??this.strings.title,description:e.config?.description??this.strings.description,buttonText:e.config?.buttonText??this.strings.buttonText,closeText:e.config?.closeText??this.strings.closeText,iconUrl:e.config?.iconUrl,customStyles:e.config?.customStyles??{},showDelay:e.config?.showDelay??3e3,dismissalDays:e.config?.dismissalDays??7,position:e.config?.position??"bottom"},this.styles={...fe,...this.config.customStyles},this.log(`Initialized with language: ${this.language}`);}getLanguage(){return this.language}getStrings(){return this.strings}setLanguage(e){this.language=e;let t=C[e];this.strings={...t},this.config.title=this.strings.title,this.config.description=this.strings.description,this.config.buttonText=this.strings.buttonText,this.config.closeText=this.strings.closeText,this.log(`Language changed to: ${e}`);}getState(){return {isVisible:this.bannerElement!==null,wasDismissed:this.wasDismissed(),isEligible:this.isEligible(),isInstalled:this.isInstalled()}}isEligible(){let e=navigator.userAgent;return !(!(/iPad|iPhone|iPod/.test(e)&&!window.MSStream)||!(/Safari/i.test(e)&&!/Chrome|CriOS|FxiOS|EdgiOS/i.test(e))||this.isInstalled())}isInstalled(){return !!(navigator.standalone===true||window.matchMedia("(display-mode: standalone)").matches)}wasDismissed(){try{let e=localStorage.getItem(L);if(!e)return !1;let t=parseInt(e,10);return (Date.now()-t)/(1e3*60*60*24)>this.config.dismissalDays?(localStorage.removeItem(L),!1):!0}catch{return false}}async show(){return this.config.enabled?this.isEligible()?this.wasDismissed()?(this.log("Banner was dismissed recently"),false):this.bannerElement?(this.log("Banner already visible"),true):(this.config.showDelay>0&&await new Promise(e=>setTimeout(e,this.config.showDelay)),!this.isEligible()||this.wasDismissed()?false:(this.createBanner(),this.log("Banner shown"),this.onShow?.(),true)):(this.log("Device not eligible for iOS install banner"),false):(this.log("Banner is disabled"),false)}hide(){this.bannerElement&&(this.bannerElement.remove(),this.bannerElement=null),this.overlayElement&&(this.overlayElement.remove(),this.overlayElement=null);}dismiss(){this.hide();try{localStorage.setItem(L,Date.now().toString());}catch{}this.log("Banner dismissed"),this.onDismiss?.();}resetDismissal(){try{localStorage.removeItem(L);}catch{}}getInstallSteps(){return [this.strings.step1,this.strings.step2,this.strings.step3]}createBanner(){this.overlayElement=document.createElement("div"),this.overlayElement.id=`${m}-overlay`,this.overlayElement.style.cssText=`
|
|
8
8
|
position: fixed;
|
|
9
9
|
top: 0;
|
|
10
10
|
left: 0;
|
|
@@ -80,7 +80,7 @@ var te=Object.defineProperty;var ie=(n,e)=>()=>(n&&(e=n(n=0)),e);var re=(n,e)=>{
|
|
|
80
80
|
">${this.config.closeText}</button>
|
|
81
81
|
</div>
|
|
82
82
|
</div>
|
|
83
|
-
`,document.body.appendChild(this.bannerElement);let r=document.getElementById(`${m}-show`),s=document.getElementById(`${m}-close`),o=document.getElementById(`${m}-steps`);r?.addEventListener("click",()=>{o&&(o.style.display=o.style.display==="none"?"block":"none",r.textContent=o.style.display==="none"?this.config.buttonText:"Got it!"),this.onInstallClick?.();}),s?.addEventListener("click",()=>this.dismiss()),requestAnimationFrame(()=>{this.overlayElement&&(this.overlayElement.style.opacity="1"),this.bannerElement&&(this.bannerElement.style.opacity="1",this.bannerElement.style.transform="translateY(0)");});}log(e,t="log"){if(!this.debug&&t==="log")return;console[t](`[CloudSignal PWA IOSBanner] ${e}`);}};var pe="https://pwa.cloudsignal.app",Z="1.2.0",M=class{constructor(e){this.initialized=false;this.serviceConfig=null;this.wakeLockManager=null;this.offlineQueueManager=null;this.iosInstallBanner=null;this.eventHandlers=new Map;if(this.config=e,this.serviceUrl=e.serviceUrl||pe,this.debug=e.debug??false,!e.organizationSecret&&!e.userToken)throw new Error("Either organizationSecret or userToken must be provided");if(this.authContext=y({organizationId:e.organizationId,organizationSecret:e.organizationSecret,userToken:e.userToken}),this.deviceDetector=new f,this.serviceWorkerManager=new I({config:e.serviceWorker,debug:this.debug,onRegistered:t=>this.emit("sw:registered",{registration:t}),onUpdated:t=>this.emit("sw:updated",{registration:t}),onError:t=>this.emit("sw:error",{error:t})}),this.installationManager=new k({debug:this.debug,onInstallAvailable:t=>this.emit("install:available",{platforms:t.platforms}),onInstallAccepted:t=>this.emit("install:accepted",t),onInstallDismissed:t=>this.emit("install:dismissed",t),onInstalled:()=>this.emit("install:completed",{})}),this.pushNotificationManager=new x({serviceUrl:this.serviceUrl,organizationId:e.organizationId,organizationSecret:e.organizationSecret,userToken:e.userToken,onTokenExpired:e.onTokenExpired,serviceId:e.serviceId,debug:this.debug,onRegistered:t=>{this.emit("push:registered",{registrationId:t.registrationId,endpoint:""}),this.heartbeatManager.setRegistrationId(t.registrationId);},onUnregistered:()=>{this.emit("push:unregistered",{}),this.heartbeatManager.stop();},onError:t=>this.emit("push:error",{error:t}),onPermissionDenied:()=>this.emit("permission:denied",{permission:"denied"})}),this.heartbeatManager=new R({serviceUrl:this.serviceUrl,organizationId:e.organizationId,organizationSecret:e.organizationSecret,userToken:e.userToken,onTokenExpired:e.onTokenExpired,config:e.heartbeat,debug:this.debug,onHeartbeatSent:()=>this.emit("heartbeat:sent",{timestamp:Date.now()}),onHeartbeatError:t=>this.emit("heartbeat:error",{timestamp:Date.now(),error:t.message}),onIntervalChanged:(t,i)=>this.emit("heartbeat:intervalChanged",{interval:t,reason:i}),onPausedForBattery:()=>this.emit("heartbeat:pausedForBattery",{timestamp:Date.now()}),onResumedFromBattery:()=>this.emit("heartbeat:resumedFromBattery",{timestamp:Date.now()})}),e.wakeLock?.enabled!==false&&(this.wakeLockManager=new E({config:{enabled:e.wakeLock?.enabled??true,autoReacquire:e.wakeLock?.reacquireOnVisibility??true},debug:this.debug,onAcquired:()=>this.emit("wakeLock:acquired",{timestamp:Date.now()}),onReleased:t=>this.emit("wakeLock:released",{reason:t.reason,timestamp:Date.now()}),onError:t=>this.emit("wakeLock:error",{error:t.error})})),e.offlineQueue?.enabled!==false&&(this.offlineQueueManager=new T({config:{enabled:e.offlineQueue?.enabled??true,maxQueueSize:e.offlineQueue?.maxQueueSize??100,maxAge:(e.offlineQueue?.maxAgeTTLHours??24)*60*60*1e3,processOnOnline:e.offlineQueue?.autoProcessOnOnline??true},debug:this.debug,onRequestQueued:t=>this.emit("offlineQueue:queued",{url:t.url,method:t.method}),onRequestProcessed:t=>this.emit("offlineQueue:processed",{success:t.success,requestId:t.id}),onQueueEmpty:()=>this.emit("offlineQueue:flushed",{})})),e.iosInstallBanner?.enabled!==false){let t=this.deviceDetector.getDeviceInfo();t.isIOS&&t.browser==="Safari"&&(this.iosInstallBanner=new B({config:{enabled:e.iosInstallBanner?.enabled??true,title:e.iosInstallBanner?.title,description:e.iosInstallBanner?.subtitle,iconUrl:e.iosInstallBanner?.iconUrl,showDelay:e.iosInstallBanner?.showDelay,dismissalDays:e.iosInstallBanner?.dismissRememberDays},debug:this.debug,onShow:()=>this.emit("iosBanner:shown",{}),onDismiss:()=>this.emit("iosBanner:dismissed",{}),onInstallClick:()=>this.emit("iosBanner:installClicked",{})}));}this.log(`CloudSignal PWA SDK v${Z} initialized`);}async initialize(){try{this.log("Initializing PWA client..."),this.installationManager.initialize();let e=await this.serviceWorkerManager.register();e&&this.pushNotificationManager.setServiceWorkerRegistration(e);let t=await this.downloadConfig();this.setupNetworkListeners(),this.offlineQueueManager&&await this.offlineQueueManager.initialize(),this.config.notificationAnalytics?.enabled!==!1&&e&&this.configureNotificationAnalytics(e),this.iosInstallBanner&&this.config.iosInstallBanner?.showOnFirstVisit!==!1&&(this.installationManager.getState().isInstalled||this.iosInstallBanner.show()),this.initialized=!0;let i={success:!0,config:t||void 0,deviceInfo:this.deviceDetector.getDeviceInfo(),installationState:this.installationManager.getState()};return this.log("PWA client initialized successfully"),i}catch(e){let t=e instanceof Error?e:new Error(String(e));return this.log(`Initialization failed: ${t.message}`,"error"),{success:false,error:t.message}}}async downloadConfig(){try{let e=`${this.serviceUrl}/api/v1/config/download`,t=await h(this.authContext,"POST",e,{organization_id:this.config.organizationId},this.config.onTokenExpired);if(!t.ok)throw new Error(`Config download failed: ${t.status}`);let i=await t.json();return this.serviceConfig=i,i.vapid_public_key&&this.pushNotificationManager.setVapidPublicKey(i.vapid_public_key),i.manifest_url&&this.injectManifest(i.manifest_url),this.emit("config:loaded",{config:i}),this.log("Configuration downloaded successfully"),i}catch(e){let t=e instanceof Error?e:new Error(String(e));return this.log(`Config download failed: ${t.message}`,"error"),this.emit("config:error",{error:t}),null}}async showInstallPrompt(){return this.installationManager.showInstallPrompt()}getInstallationState(){return this.installationManager.getState()}canInstall(){return this.installationManager.canInstall()}isInstalled(){return this.installationManager.isPWAInstalled()}getInstallSteps(){return this.installationManager.getInstallSteps()}async registerForPush(e){return this.pushNotificationManager.register(e)}async unregisterFromPush(){return this.pushNotificationManager.unregister()}async updatePreferences(e){return this.pushNotificationManager.updatePreferences(e)}async checkRegistrationStatus(){return this.pushNotificationManager.checkStatus()}getRegistrationId(){return this.pushNotificationManager.getRegistrationId()}isRegistered(){return this.pushNotificationManager.isRegistered()}async requestPermission(){return this.pushNotificationManager.requestPermission()}getAuthMode(){return this.authContext.mode}setUserToken(e){this.authContext=b(this.authContext,e),this.pushNotificationManager.updateToken(e),this.heartbeatManager.updateToken(e),this.emit("auth:tokenUpdated",{mode:this.authContext.mode}),this.log(`Auth mode updated to: ${this.authContext.mode}`);}getDeviceInfo(){return this.deviceDetector.getDeviceInfo()}getCapabilities(){return this.deviceDetector.getCapabilities()}startHeartbeat(){let e=this.pushNotificationManager.getRegistrationId();e?(this.heartbeatManager.setRegistrationId(e),this.heartbeatManager.start(),this.emit("heartbeat:started",{timestamp:Date.now()})):this.log("Cannot start heartbeat: not registered","warn");}stopHeartbeat(){this.heartbeatManager.stop(),this.emit("heartbeat:stopped",{timestamp:Date.now()});}getHeartbeatInterval(){return this.heartbeatManager.getCurrentInterval()}getNetworkInfo(){return this.heartbeatManager.getNetworkInfo()}async getBatteryInfo(){return this.heartbeatManager.getBatteryInfo()}async requestWakeLock(){return this.wakeLockManager?this.wakeLockManager.acquire():(this.log("Wake lock manager not initialized","warn"),false)}releaseWakeLock(){this.wakeLockManager?.release();}getWakeLockState(){return this.wakeLockManager?this.wakeLockManager.getState():{isSupported:false,isActive:false}}async queueOfflineRequest(e,t,i){return this.offlineQueueManager?this.offlineQueueManager.queueRequest(e,t,{body:i?.body,headers:i?.headers}):(this.log("Offline queue manager not initialized","warn"),null)}async processOfflineQueue(){return this.offlineQueueManager?this.offlineQueueManager.processQueue():[]}async getOfflineQueueStats(){return this.offlineQueueManager?this.offlineQueueManager.getStats():{totalQueued:0,byType:{registration:0,heartbeat:0,analytics:0,preferences:0,unregister:0,custom:0}}}async clearOfflineQueue(){await this.offlineQueueManager?.clearQueue();}showIOSInstallBanner(){if(!this.iosInstallBanner){this.log("iOS install banner not available (not on iOS Safari)","warn");return}this.iosInstallBanner.show();}hideIOSInstallBanner(){this.iosInstallBanner?.hide();}wasIOSBannerDismissed(){return this.iosInstallBanner?.wasDismissed()??false}resetIOSBannerDismissal(){this.iosInstallBanner?.resetDismissal();}clearBadge(){this.serviceWorkerManager.clearBadge();}setBadge(e){this.serviceWorkerManager.setBadge(e);}async checkForUpdates(){return this.serviceWorkerManager.checkForUpdate()}on(e,t){this.eventHandlers.has(e)||this.eventHandlers.set(e,new Set),this.eventHandlers.get(e).add(t);}off(e,t){let i=this.eventHandlers.get(e);i&&i.delete(t);}emit(e,t){let i=this.eventHandlers.get(e);i&&i.forEach(r=>{try{r(t);}catch(s){this.log(`Event handler error for ${e}: ${s}`,"error");}});}getVersion(){return Z}getServiceConfig(){return this.serviceConfig}isInitialized(){return this.initialized}injectManifest(e){let t=document.querySelector('link[rel="manifest"]');t||(t=document.createElement("link"),t.setAttribute("rel","manifest"),document.head.appendChild(t)),t.setAttribute("href",e),this.log(`Manifest injected: ${e}`);}setupNetworkListeners(){window.addEventListener("online",()=>{this.deviceDetector.clearCache(),this.emit("network:online",{isOnline:true}),this.offlineQueueManager&&this.offlineQueueManager.processQueue().catch(e=>{this.log(`Failed to process offline queue: ${e.message}`,"error");});}),window.addEventListener("offline",()=>{this.deviceDetector.clearCache(),this.emit("network:offline",{isOnline:false});});}configureNotificationAnalytics(e){let t=this.config.notificationAnalytics?.endpoint||`${this.serviceUrl}/api/v1/analytics/notifications`;e.active?.postMessage({type:"CONFIGURE_ANALYTICS",config:{enabled:this.config.notificationAnalytics?.enabled!==false,endpoint:t,organizationId:this.config.organizationId}}),this.log("Notification analytics configured");}log(e,t="log"){if(!this.debug&&t==="log")return;console[t](`[CloudSignal PWA] ${e}`);}},fe=M;var N="cloudsignal_pwa_notification_prompt_dismissed",w="cloudsignal-notification-prompt",F={en:{title:"Stay Updated",description:"Get notified about important updates, messages, and alerts.",allowButton:"Enable Notifications",laterButton:"Maybe Later",iosNote:"On iOS, you must first add this app to your home screen."},es:{title:"Mantente Actualizado",description:"Recibe notificaciones sobre actualizaciones importantes, mensajes y alertas.",allowButton:"Activar Notificaciones",laterButton:"Quiz\xE1s Despu\xE9s",iosNote:"En iOS, primero debes a\xF1adir esta aplicaci\xF3n a tu pantalla de inicio."},fr:{title:"Restez Inform\xE9",description:"Recevez des notifications sur les mises \xE0 jour importantes, messages et alertes.",allowButton:"Activer les Notifications",laterButton:"Plus Tard",iosNote:"Sur iOS, vous devez d'abord ajouter cette application \xE0 votre \xE9cran d'accueil."},de:{title:"Bleiben Sie Informiert",description:"Erhalten Sie Benachrichtigungen \xFCber wichtige Updates, Nachrichten und Warnungen.",allowButton:"Benachrichtigungen Aktivieren",laterButton:"Vielleicht Sp\xE4ter",iosNote:"Auf iOS m\xFCssen Sie diese App zuerst zum Startbildschirm hinzuf\xFCgen."},it:{title:"Rimani Aggiornato",description:"Ricevi notifiche su aggiornamenti importanti, messaggi e avvisi.",allowButton:"Attiva Notifiche",laterButton:"Forse Dopo",iosNote:"Su iOS, devi prima aggiungere questa app alla schermata Home."},pt:{title:"Fique Atualizado",description:"Receba notifica\xE7\xF5es sobre atualiza\xE7\xF5es importantes, mensagens e alertas.",allowButton:"Ativar Notifica\xE7\xF5es",laterButton:"Talvez Depois",iosNote:"No iOS, voc\xEA deve primeiro adicionar este aplicativo \xE0 tela inicial."},nl:{title:"Blijf Op De Hoogte",description:"Ontvang meldingen over belangrijke updates, berichten en waarschuwingen.",allowButton:"Meldingen Inschakelen",laterButton:"Misschien Later",iosNote:"Op iOS moet je deze app eerst toevoegen aan je beginscherm."},ru:{title:"\u0411\u0443\u0434\u044C\u0442\u0435 \u0432 \u041A\u0443\u0440\u0441\u0435",description:"\u041F\u043E\u043B\u0443\u0447\u0430\u0439\u0442\u0435 \u0443\u0432\u0435\u0434\u043E\u043C\u043B\u0435\u043D\u0438\u044F \u043E \u0432\u0430\u0436\u043D\u044B\u0445 \u043E\u0431\u043D\u043E\u0432\u043B\u0435\u043D\u0438\u044F\u0445, \u0441\u043E\u043E\u0431\u0449\u0435\u043D\u0438\u044F\u0445 \u0438 \u043F\u0440\u0435\u0434\u0443\u043F\u0440\u0435\u0436\u0434\u0435\u043D\u0438\u044F\u0445.",allowButton:"\u0412\u043A\u043B\u044E\u0447\u0438\u0442\u044C \u0423\u0432\u0435\u0434\u043E\u043C\u043B\u0435\u043D\u0438\u044F",laterButton:"\u041F\u043E\u0437\u0436\u0435",iosNote:"\u041D\u0430 iOS \u0441\u043D\u0430\u0447\u0430\u043B\u0430 \u0434\u043E\u0431\u0430\u0432\u044C\u0442\u0435 \u044D\u0442\u043E \u043F\u0440\u0438\u043B\u043E\u0436\u0435\u043D\u0438\u0435 \u043D\u0430 \u0433\u043B\u0430\u0432\u043D\u044B\u0439 \u044D\u043A\u0440\u0430\u043D."},zh:{title:"\u4FDD\u6301\u66F4\u65B0",description:"\u83B7\u53D6\u91CD\u8981\u66F4\u65B0\u3001\u6D88\u606F\u548C\u63D0\u9192\u7684\u901A\u77E5\u3002",allowButton:"\u542F\u7528\u901A\u77E5",laterButton:"\u7A0D\u540E\u518D\u8BF4",iosNote:"\u5728iOS\u4E0A\uFF0C\u60A8\u5FC5\u987B\u5148\u5C06\u6B64\u5E94\u7528\u6DFB\u52A0\u5230\u4E3B\u5C4F\u5E55\u3002"},ja:{title:"\u6700\u65B0\u60C5\u5831\u3092\u5165\u624B",description:"\u91CD\u8981\u306A\u30A2\u30C3\u30D7\u30C7\u30FC\u30C8\u3001\u30E1\u30C3\u30BB\u30FC\u30B8\u3001\u30A2\u30E9\u30FC\u30C8\u306E\u901A\u77E5\u3092\u53D7\u3051\u53D6\u308A\u307E\u3059\u3002",allowButton:"\u901A\u77E5\u3092\u6709\u52B9\u306B\u3059\u308B",laterButton:"\u5F8C\u3067",iosNote:"iOS\u3067\u306F\u3001\u307E\u305A\u3053\u306E\u30A2\u30D7\u30EA\u3092\u30DB\u30FC\u30E0\u753B\u9762\u306B\u8FFD\u52A0\u3059\u308B\u5FC5\u8981\u304C\u3042\u308A\u307E\u3059\u3002"},ko:{title:"\uCD5C\uC2E0 \uC815\uBCF4 \uBC1B\uAE30",description:"\uC911\uC694\uD55C \uC5C5\uB370\uC774\uD2B8, \uBA54\uC2DC\uC9C0 \uBC0F \uC54C\uB9BC\uC5D0 \uB300\uD55C \uC54C\uB9BC\uC744 \uBC1B\uC73C\uC138\uC694.",allowButton:"\uC54C\uB9BC \uD65C\uC131\uD654",laterButton:"\uB098\uC911\uC5D0",iosNote:"iOS\uC5D0\uC11C\uB294 \uBA3C\uC800 \uC774 \uC571\uC744 \uD648 \uD654\uBA74\uC5D0 \uCD94\uAC00\uD574\uC57C \uD569\uB2C8\uB2E4."},ar:{title:"\u0627\u0628\u0642 \u0639\u0644\u0649 \u0627\u0637\u0644\u0627\u0639",description:"\u0627\u062D\u0635\u0644 \u0639\u0644\u0649 \u0625\u0634\u0639\u0627\u0631\u0627\u062A \u062D\u0648\u0644 \u0627\u0644\u062A\u062D\u062F\u064A\u062B\u0627\u062A \u0627\u0644\u0645\u0647\u0645\u0629 \u0648\u0627\u0644\u0631\u0633\u0627\u0626\u0644 \u0648\u0627\u0644\u062A\u0646\u0628\u064A\u0647\u0627\u062A.",allowButton:"\u062A\u0641\u0639\u064A\u0644 \u0627\u0644\u0625\u0634\u0639\u0627\u0631\u0627\u062A",laterButton:"\u0631\u0628\u0645\u0627 \u0644\u0627\u062D\u0642\u0627\u064B",iosNote:"\u0639\u0644\u0649 iOS\u060C \u064A\u062C\u0628 \u0623\u0648\u0644\u0627\u064B \u0625\u0636\u0627\u0641\u0629 \u0647\u0630\u0627 \u0627\u0644\u062A\u0637\u0628\u064A\u0642 \u0625\u0644\u0649 \u0627\u0644\u0634\u0627\u0634\u0629 \u0627\u0644\u0631\u0626\u064A\u0633\u064A\u0629."},he:{title:"\u05D4\u05D9\u05E9\u05D0\u05E8 \u05DE\u05E2\u05D5\u05D3\u05DB\u05DF",description:"\u05E7\u05D1\u05DC \u05D4\u05EA\u05E8\u05D0\u05D5\u05EA \u05E2\u05DC \u05E2\u05D3\u05DB\u05D5\u05E0\u05D9\u05DD \u05D7\u05E9\u05D5\u05D1\u05D9\u05DD, \u05D4\u05D5\u05D3\u05E2\u05D5\u05EA \u05D5\u05D4\u05EA\u05E8\u05D0\u05D5\u05EA.",allowButton:"\u05D4\u05E4\u05E2\u05DC \u05D4\u05EA\u05E8\u05D0\u05D5\u05EA",laterButton:"\u05D0\u05D5\u05DC\u05D9 \u05DE\u05D0\u05D5\u05D7\u05E8 \u05D9\u05D5\u05EA\u05E8",iosNote:"\u05D1-iOS, \u05E2\u05DC\u05D9\u05DA \u05DC\u05D4\u05D5\u05E1\u05D9\u05E3 \u05EA\u05D7\u05D9\u05DC\u05D4 \u05D0\u05EA \u05D4\u05D0\u05E4\u05DC\u05D9\u05E7\u05E6\u05D9\u05D4 \u05DC\u05DE\u05E1\u05DA \u05D4\u05D1\u05D9\u05EA."},hi:{title:"\u0905\u092A\u0921\u0947\u091F \u0930\u0939\u0947\u0902",description:"\u092E\u0939\u0924\u094D\u0935\u092A\u0942\u0930\u094D\u0923 \u0905\u092A\u0921\u0947\u091F, \u0938\u0902\u0926\u0947\u0936\u094B\u0902 \u0914\u0930 \u0905\u0932\u0930\u094D\u091F \u0915\u0947 \u092C\u093E\u0930\u0947 \u092E\u0947\u0902 \u0938\u0942\u091A\u0928\u093E\u090F\u0902 \u092A\u094D\u0930\u093E\u092A\u094D\u0924 \u0915\u0930\u0947\u0902\u0964",allowButton:"\u0938\u0942\u091A\u0928\u093E\u090F\u0902 \u0938\u0915\u094D\u0937\u092E \u0915\u0930\u0947\u0902",laterButton:"\u092C\u093E\u0926 \u092E\u0947\u0902",iosNote:"iOS \u092A\u0930, \u0906\u092A\u0915\u094B \u092A\u0939\u0932\u0947 \u0907\u0938 \u0910\u092A \u0915\u094B \u0939\u094B\u092E \u0938\u094D\u0915\u094D\u0930\u0940\u0928 \u092A\u0930 \u091C\u094B\u0921\u093C\u0928\u093E \u0939\u094B\u0917\u093E\u0964"},tr:{title:"G\xFCncel Kal\u0131n",description:"\xD6nemli g\xFCncellemeler, mesajlar ve uyar\u0131lar hakk\u0131nda bildirim al\u0131n.",allowButton:"Bildirimleri Etkinle\u015Ftir",laterButton:"Belki Sonra",iosNote:"iOS'ta \xF6nce bu uygulamay\u0131 ana ekran\u0131n\u0131za eklemelisiniz."},pl:{title:"B\u0105d\u017A Na Bie\u017C\u0105co",description:"Otrzymuj powiadomienia o wa\u017Cnych aktualizacjach, wiadomo\u015Bciach i alertach.",allowButton:"W\u0142\u0105cz Powiadomienia",laterButton:"Mo\u017Ce P\xF3\u017Aniej",iosNote:"Na iOS musisz najpierw doda\u0107 t\u0119 aplikacj\u0119 do ekranu g\u0142\xF3wnego."},sv:{title:"H\xE5ll Dig Uppdaterad",description:"F\xE5 aviseringar om viktiga uppdateringar, meddelanden och varningar.",allowButton:"Aktivera Aviseringar",laterButton:"Kanske Senare",iosNote:"P\xE5 iOS m\xE5ste du f\xF6rst l\xE4gga till denna app p\xE5 hemsk\xE4rmen."},da:{title:"Hold Dig Opdateret",description:"F\xE5 notifikationer om vigtige opdateringer, beskeder og advarsler.",allowButton:"Aktiv\xE9r Notifikationer",laterButton:"M\xE5ske Senere",iosNote:"P\xE5 iOS skal du f\xF8rst tilf\xF8je denne app til startsk\xE6rmen."},no:{title:"Hold Deg Oppdatert",description:"F\xE5 varsler om viktige oppdateringer, meldinger og varsler.",allowButton:"Aktiver Varsler",laterButton:"Kanskje Senere",iosNote:"P\xE5 iOS m\xE5 du f\xF8rst legge til denne appen p\xE5 startskjermen."},fi:{title:"Pysy Ajan Tasalla",description:"Saat ilmoituksia t\xE4rkeist\xE4 p\xE4ivityksist\xE4, viesteist\xE4 ja h\xE4lytyksist\xE4.",allowButton:"Ota Ilmoitukset K\xE4ytt\xF6\xF6n",laterButton:"Ehk\xE4 My\xF6hemmin",iosNote:"iOS:ssa sinun on ensin lis\xE4tt\xE4v\xE4 t\xE4m\xE4 sovellus aloitusn\xE4yt\xF6lle."}},me={backgroundColor:"#ffffff",textColor:"#1a1a1a",primaryButtonBackground:"#007AFF",primaryButtonText:"#ffffff",secondaryButtonBackground:"transparent",secondaryButtonText:"#666666",borderRadius:"16px",boxShadow:"0 4px 24px rgba(0, 0, 0, 0.15)"},_=class{constructor(e={}){this.promptElement=null;this.overlayElement=null;this.debug=e.debug??false,this.onAllow=e.onAllow,this.onLater=e.onLater,this.onShow=e.onShow,this.language=e.language??C();let t=F[this.language];this.strings={...t,...e.customStrings},this.config={enabled:e.config?.enabled??true,iconUrl:e.config?.iconUrl??"",showDelay:e.config?.showDelay??2e3,dismissalDays:e.config?.dismissalDays??3,position:e.config?.position??"center",customStyles:e.config?.customStyles??{},showIOSNote:e.config?.showIOSNote??true},this.styles={...me,...this.config.customStyles},this.log(`Initialized with language: ${this.language}`);}getLanguage(){return this.language}setLanguage(e){this.language=e,this.strings={...F[e]},this.log(`Language changed to: ${e}`);}shouldShow(){return !("Notification"in window&&Notification.permission!=="default"||this.wasDismissed())}wasDismissed(){try{let e=localStorage.getItem(N);if(!e)return !1;let t=parseInt(e,10);return (Date.now()-t)/(1e3*60*60*24)>this.config.dismissalDays?(localStorage.removeItem(N),!1):!0}catch{return false}}isIOS(){return /iPad|iPhone|iPod/.test(navigator.userAgent)&&!window.MSStream}isInstalled(){return !!(navigator.standalone===true||window.matchMedia("(display-mode: standalone)").matches)}async show(){return this.config.enabled?this.shouldShow()?this.promptElement?(this.log("Prompt already visible"),true):(this.config.showDelay>0&&await new Promise(e=>setTimeout(e,this.config.showDelay)),this.shouldShow()?(this.createPrompt(),this.log("Prompt shown"),this.onShow?.(),true):false):(this.log("Prompt should not be shown"),false):(this.log("Prompt is disabled"),false)}hide(){this.promptElement&&(this.promptElement.remove(),this.promptElement=null),this.overlayElement&&(this.overlayElement.remove(),this.overlayElement=null);}dismiss(){this.hide();try{localStorage.setItem(N,Date.now().toString());}catch{}this.log("Prompt dismissed"),this.onLater?.();}resetDismissal(){try{localStorage.removeItem(N);}catch{}}async handleAllow(){return this.hide(),this.onAllow?.(),"Notification"in window?await Notification.requestPermission():"denied"}createPrompt(){this.overlayElement=document.createElement("div"),this.overlayElement.id=`${w}-overlay`,this.overlayElement.style.cssText=`
|
|
83
|
+
`,document.body.appendChild(this.bannerElement);let r=document.getElementById(`${m}-show`),s=document.getElementById(`${m}-close`),o=document.getElementById(`${m}-steps`);r?.addEventListener("click",()=>{o&&(o.style.display=o.style.display==="none"?"block":"none",r.textContent=o.style.display==="none"?this.config.buttonText:"Got it!"),this.onInstallClick?.();}),s?.addEventListener("click",()=>this.dismiss()),requestAnimationFrame(()=>{this.overlayElement&&(this.overlayElement.style.opacity="1"),this.bannerElement&&(this.bannerElement.style.opacity="1",this.bannerElement.style.transform="translateY(0)");});}log(e,t="log"){if(!this.debug&&t==="log")return;console[t](`[CloudSignal PWA IOSBanner] ${e}`);}};var me="https://pwa.cloudsignal.app",te="1.2.3",q=class{constructor(e){this.initialized=false;this.serviceConfig=null;this.wakeLockManager=null;this.offlineQueueManager=null;this.iosInstallBanner=null;this.eventHandlers=new Map;if(this.config=e,this.serviceUrl=e.serviceUrl||me,this.debug=e.debug??false,!e.organizationSecret&&!e.userToken)throw new Error("Either organizationSecret or userToken must be provided");if(this.authContext=y({organizationId:e.organizationId,organizationSecret:e.organizationSecret,userToken:e.userToken}),this.deviceDetector=new f,this.serviceWorkerManager=new S({config:e.serviceWorker,debug:this.debug,onRegistered:t=>this.emit("sw:registered",{registration:t}),onUpdated:t=>this.emit("sw:updated",{registration:t}),onError:t=>this.emit("sw:error",{error:t})}),this.installationManager=new k({debug:this.debug,onInstallAvailable:t=>this.emit("install:available",{platforms:t.platforms}),onInstallAccepted:t=>this.emit("install:accepted",t),onInstallDismissed:t=>this.emit("install:dismissed",t),onInstalled:()=>this.emit("install:completed",{})}),this.pushNotificationManager=new R({serviceUrl:this.serviceUrl,organizationId:e.organizationId,organizationSecret:e.organizationSecret,userToken:e.userToken,onTokenExpired:e.onTokenExpired,serviceId:e.serviceId,debug:this.debug,onRegistered:t=>{this.emit("push:registered",{registrationId:t.registrationId,endpoint:""}),this.heartbeatManager.setRegistrationId(t.registrationId);},onUnregistered:()=>{this.emit("push:unregistered",{}),this.heartbeatManager.stop();},onError:t=>this.emit("push:error",{error:t}),onPermissionDenied:()=>this.emit("permission:denied",{permission:"denied"})}),this.heartbeatManager=new E({serviceUrl:this.serviceUrl,organizationId:e.organizationId,organizationSecret:e.organizationSecret,userToken:e.userToken,onTokenExpired:e.onTokenExpired,config:e.heartbeat,debug:this.debug,onHeartbeatSent:()=>this.emit("heartbeat:sent",{timestamp:Date.now()}),onHeartbeatError:t=>this.emit("heartbeat:error",{timestamp:Date.now(),error:t.message}),onIntervalChanged:(t,i)=>this.emit("heartbeat:intervalChanged",{interval:t,reason:i}),onPausedForBattery:()=>this.emit("heartbeat:pausedForBattery",{timestamp:Date.now()}),onResumedFromBattery:()=>this.emit("heartbeat:resumedFromBattery",{timestamp:Date.now()})}),e.wakeLock?.enabled!==false&&(this.wakeLockManager=new T({config:{enabled:e.wakeLock?.enabled??true,autoReacquire:e.wakeLock?.reacquireOnVisibility??true},debug:this.debug,onAcquired:()=>this.emit("wakeLock:acquired",{timestamp:Date.now()}),onReleased:t=>this.emit("wakeLock:released",{reason:t.reason,timestamp:Date.now()}),onError:t=>this.emit("wakeLock:error",{error:t.error})})),e.offlineQueue?.enabled!==false&&(this.offlineQueueManager=new A({config:{enabled:e.offlineQueue?.enabled??true,maxQueueSize:e.offlineQueue?.maxQueueSize??100,maxAge:(e.offlineQueue?.maxAgeTTLHours??24)*60*60*1e3,processOnOnline:e.offlineQueue?.autoProcessOnOnline??true},debug:this.debug,onRequestQueued:t=>this.emit("offlineQueue:queued",{url:t.url,method:t.method}),onRequestProcessed:t=>this.emit("offlineQueue:processed",{success:t.success,requestId:t.id}),onQueueEmpty:()=>this.emit("offlineQueue:flushed",{})})),e.iosInstallBanner?.enabled!==false){let t=this.deviceDetector.getDeviceInfo();t.isIOS&&t.browser==="Safari"&&(this.iosInstallBanner=new D({config:{enabled:e.iosInstallBanner?.enabled??true,title:e.iosInstallBanner?.title,description:e.iosInstallBanner?.subtitle,iconUrl:e.iosInstallBanner?.iconUrl,showDelay:e.iosInstallBanner?.showDelay,dismissalDays:e.iosInstallBanner?.dismissRememberDays},debug:this.debug,onShow:()=>this.emit("iosBanner:shown",{}),onDismiss:()=>this.emit("iosBanner:dismissed",{}),onInstallClick:()=>this.emit("iosBanner:installClicked",{})}));}this.log(`CloudSignal PWA SDK v${te} initialized`);}async initialize(){try{this.log("Initializing PWA client..."),this.installationManager.initialize();let e=await this.serviceWorkerManager.register();e&&this.pushNotificationManager.setServiceWorkerRegistration(e);let t=await this.downloadConfig();if(this.setupNetworkListeners(),this.offlineQueueManager&&await this.offlineQueueManager.initialize(),this.config.notificationAnalytics?.enabled!==!1&&e&&this.configureNotificationAnalytics(e),this.iosInstallBanner&&this.config.iosInstallBanner?.showOnFirstVisit!==!1&&(this.installationManager.getState().isInstalled||this.iosInstallBanner.show()),this.installationManager.getState().isInstalled){this.log("PWA installation detected, registering...");let s=await this.pushNotificationManager.registerInstallation();s&&(this.log(`Installation registered: ${s.registrationId}`),this.emit("install:registered",{registrationId:s.registrationId}));}this.initialized=!0;let r={success:!0,config:t||void 0,deviceInfo:this.deviceDetector.getDeviceInfo(),installationState:this.installationManager.getState()};return this.log("PWA client initialized successfully"),r}catch(e){let t=e instanceof Error?e:new Error(String(e));return this.log(`Initialization failed: ${t.message}`,"error"),{success:false,error:t.message}}}async downloadConfig(){try{let e=`${this.serviceUrl}/api/v1/config/download`,t=await h(this.authContext,"POST",e,{organization_id:this.config.organizationId},this.config.onTokenExpired);if(!t.ok)throw new Error(`Config download failed: ${t.status}`);let i=await t.json();return this.serviceConfig=i,i.vapid_public_key&&this.pushNotificationManager.setVapidPublicKey(i.vapid_public_key),i.manifest_url&&this.injectManifest(i.manifest_url),this.emit("config:loaded",{config:i}),this.log("Configuration downloaded successfully"),i}catch(e){let t=e instanceof Error?e:new Error(String(e));return this.log(`Config download failed: ${t.message}`,"error"),this.emit("config:error",{error:t}),null}}async showInstallPrompt(){return this.installationManager.showInstallPrompt()}getInstallationState(){return this.installationManager.getState()}canInstall(){return this.installationManager.canInstall()}isInstalled(){return this.installationManager.isPWAInstalled()}getInstallSteps(){return this.installationManager.getInstallSteps()}async registerForPush(e){return this.pushNotificationManager.register(e)}async unregisterFromPush(){return this.pushNotificationManager.unregister()}async updatePreferences(e){return this.pushNotificationManager.updatePreferences(e)}async checkRegistrationStatus(){return this.pushNotificationManager.checkStatus()}getRegistrationId(){return this.pushNotificationManager.getRegistrationId()}isRegistered(){return this.pushNotificationManager.isRegistered()}async requestPermission(){return this.pushNotificationManager.requestPermission()}getAuthMode(){return this.authContext.mode}setUserToken(e){this.authContext=b(this.authContext,e),this.pushNotificationManager.updateToken(e),this.heartbeatManager.updateToken(e),this.emit("auth:tokenUpdated",{mode:this.authContext.mode}),this.log(`Auth mode updated to: ${this.authContext.mode}`);}getDeviceInfo(){return this.deviceDetector.getDeviceInfo()}getCapabilities(){return this.deviceDetector.getCapabilities()}startHeartbeat(){let e=this.pushNotificationManager.getRegistrationId();e?(this.heartbeatManager.setRegistrationId(e),this.heartbeatManager.start(),this.emit("heartbeat:started",{timestamp:Date.now()})):this.log("Cannot start heartbeat: not registered","warn");}stopHeartbeat(){this.heartbeatManager.stop(),this.emit("heartbeat:stopped",{timestamp:Date.now()});}getHeartbeatInterval(){return this.heartbeatManager.getCurrentInterval()}getNetworkInfo(){return this.heartbeatManager.getNetworkInfo()}async getBatteryInfo(){return this.heartbeatManager.getBatteryInfo()}async requestWakeLock(){return this.wakeLockManager?this.wakeLockManager.acquire():(this.log("Wake lock manager not initialized","warn"),false)}releaseWakeLock(){this.wakeLockManager?.release();}getWakeLockState(){return this.wakeLockManager?this.wakeLockManager.getState():{isSupported:false,isActive:false}}async queueOfflineRequest(e,t,i){return this.offlineQueueManager?this.offlineQueueManager.queueRequest(e,t,{body:i?.body,headers:i?.headers}):(this.log("Offline queue manager not initialized","warn"),null)}async processOfflineQueue(){return this.offlineQueueManager?this.offlineQueueManager.processQueue():[]}async getOfflineQueueStats(){return this.offlineQueueManager?this.offlineQueueManager.getStats():{totalQueued:0,byType:{registration:0,heartbeat:0,analytics:0,preferences:0,unregister:0,custom:0}}}async clearOfflineQueue(){await this.offlineQueueManager?.clearQueue();}showIOSInstallBanner(){if(!this.iosInstallBanner){this.log("iOS install banner not available (not on iOS Safari)","warn");return}this.iosInstallBanner.show();}hideIOSInstallBanner(){this.iosInstallBanner?.hide();}wasIOSBannerDismissed(){return this.iosInstallBanner?.wasDismissed()??false}resetIOSBannerDismissal(){this.iosInstallBanner?.resetDismissal();}clearBadge(){this.serviceWorkerManager.clearBadge();}setBadge(e){this.serviceWorkerManager.setBadge(e);}async checkForUpdates(){return this.serviceWorkerManager.checkForUpdate()}on(e,t){this.eventHandlers.has(e)||this.eventHandlers.set(e,new Set),this.eventHandlers.get(e).add(t);}off(e,t){let i=this.eventHandlers.get(e);i&&i.delete(t);}emit(e,t){let i=this.eventHandlers.get(e);i&&i.forEach(r=>{try{r(t);}catch(s){this.log(`Event handler error for ${e}: ${s}`,"error");}});}getVersion(){return te}getServiceConfig(){return this.serviceConfig}isInitialized(){return this.initialized}injectManifest(e){let t=document.querySelector('link[rel="manifest"]');t||(t=document.createElement("link"),t.setAttribute("rel","manifest"),document.head.appendChild(t)),t.setAttribute("href",e),this.log(`Manifest injected: ${e}`);}setupNetworkListeners(){window.addEventListener("online",()=>{this.deviceDetector.clearCache(),this.emit("network:online",{isOnline:true}),this.offlineQueueManager&&this.offlineQueueManager.processQueue().catch(e=>{this.log(`Failed to process offline queue: ${e.message}`,"error");});}),window.addEventListener("offline",()=>{this.deviceDetector.clearCache(),this.emit("network:offline",{isOnline:false});});}configureNotificationAnalytics(e){let t=this.config.notificationAnalytics?.endpoint||`${this.serviceUrl}/api/v1/analytics/notifications`;e.active?.postMessage({type:"CONFIGURE_ANALYTICS",config:{enabled:this.config.notificationAnalytics?.enabled!==false,endpoint:t,organizationId:this.config.organizationId}}),this.log("Notification analytics configured");}log(e,t="log"){if(!this.debug&&t==="log")return;console[t](`[CloudSignal PWA] ${e}`);}},ve=q;var W="cloudsignal_pwa_notification_prompt_dismissed",w="cloudsignal-notification-prompt",G={en:{title:"Stay Updated",description:"Get notified about important updates, messages, and alerts.",allowButton:"Enable Notifications",laterButton:"Maybe Later",iosNote:"On iOS, you must first add this app to your home screen."},es:{title:"Mantente Actualizado",description:"Recibe notificaciones sobre actualizaciones importantes, mensajes y alertas.",allowButton:"Activar Notificaciones",laterButton:"Quiz\xE1s Despu\xE9s",iosNote:"En iOS, primero debes a\xF1adir esta aplicaci\xF3n a tu pantalla de inicio."},fr:{title:"Restez Inform\xE9",description:"Recevez des notifications sur les mises \xE0 jour importantes, messages et alertes.",allowButton:"Activer les Notifications",laterButton:"Plus Tard",iosNote:"Sur iOS, vous devez d'abord ajouter cette application \xE0 votre \xE9cran d'accueil."},de:{title:"Bleiben Sie Informiert",description:"Erhalten Sie Benachrichtigungen \xFCber wichtige Updates, Nachrichten und Warnungen.",allowButton:"Benachrichtigungen Aktivieren",laterButton:"Vielleicht Sp\xE4ter",iosNote:"Auf iOS m\xFCssen Sie diese App zuerst zum Startbildschirm hinzuf\xFCgen."},it:{title:"Rimani Aggiornato",description:"Ricevi notifiche su aggiornamenti importanti, messaggi e avvisi.",allowButton:"Attiva Notifiche",laterButton:"Forse Dopo",iosNote:"Su iOS, devi prima aggiungere questa app alla schermata Home."},pt:{title:"Fique Atualizado",description:"Receba notifica\xE7\xF5es sobre atualiza\xE7\xF5es importantes, mensagens e alertas.",allowButton:"Ativar Notifica\xE7\xF5es",laterButton:"Talvez Depois",iosNote:"No iOS, voc\xEA deve primeiro adicionar este aplicativo \xE0 tela inicial."},nl:{title:"Blijf Op De Hoogte",description:"Ontvang meldingen over belangrijke updates, berichten en waarschuwingen.",allowButton:"Meldingen Inschakelen",laterButton:"Misschien Later",iosNote:"Op iOS moet je deze app eerst toevoegen aan je beginscherm."},ru:{title:"\u0411\u0443\u0434\u044C\u0442\u0435 \u0432 \u041A\u0443\u0440\u0441\u0435",description:"\u041F\u043E\u043B\u0443\u0447\u0430\u0439\u0442\u0435 \u0443\u0432\u0435\u0434\u043E\u043C\u043B\u0435\u043D\u0438\u044F \u043E \u0432\u0430\u0436\u043D\u044B\u0445 \u043E\u0431\u043D\u043E\u0432\u043B\u0435\u043D\u0438\u044F\u0445, \u0441\u043E\u043E\u0431\u0449\u0435\u043D\u0438\u044F\u0445 \u0438 \u043F\u0440\u0435\u0434\u0443\u043F\u0440\u0435\u0436\u0434\u0435\u043D\u0438\u044F\u0445.",allowButton:"\u0412\u043A\u043B\u044E\u0447\u0438\u0442\u044C \u0423\u0432\u0435\u0434\u043E\u043C\u043B\u0435\u043D\u0438\u044F",laterButton:"\u041F\u043E\u0437\u0436\u0435",iosNote:"\u041D\u0430 iOS \u0441\u043D\u0430\u0447\u0430\u043B\u0430 \u0434\u043E\u0431\u0430\u0432\u044C\u0442\u0435 \u044D\u0442\u043E \u043F\u0440\u0438\u043B\u043E\u0436\u0435\u043D\u0438\u0435 \u043D\u0430 \u0433\u043B\u0430\u0432\u043D\u044B\u0439 \u044D\u043A\u0440\u0430\u043D."},zh:{title:"\u4FDD\u6301\u66F4\u65B0",description:"\u83B7\u53D6\u91CD\u8981\u66F4\u65B0\u3001\u6D88\u606F\u548C\u63D0\u9192\u7684\u901A\u77E5\u3002",allowButton:"\u542F\u7528\u901A\u77E5",laterButton:"\u7A0D\u540E\u518D\u8BF4",iosNote:"\u5728iOS\u4E0A\uFF0C\u60A8\u5FC5\u987B\u5148\u5C06\u6B64\u5E94\u7528\u6DFB\u52A0\u5230\u4E3B\u5C4F\u5E55\u3002"},ja:{title:"\u6700\u65B0\u60C5\u5831\u3092\u5165\u624B",description:"\u91CD\u8981\u306A\u30A2\u30C3\u30D7\u30C7\u30FC\u30C8\u3001\u30E1\u30C3\u30BB\u30FC\u30B8\u3001\u30A2\u30E9\u30FC\u30C8\u306E\u901A\u77E5\u3092\u53D7\u3051\u53D6\u308A\u307E\u3059\u3002",allowButton:"\u901A\u77E5\u3092\u6709\u52B9\u306B\u3059\u308B",laterButton:"\u5F8C\u3067",iosNote:"iOS\u3067\u306F\u3001\u307E\u305A\u3053\u306E\u30A2\u30D7\u30EA\u3092\u30DB\u30FC\u30E0\u753B\u9762\u306B\u8FFD\u52A0\u3059\u308B\u5FC5\u8981\u304C\u3042\u308A\u307E\u3059\u3002"},ko:{title:"\uCD5C\uC2E0 \uC815\uBCF4 \uBC1B\uAE30",description:"\uC911\uC694\uD55C \uC5C5\uB370\uC774\uD2B8, \uBA54\uC2DC\uC9C0 \uBC0F \uC54C\uB9BC\uC5D0 \uB300\uD55C \uC54C\uB9BC\uC744 \uBC1B\uC73C\uC138\uC694.",allowButton:"\uC54C\uB9BC \uD65C\uC131\uD654",laterButton:"\uB098\uC911\uC5D0",iosNote:"iOS\uC5D0\uC11C\uB294 \uBA3C\uC800 \uC774 \uC571\uC744 \uD648 \uD654\uBA74\uC5D0 \uCD94\uAC00\uD574\uC57C \uD569\uB2C8\uB2E4."},ar:{title:"\u0627\u0628\u0642 \u0639\u0644\u0649 \u0627\u0637\u0644\u0627\u0639",description:"\u0627\u062D\u0635\u0644 \u0639\u0644\u0649 \u0625\u0634\u0639\u0627\u0631\u0627\u062A \u062D\u0648\u0644 \u0627\u0644\u062A\u062D\u062F\u064A\u062B\u0627\u062A \u0627\u0644\u0645\u0647\u0645\u0629 \u0648\u0627\u0644\u0631\u0633\u0627\u0626\u0644 \u0648\u0627\u0644\u062A\u0646\u0628\u064A\u0647\u0627\u062A.",allowButton:"\u062A\u0641\u0639\u064A\u0644 \u0627\u0644\u0625\u0634\u0639\u0627\u0631\u0627\u062A",laterButton:"\u0631\u0628\u0645\u0627 \u0644\u0627\u062D\u0642\u0627\u064B",iosNote:"\u0639\u0644\u0649 iOS\u060C \u064A\u062C\u0628 \u0623\u0648\u0644\u0627\u064B \u0625\u0636\u0627\u0641\u0629 \u0647\u0630\u0627 \u0627\u0644\u062A\u0637\u0628\u064A\u0642 \u0625\u0644\u0649 \u0627\u0644\u0634\u0627\u0634\u0629 \u0627\u0644\u0631\u0626\u064A\u0633\u064A\u0629."},he:{title:"\u05D4\u05D9\u05E9\u05D0\u05E8 \u05DE\u05E2\u05D5\u05D3\u05DB\u05DF",description:"\u05E7\u05D1\u05DC \u05D4\u05EA\u05E8\u05D0\u05D5\u05EA \u05E2\u05DC \u05E2\u05D3\u05DB\u05D5\u05E0\u05D9\u05DD \u05D7\u05E9\u05D5\u05D1\u05D9\u05DD, \u05D4\u05D5\u05D3\u05E2\u05D5\u05EA \u05D5\u05D4\u05EA\u05E8\u05D0\u05D5\u05EA.",allowButton:"\u05D4\u05E4\u05E2\u05DC \u05D4\u05EA\u05E8\u05D0\u05D5\u05EA",laterButton:"\u05D0\u05D5\u05DC\u05D9 \u05DE\u05D0\u05D5\u05D7\u05E8 \u05D9\u05D5\u05EA\u05E8",iosNote:"\u05D1-iOS, \u05E2\u05DC\u05D9\u05DA \u05DC\u05D4\u05D5\u05E1\u05D9\u05E3 \u05EA\u05D7\u05D9\u05DC\u05D4 \u05D0\u05EA \u05D4\u05D0\u05E4\u05DC\u05D9\u05E7\u05E6\u05D9\u05D4 \u05DC\u05DE\u05E1\u05DA \u05D4\u05D1\u05D9\u05EA."},hi:{title:"\u0905\u092A\u0921\u0947\u091F \u0930\u0939\u0947\u0902",description:"\u092E\u0939\u0924\u094D\u0935\u092A\u0942\u0930\u094D\u0923 \u0905\u092A\u0921\u0947\u091F, \u0938\u0902\u0926\u0947\u0936\u094B\u0902 \u0914\u0930 \u0905\u0932\u0930\u094D\u091F \u0915\u0947 \u092C\u093E\u0930\u0947 \u092E\u0947\u0902 \u0938\u0942\u091A\u0928\u093E\u090F\u0902 \u092A\u094D\u0930\u093E\u092A\u094D\u0924 \u0915\u0930\u0947\u0902\u0964",allowButton:"\u0938\u0942\u091A\u0928\u093E\u090F\u0902 \u0938\u0915\u094D\u0937\u092E \u0915\u0930\u0947\u0902",laterButton:"\u092C\u093E\u0926 \u092E\u0947\u0902",iosNote:"iOS \u092A\u0930, \u0906\u092A\u0915\u094B \u092A\u0939\u0932\u0947 \u0907\u0938 \u0910\u092A \u0915\u094B \u0939\u094B\u092E \u0938\u094D\u0915\u094D\u0930\u0940\u0928 \u092A\u0930 \u091C\u094B\u0921\u093C\u0928\u093E \u0939\u094B\u0917\u093E\u0964"},tr:{title:"G\xFCncel Kal\u0131n",description:"\xD6nemli g\xFCncellemeler, mesajlar ve uyar\u0131lar hakk\u0131nda bildirim al\u0131n.",allowButton:"Bildirimleri Etkinle\u015Ftir",laterButton:"Belki Sonra",iosNote:"iOS'ta \xF6nce bu uygulamay\u0131 ana ekran\u0131n\u0131za eklemelisiniz."},pl:{title:"B\u0105d\u017A Na Bie\u017C\u0105co",description:"Otrzymuj powiadomienia o wa\u017Cnych aktualizacjach, wiadomo\u015Bciach i alertach.",allowButton:"W\u0142\u0105cz Powiadomienia",laterButton:"Mo\u017Ce P\xF3\u017Aniej",iosNote:"Na iOS musisz najpierw doda\u0107 t\u0119 aplikacj\u0119 do ekranu g\u0142\xF3wnego."},sv:{title:"H\xE5ll Dig Uppdaterad",description:"F\xE5 aviseringar om viktiga uppdateringar, meddelanden och varningar.",allowButton:"Aktivera Aviseringar",laterButton:"Kanske Senare",iosNote:"P\xE5 iOS m\xE5ste du f\xF6rst l\xE4gga till denna app p\xE5 hemsk\xE4rmen."},da:{title:"Hold Dig Opdateret",description:"F\xE5 notifikationer om vigtige opdateringer, beskeder og advarsler.",allowButton:"Aktiv\xE9r Notifikationer",laterButton:"M\xE5ske Senere",iosNote:"P\xE5 iOS skal du f\xF8rst tilf\xF8je denne app til startsk\xE6rmen."},no:{title:"Hold Deg Oppdatert",description:"F\xE5 varsler om viktige oppdateringer, meldinger og varsler.",allowButton:"Aktiver Varsler",laterButton:"Kanskje Senere",iosNote:"P\xE5 iOS m\xE5 du f\xF8rst legge til denne appen p\xE5 startskjermen."},fi:{title:"Pysy Ajan Tasalla",description:"Saat ilmoituksia t\xE4rkeist\xE4 p\xE4ivityksist\xE4, viesteist\xE4 ja h\xE4lytyksist\xE4.",allowButton:"Ota Ilmoitukset K\xE4ytt\xF6\xF6n",laterButton:"Ehk\xE4 My\xF6hemmin",iosNote:"iOS:ssa sinun on ensin lis\xE4tt\xE4v\xE4 t\xE4m\xE4 sovellus aloitusn\xE4yt\xF6lle."}},ye={backgroundColor:"#ffffff",textColor:"#1a1a1a",primaryButtonBackground:"#007AFF",primaryButtonText:"#ffffff",secondaryButtonBackground:"transparent",secondaryButtonText:"#666666",borderRadius:"16px",boxShadow:"0 4px 24px rgba(0, 0, 0, 0.15)"},K=class{constructor(e={}){this.promptElement=null;this.overlayElement=null;this.debug=e.debug??false,this.onAllow=e.onAllow,this.onLater=e.onLater,this.onShow=e.onShow,this.language=e.language??B();let t=G[this.language];this.strings={...t,...e.customStrings},this.config={enabled:e.config?.enabled??true,iconUrl:e.config?.iconUrl??"",showDelay:e.config?.showDelay??2e3,dismissalDays:e.config?.dismissalDays??3,position:e.config?.position??"center",customStyles:e.config?.customStyles??{},showIOSNote:e.config?.showIOSNote??true},this.styles={...ye,...this.config.customStyles},this.log(`Initialized with language: ${this.language}`);}getLanguage(){return this.language}setLanguage(e){this.language=e,this.strings={...G[e]},this.log(`Language changed to: ${e}`);}shouldShow(){return !("Notification"in window&&Notification.permission!=="default"||this.wasDismissed())}wasDismissed(){try{let e=localStorage.getItem(W);if(!e)return !1;let t=parseInt(e,10);return (Date.now()-t)/(1e3*60*60*24)>this.config.dismissalDays?(localStorage.removeItem(W),!1):!0}catch{return false}}isIOS(){return /iPad|iPhone|iPod/.test(navigator.userAgent)&&!window.MSStream}isInstalled(){return !!(navigator.standalone===true||window.matchMedia("(display-mode: standalone)").matches)}async show(){return this.config.enabled?this.shouldShow()?this.promptElement?(this.log("Prompt already visible"),true):(this.config.showDelay>0&&await new Promise(e=>setTimeout(e,this.config.showDelay)),this.shouldShow()?(this.createPrompt(),this.log("Prompt shown"),this.onShow?.(),true):false):(this.log("Prompt should not be shown"),false):(this.log("Prompt is disabled"),false)}hide(){this.promptElement&&(this.promptElement.remove(),this.promptElement=null),this.overlayElement&&(this.overlayElement.remove(),this.overlayElement=null);}dismiss(){this.hide();try{localStorage.setItem(W,Date.now().toString());}catch{}this.log("Prompt dismissed"),this.onLater?.();}resetDismissal(){try{localStorage.removeItem(W);}catch{}}async handleAllow(){return this.hide(),this.onAllow?.(),"Notification"in window?await Notification.requestPermission():"denied"}createPrompt(){this.overlayElement=document.createElement("div"),this.overlayElement.id=`${w}-overlay`,this.overlayElement.style.cssText=`
|
|
84
84
|
position: fixed;
|
|
85
85
|
top: 0;
|
|
86
86
|
left: 0;
|
|
@@ -142,5 +142,5 @@ var te=Object.defineProperty;var ie=(n,e)=>()=>(n&&(e=n(n=0)),e);var re=(n,e)=>{
|
|
|
142
142
|
">${this.strings.laterButton}</button>
|
|
143
143
|
</div>
|
|
144
144
|
</div>
|
|
145
|
-
`,document.body.appendChild(this.promptElement),document.getElementById(`${w}-allow`)?.addEventListener("click",()=>this.handleAllow()),document.getElementById(`${w}-later`)?.addEventListener("click",()=>this.dismiss()),requestAnimationFrame(()=>{this.overlayElement&&(this.overlayElement.style.opacity="1"),this.promptElement&&(this.promptElement.style.opacity="1",this.config.position==="center"?this.promptElement.style.transform="translate(-50%, -50%) scale(1)":this.config.position==="top"?this.promptElement.style.transform="translateX(-50%) translateY(0)":this.promptElement.style.transform="translateX(-50%) translateY(0)");});}log(e,t="log"){if(!this.debug&&t==="log")return;console[t](`[CloudSignal PWA NotificationPrompt] ${e}`);}};P();var
|
|
145
|
+
`,document.body.appendChild(this.promptElement),document.getElementById(`${w}-allow`)?.addEventListener("click",()=>this.handleAllow()),document.getElementById(`${w}-later`)?.addEventListener("click",()=>this.dismiss()),requestAnimationFrame(()=>{this.overlayElement&&(this.overlayElement.style.opacity="1"),this.promptElement&&(this.promptElement.style.opacity="1",this.config.position==="center"?this.promptElement.style.transform="translate(-50%, -50%) scale(1)":this.config.position==="top"?this.promptElement.style.transform="translateX(-50%) translateY(0)":this.promptElement.style.transform="translateX(-50%) translateY(0)");});}log(e,t="log"){if(!this.debug&&t==="log")return;console[t](`[CloudSignal PWA NotificationPrompt] ${e}`);}};P();var tt="1.2.0";exports.CloudSignalPWA=q;exports.DeviceDetector=f;exports.HeartbeatManager=E;exports.IOSInstallBanner=D;exports.IOS_BANNER_TRANSLATIONS=C;exports.IndexedDBStorage=Q;exports.InstallationManager=k;exports.NOTIFICATION_PROMPT_TRANSLATIONS=G;exports.NotificationPermissionPrompt=K;exports.OfflineQueueManager=A;exports.PushNotificationManager=R;exports.ServiceWorkerManager=S;exports.VERSION=tt;exports.WakeLockManager=T;exports.createAuthContext=y;exports.default=ve;exports.detectBrowserLanguage=B;exports.deviceDetector=ue;exports.generateAuthHeaders=z;exports.generateBrowserFingerprint=O;exports.generateHMACSignature=H;exports.generateJWTHeaders=j;exports.generateTrackingId=$;exports.getRegistrationId=_;exports.getStorageItem=x;exports.isValidUUID=v;exports.makeAuthenticatedRequest=X;exports.makeAuthenticatedRequestWithContext=h;exports.makeJWTAuthenticatedRequest=Y;exports.removeRegistrationId=N;exports.removeStorageItem=Z;exports.setRegistrationId=F;exports.setStorageItem=M;exports.updateAuthToken=b;Object.defineProperty(exports,'__esModule',{value:true});return exports;})({});//# sourceMappingURL=index.global.js.map
|
|
146
146
|
//# sourceMappingURL=index.global.js.map
|