{"version":3,"sources":["../../src/sse/index.ts","../../src/sse/apply-patch.ts","../../src/sse/broadcast.ts","../../src/sse/state-cache.ts","../../src/sse/presence.ts"],"sourcesContent":["/**\n * @packageDocumentation\n * @module act-http/sse\n *\n * Incremental state broadcast over SSE for act event-sourced apps.\n *\n * Server-side broadcast with domain patch forwarding, an LRU state cache,\n * presence tracking, and a client-side patch applicator with version\n * validation and resync detection.\n *\n * ## Architecture\n *\n * ```\n *   app.do() → snapshots (each carries its domain patch)\n *       │\n *       ▼\n *   deriveState(snap)          ← app-specific (overlay presence, deadlines, etc.)\n *   state._v = snap.event.version\n *       │\n *       ▼\n *   broadcast.publish(streamId, state, patches)\n *       │\n *       ├── version-key each patch: { [baseV+1]: patch1, [baseV+2]: patch2 }\n *       └── push to all SSE subscribers\n *       │\n *       ▼\n *   Client: applyPatchMessage(msg, cached)\n *       │\n *       ├── contiguous → deep-merge patches in version order\n *       ├── stale    → skip (client already ahead)\n *       └── behind   → resync (client missed versions)\n * ```\n *\n * ## Version Contract\n *\n * `_v` is always the event store stream version (`snap.event.version`).\n * No separate version counters. The event store is the single source of truth.\n */\n\nexport { patch } from \"@rotorsoft/act-patch\";\nexport type { ApplyResult } from \"./apply-patch.js\";\nexport { applyPatchMessage } from \"./apply-patch.js\";\nexport { BroadcastChannel } from \"./broadcast.js\";\nexport { PresenceTracker } from \"./presence.js\";\nexport { StateCache } from \"./state-cache.js\";\nexport type { BroadcastState, PatchMessage, Subscriber } from \"./types.js\";\n","import { patch as deep_merge } from \"@rotorsoft/act-patch\";\nimport type { BroadcastState, PatchMessage } from \"./types.js\";\n\n/**\n * Result of applying a patch message to cached client state.\n */\nexport type ApplyResult<S extends BroadcastState = BroadcastState> =\n  | { ok: true; state: S }\n  | { ok: false; reason: \"stale\" | \"behind\" };\n\n/**\n * Apply a version-keyed patch message to the client's cached state.\n *\n * ## Version logic\n *\n * - All patches older than cached → \"stale\" (client already ahead)\n * - Gap between cached version and first patch → \"behind\" (client missed versions, must resync)\n * - Contiguous from cached version → apply in order\n * - No baseline (fresh client) → the genesis patch (version 0) folds onto init\n *   state; a first patch at version ≥ 1 is \"behind\" (can't build from init)\n * - Overlay frame ({@link PatchMessage._overlay}) at the current version →\n *   merged on top of cached state, `_v` unchanged (presence / computed\n *   fields reach caught-up clients instead of being dropped as stale)\n *\n * ## Usage (React Query)\n *\n * ```typescript\n * onData: (msg) => {\n *   const cached = utils.get_state.get_data({ streamId });\n *   const result = applyPatchMessage(msg, cached);\n *   if (result.ok) {\n *     utils.get_state.setData({ streamId }, result.state);\n *   } else if (result.reason === \"behind\") {\n *     utils.get_state.invalidate({ streamId }); // trigger full refetch\n *   }\n *   // \"stale\" → no-op, client already has newer state\n * }\n * ```\n */\nexport function applyPatchMessage<S extends BroadcastState>(\n  msg: PatchMessage<S>,\n  cached: S | null | undefined\n): ApplyResult<S> {\n  // Distinguish an *absent* baseline from a real version-0 baseline (#1346).\n  // Act assigns the first event of any stream `version = 0`, so a fresh client\n  // (no cache) must resume from a pre-baseline watermark of -1 — otherwise the\n  // `?? 0` default collides with a genuine version-0 genesis patch and drops\n  // it as \"stale\". A present baseline keeps its own `_v`.\n  const hasBaseline = cached != null;\n  const cachedV = cached?._v ?? -1;\n  // `overlay` is a non-numeric marker key, not a version — exclude it.\n  const versions = Object.keys(msg)\n    .map(Number)\n    .filter((v) => Number.isInteger(v))\n    .sort((a, b) => a - b);\n\n  // Server-forced resync: it could not construct a patch (e.g. `overlay()`\n  // found the baseline evicted), so the client must refetch. Checked before\n  // anything else — a resync frame carries no versions, and the empty-frame\n  // branch below would otherwise report it as `stale`, which is the one\n  // answer that does NOT refetch (#1423).\n  if (msg._resync) return { ok: false, reason: \"behind\" };\n\n  // An empty frame carries nothing to apply. For a client that already has a\n  // baseline that is genuinely `stale` — a no-op, don't refetch. For one with\n  // NO baseline there is nothing to be stale relative to, and `stale` is the\n  // one answer that does not refetch, so it would strand the client (#1474).\n  // Both the doc-comment below and `real-time.md` already say a fresh client\n  // is never stale; this is the branch that made that false.\n  if (!versions.length)\n    return { ok: false, reason: hasBaseline ? \"stale\" : \"behind\" };\n\n  const minV = versions[0];\n  const maxV = versions[versions.length - 1];\n\n  // Overlay frame: a version-neutral update (presence, computed field) at the\n  // current version. Handled EXHAUSTIVELY here — an overlay must never reach\n  // the contiguous fold below, which would apply its payload as if it were\n  // that version's domain patch. At exactly `cachedV + 1` that fold made the\n  // client adopt presence data as version N, stamp itself caught up, and\n  // never refetch — the real update for N lost permanently (#1419).\n  if (msg._overlay) {\n    // No baseline to merge onto: the client must fetch one.\n    if (!cached) return { ok: false, reason: \"behind\" };\n    // Caught up: merge on top, keeping _v (an overlay changes no version).\n    if (maxV === cachedV)\n      return {\n        ok: true,\n        state: { ...deep_merge(cached, msg[maxV]), _v: cachedV },\n      };\n    // Ahead by any amount: the client missed at least one domain patch.\n    if (maxV > cachedV) return { ok: false, reason: \"behind\" };\n    // Older than the baseline: genuinely stale.\n    return { ok: false, reason: \"stale\" };\n  }\n\n  // A present baseline that already covers these versions is stale. A fresh\n  // client (no baseline, cachedV = -1) can never be stale — its first\n  // contiguous update is the genesis version 0.\n  if (hasBaseline && maxV <= cachedV) return { ok: false, reason: \"stale\" };\n  // A gap between the baseline (or the init floor -1) and the first patch means\n  // missed versions — resync. For a fresh client this admits the genesis patch\n  // (minV 0 === -1 + 1) but rejects a first patch at version >= 1, which cannot\n  // be built from init state alone.\n  if (minV > cachedV + 1) return { ok: false, reason: \"behind\" };\n\n  // No baseline → fold the genesis patch(es) onto init state ({}).\n  let state = (cached ?? {}) as S;\n  for (const v of versions) {\n    if (v <= cachedV) continue;\n    state = { ...deep_merge(state, msg[v]), _v: v } as S;\n  }\n  return { ok: true, state };\n}\n","import { patch as apply_patch } from \"@rotorsoft/act-patch\";\nimport { StateCache } from \"./state-cache.js\";\nimport type { BroadcastState, PatchMessage, Subscriber } from \"./types.js\";\n\n/**\n * Server-side broadcast channel for incremental state sync over SSE.\n *\n * Manages per-stream subscriber sets and an LRU state cache. When state\n * changes, forwards domain patches (from event handlers) to all subscribers\n * as version-keyed messages.\n *\n * ## Usage\n *\n * ```typescript\n * const broadcast = new BroadcastChannel<MyState>();\n *\n * // After every app.do():\n * const snaps = await app.do(...);\n * const patches = snaps.map(s => s.patch).filter(Boolean);\n * const state = deriveState(snaps.at(-1));\n * broadcast.publish(streamId, state, patches);\n *\n * // In SSE subscription:\n * const cleanup = broadcast.subscribe(streamId, (msg) => {\n *   pending = msg;\n *   resolve?.();\n * });\n *\n * // Initial state for reconnects:\n * const cached = broadcast.state(streamId);\n * ```\n *\n * ## Version Contract\n *\n * The `_v` field on state MUST be set from `snap.event.version` (the event\n * store's monotonic stream version) BEFORE calling `publish()`. This is the\n * single source of truth for ordering — no separate version counters.\n */\n/**\n * Deliver a frame to every subscriber, containing each one individually.\n *\n * SSE subscribers are the least-trusted callbacks in the system — one per\n * connection, driven by network state. The unguarded loop this replaces let\n * the first thrower abort iteration, so every later subscriber lost the\n * frame and the exception escaped into the host's commit path (#1423). Same\n * containment principle the orchestrator applies to lifecycle listeners.\n * Guarding each callback rather than the loop is the point: one guard around\n * the whole loop would still let the first throw suppress the rest.\n *\n * @internal\n */\nfunction fan_out<S extends BroadcastState>(\n  subs: Set<Subscriber<S>> | undefined,\n  msg: PatchMessage<S>,\n  on_error: (error: unknown) => void\n): void {\n  if (!subs?.size) return;\n  for (const cb of subs) {\n    try {\n      cb(msg);\n    } catch (error) {\n      on_error(error);\n    }\n  }\n}\n\n/**\n * Rewrite `undefined`-valued keys to `null`, recursively.\n *\n * `@rotorsoft/act-patch` treats `undefined` and `null` as the same delete\n * signal, but `JSON.stringify` drops `undefined`-valued keys entirely — and\n * every SSE transport serializes frames as JSON. A reducer that clears a\n * field the idiomatic way (`{ left: undefined }`) therefore produced a frame\n * with no mention of `left` at all, so a live client kept the stale value\n * while stamping the new version — believing itself caught up, and never\n * refetching (#1471).\n *\n * `null` reaches the same `delete` branch in the patch applicator and\n * survives JSON, so normalizing here makes the two spellings equivalent on\n * the wire as they already are in memory.\n *\n * Only the broadcast frame is normalized. Server-side state is applied\n * through `apply_patch`, which handles `undefined` natively.\n */\nconst wire_safe = <T>(patch: T): T => {\n  if (patch === null || typeof patch !== \"object\") return patch;\n  if (Array.isArray(patch)) return patch.map(wire_safe) as T;\n  // A Set has exactly one sensible JSON encoding, and `JSON.stringify` gives\n  // it the wrong one: `{}`. The framework's own `PresenceTracker.online()`\n  // returns a Set and the presence recipe feeds it straight to `overlay()`,\n  // so the documented way to broadcast presence shipped an empty object to\n  // every client — and then froze, because a client holding `{}` treats\n  // every later empty patch as a no-op (#1472).\n  if (patch instanceof Set) return [...patch].map(wire_safe) as T;\n  // Everything else non-plain (Date, Map, class instances) is left to\n  // whatever the host's serializer already does with it. `Date` has a\n  // defined encoding; `Map` does not have an unambiguous one (entries or\n  // object?), so guessing would trade a visible bug for a silent choice.\n  const proto = Object.getPrototypeOf(patch);\n  if (proto !== Object.prototype && proto !== null) return patch;\n  const out: Record<string, unknown> = {};\n  for (const [k, v] of Object.entries(patch as Record<string, unknown>))\n    out[k] = v === undefined ? null : wire_safe(v);\n  return out as T;\n};\n\n/**\n * Keys an `overlay()` contributed to a stream's cached state, carried on the\n * cached object itself.\n *\n * `publish()` replaces the cache entry with host-derived state, so overlay\n * data — presence, computed fields — vanished from the cache while live\n * clients, which had already applied the overlay frame, kept it. A\n * reconnecting client then reseeded WITHOUT it and had no way to notice: its\n * `_v` matches the server's, so nothing classifies as `behind` (#1473).\n *\n * A symbol keeps this out of `Object.keys`, `JSON.stringify` and therefore\n * off the wire; living on the cached object means it is evicted with the\n * entry rather than needing a parallel structure to prune.\n */\nconst OVERLAY_KEYS = Symbol(\"act.sse.overlay_keys\");\n\ntype WithOverlayKeys = { [OVERLAY_KEYS]?: ReadonlySet<string> };\n\n/**\n * Default `onSubscriberError` — routes through the framework logger, so a\n * throwing subscriber lands wherever the host already sends framework logs.\n *\n * The logger is reached through a dynamic import on purpose. This module sits\n * in the `sse` subpath alongside `applyPatchMessage` and the wire types, which\n * browser code imports; a static `import { log } from \"@rotorsoft/act\"` puts\n * the whole framework in that bundle, and the framework builds an\n * `AsyncLocalStorage` the moment it loads — a Node API the browser stubs out\n * and throws on. Only a server ever constructs a `BroadcastChannel`, so this\n * path never runs client-side, and the import stays out of the static graph\n * where the bundler would follow it.\n */\nconst default_subscriber_error = (error: unknown, streamId: string): void => {\n  void import(\"@rotorsoft/act\").then(({ log }) =>\n    log().error(error, `sse subscriber threw for \"${streamId}\"`)\n  );\n};\n\n/** Record which keys an overlay owns, accumulating across overlays. */\nconst tag_overlay_keys = <S extends object>(\n  state: S,\n  prev: S | undefined,\n  keys: readonly string[]\n): S => {\n  const carried = (prev as WithOverlayKeys | undefined)?.[OVERLAY_KEYS];\n  Object.defineProperty(state, OVERLAY_KEYS, {\n    value: new Set([...(carried ?? []), ...keys]),\n    enumerable: false,\n    configurable: true,\n  });\n  return state;\n};\n\nexport class BroadcastChannel<S extends BroadcastState = BroadcastState> {\n  private channels = new Map<string, Set<Subscriber<S>>>();\n  private state_cache: StateCache<S>;\n\n  /**\n   * @param options.cacheSize - Max number of stream states kept in the LRU\n   * cache (default 50).\n   */\n  private on_subscriber_error: (error: unknown, streamId: string) => void;\n  private on_overlay_miss: (streamId: string) => void;\n\n  constructor(options?: {\n    cacheSize?: number;\n    /**\n     * Called when `overlay()` finds no cached baseline for the stream, so\n     * the update cannot be broadcast. Live subscribers receive nothing and\n     * have no way to notice — a host that cares should raise `cacheSize`,\n     * re-`publish` the stream, or push the viewers to refetch. Defaults to a\n     * no-op so existing behavior is unchanged apart from being observable.\n     */\n    onOverlayMiss?: (streamId: string) => void;\n    /**\n     * Called when a subscriber callback throws. The frame is still delivered\n     * to every other subscriber and the publish still returns normally — a\n     * bad consumer must not break the publisher (#1423). Defaults to the\n     * framework's `log()` port, so it lands wherever the host already\n     * routes framework logs.\n     */\n    onSubscriberError?: (error: unknown, streamId: string) => void;\n    /**\n     * Deprecated alias of `cacheSize` — removal in the next major. When\n     * both are given, `cacheSize` wins.\n     * @deprecated use `cacheSize`\n     */\n    cache_size?: number;\n  }) {\n    this.state_cache = new StateCache<S>(\n      options?.cacheSize ?? options?.cache_size ?? 50\n    );\n    this.on_overlay_miss = options?.onOverlayMiss ?? (() => {});\n    this.on_subscriber_error =\n      options?.onSubscriberError ?? default_subscriber_error;\n  }\n\n  /**\n   * Publish domain patches from a commit.\n   * patches[i] corresponds to version baseV + i + 1.\n   *\n   * @param streamId - The event store stream ID\n   * @param state - Full state with `_v` set from `snap.event.version`\n   * @param patches - Array of domain patches, one per emitted event\n   */\n  publish(\n    streamId: string,\n    state: S,\n    patches: Partial<S>[] = []\n  ): PatchMessage<S> {\n    // Carry overlay-contributed keys across the commit (#1473). Only keys\n    // an `overlay()` actually owns, and only when the new domain state does\n    // not speak to them — so a publisher that drops or overwrites a key\n    // still wins, and presence survives a commit as the docs imply.\n    const prev = this.state_cache.get(streamId) as\n      | (S & WithOverlayKeys)\n      | undefined;\n    const overlay_keys = prev?.[OVERLAY_KEYS];\n    let cached = state;\n    if (overlay_keys?.size && prev) {\n      const carried = { ...state } as S;\n      const kept: string[] = [];\n      for (const key of overlay_keys)\n        if (!(key in state) && key in prev) {\n          (carried as Record<string, unknown>)[key] = (\n            prev as Record<string, unknown>\n          )[key];\n          kept.push(key);\n        }\n      cached = tag_overlay_keys(carried, undefined, kept);\n    }\n    this.state_cache.set(streamId, cached);\n\n    const baseV = state._v - patches.length;\n    const msg: PatchMessage<S> = {};\n    patches.forEach((p, i) => {\n      msg[baseV + i + 1] = wire_safe(p);\n    });\n\n    fan_out(this.channels.get(streamId), msg, (error) =>\n      this.on_subscriber_error(error, streamId)\n    );\n    return msg;\n  }\n\n  /**\n   * Publish a state update that doesn't change the event version\n   * (e.g. presence overlay, computed field refresh).\n   * Uses the same version as the cached state, single entry.\n   */\n  overlay(\n    streamId: string,\n    overlay_patch: Partial<S>\n  ): PatchMessage<S> | undefined {\n    const prev = this.state_cache.get(streamId);\n    if (!prev) {\n      // No baseline to read-modify-write, so nothing is broadcast — and\n      // because no frame is emitted there is nothing for a live client to\n      // classify as `behind`, so it never refetches either. Unlike a domain\n      // commit (which repopulates the cache via `publish`), an overlay-only\n      // stream never recovers. The defaults make this reachable rather than\n      // exotic: `cacheSize` is 50 while a host may hold far more live\n      // subscriptions, and cache promotion happens at connect time, so a\n      // busy-but-not-committing stream ages out while fully subscribed.\n      //\n      // Emit a resync frame so live subscribers refetch instead of silently\n      // missing the update forever (#1423). `on_overlay_miss` still fires so\n      // a host can count these — a steady stream of them means `cacheSize`\n      // is too small for the working set.\n      this.on_overlay_miss(streamId);\n      const resync: PatchMessage<S> = { _resync: true } as PatchMessage<S>;\n      fan_out(this.channels.get(streamId), resync, (error) =>\n        this.on_subscriber_error(error, streamId)\n      );\n      // Still `undefined`: no overlay state was produced, and callers use the\n      // return value as \"the patch I broadcast\", which a resync is not.\n      return undefined;\n    }\n\n    // Normalize BEFORE applying to the cache, so a reconnecting client's\n    // reseed and a live client's frame agree (#1472). `apply_patch` treats\n    // `null` and `undefined` as the same delete signal, so normalizing first\n    // does not change the delete semantics — it only fixes the encodings\n    // that would not survive JSON.\n    const safe_patch = wire_safe(overlay_patch);\n    const state = apply_patch(prev, safe_patch) as S;\n    this.state_cache.set(\n      streamId,\n      tag_overlay_keys(state, prev, Object.keys(safe_patch as object))\n    );\n\n    // `_overlay: true` marks this as a version-neutral update so a caught-up\n    // client applies it at the current version instead of dropping it as\n    // stale (the key equals the client's cachedV). Ordinary patches omit it.\n    const msg: PatchMessage<S> = {\n      [state._v]: safe_patch,\n      _overlay: true,\n    };\n    fan_out(this.channels.get(streamId), msg, (error) =>\n      this.on_subscriber_error(error, streamId)\n    );\n    return msg;\n  }\n\n  /**\n   * Subscribe to broadcast messages for a stream.\n   * Returns a cleanup function that removes the subscription.\n   */\n  subscribe(streamId: string, cb: Subscriber<S>): () => void {\n    if (!this.channels.has(streamId)) this.channels.set(streamId, new Set());\n    this.channels.get(streamId)!.add(cb);\n    return () => {\n      this.channels.get(streamId)?.delete(cb);\n      if (this.channels.get(streamId)?.size === 0) {\n        this.channels.delete(streamId);\n      }\n    };\n  }\n\n  /** Get the number of subscribers for a stream. */\n  subscriberCount(streamId: string): number {\n    return this.channels.get(streamId)?.size ?? 0;\n  }\n\n  /** Get the cached state for a stream (for reconnects / initial SSE yield). */\n  state(streamId: string): S | undefined {\n    return this.state_cache.get(streamId);\n  }\n\n  /** @deprecated use `overlay` — removal in the next major */\n  publish_overlay(\n    streamId: string,\n    overlay_patch: Partial<S>\n  ): PatchMessage<S> | undefined {\n    return this.overlay(streamId, overlay_patch);\n  }\n\n  /** @deprecated use `subscriberCount` — removal in the next major */\n  get_subscriber_count(streamId: string): number {\n    return this.subscriberCount(streamId);\n  }\n\n  /** @deprecated use `state` — removal in the next major */\n  get_state(streamId: string): S | undefined {\n    return this.state(streamId);\n  }\n\n  /** Direct access to the state cache (for app-specific reads like presence). */\n  get cache(): StateCache<S> {\n    return this.state_cache;\n  }\n}\n","import type { BroadcastState } from \"./types.js\";\n\n/**\n * Generic LRU cache for aggregate state objects.\n *\n * Keyed by stream ID. Each entry stores the full state (with `_v` from the\n * event store). Used as the \"previous state\" baseline for computing patches,\n * and as the fast path for reconnects.\n *\n * The cache is shared between the broadcast hot path and read queries.\n * Projections should maintain their own cache to avoid double-apply bugs.\n */\nexport class StateCache<S extends BroadcastState = BroadcastState> {\n  private cache = new Map<string, S>();\n  private maxSize: number;\n\n  constructor(maxSize = 50) {\n    this.maxSize = maxSize;\n  }\n\n  /** Get a cached state, promoting it to MRU position. */\n  get(key: string): S | undefined {\n    const s = this.cache.get(key);\n    if (s) {\n      this.cache.delete(key);\n      this.cache.set(key, s);\n    }\n    return s;\n  }\n\n  /** Set a cached state, evicting the LRU entry if at capacity. */\n  set(key: string, state: S): void {\n    this.cache.delete(key);\n    this.cache.set(key, state);\n    if (this.cache.size > this.maxSize) {\n      this.cache.delete(this.cache.keys().next().value!);\n    }\n  }\n\n  /** Remove a cached entry. */\n  delete(key: string): void {\n    this.cache.delete(key);\n  }\n\n  /** Check if a key exists in the cache. */\n  has(key: string): boolean {\n    return this.cache.has(key);\n  }\n\n  /** Current number of cached entries. */\n  get size(): number {\n    return this.cache.size;\n  }\n\n  /** Direct access to the underlying map (for iteration). */\n  entries(): IterableIterator<[string, S]> {\n    return this.cache.entries();\n  }\n}\n","/**\n * Generic presence tracker — ref-counted online status per stream per identity.\n *\n * Supports multi-tab: each subscribe increments the ref count, each\n * unsubscribe decrements it. An identity is considered online when\n * ref count > 0.\n *\n * ## Usage\n *\n * ```typescript\n * const presence = new PresenceTracker();\n *\n * // On SSE connect:\n * presence.add(game_id, player_id);\n *\n * // On SSE disconnect:\n * presence.remove(game_id, player_id);\n *\n * // Query:\n * presence.online(game_id); // Set<string>\n * ```\n */\nexport class PresenceTracker {\n  private streams = new Map<string, Map<string, number>>();\n\n  /** Increment ref count for an identity on a stream. */\n  add(streamId: string, identity_id: string): void {\n    if (!this.streams.has(streamId)) this.streams.set(streamId, new Map());\n    const counts = this.streams.get(streamId)!;\n    counts.set(identity_id, (counts.get(identity_id) ?? 0) + 1);\n  }\n\n  /** Decrement ref count. Removes the identity when count reaches 0. */\n  remove(streamId: string, identity_id: string): void {\n    const counts = this.streams.get(streamId);\n    if (!counts) return;\n    const n = (counts.get(identity_id) ?? 1) - 1;\n    if (n <= 0) counts.delete(identity_id);\n    else counts.set(identity_id, n);\n    if (counts.size === 0) this.streams.delete(streamId);\n  }\n\n  /** Get the set of online identity IDs for a stream. */\n  online(streamId: string): Set<string> {\n    const counts = this.streams.get(streamId);\n    return counts ? new Set(counts.keys()) : new Set();\n  }\n\n  /** Check if a specific identity is online for a stream. */\n  isOnline(streamId: string, identity_id: string): boolean {\n    return (this.streams.get(streamId)?.get(identity_id) ?? 0) > 0;\n  }\n\n  /** @deprecated use `online` — removal in the next major */\n  get_online(streamId: string): Set<string> {\n    return this.online(streamId);\n  }\n\n  /** @deprecated use `isOnline` — removal in the next major */\n  is_online(streamId: string, identity_id: string): boolean {\n    return this.isOnline(streamId, identity_id);\n  }\n}\n"],"mappings":"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","names":["import_act_patch","deep_merge","import_act_patch","patch","apply_patch"]}