← All @molecule/* packages · App templates

@molecule/app-push

Native · native · App (browser) · v1.0.1 · Apache-2.0

Client-side push notifications interface for molecule.dev

npm install @molecule/app-push

npm · Source on GitHub

How it works

@molecule/app-push bridges the native core to the native platform layer of the app.

import { getToken, onNotificationAction, register, requestPermission } from '@molecule/app-push'

async function enablePush(vapidPublicKey: string): Promise<string | null> {
  const permission = await requestPermission() // from a user gesture
  if (permission !== 'granted') return null
  const token = await register({ vapidPublicKey })
  // POST token.value to your API so api-push-notifications can target it
  return token.value
}

function handleTaps(open: (data: unknown) => void): () => void {
  return onNotificationAction((event) => open(event.notification.data))
}

Providers (1): @molecule/app-push-react-native

Works with: @molecule/app-bond, @molecule/app-i18n

Reference

Auto-generated, AI-first package reference for the molecule.dev ecosystem. It is written to be read by coding agents as much as by people, and is generated from this package's source — edit src/index.ts JSDoc, not this file.

Client-side push notifications interface for molecule.dev.

Provides a unified API for push notifications across platforms (web, native containers, etc.): permission flow (checkPermission, requestPermission), registration (register, getToken), incoming events (onNotificationReceived, onNotificationAction), local notifications (scheduleLocal), and badges (setBadge, clearBadge). The device token is what your API's @molecule/api-push-notifications bond sends to.

Quick Start

import { getToken, onNotificationAction, register, requestPermission } from '@molecule/app-push'

async function enablePush(vapidPublicKey: string): Promise<string | null> {
  const permission = await requestPermission() // from a user gesture
  if (permission !== 'granted') return null
  const token = await register({ vapidPublicKey })
  // POST token.value to your API so api-push-notifications can target it
  return token.value
}

function handleTaps(open: (data: unknown) => void): () => void {
  return onNotificationAction((event) => open(event.notification.data))
}

Type

native

Installation

npm install @molecule/app-push @molecule/app-bond @molecule/app-i18n

API

Interfaces

LocalNotificationOptions

Options for scheduling a local notification.

interface LocalNotificationOptions {
  /**
   * Notification ID.
   */
  id?: string

  /**
   * Notification title.
   */
  title: string

  /**
   * Notification body.
   */
  body?: string

  /**
   * Schedule at a specific time.
   */
  at?: Date

  /**
   * Repeat interval.
   */
  repeat?: 'minute' | 'hour' | 'day' | 'week' | 'month' | 'year'

  /**
   * Extra data.
   */
  extra?: Record<string, unknown>

  /**
   * Sound to play.
   */
  sound?: string

  /**
   * Badge count.
   */
  badge?: number

  /**
   * Notification channel (Android).
   */
  channelId?: string

  /**
   * Actions/buttons.
   */
  actions?: PushNotificationAction[]
}

NotificationActionEvent

Notification action event.

interface NotificationActionEvent {
  /**
   * The notification.
   */
  notification: PushNotification

  /**
   * Action that was triggered.
   */
  actionId?: string
}

NotificationReceivedEvent

Notification received event.

interface NotificationReceivedEvent {
  /**
   * The notification.
   */
  notification: PushNotification

  /**
   * Whether the app was in foreground.
   */
  foreground: boolean
}

PushNotification

Push notification payload.

interface PushNotification {
  /**
   * Notification ID.
   */
  id: string

  /**
   * Notification title.
   */
  title: string

  /**
   * Notification body/message.
   */
  body?: string

  /**
   * Notification data payload.
   */
  data?: Record<string, unknown>

  /**
   * Badge count.
   */
  badge?: number

  /**
   * Sound to play.
   */
  sound?: string

  /**
   * Icon URL.
   */
  icon?: string

  /**
   * Image URL.
   */
  image?: string

  /**
   * Click action/URL.
   */
  clickAction?: string

