UNPKG

@aws-amplify/core

Version:

Core category of aws-amplify

139 lines (137 loc) • 4.76 kB
'use strict'; // Copyright Amazon.com, Inc. or its affiliates. All Rights Reserved. // SPDX-License-Identifier: Apache-2.0 Object.defineProperty(exports, "__esModule", { value: true }); exports.HubInternal = exports.Hub = exports.HubClass = exports.AMPLIFY_SYMBOL = void 0; const Logger_1 = require("../Logger"); const constants_1 = require("../constants"); const errors_1 = require("../errors"); exports.AMPLIFY_SYMBOL = (typeof Symbol !== 'undefined' ? Symbol('amplify_default') : '@@amplify_default'); const logger = new Logger_1.ConsoleLogger('Hub'); class HubClass { constructor(name) { this.listeners = new Map(); this.protectedChannels = [ 'core', 'auth', 'api', 'analytics', 'interactions', 'pubsub', 'storage', 'ui', 'xr', ]; this.name = name; } /** * Used internally to remove a Hub listener. * * @remarks * This private method is for internal use only. Instead of calling Hub.remove, call the result of Hub.listen. */ _remove(channel, listener) { const holder = this.listeners.get(channel); if (!holder) { logger.warn(`No listeners for ${channel}`); return; } this.listeners.set(channel, [ ...holder.filter(({ callback }) => callback !== listener), ]); } dispatch(channel, payload, source, ampSymbol, crossTab) { if (typeof channel === 'string' && this.protectedChannels.indexOf(channel) > -1) { const hasAccess = ampSymbol === exports.AMPLIFY_SYMBOL; if (!hasAccess) { logger.warn(`WARNING: ${channel} is protected and dispatching on it can have unintended consequences`); } } const capsule = { channel, crossTab, payload: { ...payload }, source, patternInfo: [], }; try { this._toListeners(capsule); } catch (e) { logger.error(e); } } listen(channel, callback, options = { listenerName: 'noname', }) { let cb; const o = typeof options === 'string' ? { listenerName: options, enableCrossTabEvents: false } : { listenerName: 'noname', enableCrossTabEvents: false, ...options }; if (typeof callback !== 'function') { throw new errors_1.AmplifyError({ name: constants_1.NO_HUBCALLBACK_PROVIDED_EXCEPTION, message: 'No callback supplied to Hub', }); } else { // Needs to be casted as a more generic type cb = callback; } let holder = this.listeners.get(channel); if (!holder) { holder = []; this.listeners.set(channel, holder); } holder.push({ name: o.listenerName, crossTab: o.enableCrossTabEvents, callback: cb, }); return () => { this._remove(channel, cb); }; } _toListeners(capsule) { const { channel, payload, crossTab } = capsule; const holder = this.listeners.get(channel); if (holder) { const eligibleListeners = holder.filter(listener => { // Cross-tab dispatch: only cross-tab listeners on the 'auth' // channel are eligible (cross-tab events are auth-only). if (crossTab) { return !!listener.crossTab && channel === 'auth'; } // Same-tab dispatch: every listener is eligible — cross-tab // listeners form a superset and therefore ALSO receive same-tab // events, while plain listeners receive same-tab events only. return true; }); eligibleListeners.forEach(listener => { logger.debug(`Dispatching to ${channel} with `, payload); try { listener.callback(capsule); } catch (e) { logger.error(e); } }); } } } exports.HubClass = HubClass; /* We export a __default__ instance of HubClass to use it as a pseudo Singleton for the main messaging bus, however you can still create your own instance of HubClass() for a separate "private bus" of events. */ exports.Hub = new HubClass('__default__'); /** * @internal * * Internal hub used for core Amplify functionality. Not intended for use outside of Amplify. * */ exports.HubInternal = new HubClass('internal-hub'); //# sourceMappingURL=index.js.map