{"version":3,"sources":["../../core/src/tx.ts","../../preact/src/index.tsx","../src/preact.ts"],"names":["createContext","_jsx","useContext","useMemo","useState","useEffect","totals","OdlaProvider","useDb","useQuery","useTransact"],"mappings":"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","file":"preact.cjs","sourcesContent":["import type { EntityRef, Json, Op, QueryResult, QueryTotals, Value } from \"@odla/protocol\";\n\n/** What a subscriber receives. `totals` is present only for queries whose nodes\n * asked for `count`; it is a second argument rather than a field on the result\n * so the plain `(result) => void` callback keeps working untouched. */\nexport type QueryCallback = (result: QueryResult, totals?: QueryTotals) => void;\n\n// ---------------------------------------------------------------------------\n// Transaction builder\n// ---------------------------------------------------------------------------\ntype Attrs = Record<string, Value>;\n\n/**\n * Chainable builder for one entity's mutations. Created via the {@link tx}\n * proxy (`tx.<namespace>[id]`), it accumulates ops in `ops`; each method\n * (`update`, `merge`, `delete`, `retract`, `link`, `unlink`) pushes one `Op`\n * and returns `this` so calls chain. Pass the chain (or an array of chains) to\n * `transact`.\n */\nexport class TxChain {\n  readonly ops: Op[] = [];\n  constructor(\n    private ns: string,\n    private id: EntityRef,\n  ) {}\n  update(attrs: Attrs): this {\n    this.ops.push({ t: \"update\", ns: this.ns, id: this.id, attrs });\n    return this;\n  }\n  merge(attrs: Record<string, Json>): this {\n    this.ops.push({ t: \"merge\", ns: this.ns, id: this.id, attrs });\n    return this;\n  }\n  delete(): this {\n    this.ops.push({ t: \"delete\", ns: this.ns, id: this.id });\n    return this;\n  }\n  /**\n   * Remove the named scalar/json attributes from this entity, returning them to\n   * the absence-of-triple state — the scalar sibling of {@link unlink}. Use it\n   * to CLEAR a value: a typed scalar attribute cannot store `null`, so\n   * `retract([\"dueAt\"])` is how you unset one. A no-op for attributes already\n   * absent; retracting a required attribute aborts the transaction.\n   */\n  retract(attrs: string[]): this {\n    this.ops.push({ t: \"retract\", ns: this.ns, id: this.id, attrs });\n    return this;\n  }\n  link(label: string, target: EntityRef): this {\n    this.ops.push({ t: \"link\", ns: this.ns, id: this.id, label, target });\n    return this;\n  }\n  unlink(label: string, target: EntityRef): this {\n    this.ops.push({ t: \"unlink\", ns: this.ns, id: this.id, label, target });\n    return this;\n  }\n}\n\nexport type TxInput = TxChain | Op | TxInput[];\n/**\n * Flatten a transaction input into the wire `Op[]`. Accepts a {@link TxChain}\n * (returns its accumulated `ops`), a bare `Op` literal (wrapped in a\n * single-element array), or an arbitrarily nested array of either, recursing to\n * produce one flat, ordered op list — the shape sent to the `transact` endpoint.\n */\nexport function flattenTx(input: TxInput): Op[] {\n  if (Array.isArray(input)) return input.flatMap(flattenTx);\n  if (input instanceof TxChain) return input.ops;\n  return [input];\n}\n\ntype NamespaceProxy = Record<string, TxChain>;\nexport const tx: Record<string, NamespaceProxy> = new Proxy(\n  {},\n  {\n    get(_t, ns: string): NamespaceProxy {\n      return new Proxy({}, { get: (_n, id: string): TxChain => new TxChain(ns, id) }) as NamespaceProxy;\n    },\n  },\n) as Record<string, NamespaceProxy>;\n","/**\n * @odla/preact — thin Preact bindings over @odla/core.\n */\nimport { createContext, type ComponentChildren } from \"preact\";\nimport { useContext, useEffect, useMemo, useState } from \"preact/hooks\";\nimport type { Db, TxInput } from \"@odla/core\";\nimport type { InstaQLQuery, QueryResult, QueryTotals } from \"@odla/protocol\";\n\nconst DbContext = createContext<Db | null>(null);\n\nexport function OdlaProvider({ db, children }: { db: Db; children: ComponentChildren }) {\n  return <DbContext.Provider value={db}>{children}</DbContext.Provider>;\n}\n\nexport function useDb(): Db {\n  const db = useContext(DbContext);\n  if (!db) throw new Error(\"useDb must be used within an <OdlaProvider>\");\n  return db;\n}\n\nexport interface UseQueryOptions {\n  /** Keep showing the previous query's data (flagged `isStale`) while the new\n   * query's first result is in flight, instead of flashing to null. */\n  keepPrevious?: boolean;\n}\n\nexport interface UseQueryResult {\n  data: QueryResult | null;\n  isLoading: boolean;\n  /** True while `data` belongs to a previous query shape (keepPrevious). */\n  isStale: boolean;\n  /**\n   * Per-namespace match counts, for query nodes that asked with `count: true` —\n   * the total a pager needs, ignoring `limit`/`offset`. Recomputed with the rows\n   * and delivered on the same frames, so it stays live instead of going stale\n   * the moment anything changes. Undefined when nothing asked.\n   */\n  totals?: QueryTotals;\n}\n\nexport function useQuery(query: InstaQLQuery, opts?: UseQueryOptions): UseQueryResult {\n  const db = useDb();\n  const key = useMemo(() => JSON.stringify(query), [query]);\n  // Staleness is DERIVED from a key mismatch on the last snapshot — there is\n  // no reset-to-null effect, so a warm cache never flashes a loading state.\n  const [snap, setSnap] = useState<{ key: string; data: QueryResult; totals?: QueryTotals } | null>(() => {\n    const cached = db.peekQuery?.(query);\n    return cached ? { key, data: cached } : null;\n  });\n\n  useEffect(() => {\n    // Key change with a warm cache: swap synchronously instead of going stale.\n    const cached = db.peekQuery?.(query);\n    if (cached) setSnap((prev) => (prev?.key === key && prev.data === cached ? prev : { key, data: cached }));\n    return db.subscribeQuery(query, (r, totals) => setSnap({ key, data: r, totals }));\n    // re-subscribe only when the query shape changes\n  }, [db, key]);\n\n  const fresh = snap !== null && snap.key === key;\n  const data = fresh ? snap.data : opts?.keepPrevious ? (snap?.data ?? null) : null;\n  // Totals track whichever result is being shown, so a kept-previous page and\n  // its \"of N\" never disagree.\n  const totals = data === null ? undefined : fresh ? snap!.totals : snap?.totals;\n  return { data, isLoading: data === null, isStale: !fresh && data !== null, totals };\n}\n\nexport function useTransact() {\n  const db = useDb();\n  return (input: TxInput, opts?: { mutationId?: string }) => db.transact(input, opts);\n}\n\nexport { type Db } from \"@odla/core\";\n","import {\n  OdlaProvider as preactOdlaProvider,\n  useDb as preactUseDb,\n  useQuery as preactUseQuery,\n  useTransact as preactUseTransact,\n} from \"@odla/preact\";\nimport type * as PreactApi from \"@odla/preact\";\n\n/** Context provider that owns one permission-governed realtime database client. */\nexport const OdlaProvider = preactOdlaProvider;\n/** Read the current realtime database client from `OdlaProvider`. */\nexport const useDb = preactUseDb;\n/** Subscribe a component to a realtime query with data and loading state. */\nexport const useQuery = preactUseQuery;\n/** Return a callback that applies optimistic transaction operations. */\nexport const useTransact = preactUseTransact;\n/** Realtime database client supplied through `OdlaProvider`. */\nexport type Db = PreactApi.Db;\n/** Reactive query result containing current data, loading state, and — for\n * nodes that asked with `count: true` — live per-namespace totals. */\nexport type UseQueryResult = PreactApi.UseQueryResult;\n"]}