PWA

Full Progressive Web App support including service worker lifecycle management, install prompts, caching strategies, and offline-first capabilities. The PWA module communicates with a companion service worker file (aura-sw.js) via postMessage to configure caching at runtime. Access everything through Aura.pwa.

Quick Start

Register the service worker, define caching strategies, and handle install prompts in just a few lines.

js
// 1. Define caching strategies before registering
Aura.pwa.addStrategy({
  name: 'images',
  strategy: 'cache-first',
  match: /\.(png|jpg|webp|svg)$/,
  maxAge: 7 * 24 * 60 * 60 * 1000
});

// 2. Register the service worker
await Aura.pwa.register('/aura-sw.js');

// 3. Precache critical assets
Aura.pwa.precache(['/index.html', '/styles.css', '/app.js']);

// 4. Handle install prompt
Aura.pwa.onInstallPrompt(() => {
  showInstallBanner();
});

Service Worker Setup

Aura ships with a companion service worker file called aura-sw.js. Place it in your project root (or public directory) so the browser can register it at the top-level scope.

How it works

File structure

text
your-project/
  aura-sw.js        <-- Service worker (from Aura)
  index.html
  app.js            <-- Aura.pwa.register('/aura-sw.js')
  manifest.json

Cache versioning

The service worker uses a CACHE_PREFIX of "aura-cache-" and a CACHE_VERSION of "v1". Each strategy gets its own named cache in the format aura-cache-{name}-v1. Precached assets go into aura-cache-precache-v1. Old caches with the prefix but a different version are automatically deleted on activation.

register()

Register a service worker at the given path. Sends any previously configured strategies to the worker once it activates. Returns the ServiceWorkerRegistration on success, or null if service workers are not supported or registration fails.

async register(swPath: string, opts?: { scope?: string }): Promise<ServiceWorkerRegistration | null>
ParamTypeDescription
swPathstringPath to the service worker file.
opts.scopestring?Scope for the SW registration. Defaults to "/".

Returns: Promise<ServiceWorkerRegistration | null>

js
// Basic registration
const reg = await Aura.pwa.register('/aura-sw.js');

// With custom scope
const reg = await Aura.pwa.register('/sw.js', { scope: '/app/' });

// Guard against unsupported browsers
if (reg) {
  console.log('SW registered', reg.scope);
}

unregister()

Unregister the current service worker.

async unregister(): Promise<boolean>

Takes no arguments. Returns true if successfully unregistered, false if no SW was registered.

js
const success = await Aura.pwa.unregister();
console.log('Unregistered:', success);

onInstallPrompt()

Register a handler for the beforeinstallprompt event. If the event has already fired before this is called, the handler is invoked immediately with the captured event.

onInstallPrompt(handler: (e: Event) => void): void
ParamTypeDescription
handler(e: Event) => voidCallback that receives the beforeinstallprompt event.
js
Aura.pwa.onInstallPrompt((e) => {
  // Show your custom install UI
  installBanner.style.display = 'flex';
});

promptInstall()

Trigger the native install prompt. Must be called after onInstallPrompt has captured the event. Returns whether the user accepted.

async promptInstall(): Promise<boolean>

Takes no arguments. Returns true if the user accepted the install, false otherwise.

js
installBtn.addEventListener('click', async () => {
  const accepted = await Aura.pwa.promptInstall();
  if (accepted) {
    console.log('App installed!');
    installBanner.style.display = 'none';
  }
});

isStandalone()

Check if the app is currently running in standalone mode (installed PWA). Works on both Chromium and Safari.

isStandalone(): boolean

Takes no arguments. Returns true if running as an installed PWA.

js
if (Aura.pwa.isStandalone()) {
  // Hide browser-specific UI
  addressBar.style.display = 'none';
  console.log('Running as installed PWA');
}

onUpdate()

Listen for service worker updates. The handler fires when a new SW is installed while a previous one is still controlling the page (i.e., an update is available).

onUpdate(handler: (reg: ServiceWorkerRegistration) => void): void
ParamTypeDescription
handler(reg) => voidCallback that receives the ServiceWorkerRegistration.
js
Aura.pwa.onUpdate((reg) => {
  if (confirm('A new version is available. Reload?')) {
    Aura.pwa.skipWaiting();
    window.location.reload();
  }
});

checkForUpdate()

Force a service worker update check. Useful for long-lived tabs where you want to periodically check for new versions.

async checkForUpdate(): Promise<void>

Takes no arguments. Triggers an update check on the current registration.

js
// Check for updates every 30 minutes
setInterval(() => {
  Aura.pwa.checkForUpdate();
}, 30 * 60 * 1000);

// Or check on visibility change
document.addEventListener('visibilitychange', () => {
  if (document.visibilityState === 'visible') {
    Aura.pwa.checkForUpdate();
  }
});

skipWaiting()

Tell a waiting service worker to activate immediately. Sends a SKIP_WAITING message to the waiting worker. Typically called after the user confirms they want to update.

