UNPKG

@ricardojbd/ngrx-signals-broadcast-sync

Version:

Enables seamless synchronization of state between browser contexts

95 lines 16.7 kB
import { signalStoreFeature, withMethods, withHooks, getState, patchState } from '@ngrx/signals'; import { effect, inject, PLATFORM_ID } from '@angular/core'; import { isPlatformServer } from '@angular/common'; import isEqual from 'lodash.isequal'; const NOOP = () => null; const BroadcastSyncStub = { getBroadcastChannel: NOOP, broadcastState: NOOP, _requestBroadcastState: NOOP, _patchStateFromBroadcast: NOOP }; /** * Adds broadcast synchronization capabilities to a Signal Store. * * This function enables state synchronization between multiple clients using the `BroadcastChannel` API. * It can be invoked either with a broadcast channel name or with a configuration object (`Options`). * It allows clients to request, send, and patch the state across multiple contexts. * * @template Input The type of the store feature result, extending `SignalStoreFeatureResult`. * @param channelOrOptions Either the name of the broadcast channel or a configuration object. * If a string is provided, it is treated as the broadcast channel name. * If an `Options` object is provided, it allows further configuration of the broadcast behavior. * @returns A Signal Store feature that adds methods for broadcast synchronization. */ export function withBroadcastSync(channelOrOptions) { const { channel, requestState = false, select = (state) => state, messageEventInterceptor = (event) => event.data, broadcastStateInterceptor = (state) => state, onMessageError = () => null } = typeof channelOrOptions === 'string' ? { channel: channelOrOptions } : channelOrOptions; const runGuard = (platformId) => isPlatformServer(platformId) || typeof window?.BroadcastChannel === 'undefined'; let stateChannel; let lastSyncedState = null; return signalStoreFeature(withMethods((store, platformId = inject(PLATFORM_ID)) => { if (runGuard(platformId)) { console.warn(`'withBroadcastSync' provides non-functional implementation due to server-side execution`); return BroadcastSyncStub; } return { getBroadcastChannel() { return stateChannel; }, broadcastState() { let state = select(getState(store)); if (isEqual(state, lastSyncedState)) { return; } state = broadcastStateInterceptor(state); if (stateChannel != null) { lastSyncedState = state; // Avoid broadcast duplicated state stateChannel.postMessage({ type: 'UPDATE_STATE', state }); } }, _requestBroadcastState() { lastSyncedState = select(getState(store)); // Avoid broadcast initial state stateChannel?.postMessage({ type: 'REQUEST_STATE' }); }, _patchStateFromBroadcast(state) { lastSyncedState = state; // Avoid broadcast this state change patchState(store, state); } }; }), withHooks({ onInit(store, platformId = inject(PLATFORM_ID)) { if (runGuard(platformId)) { return; } stateChannel = new BroadcastChannel(channel); if (requestState) { store._requestBroadcastState(); } stateChannel.onmessage = (event) => { const message = messageEventInterceptor(event); switch (message.type) { case 'REQUEST_STATE': { lastSyncedState = null; // Force broadcast state store.broadcastState(); break; } case 'UPDATE_STATE': { store._patchStateFromBroadcast(message.state); break; } default: { console.warn(`Unknown message type "${message}" in the broadcast channel "${channel}"`); } } }; stateChannel.onmessageerror = (event) => onMessageError(event); effect(() => { store.broadcastState(); }); }, onDestroy() { stateChannel?.close(); } })); } //# sourceMappingURL=data:application/json;base64,eyJ2ZXJzaW9uIjozLCJmaWxlIjoid2l0aC1icm9hZGNhc3Qtc3luYy5qcyIsInNvdXJjZVJvb3QiOiIiLCJzb3VyY2VzIjpbIi4uLy4uLy4uLy4uLy4uL2xpYnMvbmdyeC1zaWduYWxzLWJyb2FkY2FzdC1zeW5jL3NyYy9saWIvd2l0aC1icm9hZGNhc3Qtc3luYy50cyJdLCJuYW1lcyI6W10sIm1hcHBpbmdzIjoiQUFBQSxPQUFPLEVBQ0wsa0JBQWtCLEVBR2xCLFdBQVcsRUFDWCxTQUFTLEVBQ1QsUUFBUSxFQUNSLFVBQVUsRUFDWCxNQUFNLGVBQWUsQ0FBQztBQUN2QixPQUFPLEVBQUUsTUFBTSxFQUFFLE1BQU0sRUFBRSxXQUFXLEVBQUUsTUFBTSxlQUFlLENBQUM7QUFDNUQsT0FBTyxFQUFFLGdCQUFnQixFQUFFLE1BQU0saUJBQWlCLENBQUM7QUFDbkQsT0FBTyxPQUFPLE1BQU0sZ0JBQWdCLENBQUM7QUFHckMsTUFBTSxJQUFJLEdBQUcsR0FBRyxFQUFFLENBQUMsSUFBSSxDQUFDO0FBRXhCLE1BQU0saUJBQWlCLEdBQTJEO0lBQ2hGLG1CQUFtQixFQUFFLElBQUk7SUFDekIsY0FBYyxFQUFFLElBQUk7SUFDcEIsc0JBQXNCLEVBQUUsSUFBSTtJQUM1Qix3QkFBd0IsRUFBRSxJQUFJO0NBQy9CLENBQUM7QUE4QkY7Ozs7Ozs7Ozs7OztHQVlHO0FBQ0gsTUFBTSxVQUFVLGlCQUFpQixDQUMvQixnQkFBa0Q7SUFFbEQsTUFBTSxFQUNKLE9BQU8sRUFDUCxZQUFZLEdBQUcsS0FBSyxFQUNwQixNQUFNLEdBQUcsQ0FBQyxLQUFxQixFQUFFLEVBQUUsQ0FBQyxLQUFLLEVBQ3pDLHVCQUF1QixHQUFHLENBQUMsS0FBNEMsRUFBRSxFQUFFLENBQUMsS0FBSyxDQUFDLElBQUksRUFDdEYseUJBQXlCLEdBQUcsQ0FBQyxLQUFxQixFQUFFLEVBQUUsQ0FBQyxLQUFLLEVBQzVELGNBQWMsR0FBRyxHQUFHLEVBQUUsQ0FBQyxJQUFJLEVBQzVCLEdBQUcsT0FBTyxnQkFBZ0IsS0FBSyxRQUFRLENBQUMsQ0FBQyxDQUFDLEVBQUUsT0FBTyxFQUFFLGdCQUFnQixFQUFFLENBQUMsQ0FBQyxDQUFDLGdCQUFnQixDQUFDO0lBRTVGLE1BQU0sUUFBUSxHQUFHLENBQUMsVUFBa0IsRUFBRSxFQUFFLENBQ3RDLGdCQUFnQixDQUFDLFVBQVUsQ0FBQyxJQUFJLE9BQU8sTUFBTSxFQUFFLGdCQUFnQixLQUFLLFdBQVcsQ0FBQztJQUNsRixJQUFJLFlBQXFDLENBQUM7SUFDMUMsSUFBSSxlQUFlLEdBQW1DLElBQUksQ0FBQztJQUUzRCxPQUFPLGtCQUFrQixDQUN2QixXQUFXLENBQUMsQ0FBQyxLQUFLLEVBQUUsVUFBVSxHQUFHLE1BQU0sQ0FBQyxXQUFXLENBQUMsRUFBRSxFQUFFO1FBQ3RELElBQUksUUFBUSxDQUFDLFVBQVUsQ0FBQyxFQUFFLENBQUM7WUFDekIsT0FBTyxDQUFDLElBQUksQ0FBQyx5RkFBeUYsQ0FBQyxDQUFDO1lBQ3hHLE9BQU8saUJBQWlCLENBQUM7UUFDM0IsQ0FBQztRQUVELE9BQU87WUFDTCxtQkFBbUI7Z0JBQ2pCLE9BQU8sWUFBWSxDQUFDO1lBQ3RCLENBQUM7WUFFRCxjQUFjO2dCQUNaLElBQUksS0FBSyxHQUFHLE1BQU0sQ0FBQyxRQUFRLENBQUMsS0FBSyxDQUFDLENBQUMsQ0FBQztnQkFFcEMsSUFBSSxPQUFPLENBQUMsS0FBSyxFQUFFLGVBQWUsQ0FBQyxFQUFFLENBQUM7b0JBQ3BDLE9BQU87Z0JBQ1QsQ0FBQztnQkFFRCxLQUFLLEdBQUcseUJBQXlCLENBQUMsS0FBSyxDQUFDLENBQUM7Z0JBRXpDLElBQUksWUFBWSxJQUFJLElBQUksRUFBRSxDQUFDO29CQUN6QixlQUFlLEdBQUcsS0FBSyxDQUFDLENBQUMsbUNBQW1DO29CQUM1RCxZQUFZLENBQUMsV0FBVyxDQUFDLEVBQUUsSUFBSSxFQUFFLGNBQWMsRUFBRSxLQUFLLEVBQUUsQ0FBQyxDQUFDO2dCQUM1RCxDQUFDO1lBQ0gsQ0FBQztZQUVELHNCQUFzQjtnQkFDcEIsZUFBZSxHQUFHLE1BQU0sQ0FBQyxRQUFRLENBQUMsS0FBSyxDQUFDLENBQUMsQ0FBQyxDQUFDLGdDQUFnQztnQkFDM0UsWUFBWSxFQUFFLFdBQVcsQ0FBQyxFQUFFLElBQUksRUFBRSxlQUFlLEVBQUUsQ0FBQyxDQUFDO1lBQ3ZELENBQUM7WUFFRCx3QkFBd0IsQ0FBQyxLQUFxQjtnQkFDNUMsZUFBZSxHQUFHLEtBQUssQ0FBQyxDQUFDLG9DQUFvQztnQkFDN0QsVUFBVSxDQUFDLEtBQUssRUFBRSxLQUFLLENBQUMsQ0FBQztZQUMzQixDQUFDO1NBQ0YsQ0FBQztJQUNKLENBQUMsQ0FBQyxFQUNGLFNBQVMsQ0FBQztRQUNSLE1BQU0sQ0FBQyxLQUFLLEVBQUUsVUFBVSxHQUFHLE1BQU0sQ0FBQyxXQUFXLENBQUM7WUFDNUMsSUFBSSxRQUFRLENBQUMsVUFBVSxDQUFDLEVBQUUsQ0FBQztnQkFDekIsT0FBTztZQUNULENBQUM7WUFFRCxZQUFZLEdBQUcsSUFBSSxnQkFBZ0IsQ0FBQyxPQUFPLENBQUMsQ0FBQztZQUU3QyxJQUFJLFlBQVksRUFBRSxDQUFDO2dCQUNqQixLQUFLLENBQUMsc0JBQXNCLEVBQUUsQ0FBQztZQUNqQyxDQUFDO1lBRUQsWUFBWSxDQUFDLFNBQVMsR0FBRyxDQUFDLEtBQTRDLEVBQUUsRUFBRTtnQkFDeEUsTUFBTSxPQUFPLEdBQUcsdUJBQXVCLENBQUMsS0FBSyxDQUFDLENBQUM7Z0JBRS9DLFFBQVEsT0FBTyxDQUFDLElBQUksRUFBRSxDQUFDO29CQUNyQixLQUFLLGVBQWUsQ0FBQyxDQUFDLENBQUM7d0JBQ3JCLGVBQWUsR0FBRyxJQUFJLENBQUMsQ0FBQyx3QkFBd0I7d0JBQ2hELEtBQUssQ0FBQyxjQUFjLEVBQUUsQ0FBQzt3QkFDdkIsTUFBTTtvQkFDUixDQUFDO29CQUNELEtBQUssY0FBYyxDQUFDLENBQUMsQ0FBQzt3QkFDcEIsS0FBSyxDQUFDLHdCQUF3QixDQUFDLE9BQU8sQ0FBQyxLQUFLLENBQUMsQ0FBQzt3QkFDOUMsTUFBTTtvQkFDUixDQUFDO29CQUNELE9BQU8sQ0FBQyxDQUFDLENBQUM7d0JBQ1IsT0FBTyxDQUFDLElBQUksQ0FBQyx5QkFBeUIsT0FBTywrQkFBK0IsT0FBTyxHQUFHLENBQUMsQ0FBQztvQkFDMUYsQ0FBQztnQkFDSCxDQUFDO1lBQ0gsQ0FBQyxDQUFDO1lBRUYsWUFBWSxDQUFDLGNBQWMsR0FBRyxDQUFDLEtBQW1CLEVBQUUsRUFBRSxDQUFDLGNBQWMsQ0FBQyxLQUFLLENBQUMsQ0FBQztZQUU3RSxNQUFNLENBQUMsR0FBRyxFQUFFO2dCQUNWLEtBQUssQ0FBQyxjQUFjLEVBQUUsQ0FBQztZQUN6QixDQUFDLENBQUMsQ0FBQztRQUNMLENBQUM7UUFFRCxTQUFTO1lBQ1AsWUFBWSxFQUFFLEtBQUssRUFBRSxDQUFDO1FBQ3hCLENBQUM7S0FDRixDQUFDLENBQ0gsQ0FBQztBQUNKLENBQUMiLCJzb3VyY2VzQ29udGVudCI6WyJpbXBvcnQge1xuICBzaWduYWxTdG9yZUZlYXR1cmUsXG4gIFNpZ25hbFN0b3JlRmVhdHVyZSxcbiAgU2lnbmFsU3RvcmVGZWF0dXJlUmVzdWx0LFxuICB3aXRoTWV0aG9kcyxcbiAgd2l0aEhvb2tzLFxuICBnZXRTdGF0ZSxcbiAgcGF0Y2hTdGF0ZVxufSBmcm9tICdAbmdyeC9zaWduYWxzJztcbmltcG9ydCB7IGVmZmVjdCwgaW5qZWN0LCBQTEFURk9STV9JRCB9IGZyb20gJ0Bhbmd1bGFyL2NvcmUnO1xuaW1wb3J0IHsgaXNQbGF0Zm9ybVNlcnZlciB9IGZyb20gJ0Bhbmd1bGFyL2NvbW1vbic7XG5pbXBvcnQgaXNFcXVhbCBmcm9tICdsb2Rhc2guaXNlcXVhbCc7XG5pbXBvcnQgeyBNZXNzYWdlLCBPcHRpb25zLCBCcm9hZGNhc3RTeW5jRmVhdHVyZVJlc3VsdCB9IGZyb20gJy4vbW9kZWxzJztcblxuY29uc3QgTk9PUCA9ICgpID0+IG51bGw7XG5cbmNvbnN0IEJyb2FkY2FzdFN5bmNTdHViOiBQaWNrPEJyb2FkY2FzdFN5bmNGZWF0dXJlUmVzdWx0LCAnbWV0aG9kcyc+WydtZXRob2RzJ10gPSB7XG4gIGdldEJyb2FkY2FzdENoYW5uZWw6IE5PT1AsXG4gIGJyb2FkY2FzdFN0YXRlOiBOT09QLFxuICBfcmVxdWVzdEJyb2FkY2FzdFN0YXRlOiBOT09QLFxuICBfcGF0Y2hTdGF0ZUZyb21Ccm9hZGNhc3Q6IE5PT1Bcbn07XG5cbi8qKlxuICogQWRkcyBicm9hZGNhc3Qgc3luY2hyb25pemF0aW9uIGNhcGFiaWxpdGllcyB0byBhIFNpZ25hbCBTdG9yZS5cbiAqXG4gKiBUaGlzIGZ1bmN0aW9uIGVuYWJsZXMgc3RhdGUgc3luY2hyb25pemF0aW9uIGJldHdlZW4gbXVsdGlwbGUgY2xpZW50cyB1c2luZyB0aGUgYEJyb2FkY2FzdENoYW5uZWxgIEFQSS5cbiAqIEl0IGFsbG93cyBjbGllbnRzIHRvIHJlcXVlc3QsIHNlbmQsIGFuZCBwYXRjaCB0aGUgc3RhdGUgYWNyb3NzIG11bHRpcGxlIGNvbnRleHRzLlxuICpcbiAqIEB0ZW1wbGF0ZSBJbnB1dCBUaGUgdHlwZSBvZiB0aGUgc3RvcmUgZmVhdHVyZSByZXN1bHQsIGV4dGVuZGluZyBgU2lnbmFsU3RvcmVGZWF0dXJlUmVzdWx0YC5cbiAqIEBwYXJhbSBjaGFubmVsIFRoZSBuYW1lIG9mIHRoZSBicm9hZGNhc3QgY2hhbm5lbCB0byB1c2UgZm9yIHN5bmNocm9uaXppbmcgc3RhdGUgYWNyb3NzIGNsaWVudHMuXG4gKiBAcmV0dXJucyBBIFNpZ25hbCBTdG9yZSBmZWF0dXJlIHdpdGggYnJvYWRjYXN0IGNhcGFiaWxpdGllcy5cbiAqL1xuZXhwb3J0IGZ1bmN0aW9uIHdpdGhCcm9hZGNhc3RTeW5jPElucHV0IGV4dGVuZHMgU2lnbmFsU3RvcmVGZWF0dXJlUmVzdWx0PihcbiAgY2hhbm5lbDogc3RyaW5nXG4pOiBTaWduYWxTdG9yZUZlYXR1cmU8SW5wdXQsIEJyb2FkY2FzdFN5bmNGZWF0dXJlUmVzdWx0PjtcblxuLyoqXG4gKiBBZGRzIGJyb2FkY2FzdCBzeW5jaHJvbml6YXRpb24gY2FwYWJpbGl0aWVzIHRvIGEgU2lnbmFsIFN0b3JlLlxuICpcbiAqIFRoaXMgZnVuY3Rpb24gZW5hYmxlcyBzdGF0ZSBzeW5jaHJvbml6YXRpb24gYmV0d2VlbiBtdWx0aXBsZSBjbGllbnRzIHVzaW5nIHRoZSBgQnJvYWRjYXN0Q2hhbm5lbGAgQVBJLlxuICogSXQgYWxsb3dzIGNsaWVudHMgdG8gcmVxdWVzdCwgc2VuZCwgYW5kIHBhdGNoIHRoZSBzdGF0ZSBhY3Jvc3MgbXVsdGlwbGUgY29udGV4dHMuXG4gKlxuICogQHRlbXBsYXRlIElucHV0IFRoZSB0eXBlIG9mIHRoZSBzdG9yZSBmZWF0dXJlIHJlc3VsdCwgZXh0ZW5kaW5nIGBTaWduYWxTdG9yZUZlYXR1cmVSZXN1bHRgLlxuICogQHBhcmFtIG9wdGlvbnMgQSBjb25maWd1cmF0aW9uIG9iamVjdCBzcGVjaWZ5aW5nIHRoZSBicm9hZGNhc3QgY2hhbm5lbCBhbmQgYWRkaXRpb25hbCBiZWhhdmlvciBmb3Igc3RhdGUgc3luY2hyb25pemF0aW9uLlxuICogQHJldHVybnMgQSBTaWduYWwgU3RvcmUgZmVhdHVyZSB3aXRoIGN1c3RvbWl6YWJsZSBicm9hZGNhc3QgY2FwYWJpbGl0aWVzLlxuICovXG5leHBvcnQgZnVuY3Rpb24gd2l0aEJyb2FkY2FzdFN5bmM8SW5wdXQgZXh0ZW5kcyBTaWduYWxTdG9yZUZlYXR1cmVSZXN1bHQ+KFxuICBvcHRpb25zOiBPcHRpb25zPElucHV0WydzdGF0ZSddPlxuKTogU2lnbmFsU3RvcmVGZWF0dXJlPElucHV0LCBCcm9hZGNhc3RTeW5jRmVhdHVyZVJlc3VsdD47XG5cbi8qKlxuICogQWRkcyBicm9hZGNhc3Qgc3luY2hyb25pemF0aW9uIGNhcGFiaWxpdGllcyB0byBhIFNpZ25hbCBTdG9yZS5cbiAqXG4gKiBUaGlzIGZ1bmN0aW9uIGVuYWJsZXMgc3RhdGUgc3luY2hyb25pemF0aW9uIGJldHdlZW4gbXVsdGlwbGUgY2xpZW50cyB1c2luZyB0aGUgYEJyb2FkY2FzdENoYW5uZWxgIEFQSS5cbiAqIEl0IGNhbiBiZSBpbnZva2VkIGVpdGhlciB3aXRoIGEgYnJvYWRjYXN0IGNoYW5uZWwgbmFtZSBvciB3aXRoIGEgY29uZmlndXJhdGlvbiBvYmplY3QgKGBPcHRpb25zYCkuXG4gKiBJdCBhbGxvd3MgY2xpZW50cyB0byByZXF1ZXN0LCBzZW5kLCBhbmQgcGF0Y2ggdGhlIHN0YXRlIGFjcm9zcyBtdWx0aXBsZSBjb250ZXh0cy5cbiAqXG4gKiBAdGVtcGxhdGUgSW5wdXQgVGhlIHR5cGUgb2YgdGhlIHN0b3JlIGZlYXR1cmUgcmVzdWx0LCBleHRlbmRpbmcgYFNpZ25hbFN0b3JlRmVhdHVyZVJlc3VsdGAuXG4gKiBAcGFyYW0gY2hhbm5lbE9yT3B0aW9ucyBFaXRoZXIgdGhlIG5hbWUgb2YgdGhlIGJyb2FkY2FzdCBjaGFubmVsIG9yIGEgY29uZmlndXJhdGlvbiBvYmplY3QuXG4gKiBJZiBhIHN0cmluZyBpcyBwcm92aWRlZCwgaXQgaXMgdHJlYXRlZCBhcyB0aGUgYnJvYWRjYXN0IGNoYW5uZWwgbmFtZS5cbiAqIElmIGFuIGBPcHRpb25zYCBvYmplY3QgaXMgcHJvdmlkZWQsIGl0IGFsbG93cyBmdXJ0aGVyIGNvbmZpZ3VyYXRpb24gb2YgdGhlIGJyb2FkY2FzdCBiZWhhdmlvci5cbiAqIEByZXR1cm5zIEEgU2lnbmFsIFN0b3JlIGZlYXR1cmUgdGhhdCBhZGRzIG1ldGhvZHMgZm9yIGJyb2FkY2FzdCBzeW5jaHJvbml6YXRpb24uXG4gKi9cbmV4cG9ydCBmdW5jdGlvbiB3aXRoQnJvYWRjYXN0U3luYzxJbnB1dCBleHRlbmRzIFNpZ25hbFN0b3JlRmVhdHVyZVJlc3VsdD4oXG4gIGNoYW5uZWxPck9wdGlvbnM6IE9wdGlvbnM8SW5wdXRbJ3N0YXRlJ10+IHwgc3RyaW5nXG4pOiBTaWduYWxTdG9yZUZlYXR1cmU8SW5wdXQsIEJyb2FkY2FzdFN5bmNGZWF0dXJlUmVzdWx0PiB7XG4gIGNvbnN0IHtcbiAgICBjaGFubmVsLFxuICAgIHJlcXVlc3RTdGF0ZSA9IGZhbHNlLFxuICAgIHNlbGVjdCA9IChzdGF0ZTogSW5wdXRbJ3N0YXRlJ10pID0+IHN0YXRlLFxuICAgIG1lc3NhZ2VFdmVudEludGVyY2VwdG9yID0gKGV2ZW50OiBNZXNzYWdlRXZlbnQ8TWVzc2FnZTxJbnB1dFsnc3RhdGUnXT4+KSA9PiBldmVudC5kYXRhLFxuICAgIGJyb2FkY2FzdFN0YXRlSW50ZXJjZXB0b3IgPSAoc3RhdGU6IElucHV0WydzdGF0ZSddKSA9PiBzdGF0ZSxcbiAgICBvbk1lc3NhZ2VFcnJvciA9ICgpID0+IG51bGxcbiAgfSA9IHR5cGVvZiBjaGFubmVsT3JPcHRpb25zID09PSAnc3RyaW5nJyA/IHsgY2hhbm5lbDogY2hhbm5lbE9yT3B0aW9ucyB9IDogY2hhbm5lbE9yT3B0aW9ucztcblxuICBjb25zdCBydW5HdWFyZCA9IChwbGF0Zm9ybUlkOiBvYmplY3QpID0+XG4gICAgaXNQbGF0Zm9ybVNlcnZlcihwbGF0Zm9ybUlkKSB8fCB0eXBlb2Ygd2luZG93Py5Ccm9hZGNhc3RDaGFubmVsID09PSAndW5kZWZpbmVkJztcbiAgbGV0IHN0YXRlQ2hhbm5lbDogQnJvYWRjYXN0Q2hhbm5lbCB8IG51bGw7XG4gIGxldCBsYXN0U3luY2VkU3RhdGU6IFBhcnRpYWw8SW5wdXRbJ3N0YXRlJ10+IHwgbnVsbCA9IG51bGw7XG5cbiAgcmV0dXJuIHNpZ25hbFN0b3JlRmVhdHVyZShcbiAgICB3aXRoTWV0aG9kcygoc3RvcmUsIHBsYXRmb3JtSWQgPSBpbmplY3QoUExBVEZPUk1fSUQpKSA9PiB7XG4gICAgICBpZiAocnVuR3VhcmQocGxhdGZvcm1JZCkpIHtcbiAgICAgICAgY29uc29sZS53YXJuKGAnd2l0aEJyb2FkY2FzdFN5bmMnIHByb3ZpZGVzIG5vbi1mdW5jdGlvbmFsIGltcGxlbWVudGF0aW9uIGR1ZSB0byBzZXJ2ZXItc2lkZSBleGVjdXRpb25gKTtcbiAgICAgICAgcmV0dXJuIEJyb2FkY2FzdFN5bmNTdHViO1xuICAgICAgfVxuXG4gICAgICByZXR1cm4ge1xuICAgICAgICBnZXRCcm9hZGNhc3RDaGFubmVsKCk6IEJyb2FkY2FzdENoYW5uZWwgfCBudWxsIHtcbiAgICAgICAgICByZXR1cm4gc3RhdGVDaGFubmVsO1xuICAgICAgICB9LFxuXG4gICAgICAgIGJyb2FkY2FzdFN0YXRlKCk6IHZvaWQge1xuICAgICAgICAgIGxldCBzdGF0ZSA9IHNlbGVjdChnZXRTdGF0ZShzdG9yZSkpO1xuXG4gICAgICAgICAgaWYgKGlzRXF1YWwoc3RhdGUsIGxhc3RTeW5jZWRTdGF0ZSkpIHtcbiAgICAgICAgICAgIHJldHVybjtcbiAgICAgICAgICB9XG5cbiAgICAgICAgICBzdGF0ZSA9IGJyb2FkY2FzdFN0YXRlSW50ZXJjZXB0b3Ioc3RhdGUpO1xuXG4gICAgICAgICAgaWYgKHN0YXRlQ2hhbm5lbCAhPSBudWxsKSB7XG4gICAgICAgICAgICBsYXN0U3luY2VkU3RhdGUgPSBzdGF0ZTsgLy8gQXZvaWQgYnJvYWRjYXN0IGR1cGxpY2F0ZWQgc3RhdGVcbiAgICAgICAgICAgIHN0YXRlQ2hhbm5lbC5wb3N0TWVzc2FnZSh7IHR5cGU6ICdVUERBVEVfU1RBVEUnLCBzdGF0ZSB9KTtcbiAgICAgICAgICB9XG4gICAgICAgIH0sXG5cbiAgICAgICAgX3JlcXVlc3RCcm9hZGNhc3RTdGF0ZSgpOiB2b2lkIHtcbiAgICAgICAgICBsYXN0U3luY2VkU3RhdGUgPSBzZWxlY3QoZ2V0U3RhdGUoc3RvcmUpKTsgLy8gQXZvaWQgYnJvYWRjYXN0IGluaXRpYWwgc3RhdGVcbiAgICAgICAgICBzdGF0ZUNoYW5uZWw/LnBvc3RNZXNzYWdlKHsgdHlwZTogJ1JFUVVFU1RfU1RBVEUnIH0pO1xuICAgICAgICB9LFxuXG4gICAgICAgIF9wYXRjaFN0YXRlRnJvbUJyb2FkY2FzdChzdGF0ZTogSW5wdXRbJ3N0YXRlJ10pIHtcbiAgICAgICAgICBsYXN0U3luY2VkU3RhdGUgPSBzdGF0ZTsgLy8gQXZvaWQgYnJvYWRjYXN0IHRoaXMgc3RhdGUgY2hhbmdlXG4gICAgICAgICAgcGF0Y2hTdGF0ZShzdG9yZSwgc3RhdGUpO1xuICAgICAgICB9XG4gICAgICB9O1xuICAgIH0pLFxuICAgIHdpdGhIb29rcyh7XG4gICAgICBvbkluaXQoc3RvcmUsIHBsYXRmb3JtSWQgPSBpbmplY3QoUExBVEZPUk1fSUQpKSB7XG4gICAgICAgIGlmIChydW5HdWFyZChwbGF0Zm9ybUlkKSkge1xuICAgICAgICAgIHJldHVybjtcbiAgICAgICAgfVxuXG4gICAgICAgIHN0YXRlQ2hhbm5lbCA9IG5ldyBCcm9hZGNhc3RDaGFubmVsKGNoYW5uZWwpO1xuXG4gICAgICAgIGlmIChyZXF1ZXN0U3RhdGUpIHtcbiAgICAgICAgICBzdG9yZS5fcmVxdWVzdEJyb2FkY2FzdFN0YXRlKCk7XG4gICAgICAgIH1cblxuICAgICAgICBzdGF0ZUNoYW5uZWwub25tZXNzYWdlID0gKGV2ZW50OiBNZXNzYWdlRXZlbnQ8TWVzc2FnZTxJbnB1dFsnc3RhdGUnXT4+KSA9PiB7XG4gICAgICAgICAgY29uc3QgbWVzc2FnZSA9IG1lc3NhZ2VFdmVudEludGVyY2VwdG9yKGV2ZW50KTtcblxuICAgICAgICAgIHN3aXRjaCAobWVzc2FnZS50eXBlKSB7XG4gICAgICAgICAgICBjYXNlICdSRVFVRVNUX1NUQVRFJzoge1xuICAgICAgICAgICAgICBsYXN0U3luY2VkU3RhdGUgPSBudWxsOyAvLyBGb3JjZSBicm9hZGNhc3Qgc3RhdGVcbiAgICAgICAgICAgICAgc3RvcmUuYnJvYWRjYXN0U3RhdGUoKTtcbiAgICAgICAgICAgICAgYnJlYWs7XG4gICAgICAgICAgICB9XG4gICAgICAgICAgICBjYXNlICdVUERBVEVfU1RBVEUnOiB7XG4gICAgICAgICAgICAgIHN0b3JlLl9wYXRjaFN0YXRlRnJvbUJyb2FkY2FzdChtZXNzYWdlLnN0YXRlKTtcbiAgICAgICAgICAgICAgYnJlYWs7XG4gICAgICAgICAgICB9XG4gICAgICAgICAgICBkZWZhdWx0OiB7XG4gICAgICAgICAgICAgIGNvbnNvbGUud2FybihgVW5rbm93biBtZXNzYWdlIHR5cGUgXCIke21lc3NhZ2V9XCIgaW4gdGhlIGJyb2FkY2FzdCBjaGFubmVsIFwiJHtjaGFubmVsfVwiYCk7XG4gICAgICAgICAgICB9XG4gICAgICAgICAgfVxuICAgICAgICB9O1xuXG4gICAgICAgIHN0YXRlQ2hhbm5lbC5vbm1lc3NhZ2VlcnJvciA9IChldmVudDogTWVzc2FnZUV2ZW50KSA9PiBvbk1lc3NhZ2VFcnJvcihldmVudCk7XG5cbiAgICAgICAgZWZmZWN0KCgpID0+IHtcbiAgICAgICAgICBzdG9yZS5icm9hZGNhc3RTdGF0ZSgpO1xuICAgICAgICB9KTtcbiAgICAgIH0sXG5cbiAgICAgIG9uRGVzdHJveSgpIHtcbiAgICAgICAgc3RhdGVDaGFubmVsPy5jbG9zZSgpO1xuICAgICAgfVxuICAgIH0pXG4gICk7XG59XG4iXX0=