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.
617 lines (616 loc) • 18 kB
JavaScript
import { L as Logger, D as DynamicLoader } from "./inApp-DOHkBonY.mjs";
import { C as ConfigValidator } from "./config-validator-CAcf6-xn.mjs";
class OneSignalNativeBridge {
static isInitialized = false;
/**
* Initialize OneSignal on native platforms with runtime configuration
*/
static async initializeNative(config) {
if (this.isInitialized) {
Logger.warn("OneSignal native bridge already initialized");
return;
}
const isNative = await DynamicLoader.isNativePlatform();
if (!isNative) {
return;
}
const platform = await DynamicLoader.getPlatform();
try {
const capacitor = await DynamicLoader.loadCapacitorCore();
if (!capacitor) {
throw new Error("Capacitor not available for native OneSignal initialization");
}
await this.configureNativePlatform(platform, config);
this.isInitialized = true;
Logger.info(`OneSignal native bridge initialized for ${platform}`);
} catch (error) {
Logger.error("Failed to initialize OneSignal native bridge:", error);
throw error;
}
}
/**
* Configure OneSignal for specific native platform
*/
static async configureNativePlatform(platform, config) {
if (platform === "ios") {
await this.configureIOS(config);
} else if (platform === "android") {
await this.configureAndroid(config);
}
}
/**
* Configure OneSignal for iOS
*/
static async configureIOS(config) {
Logger.debug("iOS OneSignal configuration:", {
appId: config.appId ? "***" : "not provided"
// Log config status without exposing sensitive data
});
}
/**
* Configure OneSignal for Android
*/
static async configureAndroid(config) {
Logger.debug("Android OneSignal configuration:", {
appId: config.appId ? "***" : "not provided"
// Log config status without exposing sensitive data
});
}
/**
* Get initialization status
*/
static isNativeInitialized() {
return this.isInitialized;
}
/**
* Reset initialization (useful for testing)
*/
static reset() {
this.isInitialized = false;
}
}
class OneSignalProvider {
name = "onesignal";
type = "onesignal";
config = null;
initialized = false;
OneSignal = null;
messageListeners = [];
tokenListeners = [];
errorListeners = [];
/**
* Initialize OneSignal provider
*/
async init(config) {
try {
ConfigValidator.validateOneSignalConfig(config);
ConfigValidator.validateEnvironmentVariables("onesignal");
this.config = config;
const isNative = await DynamicLoader.isNativePlatform();
if (isNative) {
await OneSignalNativeBridge.initializeNative(config);
this.initialized = true;
await this.setupNativeEventListeners();
} else {
const initOptions = {
appId: config.appId,
safari_web_id: config.safariWebId,
autoPrompt: config.autoPrompt ?? true,
autoResubscribe: config.autoResubscribe ?? true,
path: config.path,
serviceWorkerPath: config.serviceWorkerPath,
serviceWorkerUpdaterPath: config.serviceWorkerUpdaterPath,
notificationClickHandlerMatch: config.notificationClickHandlerMatch ?? "origin",
notificationClickHandlerAction: config.notificationClickHandlerAction ?? "focusOrNavigate",
allowLocalhostAsSecureOrigin: config.allowLocalhostAsSecureOrigin ?? false
};
if (config.promptOptions) {
initOptions.promptOptions = config.promptOptions;
}
if (config.welcomeNotification) {
initOptions.welcomeNotification = config.welcomeNotification;
}
const oneSignalModule = await DynamicLoader.loadOneSignal();
if (!oneSignalModule) {
throw new Error("OneSignal is required but not installed");
}
this.OneSignal = oneSignalModule.default;
await this.OneSignal.init(initOptions);
this.initialized = true;
await this.setupEventListeners();
}
} catch (error) {
this.handleError(new Error(`OneSignal initialization failed: ${error}`));
throw error;
}
}
/**
* Destroy OneSignal provider
*/
async destroy() {
try {
if (this.initialized) {
this.initialized = false;
this.config = null;
this.messageListeners = [];
this.tokenListeners = [];
this.errorListeners = [];
}
} catch (error) {
this.handleError(new Error(`OneSignal destroy failed: ${error}`));
throw error;
}
}
/**
* Request notification permission
*/
async requestPermission() {
try {
const isNative = await DynamicLoader.isNativePlatform();
if (isNative) {
return await this.requestNativePermission();
} else {
return await this.requestWebPermission();
}
} catch (error) {
this.handleError(new Error(`Permission request failed: ${error}`));
return false;
}
}
/**
* Check notification permission status
*/
async checkPermission() {
try {
const isNative = await DynamicLoader.isNativePlatform();
if (isNative) {
return await this.checkNativePermission();
} else {
return await this.checkWebPermission();
}
} catch (error) {
this.handleError(new Error(`Permission check failed: ${error}`));
return "denied";
}
}
/**
* Get OneSignal player ID (token)
*/
async getToken() {
try {
if (!this.OneSignal) {
throw new Error("OneSignal not initialized");
}
const playerId = await this.OneSignal.getUserId();
if (playerId) {
return playerId;
} else {
throw new Error("No OneSignal player ID available");
}
} catch (error) {
this.handleError(new Error(`Token retrieval failed: ${error}`));
throw error;
}
}
/**
* Refresh OneSignal token
*/
async refreshToken() {
try {
const newToken = await this.getToken();
this.notifyTokenListeners(newToken);
return newToken;
} catch (error) {
this.handleError(new Error(`Token refresh failed: ${error}`));
throw error;
}
}
/**
* Delete OneSignal token
*/
async deleteToken() {
try {
if (!this.OneSignal) {
throw new Error("OneSignal not initialized");
}
await this.OneSignal.logoutUser();
} catch (error) {
this.handleError(new Error(`Token deletion failed: ${error}`));
throw error;
}
}
/**
* Subscribe to tag (OneSignal's equivalent of topics)
*/
async subscribe(topic) {
try {
if (!this.OneSignal) {
throw new Error("OneSignal not initialized");
}
await this.OneSignal.sendTag(topic, "true");
} catch (error) {
this.handleError(new Error(`Tag subscription failed: ${error}`));
throw error;
}
}
/**
* Unsubscribe from tag
*/
async unsubscribe(topic) {
try {
if (!this.OneSignal) {
throw new Error("OneSignal not initialized");
}
await this.OneSignal.deleteTag(topic);
} catch (error) {
this.handleError(new Error(`Tag unsubscription failed: ${error}`));
throw error;
}
}
/**
* Get subscribed tags
*/
async getSubscriptions() {
try {
if (!this.OneSignal) {
throw new Error("OneSignal not initialized");
}
const tags = await this.OneSignal.getTags();
return Object.keys(tags || {});
} catch (error) {
this.handleError(new Error(`Get subscriptions failed: ${error}`));
throw error;
}
}
/**
* Send notification (requires REST API)
*/
async sendNotification(payload) {
if (!this.config?.restApiKey) {
throw new Error("REST API key required for sending notifications");
}
try {
const response = await fetch(
"https://onesignal.com/api/v1/notifications",
{
method: "POST",
headers: {
"Content-Type": "application/json",
Authorization: `Basic ${this.config.restApiKey}`
},
body: JSON.stringify({
app_id: this.config.appId,
headings: { en: payload.notification?.title || "Notification" },
contents: { en: payload.notification?.body || "" },
data: payload.data,
included_segments: ["All"]
})
}
);
if (!response.ok) {
throw new Error(`OneSignal API error: ${response.statusText}`);
}
} catch (error) {
this.handleError(new Error(`Send notification failed: ${error}`));
throw error;
}
}
/**
* Listen for messages
*/
onMessage(callback) {
this.messageListeners.push(callback);
return () => {
const index = this.messageListeners.indexOf(callback);
if (index > -1) {
this.messageListeners.splice(index, 1);
}
};
}
/**
* Listen for token refresh
*/
onTokenRefresh(callback) {
this.tokenListeners.push(callback);
return () => {
const index = this.tokenListeners.indexOf(callback);
if (index > -1) {
this.tokenListeners.splice(index, 1);
}
};
}
/**
* Listen for errors
*/
onError(callback) {
this.errorListeners.push(callback);
return () => {
const index = this.errorListeners.indexOf(callback);
if (index > -1) {
this.errorListeners.splice(index, 1);
}
};
}
/**
* Check if OneSignal is supported
*/
async isSupported() {
try {
const isNative = await DynamicLoader.isNativePlatform();
if (isNative) {
return true;
} else {
return typeof window !== "undefined" && "serviceWorker" in navigator && "PushManager" in window;
}
} catch (_error) {
return false;
}
}
/**
* Get provider capabilities
*/
async getCapabilities() {
const isWeb = !await DynamicLoader.isNativePlatform();
return {
pushNotifications: true,
topics: true,
// Using tags
richMedia: true,
actions: true,
backgroundSync: true,
analytics: true,
segmentation: true,
scheduling: true,
geofencing: false,
inAppMessages: true,
webPush: isWeb,
badges: !isWeb,
sounds: true,
vibration: !isWeb,
lights: !isWeb,
bigText: !isWeb,
bigPicture: !isWeb,
inbox: false,
progress: false,
channels: !isWeb,
groups: !isWeb,
categories: true,
quietHours: true,
deliveryReceipts: true,
clickTracking: true,
impressionTracking: true,
customData: true,
multipleDevices: true,
userTags: true,
triggers: true,
templates: true,
abTesting: true,
automation: true,
journeys: true,
realTimeUpdates: true
};
}
/**
* Setup native event listeners for Capacitor
*/
async setupNativeEventListeners() {
try {
const pushNotificationsModule = await DynamicLoader.loadPushNotifications();
if (!pushNotificationsModule) {
throw new Error("Push notifications module not available");
}
const { PushNotifications } = pushNotificationsModule;
await PushNotifications.addListener("pushNotificationReceived", (notification) => {
const payload = {
data: notification.data || {},
notification: {
title: notification.title || "",
body: notification.body || "",
...notification.id && { id: notification.id },
...notification.badge && { badge: notification.badge.toString() }
}
};
this.notifyMessageListeners(payload);
});
await PushNotifications.addListener("pushNotificationActionPerformed", (notificationAction) => {
const payload = {
data: notificationAction.notification.data || {},
notification: {
title: notificationAction.notification.title || "",
body: notificationAction.notification.body || "",
...notificationAction.notification.id && { id: notificationAction.notification.id }
}
};
this.notifyMessageListeners(payload);
});
await PushNotifications.addListener("registration", (token) => {
this.notifyTokenListeners(token.value);
});
await PushNotifications.addListener("registrationError", (error) => {
this.handleError(new Error(`Registration error: ${error.error}`));
});
} catch (error) {
this.handleError(new Error(`Native event listener setup failed: ${error}`));
}
}
/**
* Setup event listeners
*/
async setupEventListeners() {
try {
if (!this.OneSignal) {
throw new Error("OneSignal not initialized");
}
const oneSignalInstance = this.OneSignal;
oneSignalInstance.on("notificationReceived", (notification) => {
const notificationData = notification;
const notificationObj = {
title: notificationData.heading,
body: notificationData.content
};
if (notificationData.icon)
notificationObj.icon = notificationData.icon;
if (notificationData.badge)
notificationObj.badge = notificationData.badge;
if (notificationData.image)
notificationObj.image = notificationData.image;
const payload = {
data: notificationData.additionalData || {},
notification: notificationObj
};
this.notifyMessageListeners(payload);
});
oneSignalInstance.on("notificationClicked", (notification) => {
const notificationData = notification;
const notificationObj = {
title: notificationData.heading,
body: notificationData.content
};
if (notificationData.icon)
notificationObj.icon = notificationData.icon;
if (notificationData.badge)
notificationObj.badge = notificationData.badge;
if (notificationData.image)
notificationObj.image = notificationData.image;
const payload = {
data: notificationData.additionalData || {},
notification: notificationObj
};
this.notifyMessageListeners(payload);
});
oneSignalInstance.on("subscriptionChanged", (isSubscribed) => {
if (isSubscribed) {
this.getToken().then((token) => {
this.notifyTokenListeners(token);
}).catch((error) => {
this.handleError(
new Error(
`Token refresh on subscription change failed: ${error}`
)
);
});
}
});
} catch (error) {
this.handleError(new Error(`Event listener setup failed: ${error}`));
}
}
/**
* Request native permission
*/
async requestNativePermission() {
try {
const pushNotificationsModule = await DynamicLoader.loadPushNotifications();
if (!pushNotificationsModule) {
throw new Error("Push notifications require @capacitor/push-notifications");
}
const { PushNotifications } = pushNotificationsModule;
const result = await PushNotifications.requestPermissions();
return result.receive === "granted";
} catch (_error) {
return false;
}
}
/**
* Check native permission
*/
async checkNativePermission() {
try {
const pushNotificationsModule = await DynamicLoader.loadPushNotifications();
if (!pushNotificationsModule) {
throw new Error("Push notifications require @capacitor/push-notifications");
}
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";
}
}
/**
* Request web permission
*/
async requestWebPermission() {
try {
if (!this.OneSignal) {
throw new Error("OneSignal not initialized");
}
const permission = await this.OneSignal.showSlidedownPrompt();
return permission;
} catch (_error) {
if ("Notification" in window) {
const permission = await Notification.requestPermission();
return permission === "granted";
}
return false;
}
}
/**
* Check web permission
*/
async checkWebPermission() {
try {
if (!this.OneSignal) {
throw new Error("OneSignal not initialized");
}
const isSubscribed = await this.OneSignal.isPushNotificationsEnabled();
return isSubscribed ? "granted" : "prompt";
} catch (_error) {
if ("Notification" in window) {
const permission = Notification.permission;
if (permission === "default") {
return "prompt";
}
return permission;
}
return "denied";
}
}
/**
* Notify message listeners
*/
notifyMessageListeners(payload) {
this.messageListeners.forEach((listener) => {
try {
listener(payload);
} catch (error) {
this.handleError(new Error(`Message listener error: ${error}`));
}
});
}
/**
* Notify token listeners
*/
notifyTokenListeners(token) {
this.tokenListeners.forEach((listener) => {
try {
listener(token);
} catch (error) {
this.handleError(new Error(`Token listener error: ${error}`));
}
});
}
/**
* Handle errors
*/
handleError(error) {
this.errorListeners.forEach((listener) => {
try {
listener(error);
} catch (listenerError) {
}
});
}
}
export {
OneSignalProvider
};
//# sourceMappingURL=OneSignalProvider-mRblKTku.mjs.map