skipWaiting(): void

Takes no arguments. No-ops if there is no waiting worker.

js
// Activate the new worker and reload
Aura.pwa.skipWaiting();
window.location.reload();

addStrategy()

Add a caching strategy that the service worker will apply to matching requests. If the SW is already active, the strategy is sent immediately via postMessage.

addStrategy(strategy: CacheStrategy): void

CacheStrategy interface

PropertyTypeDescription
namestringUnique cache name (used as part of the cache key).
strategystringOne of: 'cache-first', 'network-first', 'stale-while-revalidate', 'network-only', 'cache-only'.
matchstring | RegExpURL pattern. Strings use includes() matching; RegExp uses .test().
maxAgenumber?Maximum cache age in milliseconds. Only used by cache-first.
js
// Cache images aggressively
Aura.pwa.addStrategy({
  name: 'images',
  strategy: 'cache-first',
  match: /\.(png|jpg|webp|gif|svg)$/,
  maxAge: 7 * 24 * 60 * 60 * 1000  // 7 days
});

// API calls: network first with cache fallback
Aura.pwa.addStrategy({
  name: 'api',
  strategy: 'network-first',
  match: '/api/'
});

// Static assets: serve stale, update in background
Aura.pwa.addStrategy({
  name: 'static',
  strategy: 'stale-while-revalidate',
  match: /\.(css|js|woff2?)$/
});

precache()

Send a list of URLs to the service worker for precaching. The SW will add them to the aura-cache-precache-v1 cache. Only works after the SW is active.

precache(urls: string[]): void
ParamTypeDescription
urlsstring[]Array of URLs to precache.
js
Aura.pwa.precache([
  '/',
  '/index.html',
  '/styles.css',
  '/app.js',
  '/offline.html',
  '/icons/logo-192.png'
]);

clearCache()

Delete a specific named cache or all caches. Useful for forcing a fresh start or clearing storage.

async clearCache(name?: string): Promise<boolean>
ParamTypeDescription
namestring?Cache name to delete. If omitted, deletes all caches.

Returns: true when complete.

js
// Clear a specific cache
await Aura.pwa.clearCache('aura-cache-images-v1');

// Nuclear option: clear everything
await Aura.pwa.clearCache();

registration

Getter that returns the current ServiceWorkerRegistration, or null if not registered.

get registration: ServiceWorkerRegistration | null
js
const reg = Aura.pwa.registration;
if (reg) {
  console.log('SW scope:', reg.scope);
  console.log('Active:', reg.active?.state);
}

isSupported

Getter that returns whether the browser supports service workers.

get isSupported: boolean
js
if (Aura.pwa.isSupported) {
  await Aura.pwa.register('/aura-sw.js');
} else {
  console.log('Service workers not supported');
}

Caching Strategies Guide

The Aura service worker supports five caching strategies. Choose the right one based on the type of resource and your freshness requirements.

cache-first

Serve from cache if available (and not expired via maxAge). Falls back to network, then caches the response. If both cache and network fail, serves a stale cached version if one exists. Best for static assets that rarely change.

network-first

Try the network first. If the request succeeds, cache the response. If the network fails, fall back to the cached version. Best for data that should be fresh but must work offline.

stale-while-revalidate

Return the cached version immediately (if available) while fetching an updated version in the background. The next request will get the fresh data. Best for content where speed matters more than absolute freshness.

network-only

Always go to the network. No caching at all. Best for requests that must never be stale (e.g., authentication, payments).

cache-only

Only serve from cache. Never goes to the network. Returns a 404 if the item is not cached. Best for precached assets that you know will always be available.

Full example: multi-strategy setup

js
// Images: cache aggressively for 7 days
Aura.pwa.addStrategy({
  name: 'images',
  strategy: 'cache-first',
  match: /\.(png|jpg|webp|gif|svg|ico)$/,
  maxAge: 7 * 24 * 60 * 60 * 1000
});

// Fonts: cache first, long expiry
Aura.pwa.addStrategy({
  name: 'fonts',
  strategy: 'cache-first',
  match: /\.(woff2?|ttf|otf|eot)$/,
  maxAge: 30 * 24 * 60 * 60 * 1000
});

// Static assets: fast but stays updated
Aura.pwa.addStrategy({
  name: 'static',
  strategy: 'stale-while-revalidate',
  match: /\.(css|js)$/
});

// API: fresh data with offline fallback
Aura.pwa.addStrategy({
  name: 'api',
  strategy: 'network-first',
  match: '/api/'
});

// Auth: never cache
Aura.pwa.addStrategy({
  name: 'auth',
  strategy: 'network-only',
  match: '/auth/'
});

// Register after strategies are configured
await Aura.pwa.register('/aura-sw.js');

// Precache the app shell
Aura.pwa.precache(['/', '/index.html', '/offline.html']);

// Handle updates gracefully
Aura.pwa.onUpdate(() => {
  showToast('Update available — click to refresh');
});