UNPKG

@aws-amplify/core

Version:

Core category of aws-amplify

1 lines 18.7 kB
{"version":3,"file":"ServiceWorker.mjs","sources":["../../../src/ServiceWorker/ServiceWorker.ts"],"sourcesContent":["// Copyright Amazon.com, Inc. or its affiliates. All Rights Reserved.\n// SPDX-License-Identifier: Apache-2.0\nimport { ConsoleLogger } from '../Logger';\nimport { isBrowser } from '../utils';\nimport { AmplifyError } from '../errors';\nimport { record } from '../providers/pinpoint';\nimport { Amplify, fetchAuthSession } from '../singleton';\nimport { ServiceWorkerErrorCode, assert } from './errorHelpers';\n/**\n * Provides a means to registering a service worker in the browser\n * and communicating with it via postMessage events.\n * https://developer.mozilla.org/en-US/docs/Web/API/Service_Worker_API/\n *\n * postMessage events are currently not supported in all browsers. See:\n * https://developer.mozilla.org/en-US/docs/Web/API/Service_Worker_API\n *\n * At the minmum this class will register the service worker and listen\n * and attempt to dispatch messages on state change and record analytics\n * events based on the service worker lifecycle.\n */\nexport class ServiceWorkerClass {\n constructor() {\n // The AWS Amplify logger\n this._logger = new ConsoleLogger('ServiceWorker');\n }\n /**\n * Get the currently active service worker\n */\n get serviceWorker() {\n assert(this._serviceWorker !== undefined, ServiceWorkerErrorCode.UndefinedInstance);\n return this._serviceWorker;\n }\n /**\n * Register the service-worker.js file in the browser\n * Make sure the service-worker.js is part of the build\n * for example with Angular, modify the angular-cli.json file\n * and add to \"assets\" array \"service-worker.js\"\n *\n * Note: when `options.onStateChange` is omitted, this method implicitly\n * records service worker lifecycle (`statechange`) events to Amazon\n * Pinpoint. That built-in auto-recording is deprecated and will be removed\n * in a future major version — only the implicit Pinpoint recording is\n * deprecated, not `register()` itself. Provide `options.onStateChange` to\n * observe lifecycle state changes and emit vendor-neutral telemetry instead.\n * @param {string} filePath Service worker file. Defaults to \"/service-worker.js\"\n * @param {string} scope The service worker scope. Defaults to \"/\"\n * - API Doc: https://developer.mozilla.org/en-US/docs/Web/API/ServiceWorkerContainer/register\n * @param {ServiceWorkerOptions} [options] Optional registration options. When\n * `onStateChange` is provided it is invoked on every service worker state\n * change and replaces the built-in Pinpoint auto-recording. It is also\n * invoked once with the worker's current state at registration time, so an\n * already-active worker (which dispatches no `statechange` event) is still\n * observed. This initial emit applies only to `onStateChange`; the built-in\n * Pinpoint path is unaffected.\n * @returns {Promise}\n *\t- resolve(ServiceWorkerRegistration)\n *\t- reject(Error)\n **/\n register(filePath = '/service-worker.js', scope = '/', options) {\n this._onStateChange = options?.onStateChange;\n this._logger.debug(`registering ${filePath}`);\n this._logger.debug(`registering service worker with scope ${scope}`);\n return new Promise((resolve, reject) => {\n if (navigator && 'serviceWorker' in navigator) {\n navigator.serviceWorker\n .register(filePath, {\n scope,\n })\n .then(registration => {\n if (registration.installing) {\n this._serviceWorker = registration.installing;\n }\n else if (registration.waiting) {\n this._serviceWorker = registration.waiting;\n }\n else if (registration.active) {\n this._serviceWorker = registration.active;\n }\n this._registration = registration;\n this._setupListeners();\n this._logger.debug(`Service Worker Registration Success: ${registration}`);\n resolve(registration);\n })\n .catch(error => {\n this._logger.debug(`Service Worker Registration Failed ${error}`);\n reject(new AmplifyError({\n name: ServiceWorkerErrorCode.Unavailable,\n message: 'Service Worker not available',\n underlyingError: error,\n }));\n });\n }\n else {\n reject(new AmplifyError({\n name: ServiceWorkerErrorCode.Unavailable,\n message: 'Service Worker not available',\n }));\n }\n });\n }\n /**\n * Enable web push notifications. If not subscribed, a new subscription will\n * be created and registered.\n * \tTest Push Server: https://web-push-codelab.glitch.me/\n * \tPush Server Libraries: https://github.com/web-push-libs/\n * \tAPI Doc: https://developers.google.com/web/fundamentals/codelabs/push-notifications/\n * @param publicKey\n * @returns {Promise}\n * \t- resolve(PushSubscription)\n * - reject(Error)\n */\n enablePush(publicKey) {\n assert(this._registration !== undefined, ServiceWorkerErrorCode.UndefinedRegistration);\n this._publicKey = publicKey;\n return new Promise((resolve, reject) => {\n if (isBrowser()) {\n assert(this._registration !== undefined, ServiceWorkerErrorCode.UndefinedRegistration);\n this._registration.pushManager.getSubscription().then(subscription => {\n if (subscription) {\n this._subscription = subscription;\n this._logger.debug(`User is subscribed to push: ${JSON.stringify(subscription)}`);\n resolve(subscription);\n }\n else {\n this._logger.debug(`User is NOT subscribed to push`);\n return this._registration.pushManager.subscribe({\n userVisibleOnly: true,\n applicationServerKey: this._urlB64ToUint8Array(publicKey),\n })\n .then(pushManagerSubscription => {\n this._subscription = pushManagerSubscription;\n this._logger.debug(`User subscribed: ${JSON.stringify(pushManagerSubscription)}`);\n resolve(pushManagerSubscription);\n })\n .catch(error => {\n this._logger.error(error);\n });\n }\n });\n }\n else {\n reject(new AmplifyError({\n name: ServiceWorkerErrorCode.Unavailable,\n message: 'Service Worker not available',\n }));\n }\n });\n }\n /**\n * Convert a base64 encoded string to a Uint8 array for the push server key\n * @param base64String\n */\n _urlB64ToUint8Array(base64String) {\n const padding = '='.repeat((4 - (base64String.length % 4)) % 4);\n const base64 = (base64String + padding)\n .replace(/-/g, '+')\n .replace(/_/g, '/');\n const rawData = window.atob(base64);\n const outputArray = new Uint8Array(rawData.length);\n for (let i = 0; i < rawData.length; ++i) {\n outputArray[i] = rawData.charCodeAt(i);\n }\n return outputArray;\n }\n /**\n * Send a message to the service worker. The service worker needs\n * to implement `self.addEventListener('message') to handle the\n * message. This ***currently*** does not work in Safari or IE.\n * @param {object | string} message An arbitrary JSON object or string message to send to the service worker\n *\t- see: https://developer.mozilla.org/en-US/docs/Web/API/Transferable\n * @returns {Promise}\n **/\n send(message) {\n if (this._serviceWorker) {\n this._serviceWorker.postMessage(typeof message === 'object' ? JSON.stringify(message) : message);\n }\n }\n /**\n * Listen for service worker state change and message events\n * https://developer.mozilla.org/en-US/docs/Web/API/ServiceWorker/state\n *\n * Each call to `register()` attaches its own `statechange` listener. The\n * `onStateChange` handler is captured in a local at listener-creation time,\n * so re-registering with a different handler only affects its own listener\n * and never re-targets a previously attached one.\n **/\n _setupListeners() {\n const onStateChange = this._onStateChange;\n this.serviceWorker.addEventListener('statechange', async () => {\n const currentState = this.serviceWorker.state;\n this._logger.debug(`ServiceWorker statechange: ${currentState}`);\n // Notify a consumer-provided handler, isolating any error it throws so\n // it cannot surface as an unhandled rejection from the listener.\n await this._notifyStateChange(onStateChange, currentState);\n // When no handler is provided, fall back to the built-in (deprecated)\n // Pinpoint auto-recording. A supplied handler overrides it, preventing\n // double-recording of the same state change.\n if (!onStateChange) {\n const { appId, region, bufferSize, flushInterval, flushSize, resendLimit, } = Amplify.getConfig().Analytics?.Pinpoint ?? {};\n const { credentials } = await fetchAuthSession();\n if (appId && region && credentials) {\n // Pinpoint is configured, record an event\n record({\n appId,\n region,\n category: 'Core',\n credentials,\n bufferSize,\n flushInterval,\n flushSize,\n resendLimit,\n event: {\n name: 'ServiceWorker',\n attributes: {\n state: currentState,\n },\n },\n });\n }\n }\n });\n // A worker that is already in a state when this listener is attached\n // (e.g. `activated` on a repeat visit, where `register()` resolves via\n // the `registration.active` branch) emits no `statechange` event, so the\n // consumer hook would otherwise never observe the current state. Notify\n // the hook once with the current state to close that gap. The built-in\n // Pinpoint path is intentionally NOT invoked here: doing so would change\n // existing (no-hook) behavior, which must remain identical to today.\n const initialState = this.serviceWorker.state;\n if (onStateChange && initialState) {\n this._logger.debug(`ServiceWorker initial state: ${initialState}`);\n this._notifyStateChange(onStateChange, initialState).catch(() => {\n // _notifyStateChange already logs handler errors; this catch only\n // satisfies the no-floating-promises contract for the fire-and-forget\n // initial emit.\n });\n }\n this.serviceWorker.addEventListener('message', event => {\n this._logger.debug(`ServiceWorker message event: ${event}`);\n });\n }\n /**\n * Invoke the consumer `onStateChange` handler with the given state, isolating\n * any error it throws (or rejects with, for an async handler) so it cannot\n * surface as an unhandled rejection. Awaiting the handler means a rejected\n * promise from an async handler is caught here too; `await undefined`\n * resolves immediately for sync or absent handlers.\n */\n async _notifyStateChange(onStateChange, state) {\n try {\n await onStateChange?.(state);\n }\n catch (e) {\n this._logger.error('onStateChange handler threw', e);\n }\n }\n}\n"],"names":[],"mappings":"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"}