npm package discovery and stats viewer.

Discover Tips

  • General search

    [free text search, go nuts!]

  • Package details

    pkg:[package-name]

  • User packages

    @[username]

Sponsor

Optimize Toolset

I’ve always been into building performant and accessible sites, but lately I’ve been taking it extremely seriously. So much so that I’ve been building a tool to help me optimize and monitor the sites that I build to make sure that I’m making an attempt to offer the best experience to those who visit them. If you’re into performant, accessible and SEO friendly sites, you might like it too! You can check it out at Optimize Toolset.

About

Hi, 👋, I’m Ryan Hefner  and I built this site for me, and you! The goal of this site was to provide an easy way for me to check the stats on my npm packages, both for prioritizing issues and updates, and to give me a little kick in the pants to keep up on stuff.

As I was building it, I realized that I was actually using the tool to build the tool, and figured I might as well put this out there and hopefully others will find it to be a fast and useful way to search and browse npm packages as I have.

If you’re interested in other things I’m working on, follow me on Twitter or check out the open source projects I’ve been publishing on GitHub.

I am also working on a Twitter bot for this site to tweet the most popular, newest, random packages from npm. Please follow that account now and it will start sending out packages soon–ish.

Open Software & Tools

This site wouldn’t be possible without the immense generosity and tireless efforts from the people who make contributions to the world and share their work via open source initiatives. Thank you 🙏

© 2026 – Pkg Stats / Ryan Hefner

@pwa-kit/sdk

v0.1.2

Published

JavaScript SDK for PWAKit native bridge

Readme

@pwa-kit/sdk npm

TypeScript SDK for communicating with the PWAKit native iOS bridge. Provides Web API-aligned interfaces for native capabilities like push notifications, badges, haptics, biometrics, HealthKit, StoreKit, and more.

Installation

npm install @pwa-kit/sdk

Browser Bundle

For direct browser usage without a bundler:

<script src="https://cdn.jsdelivr.net/gh/eddmann/pwa-kit@main/sdk/dist/index.global.js"></script>
<script>
  const { push, badging, haptics, ios, isNative } = PWAKit;

  if (isNative) {
    badging.setAppBadge(5);
  }
</script>

Quick Start

import { push, badging, haptics, ios, isNative } from "@pwa-kit/sdk";

if (isNative) {
  // Subscribe to push notifications (PushManager API)
  const subscription = await push.subscribe();
  console.log("Token:", subscription.token);

  // Set app badge (Badging API)
  await badging.setAppBadge(5);

  // Haptic feedback
  await haptics.impact("medium");

  // iOS-specific: Face ID / Touch ID
  const result = await ios.biometrics.authenticate("Confirm purchase");
}

API Structure

The SDK organizes APIs into three categories:

Web API-Aligned Modules

These modules follow Web Platform API conventions:

| Module | Web Standard | Description | | ------------- | ----------------------------------------------------------------------------------- | ------------------------------- | | push | PushManager | Push notification registration | | badging | Badging API | App icon badges | | vibration | Vibration API | Vibration (uses haptics on iOS) | | clipboard | Clipboard API | Read/write clipboard | | share | Web Share API | Native share sheet | | permissions | Permissions API | Permission management |

Enhanced APIs

Extended functionality beyond web standards:

| Module | Description | | ---------- | ----------------------------------------------------- | | haptics | iOS haptic feedback (impact, notification, selection) | | print | AirPrint functionality | | platform | Platform detection and device info |

iOS-Specific Modules (Namespaced)

Native iOS features without web equivalents, namespaced under ios.*:

| Module | Description | | ------------------- | --------------------------------- | | ios.biometrics | Face ID / Touch ID authentication | | ios.secureStorage | Keychain storage | | ios.healthKit | HealthKit data access | | ios.storeKit | In-app purchases (StoreKit 2) | | ios.app | App lifecycle and reviews | | ios.notifications | Local notification scheduling |

Web API Alignment

PWAKit SDK methods are designed to match Web Platform API signatures as closely as possible:

