@immediately-run/sdk 0.57.0 → 0.57.4
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/dist/agentChatClient.cjs +112 -0
- package/dist/agentChatClient.cjs.map +1 -0
- package/dist/agentChatClient.d.cts +9 -0
- package/dist/agentChatClient.d.ts +9 -0
- package/dist/agentChatClient.js +89 -0
- package/dist/agentChatClient.js.map +1 -0
- package/dist/agentContext.cjs +69 -0
- package/dist/agentContext.cjs.map +1 -0
- package/dist/agentContext.d.cts +45 -0
- package/dist/agentContext.d.ts +45 -0
- package/dist/agentContext.js +45 -0
- package/dist/agentContext.js.map +1 -0
- package/dist/agentLoop.cjs +301 -0
- package/dist/agentLoop.cjs.map +1 -0
- package/dist/agentLoop.d.cts +267 -0
- package/dist/agentLoop.d.ts +267 -0
- package/dist/agentLoop.js +271 -0
- package/dist/agentLoop.js.map +1 -0
- package/dist/agentSteering.cjs +127 -0
- package/dist/agentSteering.cjs.map +1 -0
- package/dist/agentSteering.d.cts +80 -0
- package/dist/agentSteering.d.ts +80 -0
- package/dist/agentSteering.js +98 -0
- package/dist/agentSteering.js.map +1 -0
- package/dist/auth.cjs.map +1 -1
- package/dist/auth.d.cts +33 -2
- package/dist/auth.d.ts +33 -2
- package/dist/auth.js.map +1 -1
- package/dist/bundle.cjs +91 -0
- package/dist/bundle.cjs.map +1 -0
- package/dist/bundle.d.cts +63 -0
- package/dist/bundle.d.ts +63 -0
- package/dist/bundle.js +62 -0
- package/dist/bundle.js.map +1 -0
- package/dist/collectHeadings.cjs +59 -0
- package/dist/collectHeadings.cjs.map +1 -0
- package/dist/collectHeadings.d.cts +16 -0
- package/dist/collectHeadings.d.ts +16 -0
- package/dist/collectHeadings.js +36 -0
- package/dist/collectHeadings.js.map +1 -0
- package/dist/components/MainContent.cjs +3 -1
- package/dist/components/MainContent.cjs.map +1 -1
- package/dist/components/MainContent.js +4 -2
- package/dist/components/MainContent.js.map +1 -1
- package/dist/corpus.cjs +9 -58
- package/dist/corpus.cjs.map +1 -1
- package/dist/corpus.d.cts +3 -63
- package/dist/corpus.d.ts +3 -63
- package/dist/corpus.js +15 -57
- package/dist/corpus.js.map +1 -1
- package/dist/debug.cjs +115 -0
- package/dist/debug.cjs.map +1 -1
- package/dist/debug.js +115 -0
- package/dist/debug.js.map +1 -1
- package/dist/fence.cjs +49 -0
- package/dist/fence.cjs.map +1 -0
- package/dist/fence.d.cts +4 -0
- package/dist/fence.d.ts +4 -0
- package/dist/fence.js +26 -0
- package/dist/fence.js.map +1 -0
- package/dist/formFactor.cjs.map +1 -1
- package/dist/formFactor.d.cts +11 -2
- package/dist/formFactor.d.ts +11 -2
- package/dist/formFactor.js.map +1 -1
- package/dist/fs.cjs.map +1 -1
- package/dist/fs.d.cts +16 -6
- package/dist/fs.d.ts +16 -6
- package/dist/fs.js.map +1 -1
- package/dist/hooks.cjs.map +1 -1
- package/dist/hooks.d.cts +7 -0
- package/dist/hooks.d.ts +7 -0
- package/dist/hooks.js.map +1 -1
- package/dist/index.cjs +19 -1
- package/dist/index.cjs.map +1 -1
- package/dist/index.d.cts +11 -3
- package/dist/index.d.ts +11 -3
- package/dist/index.js +9 -0
- package/dist/index.js.map +1 -1
- package/dist/launch.cjs +45 -6
- package/dist/launch.cjs.map +1 -1
- package/dist/launch.d.cts +3 -0
- package/dist/launch.d.ts +3 -0
- package/dist/launch.js +45 -6
- package/dist/launch.js.map +1 -1
- package/dist/llm.cjs.map +1 -1
- package/dist/llm.d.cts +20 -3
- package/dist/llm.d.ts +20 -3
- package/dist/llm.js.map +1 -1
- package/dist/metadataQueryTool.cjs +271 -0
- package/dist/metadataQueryTool.cjs.map +1 -0
- package/dist/metadataQueryTool.d.cts +159 -0
- package/dist/metadataQueryTool.d.ts +159 -0
- package/dist/metadataQueryTool.js +241 -0
- package/dist/metadataQueryTool.js.map +1 -0
- package/dist/mounts.cjs.map +1 -1
- package/dist/mounts.d.cts +22 -3
- package/dist/mounts.d.ts +22 -3
- package/dist/mounts.js.map +1 -1
- package/dist/onFsChange.cjs +13 -1
- package/dist/onFsChange.cjs.map +1 -1
- package/dist/onFsChange.d.cts +21 -1
- package/dist/onFsChange.d.ts +21 -1
- package/dist/onFsChange.js +13 -1
- package/dist/onFsChange.js.map +1 -1
- package/dist/protocolSchemes.cjs +1 -0
- package/dist/protocolSchemes.cjs.map +1 -1
- package/dist/protocolSchemes.d.cts +1 -0
- package/dist/protocolSchemes.d.ts +1 -0
- package/dist/protocolSchemes.js +2 -0
- package/dist/protocolSchemes.js.map +1 -1
- package/dist/recents.cjs +41 -0
- package/dist/recents.cjs.map +1 -0
- package/dist/recents.d.cts +23 -0
- package/dist/recents.d.ts +23 -0
- package/dist/recents.js +17 -0
- package/dist/recents.js.map +1 -0
- package/dist/tasks.cjs +41 -7
- package/dist/tasks.cjs.map +1 -1
- package/dist/tasks.d.cts +136 -7
- package/dist/tasks.d.ts +136 -7
- package/dist/tasks.js +39 -7
- package/dist/tasks.js.map +1 -1
- package/dist/version.cjs +1 -1
- package/dist/version.cjs.map +1 -1
- package/dist/version.d.cts +1 -1
- package/dist/version.d.ts +1 -1
- package/dist/version.js +1 -1
- package/dist/version.js.map +1 -1
- package/package.json +6 -5
package/dist/bundle.js
ADDED
|
@@ -0,0 +1,62 @@
|
|
|
1
|
+
import "./chunk-VHAA22YE.js";
|
|
2
|
+
import { createContext, use, useMemo } from "react";
|
|
3
|
+
import { useMetadataStore } from "./metadataSource";
|
|
4
|
+
const EMPTY_SCOPE = { root: null, entry: null, toHref: (p) => p };
|
|
5
|
+
const BundleContext = createContext(EMPTY_SCOPE);
|
|
6
|
+
const useBundle = () => use(BundleContext);
|
|
7
|
+
const toBundlePath = (absolute, root) => {
|
|
8
|
+
if (root === null) return null;
|
|
9
|
+
const base = root.replace(/\/+$/, "");
|
|
10
|
+
if (base === "") return absolute;
|
|
11
|
+
if (!absolute.startsWith(`${base}/`)) return null;
|
|
12
|
+
return absolute.slice(base.length);
|
|
13
|
+
};
|
|
14
|
+
const fromBundlePath = (bundlePath, root) => {
|
|
15
|
+
if (root === null) return null;
|
|
16
|
+
const base = root.replace(/\/+$/, "");
|
|
17
|
+
return `${base}${bundlePath.startsWith("/") ? "" : "/"}${bundlePath}`;
|
|
18
|
+
};
|
|
19
|
+
const useBundleEntries = () => {
|
|
20
|
+
const files = useMetadataStore();
|
|
21
|
+
const { root, toHref } = useBundle();
|
|
22
|
+
return useMemo(() => {
|
|
23
|
+
if (root === null) return [];
|
|
24
|
+
const out = [];
|
|
25
|
+
for (const [absolute, meta] of Object.entries(files)) {
|
|
26
|
+
const path = toBundlePath(absolute, root);
|
|
27
|
+
if (path === null) continue;
|
|
28
|
+
out.push({ path, href: toHref(path), meta });
|
|
29
|
+
}
|
|
30
|
+
out.sort((a, b) => a.path.localeCompare(b.path));
|
|
31
|
+
return out;
|
|
32
|
+
}, [files, root, toHref]);
|
|
33
|
+
};
|
|
34
|
+
const useBundleEntry = (bundlePath) => {
|
|
35
|
+
const files = useMetadataStore();
|
|
36
|
+
const { root } = useBundle();
|
|
37
|
+
return useMemo(() => {
|
|
38
|
+
const absolute = fromBundlePath(bundlePath, root);
|
|
39
|
+
return absolute === null ? void 0 : files[absolute];
|
|
40
|
+
}, [bundlePath, files, root]);
|
|
41
|
+
};
|
|
42
|
+
const useCurrentEntry = () => {
|
|
43
|
+
const files = useMetadataStore();
|
|
44
|
+
const { root, entry, toHref } = useBundle();
|
|
45
|
+
return useMemo(() => {
|
|
46
|
+
if (root === null || entry === null) return null;
|
|
47
|
+
const absolute = fromBundlePath(entry, root);
|
|
48
|
+
const meta = absolute === null ? void 0 : files[absolute];
|
|
49
|
+
if (meta === void 0) return null;
|
|
50
|
+
return { path: entry, href: toHref(entry), meta };
|
|
51
|
+
}, [files, root, entry, toHref]);
|
|
52
|
+
};
|
|
53
|
+
export {
|
|
54
|
+
BundleContext,
|
|
55
|
+
fromBundlePath,
|
|
56
|
+
toBundlePath,
|
|
57
|
+
useBundle,
|
|
58
|
+
useBundleEntries,
|
|
59
|
+
useBundleEntry,
|
|
60
|
+
useCurrentEntry
|
|
61
|
+
};
|
|
62
|
+
//# sourceMappingURL=bundle.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"sources":["../src/bundle.ts"],"sourcesContent":["// The bundle scope — what a component rendered INSIDE a bundle may know about it\n// (R3-174; MDX_FROM_MOUNT_SPEC §2, §7 1a).\n//\n// A bundle viewer can register components the bundle itself ships, so an entry writes\n// `<ProjectIndex/>` and the viewer resolves it — no engine fork, no import line\n// (`MDX_FROM_MOUNT_SPEC` §2's \"provider composition is consumer policy\"). Those components\n// live in the CONTENT filesystem and the viewer lives in its own, and the seam between\n// them is this package: a content component cannot import the viewer (it would resolve a\n// second copy from the registry, with its own module state, and read the wrong bundle), so\n// anything the viewer must tell it has to arrive through a surface both sides already\n// share. This is that surface.\n//\n// **Why paths here are bundle-absolute, not filesystem-absolute.** The metadata store is\n// keyed by absolute module path, which under dispatch means `/mnt/<hash>/roadmap/x.mdx` —\n// the host-minted chroot. That prefix is host knowledge a viewer may read THROUGH but must\n// never publish (the property `grove/src/components/DirectoryList.test.tsx` pins with\n// `expect(el.innerHTML).not.toContain('mnt')`), and it is not stable across loads. A\n// content component that saw it would embed it in hrefs and keys. So the bundle scope\n// rebases every path it hands out to the bundle root (`/roadmap/x.mdx`), which is the same\n// address under fork, library and dispatch composition — `PLATFORM_LAYERING_SPEC` §1.1's\n// mode-invariance rule, applied to metadata rather than to links.\n//\n// **Why the href mapping is injected rather than derived.** Bundle path → in-app URL is\n// VIEWER policy, and the two packagings genuinely disagree (a fork's URLs are anchored at\n// its app root and are already published and cited; a dispatched viewer's are bundle-\n// relative). A content component must not have to know which it is in, and the SDK must\n// not guess — so the viewer supplies `toHref` and content never computes a URL itself.\n\nimport { createContext, use, useMemo } from 'react';\nimport { useMetadataStore } from './metadataSource';\nimport type { Metadata } from './sandboxTypes';\n\n/** What a bundle viewer declares about the bundle it is rendering. */\nexport interface BundleScope {\n /**\n * Absolute filesystem path of the bundle root, WITHOUT a trailing slash\n * (`/app/content` in a fork, `/mnt/<hash>` under dispatch), or `null` when the\n * surrounding app is not rendering a bundle — the default, which leaves every hook here\n * returning the empty result rather than guessing a root.\n */\n root: string | null;\n /** Bundle-absolute path of the entry currently being read (`/roadmap/R3-174.mdx`), or\n * `null` when nothing is. This is the entry, NOT the file being rendered: a component\n * in a `_layout.mdx` wrapping that entry sees the entry, which is what makes furniture\n * in the layout chain (a status line, a dependency rail) able to describe the page. */\n entry: string | null;\n /** Bundle-absolute path → the href to navigate to it. Supplied by the viewer; the\n * identity function by default, which is correct for a viewer whose URL space IS the\n * bundle space. */\n toHref: (bundlePath: string) => string;\n}\n\nconst EMPTY_SCOPE: BundleScope = { root: null, entry: null, toHref: (p) => p };\n\n/** Ambient bundle scope. A bundle-rendering app wraps its content tree in\n * `<BundleContext value={{ root, entry, toHref }}>`; nesting a second provider inside a\n * rendered sub-bundle makes the innermost win, as with {@link LinkSpaceContext}. */\nexport const BundleContext = createContext<BundleScope>(EMPTY_SCOPE);\n\n/** Read the ambient bundle scope. Every hook below is a convenience over this. */\nexport const useBundle = (): BundleScope => use(BundleContext);\n\n/**\n * Filesystem-absolute path → bundle-absolute, or `null` when the path is not inside the\n * bundle. Exact-root and separator-boundary aware, so `/mnt/hash2/x` is not treated as\n * living under `/mnt/hash`.\n */\nexport const toBundlePath = (absolute: string, root: string | null): string | null => {\n if (root === null) return null;\n const base = root.replace(/\\/+$/, '');\n if (base === '') return absolute;\n if (!absolute.startsWith(`${base}/`)) return null;\n return absolute.slice(base.length);\n};\n\n/** Bundle-absolute path → filesystem-absolute, or `null` without a root. The inverse of\n * {@link toBundlePath}, for the rare content component that must read raw bytes. */\nexport const fromBundlePath = (bundlePath: string, root: string | null): string | null => {\n if (root === null) return null;\n const base = root.replace(/\\/+$/, '');\n return `${base}${bundlePath.startsWith('/') ? '' : '/'}${bundlePath}`;\n};\n\n/** One entry as content sees it: where it is, where it links, and its frontmatter. */\nexport interface BundleEntry<T = Metadata> {\n /** Bundle-absolute path (`/roadmap/R3-174.mdx`). */\n path: string;\n /** The href that navigates to it, per the viewer's mapping. */\n href: string;\n meta: T;\n}\n\n/**\n * Every entry in the surrounding bundle, with bundle-absolute paths and viewer-supplied\n * hrefs — the surface a content component queries instead of {@link useMetadataQuery},\n * whose keys are filesystem-absolute and therefore carry the mount prefix.\n *\n * Returns an empty array outside a bundle, so a component written for a bundle renders\n * nothing rather than throwing when someone drops it elsewhere. The array keeps its\n * identity while the store and root are unchanged, so it is safe in dependency arrays.\n */\nexport const useBundleEntries = <T = Metadata>(): BundleEntry<T>[] => {\n const files = useMetadataStore<T>();\n const { root, toHref } = useBundle();\n return useMemo(() => {\n if (root === null) return [];\n const out: BundleEntry<T>[] = [];\n for (const [absolute, meta] of Object.entries(files)) {\n const path = toBundlePath(absolute, root);\n if (path === null) continue;\n out.push({ path, href: toHref(path), meta: meta as T });\n }\n // Path order, so a consumer that does not sort still renders deterministically\n // (object key order is insertion order, which is scan order, which is not stable).\n out.sort((a, b) => a.path.localeCompare(b.path));\n return out;\n }, [files, root, toHref]);\n};\n\n/** One entry's frontmatter by bundle-absolute path, or `undefined`. */\nexport const useBundleEntry = <T = Metadata>(bundlePath: string): T | undefined => {\n const files = useMetadataStore<T>();\n const { root } = useBundle();\n return useMemo(() => {\n const absolute = fromBundlePath(bundlePath, root);\n return absolute === null ? undefined : files[absolute];\n }, [bundlePath, files, root]);\n};\n\n/** The entry currently being read — `null` outside a bundle, or when the viewer declares\n * no entry (a directory listing, a 404). See {@link BundleScope.entry} for why this is\n * the entry rather than the file the component happens to be written in. */\nexport const useCurrentEntry = <T = Metadata>(): BundleEntry<T> | null => {\n const files = useMetadataStore<T>();\n const { root, entry, toHref } = useBundle();\n return useMemo(() => {\n if (root === null || entry === null) return null;\n const absolute = fromBundlePath(entry, root);\n const meta = absolute === null ? undefined : files[absolute];\n if (meta === undefined) return null;\n return { path: entry, href: toHref(entry), meta: meta as T };\n }, [files, root, entry, toHref]);\n};\n"],"mappings":";AA4BA,SAAS,eAAe,KAAK,eAAe;AAC5C,SAAS,wBAAwB;AAuBjC,MAAM,cAA2B,EAAE,MAAM,MAAM,OAAO,MAAM,QAAQ,CAAC,MAAM,EAAE;AAKtE,MAAM,gBAAgB,cAA2B,WAAW;AAG5D,MAAM,YAAY,MAAmB,IAAI,aAAa;AAOtD,MAAM,eAAe,CAAC,UAAkB,SAAuC;AACpF,MAAI,SAAS,KAAM,QAAO;AAC1B,QAAM,OAAO,KAAK,QAAQ,QAAQ,EAAE;AACpC,MAAI,SAAS,GAAI,QAAO;AACxB,MAAI,CAAC,SAAS,WAAW,GAAG,IAAI,GAAG,EAAG,QAAO;AAC7C,SAAO,SAAS,MAAM,KAAK,MAAM;AACnC;AAIO,MAAM,iBAAiB,CAAC,YAAoB,SAAuC;AACxF,MAAI,SAAS,KAAM,QAAO;AAC1B,QAAM,OAAO,KAAK,QAAQ,QAAQ,EAAE;AACpC,SAAO,GAAG,IAAI,GAAG,WAAW,WAAW,GAAG,IAAI,KAAK,GAAG,GAAG,UAAU;AACrE;AAoBO,MAAM,mBAAmB,MAAsC;AACpE,QAAM,QAAQ,iBAAoB;AAClC,QAAM,EAAE,MAAM,OAAO,IAAI,UAAU;AACnC,SAAO,QAAQ,MAAM;AACnB,QAAI,SAAS,KAAM,QAAO,CAAC;AAC3B,UAAM,MAAwB,CAAC;AAC/B,eAAW,CAAC,UAAU,IAAI,KAAK,OAAO,QAAQ,KAAK,GAAG;AACpD,YAAM,OAAO,aAAa,UAAU,IAAI;AACxC,UAAI,SAAS,KAAM;AACnB,UAAI,KAAK,EAAE,MAAM,MAAM,OAAO,IAAI,GAAG,KAAgB,CAAC;AAAA,IACxD;AAGA,QAAI,KAAK,CAAC,GAAG,MAAM,EAAE,KAAK,cAAc,EAAE,IAAI,CAAC;AAC/C,WAAO;AAAA,EACT,GAAG,CAAC,OAAO,MAAM,MAAM,CAAC;AAC1B;AAGO,MAAM,iBAAiB,CAAe,eAAsC;AACjF,QAAM,QAAQ,iBAAoB;AAClC,QAAM,EAAE,KAAK,IAAI,UAAU;AAC3B,SAAO,QAAQ,MAAM;AACnB,UAAM,WAAW,eAAe,YAAY,IAAI;AAChD,WAAO,aAAa,OAAO,SAAY,MAAM,QAAQ;AAAA,EACvD,GAAG,CAAC,YAAY,OAAO,IAAI,CAAC;AAC9B;AAKO,MAAM,kBAAkB,MAA2C;AACxE,QAAM,QAAQ,iBAAoB;AAClC,QAAM,EAAE,MAAM,OAAO,OAAO,IAAI,UAAU;AAC1C,SAAO,QAAQ,MAAM;AACnB,QAAI,SAAS,QAAQ,UAAU,KAAM,QAAO;AAC5C,UAAM,WAAW,eAAe,OAAO,IAAI;AAC3C,UAAM,OAAO,aAAa,OAAO,SAAY,MAAM,QAAQ;AAC3D,QAAI,SAAS,OAAW,QAAO;AAC/B,WAAO,EAAE,MAAM,OAAO,MAAM,OAAO,KAAK,GAAG,KAAgB;AAAA,EAC7D,GAAG,CAAC,OAAO,MAAM,OAAO,MAAM,CAAC;AACjC;","names":[]}
|
|
@@ -0,0 +1,59 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
var __defProp = Object.defineProperty;
|
|
3
|
+
var __getOwnPropDesc = Object.getOwnPropertyDescriptor;
|
|
4
|
+
var __getOwnPropNames = Object.getOwnPropertyNames;
|
|
5
|
+
var __hasOwnProp = Object.prototype.hasOwnProperty;
|
|
6
|
+
var __export = (target, all) => {
|
|
7
|
+
for (var name in all)
|
|
8
|
+
__defProp(target, name, { get: all[name], enumerable: true });
|
|
9
|
+
};
|
|
10
|
+
var __copyProps = (to, from, except, desc) => {
|
|
11
|
+
if (from && typeof from === "object" || typeof from === "function") {
|
|
12
|
+
for (let key of __getOwnPropNames(from))
|
|
13
|
+
if (!__hasOwnProp.call(to, key) && key !== except)
|
|
14
|
+
__defProp(to, key, { get: () => from[key], enumerable: !(desc = __getOwnPropDesc(from, key)) || desc.enumerable });
|
|
15
|
+
}
|
|
16
|
+
return to;
|
|
17
|
+
};
|
|
18
|
+
var __toCommonJS = (mod) => __copyProps(__defProp({}, "__esModule", { value: true }), mod);
|
|
19
|
+
var collectHeadings_exports = {};
|
|
20
|
+
__export(collectHeadings_exports, {
|
|
21
|
+
collectHeadings: () => collectHeadings
|
|
22
|
+
});
|
|
23
|
+
module.exports = __toCommonJS(collectHeadings_exports);
|
|
24
|
+
var import_mdx_plugins = require("@immediately-run/mdx-plugins");
|
|
25
|
+
function collectHeadings(body, opts = {}) {
|
|
26
|
+
const sectionIds = opts.sectionIds !== false;
|
|
27
|
+
const seen = /* @__PURE__ */ new Map();
|
|
28
|
+
const out = [];
|
|
29
|
+
let fenceMarker = null;
|
|
30
|
+
for (const line of body.split("\n")) {
|
|
31
|
+
const fenceMatch = /^(\s{0,3})(`{3,}|~{3,})/.exec(line);
|
|
32
|
+
if (fenceMarker) {
|
|
33
|
+
if (fenceMatch && line.trim().startsWith(fenceMarker)) fenceMarker = null;
|
|
34
|
+
continue;
|
|
35
|
+
}
|
|
36
|
+
if (fenceMatch) {
|
|
37
|
+
fenceMarker = fenceMatch[2][0].repeat(3);
|
|
38
|
+
continue;
|
|
39
|
+
}
|
|
40
|
+
const h = /^(#{1,6})[ \t]+(\S.*)$/.exec(line);
|
|
41
|
+
if (!h) continue;
|
|
42
|
+
const text = flattenInline(h[2].trim());
|
|
43
|
+
if (!text) continue;
|
|
44
|
+
const baseId = (0, import_mdx_plugins.headingId)(text, { sectionIds });
|
|
45
|
+
const n = seen.get(baseId) ?? 0;
|
|
46
|
+
seen.set(baseId, n + 1);
|
|
47
|
+
const id = n === 0 ? baseId : `${baseId}-${n}`;
|
|
48
|
+
out.push({ id, text, depth: h[1].length });
|
|
49
|
+
}
|
|
50
|
+
return out;
|
|
51
|
+
}
|
|
52
|
+
function flattenInline(s) {
|
|
53
|
+
return s.replace(/!?\[([^\]]*)\]\([^)]*\)/g, "$1").replace(/`([^`]*)`/g, "$1").replace(/\*\*([^*]+)\*\*/g, "$1").replace(/\*([^*]+)\*/g, "$1").replace(/__([^_]+)__/g, "$1").replace(/_([^_]+)_/g, "$1");
|
|
54
|
+
}
|
|
55
|
+
// Annotate the CommonJS export names for ESM import in node:
|
|
56
|
+
0 && (module.exports = {
|
|
57
|
+
collectHeadings
|
|
58
|
+
});
|
|
59
|
+
//# sourceMappingURL=collectHeadings.cjs.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"sources":["../src/collectHeadings.ts"],"sourcesContent":["// The headings index extension (GROVE_AGENT_SPEC §4): `headings: [{id, text, depth}]`\n// computed from an entry's BODY with the same `@immediately-run/mdx-plugins`\n// heading-anchor canon the render paths use — so an index heading's id IS the id a\n// reader's `#fragment` lands on, and section-level questions are answerable from the\n// index without body reads.\n//\n// IDS CANNOT DRIFT: every id is `headingId(text, { sectionIds })` from mdx-plugins,\n// with the same in-document duplicate counter (`baseId-2`, `-3`, …) the remark pass\n// applies. What this module adds is the WALK — a byte-level ATX scan used where the\n// remark tree is not at hand (the bundler's metadata scan, a dispatched corpus scan).\n// It walks only what corpus entries actually contain: top-level ATX headings\n// (`#`–`######`) outside fenced code blocks; headings carrying an author id\n// (MDX `{#…}`/JSX) are invisible to a byte scan and stay the remark pass's to own.\n//\n// Additive by design: an older index simply lacks `headings`, and readers degrade to\n// body reads (ways_of_working §6).\n\nimport { headingId } from '@immediately-run/mdx-plugins';\nimport type { HeadingSummary } from './metadataQueryTool';\n\nexport type { HeadingSummary };\n\n/**\n * Collect an entry's headings from its MDX/Markdown BODY (frontmatter already\n * stripped — `parseFrontmatter(...).body`).\n *\n * Inline markup is flattened the way the remark pass flattens it (`## The **bold**\n * heading` → \"The bold heading\"), code fences are skipped, and ids follow the canon\n * with per-document duplicate suffixes.\n */\nexport function collectHeadings(body: string, opts: { sectionIds?: boolean } = {}): HeadingSummary[] {\n const sectionIds = opts.sectionIds !== false;\n const seen = new Map<string, number>();\n const out: HeadingSummary[] = [];\n\n let fenceMarker: string | null = null; // inside a ``` or ~~~ block\n for (const line of body.split('\\n')) {\n const fenceMatch = /^(\\s{0,3})(`{3,}|~{3,})/.exec(line);\n if (fenceMarker) {\n if (fenceMatch && line.trim().startsWith(fenceMarker)) fenceMarker = null;\n continue;\n }\n if (fenceMatch) {\n fenceMarker = fenceMatch[2][0].repeat(3);\n continue;\n }\n const h = /^(#{1,6})[ \\t]+(\\S.*)$/.exec(line);\n if (!h) continue;\n const text = flattenInline(h[2].trim());\n if (!text) continue;\n const baseId = headingId(text, { sectionIds });\n const n = seen.get(baseId) ?? 0;\n seen.set(baseId, n + 1);\n const id = n === 0 ? baseId : `${baseId}-${n}`;\n out.push({ id, text, depth: h[1].length });\n }\n return out;\n}\n\n/** Flatten inline markup the way `headingText` does in the remark pass: emphasis and\n * code markers drop, link/image syntax keeps its text. Covers what corpus headings\n * actually carry; anything else passes through verbatim (and the id canon slugifies\n * punctuation anyway). */\nfunction flattenInline(s: string): string {\n return s\n .replace(/!?\\[([^\\]]*)\\]\\([^)]*\\)/g, '$1') // [text](url) /  → text\n .replace(/`([^`]*)`/g, '$1') // `code` → code\n .replace(/\\*\\*([^*]+)\\*\\*/g, '$1') // **bold** → bold\n .replace(/\\*([^*]+)\\*/g, '$1') // *em* → em\n .replace(/__([^_]+)__/g, '$1') // __bold__ → bold\n .replace(/_([^_]+)_/g, '$1'); // _em_ → em\n}\n"],"mappings":";;;;;;;;;;;;;;;;;;AAAA;AAAA;AAAA;AAAA;AAAA;AAiBA,yBAA0B;AAanB,SAAS,gBAAgB,MAAc,OAAiC,CAAC,GAAqB;AACnG,QAAM,aAAa,KAAK,eAAe;AACvC,QAAM,OAAO,oBAAI,IAAoB;AACrC,QAAM,MAAwB,CAAC;AAE/B,MAAI,cAA6B;AACjC,aAAW,QAAQ,KAAK,MAAM,IAAI,GAAG;AACnC,UAAM,aAAa,0BAA0B,KAAK,IAAI;AACtD,QAAI,aAAa;AACf,UAAI,cAAc,KAAK,KAAK,EAAE,WAAW,WAAW,EAAG,eAAc;AACrE;AAAA,IACF;AACA,QAAI,YAAY;AACd,oBAAc,WAAW,CAAC,EAAE,CAAC,EAAE,OAAO,CAAC;AACvC;AAAA,IACF;AACA,UAAM,IAAI,yBAAyB,KAAK,IAAI;AAC5C,QAAI,CAAC,EAAG;AACR,UAAM,OAAO,cAAc,EAAE,CAAC,EAAE,KAAK,CAAC;AACtC,QAAI,CAAC,KAAM;AACX,UAAM,aAAS,8BAAU,MAAM,EAAE,WAAW,CAAC;AAC7C,UAAM,IAAI,KAAK,IAAI,MAAM,KAAK;AAC9B,SAAK,IAAI,QAAQ,IAAI,CAAC;AACtB,UAAM,KAAK,MAAM,IAAI,SAAS,GAAG,MAAM,IAAI,CAAC;AAC5C,QAAI,KAAK,EAAE,IAAI,MAAM,OAAO,EAAE,CAAC,EAAE,OAAO,CAAC;AAAA,EAC3C;AACA,SAAO;AACT;AAMA,SAAS,cAAc,GAAmB;AACxC,SAAO,EACJ,QAAQ,4BAA4B,IAAI,EACxC,QAAQ,cAAc,IAAI,EAC1B,QAAQ,oBAAoB,IAAI,EAChC,QAAQ,gBAAgB,IAAI,EAC5B,QAAQ,gBAAgB,IAAI,EAC5B,QAAQ,cAAc,IAAI;AAC/B;","names":[]}
|
|
@@ -0,0 +1,16 @@
|
|
|
1
|
+
import { HeadingSummary } from './metadataQueryTool.cjs';
|
|
2
|
+
import './sandboxTypes.cjs';
|
|
3
|
+
|
|
4
|
+
/**
|
|
5
|
+
* Collect an entry's headings from its MDX/Markdown BODY (frontmatter already
|
|
6
|
+
* stripped — `parseFrontmatter(...).body`).
|
|
7
|
+
*
|
|
8
|
+
* Inline markup is flattened the way the remark pass flattens it (`## The **bold**
|
|
9
|
+
* heading` → "The bold heading"), code fences are skipped, and ids follow the canon
|
|
10
|
+
* with per-document duplicate suffixes.
|
|
11
|
+
*/
|
|
12
|
+
declare function collectHeadings(body: string, opts?: {
|
|
13
|
+
sectionIds?: boolean;
|
|
14
|
+
}): HeadingSummary[];
|
|
15
|
+
|
|
16
|
+
export { HeadingSummary, collectHeadings };
|
|
@@ -0,0 +1,16 @@
|
|
|
1
|
+
import { HeadingSummary } from './metadataQueryTool.js';
|
|
2
|
+
import './sandboxTypes.js';
|
|
3
|
+
|
|
4
|
+
/**
|
|
5
|
+
* Collect an entry's headings from its MDX/Markdown BODY (frontmatter already
|
|
6
|
+
* stripped — `parseFrontmatter(...).body`).
|
|
7
|
+
*
|
|
8
|
+
* Inline markup is flattened the way the remark pass flattens it (`## The **bold**
|
|
9
|
+
* heading` → "The bold heading"), code fences are skipped, and ids follow the canon
|
|
10
|
+
* with per-document duplicate suffixes.
|
|
11
|
+
*/
|
|
12
|
+
declare function collectHeadings(body: string, opts?: {
|
|
13
|
+
sectionIds?: boolean;
|
|
14
|
+
}): HeadingSummary[];
|
|
15
|
+
|
|
16
|
+
export { HeadingSummary, collectHeadings };
|
|
@@ -0,0 +1,36 @@
|
|
|
1
|
+
import "./chunk-VHAA22YE.js";
|
|
2
|
+
import { headingId } from "@immediately-run/mdx-plugins";
|
|
3
|
+
function collectHeadings(body, opts = {}) {
|
|
4
|
+
const sectionIds = opts.sectionIds !== false;
|
|
5
|
+
const seen = /* @__PURE__ */ new Map();
|
|
6
|
+
const out = [];
|
|
7
|
+
let fenceMarker = null;
|
|
8
|
+
for (const line of body.split("\n")) {
|
|
9
|
+
const fenceMatch = /^(\s{0,3})(`{3,}|~{3,})/.exec(line);
|
|
10
|
+
if (fenceMarker) {
|
|
11
|
+
if (fenceMatch && line.trim().startsWith(fenceMarker)) fenceMarker = null;
|
|
12
|
+
continue;
|
|
13
|
+
}
|
|
14
|
+
if (fenceMatch) {
|
|
15
|
+
fenceMarker = fenceMatch[2][0].repeat(3);
|
|
16
|
+
continue;
|
|
17
|
+
}
|
|
18
|
+
const h = /^(#{1,6})[ \t]+(\S.*)$/.exec(line);
|
|
19
|
+
if (!h) continue;
|
|
20
|
+
const text = flattenInline(h[2].trim());
|
|
21
|
+
if (!text) continue;
|
|
22
|
+
const baseId = headingId(text, { sectionIds });
|
|
23
|
+
const n = seen.get(baseId) ?? 0;
|
|
24
|
+
seen.set(baseId, n + 1);
|
|
25
|
+
const id = n === 0 ? baseId : `${baseId}-${n}`;
|
|
26
|
+
out.push({ id, text, depth: h[1].length });
|
|
27
|
+
}
|
|
28
|
+
return out;
|
|
29
|
+
}
|
|
30
|
+
function flattenInline(s) {
|
|
31
|
+
return s.replace(/!?\[([^\]]*)\]\([^)]*\)/g, "$1").replace(/`([^`]*)`/g, "$1").replace(/\*\*([^*]+)\*\*/g, "$1").replace(/\*([^*]+)\*/g, "$1").replace(/__([^_]+)__/g, "$1").replace(/_([^_]+)_/g, "$1");
|
|
32
|
+
}
|
|
33
|
+
export {
|
|
34
|
+
collectHeadings
|
|
35
|
+
};
|
|
36
|
+
//# sourceMappingURL=collectHeadings.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"sources":["../src/collectHeadings.ts"],"sourcesContent":["// The headings index extension (GROVE_AGENT_SPEC §4): `headings: [{id, text, depth}]`\n// computed from an entry's BODY with the same `@immediately-run/mdx-plugins`\n// heading-anchor canon the render paths use — so an index heading's id IS the id a\n// reader's `#fragment` lands on, and section-level questions are answerable from the\n// index without body reads.\n//\n// IDS CANNOT DRIFT: every id is `headingId(text, { sectionIds })` from mdx-plugins,\n// with the same in-document duplicate counter (`baseId-2`, `-3`, …) the remark pass\n// applies. What this module adds is the WALK — a byte-level ATX scan used where the\n// remark tree is not at hand (the bundler's metadata scan, a dispatched corpus scan).\n// It walks only what corpus entries actually contain: top-level ATX headings\n// (`#`–`######`) outside fenced code blocks; headings carrying an author id\n// (MDX `{#…}`/JSX) are invisible to a byte scan and stay the remark pass's to own.\n//\n// Additive by design: an older index simply lacks `headings`, and readers degrade to\n// body reads (ways_of_working §6).\n\nimport { headingId } from '@immediately-run/mdx-plugins';\nimport type { HeadingSummary } from './metadataQueryTool';\n\nexport type { HeadingSummary };\n\n/**\n * Collect an entry's headings from its MDX/Markdown BODY (frontmatter already\n * stripped — `parseFrontmatter(...).body`).\n *\n * Inline markup is flattened the way the remark pass flattens it (`## The **bold**\n * heading` → \"The bold heading\"), code fences are skipped, and ids follow the canon\n * with per-document duplicate suffixes.\n */\nexport function collectHeadings(body: string, opts: { sectionIds?: boolean } = {}): HeadingSummary[] {\n const sectionIds = opts.sectionIds !== false;\n const seen = new Map<string, number>();\n const out: HeadingSummary[] = [];\n\n let fenceMarker: string | null = null; // inside a ``` or ~~~ block\n for (const line of body.split('\\n')) {\n const fenceMatch = /^(\\s{0,3})(`{3,}|~{3,})/.exec(line);\n if (fenceMarker) {\n if (fenceMatch && line.trim().startsWith(fenceMarker)) fenceMarker = null;\n continue;\n }\n if (fenceMatch) {\n fenceMarker = fenceMatch[2][0].repeat(3);\n continue;\n }\n const h = /^(#{1,6})[ \\t]+(\\S.*)$/.exec(line);\n if (!h) continue;\n const text = flattenInline(h[2].trim());\n if (!text) continue;\n const baseId = headingId(text, { sectionIds });\n const n = seen.get(baseId) ?? 0;\n seen.set(baseId, n + 1);\n const id = n === 0 ? baseId : `${baseId}-${n}`;\n out.push({ id, text, depth: h[1].length });\n }\n return out;\n}\n\n/** Flatten inline markup the way `headingText` does in the remark pass: emphasis and\n * code markers drop, link/image syntax keeps its text. Covers what corpus headings\n * actually carry; anything else passes through verbatim (and the id canon slugifies\n * punctuation anyway). */\nfunction flattenInline(s: string): string {\n return s\n .replace(/!?\\[([^\\]]*)\\]\\([^)]*\\)/g, '$1') // [text](url) /  → text\n .replace(/`([^`]*)`/g, '$1') // `code` → code\n .replace(/\\*\\*([^*]+)\\*\\*/g, '$1') // **bold** → bold\n .replace(/\\*([^*]+)\\*/g, '$1') // *em* → em\n .replace(/__([^_]+)__/g, '$1') // __bold__ → bold\n .replace(/_([^_]+)_/g, '$1'); // _em_ → em\n}\n"],"mappings":";AAiBA,SAAS,iBAAiB;AAanB,SAAS,gBAAgB,MAAc,OAAiC,CAAC,GAAqB;AACnG,QAAM,aAAa,KAAK,eAAe;AACvC,QAAM,OAAO,oBAAI,IAAoB;AACrC,QAAM,MAAwB,CAAC;AAE/B,MAAI,cAA6B;AACjC,aAAW,QAAQ,KAAK,MAAM,IAAI,GAAG;AACnC,UAAM,aAAa,0BAA0B,KAAK,IAAI;AACtD,QAAI,aAAa;AACf,UAAI,cAAc,KAAK,KAAK,EAAE,WAAW,WAAW,EAAG,eAAc;AACrE;AAAA,IACF;AACA,QAAI,YAAY;AACd,oBAAc,WAAW,CAAC,EAAE,CAAC,EAAE,OAAO,CAAC;AACvC;AAAA,IACF;AACA,UAAM,IAAI,yBAAyB,KAAK,IAAI;AAC5C,QAAI,CAAC,EAAG;AACR,UAAM,OAAO,cAAc,EAAE,CAAC,EAAE,KAAK,CAAC;AACtC,QAAI,CAAC,KAAM;AACX,UAAM,SAAS,UAAU,MAAM,EAAE,WAAW,CAAC;AAC7C,UAAM,IAAI,KAAK,IAAI,MAAM,KAAK;AAC9B,SAAK,IAAI,QAAQ,IAAI,CAAC;AACtB,UAAM,KAAK,MAAM,IAAI,SAAS,GAAG,MAAM,IAAI,CAAC;AAC5C,QAAI,KAAK,EAAE,IAAI,MAAM,OAAO,EAAE,CAAC,EAAE,OAAO,CAAC;AAAA,EAC3C;AACA,SAAO;AACT;AAMA,SAAS,cAAc,GAAmB;AACxC,SAAO,EACJ,QAAQ,4BAA4B,IAAI,EACxC,QAAQ,cAAc,IAAI,EAC1B,QAAQ,oBAAoB,IAAI,EAChC,QAAQ,gBAAgB,IAAI,EAC5B,QAAQ,gBAAgB,IAAI,EAC5B,QAAQ,cAAc,IAAI;AAC/B;","names":[]}
|
|
@@ -60,7 +60,9 @@ const fileExists = async (path) => {
|
|
|
60
60
|
};
|
|
61
61
|
const MainContentRedirect = ({ filename }) => {
|
|
62
62
|
const url = (0, import_routing.useTinkerableLink)(filename);
|
|
63
|
-
(0,
|
|
63
|
+
(0, import_react.useEffect)(() => {
|
|
64
|
+
(0, import_routing.navigate)(url);
|
|
65
|
+
}, [url]);
|
|
64
66
|
return /* @__PURE__ */ (0, import_jsx_runtime.jsxs)(import_jsx_runtime.Fragment, { children: [
|
|
65
67
|
"Redirecting to ",
|
|
66
68
|
filename
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"sources":["../../src/components/MainContent.tsx"],"sourcesContent":["import { Suspense, use, useMemo } from 'react';\nimport { ErrorBoundary } from 'react-error-boundary';\nimport { navigate, useTinkerableLink } from '../routing';\nimport { FILES_PREFIX, underAppRoot } from '../urlUtils';\nimport { sandboxFs, type SandboxFsPort } from '../fs';\n\nimport { defaultErrorComponent, defaultLoadingComponent } from './defaults';\n\n// Repo-relative candidate paths. These are kept repo-relative because the\n// returned path is reused below to build the redirect URL (which is anchored to\n// `/app` by the file router); only the filesystem existence check is resolved\n// under `APP_ROOT`, since `bundler.fs` is rooted at `/`.\nconst candidates = [\n '/src/App.tsx',\n '/src/App.ts',\n '/src/App.js',\n '/App.tsx',\n '/App.ts',\n '/App.js',\n '/README.md',\n '/README.mdx',\n '/README.html',\n];\n\n// R3-278: the existence probe goes through the SDK's OWN fs surface (`sandboxFs`),\n// not the injected bundler — this was the last direct `bundler.*` read on a\n// PUBLIC component, and the one with no fallback: with no injected bundler\n// (npm-fetched SDK, `vite dev`, pre-boot) the old read THREW. Unavailable fs\n// simply answers `false` for every candidate (the \"no main content file\" path),\n// so the component degrades instead of crashing — the regression case this\n// item exists to close.\nconst fileExists = async (path: string): Promise<[string, boolean]> => {\n const fs = sandboxFs();\n if (!fs) return [path, false];\n const absolute = underAppRoot(path);\n try {\n // stat when the port has it, else readFile (dirs reject with EISDIR → false).\n const stat = (fs.promises as { stat?: Function } | undefined)?.stat ?? (fs as { stat?: Function }).stat;\n if (typeof stat === 'function') {\n await stat.call(fs.promises ?? fs, absolute);\n return [path, true];\n }\n const holder = fs.promises ?? (fs as { readFile: NonNullable<SandboxFsPort['readFile']> });\n await holder.readFile(absolute);\n return [path, true];\n } catch {\n return [path, false];\n }\n};\n\nexport const MainContentRedirect = ({ filename }: { filename: string }) => {\n const url = useTinkerableLink(filename);\n navigate(url);\n return <>Redirecting to {filename}</>;\n};\n\nexport const MainContentInner = ({\n candidatesExistPromise,\n}: {\n candidatesExistPromise: Promise<[string, boolean][]>;\n}) => {\n const candidatesExist = use(candidatesExistPromise);\n const filename = candidatesExist.find(([_, exists]) => exists)?.[0];\n if (!filename) {\n // todo: show file list\n throw new Error(`No main content file present`);\n }\n return <MainContentRedirect filename={FILES_PREFIX + filename} />;\n};\n\nexport const MainContent = ({\n LoadingComponent = defaultLoadingComponent,\n ErrorComponent = defaultErrorComponent,\n}: {\n LoadingComponent?: typeof defaultLoadingComponent;\n ErrorComponent?: typeof defaultErrorComponent;\n} = {}) => {\n // TODO: when to invalidate?\n const candidatesExistPromise = useMemo(() => Promise.all(candidates.map(fileExists)), []);\n return (\n <ErrorBoundary fallbackRender={ErrorComponent}>\n <Suspense fallback={<LoadingComponent />}>\n <MainContentInner candidatesExistPromise={candidatesExistPromise} />\n </Suspense>\n </ErrorBoundary>\n );\n};\n"],"mappings":";;;;;;;;;;;;;;;;;;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;
|
|
1
|
+
{"version":3,"sources":["../../src/components/MainContent.tsx"],"sourcesContent":["import { Suspense, use, useEffect, useMemo } from 'react';\nimport { ErrorBoundary } from 'react-error-boundary';\nimport { navigate, useTinkerableLink } from '../routing';\nimport { FILES_PREFIX, underAppRoot } from '../urlUtils';\nimport { sandboxFs, type SandboxFsPort } from '../fs';\n\nimport { defaultErrorComponent, defaultLoadingComponent } from './defaults';\n\n// Repo-relative candidate paths. These are kept repo-relative because the\n// returned path is reused below to build the redirect URL (which is anchored to\n// `/app` by the file router); only the filesystem existence check is resolved\n// under `APP_ROOT`, since `bundler.fs` is rooted at `/`.\nconst candidates = [\n '/src/App.tsx',\n '/src/App.ts',\n '/src/App.js',\n '/App.tsx',\n '/App.ts',\n '/App.js',\n '/README.md',\n '/README.mdx',\n '/README.html',\n];\n\n// R3-278: the existence probe goes through the SDK's OWN fs surface (`sandboxFs`),\n// not the injected bundler — this was the last direct `bundler.*` read on a\n// PUBLIC component, and the one with no fallback: with no injected bundler\n// (npm-fetched SDK, `vite dev`, pre-boot) the old read THREW. Unavailable fs\n// simply answers `false` for every candidate (the \"no main content file\" path),\n// so the component degrades instead of crashing — the regression case this\n// item exists to close.\nconst fileExists = async (path: string): Promise<[string, boolean]> => {\n const fs = sandboxFs();\n if (!fs) return [path, false];\n const absolute = underAppRoot(path);\n try {\n // stat when the port has it, else readFile (dirs reject with EISDIR → false).\n const stat = (fs.promises as { stat?: Function } | undefined)?.stat ?? (fs as { stat?: Function }).stat;\n if (typeof stat === 'function') {\n await stat.call(fs.promises ?? fs, absolute);\n return [path, true];\n }\n const holder = fs.promises ?? (fs as { readFile: NonNullable<SandboxFsPort['readFile']> });\n await holder.readFile(absolute);\n return [path, true];\n } catch {\n return [path, false];\n }\n};\n\n// The redirect is a COMMIT-phase effect, not a render-phase call. `navigate()` only\n// posts `urlchange` and relies on the host pushing the resolved href back; calling it\n// during render re-navigated on every re-render, and on a slow host (local dev, a\n// region app booting at `/`) the push-back never settled before the next render —\n// an unbounded \"Redirecting to /files/src/App.tsx\" loop (site-main worked around it\n// by booting region apps past `/`, R3-240). An effect keyed on the target fires once\n// per distinct URL, which is the only thing a redirect should ever do.\nexport const MainContentRedirect = ({ filename }: { filename: string }) => {\n const url = useTinkerableLink(filename);\n useEffect(() => {\n navigate(url);\n }, [url]);\n return <>Redirecting to {filename}</>;\n};\n\nexport const MainContentInner = ({\n candidatesExistPromise,\n}: {\n candidatesExistPromise: Promise<[string, boolean][]>;\n}) => {\n const candidatesExist = use(candidatesExistPromise);\n const filename = candidatesExist.find(([_, exists]) => exists)?.[0];\n if (!filename) {\n // todo: show file list\n throw new Error(`No main content file present`);\n }\n return <MainContentRedirect filename={FILES_PREFIX + filename} />;\n};\n\nexport const MainContent = ({\n LoadingComponent = defaultLoadingComponent,\n ErrorComponent = defaultErrorComponent,\n}: {\n LoadingComponent?: typeof defaultLoadingComponent;\n ErrorComponent?: typeof defaultErrorComponent;\n} = {}) => {\n // TODO: when to invalidate?\n const candidatesExistPromise = useMemo(() => Promise.all(candidates.map(fileExists)), []);\n return (\n <ErrorBoundary fallbackRender={ErrorComponent}>\n <Suspense fallback={<LoadingComponent />}>\n <MainContentInner candidatesExistPromise={candidatesExistPromise} />\n </Suspense>\n </ErrorBoundary>\n );\n};\n"],"mappings":";;;;;;;;;;;;;;;;;;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AA8DS;AA9DT,mBAAkD;AAClD,kCAA8B;AAC9B,qBAA4C;AAC5C,sBAA2C;AAC3C,gBAA8C;AAE9C,sBAA+D;AAM/D,MAAM,aAAa;AAAA,EACjB;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AACF;AASA,MAAM,aAAa,OAAO,SAA6C;AACrE,QAAM,SAAK,qBAAU;AACrB,MAAI,CAAC,GAAI,QAAO,CAAC,MAAM,KAAK;AAC5B,QAAM,eAAW,8BAAa,IAAI;AAClC,MAAI;AAEF,UAAM,OAAQ,GAAG,UAA8C,QAAS,GAA2B;AACnG,QAAI,OAAO,SAAS,YAAY;AAC9B,YAAM,KAAK,KAAK,GAAG,YAAY,IAAI,QAAQ;AAC3C,aAAO,CAAC,MAAM,IAAI;AAAA,IACpB;AACA,UAAM,SAAS,GAAG,YAAa;AAC/B,UAAM,OAAO,SAAS,QAAQ;AAC9B,WAAO,CAAC,MAAM,IAAI;AAAA,EACpB,QAAQ;AACN,WAAO,CAAC,MAAM,KAAK;AAAA,EACrB;AACF;AASO,MAAM,sBAAsB,CAAC,EAAE,SAAS,MAA4B;AACzE,QAAM,UAAM,kCAAkB,QAAQ;AACtC,8BAAU,MAAM;AACd,iCAAS,GAAG;AAAA,EACd,GAAG,CAAC,GAAG,CAAC;AACR,SAAO,4EAAE;AAAA;AAAA,IAAgB;AAAA,KAAS;AACpC;AAEO,MAAM,mBAAmB,CAAC;AAAA,EAC/B;AACF,MAEM;AACJ,QAAM,sBAAkB,kBAAI,sBAAsB;AAClD,QAAM,WAAW,gBAAgB,KAAK,CAAC,CAAC,GAAG,MAAM,MAAM,MAAM,IAAI,CAAC;AAClE,MAAI,CAAC,UAAU;AAEb,UAAM,IAAI,MAAM,8BAA8B;AAAA,EAChD;AACA,SAAO,4CAAC,uBAAoB,UAAU,+BAAe,UAAU;AACjE;AAEO,MAAM,cAAc,CAAC;AAAA,EAC1B,mBAAmB;AAAA,EACnB,iBAAiB;AACnB,IAGI,CAAC,MAAM;AAET,QAAM,6BAAyB,sBAAQ,MAAM,QAAQ,IAAI,WAAW,IAAI,UAAU,CAAC,GAAG,CAAC,CAAC;AACxF,SACE,4CAAC,6CAAc,gBAAgB,gBAC7B,sDAAC,yBAAS,UAAU,4CAAC,oBAAiB,GACpC,sDAAC,oBAAiB,wBAAgD,GACpE,GACF;AAEJ;","names":[]}
|
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
import "../chunk-VHAA22YE.js";
|
|
2
2
|
import { Fragment, jsx, jsxs } from "react/jsx-runtime";
|
|
3
|
-
import { Suspense, use, useMemo } from "react";
|
|
3
|
+
import { Suspense, use, useEffect, useMemo } from "react";
|
|
4
4
|
import { ErrorBoundary } from "react-error-boundary";
|
|
5
5
|
import { navigate, useTinkerableLink } from "../routing";
|
|
6
6
|
import { FILES_PREFIX, underAppRoot } from "../urlUtils";
|
|
@@ -36,7 +36,9 @@ const fileExists = async (path) => {
|
|
|
36
36
|
};
|
|
37
37
|
const MainContentRedirect = ({ filename }) => {
|
|
38
38
|
const url = useTinkerableLink(filename);
|
|
39
|
-
|
|
39
|
+
useEffect(() => {
|
|
40
|
+
navigate(url);
|
|
41
|
+
}, [url]);
|
|
40
42
|
return /* @__PURE__ */ jsxs(Fragment, { children: [
|
|
41
43
|
"Redirecting to ",
|
|
42
44
|
filename
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"sources":["../../src/components/MainContent.tsx"],"sourcesContent":["import { Suspense, use, useMemo } from 'react';\nimport { ErrorBoundary } from 'react-error-boundary';\nimport { navigate, useTinkerableLink } from '../routing';\nimport { FILES_PREFIX, underAppRoot } from '../urlUtils';\nimport { sandboxFs, type SandboxFsPort } from '../fs';\n\nimport { defaultErrorComponent, defaultLoadingComponent } from './defaults';\n\n// Repo-relative candidate paths. These are kept repo-relative because the\n// returned path is reused below to build the redirect URL (which is anchored to\n// `/app` by the file router); only the filesystem existence check is resolved\n// under `APP_ROOT`, since `bundler.fs` is rooted at `/`.\nconst candidates = [\n '/src/App.tsx',\n '/src/App.ts',\n '/src/App.js',\n '/App.tsx',\n '/App.ts',\n '/App.js',\n '/README.md',\n '/README.mdx',\n '/README.html',\n];\n\n// R3-278: the existence probe goes through the SDK's OWN fs surface (`sandboxFs`),\n// not the injected bundler — this was the last direct `bundler.*` read on a\n// PUBLIC component, and the one with no fallback: with no injected bundler\n// (npm-fetched SDK, `vite dev`, pre-boot) the old read THREW. Unavailable fs\n// simply answers `false` for every candidate (the \"no main content file\" path),\n// so the component degrades instead of crashing — the regression case this\n// item exists to close.\nconst fileExists = async (path: string): Promise<[string, boolean]> => {\n const fs = sandboxFs();\n if (!fs) return [path, false];\n const absolute = underAppRoot(path);\n try {\n // stat when the port has it, else readFile (dirs reject with EISDIR → false).\n const stat = (fs.promises as { stat?: Function } | undefined)?.stat ?? (fs as { stat?: Function }).stat;\n if (typeof stat === 'function') {\n await stat.call(fs.promises ?? fs, absolute);\n return [path, true];\n }\n const holder = fs.promises ?? (fs as { readFile: NonNullable<SandboxFsPort['readFile']> });\n await holder.readFile(absolute);\n return [path, true];\n } catch {\n return [path, false];\n }\n};\n\nexport const MainContentRedirect = ({ filename }: { filename: string }) => {\n const url = useTinkerableLink(filename);\n navigate(url);\n return <>Redirecting to {filename}</>;\n};\n\nexport const MainContentInner = ({\n candidatesExistPromise,\n}: {\n candidatesExistPromise: Promise<[string, boolean][]>;\n}) => {\n const candidatesExist = use(candidatesExistPromise);\n const filename = candidatesExist.find(([_, exists]) => exists)?.[0];\n if (!filename) {\n // todo: show file list\n throw new Error(`No main content file present`);\n }\n return <MainContentRedirect filename={FILES_PREFIX + filename} />;\n};\n\nexport const MainContent = ({\n LoadingComponent = defaultLoadingComponent,\n ErrorComponent = defaultErrorComponent,\n}: {\n LoadingComponent?: typeof defaultLoadingComponent;\n ErrorComponent?: typeof defaultErrorComponent;\n} = {}) => {\n // TODO: when to invalidate?\n const candidatesExistPromise = useMemo(() => Promise.all(candidates.map(fileExists)), []);\n return (\n <ErrorBoundary fallbackRender={ErrorComponent}>\n <Suspense fallback={<LoadingComponent />}>\n <MainContentInner candidatesExistPromise={candidatesExistPromise} />\n </Suspense>\n </ErrorBoundary>\n );\n};\n"],"mappings":";
|
|
1
|
+
{"version":3,"sources":["../../src/components/MainContent.tsx"],"sourcesContent":["import { Suspense, use, useEffect, useMemo } from 'react';\nimport { ErrorBoundary } from 'react-error-boundary';\nimport { navigate, useTinkerableLink } from '../routing';\nimport { FILES_PREFIX, underAppRoot } from '../urlUtils';\nimport { sandboxFs, type SandboxFsPort } from '../fs';\n\nimport { defaultErrorComponent, defaultLoadingComponent } from './defaults';\n\n// Repo-relative candidate paths. These are kept repo-relative because the\n// returned path is reused below to build the redirect URL (which is anchored to\n// `/app` by the file router); only the filesystem existence check is resolved\n// under `APP_ROOT`, since `bundler.fs` is rooted at `/`.\nconst candidates = [\n '/src/App.tsx',\n '/src/App.ts',\n '/src/App.js',\n '/App.tsx',\n '/App.ts',\n '/App.js',\n '/README.md',\n '/README.mdx',\n '/README.html',\n];\n\n// R3-278: the existence probe goes through the SDK's OWN fs surface (`sandboxFs`),\n// not the injected bundler — this was the last direct `bundler.*` read on a\n// PUBLIC component, and the one with no fallback: with no injected bundler\n// (npm-fetched SDK, `vite dev`, pre-boot) the old read THREW. Unavailable fs\n// simply answers `false` for every candidate (the \"no main content file\" path),\n// so the component degrades instead of crashing — the regression case this\n// item exists to close.\nconst fileExists = async (path: string): Promise<[string, boolean]> => {\n const fs = sandboxFs();\n if (!fs) return [path, false];\n const absolute = underAppRoot(path);\n try {\n // stat when the port has it, else readFile (dirs reject with EISDIR → false).\n const stat = (fs.promises as { stat?: Function } | undefined)?.stat ?? (fs as { stat?: Function }).stat;\n if (typeof stat === 'function') {\n await stat.call(fs.promises ?? fs, absolute);\n return [path, true];\n }\n const holder = fs.promises ?? (fs as { readFile: NonNullable<SandboxFsPort['readFile']> });\n await holder.readFile(absolute);\n return [path, true];\n } catch {\n return [path, false];\n }\n};\n\n// The redirect is a COMMIT-phase effect, not a render-phase call. `navigate()` only\n// posts `urlchange` and relies on the host pushing the resolved href back; calling it\n// during render re-navigated on every re-render, and on a slow host (local dev, a\n// region app booting at `/`) the push-back never settled before the next render —\n// an unbounded \"Redirecting to /files/src/App.tsx\" loop (site-main worked around it\n// by booting region apps past `/`, R3-240). An effect keyed on the target fires once\n// per distinct URL, which is the only thing a redirect should ever do.\nexport const MainContentRedirect = ({ filename }: { filename: string }) => {\n const url = useTinkerableLink(filename);\n useEffect(() => {\n navigate(url);\n }, [url]);\n return <>Redirecting to {filename}</>;\n};\n\nexport const MainContentInner = ({\n candidatesExistPromise,\n}: {\n candidatesExistPromise: Promise<[string, boolean][]>;\n}) => {\n const candidatesExist = use(candidatesExistPromise);\n const filename = candidatesExist.find(([_, exists]) => exists)?.[0];\n if (!filename) {\n // todo: show file list\n throw new Error(`No main content file present`);\n }\n return <MainContentRedirect filename={FILES_PREFIX + filename} />;\n};\n\nexport const MainContent = ({\n LoadingComponent = defaultLoadingComponent,\n ErrorComponent = defaultErrorComponent,\n}: {\n LoadingComponent?: typeof defaultLoadingComponent;\n ErrorComponent?: typeof defaultErrorComponent;\n} = {}) => {\n // TODO: when to invalidate?\n const candidatesExistPromise = useMemo(() => Promise.all(candidates.map(fileExists)), []);\n return (\n <ErrorBoundary fallbackRender={ErrorComponent}>\n <Suspense fallback={<LoadingComponent />}>\n <MainContentInner candidatesExistPromise={candidatesExistPromise} />\n </Suspense>\n </ErrorBoundary>\n );\n};\n"],"mappings":";AA8DS,mBAcA,KAdA;AA9DT,SAAS,UAAU,KAAK,WAAW,eAAe;AAClD,SAAS,qBAAqB;AAC9B,SAAS,UAAU,yBAAyB;AAC5C,SAAS,cAAc,oBAAoB;AAC3C,SAAS,iBAAqC;AAE9C,SAAS,uBAAuB,+BAA+B;AAM/D,MAAM,aAAa;AAAA,EACjB;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AACF;AASA,MAAM,aAAa,OAAO,SAA6C;AACrE,QAAM,KAAK,UAAU;AACrB,MAAI,CAAC,GAAI,QAAO,CAAC,MAAM,KAAK;AAC5B,QAAM,WAAW,aAAa,IAAI;AAClC,MAAI;AAEF,UAAM,OAAQ,GAAG,UAA8C,QAAS,GAA2B;AACnG,QAAI,OAAO,SAAS,YAAY;AAC9B,YAAM,KAAK,KAAK,GAAG,YAAY,IAAI,QAAQ;AAC3C,aAAO,CAAC,MAAM,IAAI;AAAA,IACpB;AACA,UAAM,SAAS,GAAG,YAAa;AAC/B,UAAM,OAAO,SAAS,QAAQ;AAC9B,WAAO,CAAC,MAAM,IAAI;AAAA,EACpB,QAAQ;AACN,WAAO,CAAC,MAAM,KAAK;AAAA,EACrB;AACF;AASO,MAAM,sBAAsB,CAAC,EAAE,SAAS,MAA4B;AACzE,QAAM,MAAM,kBAAkB,QAAQ;AACtC,YAAU,MAAM;AACd,aAAS,GAAG;AAAA,EACd,GAAG,CAAC,GAAG,CAAC;AACR,SAAO,iCAAE;AAAA;AAAA,IAAgB;AAAA,KAAS;AACpC;AAEO,MAAM,mBAAmB,CAAC;AAAA,EAC/B;AACF,MAEM;AACJ,QAAM,kBAAkB,IAAI,sBAAsB;AAClD,QAAM,WAAW,gBAAgB,KAAK,CAAC,CAAC,GAAG,MAAM,MAAM,MAAM,IAAI,CAAC;AAClE,MAAI,CAAC,UAAU;AAEb,UAAM,IAAI,MAAM,8BAA8B;AAAA,EAChD;AACA,SAAO,oBAAC,uBAAoB,UAAU,eAAe,UAAU;AACjE;AAEO,MAAM,cAAc,CAAC;AAAA,EAC1B,mBAAmB;AAAA,EACnB,iBAAiB;AACnB,IAGI,CAAC,MAAM;AAET,QAAM,yBAAyB,QAAQ,MAAM,QAAQ,IAAI,WAAW,IAAI,UAAU,CAAC,GAAG,CAAC,CAAC;AACxF,SACE,oBAAC,iBAAc,gBAAgB,gBAC7B,8BAAC,YAAS,UAAU,oBAAC,oBAAiB,GACpC,8BAAC,oBAAiB,wBAAgD,GACpE,GACF;AAEJ;","names":[]}
|
package/dist/corpus.cjs
CHANGED
|
@@ -18,66 +18,17 @@ var __copyProps = (to, from, except, desc) => {
|
|
|
18
18
|
var __toCommonJS = (mod) => __copyProps(__defProp({}, "__esModule", { value: true }), mod);
|
|
19
19
|
var corpus_exports = {};
|
|
20
20
|
__export(corpus_exports, {
|
|
21
|
-
CorpusContext: () =>
|
|
22
|
-
fromCorpusPath: () =>
|
|
23
|
-
toCorpusPath: () =>
|
|
24
|
-
useCorpus: () =>
|
|
25
|
-
useCorpusEntries: () =>
|
|
26
|
-
useCorpusEntry: () =>
|
|
27
|
-
useCurrentEntry: () => useCurrentEntry
|
|
21
|
+
CorpusContext: () => import_bundle.BundleContext,
|
|
22
|
+
fromCorpusPath: () => import_bundle.fromBundlePath,
|
|
23
|
+
toCorpusPath: () => import_bundle.toBundlePath,
|
|
24
|
+
useCorpus: () => import_bundle.useBundle,
|
|
25
|
+
useCorpusEntries: () => import_bundle.useBundleEntries,
|
|
26
|
+
useCorpusEntry: () => import_bundle.useBundleEntry,
|
|
27
|
+
useCurrentEntry: () => import_bundle2.useCurrentEntry
|
|
28
28
|
});
|
|
29
29
|
module.exports = __toCommonJS(corpus_exports);
|
|
30
|
-
var
|
|
31
|
-
var
|
|
32
|
-
const EMPTY_SCOPE = { root: null, entry: null, toHref: (p) => p };
|
|
33
|
-
const CorpusContext = (0, import_react.createContext)(EMPTY_SCOPE);
|
|
34
|
-
const useCorpus = () => (0, import_react.use)(CorpusContext);
|
|
35
|
-
const toCorpusPath = (absolute, root) => {
|
|
36
|
-
if (root === null) return null;
|
|
37
|
-
const base = root.replace(/\/+$/, "");
|
|
38
|
-
if (base === "") return absolute;
|
|
39
|
-
if (!absolute.startsWith(`${base}/`)) return null;
|
|
40
|
-
return absolute.slice(base.length);
|
|
41
|
-
};
|
|
42
|
-
const fromCorpusPath = (corpusPath, root) => {
|
|
43
|
-
if (root === null) return null;
|
|
44
|
-
const base = root.replace(/\/+$/, "");
|
|
45
|
-
return `${base}${corpusPath.startsWith("/") ? "" : "/"}${corpusPath}`;
|
|
46
|
-
};
|
|
47
|
-
const useCorpusEntries = () => {
|
|
48
|
-
const files = (0, import_metadataSource.useMetadataStore)();
|
|
49
|
-
const { root, toHref } = useCorpus();
|
|
50
|
-
return (0, import_react.useMemo)(() => {
|
|
51
|
-
if (root === null) return [];
|
|
52
|
-
const out = [];
|
|
53
|
-
for (const [absolute, meta] of Object.entries(files)) {
|
|
54
|
-
const path = toCorpusPath(absolute, root);
|
|
55
|
-
if (path === null) continue;
|
|
56
|
-
out.push({ path, href: toHref(path), meta });
|
|
57
|
-
}
|
|
58
|
-
out.sort((a, b) => a.path.localeCompare(b.path));
|
|
59
|
-
return out;
|
|
60
|
-
}, [files, root, toHref]);
|
|
61
|
-
};
|
|
62
|
-
const useCorpusEntry = (corpusPath) => {
|
|
63
|
-
const files = (0, import_metadataSource.useMetadataStore)();
|
|
64
|
-
const { root } = useCorpus();
|
|
65
|
-
return (0, import_react.useMemo)(() => {
|
|
66
|
-
const absolute = fromCorpusPath(corpusPath, root);
|
|
67
|
-
return absolute === null ? void 0 : files[absolute];
|
|
68
|
-
}, [corpusPath, files, root]);
|
|
69
|
-
};
|
|
70
|
-
const useCurrentEntry = () => {
|
|
71
|
-
const files = (0, import_metadataSource.useMetadataStore)();
|
|
72
|
-
const { root, entry, toHref } = useCorpus();
|
|
73
|
-
return (0, import_react.useMemo)(() => {
|
|
74
|
-
if (root === null || entry === null) return null;
|
|
75
|
-
const absolute = fromCorpusPath(entry, root);
|
|
76
|
-
const meta = absolute === null ? void 0 : files[absolute];
|
|
77
|
-
if (meta === void 0) return null;
|
|
78
|
-
return { path: entry, href: toHref(entry), meta };
|
|
79
|
-
}, [files, root, entry, toHref]);
|
|
80
|
-
};
|
|
30
|
+
var import_bundle = require("./bundle");
|
|
31
|
+
var import_bundle2 = require("./bundle");
|
|
81
32
|
// Annotate the CommonJS export names for ESM import in node:
|
|
82
33
|
0 && (module.exports = {
|
|
83
34
|
CorpusContext,
|
package/dist/corpus.cjs.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"sources":["../src/corpus.ts"],"sourcesContent":["//
|
|
1
|
+
{"version":3,"sources":["../src/corpus.ts"],"sourcesContent":["// DEPRECATED alias surface — the pre-2026-08-31 spelling of `./bundle` (R3-482).\n//\n// `core_concepts §7a`/§11 renamed the file-collection concept `corpus` → **bundle**\n// on 2026-08-22; `./bundle.ts` is the implementation and the canonical spelling.\n// These eight names are in `api-snapshot.json`, so `ways_of_working §6`'s\n// forever-compat rule applies: an app pinned to an older SDK, or one nobody in this\n// org can grep, keeps working. Removing them would be its own PR and may simply\n// never happen.\n//\n// **Every name here is a RE-EXPORT, never a re-declaration.** `BundleContext` in\n// particular must stay one object across both spellings — a second `createContext`\n// would make a provider written as `<CorpusContext>` invisible to `useBundle`, which\n// is exactly the silent breakage a compatibility alias exists to prevent.\n\nexport type {\n /** @deprecated Renamed to `BundleScope` (R3-482). */\n BundleScope as CorpusScope,\n /** @deprecated Renamed to `BundleEntry` (R3-482). */\n BundleEntry as CorpusEntry,\n} from './bundle';\n\nexport {\n /** @deprecated Renamed to `BundleContext` (R3-482). Same object — safe to mix. */\n BundleContext as CorpusContext,\n /** @deprecated Renamed to `useBundle` (R3-482). */\n useBundle as useCorpus,\n /** @deprecated Renamed to `useBundleEntries` (R3-482). */\n useBundleEntries as useCorpusEntries,\n /** @deprecated Renamed to `useBundleEntry` (R3-482). */\n useBundleEntry as useCorpusEntry,\n /** @deprecated Renamed to `toBundlePath` (R3-482). */\n toBundlePath as toCorpusPath,\n /** @deprecated Renamed to `fromBundlePath` (R3-482). */\n fromBundlePath as fromCorpusPath,\n} from './bundle';\n\n// `useCurrentEntry` carries no `corpus` token, so it is not renamed — but it IS\n// re-exported, because `@immediately-run/sdk/corpus` is a real subpath (the `./*`\n// wildcard in `exports`) and dropping a name from it would shrink that module's\n// surface. `api:check` catches exactly this.\nexport { useCurrentEntry } from './bundle';\n"],"mappings":";;;;;;;;;;;;;;;;;;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAqBA,oBAaO;AAMP,IAAAA,iBAAgC;","names":["import_bundle"]}
|
package/dist/corpus.d.cts
CHANGED
|
@@ -1,63 +1,3 @@
|
|
|
1
|
-
|
|
2
|
-
import
|
|
3
|
-
|
|
4
|
-
/** What a corpus viewer declares about the corpus it is rendering. */
|
|
5
|
-
interface CorpusScope {
|
|
6
|
-
/**
|
|
7
|
-
* Absolute filesystem path of the corpus root, WITHOUT a trailing slash
|
|
8
|
-
* (`/app/content` in a fork, `/mnt/<hash>` under dispatch), or `null` when the
|
|
9
|
-
* surrounding app is not rendering a corpus — the default, which leaves every hook here
|
|
10
|
-
* returning the empty result rather than guessing a root.
|
|
11
|
-
*/
|
|
12
|
-
root: string | null;
|
|
13
|
-
/** Corpus-absolute path of the entry currently being read (`/roadmap/R3-174.mdx`), or
|
|
14
|
-
* `null` when nothing is. This is the entry, NOT the file being rendered: a component
|
|
15
|
-
* in a `_layout.mdx` wrapping that entry sees the entry, which is what makes furniture
|
|
16
|
-
* in the layout chain (a status line, a dependency rail) able to describe the page. */
|
|
17
|
-
entry: string | null;
|
|
18
|
-
/** Corpus-absolute path → the href to navigate to it. Supplied by the viewer; the
|
|
19
|
-
* identity function by default, which is correct for a viewer whose URL space IS the
|
|
20
|
-
* corpus space. */
|
|
21
|
-
toHref: (corpusPath: string) => string;
|
|
22
|
-
}
|
|
23
|
-
/** Ambient corpus scope. A corpus-rendering app wraps its content tree in
|
|
24
|
-
* `<CorpusContext value={{ root, entry, toHref }}>`; nesting a second provider inside a
|
|
25
|
-
* rendered sub-corpus makes the innermost win, as with {@link LinkSpaceContext}. */
|
|
26
|
-
declare const CorpusContext: react.Context<CorpusScope>;
|
|
27
|
-
/** Read the ambient corpus scope. Every hook below is a convenience over this. */
|
|
28
|
-
declare const useCorpus: () => CorpusScope;
|
|
29
|
-
/**
|
|
30
|
-
* Filesystem-absolute path → corpus-absolute, or `null` when the path is not inside the
|
|
31
|
-
* corpus. Exact-root and separator-boundary aware, so `/mnt/hash2/x` is not treated as
|
|
32
|
-
* living under `/mnt/hash`.
|
|
33
|
-
*/
|
|
34
|
-
declare const toCorpusPath: (absolute: string, root: string | null) => string | null;
|
|
35
|
-
/** Corpus-absolute path → filesystem-absolute, or `null` without a root. The inverse of
|
|
36
|
-
* {@link toCorpusPath}, for the rare content component that must read raw bytes. */
|
|
37
|
-
declare const fromCorpusPath: (corpusPath: string, root: string | null) => string | null;
|
|
38
|
-
/** One entry as content sees it: where it is, where it links, and its frontmatter. */
|
|
39
|
-
interface CorpusEntry<T = Metadata> {
|
|
40
|
-
/** Corpus-absolute path (`/roadmap/R3-174.mdx`). */
|
|
41
|
-
path: string;
|
|
42
|
-
/** The href that navigates to it, per the viewer's mapping. */
|
|
43
|
-
href: string;
|
|
44
|
-
meta: T;
|
|
45
|
-
}
|
|
46
|
-
/**
|
|
47
|
-
* Every entry in the surrounding corpus, with corpus-absolute paths and viewer-supplied
|
|
48
|
-
* hrefs — the surface a content component queries instead of {@link useMetadataQuery},
|
|
49
|
-
* whose keys are filesystem-absolute and therefore carry the mount prefix.
|
|
50
|
-
*
|
|
51
|
-
* Returns an empty array outside a corpus, so a component written for a corpus renders
|
|
52
|
-
* nothing rather than throwing when someone drops it elsewhere. The array keeps its
|
|
53
|
-
* identity while the store and root are unchanged, so it is safe in dependency arrays.
|
|
54
|
-
*/
|
|
55
|
-
declare const useCorpusEntries: <T = Metadata>() => CorpusEntry<T>[];
|
|
56
|
-
/** One entry's frontmatter by corpus-absolute path, or `undefined`. */
|
|
57
|
-
declare const useCorpusEntry: <T = Metadata>(corpusPath: string) => T | undefined;
|
|
58
|
-
/** The entry currently being read — `null` outside a corpus, or when the viewer declares
|
|
59
|
-
* no entry (a directory listing, a 404). See {@link CorpusScope.entry} for why this is
|
|
60
|
-
* the entry rather than the file the component happens to be written in. */
|
|
61
|
-
declare const useCurrentEntry: <T = Metadata>() => CorpusEntry<T> | null;
|
|
62
|
-
|
|
63
|
-
export { CorpusContext, type CorpusEntry, type CorpusScope, fromCorpusPath, toCorpusPath, useCorpus, useCorpusEntries, useCorpusEntry, useCurrentEntry };
|
|
1
|
+
export { BundleContext as CorpusContext, BundleEntry as CorpusEntry, BundleScope as CorpusScope, fromBundlePath as fromCorpusPath, toBundlePath as toCorpusPath, useBundle as useCorpus, useBundleEntries as useCorpusEntries, useBundleEntry as useCorpusEntry, useCurrentEntry } from './bundle.cjs';
|
|
2
|
+
import 'react';
|
|
3
|
+
import './sandboxTypes.cjs';
|
package/dist/corpus.d.ts
CHANGED
|
@@ -1,63 +1,3 @@
|
|
|
1
|
-
|
|
2
|
-
import
|
|
3
|
-
|
|
4
|
-
/** What a corpus viewer declares about the corpus it is rendering. */
|
|
5
|
-
interface CorpusScope {
|
|
6
|
-
/**
|
|
7
|
-
* Absolute filesystem path of the corpus root, WITHOUT a trailing slash
|
|
8
|
-
* (`/app/content` in a fork, `/mnt/<hash>` under dispatch), or `null` when the
|
|
9
|
-
* surrounding app is not rendering a corpus — the default, which leaves every hook here
|
|
10
|
-
* returning the empty result rather than guessing a root.
|
|
11
|
-
*/
|
|
12
|
-
root: string | null;
|
|
13
|
-
/** Corpus-absolute path of the entry currently being read (`/roadmap/R3-174.mdx`), or
|
|
14
|
-
* `null` when nothing is. This is the entry, NOT the file being rendered: a component
|
|
15
|
-
* in a `_layout.mdx` wrapping that entry sees the entry, which is what makes furniture
|
|
16
|
-
* in the layout chain (a status line, a dependency rail) able to describe the page. */
|
|
17
|
-
entry: string | null;
|
|
18
|
-
/** Corpus-absolute path → the href to navigate to it. Supplied by the viewer; the
|
|
19
|
-
* identity function by default, which is correct for a viewer whose URL space IS the
|
|
20
|
-
* corpus space. */
|
|
21
|
-
toHref: (corpusPath: string) => string;
|
|
22
|
-
}
|
|
23
|
-
/** Ambient corpus scope. A corpus-rendering app wraps its content tree in
|
|
24
|
-
* `<CorpusContext value={{ root, entry, toHref }}>`; nesting a second provider inside a
|
|
25
|
-
* rendered sub-corpus makes the innermost win, as with {@link LinkSpaceContext}. */
|
|
26
|
-
declare const CorpusContext: react.Context<CorpusScope>;
|
|
27
|
-
/** Read the ambient corpus scope. Every hook below is a convenience over this. */
|
|
28
|
-
declare const useCorpus: () => CorpusScope;
|
|
29
|
-
/**
|
|
30
|
-
* Filesystem-absolute path → corpus-absolute, or `null` when the path is not inside the
|
|
31
|
-
* corpus. Exact-root and separator-boundary aware, so `/mnt/hash2/x` is not treated as
|
|
32
|
-
* living under `/mnt/hash`.
|
|
33
|
-
*/
|
|
34
|
-
declare const toCorpusPath: (absolute: string, root: string | null) => string | null;
|
|
35
|
-
/** Corpus-absolute path → filesystem-absolute, or `null` without a root. The inverse of
|
|
36
|
-
* {@link toCorpusPath}, for the rare content component that must read raw bytes. */
|
|
37
|
-
declare const fromCorpusPath: (corpusPath: string, root: string | null) => string | null;
|
|
38
|
-
/** One entry as content sees it: where it is, where it links, and its frontmatter. */
|
|
39
|
-
interface CorpusEntry<T = Metadata> {
|
|
40
|
-
/** Corpus-absolute path (`/roadmap/R3-174.mdx`). */
|
|
41
|
-
path: string;
|
|
42
|
-
/** The href that navigates to it, per the viewer's mapping. */
|
|
43
|
-
href: string;
|
|
44
|
-
meta: T;
|
|
45
|
-
}
|
|
46
|
-
/**
|
|
47
|
-
* Every entry in the surrounding corpus, with corpus-absolute paths and viewer-supplied
|
|
48
|
-
* hrefs — the surface a content component queries instead of {@link useMetadataQuery},
|
|
49
|
-
* whose keys are filesystem-absolute and therefore carry the mount prefix.
|
|
50
|
-
*
|
|
51
|
-
* Returns an empty array outside a corpus, so a component written for a corpus renders
|
|
52
|
-
* nothing rather than throwing when someone drops it elsewhere. The array keeps its
|
|
53
|
-
* identity while the store and root are unchanged, so it is safe in dependency arrays.
|
|
54
|
-
*/
|
|
55
|
-
declare const useCorpusEntries: <T = Metadata>() => CorpusEntry<T>[];
|
|
56
|
-
/** One entry's frontmatter by corpus-absolute path, or `undefined`. */
|
|
57
|
-
declare const useCorpusEntry: <T = Metadata>(corpusPath: string) => T | undefined;
|
|
58
|
-
/** The entry currently being read — `null` outside a corpus, or when the viewer declares
|
|
59
|
-
* no entry (a directory listing, a 404). See {@link CorpusScope.entry} for why this is
|
|
60
|
-
* the entry rather than the file the component happens to be written in. */
|
|
61
|
-
declare const useCurrentEntry: <T = Metadata>() => CorpusEntry<T> | null;
|
|
62
|
-
|
|
63
|
-
export { CorpusContext, type CorpusEntry, type CorpusScope, fromCorpusPath, toCorpusPath, useCorpus, useCorpusEntries, useCorpusEntry, useCurrentEntry };
|
|
1
|
+
export { BundleContext as CorpusContext, BundleEntry as CorpusEntry, BundleScope as CorpusScope, fromBundlePath as fromCorpusPath, toBundlePath as toCorpusPath, useBundle as useCorpus, useBundleEntries as useCorpusEntries, useBundleEntry as useCorpusEntry, useCurrentEntry } from './bundle.js';
|
|
2
|
+
import 'react';
|
|
3
|
+
import './sandboxTypes.js';
|