{"version":3,"file":"ricardojbd-ngrx-signals-broadcast-sync.mjs","sources":["../../../../libs/ngrx-signals-broadcast-sync/src/lib/with-broadcast-sync.ts","../../../../libs/ngrx-signals-broadcast-sync/src/ricardojbd-ngrx-signals-broadcast-sync.ts"],"sourcesContent":["import {\n  signalStoreFeature,\n  SignalStoreFeature,\n  SignalStoreFeatureResult,\n  withMethods,\n  withHooks,\n  getState,\n  patchState\n} from '@ngrx/signals';\nimport { effect, inject, PLATFORM_ID } from '@angular/core';\nimport { isPlatformServer } from '@angular/common';\nimport isEqual from 'lodash.isequal';\nimport { Message, Options, BroadcastSyncFeatureResult } from './models';\n\nconst NOOP = () => null;\n\nconst BroadcastSyncStub: Pick<BroadcastSyncFeatureResult, 'methods'>['methods'] = {\n  getBroadcastChannel: NOOP,\n  broadcastState: NOOP,\n  _requestBroadcastState: NOOP,\n  _patchStateFromBroadcast: NOOP\n};\n\n/**\n * Adds broadcast synchronization capabilities to a Signal Store.\n *\n * This function enables state synchronization between multiple clients using the `BroadcastChannel` API.\n * It allows clients to request, send, and patch the state across multiple contexts.\n *\n * @template Input The type of the store feature result, extending `SignalStoreFeatureResult`.\n * @param channel The name of the broadcast channel to use for synchronizing state across clients.\n * @returns A Signal Store feature with broadcast capabilities.\n */\nexport function withBroadcastSync<Input extends SignalStoreFeatureResult>(\n  channel: string\n): SignalStoreFeature<Input, BroadcastSyncFeatureResult>;\n\n/**\n * Adds broadcast synchronization capabilities to a Signal Store.\n *\n * This function enables state synchronization between multiple clients using the `BroadcastChannel` API.\n * It allows clients to request, send, and patch the state across multiple contexts.\n *\n * @template Input The type of the store feature result, extending `SignalStoreFeatureResult`.\n * @param options A configuration object specifying the broadcast channel and additional behavior for state synchronization.\n * @returns A Signal Store feature with customizable broadcast capabilities.\n */\nexport function withBroadcastSync<Input extends SignalStoreFeatureResult>(\n  options: Options<Input['state']>\n): SignalStoreFeature<Input, BroadcastSyncFeatureResult>;\n\n/**\n * Adds broadcast synchronization capabilities to a Signal Store.\n *\n * This function enables state synchronization between multiple clients using the `BroadcastChannel` API.\n * It can be invoked either with a broadcast channel name or with a configuration object (`Options`).\n * It allows clients to request, send, and patch the state across multiple contexts.\n *\n * @template Input The type of the store feature result, extending `SignalStoreFeatureResult`.\n * @param channelOrOptions Either the name of the broadcast channel or a configuration object.\n * If a string is provided, it is treated as the broadcast channel name.\n * If an `Options` object is provided, it allows further configuration of the broadcast behavior.\n * @returns A Signal Store feature that adds methods for broadcast synchronization.\n */\nexport function withBroadcastSync<Input extends SignalStoreFeatureResult>(\n  channelOrOptions: Options<Input['state']> | string\n): SignalStoreFeature<Input, BroadcastSyncFeatureResult> {\n  const {\n    channel,\n    requestState = false,\n    select = (state: Input['state']) => state,\n    messageEventInterceptor = (event: MessageEvent<Message<Input['state']>>) => event.data,\n    broadcastStateInterceptor = (state: Input['state']) => state,\n    onMessageError = () => null\n  } = typeof channelOrOptions === 'string' ? { channel: channelOrOptions } : channelOrOptions;\n\n  const runGuard = (platformId: object) =>\n    isPlatformServer(platformId) || typeof window?.BroadcastChannel === 'undefined';\n  let stateChannel: BroadcastChannel | null;\n  let lastSyncedState: Partial<Input['state']> | null = null;\n\n  return signalStoreFeature(\n    withMethods((store, platformId = inject(PLATFORM_ID)) => {\n      if (runGuard(platformId)) {\n        console.warn(`'withBroadcastSync' provides non-functional implementation due to server-side execution`);\n        return BroadcastSyncStub;\n      }\n\n      return {\n        getBroadcastChannel(): BroadcastChannel | null {\n          return stateChannel;\n        },\n\n        broadcastState(): void {\n          let state = select(getState(store));\n\n          if (isEqual(state, lastSyncedState)) {\n            return;\n          }\n\n          state = broadcastStateInterceptor(state);\n\n          if (stateChannel != null) {\n            lastSyncedState = state; // Avoid broadcast duplicated state\n            stateChannel.postMessage({ type: 'UPDATE_STATE', state });\n          }\n        },\n\n        _requestBroadcastState(): void {\n          lastSyncedState = select(getState(store)); // Avoid broadcast initial state\n          stateChannel?.postMessage({ type: 'REQUEST_STATE' });\n        },\n\n        _patchStateFromBroadcast(state: Input['state']) {\n          lastSyncedState = state; // Avoid broadcast this state change\n          patchState(store, state);\n        }\n      };\n    }),\n    withHooks({\n      onInit(store, platformId = inject(PLATFORM_ID)) {\n        if (runGuard(platformId)) {\n          return;\n        }\n\n        stateChannel = new BroadcastChannel(channel);\n\n        if (requestState) {\n          store._requestBroadcastState();\n        }\n\n        stateChannel.onmessage = (event: MessageEvent<Message<Input['state']>>) => {\n          const message = messageEventInterceptor(event);\n\n          switch (message.type) {\n            case 'REQUEST_STATE': {\n              lastSyncedState = null; // Force broadcast state\n              store.broadcastState();\n              break;\n            }\n            case 'UPDATE_STATE': {\n              store._patchStateFromBroadcast(message.state);\n              break;\n            }\n            default: {\n              console.warn(`Unknown message type \"${message}\" in the broadcast channel \"${channel}\"`);\n            }\n          }\n        };\n\n        stateChannel.onmessageerror = (event: MessageEvent) => onMessageError(event);\n\n        effect(() => {\n          store.broadcastState();\n        });\n      },\n\n      onDestroy() {\n        stateChannel?.close();\n      }\n    })\n  );\n}\n","/**\n * Generated bundle index. Do not edit.\n */\n\nexport * from './index';\n"],"names":[],"mappings":"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"}