| SDK Module | Web Standard | Alignment | | ------------- | ----------------------------------------------------------------------------------- | --------------------------------------------------------------------- | | push | PushManager | Exact match - subscribe(), getSubscription(), permissionState() | | badging | Badging API | Exact match - setAppBadge(), clearAppBadge() | | vibration | Vibration API | Exact match - vibrate(pattern) (polyfills with haptics on iOS) | | clipboard | Clipboard API | Text methods - writeText(), readText() | | share | Web Share API | Match - share(), async canShare() | | permissions | Permissions API | Match with extension - query() + request() |

Intentional Deviations

These deviations improve the developer experience on mobile:

  • clipboard.readText() returns string | null instead of throwing when clipboard is empty
  • share.canShare() is async to check native availability (Web API is sync)
  • share.share() returns ShareResult with completed and activityType (Web returns void)
  • permissions.request() is an extension for pre-prompting (not in Web standard)

Web API-Aligned Modules

Push (PushManager)

import { push } from "@pwa-kit/sdk";

// Subscribe to push notifications
const subscription = await push.subscribe();
console.log("Token:", subscription.token);
console.log("Endpoint:", subscription.endpoint); // apns://token

// Get existing subscription
const existing = await push.getSubscription();
if (existing) {
  console.log("Already subscribed");
}

// Check permission state
const state = await push.permissionState();
// 'granted' | 'denied' | 'prompt'

Badging (Badging API)

import { badging } from "@pwa-kit/sdk";

// Set badge count
await badging.setAppBadge(5);

// Clear badge
await badging.clearAppBadge();

Vibration (Vibration API)

import { vibration } from "@pwa-kit/sdk";

// Vibrate (triggers haptic on iOS)
await vibration.vibrate(100);
await vibration.vibrate([100, 50, 100]); // Pattern

Clipboard (Clipboard API)

import { clipboard } from "@pwa-kit/sdk";

// Write text
await clipboard.writeText("Hello, World!");

// Read text
const text = await clipboard.readText();

Share (Web Share API)

import { share } from "@pwa-kit/sdk";

// Share URL
await share.share({
  title: "Check this out",
  url: "https://example.com",
});

// Share with files
await share.share({
  title: "Document",
  files: [
    {
      name: "report.pdf",
      type: "application/pdf",
      data: "base64encodeddata...",
    },
  ],
});

// Check availability
const canShare = await share.canShare();

Permissions (Permissions API)

import { permissions } from "@pwa-kit/sdk";

// Query permission state
const status = await permissions.query({ name: "camera" });
console.log("Camera:", status.state); // 'granted' | 'denied' | 'prompt'

// Request permission
const result = await permissions.request({ name: "geolocation" });

// Supported permissions: 'camera', 'geolocation', 'microphone'

Enhanced APIs

Haptics

Native iOS haptic feedback with impact, notification, and selection patterns.

import { haptics } from "@pwa-kit/sdk";

// Impact feedback
await haptics.impact("light"); // light, medium, heavy, soft, rigid
await haptics.impact("medium");
await haptics.impact("heavy");

// Notification feedback
await haptics.notification("success"); // success, warning, error
await haptics.notification("error");

// Selection feedback
await haptics.selection();

Print

AirPrint support for the current page.

import { print } from "@pwa-kit/sdk";

const result = await print.print();
if (result.success) {
  console.log("Print job submitted");
}

Platform

Platform detection and device information.

import { platform } from "@pwa-kit/sdk";

const info = await platform.getInfo();
// {
//   platform: 'ios',
//   version: '17.0',
//   isNative: true,
//   appVersion: '1.0.0',
//   buildNumber: '42',
//   deviceModel: 'iPhone15,2'
// }

iOS-Specific Modules

These modules are namespaced under ios.* as they don't have web equivalents.

ios.biometrics

Face ID and Touch ID authentication.

import { ios } from "@pwa-kit/sdk";

// Check availability
const availability = await ios.biometrics.isAvailable();
// { available: true, biometryType: 'faceId' }

// Authenticate
const result = await ios.biometrics.authenticate("Confirm your identity");
if (result.success) {
  // Authentication successful
}

ios.secureStorage

Keychain-backed secure storage that persists across app reinstalls.

import { ios } from "@pwa-kit/sdk";

// Store value
await ios.secureStorage.set("auth_token", "secret123");