  /**
   * Notification tag (for grouping).
   */
  tag?: string

  /**
   * Whether the notification requires interaction.
   */
  requireInteraction?: boolean

  /**
   * Notification timestamp.
   */
  timestamp?: number

  /**
   * Notification actions (buttons).
   */
  actions?: PushNotificationAction[]
}

PushNotificationAction

Notification action button.

interface PushNotificationAction {
  /**
   * Action ID.
   */
  id: string

  /**
   * Action title.
   */
  title: string

  /**
   * Action icon.
   */
  icon?: string
}

PushProvider

Push notifications provider interface.

All push providers must implement this interface.

interface PushProvider {
  /**
   * Checks the current permission status.
   */
  checkPermission(): Promise<PermissionStatus>

  /**
   * Requests notification permission.
   */
  requestPermission(): Promise<PermissionStatus>

  /**
   * Registers for push notifications and gets a token.
   *
   * @param options - Optional registration options (e.g. a runtime VAPID
   * public key for web subscriptions).
   */
  register(options?: PushRegisterOptions): Promise<PushToken>

  /**
   * Unregisters from push notifications.
   */
  unregister(): Promise<void>

  /**
   * Gets the current push token.
   * @returns The current token, or `null` if not registered.
   */
  getToken(): Promise<PushToken | null>

  /**
   * Subscribes to notification received events.
   */
  onNotificationReceived(listener: NotificationReceivedListener): () => void

  /**
   * Subscribes to notification action events (taps, button clicks).
   */
  onNotificationAction(listener: NotificationActionListener): () => void

  /**
   * Subscribes to token changes.
   */
  onTokenChange(listener: TokenChangeListener): () => void

  /**
   * Schedules a local notification.
   */
  scheduleLocal(options: LocalNotificationOptions): Promise<string>

  /**
   * Cancels a local notification.
   */
  cancelLocal(id: string): Promise<void>

  /**
   * Cancels all local notifications.
   */
  cancelAllLocal(): Promise<void>

  /**
   * Gets pending local notifications.
   */
  getPendingLocal(): Promise<LocalNotificationOptions[]>

  /**
   * Gets delivered notifications.
   */
  getDelivered(): Promise<PushNotification[]>

  /**
   * Removes delivered notifications.
   */
  removeDelivered(ids: string[]): Promise<void>

  /**
   * Removes all delivered notifications.
   */
  removeAllDelivered(): Promise<void>

  /**
   * Sets the badge count.
   */
  setBadge(count: number): Promise<void>

  /**
   * Gets the badge count.
   */
  getBadge(): Promise<number>

  /**
   * Clears the badge.
   */
  clearBadge(): Promise<void>

  /**
   * Destroys the provider.
   */
  destroy(): void
}

PushRegisterOptions

Options for {@link PushProvider.register}.

interface PushRegisterOptions {
  /**
   * VAPID public key (URL-safe base64) used as the `applicationServerKey`
   * when subscribing on the web. Chromium rejects keyless subscriptions, so
   * web apps should deliver the server's key at runtime (e.g. from
   * `GET /api/devices/push/public-key`) and pass it here. Takes precedence
   * over any key the provider was constructed with. Ignored by providers
   * whose platform does not use VAPID (e.g. FCM/APNs native providers).
   */
  vapidPublicKey?: string
}

PushToken

Push token info.

interface PushToken {
  /**
   * Token value.
   */
  value: string

  /**
   * Platform the token is for.
   */
  platform: 'web' | 'ios' | 'android'

  /**
   * When the token was obtained.
   */
  timestamp: number
}

Types

NotificationActionListener

Notification Action Listener type.

type NotificationActionListener = (event: NotificationActionEvent) => void

NotificationReceivedListener

Listener invoked when a push notification is received.

type NotificationReceivedListener = (event: NotificationReceivedEvent) => void

PermissionStatus

Push notification permission status.

type PermissionStatus = 'granted' | 'denied' | 'default' | 'prompt'

