{"version":3,"sources":["../../event-target-impl/src/index.browser.ts","../src/async-iterable.ts","../src/data-publisher.ts","../src/demultiplex.ts","../src/reactive-store.ts"],"names":["AbortController","EventTarget"],"mappings":"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","file":"index.browser.mjs","sourcesContent":["export const AbortController = globalThis.AbortController;\nexport const EventTarget = globalThis.EventTarget;\n","import {\n    SOLANA_ERROR__INVARIANT_VIOLATION__SUBSCRIPTION_ITERATOR_MUST_NOT_POLL_BEFORE_RESOLVING_EXISTING_MESSAGE_PROMISE,\n    SOLANA_ERROR__INVARIANT_VIOLATION__SUBSCRIPTION_ITERATOR_STATE_MISSING,\n    SolanaError,\n} from '@solana/errors';\nimport { AbortController } from '@solana/event-target-impl';\n\nimport { DataPublisher } from './data-publisher';\n\ntype Config = Readonly<{\n    /**\n     * Triggering this abort signal will cause all iterators spawned from this iterator to return\n     * once they have published all queued messages.\n     */\n    abortSignal: AbortSignal;\n    /**\n     * Messages from this channel of `dataPublisher` will be the ones yielded through the iterators.\n     *\n     * Messages only begin to be queued after the first time an iterator begins to poll. Channel\n     * messages published before that time will be dropped.\n     */\n    dataChannelName: string;\n    // FIXME: It would be nice to be able to constrain the type of `dataPublisher` to one that\n    //        definitely supports the `dataChannelName` and `errorChannelName` channels, and\n    //        furthermore publishes `TData` on the `dataChannelName` channel. This is more difficult\n    //        than it should be: https://tsplay.dev/NlZelW\n    dataPublisher: DataPublisher;\n    /**\n     * Messages from this channel of `dataPublisher` will be the ones thrown through the iterators.\n     *\n     * Any new iterators created after the first error is encountered will reject with that error\n     * when polled.\n     */\n    errorChannelName: string;\n}>;\n\nconst enum PublishType {\n    DATA,\n    ERROR,\n}\n\ntype IteratorKey = symbol;\ntype IteratorState<TData> =\n    | {\n          __hasPolled: false;\n          publishQueue: (\n              | {\n                    __type: PublishType.DATA;\n                    data: TData;\n                }\n              | {\n                    __type: PublishType.ERROR;\n                    err: unknown;\n                }\n          )[];\n      }\n    | {\n          __hasPolled: true;\n          onData: (data: TData) => void;\n          onError: Parameters<ConstructorParameters<typeof Promise>[0]>[1];\n      };\n\nlet EXPLICIT_ABORT_TOKEN: symbol;\nfunction createExplicitAbortToken() {\n    // This function is an annoying workaround to prevent `process.env.NODE_ENV` from appearing at\n    // the top level of this module and thwarting an optimizing compiler's attempt to tree-shake.\n    return Symbol(\n        process.env.NODE_ENV !== \"production\"\n            ? \"This symbol is thrown from a socket's iterator when the connection is explicitly \" +\n                  'aborted by the user'\n            : undefined,\n    );\n}\n\nconst UNINITIALIZED = Symbol();\n\n/**\n * Returns an `AsyncIterable` given a data publisher.\n *\n * The iterable will produce iterators that vend messages published to `dataChannelName` and will\n * throw the first time a message is published to `errorChannelName`. Triggering the abort signal\n * will cause all iterators spawned from this iterator to return once they have published all queued\n * messages.\n *\n * Things to note:\n *\n * - If a message is published over a channel before the `AsyncIterator` attached to it has polled\n *   for the next result, the message will be queued in memory.\n * - Messages only begin to be queued after the first time an iterator begins to poll. Channel\n *   messages published before that time will be dropped.\n * - If there are messages in the queue and an error occurs, all queued messages will be vended to\n *   the iterator before the error is thrown.\n * - If there are messages in the queue and the abort signal fires, all queued messages will be\n *   vended to the iterator after which it will return.\n * - Any new iterators created after the first error is encountered will reject with that error when\n *   polled.\n *\n * @param config\n *\n * @example\n * ```ts\n * const iterable = createAsyncIterableFromDataPublisher({\n *     abortSignal: AbortSignal.timeout(10_000),\n *     dataChannelName: 'message',\n *     dataPublisher,\n *     errorChannelName: 'error',\n * });\n * try {\n *     for await (const message of iterable) {\n *         console.log('Got message', message);\n *     }\n * } catch (e) {\n *     console.error('An error was published to the error channel', e);\n * } finally {\n *     console.log(\"It's been 10 seconds; that's enough for now.\");\n * }\n * ```\n */\nexport function createAsyncIterableFromDataPublisher<TData>({\n    abortSignal,\n    dataChannelName,\n    dataPublisher,\n    errorChannelName,\n}: Config): AsyncIterable<TData> {\n    const iteratorState: Map<IteratorKey, IteratorState<TData>> = new Map();\n    function publishErrorToAllIterators(reason: unknown) {\n        for (const [iteratorKey, state] of iteratorState.entries()) {\n            if (state.__hasPolled) {\n                iteratorState.delete(iteratorKey);\n                state.onError(reason);\n            } else {\n                state.publishQueue.push({\n                    __type: PublishType.ERROR,\n                    err: reason,\n                });\n            }\n        }\n    }\n    const abortController = new AbortController();\n    abortSignal.addEventListener('abort', () => {\n        abortController.abort();\n        publishErrorToAllIterators((EXPLICIT_ABORT_TOKEN ||= createExplicitAbortToken()));\n    });\n    const options = { signal: abortController.signal } as const;\n    let firstError: unknown = UNINITIALIZED;\n    dataPublisher.on(\n        errorChannelName,\n        err => {\n            if (firstError === UNINITIALIZED) {\n                firstError = err;\n                abortController.abort();\n                publishErrorToAllIterators(err);\n            }\n        },\n        options,\n    );\n    dataPublisher.on(\n        dataChannelName,\n        data => {\n            iteratorState.forEach((state, iteratorKey) => {\n                if (state.__hasPolled) {\n                    const { onData } = state;\n                    iteratorState.set(iteratorKey, { __hasPolled: false, publishQueue: [] });\n                    onData(data as TData);\n                } else {\n                    state.publishQueue.push({\n                        __type: PublishType.DATA,\n                        data: data as TData,\n                    });\n                }\n            });\n        },\n        options,\n    );\n    return {\n        async *[Symbol.asyncIterator]() {\n            if (abortSignal.aborted) {\n                return;\n            }\n            if (firstError !== UNINITIALIZED) {\n                throw firstError;\n            }\n            const iteratorKey = Symbol();\n            iteratorState.set(iteratorKey, { __hasPolled: false, publishQueue: [] });\n            try {\n                while (true) {\n                    const state = iteratorState.get(iteratorKey);\n                    if (!state) {\n                        // There should always be state by now.\n                        throw new SolanaError(SOLANA_ERROR__INVARIANT_VIOLATION__SUBSCRIPTION_ITERATOR_STATE_MISSING);\n                    }\n                    if (state.__hasPolled) {\n                        // You should never be able to poll twice in a row.\n                        throw new SolanaError(\n                            SOLANA_ERROR__INVARIANT_VIOLATION__SUBSCRIPTION_ITERATOR_MUST_NOT_POLL_BEFORE_RESOLVING_EXISTING_MESSAGE_PROMISE,\n                        );\n                    }\n                    const publishQueue = state.publishQueue;\n                    try {\n                        if (publishQueue.length) {\n                            state.publishQueue = [];\n                            for (const item of publishQueue) {\n                                if (item.__type === PublishType.DATA) {\n                                    yield item.data;\n                                } else {\n                                    throw item.err;\n                                }\n                            }\n                        } else {\n                            yield await new Promise<TData>((resolve, reject) => {\n                                iteratorState.set(iteratorKey, {\n                                    __hasPolled: true,\n                                    onData: resolve,\n                                    onError: reject,\n                                });\n                            });\n                        }\n                    } catch (e) {\n                        if (e === (EXPLICIT_ABORT_TOKEN ||= createExplicitAbortToken())) {\n                            return;\n                        } else {\n                            throw e;\n                        }\n                    }\n                }\n            } finally {\n                iteratorState.delete(iteratorKey);\n            }\n        },\n    };\n}\n","import { TypedEventEmitter, TypedEventTarget } from './event-emitter';\n\ntype UnsubscribeFn = () => void;\n\n/**\n * Represents an object with an `on` function that you can call to subscribe to certain data over a\n * named channel.\n *\n * @example\n * ```ts\n * let dataPublisher: DataPublisher<{ error: SolanaError }>;\n * dataPublisher.on('data', handleData); // ERROR. `data` is not a known channel name.\n * dataPublisher.on('error', e => {\n *     console.error(e);\n * }); // OK.\n * ```\n */\nexport interface DataPublisher<TDataByChannelName extends Record<string, unknown> = Record<string, unknown>> {\n    /**\n     * Call this to subscribe to data over a named channel.\n     *\n     * @param channelName The name of the channel on which to subscribe for messages\n     * @param subscriber The function to call when a message becomes available\n     * @param options.signal An abort signal you can fire to unsubscribe\n     *\n     * @returns A function that you can call to unsubscribe\n     */\n    on<const TChannelName extends keyof TDataByChannelName>(\n        channelName: TChannelName,\n        subscriber: (data: TDataByChannelName[TChannelName]) => void,\n        options?: { signal: AbortSignal },\n    ): UnsubscribeFn;\n}\n\n/**\n * Returns an object with an `on` function that you can call to subscribe to certain data over a\n * named channel.\n *\n * The `on` function returns an unsubscribe function.\n *\n * @example\n * ```ts\n * const socketDataPublisher = getDataPublisherFromEventEmitter(new WebSocket('wss://api.devnet.solana.com'));\n * const unsubscribe = socketDataPublisher.on('message', message => {\n *     if (JSON.parse(message.data).id === 42) {\n *         console.log('Got response 42');\n *         unsubscribe();\n *     }\n * });\n * ```\n */\nexport function getDataPublisherFromEventEmitter<TEventMap extends Record<string, Event>>(\n    eventEmitter: TypedEventEmitter<TEventMap> | TypedEventTarget<TEventMap>,\n): DataPublisher<{\n    [TEventType in keyof TEventMap]: TEventMap[TEventType] extends CustomEvent ? TEventMap[TEventType]['detail'] : null;\n}> {\n    return {\n        on(channelName, subscriber, options) {\n            function innerListener(ev: Event) {\n                if (ev instanceof CustomEvent) {\n                    const data = (ev as CustomEvent<TEventMap[typeof channelName]>).detail;\n                    (subscriber as unknown as (data: TEventMap[typeof channelName]) => void)(data);\n                } else {\n                    (subscriber as () => void)();\n                }\n            }\n            eventEmitter.addEventListener(channelName, innerListener, options);\n            return () => {\n                eventEmitter.removeEventListener(channelName, innerListener);\n            };\n        },\n    };\n}\n","import { EventTarget } from '@solana/event-target-impl';\n\nimport { DataPublisher, getDataPublisherFromEventEmitter } from './data-publisher';\n\n/**\n * Given a channel that carries messages for multiple subscribers on a single channel name, this\n * function returns a new {@link DataPublisher} that splits them into multiple channel names.\n *\n * @param messageTransformer A function that receives the message as the first argument, and returns\n * a tuple of the derived channel name and the message.\n *\n * @example\n * Imagine a channel that carries multiple notifications whose destination is contained within the\n * message itself.\n *\n * ```ts\n * const demuxedDataPublisher = demultiplexDataPublisher(channel, 'message', message => {\n *     const destinationChannelName = `notification-for:${message.subscriberId}`;\n *     return [destinationChannelName, message];\n * });\n * ```\n *\n * Now you can subscribe to _only_ the messages you are interested in, without having to subscribe\n * to the entire `'message'` channel and filter out the messages that are not for you.\n *\n * ```ts\n * demuxedDataPublisher.on(\n *     'notification-for:123',\n *     message => {\n *         console.log('Got a message for subscriber 123', message);\n *     },\n *     { signal: AbortSignal.timeout(5_000) },\n * );\n * ```\n */\nexport function demultiplexDataPublisher<\n    TDataPublisher extends DataPublisher,\n    const TChannelName extends Parameters<TDataPublisher['on']>[0],\n>(\n    publisher: TDataPublisher,\n    sourceChannelName: TChannelName,\n    messageTransformer: (\n        // FIXME: Deriving the type of the message from `TDataPublisher` and `TChannelName` would\n        //        help callers to constrain their transform functions.\n        message: unknown,\n    ) => [destinationChannelName: string, message: unknown] | void,\n): DataPublisher {\n    let innerPublisherState:\n        | {\n              readonly dispose: () => void;\n              numSubscribers: number;\n          }\n        | undefined;\n    const eventTarget = new EventTarget();\n    const demultiplexedDataPublisher = getDataPublisherFromEventEmitter(eventTarget);\n    return {\n        ...demultiplexedDataPublisher,\n        on(channelName, subscriber, options) {\n            if (!innerPublisherState) {\n                const innerPublisherUnsubscribe = publisher.on(sourceChannelName, sourceMessage => {\n                    const transformResult = messageTransformer(sourceMessage);\n                    if (!transformResult) {\n                        return;\n                    }\n                    const [destinationChannelName, message] = transformResult;\n                    eventTarget.dispatchEvent(\n                        new CustomEvent(destinationChannelName, {\n                            detail: message,\n                        }),\n                    );\n                });\n                innerPublisherState = {\n                    dispose: innerPublisherUnsubscribe,\n                    numSubscribers: 0,\n                };\n            }\n            innerPublisherState.numSubscribers++;\n            const unsubscribe = demultiplexedDataPublisher.on(channelName, subscriber, options);\n            let isActive = true;\n            function handleUnsubscribe() {\n                if (!isActive) {\n                    return;\n                }\n                isActive = false;\n                options?.signal.removeEventListener('abort', handleUnsubscribe);\n                innerPublisherState!.numSubscribers--;\n                if (innerPublisherState!.numSubscribers === 0) {\n                    innerPublisherState!.dispose();\n                    innerPublisherState = undefined;\n                }\n                unsubscribe();\n            }\n            options?.signal.addEventListener('abort', handleUnsubscribe);\n            return handleUnsubscribe;\n        },\n    };\n}\n","import { AbortController } from '@solana/event-target-impl';\n\nimport { DataPublisher } from './data-publisher';\n\ntype Config = Readonly<{\n    /**\n     * Triggering this abort signal will cause the store to stop updating and will disconnect it from\n     * the underlying data publisher.\n     */\n    abortSignal: AbortSignal;\n    /**\n     * Messages from this channel of `dataPublisher` will be used to update the store's state.\n     */\n    dataChannelName: string;\n    // FIXME: It would be nice to be able to constrain the type of `dataPublisher` to one that\n    //        definitely supports the `dataChannelName` and `errorChannelName` channels, and\n    //        furthermore publishes `TData` on the `dataChannelName` channel. This is more difficult\n    //        than it should be: https://tsplay.dev/NlZelW\n    dataPublisher: DataPublisher;\n    /**\n     * Messages from this channel of `dataPublisher` will cause subscribers to be notified without\n     * updating the state, so that they can respond to the error condition.\n     */\n    errorChannelName: string;\n}>;\n\n/**\n * A reactive store that holds the latest value published to a data channel and allows external\n * systems to subscribe to changes. Compatible with `useSyncExternalStore`, Svelte stores, Solid's\n * `from()`, and other reactive primitives that expect a `{ subscribe, getState }` contract.\n *\n * @example\n * ```ts\n * // React — throw error from snapshot function to surface via Error Boundary\n * const state = useSyncExternalStore(store.subscribe, () => {\n *     if (store.getError()) throw store.getError();\n *     return store.getState();\n * });\n *\n * // Vue — check error reactively in a composable\n * const data = shallowRef(store.getState());\n * const error = shallowRef(store.getError());\n * store.subscribe(() => {\n *     data.value = store.getState();\n *     error.value = store.getError();\n * });\n * ```\n *\n * @see {@link createReactiveStoreFromDataPublisher}\n */\nexport type ReactiveStore<T> = {\n    /**\n     * Returns the error published to the error channel, or `undefined` if no error has occurred.\n     * Once set, the error is preserved — subsequent errors do not overwrite it.\n     */\n    getError(): unknown;\n    /**\n     * Returns the most recent value published to the data channel, or `undefined` if no\n     * notification has arrived yet. On error, continues to return the last known value.\n     */\n    getState(): T | undefined;\n    /**\n     * Registers a callback to be called whenever the state changes or an error is received.\n     * Returns an unsubscribe function. Safe to call multiple times.\n     */\n    subscribe(callback: () => void): () => void;\n};\n\n/**\n * Returns a {@link ReactiveStore} given a data publisher.\n *\n * The store will update its state with each message published to `dataChannelName` and notify all\n * subscribers. When a message is published to `errorChannelName`, subscribers are notified so they\n * can react to the error condition, but the last-known state is preserved. Triggering the abort\n * signal disconnects the store from the data publisher.\n *\n * Things to note:\n *\n * - `getState()` returns `undefined` until the first notification arrives.\n * - On error, `getState()` continues to return the last known value and `getError()` returns the\n *   error. Only the first error is captured.\n * - The function returned by `subscribe` is idempotent — calling it multiple times is safe.\n *\n * @param config\n *\n * @example\n * ```ts\n * const store = createReactiveStoreFromDataPublisher({\n *     abortSignal: AbortSignal.timeout(10_000),\n *     dataChannelName: 'notification',\n *     dataPublisher,\n *     errorChannelName: 'error',\n * });\n * const unsubscribe = store.subscribe(() => {\n *     console.log('State updated:', store.getState());\n * });\n * ```\n */\nexport function createReactiveStoreFromDataPublisher<TData>({\n    abortSignal,\n    dataChannelName,\n    dataPublisher,\n    errorChannelName,\n}: Config): ReactiveStore<TData> {\n    let currentState: TData | undefined;\n    let currentError: unknown;\n    const subscribers = new Set<() => void>();\n\n    const abortController = new AbortController();\n    abortSignal.addEventListener('abort', () => abortController.abort(abortSignal.reason));\n\n    dataPublisher.on(\n        dataChannelName,\n        data => {\n            currentState = data as TData;\n            subscribers.forEach(cb => cb());\n        },\n        { signal: abortController.signal },\n    );\n    dataPublisher.on(\n        errorChannelName,\n        err => {\n            if (currentError !== undefined) return;\n            currentError = err;\n            // Abort the signal passed to dataPublisher, which stops the subscriptions\n            abortController.abort(err);\n            subscribers.forEach(cb => cb());\n        },\n        { signal: abortController.signal },\n    );\n\n    return {\n        getError(): unknown {\n            return currentError;\n        },\n        getState(): TData | undefined {\n            return currentState;\n        },\n        subscribe(callback: () => void): () => void {\n            subscribers.add(callback);\n            return () => {\n                subscribers.delete(callback);\n            };\n        },\n    };\n}\n"]}