// Retrieve value
const token = await ios.secureStorage.get("auth_token");

// Check if key exists
const exists = await ios.secureStorage.has("auth_token");

// Delete value
await ios.secureStorage.delete("auth_token");

ios.healthKit

Access health and fitness data via Apple HealthKit.

import { ios } from "@pwa-kit/sdk";

// Check availability
const { available } = await ios.healthKit.isAvailable();

// Request authorization
const auth = await ios.healthKit.requestAuthorization({
  read: ["stepCount", "heartRate"],
  readWorkouts: true,
  readSleep: true,
});

// Query steps
const steps = await ios.healthKit.querySteps({
  startDate: "2024-01-01T00:00:00Z",
  endDate: "2024-01-31T23:59:59Z",
});

// Query heart rate
const heartRate = await ios.healthKit.queryHeartRate({
  startDate: "2024-01-01T00:00:00Z",
  endDate: "2024-01-31T23:59:59Z",
});

// Query workouts
const workouts = await ios.healthKit.queryWorkouts({
  startDate: "2024-01-01T00:00:00Z",
  endDate: "2024-01-31T23:59:59Z",
  limit: 10,
});

// Query sleep
const sleep = await ios.healthKit.querySleep({
  startDate: "2024-01-01T00:00:00Z",
  endDate: "2024-01-31T23:59:59Z",
});

// Save workout
await ios.healthKit.saveWorkout({
  activityType: "running",
  startDate: "2024-01-15T08:00:00Z",
  endDate: "2024-01-15T08:30:00Z",
  duration: 1800,
  totalEnergyBurned: 350,
  totalDistance: 5000,
});

ios.storeKit

In-app purchases via StoreKit 2.

import { ios } from "@pwa-kit/sdk";

// Get products
const products = await ios.storeKit.getProducts(["premium", "coins_100"]);
for (const product of products) {
  console.log(`${product.displayName}: ${product.displayPrice}`);
}

// Purchase
const result = await ios.storeKit.purchase("premium");
if (result.success) {
  console.log("Transaction ID:", result.transactionId);
}

// Restore purchases
await ios.storeKit.restore();

// Get entitlements
const entitlements = await ios.storeKit.getEntitlements();
console.log("Owned:", entitlements.ownedProductIds);

// Check ownership
const hasPremium = await ios.storeKit.isOwned("premium");

ios.app

App lifecycle and utilities.

import { ios } from "@pwa-kit/sdk";

// Get app version
const version = await ios.app.getVersion();
// { version: '1.0.0', build: '42' }

// Request App Store review
await ios.app.requestReview();

// Open app settings
await ios.app.openSettings();

ios.notifications

Local notification scheduling. Schedule one-off or recurring notifications that fire even when the app is in the background.

import { ios } from "@pwa-kit/sdk";

// Schedule a notification in 60 seconds
await ios.notifications.schedule({
  id: "reminder-123",
  title: "Time for a break",
  body: "You have been working for an hour",
  trigger: { type: "timeInterval", seconds: 60 },
});

// Schedule a repeating notification (minimum 60 seconds)
await ios.notifications.schedule({
  id: "hourly",
  title: "Hourly check-in",
  trigger: { type: "timeInterval", seconds: 3600, repeats: true },
});

// Schedule at a specific date
await ios.notifications.schedule({
  id: "meeting",
  title: "Meeting starts",
  body: "Project sync in conference room A",
  trigger: { type: "date", date: new Date("2024-12-25T10:00:00") },
});

// Schedule a daily recurring notification (9 AM)
await ios.notifications.schedule({
  id: "daily-reminder",
  title: "Good morning!",
  body: "Start your day with a review",
  trigger: { type: "calendar", hour: 9, minute: 0, repeats: true },
});

// Include badge, sound, and custom data
await ios.notifications.schedule({
  id: "full-example",
  title: "New message",
  body: "You have a new message",
  subtitle: "From John",
  badge: 1,
  sound: "default",
  data: { messageId: "123", senderId: "john" },
  trigger: { type: "timeInterval", seconds: 5 },
});

// Cancel a specific notification
await ios.notifications.cancel("reminder-123");