TokenChangeListener

Token Change Listener type.

type TokenChangeListener = (token: PushToken) => void

Functions

checkPermission()

Checks the current notification permission status.

function checkPermission(): Promise<PermissionStatus>

Returns: The current permission status (granted, denied, default, or prompt).

clearBadge()

Clears the app icon badge count.

function clearBadge(): Promise<void>

Returns: A promise that resolves when the badge count is cleared.

createWebPushProvider(vapidPublicKey)

Creates a web push provider using the browser Push API and Notification API.

function createWebPushProvider(vapidPublicKey?: string): PushProvider
  • vapidPublicKey — Optional VAPID public key for server-authenticated subscriptions.

Returns: A {@link PushProvider} backed by the Web Push API.

getProvider()

Gets the current push provider, creating a default web provider if none is bonded.

function getProvider(): PushProvider

Returns: The active push provider instance.

getToken()

Gets the current push token.

function getToken(): Promise<PushToken | null>

Returns: The current token, or null if not registered.

hasProvider()

Checks if a push provider has been bonded.

function hasProvider(): boolean

Returns: Whether a push provider is currently registered.

onNotificationAction(listener)

Subscribes to notification action events (taps, button clicks).

function onNotificationAction(listener: NotificationActionListener): () => void
  • listener — Callback invoked when a notification action is triggered.

Returns: An unsubscribe function to remove the listener.

onNotificationReceived(listener)

Subscribes to notification received events.

function onNotificationReceived(listener: NotificationReceivedListener): () => void
  • listener — Callback invoked when a notification is received.

Returns: An unsubscribe function to remove the listener.

register(options)

Registers for push notifications and obtains a device token.

function register(options?: PushRegisterOptions): Promise<PushToken>
  • options — Optional registration options (e.g. a runtime VAPID public key).

Returns: The push token for this device.

requestPermission()

Requests notification permission from the user.

function requestPermission(): Promise<PermissionStatus>

Returns: The resulting permission status after the user responds.

scheduleLocal(options)

Schedules a local notification.

function scheduleLocal(options: LocalNotificationOptions): Promise<string>
  • options — Configuration for the notification (title, body, schedule time, etc.).

Returns: The notification ID that can be used to cancel it later.

setBadge(count)

Sets the app icon badge count.

function setBadge(count: number): Promise<void>
  • count — The badge number to display on the app icon.

Returns: A promise that resolves when the badge count is set.

setProvider(provider)

Sets the push provider implementation.

function setProvider(provider: PushProvider): void
  • provider — The push provider to bond as the active implementation.

Injection Notes

Requirements

Peer dependencies:

  • @molecule/app-bond ^1.0.1
  • @molecule/app-i18n ^1.0.1

Runtime Dependencies

  • @molecule/app-bond

  • @molecule/app-i18n

  • No wiring is needed on web: the first accessor call silently bonds the built-in Web Push provider. In a native app wire @molecule/app-push-react-native (the one prebuilt bond) via setProvider() BEFORE any push call — otherwise the web fallback gets bonded and native registration never happens.

  • Web register() has three hard prerequisites: (1) HTTPS (secure context), (2) a registered SERVICE WORKER — dev builds typically don't ship one, so register() throws "requires the production app build" (it fails fast instead of hanging), and (3) a VAPID public key (pass via register({ vapidPublicKey })) matching your API's VAPID_PRIVATE_KEY — without it Chrome may register but delivery fails.

  • Request permission from a user gesture at the point of value, never on load — a denied browser prompt is remembered forever (no re-prompt).

  • Web scheduleLocal at a future time uses an in-page timer: it does NOT survive reload/close. Web cancelLocal/cancelAllLocal are no-ops, and getPendingLocal() is always empty — for reliable scheduled delivery send a real push from the server.

  • token.value on web is a JSON-serialized PushSubscription (not an FCM token) — store it opaquely; platform is in token.platform.

Translations

Translation strings are provided by @molecule/app-locales-push.