{"version":3,"file":"index.cjs","sources":["../../src/index.ts"],"sourcesContent":["import {\n  DestroyRef,\n  assertInInjectionContext,\n  computed,\n  effect,\n  inject,\n  signal,\n} from '@angular/core'\nimport {\n  BaseQueryBuilder,\n  createLiveQueryObserver,\n  getPublicCollection,\n  isCollection,\n  isSingleResultCollection,\n  resolveLiveQueryValue,\n} from '@tanstack/db'\nimport type {\n  Collection,\n  CollectionStatus,\n  Context,\n  GetResult,\n  InferResultType,\n  InitialQueryBuilder,\n  LiveQueryCollectionConfig,\n  LiveQueryObserver,\n  LiveQueryPersistedStatus,\n  NonSingleResult,\n  QueryBuilder,\n  SingleResult,\n} from '@tanstack/db'\nimport type { Signal } from '@angular/core'\n\nconst DEFAULT_GC_TIME_MS = 1\n\nexport * from '@tanstack/db'\n\n/**\n * The result of calling `injectLiveQuery`.\n * Contains reactive signals for the query state and data.\n */\nexport interface InjectLiveQueryResult<TContext extends Context> {\n  /** A signal containing the complete state map of results keyed by their ID */\n  state: Signal<Map<string | number, GetResult<TContext>>>\n  /** A signal containing the results as an array, or single result for findOne queries */\n  data: Signal<InferResultType<TContext>>\n  /** A signal containing the underlying collection instance (null for disabled queries) */\n  collection: Signal<Collection<\n    GetResult<TContext>,\n    string | number,\n    {}\n  > | null>\n  /** A signal containing the current status of the collection */\n  status: Signal<CollectionStatus | `disabled`>\n  /** A signal indicating whether the collection is currently loading */\n  isLoading: Signal<boolean>\n  /** A signal indicating whether the collection is ready */\n  isReady: Signal<boolean>\n  persistedStatus: Signal<LiveQueryPersistedStatus>\n  isPersistedReady: Signal<boolean>\n  persistedError: Signal<unknown | undefined>\n  /** A signal indicating whether the collection is idle */\n  isIdle: Signal<boolean>\n  /** A signal indicating whether the collection has an error */\n  isError: Signal<boolean>\n  /** A signal indicating whether the collection has been cleaned up */\n  isCleanedUp: Signal<boolean>\n}\n\ntype InferConditionalResultType<TContext extends Context> =\n  TContext extends SingleResult\n    ? InferResultType<TContext> | []\n    : InferResultType<TContext>\n\nexport type InjectConditionalLiveQueryResult<TContext extends Context> = Omit<\n  InjectLiveQueryResult<TContext>,\n  `data`\n> & {\n  data: Signal<InferConditionalResultType<TContext>>\n}\n\nexport interface InjectLiveQueryResultWithCollection<\n  TResult extends object = any,\n  TKey extends string | number = string | number,\n  TUtils extends Record<string, any> = {},\n> {\n  state: Signal<Map<TKey, TResult>>\n  data: Signal<Array<TResult>>\n  collection: Signal<Collection<TResult, TKey, TUtils> | null>\n  status: Signal<CollectionStatus | `disabled`>\n  isLoading: Signal<boolean>\n  isReady: Signal<boolean>\n  persistedStatus: Signal<LiveQueryPersistedStatus>\n  isPersistedReady: Signal<boolean>\n  persistedError: Signal<unknown | undefined>\n  isIdle: Signal<boolean>\n  isError: Signal<boolean>\n  isCleanedUp: Signal<boolean>\n}\n\nexport interface InjectLiveQueryResultWithSingleResultCollection<\n  TResult extends object = any,\n  TKey extends string | number = string | number,\n  TUtils extends Record<string, any> = {},\n> {\n  state: Signal<Map<TKey, TResult>>\n  data: Signal<TResult | undefined>\n  collection: Signal<(Collection<TResult, TKey, TUtils> & SingleResult) | null>\n  status: Signal<CollectionStatus | `disabled`>\n  isLoading: Signal<boolean>\n  isReady: Signal<boolean>\n  persistedStatus: Signal<LiveQueryPersistedStatus>\n  isPersistedReady: Signal<boolean>\n  persistedError: Signal<unknown | undefined>\n  isIdle: Signal<boolean>\n  isError: Signal<boolean>\n  isCleanedUp: Signal<boolean>\n}\n\nexport function injectLiveQuery<\n  TContext extends Context,\n  TParams extends any,\n>(options: {\n  params: () => TParams\n  query: (args: {\n    params: TParams\n    q: InitialQueryBuilder\n  }) => QueryBuilder<TContext>\n}): InjectLiveQueryResult<TContext>\nexport function injectLiveQuery<\n  TContext extends Context,\n  TParams extends any,\n>(options: {\n  params: () => TParams\n  query: (args: {\n    params: TParams\n    q: InitialQueryBuilder\n  }) => QueryBuilder<TContext> | undefined | null\n}): InjectConditionalLiveQueryResult<TContext>\nexport function injectLiveQuery<TContext extends Context>(\n  queryFn: (q: InitialQueryBuilder) => QueryBuilder<TContext>,\n): InjectLiveQueryResult<TContext>\nexport function injectLiveQuery<TContext extends Context>(\n  queryFn: (\n    q: InitialQueryBuilder,\n  ) => QueryBuilder<TContext> | undefined | null,\n): InjectConditionalLiveQueryResult<TContext>\nexport function injectLiveQuery<TContext extends Context>(\n  config: LiveQueryCollectionConfig<TContext>,\n): InjectLiveQueryResult<TContext>\n// Pre-created collection without singleResult\nexport function injectLiveQuery<\n  TResult extends object,\n  TKey extends string | number,\n  TUtils extends Record<string, any>,\n>(\n  liveQueryCollection: Collection<TResult, TKey, TUtils> & NonSingleResult,\n): InjectLiveQueryResultWithCollection<TResult, TKey, TUtils>\n// Pre-created collection with singleResult\nexport function injectLiveQuery<\n  TResult extends object,\n  TKey extends string | number,\n  TUtils extends Record<string, any>,\n>(\n  liveQueryCollection: Collection<TResult, TKey, TUtils> & SingleResult,\n): InjectLiveQueryResultWithSingleResultCollection<TResult, TKey, TUtils>\nexport function injectLiveQuery(opts: any) {\n  assertInInjectionContext(injectLiveQuery)\n  const destroyRef = inject(DestroyRef)\n\n  const collection = computed(() => {\n    // Check if it's an existing collection\n    if (isCollection(opts)) {\n      return opts\n    }\n\n    if (typeof opts === `function`) {\n      // Check if query function returns null/undefined (disabled query)\n      const queryBuilder = new BaseQueryBuilder() as InitialQueryBuilder\n      const result = opts(queryBuilder)\n\n      if (result === undefined || result === null) {\n        // Disabled query - return null\n        return null\n      }\n\n      return resolveLiveQueryValue(result, { gcTime: DEFAULT_GC_TIME_MS })\n    }\n\n    // Check if it's reactive query options\n    const isReactiveQueryOptions =\n      opts &&\n      typeof opts === `object` &&\n      typeof opts.query === `function` &&\n      typeof opts.params === `function`\n\n    if (isReactiveQueryOptions) {\n      const { params, query } = opts\n      const currentParams = params()\n\n      // Check if query function returns null/undefined (disabled query)\n      const queryBuilder = new BaseQueryBuilder() as InitialQueryBuilder\n      const result = query({ params: currentParams, q: queryBuilder })\n\n      if (result === undefined || result === null) {\n        // Disabled query - return null\n        return null\n      }\n\n      return resolveLiveQueryValue(result, { gcTime: DEFAULT_GC_TIME_MS })\n    }\n\n    // Handle LiveQueryCollectionConfig objects. Default startSync/gcTime to\n    // match the query-fn and reactive-options paths, but let an explicit value\n    // in the config win — otherwise a bare `{ query }` never syncs.\n    if (opts && typeof opts === `object` && typeof opts.query === `function`) {\n      return resolveLiveQueryValue(opts, { gcTime: DEFAULT_GC_TIME_MS })\n    }\n\n    throw new Error(`Invalid options provided to injectLiveQuery`)\n  })\n\n  const state = signal(new Map<string | number, any>())\n  const internalData = signal<Array<any>>([])\n  const statusValue = signal<CollectionStatus | `disabled`>(`idle`)\n  const status = computed(() => {\n    const value = statusValue()\n    return value === `idle` && !collection() ? `disabled` : value\n  })\n  const persistedStatus = signal<LiveQueryPersistedStatus>(`unavailable`)\n  const persistedError = signal<unknown>(undefined)\n\n  // Returns single item for singleResult collections, array otherwise\n  const data = computed(() => {\n    const currentCollection = collection()\n    if (!currentCollection) {\n      return internalData()\n    }\n    return isSingleResultCollection(currentCollection)\n      ? internalData()[0]\n      : internalData()\n  })\n\n  const syncDataFromCollection = (\n    currentCollection: Collection<any, any, any>,\n    observer: LiveQueryObserver<any, any>,\n  ) => {\n    const newState = new Map(currentCollection.entries())\n    const newData = Array.from(newState.values())\n\n    state.set(newState)\n    internalData.set(newData)\n    const snapshot = observer.getSnapshot()\n    statusValue.set(snapshot.status)\n    persistedStatus.set(snapshot.persistedStatus)\n    persistedError.set(snapshot.persistedError)\n  }\n\n  let unsub: (() => void) | null = null\n  const cleanup = () => {\n    unsub?.()\n    unsub = null\n  }\n\n  effect((onCleanup) => {\n    const currentCollection = collection()\n\n    // Handle null collection (disabled query)\n    if (!currentCollection) {\n      statusValue.set(`disabled` as const)\n      persistedStatus.set(`unavailable`)\n      persistedError.set(undefined)\n      state.set(new Map())\n      internalData.set([])\n      cleanup()\n      return\n    }\n\n    cleanup()\n\n    // The shared observer owns sync start, subscription, the ready-race, and\n    // status transitions; Angular re-reads the whole collection on each notify\n    // (wholesale) into its signals.\n    // Angular re-reads the collection on notify; wholesale mode preserves its\n    // pre-observer loading policy (no initial-state snapshot request).\n    const observer = createLiveQueryObserver(currentCollection, {\n      mode: `wholesale`,\n    })\n\n    const unsubscribe = observer.subscribe(() => {\n      syncDataFromCollection(currentCollection, observer)\n    })\n    // Wholesale attach suppresses listener calls raised by synchronous sync\n    // startup. Read once after subscribe returns to capture that final state.\n    syncDataFromCollection(currentCollection, observer)\n    unsub = () => {\n      unsubscribe()\n      observer.dispose()\n    }\n\n    onCleanup(cleanup)\n  })\n\n  destroyRef.onDestroy(cleanup)\n\n  return {\n    state,\n    data,\n    // Loosely typed so the impl return stays compatible with every overload\n    // (the shared `isCollection` guard narrows the computed to `Collection | null`).\n    collection: computed(() =>\n      getPublicCollection(collection()),\n    ) as Signal<any>,\n    status,\n    isLoading: computed(() => status() === `loading`),\n    isReady: computed(() => status() === `ready` || status() === `disabled`),\n    persistedStatus,\n    isPersistedReady: computed(() => persistedStatus() === `ready`),\n    persistedError,\n    isIdle: computed(() => status() === `idle`),\n    isError: computed(() => status() === `error`),\n    isCleanedUp: computed(() => status() === `cleaned-up`),\n  }\n}\n"],"names":["assertInInjectionContext","inject","DestroyRef","computed","isCollection","BaseQueryBuilder","resolveLiveQueryValue","signal","isSingleResultCollection","effect","createLiveQueryObserver","getPublicCollection"],"mappings":"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"}