notification-kit
Version:
A unified notification library for React + Capacitor apps. One API for push notifications, in-app notifications, and local notifications across Web, iOS, and Android.
1,766 lines (1,765 loc) • 90.5 kB
JavaScript
class Logger {
static isDebugEnabled = false;
static enableDebug() {
Logger.isDebugEnabled = true;
}
static disableDebug() {
Logger.isDebugEnabled = false;
}
static debug(...args) {
if (Logger.isDebugEnabled && typeof console !== "undefined") {
console.log("[notification-kit]", ...args);
}
}
static info(...args) {
if (typeof console !== "undefined") {
console.info("[notification-kit]", ...args);
}
}
static warn(...args) {
if (typeof console !== "undefined") {
console.warn("[notification-kit]", ...args);
}
}
static error(...args) {
if (typeof console !== "undefined") {
console.error("[notification-kit]", ...args);
}
}
}
class DynamicLoader {
static loadedModules = /* @__PURE__ */ new Map();
static loadingPromises = /* @__PURE__ */ new Map();
/**
* Check if Capacitor is available
*/
static isCapacitorAvailable() {
try {
return typeof window !== "undefined" && "Capacitor" in window;
} catch {
return false;
}
}
/**
* Load Capacitor Core dynamically
*/
static async loadCapacitorCore() {
const cacheKey = "@capacitor/core";
if (this.loadedModules.has(cacheKey)) {
return this.loadedModules.get(cacheKey);
}
if (this.loadingPromises.has(cacheKey)) {
return this.loadingPromises.get(cacheKey);
}
const loadPromise = (async () => {
try {
if (!this.isCapacitorAvailable()) {
return null;
}
const module = await import("@capacitor/core");
this.loadedModules.set(cacheKey, module);
return module;
} catch (error) {
Logger.warn("Capacitor Core not available. Some features may be limited.");
return null;
}
})();
this.loadingPromises.set(cacheKey, loadPromise);
return loadPromise;
}
/**
* Load Capacitor Push Notifications
*/
static async loadPushNotifications() {
const cacheKey = "@capacitor/push-notifications";
if (this.loadedModules.has(cacheKey)) {
return this.loadedModules.get(cacheKey);
}
if (this.loadingPromises.has(cacheKey)) {
return this.loadingPromises.get(cacheKey);
}
const loadPromise = (async () => {
try {
const module = await import("@capacitor/push-notifications");
this.loadedModules.set(cacheKey, module);
return module;
} catch (error) {
throw new Error(
"Push notifications require @capacitor/push-notifications. Please install it: yarn add @capacitor/push-notifications"
);
}
})();
this.loadingPromises.set(cacheKey, loadPromise);
return loadPromise;
}
/**
* Load Capacitor Local Notifications
*/
static async loadLocalNotifications() {
const cacheKey = "@capacitor/local-notifications";
if (this.loadedModules.has(cacheKey)) {
return this.loadedModules.get(cacheKey);
}
if (this.loadingPromises.has(cacheKey)) {
return this.loadingPromises.get(cacheKey);
}
const loadPromise = (async () => {
try {
const module = await import("@capacitor/local-notifications");
this.loadedModules.set(cacheKey, module);
return module;
} catch (error) {
throw new Error(
"Local notifications require @capacitor/local-notifications. Please install it: yarn add @capacitor/local-notifications"
);
}
})();
this.loadingPromises.set(cacheKey, loadPromise);
return loadPromise;
}
/**
* Load Capacitor Preferences
*/
static async loadPreferences() {
const cacheKey = "@capacitor/preferences";
if (this.loadedModules.has(cacheKey)) {
return this.loadedModules.get(cacheKey);
}
if (this.loadingPromises.has(cacheKey)) {
return this.loadingPromises.get(cacheKey);
}
const loadPromise = (async () => {
try {
const module = await import("@capacitor/preferences");
this.loadedModules.set(cacheKey, module);
return module;
} catch (error) {
return null;
}
})();
this.loadingPromises.set(cacheKey, loadPromise);
return loadPromise;
}
/**
* Load Firebase
*/
static async loadFirebase() {
const cacheKey = "firebase/app";
if (this.loadedModules.has(cacheKey)) {
return this.loadedModules.get(cacheKey);
}
if (this.loadingPromises.has(cacheKey)) {
return this.loadingPromises.get(cacheKey);
}
const loadPromise = (async () => {
try {
const module = await import("firebase/app");
this.loadedModules.set(cacheKey, module);
return module;
} catch (error) {
throw new Error(
"Firebase provider requires firebase. Please install it: yarn add firebase"
);
}
})();
this.loadingPromises.set(cacheKey, loadPromise);
return loadPromise;
}
/**
* Load Firebase Messaging
*/
static async loadFirebaseMessaging() {
const cacheKey = "firebase/messaging";
if (this.loadedModules.has(cacheKey)) {
return this.loadedModules.get(cacheKey);
}
if (this.loadingPromises.has(cacheKey)) {
return this.loadingPromises.get(cacheKey);
}
const loadPromise = (async () => {
try {
const module = await import("firebase/messaging");
this.loadedModules.set(cacheKey, module);
return module;
} catch (error) {
throw new Error(
"Firebase messaging requires firebase. Please install it: yarn add firebase"
);
}
})();
this.loadingPromises.set(cacheKey, loadPromise);
return loadPromise;
}
/**
* Load OneSignal
*/
static async loadOneSignal() {
const cacheKey = "react-onesignal";
if (this.loadedModules.has(cacheKey)) {
return this.loadedModules.get(cacheKey);
}
if (this.loadingPromises.has(cacheKey)) {
return this.loadingPromises.get(cacheKey);
}
const loadPromise = (async () => {
try {
const module = await import("react-onesignal");
this.loadedModules.set(cacheKey, module);
return module;
} catch (error) {
throw new Error(
"OneSignal provider requires react-onesignal. Please install it: yarn add react-onesignal"
);
}
})();
this.loadingPromises.set(cacheKey, loadPromise);
return loadPromise;
}
/**
* Get current platform without Capacitor
*/
static async getPlatform() {
const capacitor = await this.loadCapacitorCore();
if (capacitor && capacitor.Capacitor.isNativePlatform()) {
return capacitor.Capacitor.getPlatform();
} else if (typeof window !== "undefined") {
if (window.navigator.userAgent.includes("Electron")) {
return "electron";
}
return "web";
} else {
return "unknown";
}
}
/**
* Check if platform is native
*/
static async isNativePlatform() {
const capacitor = await this.loadCapacitorCore();
return capacitor ? capacitor.Capacitor.isNativePlatform() : false;
}
/**
* Clear module cache
*/
static clearCache() {
this.loadedModules.clear();
this.loadingPromises.clear();
}
}
function toCapacitorImportance(importance) {
const map = {
1: 1,
2: 2,
3: 3,
4: 4,
5: 5
};
return map[importance] || 3;
}
function fromCapacitorImportance(importance) {
const map = {
1: 1,
2: 2,
3: 3,
4: 4,
5: 5
};
return map[importance] || 3;
}
function toCapacitorChannel(channel) {
const capacitorChannel = {
id: channel.id,
name: channel.name,
description: channel.description ?? "",
importance: channel.importance ? toCapacitorImportance(channel.importance) : void 0,
visibility: channel.visibility
// Capacitor uses similar values
};
if (channel.sound !== void 0) {
capacitorChannel.sound = channel.sound;
}
if (channel.vibration !== void 0) {
capacitorChannel.vibration = channel.vibration;
}
if (channel.lights !== void 0) {
capacitorChannel.lights = channel.lights;
}
return capacitorChannel;
}
function fromCapacitorChannel(channel) {
const notificationChannel = {
id: channel.id,
name: channel.name,
description: channel.description ?? "",
importance: channel.importance ? fromCapacitorImportance(channel.importance) : "default",
visibility: channel.visibility
};
if (channel.sound !== void 0) {
notificationChannel.sound = channel.sound;
}
if (channel.vibration !== void 0) {
notificationChannel.vibration = channel.vibration;
}
if (channel.lights !== void 0) {
notificationChannel.lights = channel.lights;
}
return notificationChannel;
}
function toCapacitorLocalNotification(options) {
const notification = {
id: typeof options.id === "string" ? parseInt(options.id, 10) : options.id || Date.now(),
title: options.title || "",
body: options.body || "",
largeBody: options.body
};
if (options.summaryText !== void 0) {
notification.summaryText = options.summaryText;
}
if (options.at) {
notification.schedule = { at: options.at };
}
if (options.sound !== void 0) {
notification.sound = options.sound;
}
if (options.smallIcon !== void 0) {
notification.smallIcon = options.smallIcon;
}
if (options.largeIcon !== void 0) {
notification.largeIcon = options.largeIcon;
}
if (options.color !== void 0) {
notification.iconColor = options.color;
}
if (options.channelId !== void 0) {
notification.channelId = options.channelId;
}
if (options.ongoing !== void 0) {
notification.ongoing = options.ongoing;
}
if (options.autoCancel !== void 0) {
notification.autoCancel = options.autoCancel;
}
if (options.group !== void 0) {
notification.group = options.group;
}
if (options.groupSummary !== void 0) {
notification.groupSummary = options.groupSummary;
}
if (options.extra || options.data) {
notification.extra = options.extra || options.data;
}
return notification;
}
function fromCapacitorLocalNotification(notification) {
const payload = {
id: notification.id.toString(),
title: notification.title,
body: notification.body
};
if (notification.summaryText !== void 0) {
payload.summaryText = notification.summaryText;
}
if (notification.sound !== void 0) {
payload.sound = notification.sound;
}
if (notification.smallIcon !== void 0) {
payload.smallIcon = notification.smallIcon;
}
if (notification.largeIcon !== void 0) {
payload.largeIcon = notification.largeIcon;
}
if (notification.iconColor !== void 0) {
payload.color = notification.iconColor;
}
if (notification.channelId !== void 0) {
payload.channelId = notification.channelId;
}
if (notification.ongoing !== void 0) {
payload.ongoing = notification.ongoing;
}
if (notification.autoCancel !== void 0) {
payload.autoCancel = notification.autoCancel;
}
if (notification.group !== void 0) {
payload.group = notification.group;
}
if (notification.groupSummary !== void 0) {
payload.groupSummary = notification.groupSummary;
}
if (notification.extra !== void 0) {
payload.extra = notification.extra;
payload.data = notification.extra;
}
return payload;
}
function toPlatformCapabilities(providerCaps) {
return {
pushNotifications: providerCaps.pushNotifications || false,
localNotifications: true,
// Always true if Capacitor is available
inAppNotifications: true,
// Always true
notificationChannels: providerCaps.channels || false,
notificationActions: providerCaps.actions || false,
notificationBadging: providerCaps.badges || false,
notificationSound: providerCaps.sounds || false,
notificationVibration: providerCaps.vibration || false,
notificationLights: providerCaps.lights || false,
notificationGrouping: providerCaps.groups || false,
notificationImportance: providerCaps.channels || false,
notificationVisibility: providerCaps.channels || false,
notificationLockScreen: providerCaps.channels || false,
notificationFullScreen: false,
notificationHeadsUp: providerCaps.channels || false,
notificationOngoing: providerCaps.channels || false,
notificationProgress: providerCaps.progress || false,
notificationBigText: providerCaps.bigText || false,
notificationBigPicture: providerCaps.bigPicture || false,
notificationInbox: providerCaps.inbox || false,
notificationMedia: providerCaps.richMedia || false,
notificationCustom: providerCaps.customData || false,
notificationScheduling: providerCaps.scheduling || false,
notificationGeofencing: providerCaps.geofencing || false,
notificationTriggers: providerCaps.triggers || false,
serviceWorker: providerCaps.webPush || false,
webPushProtocol: providerCaps.webPush || false,
backgroundSync: providerCaps.backgroundSync || false,
foregroundService: false,
criticalAlerts: false,
provisionalAuth: false,
appBadge: providerCaps.badges || false,
quietHours: providerCaps.quietHours || false,
doNotDisturb: false
};
}
class NotificationKit {
static instance = null;
provider = null;
config = null;
initialized = false;
eventListeners = /* @__PURE__ */ new Map();
platform = "unknown";
capabilities = null;
constructor() {
}
/**
* Get singleton instance
*/
static getInstance() {
if (!NotificationKit.instance) {
NotificationKit.instance = new NotificationKit();
}
return NotificationKit.instance;
}
/**
* Static init method for convenience
*/
static async init(config) {
return NotificationKit.getInstance().init(config);
}
/**
* Initialize notification kit with configuration
*/
async init(config) {
if (this.initialized) {
return;
}
try {
this.config = config;
await this.detectPlatform();
await this.initializeProvider();
await this.setupEventListeners();
this.initialized = true;
this.emit("ready", {
platform: this.platform,
capabilities: this.capabilities
});
} catch (error) {
this.emit("error", { error, context: "initialization" });
throw error;
}
}
/**
* Destroy notification kit instance
*/
async destroy() {
if (this.provider) {
await this.provider.destroy();
this.provider = null;
}
this.eventListeners.clear();
this.initialized = false;
this.config = null;
NotificationKit.instance = null;
}
/**
* Check if notification kit is initialized
*/
isInitialized() {
return this.initialized;
}
/**
* Get current platform
*/
getPlatform() {
return this.platform;
}
/**
* Get platform capabilities
*/
getCapabilities() {
return this.capabilities;
}
/**
* Get current provider
*/
getProvider() {
return this.provider;
}
/**
* Request notification permission
*/
async requestPermission() {
this.ensureInitialized();
try {
const granted = await this.provider.requestPermission();
this.emit("permissionChanged", {
granted,
status: granted ? "granted" : "denied"
});
return granted;
} catch (error) {
this.emit("error", { error, context: "permission" });
throw error;
}
}
/**
* Check notification permission status
*/
async checkPermission() {
this.ensureInitialized();
try {
return await this.provider.checkPermission();
} catch (error) {
this.emit("error", { error, context: "permission" });
throw error;
}
}
/**
* Get notification token
*/
async getToken() {
this.ensureInitialized();
try {
const token = await this.provider.getToken();
this.emit("tokenReceived", { token });
return token;
} catch (error) {
this.emit("error", { error, context: "token" });
throw error;
}
}
/**
* Subscribe to topic
*/
async subscribe(topic) {
this.ensureInitialized();
try {
await this.provider.subscribe(topic);
this.emit("subscribed", { topic });
} catch (error) {
this.emit("error", { error, context: "subscription" });
throw error;
}
}
/**
* Unsubscribe from topic
*/
async unsubscribe(topic) {
this.ensureInitialized();
try {
await this.provider.unsubscribe(topic);
this.emit("unsubscribed", { topic });
} catch (error) {
this.emit("error", { error, context: "subscription" });
throw error;
}
}
/**
* Send push notification
*/
async sendPushNotification(payload) {
this.ensureInitialized();
try {
await this.provider.sendNotification(payload);
this.emit("notificationSent", { payload, type: "push" });
} catch (error) {
this.emit("error", { error, context: "push" });
throw error;
}
}
/**
* Schedule local notification
*/
async scheduleLocalNotification(options) {
this.ensureInitialized();
try {
const localNotificationsModule = await DynamicLoader.loadLocalNotifications();
if (!localNotificationsModule) {
throw new Error("Local notifications are not available on this platform");
}
const { LocalNotifications } = localNotificationsModule;
const capacitorNotification = toCapacitorLocalNotification(options);
await LocalNotifications.schedule({
notifications: [capacitorNotification]
});
this.emit("notificationScheduled", { options, type: "local" });
} catch (error) {
this.emit("error", { error, context: "local" });
throw error;
}
}
/**
* Cancel local notification
*/
async cancelLocalNotification(id) {
this.ensureInitialized();
try {
const localNotificationsModule = await DynamicLoader.loadLocalNotifications();
if (!localNotificationsModule) {
throw new Error("Local notifications are not available on this platform");
}
const { LocalNotifications } = localNotificationsModule;
const numericId = typeof id === "string" ? parseInt(id, 10) : id;
await LocalNotifications.cancel({
notifications: [{ id: numericId }]
});
this.emit("notificationCancelled", { id, type: "local" });
} catch (error) {
this.emit("error", { error, context: "local" });
throw error;
}
}
/**
* Get pending local notifications
*/
async getPendingLocalNotifications() {
this.ensureInitialized();
try {
const localNotificationsModule = await DynamicLoader.loadLocalNotifications();
if (!localNotificationsModule) {
throw new Error("Local notifications are not available on this platform");
}
const { LocalNotifications } = localNotificationsModule;
const result = await LocalNotifications.getPending();
return result.notifications.map((n) => ({
id: n.id.toString(),
title: n.title,
body: n.body,
data: n.extra,
platform: this.platform,
type: "local",
timestamp: /* @__PURE__ */ new Date()
}));
} catch (error) {
this.emit("error", { error, context: "local" });
throw error;
}
}
/**
* Show in-app notification
*/
async showInAppNotification(options) {
try {
const { showInAppNotification: showInAppNotification2 } = await Promise.resolve().then(() => inApp$1);
const id = await showInAppNotification2(options, this.config?.inApp);
this.emit("notificationShown", { options, type: "inApp", id });
return id;
} catch (error) {
this.emit("error", { error, context: "inApp" });
throw error;
}
}
/**
* Check if notifications are supported
*/
async isSupported() {
try {
const { platform: platform2 } = await Promise.resolve().then(() => platform$1);
const capabilities = await platform2.getCapabilities();
return capabilities.pushNotifications || capabilities.localNotifications || false;
} catch (error) {
return false;
}
}
/**
* Create notification channel (Android)
*/
async createChannel(channel) {
if (this.platform !== "android") {
return;
}
try {
const localNotificationsModule = await DynamicLoader.loadLocalNotifications();
if (!localNotificationsModule) {
throw new Error("Local notifications are not available on this platform");
}
const { LocalNotifications } = localNotificationsModule;
const capacitorChannel = toCapacitorChannel(channel);
await LocalNotifications.createChannel(capacitorChannel);
this.emit("channelCreated", { channel });
} catch (error) {
this.emit("error", { error, context: "channel" });
throw error;
}
}
/**
* Delete notification channel (Android)
*/
async deleteChannel(channelId) {
if (this.platform !== "android") {
return;
}
try {
const localNotificationsModule = await DynamicLoader.loadLocalNotifications();
if (!localNotificationsModule) {
throw new Error("Local notifications are not available on this platform");
}
const { LocalNotifications } = localNotificationsModule;
await LocalNotifications.deleteChannel({ id: channelId });
this.emit("channelDeleted", { channelId });
} catch (error) {
this.emit("error", { error, context: "channel" });
throw error;
}
}
/**
* List notification channels (Android)
*/
async listChannels() {
if (this.platform !== "android") {
return [];
}
try {
const localNotificationsModule = await DynamicLoader.loadLocalNotifications();
if (!localNotificationsModule) {
throw new Error("Local notifications are not available on this platform");
}
const { LocalNotifications } = localNotificationsModule;
const result = await LocalNotifications.listChannels();
return result.channels.map((channel) => fromCapacitorChannel(channel));
} catch (error) {
this.emit("error", { error, context: "channel" });
throw error;
}
}
/**
* Add event listener
*/
on(event, callback) {
const listeners = this.eventListeners.get(event) || [];
listeners.push(callback);
this.eventListeners.set(event, listeners);
return () => {
const currentListeners = this.eventListeners.get(event) || [];
const index = currentListeners.indexOf(callback);
if (index > -1) {
currentListeners.splice(index, 1);
this.eventListeners.set(event, currentListeners);
}
};
}
/**
* Remove event listener
*/
off(event, callback) {
if (!callback) {
this.eventListeners.delete(event);
return;
}
const listeners = this.eventListeners.get(event) || [];
const index = listeners.indexOf(callback);
if (index > -1) {
listeners.splice(index, 1);
this.eventListeners.set(event, listeners);
}
}
/**
* Emit event to listeners
*/
emit(event, data) {
const listeners = this.eventListeners.get(event) || [];
const notificationEvent = {
id: Date.now().toString(),
type: event,
timestamp: /* @__PURE__ */ new Date(),
data,
...data
};
listeners.forEach((callback) => {
try {
callback(notificationEvent);
} catch (error) {
}
});
}
/**
* Detect current platform
*/
async detectPlatform() {
this.platform = await DynamicLoader.getPlatform();
}
/**
* Initialize provider based on configuration
*/
async initializeProvider() {
if (!this.config) {
throw new Error("Configuration is required");
}
try {
if (this.config.provider === "firebase") {
const { FirebaseProvider } = await import("./FirebaseProvider-CbcLVLcm.js");
this.provider = new FirebaseProvider();
} else if (this.config.provider === "onesignal") {
const { OneSignalProvider } = await import("./OneSignalProvider-oOlRK-Y1.js");
this.provider = new OneSignalProvider();
} else {
throw new Error(`Unknown provider: ${this.config.provider}`);
}
await this.provider.init(this.config.config);
const providerCapabilities = await this.provider.getCapabilities();
this.capabilities = toPlatformCapabilities(providerCapabilities);
} catch (error) {
throw new Error(`Failed to initialize provider: ${error}`);
}
}
/**
* Setup event listeners for provider
*/
async setupEventListeners() {
if (!this.provider) {
return;
}
this.provider.onMessage((payload) => {
this.emit("notificationReceived", {
payload,
type: "push",
platform: this.platform
});
});
this.provider.onTokenRefresh((token) => {
this.emit("tokenRefreshed", { token });
});
this.provider.onError((error) => {
this.emit("error", { error, context: "provider" });
});
if (this.platform !== "web") {
try {
const { LocalNotifications } = await import("@capacitor/local-notifications");
LocalNotifications.addListener(
"localNotificationReceived",
(notification) => {
this.emit("notificationReceived", {
payload: fromCapacitorLocalNotification(notification),
type: "local",
platform: this.platform
});
}
);
LocalNotifications.addListener(
"localNotificationActionPerformed",
(action) => {
this.emit("notificationActionPerformed", {
action: action.actionId,
notification: action.notification,
inputValue: action.inputValue,
platform: this.platform
});
}
);
} catch (error) {
}
}
}
/**
* Ensure notification kit is initialized
*/
ensureInitialized() {
if (!this.initialized) {
throw new Error("NotificationKit must be initialized before use");
}
}
}
const notifications = {
/**
* Initialize notification kit
*/
init: (config) => NotificationKit.getInstance().init(config),
/**
* Request permission
*/
requestPermission: () => NotificationKit.getInstance().requestPermission(),
/**
* Check permission
*/
checkPermission: () => NotificationKit.getInstance().checkPermission(),
/**
* Check if permission is granted
*/
isPermissionGranted: async () => {
const kit = NotificationKit.getInstance();
const status = await kit.checkPermission();
return status === "granted";
},
/**
* Get permission state
*/
getPermissionState: () => NotificationKit.getInstance().checkPermission(),
/**
* Get token
*/
getToken: () => NotificationKit.getInstance().getToken(),
/**
* Delete token
*/
deleteToken: async () => {
const kit = NotificationKit.getInstance();
const provider = kit.getProvider();
if (provider && "deleteToken" in provider) {
await provider.deleteToken();
} else {
throw new Error("deleteToken not supported by current provider");
}
},
/**
* Subscribe to topic
*/
subscribe: (topic) => NotificationKit.getInstance().subscribe(topic),
/**
* Unsubscribe from topic
*/
unsubscribe: (topic) => NotificationKit.getInstance().unsubscribe(topic),
/**
* Schedule local notification
*/
schedule: (options) => NotificationKit.getInstance().scheduleLocalNotification(options),
/**
* Cancel local notification
*/
cancel: (id) => NotificationKit.getInstance().cancelLocalNotification(id),
/**
* Get pending notifications
*/
getPending: () => NotificationKit.getInstance().getPendingLocalNotifications(),
/**
* Get delivered notifications
*/
getDelivered: async () => {
const kit = NotificationKit.getInstance();
if (kit.getPlatform() === "web") {
throw new Error("getDelivered not supported on web platform");
}
const localNotificationsModule = await DynamicLoader.loadLocalNotifications();
if (!localNotificationsModule) {
throw new Error("Local notifications are not available on this platform");
}
const { LocalNotifications } = localNotificationsModule;
const result = await LocalNotifications.getDeliveredNotifications();
return result.notifications;
},
/**
* Remove delivered notification
*/
removeDelivered: async (id) => {
const kit = NotificationKit.getInstance();
if (kit.getPlatform() === "web") {
throw new Error("removeDelivered not supported on web platform");
}
const localNotificationsModule = await DynamicLoader.loadLocalNotifications();
if (!localNotificationsModule) {
throw new Error("Local notifications are not available on this platform");
}
const { LocalNotifications } = localNotificationsModule;
await LocalNotifications.removeDeliveredNotifications({
notifications: [{ id: parseInt(id, 10), title: "", body: "" }]
});
},
/**
* Remove all delivered notifications
*/
removeAllDelivered: async () => {
const kit = NotificationKit.getInstance();
if (kit.getPlatform() === "web") {
throw new Error("removeAllDelivered not supported on web platform");
}
const localNotificationsModule = await DynamicLoader.loadLocalNotifications();
if (!localNotificationsModule) {
throw new Error("Local notifications are not available on this platform");
}
const { LocalNotifications } = localNotificationsModule;
await LocalNotifications.removeAllDeliveredNotifications();
},
/**
* Cancel all pending notifications
*/
cancelAll: async () => {
const kit = NotificationKit.getInstance();
if (kit.getPlatform() === "web") {
throw new Error("cancelAll not supported on web platform");
}
const localNotificationsModule = await DynamicLoader.loadLocalNotifications();
if (!localNotificationsModule) {
throw new Error("Local notifications are not available on this platform");
}
const { LocalNotifications } = localNotificationsModule;
const pending = await LocalNotifications.getPending();
if (pending.notifications.length > 0) {
await LocalNotifications.cancel({
notifications: pending.notifications.map((n) => ({ id: n.id }))
});
}
},
/**
* Listen for push notifications
*/
onPush: (callback) => {
return NotificationKit.getInstance().on("notificationReceived", (event) => {
if (event.type.startsWith("push.")) {
callback(event.notification);
}
});
},
/**
* Listen for push notification opened
*/
onPushOpened: (callback) => {
return NotificationKit.getInstance().on("notificationActionPerformed", (event) => {
if (event.type === "push.opened" || event.type === "push.action" && event.actionId === "tap") {
callback(event.notification);
}
});
},
/**
* Show in-app notification
*/
showInApp: (options) => NotificationKit.getInstance().showInAppNotification(options),
/**
* Success notification
*/
success: (title, message) => NotificationKit.getInstance().showInAppNotification({
title,
message: message ?? title,
type: "success"
}),
/**
* Error notification
*/
error: (title, message) => NotificationKit.getInstance().showInAppNotification({
title,
message: message ?? title,
type: "error"
}),
/**
* Warning notification
*/
warning: (title, message) => NotificationKit.getInstance().showInAppNotification({
title,
message: message ?? title,
type: "warning"
}),
/**
* Info notification
*/
info: (title, message) => NotificationKit.getInstance().showInAppNotification({
title,
message: message ?? title,
type: "info"
}),
/**
* Add event listener
*/
on: (event, callback) => NotificationKit.getInstance().on(event, callback),
/**
* Remove event listener
*/
off: (event, callback) => NotificationKit.getInstance().off(event, callback)
};
class PermissionManager {
platform;
constructor() {
this.platform = "unknown";
}
/**
* Request notification permissions
*/
async requestPermission() {
try {
await this.ensurePlatform();
if (this.platform === "web") {
return await this.requestWebPermission();
} else {
return await this.requestNativePermission();
}
} catch (error) {
return false;
}
}
/**
* Check current permission status
*/
async checkPermission() {
try {
await this.ensurePlatform();
if (this.platform === "web") {
return await this.checkWebPermission();
} else {
return await this.checkNativePermission();
}
} catch (error) {
return "denied";
}
}
/**
* Check if permission is granted
*/
async isPermissionGranted() {
const status = await this.checkPermission();
return status === "granted";
}
/**
* Check if permission can be requested
*/
async canRequestPermission() {
const status = await this.checkPermission();
return status === "prompt" || status === "default";
}
/**
* Open system settings for notifications
*/
async openSettings() {
if (this.platform === "web") {
throw new Error("Cannot open settings from web platform");
}
}
/**
* Request web notification permission
*/
async requestWebPermission() {
if (!("Notification" in window)) {
throw new Error("Notifications not supported in this browser");
}
if (Notification.permission === "granted") {
return true;
}
if (Notification.permission === "denied") {
return false;
}
const permission = await Notification.requestPermission();
return permission === "granted";
}
/**
* Check web notification permission
*/
async checkWebPermission() {
if (!("Notification" in window)) {
return "denied";
}
const permission = Notification.permission;
if (permission === "default") {
return "prompt";
}
return permission;
}
/**
* Request native notification permission
*/
async requestNativePermission() {
try {
const pushNotificationsModule = await DynamicLoader.loadPushNotifications();
if (!pushNotificationsModule) {
throw new Error("Push notifications are not available on this platform");
}
const { PushNotifications } = pushNotificationsModule;
const result = await PushNotifications.requestPermissions();
return result.receive === "granted";
} catch (error) {
return false;
}
}
/**
* Check native notification permission
*/
async checkNativePermission() {
try {
const pushNotificationsModule = await DynamicLoader.loadPushNotifications();
if (!pushNotificationsModule) {
throw new Error("Push notifications are not available on this platform");
}
const { PushNotifications } = pushNotificationsModule;
const result = await PushNotifications.checkPermissions();
if (result.receive === "granted") {
return "granted";
} else if (result.receive === "denied") {
return "denied";
} else if (result.receive === "prompt") {
return "prompt";
} else {
return "unknown";
}
} catch (error) {
return "denied";
}
}
/**
* Detect current platform
*/
async detectPlatform() {
return DynamicLoader.getPlatform();
}
/**
* Ensure platform is detected
*/
async ensurePlatform() {
if (this.platform === "unknown") {
this.platform = await this.detectPlatform();
}
}
}
const permissionManager = new PermissionManager();
const permissions = {
request: () => permissionManager.requestPermission(),
check: () => permissionManager.checkPermission(),
isGranted: () => permissionManager.isPermissionGranted(),
canRequest: () => permissionManager.canRequestPermission(),
openSettings: () => permissionManager.openSettings()
};
class PlatformManager {
detection = null;
capabilities = null;
/**
* Detect current platform
*/
async detect() {
if (this.detection) {
return this.detection;
}
const platform2 = await this.getPlatform();
const isCapacitor = await DynamicLoader.isNativePlatform();
const isHybrid = isCapacitor;
const isNative = isCapacitor;
const isWeb = platform2 === "web";
const isMobile = platform2 === "ios" || platform2 === "android";
const isDesktop = platform2 === "electron" || !isMobile && isWeb;
const isTablet = false;
const userAgent = typeof navigator !== "undefined" ? navigator.userAgent : "";
const version = this.getVersion();
this.detection = {
platform: platform2,
isCapacitor,
isHybrid,
isNative,
isWeb,
isMobile,
isDesktop,
isTablet,
version,
userAgent,
supportedFeatures: this.getSupportedFeatures(platform2),
limitations: this.getLimitations(platform2),
warnings: this.getWarnings(platform2)
};
return this.detection;
}
/**
* Get platform capabilities
*/
async getCapabilities(platform2) {
const targetPlatform = platform2 || await this.getPlatform();
if (this.capabilities && !platform2) {
return this.capabilities;
}
const capabilities = this.buildCapabilities(targetPlatform);
if (!platform2) {
this.capabilities = capabilities;
}
return capabilities;
}
/**
* Check if feature is supported
*/
async isSupported(feature, platform2) {
const capabilities = await this.getCapabilities(platform2);
return capabilities[feature] || false;
}
/**
* Get platform defaults
*/
getDefaults() {
return {
sound: "default",
badge: "1",
icon: "notification-icon",
web: {
sound: "default.mp3"
},
ios: {
sound: "default.caf",
badge: "auto"
},
android: {
sound: "default",
icon: "ic_notification"
},
electron: {
sound: "default"
}
};
}
/**
* Get platform compatibility matrix
*/
getCompatibility() {
return {
pushNotifications: true,
localNotifications: true,
inAppNotifications: true,
channels: true,
actions: true,
badges: true,
sounds: true,
criticalAlerts: false
};
}
/**
* Get current platform
*/
async getPlatform() {
return DynamicLoader.getPlatform();
}
/**
* Get platform version
*/
getVersion() {
if (typeof window !== "undefined") {
return window.navigator.userAgent;
}
return "unknown";
}
/**
* Build platform capabilities
*/
buildCapabilities(platform2) {
const defaults = this.getDefaults();
const platformDefaults = defaults[platform2] || {};
return {
pushNotifications: false,
localNotifications: false,
inAppNotifications: false,
notificationChannels: false,
notificationActions: false,
notificationBadging: false,
notificationSound: false,
notificationVibration: false,
notificationLights: false,
notificationGrouping: false,
notificationImportance: false,
notificationVisibility: false,
notificationLockScreen: false,
notificationFullScreen: false,
notificationHeadsUp: false,
notificationOngoing: false,
notificationProgress: false,
notificationBigText: false,
notificationBigPicture: false,
notificationInbox: false,
notificationMedia: false,
notificationCustom: false,
notificationScheduling: false,
notificationGeofencing: false,
notificationTriggers: false,
serviceWorker: false,
webPushProtocol: false,
backgroundSync: false,
foregroundService: false,
criticalAlerts: false,
provisionalAuth: false,
appBadge: false,
quietHours: false,
doNotDisturb: false,
...platformDefaults
};
}
/**
* Get supported features for platform
*/
getSupportedFeatures(platform2) {
const capabilities = this.buildCapabilities(platform2);
return Object.entries(capabilities).filter(([, supported]) => supported).map(([feature]) => feature);
}
/**
* Get platform limitations
*/
getLimitations(platform2) {
const limitations = [];
switch (platform2) {
case "web":
limitations.push("No local notifications");
limitations.push("No notification channels");
limitations.push("No app badging");
limitations.push("Requires HTTPS for push notifications");
limitations.push("Service worker required");
break;
case "ios":
limitations.push("No notification channels");
limitations.push("No notification lights");
limitations.push("Critical alerts require entitlement");
limitations.push("Limited customization");
break;
case "android":
limitations.push("Notification channels required (API 26+)");
limitations.push("Background restrictions");
limitations.push("Battery optimization affects delivery");
break;
case "electron":
limitations.push("Platform-specific implementation");
limitations.push("Limited mobile features");
break;
}
return limitations;
}
/**
* Get platform warnings
*/
getWarnings(platform2) {
const warnings = [];
switch (platform2) {
case "web":
if (typeof window !== "undefined" && !window.isSecureContext) {
warnings.push("HTTPS required for push notifications");
}
if (typeof navigator !== "undefined" && !("serviceWorker" in navigator)) {
warnings.push("Service Worker not supported");
}
break;
case "ios":
warnings.push("iOS notification permissions are sensitive");
warnings.push("Users may have notifications disabled globally");
break;
case "android":
warnings.push("Android notification behavior varies by OEM");
warnings.push("Users may have battery optimization enabled");
break;
}
return warnings;
}
}
const platformManager = new PlatformManager();
const platform = {
detect: () => platformManager.detect(),
getCapabilities: (platform2) => platformManager.getCapabilities(platform2),
isSupported: (feature, platform2) => platformManager.isSupported(feature, platform2),
getDefaults: () => platformManager.getDefaults(),
getCompatibility: () => platformManager.getCompatibility()
};
const platform$1 = /* @__PURE__ */ Object.freeze(/* @__PURE__ */ Object.defineProperty({
__proto__: null,
PlatformManager,
platform,
platformManager
}, Symbol.toStringTag, { value: "Module" }));
class StorageManager {
platform;
config;
prefix;
constructor(config = {}) {
this.platform = "unknown";
this.config = {
prefix: "notification_kit_",
adapter: "preferences",
encryption: false,
ttl: 0,
...config
};
this.prefix = this.config.prefix;
}
/**
* Store data
*/
async set(key, value) {
await this.ensurePlatform();
const fullKey = this.prefix + key;
const data = this.prepareData(value);
try {
if (this.platform === "web" || this.config.adapter === "localStorage") {
await this.setWebStorage(fullKey, data);
} else {
await this.setNativeStorage(fullKey, data);
}
} catch (error) {
throw error;
}
}
/**
* Get data
*/
async get(key) {
await this.ensurePlatform();
const fullKey = this.prefix + key;
try {
let data;
if (this.platform === "web" || this.config.adapter === "localStorage") {
data = await this.getWebStorage(fullKey);
} else {
data = await this.getNativeStorage(fullKey);
}
if (!data) {
return null;
}
return this.parseData(data);
} catch (error) {
return null;
}
}
/**
* Remove data
*/
async remove(key) {
await this.ensurePlatform();
const fullKey = this.prefix + key;
try {
if (this.platform === "web" || this.config.adapter === "localStorage") {
await this.removeWebStorage(fullKey);
} else {
await this.removeNativeStorage(fullKey);
}
} catch (error) {
throw error;
}
}
/**
* Clear all data
*/
async clear() {
await this.ensurePlatform();
try {
if (this.platform === "web" || this.config.adapter === "localStorage") {
await this.clearWebStorage();
} else {
await this.clearNativeStorage();
}
} catch (error) {
throw error;
}
}
/**
* Get all keys
*/
async keys() {
await this.ensurePlatform();
try {
if (this.platform === "web" || this.config.adapter === "localStorage") {
return await this.getWebStorageKeys();
} else {
return await this.getNativeStorageKeys();
}
} catch (error) {
return [];
}
}
/**
* Check if key exists
*/
async has(key) {
const value = await this.get(key);
return value !== null;
}
/**
* Get storage size
*/
async size() {
const keys = await this.keys();
return keys.length;
}
/**
* Set web storage
*/
async setWebStorage(key, data) {
if (this.config.adapter === "sessionStorage") {
sessionStorage.setItem(key, data);
} else {
localStorage.setItem(key, data);
}
}
/**
* Get web storage
*/
async getWebStorage(key) {
if (this.config.adapter === "sessionStorage") {
return sessionStorage.getItem(key);
} else {
return localStorage.getItem(key);
}
}
/**
* Remove web storage
*/
async removeWebStorage(key) {
if (this.config.adapter === "sessionStorage") {
sessionStorage.removeItem(key);
} else {
localStorage.removeItem(key);
}
}
/**
* Clear web storage
*/
async clearWebStorage() {
const keys = await this.getWebStorageKeys();
for (const key of keys) {
await this.removeWebStorage(key);
}
}
/**
* Get web storage keys
*/
async getWebStorageKeys() {
const storage2 = this.config.adapter === "sessionStorage" ? sessionStorage : localStorage;
const keys = [];
for (let i = 0; i < storage2.length; i++) {
const key = storage2.key(i);
if (key && key.startsWith(this.prefix)) {
keys.push(key.substring(this.prefix.length));
}
}
return keys;
}
/**
* Set native storage
*/
async setNativeStorage(key, data) {
const preferencesModule = await DynamicLoader.loadPreferences();
if (!preferencesModule) {
return this.setWebStorage(key, data);
}
await preferencesModule.Preferences.set({ key, value: data });
}
/**
* Get native storage
*/
async getNativeStorage(key) {
const preferencesModule = await DynamicLoader.loadPreferences();
if (!preferencesModule) {
return this.getWebStorage(key);
}
const result = await preferencesModule.Preferences.get({ key });
return result.value;
}
/**
* Remove native storage
*/
async removeNativeStorage(key) {
const preferencesModule = await DynamicLoader.loadPreferences();
if (!preferencesModule) {
return this.removeWebStorage(key);
}
await preferencesModule.Preferences.remove({ key });
}
/**
* Clear native storage
*/
async clearNativeStorage() {
const preferencesModule = await DynamicLoader.loadPreferences();
if (!preferencesModule) {
return this.clearWebStorage();
}
const keys = await this.getNativeStorageKeys();
for (const key of keys) {
await preferencesModule.Preferences.remove({ key: this.prefix + key });
}
}
/**
* Get native storage keys
*/
async getNativeStorageKeys() {
const preferencesModule = await DynamicLoader.loadPreferences();
if (!preferencesModule) {
return this.getWebStorageKeys();
}
const result = await preferencesModule.Preferences.keys();
return result.keys.filter((key) => key.startsWith(this.prefix)).map((key) => key.substring(this.prefix.length));
}
/**
* Prepare data for storage
*/
prepareData(value) {
const data = {
value,
timestamp: Date.now(),
ttl: this.config.ttl
};
let serialized = JSON.stringify(data);
if (this.config.encryption) {
serialized = this.encrypt(serialized);
}
return serialized;
}
/**
* Parse data from storage
*/
parseData(data) {
try {
let decrypted = data;
if (this.config.encryption) {
decrypted = this.decrypt(data);
}
const parsed = JSON.parse(decrypted);
if (this.config.ttl && this.config.ttl > 0) {
const now = Date.now();
const age = now - parsed.timestamp;
if (age > this.config.ttl) {
return null;
}
}
return parsed.value;
} catch (error) {
return null;
}
}
/**
* Encrypt data (basic implementation)
*/
encrypt(data) {
return btoa(data);
}
/**
* Decrypt data (basic implementation)
*/
decrypt(data) {
return atob(data);
}
/**
* Ensure platform is detected
*/
async ensurePlatform() {
if (this.platform === "unknown") {
this.platform = await DynamicLoader.getPlatform();
}
}
}
const storage = new StorageManager();
const createStorage = (config) => new StorageManager(config);
class SchedulingUtils {
/**
* Calculate next scheduled time
*/
static calculateNextScheduledTime(schedule) {
if (!schedule) {
return null;
}
const now = /* @__PURE__ */ new Date();
if (schedule.at) {
return this.calculateAtTime(schedule.at, now);
}
if (schedule.on) {
return this.calculateOnTime(schedule.on, now);
}