// Cancel all scheduled notifications
await ios.notifications.cancelAll();

// Get all pending notifications
const pending = await ios.notifications.getPending();
for (const notification of pending) {
  console.log(`${notification.id}: ${notification.title}`);
  if (notification.nextTriggerDate) {
    console.log(`  Next: ${notification.nextTriggerDate}`);
  }
}

Trigger Types:

| Type | Description | Example | | -------------- | -------------------------- | --------------------------------------------------------- | | timeInterval | Fire after N seconds | { type: 'timeInterval', seconds: 60, repeats: false } | | date | Fire at specific date/time | { type: 'date', date: new Date('2024-12-25T10:00:00') } | | calendar | Fire on calendar match | { type: 'calendar', hour: 9, minute: 0, repeats: true } |

Calendar Trigger Components:

  • hour (0-23), minute (0-59), second (0-59)
  • weekday (1=Sunday, 7=Saturday)
  • day (1-31), month (1-12), year

Note: iOS limits apps to 64 scheduled local notifications. Use getPending() to monitor your notification count.

Detection Utilities

import {
  isNative,
  getPlatformInfo,
  hasMessageHandlers,
} from "@pwa-kit/sdk";

// Quick check if running in native app
if (isNative) {
  // Use native features
}

// Full platform info
const info = getPlatformInfo();
// {
//   isNative: true,
//   hasMessageHandlers: true,
//   hasPWAKitUserAgent: true,
//   platform: 'ios',
//   userAgent: '...'
// }

// Check for webkit message handlers
if (hasMessageHandlers()) {
  // Bridge is available
}

Bridge API

For advanced usage, access the bridge directly.

import { bridge } from "@pwa-kit/sdk";

// Call any native module
const response = await bridge.call("myModule", "myAction", { key: "value" });

// Listen to native events
window.addEventListener("pwa:push", (event) => {
  console.log("Push notification:", event.detail);
});

window.addEventListener("pwa:lifecycle", (event) => {
  console.log("Lifecycle event:", event.detail);
});

Custom Modules

You can extend PWAKit by creating your own native Swift modules that can be called from JavaScript.

Quick Example

Swift Module:

public struct MyModule: PWAModule {
    public static let moduleName = "myModule"
    public static let supportedActions = ["doSomething"]

    public init() {}

    public func handle(
        action: String,
        payload: AnyCodable?,
        context: ModuleContext
    ) async throws -> AnyCodable? {
        try validateAction(action)

        switch action {
        case "doSomething":
            let value = payload?["value"]?.stringValue ?? "default"
            return AnyCodable([
                "result": AnyCodable("Processed: \(value)")
            ])
        default:
            throw BridgeError.unknownAction(action)
        }
    }
}

JavaScript Usage:

import { bridge } from "@pwa-kit/sdk";

const result = await bridge.call("myModule", "doSomething", { value: "test" });
console.log(result.result); // "Processed: test"

See the Custom Modules Guide for complete documentation including:

  • The PWAModule protocol
  • Registration and feature flags
  • Working with UIKit and @MainActor
  • Error handling patterns
  • Complete Hello World example

TypeScript

Full TypeScript support with type definitions for all modules.

import type {
  // Push types
  PushSubscription,
  PushPermissionState,
  // Permission types
  PermissionName,
  PermissionState,
  PermissionStatus,
  // iOS types
  BiometryType,
  BiometricAvailability,
  AuthenticationResult,
  ProductInfo,
  PurchaseResult,
  HealthSample,
  WorkoutData,
  // Local notification types
  NotificationOptions,
  NotificationTrigger,
  TimeIntervalTrigger,
  DateTrigger,
  CalendarTrigger,
  PendingNotification,
  // Platform types
  PlatformInfo,
  PlatformDetectionInfo,
} from "@pwa-kit/sdk";

Browser Compatibility

The SDK safely handles non-native environments:

import { isNative, push, haptics } from "@pwa-kit/sdk";

if (isNative) {
  // Running in PWAKit native app
  await push.subscribe();
  await haptics.impact("medium");
} else {
  // Running in browser - provide fallbacks
  console.log("Native features unavailable");
  // Use web APIs or graceful degradation
}

License

MIT