{"version":3,"sources":["../src/metadataSource.tsx"],"sourcesContent":["// A supported surface for a viewer app to provide its own metadata store\n// (PLATFORM_LAYERING_SPEC §4 / S3, R3-276).\n//\n// WHAT IT REPLACES. A viewer that scans its own corpus — Grove under dispatch, any\n// app whose content is not the app-root MDX the sandbox pre-scans — had exactly one\n// way to get that map in front of the metadata hooks: re-provide the platform's own\n// context wholesale,\n//\n//     <TinkerableContext.Provider value={{ ...host, filesMetadata: corpus.metadata }}>\n//\n// which is a fork of a platform contract in app code. It works until the platform\n// adds a field to `TinkerableState`, at which point every such app is silently\n// re-providing a stale copy of whatever it spread from — and nothing tells it.\n//\n// This narrows that to the one thing the app actually wanted to say: here is the\n// metadata store for my subtree. The platform stays free to grow `TinkerableState`.\n\nimport React, { createContext, use, useMemo } from 'react';\n\nimport { TinkerableContext } from './TinkerableContext';\nimport type { FilesMetadata, Metadata } from './sandboxTypes';\n\n/** How a provided store combines with the one already in scope. */\nexport type MetadataSourceMode =\n  /** The provided map IS the store for descendants — the host's entries are not\n   *  visible. The default: a viewer that scanned its own corpus is describing a\n   *  different file space, not adding to the platform's. */\n  | 'replace'\n  /** The provided entries are layered OVER what is already in scope: a path the\n   *  provider does not name still resolves to the outer store's value. For a viewer\n   *  that augments the app-root scan rather than replacing it. */\n  | 'merge';\n\ninterface MetadataSourceValue {\n  filesMetadata: FilesMetadata<Metadata>;\n}\n\n/** Undefined outside any provider, which is how the hooks know to read the host's\n *  store instead of an empty one — the two are NOT the same state. */\nconst MetadataSourceContext = createContext<MetadataSourceValue | undefined>(undefined);\n\nexport interface MetadataSourceProps {\n  /** The metadata store to provide: path → frontmatter. */\n  value: FilesMetadata<Metadata>;\n  /** Default `'replace'`. See {@link MetadataSourceMode}. */\n  mode?: MetadataSourceMode;\n  children?: React.ReactNode;\n}\n\n/**\n * Provide a metadata store to `useMetadataQuery`, `useFileMetadata` and\n * `useAllMetadata` for everything rendered inside.\n *\n * ```tsx\n * <MetadataSource value={corpus.metadata}>\n *   <Wiki />\n * </MetadataSource>\n * ```\n *\n * Nesting is allowed and the innermost provider wins; `mode=\"merge\"` layers over\n * whatever is in scope (an outer provider, else the host's store). Unmounting the\n * provider restores the outer store — there is no registry to clean up, so an app\n * cannot leak a stale source by forgetting to unregister.\n *\n * The value is used as given: pass a stable reference (a `useMemo`, module state)\n * if you care about the query hooks' identity-preservation, which is what keeps\n * their results usable in dependency arrays.\n */\nexport const MetadataSource = ({ value, mode = 'replace', children }: MetadataSourceProps): React.ReactElement => {\n  const outer = use(MetadataSourceContext);\n  const host = use(TinkerableContext);\n  const provided = useMemo<MetadataSourceValue>(() => {\n    if (mode !== 'merge') return { filesMetadata: value };\n    const base = outer?.filesMetadata ?? host?.filesMetadata ?? {};\n    return { filesMetadata: { ...base, ...value } };\n  }, [value, mode, outer, host]);\n  return <MetadataSourceContext.Provider value={provided}>{children}</MetadataSourceContext.Provider>;\n};\n\n/**\n * The metadata store in scope: the nearest {@link MetadataSource}, else the host's.\n *\n * The metadata hooks read through this, so an app never has to know which of the\n * two answered. Exported because a component that wants the raw map without the\n * query machinery should not have to reach for `TinkerableContext` and get the\n * answer wrong when a provider is present.\n */\nexport const useMetadataStore = <T = Metadata,>(): FilesMetadata<T> => {\n  const source = use(MetadataSourceContext);\n  const host = use(TinkerableContext);\n  return (source?.filesMetadata ?? host?.filesMetadata ?? {}) as FilesMetadata<T>;\n};\n"],"mappings":";;;;;;;;;;;;;;;;;;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AA4ES;AA3DT,mBAAmD;AAEnD,+BAAkC;AAoBlC,MAAM,4BAAwB,4BAA+C,MAAS;AA6B/E,MAAM,iBAAiB,CAAC,EAAE,OAAO,OAAO,WAAW,SAAS,MAA+C;AAChH,QAAM,YAAQ,kBAAI,qBAAqB;AACvC,QAAM,WAAO,kBAAI,0CAAiB;AAClC,QAAM,eAAW,sBAA6B,MAAM;AAClD,QAAI,SAAS,QAAS,QAAO,EAAE,eAAe,MAAM;AACpD,UAAM,OAAO,OAAO,iBAAiB,MAAM,iBAAiB,CAAC;AAC7D,WAAO,EAAE,eAAe,EAAE,GAAG,MAAM,GAAG,MAAM,EAAE;AAAA,EAChD,GAAG,CAAC,OAAO,MAAM,OAAO,IAAI,CAAC;AAC7B,SAAO,4CAAC,sBAAsB,UAAtB,EAA+B,OAAO,UAAW,UAAS;AACpE;AAUO,MAAM,mBAAmB,MAAuC;AACrE,QAAM,aAAS,kBAAI,qBAAqB;AACxC,QAAM,WAAO,kBAAI,0CAAiB;AAClC,SAAQ,QAAQ,iBAAiB,MAAM,iBAAiB,CAAC;AAC3D;","names":[]}