@buoy-gg/notifications 7.0.56 → 7.0.57
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/lib/commonjs/capacitor.js +1 -0
- package/lib/commonjs/expoStorage.js +1 -0
- package/lib/commonjs/index.js +1 -1
- package/lib/commonjs/runtime.js +1 -1
- package/lib/commonjs/storage.js +1 -1
- package/lib/commonjs/storage.web.js +1 -0
- package/lib/module/capacitor.js +1 -0
- package/lib/module/expoStorage.js +1 -0
- package/lib/module/index.js +1 -1
- package/lib/module/runtime.js +1 -1
- package/lib/module/storage.js +1 -1
- package/lib/module/storage.web.js +1 -0
- package/lib/typescript/capacitor.d.ts +73 -0
- package/lib/typescript/expoStorage.d.ts +19 -0
- package/lib/typescript/index.d.ts +4 -2
- package/lib/typescript/runtime.d.ts +13 -0
- package/lib/typescript/storage.d.ts +1 -17
- package/lib/typescript/storage.web.d.ts +8 -0
- package/lib/web/index.mjs +1 -0
- package/package.json +33 -5
|
@@ -0,0 +1 @@
|
|
|
1
|
+
"use strict";Object.defineProperty(exports,"__esModule",{value:true});exports.attachCapacitorNotifications=attachCapacitorNotifications;exports.capacitorMetadata=capacitorMetadata;var _preview=require("./preview");var _json=require("./json");const PUSH="PushNotifications";const LOCAL="LocalNotifications";function capacitorMetadata(o){const s=(0,_json.object)(o);const a=(0,_json.object)(s.notification??o);const c=(0,_json.object)(a.data??a.extra);const f=(0,_json.object)(c.body);const p=a.id;return{notificationId:typeof p==="number"?String(p):(0,_json.string)(p),testId:(0,_json.string)(c.__buoyTestId)??(0,_json.string)(f.__buoyTestId),title:(0,_json.string)(a.title)??(0,_json.string)((0,_json.object)((0,_json.object)(c.aps).alert).title),actionIdentifier:(0,_json.string)(s.actionId)}}function timeout(o,s=15e3){return new Promise((a,c)=>{const f=setTimeout(()=>c(new Error("The notification plugin timed out. Check permission and network settings, then retry.")),s);o.then(p=>{clearTimeout(f);a(p)},p=>{clearTimeout(f);c(p)})})}function attachCapacitorNotifications(o,s,a){const c=s.hasCapacitorPlugin(PUSH);const f=s.hasCapacitorPlugin(LOCAL);const p=["received","responses","permissions"];if(c)p.push("device-token","presented");if(f)p.push("local-scheduling");if(f&&!c)p.push("presented");o.configure({preview:(0,_preview.normalizePreviewAppearance)(a.preview),provider:"capacitor",platform:a.platform,appId:a.appId??null,providerVersion:a.providerVersion??null,capabilities:p});s.installCapacitorBridge();if(!a.appId){void s.loadCapacitorAppHost?.().then(t=>{if(t?.bundleId)o.configure({appId:t.bundleId})}).catch(()=>{})}const w=a.platform==="ios"?"apns":"fcm";let h=0;const v=new Set;const g=250;const l=new Map;const j=(t,e)=>{const i=l.get(t);if(i!==void 0&&e-i<g)return null;l.set(t,e);if(l.size>100){for(const[r,n]of l)if(e-n>=g)l.delete(r)}return e};const I=t=>{if(t.plugin!==PUSH&&t.plugin!==LOCAL)return;const e=t.result;const i=`${t.plugin}:${t.method}:${JSON.stringify(e??null).slice(0,1500)}`;if(t.kind==="event"&&j(i,t.start)===null)return;const r=`${i}:${t.start}`;if(t.kind==="event"){switch(t.method){case"registration":{const n=(0,_json.string)((0,_json.object)(e).value);if(n)void o.observeToken(w,n).catch(()=>{});return}case"pushNotificationReceived":case"localNotificationReceived":void o.record("received",e,{...capacitorMetadata(e),provider:"capacitor",dedupeKey:r});return;case"pushNotificationActionPerformed":case"localNotificationActionPerformed":void o.record("response",e,{...capacitorMetadata(e),provider:"capacitor",dedupeKey:r});return;default:return}}if(t.kind!=="promise"||t.ok!==true)return;if(t.method==="checkPermissions"||t.method==="requestPermissions"){o.setPermissions({plugin:t.plugin,...(0,_json.object)(e)})}else if(t.plugin===LOCAL&&t.method==="schedule"){for(const n of Array.isArray(t.options.notifications)?t.options.notifications:[]){const d=capacitorMetadata(n);void o.record("local-scheduled",n,{...d,provider:"capacitor"})}}else if(t.method==="getDeliveredNotifications"){o.setPresented((0,_json.object)(e).notifications??e)}};const b=()=>{const t=s.getCapacitorCalls();for(const i of t){if(i.seq<=h||v.has(i.seq))continue;if(i.kind==="promise"&&i.end===void 0)continue;v.add(i.seq);I(i)}const e=t[0]?.seq??0;if(e>h+1){h=e-1;for(const i of Array.from(v))if(i<=h)v.delete(i)}};const k=s.subscribeCapacitorCalls(b);b();const y=c?PUSH:LOCAL;const P={async getPermissions(){if(!c&&!f)throw new Error("Install @capacitor/push-notifications or @capacitor/local-notifications in the app.");const t=await timeout(s.callCapacitorAsApp(y,"checkPermissions"));o.setPermissions({plugin:y,...(0,_json.object)(t)});return o.getSnapshot().permissions},async listPresented(){if(!c&&!f)throw new Error("This app has no notification plugin that can list presented notifications.");const t=await timeout(s.callCapacitorNative(y,"getDeliveredNotifications"));o.setPresented((0,_json.object)(t).notifications??t);return o.getSnapshot().presented},async refreshToken(t){const{type:e}=(0,_json.object)(t);if(e==="expo")throw new Error("Expo push tokens need expo-notifications; this app uses Capacitor.");if(e!=="device")throw new Error('Token type must be "device".');if(!c)throw new Error("Install @capacitor/push-notifications to register a device token.");let i=null;const r=new Promise((n,d)=>{void s.listenCapacitorNative(PUSH,"registration",u=>{const m=(0,_json.string)((0,_json.object)(u).value);if(m)n(m)}).then(u=>{i=u.remove});void s.listenCapacitorNative(PUSH,"registrationError",u=>{d(new Error((0,_json.string)((0,_json.object)(u).error)??"Push registration failed."))}).then(u=>{const m=i;i=async()=>{await m?.();await u.remove()}})});try{await timeout(s.callCapacitorNative(PUSH,"register"));const n=await timeout(r);await o.observeToken(w,n);return{type:w,value:n}}finally{void i?.()}},async scheduleLocal(t){if(!f)throw new Error("Install @capacitor/local-notifications to schedule local notifications.");const{title:e,body:i,data:r,seconds:n}=(0,_json.object)(t);if(typeof e!=="string"||typeof i!=="string"||typeof n!=="number"||!Number.isFinite(n)||n<1||n>3600)throw new Error("Provide title, body and a delay from 1 to 3600 seconds.");if(r!==void 0&&(r===null||typeof r!=="object"||Array.isArray(r)))throw new Error("Local notification data must be an object.");const d=Math.floor(Math.random()*2e9)+1;const u={id:d,title:e,body:i,extra:r??{},schedule:{at:new Date(Date.now()+n*1e3).toISOString()}};await timeout(s.callCapacitorNative(LOCAL,"schedule",{notifications:[u]}));await o.record("local-scheduled",{title:e,body:i,data:r,seconds:n},{notificationId:String(d),title:e,testId:typeof(0,_json.object)(r).__buoyTestId==="string"?(0,_json.object)(r).__buoyTestId:null,provider:"capacitor"});return{notificationId:String(d),transport:"local"}}};void P.getPermissions().catch(()=>{});return{actions:P,ready:o.ready,dispose(){k()}}}
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
"use strict";Object.defineProperty(exports,"__esModule",{value:true});exports.createExpoNotificationStorage=createExpoNotificationStorage;function createExpoNotificationStorage(e){if(!e.documentDirectory)throw new Error("Expo FileSystem has no persistent document directory.");const r=e.documentDirectory+"buoy-notifications/";const o=t=>r+encodeURIComponent(t)+".json";return{async getItem(t){const n=o(t);return(await e.getInfoAsync(n)).exists?e.readAsStringAsync(n):null},async setItem(t,n){if(!(await e.getInfoAsync(r)).exists)await e.makeDirectoryAsync(r,{intermediates:true});await e.writeAsStringAsync(o(t),n)},async removeItem(t){await e.deleteAsync(o(t),{idempotent:true})},async getAllKeys(){if(!(await e.getInfoAsync(r)).exists)return[];return(await e.readDirectoryAsync(r)).filter(t=>t.endsWith(".json")).flatMap(t=>{try{return[decodeURIComponent(t.slice(0,-5))]}catch{return[]}})}}}
|
package/lib/commonjs/index.js
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
"use strict";Object.defineProperty(exports,"__esModule",{value:true});var _exportNames={NotificationRecorder:true,expoMetadata:true,attachExpoNotifications:true,instrumentExpoNotificationHandler:true,instrumentNotificationBackgroundTask:true,
|
|
1
|
+
"use strict";Object.defineProperty(exports,"__esModule",{value:true});var _exportNames={installExpoNotificationCapture:true,installCapacitorNotificationCapture:true,getNotificationRecorder:true,notificationSyncAdapter:true,NotificationRecorder:true,expoMetadata:true,attachExpoNotifications:true,instrumentExpoNotificationHandler:true,instrumentNotificationBackgroundTask:true,attachCapacitorNotifications:true,capacitorMetadata:true,NotificationToolView:true,notificationToolPreset:true,createNotificationTool:true,NotificationsModal:true,NotificationsIcon:true,composeSimulatorPayload:true,validateSimulatorPayload:true,createExpoNotificationStorage:true,NotificationTestView:true};Object.defineProperty(exports,"NotificationRecorder",{enumerable:true,get:function(){return _recorder.NotificationRecorder}});Object.defineProperty(exports,"NotificationTestView",{enumerable:true,get:function(){return _NotificationTestView.NotificationTestView}});Object.defineProperty(exports,"NotificationToolView",{enumerable:true,get:function(){return _NotificationToolView.NotificationToolView}});Object.defineProperty(exports,"NotificationsIcon",{enumerable:true,get:function(){return _sharedUi.NotificationsIcon}});Object.defineProperty(exports,"NotificationsModal",{enumerable:true,get:function(){return _preset.NotificationsModal}});Object.defineProperty(exports,"attachCapacitorNotifications",{enumerable:true,get:function(){return _capacitor.attachCapacitorNotifications}});Object.defineProperty(exports,"attachExpoNotifications",{enumerable:true,get:function(){return _expo.attachExpoNotifications}});Object.defineProperty(exports,"capacitorMetadata",{enumerable:true,get:function(){return _capacitor.capacitorMetadata}});Object.defineProperty(exports,"composeSimulatorPayload",{enumerable:true,get:function(){return _payload.composeSimulatorPayload}});Object.defineProperty(exports,"createExpoNotificationStorage",{enumerable:true,get:function(){return _storage.createExpoNotificationStorage}});Object.defineProperty(exports,"createNotificationTool",{enumerable:true,get:function(){return _preset.createNotificationTool}});Object.defineProperty(exports,"expoMetadata",{enumerable:true,get:function(){return _recorder.expoMetadata}});Object.defineProperty(exports,"getNotificationRecorder",{enumerable:true,get:function(){return _runtime.getNotificationRecorder}});Object.defineProperty(exports,"installCapacitorNotificationCapture",{enumerable:true,get:function(){return _runtime.installCapacitorNotificationCapture}});Object.defineProperty(exports,"installExpoNotificationCapture",{enumerable:true,get:function(){return _runtime.installExpoNotificationCapture}});Object.defineProperty(exports,"instrumentExpoNotificationHandler",{enumerable:true,get:function(){return _expo.instrumentExpoNotificationHandler}});Object.defineProperty(exports,"instrumentNotificationBackgroundTask",{enumerable:true,get:function(){return _expo.instrumentNotificationBackgroundTask}});Object.defineProperty(exports,"notificationSyncAdapter",{enumerable:true,get:function(){return _runtime.notificationSyncAdapter}});Object.defineProperty(exports,"notificationToolPreset",{enumerable:true,get:function(){return _preset.notificationToolPreset}});Object.defineProperty(exports,"validateSimulatorPayload",{enumerable:true,get:function(){return _payload.validateSimulatorPayload}});var _runtime=require("./runtime");var _types=require("./types");Object.keys(_types).forEach(function(t){if(t==="default"||t==="__esModule")return;if(Object.prototype.hasOwnProperty.call(_exportNames,t))return;if(t in exports&&exports[t]===_types[t])return;Object.defineProperty(exports,t,{enumerable:true,get:function(){return _types[t]}})});var _recorder=require("./recorder");var _expo=require("./expo");var _capacitor=require("./capacitor");var _NotificationToolView=require("./components/NotificationToolView");var _preset=require("./preset");var _sharedUi=require("@buoy-gg/shared-ui");var _payload=require("./payload");var _storage=require("./storage");var _NotificationTestView=require("./components/NotificationTestView");const isCapacitorShell=(()=>{try{const t=globalThis.Capacitor;return t?.isNativePlatform?.()===true}catch{return false}})();if(isCapacitorShell&&typeof __DEV__!=="undefined"&&__DEV__)(0,_runtime.installCapacitorNotificationCapture)();
|
package/lib/commonjs/runtime.js
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
"use strict";Object.defineProperty(exports,"__esModule",{value:true});exports.captureEnabled=captureEnabled;exports.getNotificationRecorder=getNotificationRecorder;exports.installExpoNotificationCapture=installExpoNotificationCapture;exports.notificationSyncAdapter=void 0;var _reactNative=require("react-native");var _storage=require("./storage");var _recorder=require("./recorder");var _expo=require("./expo");var _json=require("./json");const globals=globalThis;function captureEnabled(
|
|
1
|
+
"use strict";Object.defineProperty(exports,"__esModule",{value:true});exports.captureEnabled=captureEnabled;exports.getNotificationRecorder=getNotificationRecorder;exports.installCapacitorNotificationCapture=installCapacitorNotificationCapture;exports.installExpoNotificationCapture=installExpoNotificationCapture;exports.notificationSyncAdapter=void 0;var _reactNative=require("react-native");var _storage=require("./storage");var _recorder=require("./recorder");var _expo=require("./expo");var _capacitor=require("./capacitor");var license=_interopRequireWildcard(require("@buoy-gg/license"));var _json=require("./json");function _interopRequireWildcard(e,t){if("function"==typeof WeakMap)var a=new WeakMap,r=new WeakMap;return(_interopRequireWildcard=function(n,u){if(!u&&n&&n.__esModule)return n;var o,i,s={__proto__:null,default:n};if(null===n||"object"!=typeof n&&"function"!=typeof n)return s;if(o=u?r:a){if(o.has(n))return o.get(n);o.set(n,s)}for(const c in n)"default"!==c&&{}.hasOwnProperty.call(n,c)&&((i=(o=Object.defineProperty)&&Object.getOwnPropertyDescriptor(n,c))&&(i.get||i.set)?o(s,c,i):s[c]=n[c]);return s})(e,t)}const globals=globalThis;function captureEnabled(e=false){return typeof __DEV__!=="undefined"&&__DEV__||e===true}function getNotificationRecorder(){return globals.__buoyNotificationsV1?.recorder??null}function ensureRuntime(e){let t=globals.__buoyNotificationsV1;if(!t){const a=e.storage?{storage:e.storage,durable:e.durable===true}:(0,_storage.defaultNotificationStorage)();const r=new _recorder.NotificationRecorder({...a,enabled:()=>captureEnabled(e.enableInRelease),appState:()=>_reactNative.AppState.currentState??"unknown",autoStart:true});t={recorder:r};globals.__buoyNotificationsV1=t}return t}function installExpoNotificationCapture(e,t={}){if(!captureEnabled(t.enableInRelease))return null;const a=JSON.stringify([t.platform??_reactNative.Platform.OS,t.appId,t.providerVersion,t.projectId,t.enableInRelease,t.preview]);const r=ensureRuntime(t);if(r.sdk!==e||r.key!==a){r.attachment?.dispose();r.attachment=(0,_expo.attachExpoNotifications)(r.recorder,e,{...t,platform:t.platform??_reactNative.Platform.OS});r.sdk=e;r.key=a}return r.recorder}function installCapacitorNotificationCapture(e={}){const t=license.capacitorPlatform();if(!t||!captureEnabled(e.enableInRelease))return null;const a=JSON.stringify(["capacitor",e.appId,e.providerVersion,e.enableInRelease,e.preview]);const r=ensureRuntime(e);if(r.sdk!=="capacitor"||r.key!==a){r.attachment?.dispose();r.attachment=(0,_capacitor.attachCapacitorNotifications)(r.recorder,license,{...e,platform:t});r.sdk="capacitor";r.key=a}return r.recorder}const emptyRecorder=new _recorder.NotificationRecorder;function current(){const e=globals.__buoyNotificationsV1;if(!e)throw new Error("Install notification capture in the app entry point (installExpoNotificationCapture), before rendering the root component. Capacitor apps capture by themselves in debug builds.");return e}const notificationSyncAdapter=exports.notificationSyncAdapter={version:1,getSnapshot:()=>(getNotificationRecorder()??emptyRecorder).getSnapshot(),subscribe:e=>(getNotificationRecorder()??emptyRecorder).subscribe(e),actions:{getSnapshot:()=>notificationSyncAdapter.getSnapshot(),getCapabilities:()=>{const{ready:e,provider:t,providerVersion:a,platform:r,appId:n,capabilities:u,durable:o,storageError:i}=notificationSyncAdapter.getSnapshot();return{ready:e,provider:t,providerVersion:a,platform:r,appId:n,capabilities:u,durable:o,storageError:i}},getEvent(e){const{id:t}=(0,_json.object)(e);if(typeof t!=="string")throw new Error("Provide the captured event id.");return current().recorder.getSnapshot().events.find(a=>a.id===t)??null},async setCaptureSession(e){const{runId:t,durationMs:a}=(0,_json.object)(e);if(typeof t!=="string"&&t!==null)throw new Error("Provide runId, or null to stop capture.");if(a!==void 0&&typeof a!=="number")throw new Error("durationMs must be a number.");return current().recorder.setCaptureSession(t,a)},clearCapturedEvents:()=>current().recorder.clearCapturedEvents(),getPermissions:()=>current().attachment.actions.getPermissions(),listPresented:()=>current().attachment.actions.listPresented(),refreshToken:e=>current().attachment.actions.refreshToken(e),scheduleLocal:e=>current().attachment.actions.scheduleLocal(e)}};
|
package/lib/commonjs/storage.js
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
"use strict";Object.defineProperty(exports,"__esModule",{value:true});exports.createExpoNotificationStorage
|
|
1
|
+
"use strict";Object.defineProperty(exports,"__esModule",{value:true});Object.defineProperty(exports,"createExpoNotificationStorage",{enumerable:true,get:function(){return _expoStorage.createExpoNotificationStorage}});exports.defaultNotificationStorage=defaultNotificationStorage;var _expoStorage=require("./expoStorage");function hasAsyncStorageNative(){let e;try{e=require("react-native")}catch{return true}if(!e?.Platform||e.Platform.OS==="web")return true;try{return["RNCAsyncStorage","RNC_AsyncSQLiteDBStorage","PlatformLocalStorage","AsyncSQLiteDBStorage","AsyncLocalStorage"].some(t=>!!e.TurboModuleRegistry?.get?.(t)||!!e.NativeModules?.[t])}catch{return false}}function defaultNotificationStorage(){try{const e=require("expo-file-system/legacy");if(e.documentDirectory&&typeof e.writeAsStringAsync==="function")return{storage:(0,_expoStorage.createExpoNotificationStorage)(e),durable:true}}catch{}if(hasAsyncStorageNative())try{const e=require("@react-native-async-storage/async-storage");const t=e.default??e;if(typeof t.getItem==="function"&&typeof t.setItem==="function"&&typeof t.getAllKeys==="function")return{storage:t,durable:true}}catch{}return{durable:false}}
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
"use strict";Object.defineProperty(exports,"__esModule",{value:true});Object.defineProperty(exports,"createExpoNotificationStorage",{enumerable:true,get:function(){return _expoStorage.createExpoNotificationStorage}});exports.defaultNotificationStorage=defaultNotificationStorage;var _expoStorage=require("./expoStorage");function webStorage(){try{return globalThis.localStorage??null}catch{return null}}function defaultNotificationStorage(){const t=webStorage();if(!t)return{durable:false};const a={async getItem(e){return t.getItem(e)},async setItem(e,r){t.setItem(e,r)},async removeItem(e){t.removeItem(e)},async getAllKeys(){const e=[];for(let r=0;r<t.length;r++){const o=t.key(r);if(o?.startsWith("buoy.notifications."))e.push(o)}return e}};return{storage:a,durable:true}}
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
"use strict";import{normalizePreviewAppearance as S}from"./preview";import{object as a,string as l}from"./json";const m="PushNotifications";const w="LocalNotifications";export function capacitorMetadata(o){const s=a(o);const c=a(s.notification??o);const p=a(c.data??c.extra);const d=a(p.body);const f=c.id;return{notificationId:typeof f==="number"?String(f):l(f),testId:l(p.__buoyTestId)??l(d.__buoyTestId),title:l(c.title)??l(a(a(p.aps).alert).title),actionIdentifier:l(s.actionId)}}function y(o,s=15e3){return new Promise((c,p)=>{const d=setTimeout(()=>p(new Error("The notification plugin timed out. Check permission and network settings, then retry.")),s);o.then(f=>{clearTimeout(d);c(f)},f=>{clearTimeout(d);p(f)})})}export function attachCapacitorNotifications(o,s,c){const p=s.hasCapacitorPlugin(m);const d=s.hasCapacitorPlugin(w);const f=["received","responses","permissions"];if(p)f.push("device-token","presented");if(d)f.push("local-scheduling");if(d&&!p)f.push("presented");o.configure({preview:S(c.preview),provider:"capacitor",platform:c.platform,appId:c.appId??null,providerVersion:c.providerVersion??null,capabilities:f});s.installCapacitorBridge();if(!c.appId){void s.loadCapacitorAppHost?.().then(t=>{if(t?.bundleId)o.configure({appId:t.bundleId})}).catch(()=>{})}const k=c.platform==="ios"?"apns":"fcm";let g=0;const P=new Set;const N=250;const v=new Map;const b=(t,i)=>{const e=v.get(t);if(e!==void 0&&i-e<N)return null;v.set(t,i);if(v.size>100){for(const[r,n]of v)if(i-n>=N)v.delete(r)}return i};const A=t=>{if(t.plugin!==m&&t.plugin!==w)return;const i=t.result;const e=`${t.plugin}:${t.method}:${JSON.stringify(i??null).slice(0,1500)}`;if(t.kind==="event"&&b(e,t.start)===null)return;const r=`${e}:${t.start}`;if(t.kind==="event"){switch(t.method){case"registration":{const n=l(a(i).value);if(n)void o.observeToken(k,n).catch(()=>{});return}case"pushNotificationReceived":case"localNotificationReceived":void o.record("received",i,{...capacitorMetadata(i),provider:"capacitor",dedupeKey:r});return;case"pushNotificationActionPerformed":case"localNotificationActionPerformed":void o.record("response",i,{...capacitorMetadata(i),provider:"capacitor",dedupeKey:r});return;default:return}}if(t.kind!=="promise"||t.ok!==true)return;if(t.method==="checkPermissions"||t.method==="requestPermissions"){o.setPermissions({plugin:t.plugin,...a(i)})}else if(t.plugin===w&&t.method==="schedule"){for(const n of Array.isArray(t.options.notifications)?t.options.notifications:[]){const h=capacitorMetadata(n);void o.record("local-scheduled",n,{...h,provider:"capacitor"})}}else if(t.method==="getDeliveredNotifications"){o.setPresented(a(i).notifications??i)}};const E=()=>{const t=s.getCapacitorCalls();for(const e of t){if(e.seq<=g||P.has(e.seq))continue;if(e.kind==="promise"&&e.end===void 0)continue;P.add(e.seq);A(e)}const i=t[0]?.seq??0;if(i>g+1){g=i-1;for(const e of Array.from(P))if(e<=g)P.delete(e)}};const _=s.subscribeCapacitorCalls(E);E();const C=p?m:w;const T={async getPermissions(){if(!p&&!d)throw new Error("Install @capacitor/push-notifications or @capacitor/local-notifications in the app.");const t=await y(s.callCapacitorAsApp(C,"checkPermissions"));o.setPermissions({plugin:C,...a(t)});return o.getSnapshot().permissions},async listPresented(){if(!p&&!d)throw new Error("This app has no notification plugin that can list presented notifications.");const t=await y(s.callCapacitorNative(C,"getDeliveredNotifications"));o.setPresented(a(t).notifications??t);return o.getSnapshot().presented},async refreshToken(t){const{type:i}=a(t);if(i==="expo")throw new Error("Expo push tokens need expo-notifications; this app uses Capacitor.");if(i!=="device")throw new Error('Token type must be "device".');if(!p)throw new Error("Install @capacitor/push-notifications to register a device token.");let e=null;const r=new Promise((n,h)=>{void s.listenCapacitorNative(m,"registration",u=>{const I=l(a(u).value);if(I)n(I)}).then(u=>{e=u.remove});void s.listenCapacitorNative(m,"registrationError",u=>{h(new Error(l(a(u).error)??"Push registration failed."))}).then(u=>{const I=e;e=async()=>{await I?.();await u.remove()}})});try{await y(s.callCapacitorNative(m,"register"));const n=await y(r);await o.observeToken(k,n);return{type:k,value:n}}finally{void e?.()}},async scheduleLocal(t){if(!d)throw new Error("Install @capacitor/local-notifications to schedule local notifications.");const{title:i,body:e,data:r,seconds:n}=a(t);if(typeof i!=="string"||typeof e!=="string"||typeof n!=="number"||!Number.isFinite(n)||n<1||n>3600)throw new Error("Provide title, body and a delay from 1 to 3600 seconds.");if(r!==void 0&&(r===null||typeof r!=="object"||Array.isArray(r)))throw new Error("Local notification data must be an object.");const h=Math.floor(Math.random()*2e9)+1;const u={id:h,title:i,body:e,extra:r??{},schedule:{at:new Date(Date.now()+n*1e3).toISOString()}};await y(s.callCapacitorNative(w,"schedule",{notifications:[u]}));await o.record("local-scheduled",{title:i,body:e,data:r,seconds:n},{notificationId:String(h),title:i,testId:typeof a(r).__buoyTestId==="string"?a(r).__buoyTestId:null,provider:"capacitor"});return{notificationId:String(h),transport:"local"}}};void T.getPermissions().catch(()=>{});return{actions:T,ready:o.ready,dispose(){_()}}}
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
"use strict";export function createExpoNotificationStorage(e){if(!e.documentDirectory)throw new Error("Expo FileSystem has no persistent document directory.");const n=e.documentDirectory+"buoy-notifications/";const o=t=>n+encodeURIComponent(t)+".json";return{async getItem(t){const r=o(t);return(await e.getInfoAsync(r)).exists?e.readAsStringAsync(r):null},async setItem(t,r){if(!(await e.getInfoAsync(n)).exists)await e.makeDirectoryAsync(n,{intermediates:true});await e.writeAsStringAsync(o(t),r)},async removeItem(t){await e.deleteAsync(o(t),{idempotent:true})},async getAllKeys(){if(!(await e.getInfoAsync(n)).exists)return[];return(await e.readDirectoryAsync(n)).filter(t=>t.endsWith(".json")).flatMap(t=>{try{return[decodeURIComponent(t.slice(0,-5))]}catch{return[]}})}}}
|
package/lib/module/index.js
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
"use strict";export*from"./types";export{NotificationRecorder,expoMetadata}from"./recorder";export{attachExpoNotifications,instrumentExpoNotificationHandler,instrumentNotificationBackgroundTask}from"./expo";export{installExpoNotificationCapture,getNotificationRecorder,notificationSyncAdapter}from"./runtime";export{NotificationToolView}from"./components/NotificationToolView";export{notificationToolPreset,createNotificationTool,NotificationsModal}from"./preset";export{NotificationsIcon}from"@buoy-gg/shared-ui";export{composeSimulatorPayload,validateSimulatorPayload}from"./payload";export{createExpoNotificationStorage}from"./storage";export{NotificationTestView}from"./components/NotificationTestView";
|
|
1
|
+
"use strict";import{installCapacitorNotificationCapture as t}from"./runtime";export*from"./types";export{NotificationRecorder,expoMetadata}from"./recorder";export{attachExpoNotifications,instrumentExpoNotificationHandler,instrumentNotificationBackgroundTask}from"./expo";export{installExpoNotificationCapture,installCapacitorNotificationCapture,getNotificationRecorder,notificationSyncAdapter}from"./runtime";export{attachCapacitorNotifications,capacitorMetadata}from"./capacitor";export{NotificationToolView}from"./components/NotificationToolView";export{notificationToolPreset,createNotificationTool,NotificationsModal}from"./preset";export{NotificationsIcon}from"@buoy-gg/shared-ui";export{composeSimulatorPayload,validateSimulatorPayload}from"./payload";export{createExpoNotificationStorage}from"./storage";export{NotificationTestView}from"./components/NotificationTestView";const i=(()=>{try{const o=globalThis.Capacitor;return o?.isNativePlatform?.()===true}catch{return false}})();if(i&&typeof __DEV__!=="undefined"&&__DEV__)t();
|
package/lib/module/runtime.js
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
"use strict";import{AppState as
|
|
1
|
+
"use strict";import{AppState as h,Platform as i}from"react-native";import{defaultNotificationStorage as g}from"./storage";import{NotificationRecorder as c}from"./recorder";import{attachExpoNotifications as y}from"./expo";import{attachCapacitorNotifications as S}from"./capacitor";import*as s from"@buoy-gg/license";import{object as u}from"./json";const o=globalThis;export function captureEnabled(e=false){return typeof __DEV__!=="undefined"&&__DEV__||e===true}export function getNotificationRecorder(){return o.__buoyNotificationsV1?.recorder??null}function l(e){let t=o.__buoyNotificationsV1;if(!t){const n=e.storage?{storage:e.storage,durable:e.durable===true}:g();const r=new c({...n,enabled:()=>captureEnabled(e.enableInRelease),appState:()=>h.currentState??"unknown",autoStart:true});t={recorder:r};o.__buoyNotificationsV1=t}return t}export function installExpoNotificationCapture(e,t={}){if(!captureEnabled(t.enableInRelease))return null;const n=JSON.stringify([t.platform??i.OS,t.appId,t.providerVersion,t.projectId,t.enableInRelease,t.preview]);const r=l(t);if(r.sdk!==e||r.key!==n){r.attachment?.dispose();r.attachment=y(r.recorder,e,{...t,platform:t.platform??i.OS});r.sdk=e;r.key=n}return r.recorder}export function installCapacitorNotificationCapture(e={}){const t=s.capacitorPlatform();if(!t||!captureEnabled(e.enableInRelease))return null;const n=JSON.stringify(["capacitor",e.appId,e.providerVersion,e.enableInRelease,e.preview]);const r=l(e);if(r.sdk!=="capacitor"||r.key!==n){r.attachment?.dispose();r.attachment=S(r.recorder,s,{...e,platform:t});r.sdk="capacitor";r.key=n}return r.recorder}const p=new c;function a(){const e=o.__buoyNotificationsV1;if(!e)throw new Error("Install notification capture in the app entry point (installExpoNotificationCapture), before rendering the root component. Capacitor apps capture by themselves in debug builds.");return e}export const notificationSyncAdapter={version:1,getSnapshot:()=>(getNotificationRecorder()??p).getSnapshot(),subscribe:e=>(getNotificationRecorder()??p).subscribe(e),actions:{getSnapshot:()=>notificationSyncAdapter.getSnapshot(),getCapabilities:()=>{const{ready:e,provider:t,providerVersion:n,platform:r,appId:f,capabilities:d,durable:m,storageError:b}=notificationSyncAdapter.getSnapshot();return{ready:e,provider:t,providerVersion:n,platform:r,appId:f,capabilities:d,durable:m,storageError:b}},getEvent(e){const{id:t}=u(e);if(typeof t!=="string")throw new Error("Provide the captured event id.");return a().recorder.getSnapshot().events.find(n=>n.id===t)??null},async setCaptureSession(e){const{runId:t,durationMs:n}=u(e);if(typeof t!=="string"&&t!==null)throw new Error("Provide runId, or null to stop capture.");if(n!==void 0&&typeof n!=="number")throw new Error("durationMs must be a number.");return a().recorder.setCaptureSession(t,n)},clearCapturedEvents:()=>a().recorder.clearCapturedEvents(),getPermissions:()=>a().attachment.actions.getPermissions(),listPresented:()=>a().attachment.actions.listPresented(),refreshToken:e=>a().attachment.actions.refreshToken(e),scheduleLocal:e=>a().attachment.actions.scheduleLocal(e)}};
|
package/lib/module/storage.js
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
"use strict";
|
|
1
|
+
"use strict";import{createExpoNotificationStorage as r}from"./expoStorage";export{createExpoNotificationStorage}from"./expoStorage";function o(){let t;try{t=require("react-native")}catch{return true}if(!t?.Platform||t.Platform.OS==="web")return true;try{return["RNCAsyncStorage","RNC_AsyncSQLiteDBStorage","PlatformLocalStorage","AsyncSQLiteDBStorage","AsyncLocalStorage"].some(e=>!!t.TurboModuleRegistry?.get?.(e)||!!t.NativeModules?.[e])}catch{return false}}export function defaultNotificationStorage(){try{const t=require("expo-file-system/legacy");if(t.documentDirectory&&typeof t.writeAsStringAsync==="function")return{storage:r(t),durable:true}}catch{}if(o())try{const t=require("@react-native-async-storage/async-storage");const e=t.default??t;if(typeof e.getItem==="function"&&typeof e.setItem==="function"&&typeof e.getAllKeys==="function")return{storage:e,durable:true}}catch{}return{durable:false}}
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
"use strict";export{createExpoNotificationStorage}from"./expoStorage";function a(){try{return globalThis.localStorage??null}catch{return null}}export function defaultNotificationStorage(){const e=a();if(!e)return{durable:false};const n={async getItem(t){return e.getItem(t)},async setItem(t,r){e.setItem(t,r)},async removeItem(t){e.removeItem(t)},async getAllKeys(){const t=[];for(let r=0;r<e.length;r++){const o=e.key(r);if(o?.startsWith("buoy.notifications."))t.push(o)}return t}};return{storage:n,durable:true}}
|
|
@@ -0,0 +1,73 @@
|
|
|
1
|
+
import type { NotificationPreviewAppearance } from "./types";
|
|
2
|
+
import { NotificationRecorder } from "./recorder";
|
|
3
|
+
/**
|
|
4
|
+
* @capacitor/push-notifications and @capacitor/local-notifications, through
|
|
5
|
+
* Buoy's Capacitor bridge hook (@buoy-gg/license).
|
|
6
|
+
*
|
|
7
|
+
* Capture is passive: Buoy reads what reaches the app's OWN listeners from
|
|
8
|
+
* the hook's call log and never adds a push listener of its own. Capacitor
|
|
9
|
+
* holds some push events (the tap that opened the app) until the first
|
|
10
|
+
* listener arrives, so a Buoy listener added first could take that event from
|
|
11
|
+
* the app. An event the app has no listener for is not captured.
|
|
12
|
+
*
|
|
13
|
+
* Several app listeners for one event each get their own delivery; those
|
|
14
|
+
* deliveries share a dedupe key, so the event is recorded once.
|
|
15
|
+
*/
|
|
16
|
+
type Bridge = {
|
|
17
|
+
hasCapacitorPlugin(plugin: string): boolean;
|
|
18
|
+
installCapacitorBridge(): boolean;
|
|
19
|
+
subscribeCapacitorCalls(listener: () => void): () => void;
|
|
20
|
+
getCapacitorCalls(): readonly BridgeCall[];
|
|
21
|
+
callCapacitorNative<T = unknown>(plugin: string, method: string, options?: Record<string, unknown>): Promise<T>;
|
|
22
|
+
callCapacitorAsApp<T = unknown>(plugin: string, method: string, options?: Record<string, unknown>): Promise<T>;
|
|
23
|
+
listenCapacitorNative(plugin: string, eventName: string, listener: (data: unknown) => void): Promise<{
|
|
24
|
+
remove(): Promise<void>;
|
|
25
|
+
}>;
|
|
26
|
+
loadCapacitorAppHost?(): Promise<{
|
|
27
|
+
bundleId: string | null;
|
|
28
|
+
appName: string | null;
|
|
29
|
+
} | null>;
|
|
30
|
+
};
|
|
31
|
+
interface BridgeCall {
|
|
32
|
+
seq: number;
|
|
33
|
+
plugin: string;
|
|
34
|
+
method: string;
|
|
35
|
+
kind: "promise" | "callback" | "event";
|
|
36
|
+
options: Record<string, unknown>;
|
|
37
|
+
start: number;
|
|
38
|
+
end?: number;
|
|
39
|
+
ok?: boolean;
|
|
40
|
+
result?: unknown;
|
|
41
|
+
}
|
|
42
|
+
export interface CapacitorCaptureOptions {
|
|
43
|
+
platform: string;
|
|
44
|
+
appId?: string;
|
|
45
|
+
providerVersion?: string;
|
|
46
|
+
preview?: NotificationPreviewAppearance;
|
|
47
|
+
}
|
|
48
|
+
/** Title, ids and Buoy's test id from a Capacitor notification or action. */
|
|
49
|
+
export declare function capacitorMetadata(value: unknown): {
|
|
50
|
+
notificationId: string | null;
|
|
51
|
+
testId: string | null;
|
|
52
|
+
title: string | null;
|
|
53
|
+
actionIdentifier: string | null;
|
|
54
|
+
};
|
|
55
|
+
/** Same contract as attachExpoNotifications: `{ actions, ready, dispose }`. */
|
|
56
|
+
export declare function attachCapacitorNotifications(recorder: NotificationRecorder, bridge: Bridge, options: CapacitorCaptureOptions): {
|
|
57
|
+
actions: {
|
|
58
|
+
getPermissions(): Promise<import("./types").Json>;
|
|
59
|
+
listPresented(): Promise<import("./types").Json>;
|
|
60
|
+
refreshToken(params: unknown): Promise<{
|
|
61
|
+
type: string;
|
|
62
|
+
value: string;
|
|
63
|
+
}>;
|
|
64
|
+
scheduleLocal(params: unknown): Promise<{
|
|
65
|
+
notificationId: string;
|
|
66
|
+
transport: string;
|
|
67
|
+
}>;
|
|
68
|
+
};
|
|
69
|
+
ready: Promise<void>;
|
|
70
|
+
dispose(): void;
|
|
71
|
+
};
|
|
72
|
+
export {};
|
|
73
|
+
//# sourceMappingURL=capacitor.d.ts.map
|
|
@@ -0,0 +1,19 @@
|
|
|
1
|
+
import type { NotificationStorage } from "./types";
|
|
2
|
+
export interface ExpoNotificationFileSystem {
|
|
3
|
+
documentDirectory: string | null;
|
|
4
|
+
getInfoAsync(path: string): Promise<{
|
|
5
|
+
exists: boolean;
|
|
6
|
+
}>;
|
|
7
|
+
makeDirectoryAsync(path: string, options: {
|
|
8
|
+
intermediates: boolean;
|
|
9
|
+
}): Promise<void>;
|
|
10
|
+
readAsStringAsync(path: string): Promise<string>;
|
|
11
|
+
writeAsStringAsync(path: string, value: string): Promise<void>;
|
|
12
|
+
deleteAsync(path: string, options: {
|
|
13
|
+
idempotent: boolean;
|
|
14
|
+
}): Promise<void>;
|
|
15
|
+
readDirectoryAsync(path: string): Promise<string[]>;
|
|
16
|
+
}
|
|
17
|
+
/** Propagates native I/O failures so capture never acknowledges a memory fallback as durable. */
|
|
18
|
+
export declare function createExpoNotificationStorage(fs: ExpoNotificationFileSystem): NotificationStorage;
|
|
19
|
+
//# sourceMappingURL=expoStorage.d.ts.map
|
|
@@ -2,8 +2,10 @@ export * from "./types";
|
|
|
2
2
|
export { NotificationRecorder, expoMetadata } from "./recorder";
|
|
3
3
|
export { attachExpoNotifications, instrumentExpoNotificationHandler, instrumentNotificationBackgroundTask } from "./expo";
|
|
4
4
|
export type { ExpoNotifications, ExpoCaptureOptions } from "./expo";
|
|
5
|
-
export { installExpoNotificationCapture, getNotificationRecorder, notificationSyncAdapter } from "./runtime";
|
|
6
|
-
export type { InstallNotificationOptions } from "./runtime";
|
|
5
|
+
export { installExpoNotificationCapture, installCapacitorNotificationCapture, getNotificationRecorder, notificationSyncAdapter } from "./runtime";
|
|
6
|
+
export type { InstallNotificationOptions, InstallCapacitorNotificationOptions } from "./runtime";
|
|
7
|
+
export { attachCapacitorNotifications, capacitorMetadata } from "./capacitor";
|
|
8
|
+
export type { CapacitorCaptureOptions } from "./capacitor";
|
|
7
9
|
export { NotificationToolView } from "./components/NotificationToolView";
|
|
8
10
|
export type { NotificationToolViewProps, NotificationTab } from "./components/NotificationToolView";
|
|
9
11
|
export { notificationToolPreset, createNotificationTool, NotificationsModal } from "./preset";
|
|
@@ -1,5 +1,6 @@
|
|
|
1
1
|
import { NotificationRecorder } from "./recorder";
|
|
2
2
|
import { type ExpoNotifications, type ExpoCaptureOptions } from "./expo";
|
|
3
|
+
import { type CapacitorCaptureOptions } from "./capacitor";
|
|
3
4
|
import type { NotificationStorage } from "./types";
|
|
4
5
|
export interface InstallNotificationOptions extends Omit<ExpoCaptureOptions, "platform"> {
|
|
5
6
|
platform?: string;
|
|
@@ -11,6 +12,18 @@ export interface InstallNotificationOptions extends Omit<ExpoCaptureOptions, "pl
|
|
|
11
12
|
export declare function captureEnabled(enableInRelease?: boolean): boolean;
|
|
12
13
|
export declare function getNotificationRecorder(): NotificationRecorder | null;
|
|
13
14
|
export declare function installExpoNotificationCapture(sdk: ExpoNotifications, options?: InstallNotificationOptions): NotificationRecorder | null;
|
|
15
|
+
export interface InstallCapacitorNotificationOptions extends Omit<CapacitorCaptureOptions, "platform"> {
|
|
16
|
+
storage?: NotificationStorage;
|
|
17
|
+
durable?: boolean;
|
|
18
|
+
/** Explicit opt-in for internal release builds. Desktop sync still requires Pro. */
|
|
19
|
+
enableInRelease?: boolean;
|
|
20
|
+
}
|
|
21
|
+
/**
|
|
22
|
+
* Capacitor apps: capture @capacitor/push-notifications and
|
|
23
|
+
* @capacitor/local-notifications through Buoy's plugin hook. Runs by itself
|
|
24
|
+
* when the package loads in a debug Capacitor build; call it to pass options.
|
|
25
|
+
*/
|
|
26
|
+
export declare function installCapacitorNotificationCapture(options?: InstallCapacitorNotificationOptions): NotificationRecorder | null;
|
|
14
27
|
export declare const notificationSyncAdapter: {
|
|
15
28
|
version: number;
|
|
16
29
|
getSnapshot: () => import("./types").NotificationSnapshot;
|
|
@@ -1,21 +1,5 @@
|
|
|
1
1
|
import type { NotificationStorage } from "./types";
|
|
2
|
-
export
|
|
3
|
-
documentDirectory: string | null;
|
|
4
|
-
getInfoAsync(path: string): Promise<{
|
|
5
|
-
exists: boolean;
|
|
6
|
-
}>;
|
|
7
|
-
makeDirectoryAsync(path: string, options: {
|
|
8
|
-
intermediates: boolean;
|
|
9
|
-
}): Promise<void>;
|
|
10
|
-
readAsStringAsync(path: string): Promise<string>;
|
|
11
|
-
writeAsStringAsync(path: string, value: string): Promise<void>;
|
|
12
|
-
deleteAsync(path: string, options: {
|
|
13
|
-
idempotent: boolean;
|
|
14
|
-
}): Promise<void>;
|
|
15
|
-
readDirectoryAsync(path: string): Promise<string[]>;
|
|
16
|
-
}
|
|
17
|
-
/** Propagates native I/O failures so capture never acknowledges a memory fallback as durable. */
|
|
18
|
-
export declare function createExpoNotificationStorage(fs: ExpoNotificationFileSystem): NotificationStorage;
|
|
2
|
+
export { createExpoNotificationStorage, type ExpoNotificationFileSystem } from "./expoStorage";
|
|
19
3
|
export declare function defaultNotificationStorage(): {
|
|
20
4
|
storage?: NotificationStorage;
|
|
21
5
|
durable: boolean;
|
|
@@ -0,0 +1,8 @@
|
|
|
1
|
+
import type { NotificationStorage } from "./types";
|
|
2
|
+
export { createExpoNotificationStorage, type ExpoNotificationFileSystem } from "./expoStorage";
|
|
3
|
+
/** The web build (a Capacitor WebView): the page's localStorage, which survives restarts. */
|
|
4
|
+
export declare function defaultNotificationStorage(): {
|
|
5
|
+
storage?: NotificationStorage;
|
|
6
|
+
durable: boolean;
|
|
7
|
+
};
|
|
8
|
+
//# sourceMappingURL=storage.web.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
"use client";var He=Object.defineProperty;var pt=Object.getOwnPropertyDescriptor;var ut=Object.getOwnPropertyNames;var ht=Object.prototype.hasOwnProperty;var ft=(e,t)=>{for(var i in t)He(e,i,{get:t[i],enumerable:true})},Fe=(e,t,i,o)=>{if(t&&typeof t=="object"||typeof t=="function")for(let r of ut(t))!ht.call(e,r)&&r!==i&&He(e,r,{get:()=>t[r],enumerable:!(o=pt(t,r))||o.enumerable});return e},yt=(e,t,i)=>(Fe(e,t,"default"),i&&Fe(i,t,"default"));var ue=(()=>{try{let e=globalThis.Capacitor;if(e&&typeof e.isNativePlatform=="function"&&e.isNativePlatform())return e.DEBUG===true}catch{}return process.env.NODE_ENV!=="production"})();typeof window<"u"&&typeof globalThis.global>"u"&&(globalThis.global=globalThis);var We={};ft(We,{AccessibilityInfo:()=>vt,ActivityIndicator:()=>co,Alert:()=>ho,Animated:()=>wt,AppRegistry:()=>It,AppState:()=>Me,Appearance:()=>St,BackHandler:()=>xt,Button:()=>po,CheckBox:()=>Vt,Clipboard:()=>kt,DeviceEventEmitter:()=>Zt,Dimensions:()=>Ct,Easing:()=>Tt,FlatList:()=>_e,I18nManager:()=>Nt,Image:()=>Ke,ImageBackground:()=>Ht,InteractionManager:()=>Pt,Keyboard:()=>At,KeyboardAvoidingView:()=>Ft,LayoutAnimation:()=>Et,Linking:()=>Rt,LogBox:()=>Yt,Modal:()=>so,NativeEventEmitter:()=>zt,NativeModules:()=>mt,PanResponder:()=>Lt,Picker:()=>Wt,PixelRatio:()=>Dt,Platform:()=>Se,Pressable:()=>_,ProgressBar:()=>Mt,RefreshControl:()=>_t,SafeAreaView:()=>Kt,ScrollView:()=>oe,SectionList:()=>Jt,Share:()=>jt,StatusBar:()=>$t,StyleSheet:()=>he,Switch:()=>lo,Text:()=>d,TextInput:()=>se,Touchable:()=>qt,TouchableHighlight:()=>no,TouchableNativeFeedback:()=>Ut,TouchableOpacity:()=>ro,TouchableWithoutFeedback:()=>ao,UIManager:()=>Bt,Vibration:()=>Ot,View:()=>f,VirtualizedList:()=>Gt,YellowBox:()=>Xt,findNodeHandle:()=>uo,unstable_createElement:()=>bt,useColorScheme:()=>Qt,useLocaleContext:()=>eo,useWindowDimensions:()=>to});yt(We,gt);import*as gt from"react-native-web";import{unstable_createElement as bt,NativeModules as mt,AccessibilityInfo as vt,Animated as wt,Appearance as St,AppRegistry as It,AppState as Me,BackHandler as xt,Clipboard as kt,Dimensions as Ct,Easing as Tt,I18nManager as Nt,Keyboard as At,InteractionManager as Pt,LayoutAnimation as Et,Linking as Rt,NativeEventEmitter as zt,PanResponder as Lt,PixelRatio as Dt,Platform as Se,Share as jt,StyleSheet as he,UIManager as Bt,Vibration as Ot,CheckBox as Vt,FlatList as _e,Image as Ke,ImageBackground as Ht,KeyboardAvoidingView as Ft,Picker as Wt,ProgressBar as Mt,RefreshControl as _t,SafeAreaView as Kt,SectionList as Jt,StatusBar as $t,Touchable as qt,TouchableNativeFeedback as Ut,VirtualizedList as Gt,YellowBox as Xt,LogBox as Yt,DeviceEventEmitter as Zt,useColorScheme as Qt,useLocaleContext as eo,useWindowDimensions as to}from"react-native-web";import*as B from"react-native-web";import{createElement as oo,forwardRef as io}from"react";function O(e){let t=io((o,r)=>{let{accessibilityState:a,accessibilityValue:l,...u}=o;for(let p of["busy","checked","disabled","expanded","selected"])a?.[p]!==void 0&&u[`aria-${p}`]===void 0&&(u[`aria-${p}`]=a[p]);for(let[p,c]of Object.entries({min:"valuemin",max:"valuemax",now:"valuenow",text:"valuetext"}))l?.[p]!==void 0&&u[`aria-${c}`]===void 0&&(u[`aria-${c}`]=l[p]);return oo(e,{...u,ref:r})}),i=e.State;return i&&Object.assign(t,{State:i}),t.displayName=e.displayName??e.name??"NativeWebView",t}var f=O(B.View),d=O(B.Text),se=O(B.TextInput),ro=O(B.TouchableOpacity),no=O(B.TouchableHighlight),ao=O(B.TouchableWithoutFeedback),_=O(B.Pressable),oe=O(B.ScrollView),so=O(B.Modal),lo=O(B.Switch),co=O(B.ActivityIndicator),po=O(B.Button),uo=B.findNodeHandle,ho={alert(e,t,i,o){if(typeof document>"u")return;let r=document.createElement("dialog");r.dataset.buoyRoot="",r.setAttribute("aria-label",e),r.style.cssText="position:fixed;inset:0;margin:auto;width:min(440px,90vw);padding:24px;border:1px solid #475569;border-radius:14px;background:#17212e;color:#f1f5f9;font:14px system-ui;box-shadow:0 20px 80px #0008;z-index:2147483647";let a=document.createElement("h2");if(a.textContent=e,a.style.cssText="font-size:18px;margin:0 0 12px",r.appendChild(a),t){let c=document.createElement("p");c.textContent=t,c.style.cssText="line-height:1.5;white-space:pre-wrap;margin:0 0 20px",r.appendChild(c)}let l=document.createElement("div");l.style.cssText="display:flex;justify-content:flex-end;flex-wrap:wrap;gap:8px";let u=i?.length?i:[{text:"OK"}],p=()=>{r.close?.(),r.remove()};for(let c of u){let b=document.createElement("button");b.type="button",b.textContent=c.text??"OK",b.style.cssText=`padding:9px 14px;border:1px solid #64748b;border-radius:7px;color:white;background:${c.style==="destructive"?"#a52b38":"#283a4d"};cursor:pointer;font:inherit`,b.onclick=()=>{p(),c.onPress?.()},l.appendChild(b)}r.addEventListener("cancel",c=>{c.preventDefault(),o?.cancelable!==false&&(p(),o?.onDismiss?.())}),r.appendChild(l),document.body.appendChild(r),r.showModal?r.showModal():r.setAttribute("open","")}};function fo(e){if(!e.documentDirectory)throw new Error("Expo FileSystem has no persistent document directory.");let t=e.documentDirectory+"buoy-notifications/",i=o=>t+encodeURIComponent(o)+".json";return{async getItem(o){let r=i(o);return(await e.getInfoAsync(r)).exists?e.readAsStringAsync(r):null},async setItem(o,r){(await e.getInfoAsync(t)).exists||await e.makeDirectoryAsync(t,{intermediates:true}),await e.writeAsStringAsync(i(o),r)},async removeItem(o){await e.deleteAsync(i(o),{idempotent:true})},async getAllKeys(){return(await e.getInfoAsync(t)).exists?(await e.readDirectoryAsync(t)).filter(o=>o.endsWith(".json")).flatMap(o=>{try{return[decodeURIComponent(o.slice(0,-5))]}catch{return[]}}):[]}}}function yo(){try{return globalThis.localStorage??null}catch{return null}}function go(){let e=yo();return e?{storage:{async getItem(t){return e.getItem(t)},async setItem(t,i){e.setItem(t,i)},async removeItem(t){e.removeItem(t)},async getAllKeys(){let t=[];for(let i=0;i<e.length;i++){let o=e.key(i);o?.startsWith("buoy.notifications.")&&t.push(o)}return t}},durable:true}:{durable:false}}function y(e){return e!==null&&typeof e=="object"&&!Array.isArray(e)?e:{}}function L(e){return typeof e=="string"?e:null}function Ie(e){let t=new WeakSet;function i(o,r){if(o==null)return null;if(typeof o=="string")return o.length>12e3?o.slice(0,12e3)+" [truncated]":o;if(typeof o=="boolean")return o;if(typeof o=="number")return Number.isFinite(o)?o:String(o);if(typeof o!="object")return String(o);if(t.has(o))return"[Circular]";if(r>12)return"[Depth limit]";if(t.add(o),o instanceof Error)return{name:o.name,message:o.message};if(o instanceof Date)return Number.isNaN(o.getTime())?"[Invalid date]":o.toISOString();if(Array.isArray(o))return o.slice(0,200).map(l=>i(l,r+1));let a={};for(let l of Object.keys(o).slice(0,200))try{Object.defineProperty(a,l,{value:i(o[l],r+1),enumerable:true})}catch{a[l]="[Unreadable]"}return a}return i(e,0)}function ie(e){let t=0;for(let i of e){let o=i.codePointAt(0);t+=o<=127?1:o<=2047?2:o<=65535?3:4}return t}var xe="buoy.notifications.v1.",ke=xe+"session",Je=xe+"tokens",fe=xe+"event.",Ce=16*1024,bo=512*1024,mo=200,Te=class{constructor(e={}){this.options=e;this.state={version:1,ready:false,provider:null,providerVersion:null,platform:"unknown",appId:null,capabilities:[],durable:false,storageError:null,evicted:0,session:null,events:[],tokens:[],permissions:null,presented:null};this.listeners=new Set;this.sequence=0;this.queue=Promise.resolve();this.getSnapshot=()=>this.state;this.subscribe=t=>(this.listeners.add(t),()=>{this.listeners.delete(t)});this.now=e.now??Date.now,this.processId=e.processId??`${this.now().toString(36)}-${Math.random().toString(36).slice(2)}`,this.state.durable=!!e.storage&&e.durable===true,this.ready=this.hydrate(),this.queue=this.ready}update(e){this.state={...this.state,...e};for(let t of this.listeners)try{t()}catch{}}configure(e){this.update(e)}allowed(){return this.options.enabled?.()??true}storageFailure(e){this.update({storageError:e instanceof Error?e.message:String(e),durable:false})}serial(e){let t=this.queue.then(e);return this.queue=t.catch(()=>{}),t}async hydrate(){if(!this.allowed()){this.update({ready:true});return}if(this.options.durability)try{this.update({durable:await this.options.durability})}catch(i){this.storageFailure(i)}let e=this.options.storage,t=false;if(e)try{let i=await e.getItem(ke);if(t=i==="null",i){let l=JSON.parse(i);l&&typeof l.runId=="string"&&Number.isFinite(l.expiresAt)&&l.expiresAt>this.now()&&this.update({session:l})}let o=await e.getItem(Je);if(o){let l=JSON.parse(o);Array.isArray(l)&&this.update({tokens:l.filter(u=>u&&["apns","fcm","expo"].includes(u.type)&&typeof u.value=="string").slice(-10)})}let r=(await e.getAllKeys()).filter(l=>l.startsWith(fe)).sort(),a=[];for(let l of r)try{let u=await e.getItem(l);if(!u||ie(u)>Ce){await e.removeItem(l);continue}let p=JSON.parse(u);typeof p.id=="string"&&typeof p.kind=="string"&&Number.isFinite(p.capturedAt)?a.push(p):await e.removeItem(l)}catch{await e.removeItem(l)}a.sort((l,u)=>l.capturedAt-u.capturedAt||l.sequence-u.sequence||l.id.localeCompare(u.id)),this.update({events:a}),await this.prune()}catch(i){this.storageFailure(i)}if(this.options.autoStart&&!this.state.session&&!t){let i=this.now(),o={runId:this.processId,startedAt:i,expiresAt:i+1800*1e3};try{await e?.setItem(ke,JSON.stringify(o))}catch(r){this.storageFailure(r)}this.update({session:o})}this.update({ready:true})}async setCaptureSession(e,t=1800*1e3){if(!this.allowed())throw new Error("Notification capture is disabled in this build.");if(e!==null&&(typeof e!="string"||!e.trim()||e.length>128))throw new Error("runId must contain 1 to 128 characters, or be null to stop capture.");if(!Number.isFinite(t)||t<1e3||t>3600*1e3)throw new Error("Capture duration must be between 1 second and 1 hour.");return this.serial(async()=>{let i=this.now(),o=e===null?null:{runId:e,startedAt:i,expiresAt:i+t};try{this.options.storage&&await this.options.storage.setItem(ke,JSON.stringify(o))}catch(r){throw this.storageFailure(r),new Error("Could not persist the capture session. Keep the app open and check storage.")}return this.update({session:o}),{session:o,durable:this.state.durable}})}record(e,t,i={}){let o=this.now(),r=this.options.appState?.()??"unknown",a=Ie(t);return this.serial(async()=>{if(!this.allowed())return null;let l=this.state.session;if(!l||l.expiresAt<=o)return l&&this.update({session:null}),null;let u=(b,R=512)=>typeof b=="string"?b.slice(0,R):null,p=u(i.dedupeKey,2048);if(p&&this.state.events.some(b=>b.dedupeKey===p))return null;let c={id:`${this.processId}-${++this.sequence}`,processId:this.processId,sequence:this.sequence,capturedAt:o,runId:l.runId,kind:e,provider:u(i.provider,64)??this.state.provider??"app",observedAppState:r,notificationId:u(i.notificationId),testId:u(i.testId),title:u(i.title,1024),actionIdentifier:u(i.actionIdentifier),...p?{dedupeKey:p}:{},raw:a};ie(JSON.stringify(c))>Ce&&(c.raw={note:"Payload exceeded the 16 KiB capture limit."},c.truncated=true),this.update({events:[...this.state.events,c]});try{await this.options.storage?.setItem(fe+c.id,JSON.stringify(c))}catch(b){this.storageFailure(b)}try{await this.prune()}catch(b){this.storageFailure(b)}return c})}async prune(){let e=[...this.state.events],t=e.map(r=>ie(JSON.stringify(r))),i=t.reduce((r,a)=>r+a,0),o=[];for(;e.length>mo||i>bo;)o.push(e.shift()),i-=t.shift();o.length&&this.update({events:e,evicted:this.state.evicted+o.length});for(let r of o)await this.options.storage?.removeItem(fe+r.id)}async clearCapturedEvents(){return this.serial(async()=>{let e=this.state.events;for(let t of e)await this.options.storage?.removeItem(fe+t.id);return this.update({events:[],evicted:0}),{cleared:true}})}async observeToken(e,t,i={}){if(this.allowed()){if(!t||t.length>8192)throw new Error("The notification token is empty or too long.");return this.serial(async()=>{let o={type:e,value:t,observedAt:this.now(),...typeof i.projectId=="string"?{projectId:i.projectId.slice(0,256)}:{},...typeof i.environment=="string"?{environment:i.environment.slice(0,256)}:{}},r=[...this.state.tokens.filter(a=>!(a.type===e&&a.projectId===i.projectId&&a.environment===i.environment)),o].slice(-10);this.update({tokens:r});try{await this.options.storage?.setItem(Je,JSON.stringify(r))}catch(a){this.storageFailure(a)}})}}setPermissions(e){let t=Ie(e);this.update({permissions:ie(JSON.stringify(t))<=Ce?t:{note:"Permission result exceeded the capture limit."}})}setPresented(e){let t=Ie(e);ie(JSON.stringify(t))<=128*1024?this.update({presented:t}):this.update({presented:{note:"System tray result exceeded 128 KiB. Inspect fewer presented notifications in the app.",count:Array.isArray(e)?e.length:null}})}async flush(){await this.queue}};function X(e){let t=y(e),i=y(t.notification??e),o=y(i.request),r=y(o.content),a=y(y(o.trigger).payload),l=y(r.data??a.body);return{notificationId:L(o.identifier),testId:L(l.__buoyTestId),title:L(r.title),actionIdentifier:L(t.actionIdentifier)}}function vo(e){let t=y(e),i=y(t.notification);return JSON.stringify([y(i.request).identifier,i.date,t.actionIdentifier,t.userText])}function $e(e){if(!e||typeof e!="object")return;let t={};typeof e.appName=="string"&&(t.appName=e.appName.trim().slice(0,80)),typeof e.iconUri=="string"&&e.iconUri.length<=32768&&/^data:image\/(png|jpeg|webp);base64,[A-Za-z0-9+/]+={0,2}$/.test(e.iconUri)&&(t.iconUri=e.iconUri);for(let i of["backgroundColor","textColor"])typeof e[i]=="string"&&/^#[0-9a-f]{6}$/i.test(e[i])&&(t[i]=e[i]);return Object.keys(t).length?t:void 0}function le(e,t=15e3){return new Promise((i,o)=>{let r=setTimeout(()=>o(new Error("Notification SDK timed out. Check permission and network settings, then retry.")),t);e.then(a=>{clearTimeout(r),i(a)},a=>{clearTimeout(r),o(a)})})}function qe(e,t,i){let o=["received","responses","permissions","device-token"];(t.getLastNotificationResponse||t.getLastNotificationResponseAsync)&&o.push("startup-response"),t.getPresentedNotificationsAsync&&o.push("presented"),t.scheduleNotificationAsync&&o.push("local-scheduling"),i.projectId&&t.getExpoPushTokenAsync&&o.push("expo-token"),e.configure({preview:$e(i.preview),provider:"expo",platform:i.platform,appId:i.appId??null,providerVersion:i.providerVersion??null,capabilities:o});let r=false,a=[],l=(c,b=false)=>{r||!c||e.record(b?"startup-response":"response",c,{...X(c),dedupeKey:vo(c)})};try{a.push(t.addNotificationReceivedListener(c=>{r||e.record("received",c,X(c))})),a.push(t.addNotificationResponseReceivedListener(c=>l(c))),a.push(t.addPushTokenListener(c=>{!r&&(c.type==="ios"||c.type==="android")&&e.observeToken(c.type==="ios"?"apns":"fcm",c.data).catch(()=>{})}))}catch(c){for(let b of a)b.remove();throw c}let u=Promise.resolve().then(()=>t.getLastNotificationResponse?.()??t.getLastNotificationResponseAsync?.()).then(c=>l(c,true));u.catch(()=>{});let p={async getPermissions(){let c=await le(t.getPermissionsAsync());return e.setPermissions(c),e.getSnapshot().permissions},async listPresented(){if(!t.getPresentedNotificationsAsync)throw new Error("This notification SDK cannot list presented notifications.");let c=await le(t.getPresentedNotificationsAsync());return e.setPresented(c),e.getSnapshot().presented},async refreshToken(c){let{type:b}=y(c);if(b==="expo"){if(!t.getExpoPushTokenAsync||!i.projectId)throw new Error("Set projectId in installExpoNotificationCapture before requesting an Expo token.");let P=await le(t.getExpoPushTokenAsync({projectId:i.projectId}));return await e.observeToken("expo",P.data,{projectId:i.projectId}),{type:"expo",value:P.data}}if(b!=="device")throw new Error('Token type must be "device" or "expo".');if(!t.getDevicePushTokenAsync)throw new Error("This notification SDK cannot register a device token.");let R=await le(t.getDevicePushTokenAsync());if(R.type!=="ios"&&R.type!=="android")throw new Error("This platform does not provide an APNs or FCM token.");return await e.observeToken(R.type==="ios"?"apns":"fcm",R.data),{type:R.type==="ios"?"apns":"fcm",value:R.data}},async scheduleLocal(c){if(!t.scheduleNotificationAsync)throw new Error("This notification SDK cannot schedule local notifications.");let{title:b,body:R,data:P,seconds:T}=y(c);if(typeof b!="string"||typeof R!="string"||typeof T!="number"||!Number.isFinite(T)||T<1||T>3600)throw new Error("Provide title, body and a delay from 1 to 3600 seconds.");if(P!==void 0&&(P===null||typeof P!="object"||Array.isArray(P)))throw new Error("Local notification data must be an object.");let J=await le(t.scheduleNotificationAsync({content:{title:b,body:R,data:P??{}},trigger:{type:"timeInterval",seconds:T,repeats:false}}));return await e.record("local-scheduled",{title:b,body:R,data:P,seconds:T},{notificationId:J,title:b,testId:typeof y(P).__buoyTestId=="string"?y(P).__buoyTestId:null}),{notificationId:J,transport:"local"}}};return p.getPermissions().catch(()=>{}),{actions:p,ready:u,dispose(){r=true;for(let c of a)c.remove()}}}function wo(e,t){let i=new Map;return{...t,handleNotification:async function(...o){let r=X(o[0]);r.notificationId&&i.set(r.notificationId,r),i.size>50&&i.delete(i.keys().next().value);try{let a=await t.handleNotification.apply(this,o);return e.record("presentation-decision",{notification:o[0],behavior:a},X(o[0])),a}catch(a){throw e.record("presentation-error",{notification:o[0],error:a},X(o[0])),a}},handleError:function(...o){let r=L(o[0]),a=r?i.get(r):void 0;return r&&i.delete(r),e.record("presentation-error",{source:"sdk",identifier:r,error:o[1]},a??{notificationId:r}),t.handleError?.apply(this,o)}}}function So(e){let t=X(e),i=y(e),o=y(i.data),r=y(o.UIApplicationLaunchOptionsRemoteNotificationKey),a={};if(typeof o.dataString=="string")try{a=y(JSON.parse(o.dataString))}catch{}let l=y(o.body??i.body??r.body);return{...t,testId:t.testId??L(a.__buoyTestId)??L(l.__buoyTestId),title:t.title??L(y(i.notification).title)??L(y(y(i.aps??r.aps).alert).title)}}async function Ne(e){let t;await Promise.race([e.catch(()=>{}),new Promise(i=>{t=setTimeout(i,250)})]),t&&clearTimeout(t)}function Io(e,t){return e.configure({capabilities:[...new Set([...e.getSnapshot().capabilities,"background-task"])]}),(async function(...i){let o=y(i[0]).data??i[0],r=So(o);await Ne(e.record("background-started",i[0],r));try{let a=await t.apply(this,i);return await Ne(e.record("background-completed",{input:i[0],result:a},r)),a}catch(a){throw await Ne(e.record("background-error",{input:i[0],error:a},r)),a}})}var re="PushNotifications",ce="LocalNotifications";function ye(e){let t=y(e),i=y(t.notification??e),o=y(i.data??i.extra),r=y(o.body),a=i.id;return{notificationId:typeof a=="number"?String(a):L(a),testId:L(o.__buoyTestId)??L(r.__buoyTestId),title:L(i.title)??L(y(y(o.aps).alert).title),actionIdentifier:L(t.actionId)}}function de(e,t=15e3){return new Promise((i,o)=>{let r=setTimeout(()=>o(new Error("The notification plugin timed out. Check permission and network settings, then retry.")),t);e.then(a=>{clearTimeout(r),i(a)},a=>{clearTimeout(r),o(a)})})}function Ue(e,t,i){let o=t.hasCapacitorPlugin(re),r=t.hasCapacitorPlugin(ce),a=["received","responses","permissions"];o&&a.push("device-token","presented"),r&&a.push("local-scheduling"),r&&!o&&a.push("presented"),e.configure({preview:$e(i.preview),provider:"capacitor",platform:i.platform,appId:i.appId??null,providerVersion:i.providerVersion??null,capabilities:a}),t.installCapacitorBridge(),i.appId||t.loadCapacitorAppHost?.().then(g=>{g?.bundleId&&e.configure({appId:g.bundleId})}).catch(()=>{});let l=i.platform==="ios"?"apns":"fcm",u=0,p=new Set,c=250,b=new Map,R=(g,w)=>{let m=b.get(g);if(m!==void 0&&w-m<c)return null;if(b.set(g,w),b.size>100)for(let[x,C]of b)w-C>=c&&b.delete(x);return w},P=g=>{if(g.plugin!==re&&g.plugin!==ce)return;let w=g.result,m=`${g.plugin}:${g.method}:${JSON.stringify(w??null).slice(0,1500)}`;if(g.kind==="event"&&R(m,g.start)===null)return;let x=`${m}:${g.start}`;if(g.kind==="event")switch(g.method){case"registration":{let C=L(y(w).value);C&&e.observeToken(l,C).catch(()=>{});return}case"pushNotificationReceived":case"localNotificationReceived":e.record("received",w,{...ye(w),provider:"capacitor",dedupeKey:x});return;case"pushNotificationActionPerformed":case"localNotificationActionPerformed":e.record("response",w,{...ye(w),provider:"capacitor",dedupeKey:x});return;default:return}if(!(g.kind!=="promise"||g.ok!==true))if(g.method==="checkPermissions"||g.method==="requestPermissions")e.setPermissions({plugin:g.plugin,...y(w)});else if(g.plugin===ce&&g.method==="schedule")for(let C of Array.isArray(g.options.notifications)?g.options.notifications:[]){let k=ye(C);e.record("local-scheduled",C,{...k,provider:"capacitor"})}else g.method==="getDeliveredNotifications"&&e.setPresented(y(w).notifications??w)},T=()=>{let g=t.getCapacitorCalls();for(let m of g)m.seq<=u||p.has(m.seq)||m.kind==="promise"&&m.end===void 0||(p.add(m.seq),P(m));let w=g[0]?.seq??0;if(w>u+1){u=w-1;for(let m of Array.from(p))m<=u&&p.delete(m)}},J=t.subscribeCapacitorCalls(T);T();let F=o?re:ce,j={async getPermissions(){if(!o&&!r)throw new Error("Install @capacitor/push-notifications or @capacitor/local-notifications in the app.");let g=await de(t.callCapacitorAsApp(F,"checkPermissions"));return e.setPermissions({plugin:F,...y(g)}),e.getSnapshot().permissions},async listPresented(){if(!o&&!r)throw new Error("This app has no notification plugin that can list presented notifications.");let g=await de(t.callCapacitorNative(F,"getDeliveredNotifications"));return e.setPresented(y(g).notifications??g),e.getSnapshot().presented},async refreshToken(g){let{type:w}=y(g);if(w==="expo")throw new Error("Expo push tokens need expo-notifications; this app uses Capacitor.");if(w!=="device")throw new Error('Token type must be "device".');if(!o)throw new Error("Install @capacitor/push-notifications to register a device token.");let m=null,x=new Promise((C,k)=>{t.listenCapacitorNative(re,"registration",z=>{let M=L(y(z).value);M&&C(M)}).then(z=>{m=z.remove}),t.listenCapacitorNative(re,"registrationError",z=>{k(new Error(L(y(z).error)??"Push registration failed."))}).then(z=>{let M=m;m=async()=>{await M?.(),await z.remove()}})});try{await de(t.callCapacitorNative(re,"register"));let C=await de(x);return await e.observeToken(l,C),{type:l,value:C}}finally{m?.()}},async scheduleLocal(g){if(!r)throw new Error("Install @capacitor/local-notifications to schedule local notifications.");let{title:w,body:m,data:x,seconds:C}=y(g);if(typeof w!="string"||typeof m!="string"||typeof C!="number"||!Number.isFinite(C)||C<1||C>3600)throw new Error("Provide title, body and a delay from 1 to 3600 seconds.");if(x!==void 0&&(x===null||typeof x!="object"||Array.isArray(x)))throw new Error("Local notification data must be an object.");let k=Math.floor(Math.random()*2e9)+1,z={id:k,title:w,body:m,extra:x??{},schedule:{at:new Date(Date.now()+C*1e3).toISOString()}};return await de(t.callCapacitorNative(ce,"schedule",{notifications:[z]})),await e.record("local-scheduled",{title:w,body:m,data:x,seconds:C},{notificationId:String(k),title:w,testId:typeof y(x).__buoyTestId=="string"?y(x).__buoyTestId:null,provider:"capacitor"}),{notificationId:String(k),transport:"local"}}};return j.getPermissions().catch(()=>{}),{actions:j,ready:e.ready,dispose(){J()}}}import*as Ge from"@buoy-gg/license/web";var ge=globalThis;function Ae(e=false){return typeof ue<"u"&&ue||e===true}function Pe(){return ge.__buoyNotificationsV1?.recorder??null}function Xe(e){let t=ge.__buoyNotificationsV1;if(!t){let i=e.storage?{storage:e.storage,durable:e.durable===true}:go();t={recorder:new Te({...i,enabled:()=>Ae(e.enableInRelease),appState:()=>Me.currentState??"unknown",autoStart:true})},ge.__buoyNotificationsV1=t}return t}function xo(e,t={}){if(!Ae(t.enableInRelease))return null;let i=JSON.stringify([t.platform??Se.OS,t.appId,t.providerVersion,t.projectId,t.enableInRelease,t.preview]),o=Xe(t);return(o.sdk!==e||o.key!==i)&&(o.attachment?.dispose(),o.attachment=qe(o.recorder,e,{...t,platform:t.platform??Se.OS}),o.sdk=e,o.key=i),o.recorder}function Ye(e={}){let t=Ge.capacitorPlatform();if(!t||!Ae(e.enableInRelease))return null;let i=JSON.stringify(["capacitor",e.appId,e.providerVersion,e.enableInRelease,e.preview]),o=Xe(e);return(o.sdk!=="capacitor"||o.key!==i)&&(o.attachment?.dispose(),o.attachment=Ue(o.recorder,Ge,{...e,platform:t}),o.sdk="capacitor",o.key=i),o.recorder}var Ze=new Te;function Y(){let e=ge.__buoyNotificationsV1;if(!e)throw new Error("Install notification capture in the app entry point (installExpoNotificationCapture), before rendering the root component. Capacitor apps capture by themselves in debug builds.");return e}var ne={version:1,getSnapshot:()=>(Pe()??Ze).getSnapshot(),subscribe:e=>(Pe()??Ze).subscribe(e),actions:{getSnapshot:()=>ne.getSnapshot(),getCapabilities:()=>{let{ready:e,provider:t,providerVersion:i,platform:o,appId:r,capabilities:a,durable:l,storageError:u}=ne.getSnapshot();return{ready:e,provider:t,providerVersion:i,platform:o,appId:r,capabilities:a,durable:l,storageError:u}},getEvent(e){let{id:t}=y(e);if(typeof t!="string")throw new Error("Provide the captured event id.");return Y().recorder.getSnapshot().events.find(i=>i.id===t)??null},async setCaptureSession(e){let{runId:t,durationMs:i}=y(e);if(typeof t!="string"&&t!==null)throw new Error("Provide runId, or null to stop capture.");if(i!==void 0&&typeof i!="number")throw new Error("durationMs must be a number.");return Y().recorder.setCaptureSession(t,i)},clearCapturedEvents:()=>Y().recorder.clearCapturedEvents(),getPermissions:()=>Y().attachment.actions.getPermissions(),listPresented:()=>Y().attachment.actions.listPresented(),refreshToken:e=>Y().attachment.actions.refreshToken(e),scheduleLocal:e=>Y().attachment.actions.scheduleLocal(e)}};import{useEffect as ko,useMemo as Qe,useState as Z}from"react";import{ChevronDown as Co,ChevronLeft as To,ChevronRight as et,Copy as tt,ModalHeader as Ee,NightBadge as be,NightCard as U,NightRows as ot,NightSectionLabel as G,NightSegmented as No,NotificationsIcon as Ao,PowerToggleButton as Po,Search as Eo,Settings as Ro,ToolEmptyState as Re,Trash2 as zo,X as Lo,copyToClipboard as Do,night as D,useSafeAreaInsets as jo}from"@buoy-gg/shared-ui/web";import{DataViewer as Bo}from"@buoy-gg/shared-ui/web/dataViewer";import{useRef as Oo,useState as Q}from"react";import{NightSegmented as Vo,night as ae}from"@buoy-gg/shared-ui/web";import{useEffect as Ho,useState as it}from"react";import{CheckCircle as Fo,ChevronDown as Wo,ChevronRight as Mo,NotificationsIcon as rt,XCircle as _o,night as A,useSafeAreaInsets as Ko}from"@buoy-gg/shared-ui/web";import{jsx as N,jsxs as V}from"react/jsx-runtime";function nt(e){let[t,i]=it(false);Ho(()=>i(false),[e.appearance?.iconUri]);let o=e.appearance?.textColor?{color:e.appearance.textColor}:void 0,[r,a]=it(false),l=Ko({minBottom:12});return V(f,{style:I.root,children:[N(oe,{testID:"notification-test-scroll",style:I.root,contentContainerStyle:I.scroll,keyboardShouldPersistTaps:"handled",children:V(f,{style:I.content,children:[V(f,{style:I.intro,children:[N(d,{accessibilityRole:"header",style:I.heading,children:"Test a notification"}),N(d,{style:I.caption,children:"Send a test notification to your app."})]}),e.destination,e.previewNote?N(d,{style:I.caption,children:e.previewNote}):V(f,{style:[I.preview,e.appearance?.backgroundColor?{backgroundColor:e.appearance.backgroundColor,borderColor:e.appearance.backgroundColor}:void 0],accessibilityLabel:"Notification preview",children:[V(f,{style:I.row,children:[e.appearance?.iconUri&&!t?N(Ke,{testID:"buoy-internal-notification-preview",source:{uri:e.appearance.iconUri},accessibilityLabel:`${e.appearance.appName??e.appName} icon`,style:I.appIcon,onError:()=>i(true)}):N(f,{style:I.iconFallback,children:N(rt,{size:22,color:A.color.accent})}),N(d,{numberOfLines:1,style:[I.caption,I.appName,o],children:e.appearance?.appName??e.appName}),N(d,{style:[I.caption,o],children:"now"})]}),N(se,{accessibilityLabel:"Notification title",placeholder:"Title",placeholderTextColor:A.color.placeholder,value:e.title,onChangeText:e.onTitleChange,style:[I.input,I.title,o],editable:!e.busy}),N(se,{accessibilityLabel:"Notification message",placeholder:"Message",placeholderTextColor:A.color.placeholder,value:e.message,onChangeText:e.onMessageChange,style:[I.input,o],editable:!e.busy})]}),e.result&&V(f,{accessibilityRole:"summary",accessibilityLiveRegion:"polite",testID:"notification-test-result",style:I.result,children:[V(f,{style:I.row,children:[e.result.failed?N(_o,{size:16,color:A.color.danger}):N(Fo,{size:16,color:A.color.accent}),N(d,{style:I.resultTitle,children:e.result.title})]}),N(d,{style:I.caption,children:e.result.message}),N(_,{accessibilityRole:"button",accessibilityLabel:"View activity",onPress:e.onViewActivity,style:I.secondary,children:N(d,{style:I.secondaryText,children:"View activity"})})]}),V(f,{children:[V(_,{accessibilityRole:"button",accessibilityLabel:"Notification options",accessibilityState:{expanded:r},onPress:()=>a(!r),style:I.options,children:[r?N(Wo,{size:12,color:A.color.textSecondary}):N(Mo,{size:12,color:A.color.textSecondary}),N(d,{style:I.caption,children:"Options"})]}),r&&e.options]})]})}),V(f,{style:[I.footer,{paddingBottom:l.bottom}],children:[!!e.error&&N(d,{accessibilityRole:"alert",style:I.error,children:e.error}),!!e.notice&&N(d,{accessibilityLiveRegion:"polite",style:I.caption,children:e.notice}),V(f,{style:I.footerRow,children:[N(d,{style:[I.caption,I.hint],children:e.hint}),V(_,{accessibilityRole:"button",accessibilityLabel:e.busy?"Sending\u2026":"Send notification",accessibilityState:{disabled:e.disabled||e.busy},disabled:e.disabled||e.busy,onPress:e.onSend,style:({pressed:u})=>[I.send,(e.disabled||e.busy)&&I.disabled,u&&I.pressed],children:[N(rt,{size:15,color:A.color.onAccent}),N(d,{style:I.sendText,children:e.busy?"Sending\u2026":"Send notification"})]})]})]})]})}var I=he.create({root:{flex:1,minHeight:0,minWidth:0},scroll:{padding:16,flexGrow:1},content:{width:"100%",maxWidth:620,alignSelf:"center",gap:20},intro:{gap:8,paddingTop:8},heading:{color:A.color.text,fontSize:22,fontWeight:"600",letterSpacing:-.5},caption:{color:A.color.textSecondary,fontSize:12,lineHeight:18},row:{flexDirection:"row",alignItems:"center",gap:8},appName:{flex:1,fontWeight:"600"},appIcon:{width:36,height:36,borderRadius:8},iconFallback:{width:36,height:36,alignItems:"center",justifyContent:"center",borderRadius:8,backgroundColor:A.color.fillSecondary},preview:{padding:16,gap:8,borderWidth:1,borderColor:A.color.glassBorder,borderRadius:20,backgroundColor:A.color.glass},input:{color:A.color.text,fontSize:14,padding:6,minHeight:36},title:{fontSize:16,fontWeight:"600"},result:{gap:10,padding:16,borderWidth:1,borderColor:A.color.glassBorder,borderRadius:14},resultTitle:{color:A.color.text,fontWeight:"500",fontSize:13,flexShrink:1},secondary:{alignSelf:"flex-start",paddingHorizontal:14,paddingVertical:8,borderRadius:24,backgroundColor:A.color.fillSecondary},secondaryText:{color:A.color.accent,fontSize:13},options:{flexDirection:"row",alignItems:"center",gap:6,paddingVertical:12},footer:{padding:14,gap:8,borderTopWidth:1,borderTopColor:A.color.separator},footerRow:{flexDirection:"row",flexWrap:"wrap",alignItems:"center",justifyContent:"space-between",gap:12},hint:{flexGrow:1,flexShrink:1,flexBasis:200},send:{flexDirection:"row",alignItems:"center",justifyContent:"center",gap:8,borderRadius:24,paddingHorizontal:18,paddingVertical:12,backgroundColor:A.color.accent},sendText:{color:A.color.onAccent,fontSize:13,fontWeight:"600"},disabled:{opacity:.4},pressed:{opacity:.8},error:{color:A.color.danger,fontSize:12,lineHeight:18}});import{jsx as K,jsxs as me}from"react/jsx-runtime";function Jo({snapshot:e,onAction:t,onViewActivity:i}){let[o,r]=Q("Test notification"),[a,l]=Q("Tap to open the app."),[u,p]=Q("{}"),[c,b]=Q("1"),[R,P]=Q(false),T=Oo(false),[J,F]=Q(null),[j,g]=Q(null),w={},m=null;try{if(w=JSON.parse(u),!w||typeof w!="object"||Array.isArray(w))throw new Error}catch{m="Custom data must be a JSON object. Open Options to edit it."}async function x(){if(T.current||m)return;T.current=true,P(true),g(null),F(null);let E={testId:`buoy-local-${Date.now()}-${Math.random().toString(36).slice(2)}`,startedAt:Date.now(),appId:e?.appId??null};try{await t("setCaptureSession",{runId:E.testId,durationMs:18e5}),await t("scheduleLocal",{title:o,body:a,data:{...w,__buoyTestId:E.testId},seconds:Number(c)}),g(E)}catch(te){F(te instanceof Error?te.message:String(te))}finally{T.current=false,P(false)}}let C=j&&j.appId===e?.appId?e.events.filter(E=>E.testId===j.testId&&E.capturedAt>=j.startedAt):[],k=C.some(E=>E.kind==="received"),z=C.some(E=>E.kind==="response"||E.kind==="startup-response"),M=C.some(E=>E.kind==="app-outcome"),$=!!e?.capabilities.includes("local-scheduling");return K(nt,{title:o,message:a,onTitleChange:r,onMessageChange:l,appName:"This app",appearance:e?.preview,destination:me(f,{style:H.destination,children:[me(f,{style:H.field,children:[K(d,{style:H.label,children:"Device"}),K(d,{style:H.value,children:"This device"})]}),me(f,{style:H.field,children:[K(d,{style:H.label,children:"Delivery"}),K(d,{style:H.value,children:"Local notification"})]})]}),options:me(f,{style:H.options,children:[K(d,{style:H.label,children:"Send after"}),K(Vo,{tabs:[{key:"1",label:"1 second"},{key:"10",label:"10 seconds"}],activeKey:c,onChange:b,size:"sm",glass:true}),K(d,{style:H.label,children:"Custom data"}),K(se,{accessibilityLabel:"Notification custom data",value:u,onChangeText:p,multiline:true,autoCapitalize:"none",autoCorrect:false,style:H.json}),K(d,{style:H.label,children:"Use the delay to leave the app before delivery. Simulator push and raw APNs payloads are available on desktop."})]}),result:j?{title:M?"App reported an outcome":z?"Notification tapped":k?"Received by app":"Notification scheduled",message:z?"Open Activity to inspect the app\u2019s response.":"Tap the notification to test what opens."}:null,onViewActivity:i,onSend:()=>{x()},busy:R,disabled:!$||!!m,error:J??m,hint:$?c==="10"?"You have 10 seconds to leave the app.":"Sends locally on this device after one second.":"Connect Expo notification capture to send a local test."})}var H=he.create({destination:{flexDirection:"row",gap:12},field:{flex:1,gap:7},label:{color:ae.color.textSecondary,fontSize:12,lineHeight:18},value:{color:ae.color.text,fontSize:13,borderWidth:1,borderColor:ae.color.glassBorder,backgroundColor:ae.color.glass,borderRadius:10,padding:11},options:{gap:12},json:{color:ae.color.text,fontSize:12,minHeight:100,textAlignVertical:"top",padding:12,borderWidth:1,borderColor:ae.color.glassBorder,borderRadius:10}});import{monoFont as pe,night as v}from"@buoy-gg/shared-ui/web";var s=he.create({root:{flex:1,minHeight:0,backgroundColor:"transparent"},fill:{flex:1,minHeight:0},inlineHeader:{paddingHorizontal:12,paddingVertical:8,borderBottomWidth:1,borderBottomColor:v.color.separator},status:{flexDirection:"row",alignItems:"center",flexWrap:"wrap",gap:12,paddingHorizontal:16,paddingVertical:9},statusLabel:{flexDirection:"row",alignItems:"center",gap:6},dot:{width:5,height:5,borderRadius:3,backgroundColor:v.color.textTertiary},liveDot:{backgroundColor:v.color.accent},caption:{color:v.color.textSecondary,fontSize:12,lineHeight:17},provider:{color:v.color.textSecondary,fontSize:11,marginLeft:"auto",fontFamily:pe},content:{padding:14,gap:20},eventList:{paddingHorizontal:12,paddingTop:2},searchRow:{flexDirection:"row",gap:8,paddingHorizontal:12,paddingBottom:10,alignItems:"center"},searchField:{flex:1,minWidth:0,height:36,flexDirection:"row",alignItems:"center",gap:8,paddingHorizontal:10,backgroundColor:v.color.glass,borderWidth:1,borderColor:v.color.glassBorder,borderRadius:v.radius.row},searchInput:{flex:1,minWidth:0,height:"100%",color:v.color.text,fontSize:13,padding:0},clearSearch:{padding:6},iconButton:{width:34,height:34,alignItems:"center",justifyContent:"center",backgroundColor:v.color.buttonSurface,borderRadius:8,borderWidth:1,borderColor:v.color.border},event:{backgroundColor:v.color.glass,borderRadius:v.radius.input,borderWidth:1,borderColor:v.color.glassBorder,paddingHorizontal:12,paddingVertical:10,marginBottom:6,gap:6},eventTop:{flexDirection:"row",alignItems:"center",gap:10,justifyContent:"space-between"},eventKind:{flexDirection:"row",alignItems:"center",gap:6,flex:1,minWidth:0},eventLabel:{flexShrink:1,fontSize:11,fontWeight:"600"},timestamp:{color:v.color.textSecondary,fontFamily:pe,fontSize:10},eventSubject:{flexDirection:"row",alignItems:"center",gap:8},eventTitle:{flex:1,color:v.color.text,fontSize:15,fontWeight:"500"},eventMeta:{color:v.color.textSecondary,fontFamily:pe,fontSize:10,lineHeight:15},resultCount:{color:v.color.textSecondary,fontSize:12,marginBottom:10,marginLeft:4},actionRow:{flexDirection:"row",alignItems:"center",flexWrap:"wrap",gap:8},button:{flexDirection:"row",alignItems:"center",justifyContent:"center",gap:6,minHeight:34,paddingVertical:8,paddingHorizontal:14,borderRadius:v.radius.pill,backgroundColor:v.color.fillSecondary,alignSelf:"flex-start"},buttonText:{color:v.color.accent,fontSize:13,fontWeight:"600"},primaryButton:{backgroundColor:v.color.accent},primaryButtonText:{color:v.color.onAccent},pressed:{opacity:.7},disabled:{opacity:.4},detailTitle:{color:v.color.text,fontSize:20,fontWeight:"600"},field:{flexDirection:"row",paddingHorizontal:16,paddingVertical:12,gap:14},fieldLabel:{width:110,flexShrink:0},value:{flex:1,minWidth:0,color:v.color.text,fontFamily:pe,fontSize:12,lineHeight:18},disclosure:{flexDirection:"row",alignItems:"center",justifyContent:"space-between",paddingHorizontal:16,paddingVertical:14},disclosureTitle:{color:v.color.text,fontSize:13,fontWeight:"500"},jsonBody:{padding:10,borderTopWidth:1,borderTopColor:v.color.separator},token:{color:v.color.text,fontFamily:pe,fontSize:12,lineHeight:20},bodyText:{color:v.color.text,fontSize:14,lineHeight:21},footnote:{color:v.color.textSecondary,fontSize:12,lineHeight:18,marginTop:8,marginHorizontal:4},emptyFootnote:{color:v.color.textSecondary,fontSize:12,lineHeight:18,textAlign:"center",marginHorizontal:28},sectionActions:{flexDirection:"row",marginBottom:10},warning:{color:v.color.warning,fontSize:12,lineHeight:18},notice:{color:v.color.accent,backgroundColor:v.color.glass,paddingHorizontal:16,paddingVertical:10,fontSize:12,lineHeight:18},errorNotice:{color:v.color.danger,backgroundColor:v.color.glass,paddingHorizontal:16,paddingVertical:10,fontSize:12,lineHeight:18},errorText:{color:v.color.danger}});import{Fragment as ze,jsx as n,jsxs as h}from"react/jsx-runtime";var Le={received:"App received",response:"Notification response","startup-response":"Response recovered at startup","presentation-decision":"Presentation decision","presentation-error":"Presentation error","background-started":"Background task started","background-completed":"Background task completed","background-error":"Background task failed","app-outcome":"App outcome","local-scheduled":"Local notification scheduled"};function at(e){return e.includes("error")?"danger":e==="startup-response"?"warning":e==="received"||e==="app-outcome"?"accent":"neutral"}function W({label:e,onPress:t,disabled:i,primary:o,icon:r}){return h(_,{accessibilityRole:"button",accessibilityLabel:e,accessibilityState:{disabled:!!i},disabled:i,onPress:t,style:({pressed:a})=>[s.button,o&&s.primaryButton,a&&s.pressed,i&&s.disabled],children:[r,n(d,{style:[s.buttonText,o&&s.primaryButtonText],children:e})]})}function ee({label:e,value:t}){return h(f,{style:s.field,children:[n(d,{style:[s.caption,s.fieldLabel],children:e}),n(d,{selectable:true,style:s.value,children:t})]})}function ve({title:e,value:t,initiallyOpen:i=true}){let[o,r]=Z(i),a=JSON.stringify(t??null),l=Qe(()=>JSON.parse(a),[a]);return h(U,{glass:true,children:[h(_,{accessibilityRole:"button",accessibilityLabel:e,accessibilityState:{expanded:o},onPress:()=>r(u=>!u),style:s.disclosure,children:[n(d,{style:s.disclosureTitle,children:e}),o?n(Co,{size:14,color:D.color.textSecondary}):n(et,{size:14,color:D.color.textSecondary})]}),o&&n(f,{style:s.jsonBody,children:n(Bo,{title:"",data:l,rawMode:true,initialExpanded:true,showTypeFilter:false})})]})}function st({snapshot:e,onAction:t,sender:i,activeTab:o,onTabChange:r,renderShell:a}){let[l,u]=Z("send"),p=o??l,[c,b]=Z(""),[R,P]=Z(null),[T,J]=Z(false),[F,j]=Z(null),[,g]=Z(0),w=jo({minBottom:16}),m=e?.session?.expiresAt;ko(()=>{if(!m||m<=Date.now())return;let S=setTimeout(()=>g(q=>q+1),m-Date.now()+1);return()=>clearTimeout(S)},[m]);let x=!!m&&m>Date.now(),C=Qe(()=>(e?.events??[]).filter(S=>JSON.stringify(S).toLowerCase().includes(c.trim().toLowerCase())).slice().reverse(),[e?.events,c]),k=e?.events.find(S=>S.id===R),z=e?.events.length??0,M=!!e?.provider;function $(S){u(S),r?.(S),j(null)}async function E(S,q){if(T)return false;J(true),j(null);try{return await t(S,q),true}catch(we){return j({text:we instanceof Error?we.message:String(we),error:true}),false}finally{J(false)}}let te=()=>{E("setCaptureSession",{runId:`capture-${Date.now()}`,durationMs:18e5})},je=()=>{E("setCaptureSession",{runId:null})};async function Be(S){let q=await Do(S);j({text:q?"Copied to clipboard.":"Clipboard is unavailable. Select the text to copy it.",error:!q})}let dt=[{key:"send",label:"Test"},{key:"events",label:`Activity (${z})`}],Oe=h(Ee,{children:[n(Ee.Content,{title:"",noMargin:true,children:n(No,{tabs:dt,activeKey:p,onChange:$,size:"sm",glass:true})}),h(Ee.Actions,{children:[n(_,{accessibilityRole:"button",accessibilityLabel:"Notification settings",onPress:()=>$(p==="setup"||p==="tokens"?"send":"setup"),style:s.iconButton,children:n(Ro,{size:16,color:p==="setup"||p==="tokens"?D.color.accent:D.color.textSecondary})}),p!=="send"&&n(Po,{isEnabled:x,onToggle:x?je:te,disabled:!M||T,accessibilityLabel:x?"Stop notification capture":"Start notification capture",testID:"notifications-capture"})]})]}),Ve=h(f,{style:s.root,children:[M&&p!=="send"&&h(f,{style:s.status,children:[h(f,{style:s.statusLabel,children:[n(f,{style:[s.dot,x&&s.liveDot]}),n(d,{style:s.caption,children:x?"Recording":"Capture stopped"})]}),p!=="events"&&n(d,{style:s.caption,children:e.durable?"Persistent history":"Memory only"}),p!=="events"&&h(d,{style:s.provider,children:[e.provider," \xB7 ",e.platform]})]}),e?.storageError&&h(d,{accessibilityRole:"alert",style:s.errorNotice,children:["Storage: ",e.storageError]}),F&&n(d,{accessibilityRole:F.error?"alert":"text",style:[s.notice,F.error&&s.errorText],children:F.text}),!i&&n(f,{style:p==="send"?s.fill:{display:"none"},children:n(Jo,{snapshot:e,onAction:t,onViewActivity:()=>$("events")})}),p==="send"?i??null:M?h(ze,{children:[p==="events"&&h(ze,{children:[h(f,{style:s.searchRow,children:[h(f,{style:s.searchField,children:[n(Eo,{size:14,color:D.color.textSecondary}),n(se,{accessibilityLabel:"Filter notification events",placeholder:"Search notifications\u2026",placeholderTextColor:D.color.placeholder,value:c,onChangeText:S=>{b(S),P(null)},autoCapitalize:"none",autoCorrect:false,style:s.searchInput}),!!c&&n(_,{accessibilityRole:"button",accessibilityLabel:"Clear notification search",onPress:()=>b(""),style:s.clearSearch,children:n(Lo,{size:12,color:D.color.textSecondary})})]}),n(_,{accessibilityRole:"button",accessibilityLabel:"Clear captured events",disabled:T||!z,accessibilityState:{disabled:T||!z},style:[s.iconButton,(T||!z)&&s.disabled],onPress:()=>{E("clearCapturedEvents").then(S=>{S&&P(null)})},children:n(zo,{size:14,color:D.color.textSecondary})})]}),k?h(oe,{style:s.fill,contentContainerStyle:[s.content,{paddingBottom:w.bottom}],keyboardShouldPersistTaps:"handled",children:[h(f,{style:s.actionRow,children:[n(W,{label:"Back to events",onPress:()=>P(null),icon:n(To,{size:14,color:D.color.accent})}),n(W,{label:"Copy event JSON",onPress:()=>{Be(k)},icon:n(tt,{size:14,color:D.color.accent})})]}),h(U,{glass:true,padded:true,children:[n(be,{label:Le[k.kind]??k.kind,tone:at(k.kind)}),n(d,{style:s.detailTitle,children:k.title??"Notification event"}),n(d,{style:s.caption,children:new Date(k.capturedAt).toLocaleString()})]}),h(f,{children:[n(G,{children:"Observation"}),n(U,{glass:true,children:h(ot,{children:[n(ee,{label:"App state at callback",value:k.observedAppState}),k.testId&&n(ee,{label:"Test ID",value:k.testId}),k.notificationId&&n(ee,{label:"Notification ID",value:k.notificationId}),k.actionIdentifier&&n(ee,{label:"Action",value:k.actionIdentifier})]})})]}),k.kind==="startup-response"&&n(d,{style:s.footnote,children:"Recovered from the SDK cache. This alone does not establish why the app launched."}),k.truncated&&n(d,{style:s.warning,children:"This payload was truncated when captured."}),n(ve,{title:"Payload",value:k.raw}),n(ve,{title:"Full event",value:k,initiallyOpen:false})]}):n(_e,{data:C,keyExtractor:S=>S.id,style:s.fill,contentContainerStyle:[s.eventList,{paddingBottom:w.bottom}],keyboardShouldPersistTaps:"handled",initialNumToRender:15,ListHeaderComponent:c?h(d,{style:s.resultCount,children:[C.length," of ",z," events"]}):null,ListFooterComponent:e.evicted>0?h(d,{style:s.footnote,children:[e.evicted," older records removed by the history limit."]}):null,ListEmptyComponent:n(Re,{otto:c?"sad":x?"listening":"paused",title:c?"No matching events":x?"Waiting for notifications":"Capture is stopped",message:c?"Try another title, test ID, or payload value.":x?"Send a notification from Buoy Desktop or your app. Background alerts can reach the system tray before an app callback runs.":"Start capture with the power button, then send a notification."}),renderItem:({item:S})=>n($o,{event:S,onPress:()=>P(S.id)})})]}),p==="tokens"&&h(oe,{style:s.fill,contentContainerStyle:[s.content,{paddingBottom:w.bottom}],keyboardShouldPersistTaps:"handled",children:[h(f,{children:[n(W,{label:"Back to settings",onPress:()=>$("setup")}),n(G,{children:"Registration"}),h(U,{glass:true,padded:true,children:[n(d,{style:s.bodyText,children:"Register a token to test delivery through your push provider."}),h(f,{style:s.actionRow,children:[n(W,{label:"Register device token",onPress:()=>{E("refreshToken",{type:"device"})},disabled:T,primary:true}),n(W,{label:"Register Expo token",onPress:()=>{E("refreshToken",{type:"expo"})},disabled:T||!e.capabilities.includes("expo-token")})]})]}),n(d,{style:s.footnote,children:"Registration runs only when you or your app request it. Simulator sends work without a token."})]}),e.tokens.length===0?n(Re,{otto:"listening",title:"No tokens observed",message:"Register a device token above, or let your app register one."}):e.tokens.map((S,q)=>h(f,{children:[n(G,{children:S.type.toUpperCase()+" token"}),h(U,{glass:true,padded:true,children:[h(f,{style:s.actionRow,children:[n(be,{label:S.type,tone:"accent"}),S.environment&&n(d,{style:s.caption,children:S.environment})]}),n(d,{selectable:true,style:s.token,children:S.value}),S.projectId&&h(d,{selectable:true,style:s.caption,children:["Project: ",S.projectId]}),h(d,{style:s.caption,children:["Observed ",new Date(S.observedAt).toLocaleString()]}),n(f,{style:s.actionRow,children:n(W,{label:"Copy "+S.type.toUpperCase()+" token",onPress:()=>{Be(S.value)},icon:n(tt,{size:14,color:D.color.accent})})})]})]},S.type+"-"+q))]}),p==="setup"&&h(oe,{style:s.fill,contentContainerStyle:[s.content,{paddingBottom:w.bottom}],keyboardShouldPersistTaps:"handled",children:[h(f,{children:[n(W,{label:"Device tokens",onPress:()=>$("tokens")}),n(G,{children:"Capture session"}),h(U,{glass:true,padded:true,children:[h(f,{style:s.actionRow,children:[n(be,{label:x?"Recording":"Stopped",tone:x?"accent":"neutral"}),n(d,{style:s.caption,children:x?"Until "+new Date(m).toLocaleTimeString():"Ready when you are"})]}),h(f,{style:s.actionRow,children:[n(W,{label:"Arm capture for 30 minutes",onPress:te,disabled:T,primary:true}),n(W,{label:"Stop capture",onPress:je,disabled:T||!x})]})]}),n(d,{style:s.footnote,children:e.durable?"History is saved on the app and survives app and desktop restarts.":"History is held in memory. Keep the app running to retain it."})]}),h(f,{children:[n(G,{children:"Connected app"}),n(U,{glass:true,children:h(ot,{children:[n(ee,{label:"App",value:e.appId??"Not supplied"}),n(ee,{label:"Provider",value:[e.provider,e.providerVersion].filter(Boolean).join(" ")}),n(ee,{label:"Platform",value:e.platform})]})})]}),h(f,{children:[n(G,{children:"Permissions"}),n(f,{style:s.sectionActions,children:n(W,{label:"Refresh permissions",disabled:T,onPress:()=>{E("getPermissions")}})}),n(ve,{title:"Permission settings",value:e.permissions})]}),h(f,{children:[n(G,{children:"System tray"}),n(f,{style:s.sectionActions,children:n(W,{label:"Inspect system tray",disabled:T||!e.capabilities.includes("presented"),onPress:()=>{E("listPresented")}})}),n(ve,{title:"Currently presented",value:e.presented}),n(d,{style:s.footnote,children:"Notifications currently in the system tray. Captured history is in Activity."})]}),h(f,{children:[n(G,{children:"Capabilities"}),n(U,{glass:true,padded:true,children:n(f,{style:s.actionRow,children:e.capabilities.map(S=>n(be,{label:S},S))})})]})]})]}):h(oe,{children:[n(Re,{otto:"paused",title:"Connect notification capture",message:"Install @buoy-gg/notifications and call installExpoNotificationCapture in the app entry point. Use an app-specific development build for remote notifications."}),n(d,{style:s.emptyFootnote,children:"The desktop sender works with any installed app. Inspection needs the capture integration."})]})]});return n(ze,{children:a?a({header:Oe,body:Ve}):h(f,{style:s.root,children:[n(f,{style:s.inlineHeader,children:Oe}),Ve]})})}function $o({event:e,onPress:t}){let i=at(e.kind),o=i==="danger"?D.color.danger:i==="warning"?D.color.warning:i==="accent"?D.color.accent:D.color.textSecondary;return h(_,{accessibilityRole:"button",accessibilityLabel:(Le[e.kind]??e.kind)+": "+(e.title??e.testId??e.notificationId??"notification"),onPress:t,style:({pressed:r})=>[s.event,r&&s.pressed],children:[h(f,{style:s.eventTop,children:[h(f,{style:s.eventKind,children:[n(Ao,{size:13,color:o}),n(d,{numberOfLines:1,style:[s.eventLabel,{color:o}],children:Le[e.kind]??e.kind})]}),n(d,{style:s.timestamp,children:new Date(e.capturedAt).toLocaleTimeString()})]}),h(f,{style:s.eventSubject,children:[n(d,{numberOfLines:1,style:s.eventTitle,children:e.title??e.testId??e.notificationId??"Notification event"}),n(et,{size:14,color:D.color.textTertiary})]}),h(d,{numberOfLines:1,style:s.eventMeta,children:[e.observedAppState,e.truncated?" \xB7 Truncated":""]})]})}import{useSyncExternalStore as qo}from"react";import{createToolFactory as Uo,defineToolPreset as Go,JsModal as Xo,NotificationsIcon as Yo}from"@buoy-gg/shared-ui/web";import{jsx as De}from"react/jsx-runtime";function lt(e){let t=qo(ne.subscribe,ne.getSnapshot);return De(st,{snapshot:t,renderShell:({header:i,body:o})=>De(Xo,{...e,persistenceKey:e.persistenceKey??"buoy-notifications",variant:"night",header:{showToggleButton:true,customContent:i},enablePersistence:true,initialMode:"bottomSheet",disableScrollWrapper:true,children:o}),onAction:async(i,o)=>{let r=ne.actions[i];if(!r)throw new Error("This notification action is unavailable.");return r(o)}})}var ct=Go({id:"push-notifications",name:"NOTIFICATIONS",description:"Send a test notification and inspect how the app responds",slot:"both",icon:({size:e,color:t})=>De(Yo,{size:e,color:t}),component:lt}),Zo=Uo(ct);import{NotificationsIcon as Qo}from"@buoy-gg/shared-ui/web";function ei(e){let t={...e.data,__buoyTestId:e.testId},i=e.silent?{"content-available":1}:{alert:{title:e.title,body:e.body},sound:"default"};return JSON.stringify(e.adapter==="expo"?{aps:i,body:t}:{...t,aps:i},null,2)}function ti(e){let t=[],i=[];if(typeof e!="string")return{valid:false,bytes:0,errors:["Provide the APNs payload as JSON text."],warnings:i,testId:null};let o=ie(e);o>4096&&t.push(`Payload is ${o} bytes. APNs payloads must fit in 4096 UTF-8 bytes.`);let r;try{r=JSON.parse(e)}catch{t.push("Payload is not valid JSON.")}let a=y(r);(!r||typeof r!="object"||Array.isArray(r))&&t.push("The payload must be a JSON object."),(!a.aps||typeof a.aps!="object"||Array.isArray(a.aps))&&t.push('The payload needs an "aps" object.');let l=y(a.aps);l.alert!==void 0&&typeof l.alert!="string"&&(l.alert===null||typeof l.alert!="object"||Array.isArray(l.alert))&&t.push("aps.alert must be text or an object."),l.badge!==void 0&&(!Number.isInteger(l.badge)||Number(l.badge)<0)&&t.push("aps.badge must be a non-negative integer.");for(let p of["content-available","mutable-content"])l[p]!==void 0&&l[p]!==1&&t.push(`aps.${p} must be 1 when present.`);l["content-available"]===1&&i.push("Background execution depends on app configuration and OS scheduling. A successful send does not prove the task ran."),l["mutable-content"]===1&&i.push("Use real APNs delivery to verify notification service extensions."),a.data!==void 0&&a.body===void 0&&i.push("Expo on iOS reads custom data from a top-level body object. This raw payload will be sent unchanged.");let u=y(a.body).__buoyTestId??a.__buoyTestId;return{valid:t.length===0,bytes:o,errors:t,warnings:i,testId:typeof u=="string"?u:null}}var oi=(()=>{try{return globalThis.Capacitor?.isNativePlatform?.()===true}catch{return false}})();oi&&typeof ue<"u"&&ue&&Ye();export{Te as NotificationRecorder,nt as NotificationTestView,st as NotificationToolView,Qo as NotificationsIcon,lt as NotificationsModal,Ue as attachCapacitorNotifications,qe as attachExpoNotifications,ye as capacitorMetadata,ei as composeSimulatorPayload,fo as createExpoNotificationStorage,Zo as createNotificationTool,X as expoMetadata,Pe as getNotificationRecorder,Ye as installCapacitorNotificationCapture,xo as installExpoNotificationCapture,wo as instrumentExpoNotificationHandler,Io as instrumentNotificationBackgroundTask,ne as notificationSyncAdapter,ct as notificationToolPreset,ti as validateSimulatorPayload};
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@buoy-gg/notifications",
|
|
3
|
-
"version": "7.0.
|
|
3
|
+
"version": "7.0.57",
|
|
4
4
|
"description": "Send simulator notifications and inspect app receipt, interactions and device tokens.",
|
|
5
5
|
"main": "lib/commonjs/index.js",
|
|
6
6
|
"module": "lib/module/index.js",
|
|
@@ -10,18 +10,25 @@
|
|
|
10
10
|
"files": [
|
|
11
11
|
"lib"
|
|
12
12
|
],
|
|
13
|
-
"sideEffects":
|
|
13
|
+
"sideEffects": [
|
|
14
|
+
"./src/index.ts",
|
|
15
|
+
"./lib/commonjs/index.js",
|
|
16
|
+
"./lib/module/index.js",
|
|
17
|
+
"./lib/web/**/*.mjs"
|
|
18
|
+
],
|
|
14
19
|
"dependencies": {
|
|
15
|
-
"@buoy-gg/shared-ui": "^7.0.
|
|
20
|
+
"@buoy-gg/shared-ui": "^7.0.57"
|
|
16
21
|
},
|
|
17
22
|
"peerDependencies": {
|
|
23
|
+
"@buoy-gg/license": "7.0.57",
|
|
18
24
|
"react": "*",
|
|
19
25
|
"react-native": "*"
|
|
20
26
|
},
|
|
21
27
|
"devDependencies": {
|
|
22
28
|
"@types/react": "^19.1.0",
|
|
23
29
|
"@types/react-native": "^0.73.0",
|
|
24
|
-
"typescript": "~5.8.3"
|
|
30
|
+
"typescript": "~5.8.3",
|
|
31
|
+
"@buoy-gg/license": "^7.0.57"
|
|
25
32
|
},
|
|
26
33
|
"react-native-builder-bob": {
|
|
27
34
|
"source": "src",
|
|
@@ -56,8 +63,29 @@
|
|
|
56
63
|
"notifications",
|
|
57
64
|
"devtools"
|
|
58
65
|
],
|
|
66
|
+
"exports": {
|
|
67
|
+
".": {
|
|
68
|
+
"browser": {
|
|
69
|
+
"types": "./lib/typescript/index.d.ts",
|
|
70
|
+
"default": "./lib/web/index.mjs"
|
|
71
|
+
},
|
|
72
|
+
"import": {
|
|
73
|
+
"types": "./lib/typescript/index.d.ts",
|
|
74
|
+
"default": "./lib/module/index.js"
|
|
75
|
+
},
|
|
76
|
+
"require": {
|
|
77
|
+
"types": "./lib/typescript/index.d.ts",
|
|
78
|
+
"default": "./lib/commonjs/index.js"
|
|
79
|
+
}
|
|
80
|
+
},
|
|
81
|
+
"./web": {
|
|
82
|
+
"types": "./lib/typescript/index.d.ts",
|
|
83
|
+
"default": "./lib/web/index.mjs"
|
|
84
|
+
}
|
|
85
|
+
},
|
|
59
86
|
"scripts": {
|
|
60
|
-
"build": "bob build",
|
|
87
|
+
"build": "bob build && pnpm run build:web",
|
|
88
|
+
"build:web": "node ../../scripts/build-web.mjs notifications",
|
|
61
89
|
"typecheck": "tsc --noEmit",
|
|
62
90
|
"clean": "rimraf lib",
|
|
63
91
|
"test": "pnpm run typecheck",
|