{"version":3,"sources":["../../src/components/SafeInclude.tsx"],"sourcesContent":["import { Suspense, use, useMemo } from 'react';\nimport { ErrorBoundary } from 'react-error-boundary';\n\nimport { openAppFs, openFs } from '../fs';\nimport { getAppMountPath } from '../mounts';\nimport { useMDXComponents } from '../MDXProvider';\nimport { SafeContent } from '../safeContent/SafeContent';\nimport { createSourceCache, type SourceReader } from '../sourceCache';\nimport { RenderExportedComponentContext } from './includeContexts';\nimport { defaultErrorComponent, defaultLoadingComponent } from './defaults';\n\n// `<Include mode=\"interpreted\">` — the same tag, the NON-EXECUTABLE renderer. (R3-263)\n//\n// WHY THIS EXISTS. `<Include>` resolves a file through the module cache and *evaluates* it,\n// which is right for an app's own source and wrong for content. An interpreter app\n// (TRUST_MODES_SPEC §5) had no way to say \"include this file, but as data\": it could render\n// its own bodies through `<SafeContent>` while any file it pulled in with `<Include>` still\n// executed. Grove hit exactly that — a wiki declaring `render: safe` still ran author\n// JavaScript out of its `_layout.mdx`, because the layout chain went through `<Include>`.\n//\n// It is also what makes such a file renderable AT ALL when it does not live in the app: the\n// compiled path evaluates an app-source module, which a file resident in a content mount is\n// not. That is the `AGENT_AUTHORING §10` MDX-from-mount gate, which `TRUST_MODES §5.1` says\n// MUST terminate in the safe renderer and never in compiled MDX.\n//\n// The component map comes from `useMDXComponents` — the SAME provider map `boot({\n// mdxComponents })` establishes for the compiled path — so a document resolves the identical\n// vocabulary under either renderer and an app wires nothing extra to get it.\n\n/** Strip a leading YAML frontmatter block (and an optional BOM). The compiled path never\n *  renders frontmatter — the MDX loader consumes it — so the safe path must not either, or\n *  the same file gains a wall of raw YAML when the renderer changes. */\nexport function stripFrontmatter(source: string): string {\n  return source.replace(/^\\uFEFF?---\\r?\\n[\\s\\S]*?\\r?\\n---[ \\t]*\\r?\\n?/, '');\n}\n\n/** `/app/content/x.mdx` → `content/x.mdx`. {@link openAppFs} is anchored at the app mount,\n *  so an absolute module path has to be made mount-relative before it is read. A path that\n *  is already relative is passed through untouched. */\nexport function appMountRelative(filename: string): string {\n  const root = getAppMountPath().replace(/\\/+$/, '');\n  const abs = filename.startsWith(root + '/') ? filename.slice(root.length) : filename;\n  return abs.replace(/^\\/+/, '');\n}\n\n/** Is this an absolute path that lies OUTSIDE this app's own repo mount — i.e. a file\n *  resident in a content mount rather than in the app? */\nexport function isForeignMountPath(filename: string): boolean {\n  if (!filename.startsWith('/')) return false;\n  const root = getAppMountPath().replace(/\\/+$/, '');\n  return !filename.startsWith(`${root}/`) && filename !== root;\n}\n\n/**\n * Read an interpreted include's bytes.\n *\n * The reason this is not just `openAppFs()`: **the whole point of the interpreted include\n * is files the app did not author**, and the two consumers named in this file's header —\n * a dispatched wiki's `_layout.mdx`, a whiteboard object body — live in a MOUNT. An\n * app-anchored read cannot reach them, and it does not fail loudly either: the absolute\n * path is stripped to a relative one and looked up *inside the app*, so\n * `/task/<slot>/dir/_layout.mdx` becomes a miss at `task/<slot>/dir/_layout.mdx` in the\n * app's own tree. A silent wrong-file lookup, in the component whose job is rendering\n * other people's content.\n *\n * So: a path under the app mount reads exactly as before, and an absolute path outside it\n * — which could only ever have failed — reads from the unified sandbox namespace, where\n * every mount is addressable. This widens what resolves and changes nothing that resolved.\n */\nfunction readInterpretedSource(filename: string): Promise<string> {\n  if (isForeignMountPath(filename)) {\n    // Anchored at the namespace root: mounts are addressable by their absolute paths, and\n    // this component has no way to know (and no need to know) which mount a path belongs\n    // to. It confers nothing — the ZenFS port is already chroot/`ro`-enforced host-side.\n    return openFs({ path: '/', type: 'mount' } as never).readFile(\n      filename.replace(/^\\/+/, ''),\n      'utf8',\n    ) as Promise<string>;\n  }\n  return openAppFs().readFile(appMountRelative(filename), 'utf8') as Promise<string>;\n}\n\n// One cache for every interpreted include in the app: a layout file is included on every\n// page, so a per-component cache would re-read it per navigation. See `../sourceCache` for\n// why a REJECTED read must not be memoised.\nconst defaultSources = createSourceCache(readInterpretedSource);\n\nfunction InterpretedBody({\n  filename,\n  components,\n  readSource,\n}: {\n  filename: string;\n  components?: Record<string, unknown>;\n  readSource?: SourceReader;\n}) {\n  // A caller-supplied reader gets its own cache; the shared one is used otherwise. Memoised\n  // on the reader identity so `use()` still sees a stable promise across renders.\n  const sources = useMemo(() => (readSource ? createSourceCache(readSource) : defaultSources), [readSource]);\n  const raw = use(sources.read(filename));\n  const provided = useMDXComponents(components) as Record<string, unknown>;\n  const body = stripFrontmatter(raw);\n  return (\n    // Publishing the included file's path is what lets the WikiLink resolver know which file\n    // a relative `[[target]]` (and its `#sec-…` fragment) is relative TO — the same context\n    // the compiled path publishes from the module's evaluation.\n    <RenderExportedComponentContext\n      value={{ evaluationContext: { evaluation: { module: { filepath: filename } } } } as never}\n    >\n      <SafeContent source={body} components={provided as never} />\n    </RenderExportedComponentContext>\n  );\n}\n\n/** Render another file's Markdown/MDX **as data** — no author JavaScript executes. Reached\n *  via `<Include mode=\"interpreted\">` or `<IncludeModeContext value=\"interpreted\">`. */\nexport const SafeInclude = ({\n  filename,\n  components,\n  readSource,\n  LoadingComponent = defaultLoadingComponent,\n  ErrorComponent = defaultErrorComponent,\n}: {\n  filename: string;\n  /** Extra/override components, merged OVER the surrounding MDXProvider map. */\n  components?: Record<string, unknown>;\n  /** Read the raw bytes yourself — e.g. from a content mount rather than the app repo. */\n  readSource?: SourceReader;\n  LoadingComponent?: typeof defaultLoadingComponent;\n  ErrorComponent?: typeof defaultErrorComponent;\n}) => (\n  // Same boundary shape as the compiled path: a file that fails to read renders the error\n  // component rather than taking down the tree that included it.\n  <ErrorBoundary fallbackRender={ErrorComponent}>\n    <Suspense fallback={<LoadingComponent />}>\n      <InterpretedBody filename={filename} components={components} readSource={readSource} />\n    </Suspense>\n  </ErrorBoundary>\n);\n"],"mappings":";;;;;;;;;;;;;;;;;;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AA6GM;AA7GN,mBAAuC;AACvC,kCAA8B;AAE9B,gBAAkC;AAClC,oBAAgC;AAChC,yBAAiC;AACjC,yBAA4B;AAC5B,yBAAqD;AACrD,6BAA+C;AAC/C,sBAA+D;AAuBxD,SAAS,iBAAiB,QAAwB;AACvD,SAAO,OAAO,QAAQ,gDAAgD,EAAE;AAC1E;AAKO,SAAS,iBAAiB,UAA0B;AACzD,QAAM,WAAO,+BAAgB,EAAE,QAAQ,QAAQ,EAAE;AACjD,QAAM,MAAM,SAAS,WAAW,OAAO,GAAG,IAAI,SAAS,MAAM,KAAK,MAAM,IAAI;AAC5E,SAAO,IAAI,QAAQ,QAAQ,EAAE;AAC/B;AAIO,SAAS,mBAAmB,UAA2B;AAC5D,MAAI,CAAC,SAAS,WAAW,GAAG,EAAG,QAAO;AACtC,QAAM,WAAO,+BAAgB,EAAE,QAAQ,QAAQ,EAAE;AACjD,SAAO,CAAC,SAAS,WAAW,GAAG,IAAI,GAAG,KAAK,aAAa;AAC1D;AAkBA,SAAS,sBAAsB,UAAmC;AAChE,MAAI,mBAAmB,QAAQ,GAAG;AAIhC,eAAO,kBAAO,EAAE,MAAM,KAAK,MAAM,QAAQ,CAAU,EAAE;AAAA,MACnD,SAAS,QAAQ,QAAQ,EAAE;AAAA,MAC3B;AAAA,IACF;AAAA,EACF;AACA,aAAO,qBAAU,EAAE,SAAS,iBAAiB,QAAQ,GAAG,MAAM;AAChE;AAKA,MAAM,qBAAiB,sCAAkB,qBAAqB;AAE9D,SAAS,gBAAgB;AAAA,EACvB;AAAA,EACA;AAAA,EACA;AACF,GAIG;AAGD,QAAM,cAAU,sBAAQ,MAAO,iBAAa,sCAAkB,UAAU,IAAI,gBAAiB,CAAC,UAAU,CAAC;AACzG,QAAM,UAAM,kBAAI,QAAQ,KAAK,QAAQ,CAAC;AACtC,QAAM,eAAW,qCAAiB,UAAU;AAC5C,QAAM,OAAO,iBAAiB,GAAG;AACjC;AAAA;AAAA;AAAA;AAAA,IAIE;AAAA,MAAC;AAAA;AAAA,QACC,OAAO,EAAE,mBAAmB,EAAE,YAAY,EAAE,QAAQ,EAAE,UAAU,SAAS,EAAE,EAAE,EAAE;AAAA,QAE/E,sDAAC,kCAAY,QAAQ,MAAM,YAAY,UAAmB;AAAA;AAAA,IAC5D;AAAA;AAEJ;AAIO,MAAM,cAAc,CAAC;AAAA,EAC1B;AAAA,EACA;AAAA,EACA;AAAA,EACA,mBAAmB;AAAA,EACnB,iBAAiB;AACnB;AAAA;AAAA;AAAA,EAWE,4CAAC,6CAAc,gBAAgB,gBAC7B,sDAAC,yBAAS,UAAU,4CAAC,oBAAiB,GACpC,sDAAC,mBAAgB,UAAoB,YAAwB,YAAwB,GACvF,GACF;AAAA;","names":[]}