"use strict"; // The require scope var __webpack_require__ = {}; /************************************************************************/ // webpack/runtime/define_property_getters (()=>{ __webpack_require__.d = function(exports1, definition) { for(var key in definition)if (__webpack_require__.o(definition, key) && !__webpack_require__.o(exports1, key)) Object.defineProperty(exports1, key, { enumerable: true, get: definition[key] }); }; })(); // webpack/runtime/has_own_property (()=>{ __webpack_require__.o = function(obj, prop) { return Object.prototype.hasOwnProperty.call(obj, prop); }; })(); // webpack/runtime/make_namespace_object (()=>{ // define __esModule on exports __webpack_require__.r = function(exports1) { if ('undefined' != typeof Symbol && Symbol.toStringTag) Object.defineProperty(exports1, Symbol.toStringTag, { value: 'Module' }); Object.defineProperty(exports1, '__esModule', { value: true }); }; })(); /************************************************************************/ var __webpack_exports__ = {}; // ESM COMPAT FLAG __webpack_require__.r(__webpack_exports__); // EXPORTS __webpack_require__.d(__webpack_exports__, { createSharedState: ()=>/* binding */ createSharedState }); class SharedState { store; channel; merger; filter; unsubscribe; isConnected; isRemoteUpdate; lastUpdateTime; constructor(store, channel, merger, filter){ this.store = store; this.channel = channel; this.merger = merger; this.filter = filter; this.unsubscribe = null; this.isConnected = false; this.isRemoteUpdate = false; this.lastUpdateTime = 0; } connect() { if (this.isConnected) return; this.isConnected = true; this.channel.connect(); this.subscribe(); } disconnect() { if (!this.isConnected) return; if (this.unsubscribe) { this.unsubscribe(); this.unsubscribe = null; } this.channel.disconnect(); this.isConnected = false; } subscribe() { this.channel.subscribe((message)=>{ if (!message) { this.broadcastCurrentState(); return; } if (message.time <= this.lastUpdateTime) return; this.handleRemoteUpdate(message); }); this.unsubscribe = this.store.subscribe(()=>{ if (!this.isRemoteUpdate) this.broadcastCurrentState(); this.isRemoteUpdate = false; }); } broadcastCurrentState() { const currentState = this.filter.filter(this.store.getState()); this.channel.broadcast(currentState); } handleRemoteUpdate(message) { this.isRemoteUpdate = true; this.lastUpdateTime = message.time; const currentState = this.filter.filter(this.store.getState()); const mergedState = this.merger.merge(currentState, message.state); this.store.patchState(mergedState); } } class TabChannel { instant; requestChannel; updateChannel; constructor(name, instant = true){ this.instant = instant; this.requestChannel = new BroadcastChannel(`${name}:request`); this.updateChannel = new BroadcastChannel(`${name}:update`); } connect() { if (this.instant) this.requestChannel.postMessage(null); } disconnect() { this.requestChannel.close(); this.updateChannel.close(); } broadcast(state) { this.updateChannel.postMessage({ state, time: Date.now() }); } subscribe(handler) { this.requestChannel.addEventListener('message', ()=>{ handler(null); }); this.updateChannel.addEventListener('message', (event)=>{ handler(event.data); }); } } class PathFilter { pickedPaths; omittedPaths; constructor(pickPaths = [], omitPaths = []){ this.pickedPaths = new Set(pickPaths); this.omittedPaths = new Set(omitPaths); } filter(state) { if (!this.pickedPaths.size && !this.omittedPaths.size) return state; const picked = this.pickedPaths.size ? this.pick(state) : state; return this.omittedPaths.size ? this.omit(picked) : picked; } pick(state, parentPath = '') { const result = {}; for (const [key, value] of Object.entries(state)){ const currentPath = parentPath ? `${parentPath}.${key}` : key; if (this.isPickedPath(currentPath)) { if (this.isNestedObject(value)) { const picked = this.pick(value, currentPath); if (Object.keys(picked).length > 0) result[key] = picked; } else result[key] = value; } } return result; } omit(state, parentPath = '') { const result = {}; for (const [key, value] of Object.entries(state)){ const currentPath = parentPath ? `${parentPath}.${key}` : key; if (!this.omittedPaths.has(currentPath)) { if (this.isNestedObject(value)) { const filtered = this.omit(value, currentPath); if (Object.keys(filtered).length > 0) result[key] = filtered; } else result[key] = value; } } return result; } isPickedPath(path) { if (this.pickedPaths.has(path)) return true; for (const pickedPath of this.pickedPaths)if (pickedPath.startsWith(`${path}.`) || path.startsWith(`${pickedPath}.`)) return true; return false; } isNestedObject(value) { return 'object' == typeof value && null !== value && !Array.isArray(value); } } class OverwriteMerger { merge(oldState, newState) { return newState; } } class ShallowMerger { merge(oldState, newState) { return { ...oldState, ...newState }; } } class DeepMerger { merge(oldState, newState) { if (!this.isObject(oldState) || !this.isObject(newState)) return newState; const result = { ...oldState }; for(const key in newState)if (Object.prototype.hasOwnProperty.call(newState, key)) { const oldValue = oldState[key]; const newValue = newState[key]; result[key] = this.isObject(oldValue) && this.isObject(newValue) ? this.merge(oldValue, newValue) : newValue ?? oldValue; } return result; } isObject(value) { return 'object' == typeof value && null !== value && !Array.isArray(value); } } class PiniaAdapter { store; constructor(store){ this.store = store; } getState() { return this.toRaw(this.store.$state); } patchState(partialState) { this.store.$patch(partialState); } subscribe(callback) { return this.store.$subscribe(()=>callback()); } toRaw(state) { return JSON.parse(JSON.stringify(state)); } } class SharedStateBuilder { static DEFAULT_OPTIONS = { channel: (id)=>id, instant: true, mergeStrategy: 'overwrite', pickPaths: [], omitPaths: [] }; store; channel; filter; merger; setStore(store) { this.store = store; return this; } setChannel(storeId, channelFn = SharedStateBuilder.DEFAULT_OPTIONS.channel, instant = SharedStateBuilder.DEFAULT_OPTIONS.instant) { this.channel = new TabChannel(channelFn(storeId), instant); return this; } setMerger(strategy = SharedStateBuilder.DEFAULT_OPTIONS.mergeStrategy) { if ('function' == typeof strategy) { this.merger = { merge: strategy }; return this; } switch(strategy){ case 'overwrite': this.merger = new OverwriteMerger(); break; case 'shallow': this.merger = new ShallowMerger(); break; case 'deep': this.merger = new DeepMerger(); break; default: } return this; } setFilter(pickPaths = SharedStateBuilder.DEFAULT_OPTIONS.pickPaths, omitPaths = SharedStateBuilder.DEFAULT_OPTIONS.omitPaths) { this.filter = new PathFilter(pickPaths, omitPaths); return this; } build() { if (!this.store || !this.channel || !this.merger || !this.filter) throw new Error('SharedState is not configured properly'); return new SharedState(this.store, this.channel, this.merger, this.filter); } static fromOptions(store, options) { return new SharedStateBuilder().setStore(new PiniaAdapter(store)).setChannel(store.$id, options.channel, options.instant).setMerger(options.mergeStrategy).setFilter(options.pickPaths, options.omitPaths).build(); } } function createSharedState(globalOptions = {}) { const { auto, ...commonOptions } = globalOptions; return ({ store, options })=>{ if (!options.sharedState && true !== auto) return; let sharedState; sharedState = 'object' == typeof options.sharedState ? SharedStateBuilder.fromOptions(store, { ...commonOptions, ...options.sharedState }) : SharedStateBuilder.fromOptions(store, commonOptions); sharedState.connect(); const $dispose = store.$dispose; store.$dispose = ()=>{ sharedState.disconnect(); $dispose(); }; }; } var __webpack_export_target__ = exports; for(var i in __webpack_exports__)__webpack_export_target__[i] = __webpack_exports__[i]; if (__webpack_exports__.__esModule) Object.defineProperty(__webpack_export_target__, '__esModule', { value: true });