@immediately-run/sdk 0.40.0 → 0.42.0
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/components/HeadingAnchor.cjs +18 -2
- package/dist/components/HeadingAnchor.cjs.map +1 -1
- package/dist/components/HeadingAnchor.js +18 -2
- package/dist/components/HeadingAnchor.js.map +1 -1
- package/dist/components/Include.cjs +2 -0
- package/dist/components/Include.cjs.map +1 -1
- package/dist/components/Include.d.cts +7 -1
- package/dist/components/Include.d.ts +7 -1
- package/dist/components/Include.js +2 -0
- package/dist/components/Include.js.map +1 -1
- package/dist/components/SafeInclude.cjs +18 -4
- package/dist/components/SafeInclude.cjs.map +1 -1
- package/dist/components/SafeInclude.d.cts +4 -1
- package/dist/components/SafeInclude.d.ts +4 -1
- package/dist/components/SafeInclude.js +18 -5
- package/dist/components/SafeInclude.js.map +1 -1
- package/dist/urlUtils.cjs +4 -2
- package/dist/urlUtils.cjs.map +1 -1
- package/dist/urlUtils.d.cts +24 -0
- package/dist/urlUtils.d.ts +24 -0
- package/dist/urlUtils.js +4 -2
- package/dist/urlUtils.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 +1 -1
|
@@ -22,16 +22,32 @@ __export(HeadingAnchor_exports, {
|
|
|
22
22
|
});
|
|
23
23
|
module.exports = __toCommonJS(HeadingAnchor_exports);
|
|
24
24
|
var import_jsx_runtime = require("react/jsx-runtime");
|
|
25
|
+
var import_react = require("react");
|
|
26
|
+
var import_scrollToId = require("../scrollToId");
|
|
27
|
+
var import_TinkerableContext = require("../TinkerableContext");
|
|
28
|
+
var import_urlUtils = require("../urlUtils");
|
|
29
|
+
var import_Link = require("./Link");
|
|
25
30
|
const HeadingAnchor = ({
|
|
26
31
|
id,
|
|
27
32
|
...rest
|
|
28
33
|
}) => {
|
|
34
|
+
const ctx = (0, import_react.use)(import_TinkerableContext.TinkerableContext);
|
|
35
|
+
const onAnchorClick = (0, import_react.useCallback)(
|
|
36
|
+
(e) => {
|
|
37
|
+
if (e.metaKey || e.ctrlKey || e.shiftKey || e.altKey || e.button !== 0) return;
|
|
38
|
+
e.preventDefault();
|
|
39
|
+
if (id) (0, import_scrollToId.scrollToId)(id);
|
|
40
|
+
},
|
|
41
|
+
[id]
|
|
42
|
+
);
|
|
29
43
|
if (!id) return null;
|
|
44
|
+
const href = ctx?.navigationState ? (0, import_urlUtils.constructOuterUrl)(ctx.outerHref, `#${id}`, ctx.navigationState) : `#${id}`;
|
|
30
45
|
return /* @__PURE__ */ (0, import_jsx_runtime.jsx)(
|
|
31
|
-
|
|
46
|
+
import_Link.FragmentLink,
|
|
32
47
|
{
|
|
33
48
|
className: "ir-heading-anchor",
|
|
34
|
-
href
|
|
49
|
+
href,
|
|
50
|
+
onClick: onAnchorClick,
|
|
35
51
|
"aria-label": "Permalink to this heading",
|
|
36
52
|
...rest,
|
|
37
53
|
children: /* @__PURE__ */ (0, import_jsx_runtime.jsx)("span", { "aria-hidden": "true", children: "#" })
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"sources":["../../src/components/HeadingAnchor.tsx"],"sourcesContent":["import { ReactNode } from 'react';\n\n/**\n * Default MDX `HeadingAnchor` component — the render target for the autolink anchor\n * the transpiler's heading-slug plugin (R3-186, `MARKDOWN_SYNTAX_SPEC §15.4`)\n * prepends to every heading. That plugin sets the heading's own `id` (a text slug,\n * or a `sec-…` section id for a numbered heading, R3-211) and emits\n * `<HeadingAnchor id=\"<that id>\" />` as the heading's first child.\n *\n * It is registered in {@link DEFAULT_MDX_COMPONENTS} so a heading anchor renders\n * even in a plain-markdown repo that never calls `boot({ mdxComponents })` — the\n * MDX missing-reference guard never fires (§11.2 phantom defaults). The markup is\n * semantic and accessible — an `aria`-labelled `<a href=\"#id\">` permalink — but\n * **styling is intentionally minimal** (`§15.4` honesty note): an app supplies CSS\n * targeting the `ir-heading-anchor` class to reveal it on hover / add an icon, or\n * overrides this component via `boot({ mdxComponents: { HeadingAnchor } })` to\n * change the icon, position, or behaviour (e.g. copy-permalink-to-clipboard) of\n * every heading anchor in every content file at once (§15.4 late binding).\n *\n * `id` is the *heading's own* id, so the permalink `#id` is the same URL a reader\n * copies and (for a `sec-…` id) an agent computes from a `§`-citation with zero\n * lookup. A missing/empty `id` (defensive — the plugin always supplies one)\n * renders nothing rather than a dead `#` link.\n */\nexport const HeadingAnchor = ({\n id,\n ...rest\n}: {\n id?: string;\n} & Omit<React.AnchorHTMLAttributes<HTMLAnchorElement>, 'href'>): ReactNode => {\n if (!id) return null;\n return (\n <
|
|
1
|
+
{"version":3,"sources":["../../src/components/HeadingAnchor.tsx"],"sourcesContent":["import { ReactNode, use, useCallback } from 'react';\nimport { scrollToId } from '../scrollToId';\nimport { TinkerableContext } from '../TinkerableContext';\nimport { constructOuterUrl } from '../urlUtils';\nimport { FragmentLink } from './Link';\n\n/**\n * Default MDX `HeadingAnchor` component — the render target for the autolink anchor\n * the transpiler's heading-slug plugin (R3-186, `MARKDOWN_SYNTAX_SPEC §15.4`)\n * prepends to every heading. That plugin sets the heading's own `id` (a text slug,\n * or a `sec-…` section id for a numbered heading, R3-211) and emits\n * `<HeadingAnchor id=\"<that id>\" />` as the heading's first child.\n *\n * It is registered in {@link DEFAULT_MDX_COMPONENTS} so a heading anchor renders\n * even in a plain-markdown repo that never calls `boot({ mdxComponents })` — the\n * MDX missing-reference guard never fires (§11.2 phantom defaults). The markup is\n * semantic and accessible — an `aria`-labelled `<a href=\"#id\">` permalink — but\n * **styling is intentionally minimal** (`§15.4` honesty note): an app supplies CSS\n * targeting the `ir-heading-anchor` class to reveal it on hover / add an icon, or\n * overrides this component via `boot({ mdxComponents: { HeadingAnchor } })` to\n * change the icon, position, or behaviour (e.g. copy-permalink-to-clipboard) of\n * every heading anchor in every content file at once (§15.4 late binding).\n *\n * `id` is the *heading's own* id, so the permalink `#id` is the same URL a reader\n * copies and (for a `sec-…` id) an agent computes from a `§`-citation with zero\n * lookup. A missing/empty `id` (defensive — the plugin always supplies one)\n * renders nothing rather than a dead `#` link.\n */\nexport const HeadingAnchor = ({\n id,\n ...rest\n}: {\n id?: string;\n} & Omit<React.AnchorHTMLAttributes<HTMLAnchorElement>, 'href'>): ReactNode => {\n // ⚠ A BARE `#id` IS THE WRONG HREF INSIDE A SANDBOXED APP, and wrong in a way that only\n // shows up when someone copies the link. The app runs in an iframe whose document URL is\n // the SANDBOX's (`https://sandbox.immediately.run/index.html?href=…`), so the browser\n // resolves `#id` against THAT — \"copy link address\" on a heading yields a\n // sandbox-internal URL that means nothing to anyone else. Reported from a real wiki\n // (2026-08-14) as exactly that URL instead of the entry's.\n //\n // Both halves have to be right, and they pull in opposite directions:\n // • the HREF must be absolute in the HOST's space, so copy-link / middle-click /\n // open-in-new-tab all produce a URL that resolves for a reader;\n // • the CLICK must NOT navigate to it — that would be a full page load to the page you\n // are already on. It scrolls, leaving the sandbox URL the host owns untouched.\n //\n // `FragmentLink` is the SDK's existing home for the second half; it runs the caller's\n // `onClick` first and stands down if it preventDefaults, which is what lets the href be\n // absolute here while the behaviour stays a scroll.\n const ctx = use(TinkerableContext);\n const onAnchorClick = useCallback(\n (e: React.MouseEvent<HTMLAnchorElement>) => {\n // Let a modified click through: cmd/ctrl/middle-click means \"open the permalink\",\n // and that is precisely the case the absolute href exists to serve.\n if (e.metaKey || e.ctrlKey || e.shiftKey || e.altKey || e.button !== 0) return;\n e.preventDefault();\n if (id) scrollToId(id);\n },\n [id]\n );\n if (!id) return null;\n // No context (a plain-markdown repo that never called `boot()`) → keep the old bare\n // fragment, which FragmentLink handles on its own.\n const href = ctx?.navigationState\n ? constructOuterUrl(ctx.outerHref, `#${id}`, ctx.navigationState)\n : `#${id}`;\n return (\n <FragmentLink\n className=\"ir-heading-anchor\"\n href={href}\n onClick={onAnchorClick}\n aria-label=\"Permalink to this heading\"\n {...rest}\n >\n <span aria-hidden=\"true\">#</span>\n </FragmentLink>\n );\n};\n"],"mappings":";;;;;;;;;;;;;;;;;;AAAA;AAAA;AAAA;AAAA;AAAA;AA2EM;AA3EN,mBAA4C;AAC5C,wBAA2B;AAC3B,+BAAkC;AAClC,sBAAkC;AAClC,kBAA6B;AAwBtB,MAAM,gBAAgB,CAAC;AAAA,EAC5B;AAAA,EACA,GAAG;AACL,MAE+E;AAiB7E,QAAM,UAAM,kBAAI,0CAAiB;AACjC,QAAM,oBAAgB;AAAA,IACpB,CAAC,MAA2C;AAG1C,UAAI,EAAE,WAAW,EAAE,WAAW,EAAE,YAAY,EAAE,UAAU,EAAE,WAAW,EAAG;AACxE,QAAE,eAAe;AACjB,UAAI,GAAI,mCAAW,EAAE;AAAA,IACvB;AAAA,IACA,CAAC,EAAE;AAAA,EACL;AACA,MAAI,CAAC,GAAI,QAAO;AAGhB,QAAM,OAAO,KAAK,sBACd,mCAAkB,IAAI,WAAW,IAAI,EAAE,IAAI,IAAI,eAAe,IAC9D,IAAI,EAAE;AACV,SACE;AAAA,IAAC;AAAA;AAAA,MACC,WAAU;AAAA,MACV;AAAA,MACA,SAAS;AAAA,MACT,cAAW;AAAA,MACV,GAAG;AAAA,MAEJ,sDAAC,UAAK,eAAY,QAAO,eAAC;AAAA;AAAA,EAC5B;AAEJ;","names":[]}
|
|
@@ -1,15 +1,31 @@
|
|
|
1
1
|
import "../chunk-VHAA22YE.js";
|
|
2
2
|
import { jsx } from "react/jsx-runtime";
|
|
3
|
+
import { use, useCallback } from "react";
|
|
4
|
+
import { scrollToId } from "../scrollToId";
|
|
5
|
+
import { TinkerableContext } from "../TinkerableContext";
|
|
6
|
+
import { constructOuterUrl } from "../urlUtils";
|
|
7
|
+
import { FragmentLink } from "./Link";
|
|
3
8
|
const HeadingAnchor = ({
|
|
4
9
|
id,
|
|
5
10
|
...rest
|
|
6
11
|
}) => {
|
|
12
|
+
const ctx = use(TinkerableContext);
|
|
13
|
+
const onAnchorClick = useCallback(
|
|
14
|
+
(e) => {
|
|
15
|
+
if (e.metaKey || e.ctrlKey || e.shiftKey || e.altKey || e.button !== 0) return;
|
|
16
|
+
e.preventDefault();
|
|
17
|
+
if (id) scrollToId(id);
|
|
18
|
+
},
|
|
19
|
+
[id]
|
|
20
|
+
);
|
|
7
21
|
if (!id) return null;
|
|
22
|
+
const href = ctx?.navigationState ? constructOuterUrl(ctx.outerHref, `#${id}`, ctx.navigationState) : `#${id}`;
|
|
8
23
|
return /* @__PURE__ */ jsx(
|
|
9
|
-
|
|
24
|
+
FragmentLink,
|
|
10
25
|
{
|
|
11
26
|
className: "ir-heading-anchor",
|
|
12
|
-
href
|
|
27
|
+
href,
|
|
28
|
+
onClick: onAnchorClick,
|
|
13
29
|
"aria-label": "Permalink to this heading",
|
|
14
30
|
...rest,
|
|
15
31
|
children: /* @__PURE__ */ jsx("span", { "aria-hidden": "true", children: "#" })
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"sources":["../../src/components/HeadingAnchor.tsx"],"sourcesContent":["import { ReactNode } from 'react';\n\n/**\n * Default MDX `HeadingAnchor` component — the render target for the autolink anchor\n * the transpiler's heading-slug plugin (R3-186, `MARKDOWN_SYNTAX_SPEC §15.4`)\n * prepends to every heading. That plugin sets the heading's own `id` (a text slug,\n * or a `sec-…` section id for a numbered heading, R3-211) and emits\n * `<HeadingAnchor id=\"<that id>\" />` as the heading's first child.\n *\n * It is registered in {@link DEFAULT_MDX_COMPONENTS} so a heading anchor renders\n * even in a plain-markdown repo that never calls `boot({ mdxComponents })` — the\n * MDX missing-reference guard never fires (§11.2 phantom defaults). The markup is\n * semantic and accessible — an `aria`-labelled `<a href=\"#id\">` permalink — but\n * **styling is intentionally minimal** (`§15.4` honesty note): an app supplies CSS\n * targeting the `ir-heading-anchor` class to reveal it on hover / add an icon, or\n * overrides this component via `boot({ mdxComponents: { HeadingAnchor } })` to\n * change the icon, position, or behaviour (e.g. copy-permalink-to-clipboard) of\n * every heading anchor in every content file at once (§15.4 late binding).\n *\n * `id` is the *heading's own* id, so the permalink `#id` is the same URL a reader\n * copies and (for a `sec-…` id) an agent computes from a `§`-citation with zero\n * lookup. A missing/empty `id` (defensive — the plugin always supplies one)\n * renders nothing rather than a dead `#` link.\n */\nexport const HeadingAnchor = ({\n id,\n ...rest\n}: {\n id?: string;\n} & Omit<React.AnchorHTMLAttributes<HTMLAnchorElement>, 'href'>): ReactNode => {\n if (!id) return null;\n return (\n <
|
|
1
|
+
{"version":3,"sources":["../../src/components/HeadingAnchor.tsx"],"sourcesContent":["import { ReactNode, use, useCallback } from 'react';\nimport { scrollToId } from '../scrollToId';\nimport { TinkerableContext } from '../TinkerableContext';\nimport { constructOuterUrl } from '../urlUtils';\nimport { FragmentLink } from './Link';\n\n/**\n * Default MDX `HeadingAnchor` component — the render target for the autolink anchor\n * the transpiler's heading-slug plugin (R3-186, `MARKDOWN_SYNTAX_SPEC §15.4`)\n * prepends to every heading. That plugin sets the heading's own `id` (a text slug,\n * or a `sec-…` section id for a numbered heading, R3-211) and emits\n * `<HeadingAnchor id=\"<that id>\" />` as the heading's first child.\n *\n * It is registered in {@link DEFAULT_MDX_COMPONENTS} so a heading anchor renders\n * even in a plain-markdown repo that never calls `boot({ mdxComponents })` — the\n * MDX missing-reference guard never fires (§11.2 phantom defaults). The markup is\n * semantic and accessible — an `aria`-labelled `<a href=\"#id\">` permalink — but\n * **styling is intentionally minimal** (`§15.4` honesty note): an app supplies CSS\n * targeting the `ir-heading-anchor` class to reveal it on hover / add an icon, or\n * overrides this component via `boot({ mdxComponents: { HeadingAnchor } })` to\n * change the icon, position, or behaviour (e.g. copy-permalink-to-clipboard) of\n * every heading anchor in every content file at once (§15.4 late binding).\n *\n * `id` is the *heading's own* id, so the permalink `#id` is the same URL a reader\n * copies and (for a `sec-…` id) an agent computes from a `§`-citation with zero\n * lookup. A missing/empty `id` (defensive — the plugin always supplies one)\n * renders nothing rather than a dead `#` link.\n */\nexport const HeadingAnchor = ({\n id,\n ...rest\n}: {\n id?: string;\n} & Omit<React.AnchorHTMLAttributes<HTMLAnchorElement>, 'href'>): ReactNode => {\n // ⚠ A BARE `#id` IS THE WRONG HREF INSIDE A SANDBOXED APP, and wrong in a way that only\n // shows up when someone copies the link. The app runs in an iframe whose document URL is\n // the SANDBOX's (`https://sandbox.immediately.run/index.html?href=…`), so the browser\n // resolves `#id` against THAT — \"copy link address\" on a heading yields a\n // sandbox-internal URL that means nothing to anyone else. Reported from a real wiki\n // (2026-08-14) as exactly that URL instead of the entry's.\n //\n // Both halves have to be right, and they pull in opposite directions:\n // • the HREF must be absolute in the HOST's space, so copy-link / middle-click /\n // open-in-new-tab all produce a URL that resolves for a reader;\n // • the CLICK must NOT navigate to it — that would be a full page load to the page you\n // are already on. It scrolls, leaving the sandbox URL the host owns untouched.\n //\n // `FragmentLink` is the SDK's existing home for the second half; it runs the caller's\n // `onClick` first and stands down if it preventDefaults, which is what lets the href be\n // absolute here while the behaviour stays a scroll.\n const ctx = use(TinkerableContext);\n const onAnchorClick = useCallback(\n (e: React.MouseEvent<HTMLAnchorElement>) => {\n // Let a modified click through: cmd/ctrl/middle-click means \"open the permalink\",\n // and that is precisely the case the absolute href exists to serve.\n if (e.metaKey || e.ctrlKey || e.shiftKey || e.altKey || e.button !== 0) return;\n e.preventDefault();\n if (id) scrollToId(id);\n },\n [id]\n );\n if (!id) return null;\n // No context (a plain-markdown repo that never called `boot()`) → keep the old bare\n // fragment, which FragmentLink handles on its own.\n const href = ctx?.navigationState\n ? constructOuterUrl(ctx.outerHref, `#${id}`, ctx.navigationState)\n : `#${id}`;\n return (\n <FragmentLink\n className=\"ir-heading-anchor\"\n href={href}\n onClick={onAnchorClick}\n aria-label=\"Permalink to this heading\"\n {...rest}\n >\n <span aria-hidden=\"true\">#</span>\n </FragmentLink>\n );\n};\n"],"mappings":";AA2EM;AA3EN,SAAoB,KAAK,mBAAmB;AAC5C,SAAS,kBAAkB;AAC3B,SAAS,yBAAyB;AAClC,SAAS,yBAAyB;AAClC,SAAS,oBAAoB;AAwBtB,MAAM,gBAAgB,CAAC;AAAA,EAC5B;AAAA,EACA,GAAG;AACL,MAE+E;AAiB7E,QAAM,MAAM,IAAI,iBAAiB;AACjC,QAAM,gBAAgB;AAAA,IACpB,CAAC,MAA2C;AAG1C,UAAI,EAAE,WAAW,EAAE,WAAW,EAAE,YAAY,EAAE,UAAU,EAAE,WAAW,EAAG;AACxE,QAAE,eAAe;AACjB,UAAI,GAAI,YAAW,EAAE;AAAA,IACvB;AAAA,IACA,CAAC,EAAE;AAAA,EACL;AACA,MAAI,CAAC,GAAI,QAAO;AAGhB,QAAM,OAAO,KAAK,kBACd,kBAAkB,IAAI,WAAW,IAAI,EAAE,IAAI,IAAI,eAAe,IAC9D,IAAI,EAAE;AACV,SACE;AAAA,IAAC;AAAA;AAAA,MACC,WAAU;AAAA,MACV;AAAA,MACA,SAAS;AAAA,MACT,cAAW;AAAA,MACV,GAAG;AAAA,MAEJ,8BAAC,UAAK,eAAY,QAAO,eAAC;AAAA;AAAA,EAC5B;AAEJ;","names":[]}
|
|
@@ -42,6 +42,7 @@ const RenderExportedComponent = ({
|
|
|
42
42
|
};
|
|
43
43
|
const Include = ({
|
|
44
44
|
filename,
|
|
45
|
+
readSource,
|
|
45
46
|
exportedSymbol = "default",
|
|
46
47
|
LoadingComponent = import_defaults.defaultLoadingComponent,
|
|
47
48
|
ErrorComponent = import_defaults.defaultErrorComponent,
|
|
@@ -57,6 +58,7 @@ const Include = ({
|
|
|
57
58
|
{
|
|
58
59
|
filename,
|
|
59
60
|
components,
|
|
61
|
+
readSource,
|
|
60
62
|
LoadingComponent,
|
|
61
63
|
ErrorComponent
|
|
62
64
|
}
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"sources":["../../src/components/Include.tsx"],"sourcesContent":["import { Suspense, use } from 'react';\nimport { ErrorBoundary } from 'react-error-boundary';\n\nimport { ModuleCacheContext } from '../moduleCache';\nimport { EvaluationContext } from '../sandboxTypes';\nimport { defaultErrorComponent, defaultLoadingComponent } from './defaults';\nimport { IncludeModeContext, RenderExportedComponentContext, type IncludeMode } from './includeContexts';\nimport { SafeInclude } from './SafeInclude';\n\n// The contexts live in `./includeContexts` so `Include` and `SafeInclude` do not import each\n// other (`check:circular`); re-exported here because this is the public entry point and the\n// import path must not change.\nexport { IncludeModeContext, RenderExportedComponentContext } from './includeContexts';\nexport type { IncludeMode, RenderFileContextType } from './includeContexts';\n\n/** Low-level: render one export of an already-resolving module evaluation. Most\n * code should use {@link Include}, which resolves the module and adds Suspense. */\nexport const RenderExportedComponent = ({\n evaluationContextPromise,\n exportedSymbol = 'default',\n}: {\n evaluationContextPromise: Promise<EvaluationContext>;\n exportedSymbol: string;\n}) => {\n const evaluationContext = use(evaluationContextPromise);\n // TODO: handle case where exported symbol not found.\n const Component = exportedSymbol === '*' ? evaluationContext.exports : evaluationContext.exports[exportedSymbol];\n return (\n <RenderExportedComponentContext value={{ evaluationContext }}>\n <Component />\n </RenderExportedComponentContext>\n );\n};\n\n/** Render another repo file's exported component inline, resolving + evaluating it\n * through the module cache (with Suspense + an error boundary).\n *\n * Under `mode=\"interpreted\"` (or inside an {@link IncludeModeContext} set to it) the file is\n * instead rendered **as data** through the safe renderer — no author JavaScript executes,\n * and the file need not be an evaluable module at all. */\nexport const Include = ({\n filename,\n exportedSymbol = 'default',\n LoadingComponent = defaultLoadingComponent,\n ErrorComponent = defaultErrorComponent,\n baseModule,\n mode,\n components,\n}: {\n filename: string;\n exportedSymbol?: string;\n LoadingComponent?: typeof defaultLoadingComponent;\n ErrorComponent?: typeof defaultErrorComponent;\n baseModule?: EvaluationContext;\n /** Override {@link IncludeModeContext} for this one include. */\n mode?: IncludeMode;\n /** Interpreted mode only: components merged OVER the surrounding MDXProvider map.\n *\n * An app's SAFE component set is not always the same as the one it hands\n * `boot({ mdxComponents })`. Grove is the worked example: under the safe renderer it also\n * needs sanitizing wrappers for structural tags (`main`, `section`, …), and it must NOT\n * register those globally, because MDX consults the provider for intrinsics on the\n * COMPILED path too — so a global registration would silently strip `style` and other\n * non-allow-listed props from compiled authors who legitimately pass them. Ignored in\n * compiled mode, where components come from the provider as they always have. */\n components?: Record<string, unknown>;\n}) => {\n // Both contexts are read unconditionally, before the branch, so hook order is stable\n // whichever renderer this include resolves to.\n const contextMode = use(IncludeModeContext);\n const moduleCache = use(ModuleCacheContext);\n // The prop wins over the context so a single file can opt out either way: an interpreter\n // app including one trusted, executable component of its own, or a compiled app rendering\n // one file it does not trust (the shape Grove's non-executable proof page needs).\n if ((mode ?? contextMode) === 'interpreted') {\n return (\n <SafeInclude\n filename={filename}\n components={components}\n LoadingComponent={LoadingComponent}\n ErrorComponent={ErrorComponent}\n />\n );\n }\n // @ts-ignore\n const evaluationContextPromise = moduleCache!.getEvaluationContext(filename, baseModule ?? module);\n return (\n <ErrorBoundary fallbackRender={ErrorComponent}>\n <Suspense fallback={<LoadingComponent />}>\n <RenderExportedComponent evaluationContextPromise={evaluationContextPromise} exportedSymbol={exportedSymbol} />\n </Suspense>\n </ErrorBoundary>\n );\n};\n"],"mappings":";;;;;;;;;;;;;;;;;;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;
|
|
1
|
+
{"version":3,"sources":["../../src/components/Include.tsx"],"sourcesContent":["import { Suspense, use } from 'react';\nimport { ErrorBoundary } from 'react-error-boundary';\n\nimport { ModuleCacheContext } from '../moduleCache';\nimport { EvaluationContext } from '../sandboxTypes';\nimport { defaultErrorComponent, defaultLoadingComponent } from './defaults';\nimport { IncludeModeContext, RenderExportedComponentContext, type IncludeMode } from './includeContexts';\nimport { SafeInclude } from './SafeInclude';\nimport type { SourceReader } from '../sourceCache';\n\n// The contexts live in `./includeContexts` so `Include` and `SafeInclude` do not import each\n// other (`check:circular`); re-exported here because this is the public entry point and the\n// import path must not change.\nexport { IncludeModeContext, RenderExportedComponentContext } from './includeContexts';\nexport type { IncludeMode, RenderFileContextType } from './includeContexts';\n\n/** Low-level: render one export of an already-resolving module evaluation. Most\n * code should use {@link Include}, which resolves the module and adds Suspense. */\nexport const RenderExportedComponent = ({\n evaluationContextPromise,\n exportedSymbol = 'default',\n}: {\n evaluationContextPromise: Promise<EvaluationContext>;\n exportedSymbol: string;\n}) => {\n const evaluationContext = use(evaluationContextPromise);\n // TODO: handle case where exported symbol not found.\n const Component = exportedSymbol === '*' ? evaluationContext.exports : evaluationContext.exports[exportedSymbol];\n return (\n <RenderExportedComponentContext value={{ evaluationContext }}>\n <Component />\n </RenderExportedComponentContext>\n );\n};\n\n/** Render another repo file's exported component inline, resolving + evaluating it\n * through the module cache (with Suspense + an error boundary).\n *\n * Under `mode=\"interpreted\"` (or inside an {@link IncludeModeContext} set to it) the file is\n * instead rendered **as data** through the safe renderer — no author JavaScript executes,\n * and the file need not be an evaluable module at all. */\nexport const Include = ({\n filename,\n readSource,\n exportedSymbol = 'default',\n LoadingComponent = defaultLoadingComponent,\n ErrorComponent = defaultErrorComponent,\n baseModule,\n mode,\n components,\n}: {\n filename: string;\n exportedSymbol?: string;\n LoadingComponent?: typeof defaultLoadingComponent;\n ErrorComponent?: typeof defaultErrorComponent;\n baseModule?: EvaluationContext;\n /** Override {@link IncludeModeContext} for this one include. */\n mode?: IncludeMode;\n /** Interpreted mode only: components merged OVER the surrounding MDXProvider map.\n *\n * An app's SAFE component set is not always the same as the one it hands\n * `boot({ mdxComponents })`. Grove is the worked example: under the safe renderer it also\n * needs sanitizing wrappers for structural tags (`main`, `section`, …), and it must NOT\n * register those globally, because MDX consults the provider for intrinsics on the\n * COMPILED path too — so a global registration would silently strip `style` and other\n * non-allow-listed props from compiled authors who legitimately pass them. Ignored in\n * compiled mode, where components come from the provider as they always have. */\n components?: Record<string, unknown>;\n /** Interpreted mode only: read the raw bytes yourself — e.g. through a mount fs you\n * already hold, or a cache you share with the rest of your app. The default reader\n * handles both an app-source path and an absolute path in a mount, so this is for\n * control, not for reach. Ignored in compiled mode. */\n readSource?: SourceReader;\n}) => {\n // Both contexts are read unconditionally, before the branch, so hook order is stable\n // whichever renderer this include resolves to.\n const contextMode = use(IncludeModeContext);\n const moduleCache = use(ModuleCacheContext);\n // The prop wins over the context so a single file can opt out either way: an interpreter\n // app including one trusted, executable component of its own, or a compiled app rendering\n // one file it does not trust (the shape Grove's non-executable proof page needs).\n if ((mode ?? contextMode) === 'interpreted') {\n return (\n <SafeInclude\n filename={filename}\n components={components}\n readSource={readSource}\n LoadingComponent={LoadingComponent}\n ErrorComponent={ErrorComponent}\n />\n );\n }\n // @ts-ignore\n const evaluationContextPromise = moduleCache!.getEvaluationContext(filename, baseModule ?? module);\n return (\n <ErrorBoundary fallbackRender={ErrorComponent}>\n <Suspense fallback={<LoadingComponent />}>\n <RenderExportedComponent evaluationContextPromise={evaluationContextPromise} exportedSymbol={exportedSymbol} />\n </Suspense>\n </ErrorBoundary>\n );\n};\n"],"mappings":";;;;;;;;;;;;;;;;;;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AA8BM;AA9BN,mBAA8B;AAC9B,kCAA8B;AAE9B,yBAAmC;AAEnC,sBAA+D;AAC/D,6BAAqF;AACrF,yBAA4B;AAM5B,IAAAA,0BAAmE;AAK5D,MAAM,0BAA0B,CAAC;AAAA,EACtC;AAAA,EACA,iBAAiB;AACnB,MAGM;AACJ,QAAM,wBAAoB,kBAAI,wBAAwB;AAEtD,QAAM,YAAY,mBAAmB,MAAM,kBAAkB,UAAU,kBAAkB,QAAQ,cAAc;AAC/G,SACE,4CAAC,yDAA+B,OAAO,EAAE,kBAAkB,GACzD,sDAAC,aAAU,GACb;AAEJ;AAQO,MAAM,UAAU,CAAC;AAAA,EACtB;AAAA,EACA;AAAA,EACA,iBAAiB;AAAA,EACjB,mBAAmB;AAAA,EACnB,iBAAiB;AAAA,EACjB;AAAA,EACA;AAAA,EACA;AACF,MAuBM;AAGJ,QAAM,kBAAc,kBAAI,yCAAkB;AAC1C,QAAM,kBAAc,kBAAI,qCAAkB;AAI1C,OAAK,QAAQ,iBAAiB,eAAe;AAC3C,WACE;AAAA,MAAC;AAAA;AAAA,QACC;AAAA,QACA;AAAA,QACA;AAAA,QACA;AAAA,QACA;AAAA;AAAA,IACF;AAAA,EAEJ;AAEA,QAAM,2BAA2B,YAAa,qBAAqB,UAAU,cAAc,MAAM;AACjG,SACE,4CAAC,6CAAc,gBAAgB,gBAC7B,sDAAC,yBAAS,UAAU,4CAAC,oBAAiB,GACpC,sDAAC,2BAAwB,0BAAoD,gBAAgC,GAC/G,GACF;AAEJ;","names":["import_includeContexts"]}
|
|
@@ -3,6 +3,7 @@ import { EvaluationContext } from '../sandboxTypes.cjs';
|
|
|
3
3
|
import { defaultLoadingComponent, defaultErrorComponent } from './defaults.cjs';
|
|
4
4
|
import { IncludeMode } from './includeContexts.cjs';
|
|
5
5
|
export { IncludeModeContext, RenderExportedComponentContext, RenderFileContextType } from './includeContexts.cjs';
|
|
6
|
+
import { SourceReader } from '../sourceCache.cjs';
|
|
6
7
|
import 'react-error-boundary';
|
|
7
8
|
|
|
8
9
|
/** Low-level: render one export of an already-resolving module evaluation. Most
|
|
@@ -17,7 +18,7 @@ declare const RenderExportedComponent: ({ evaluationContextPromise, exportedSymb
|
|
|
17
18
|
* Under `mode="interpreted"` (or inside an {@link IncludeModeContext} set to it) the file is
|
|
18
19
|
* instead rendered **as data** through the safe renderer — no author JavaScript executes,
|
|
19
20
|
* and the file need not be an evaluable module at all. */
|
|
20
|
-
declare const Include: ({ filename, exportedSymbol, LoadingComponent, ErrorComponent, baseModule, mode, components, }: {
|
|
21
|
+
declare const Include: ({ filename, readSource, exportedSymbol, LoadingComponent, ErrorComponent, baseModule, mode, components, }: {
|
|
21
22
|
filename: string;
|
|
22
23
|
exportedSymbol?: string;
|
|
23
24
|
LoadingComponent?: typeof defaultLoadingComponent;
|
|
@@ -35,6 +36,11 @@ declare const Include: ({ filename, exportedSymbol, LoadingComponent, ErrorCompo
|
|
|
35
36
|
* non-allow-listed props from compiled authors who legitimately pass them. Ignored in
|
|
36
37
|
* compiled mode, where components come from the provider as they always have. */
|
|
37
38
|
components?: Record<string, unknown>;
|
|
39
|
+
/** Interpreted mode only: read the raw bytes yourself — e.g. through a mount fs you
|
|
40
|
+
* already hold, or a cache you share with the rest of your app. The default reader
|
|
41
|
+
* handles both an app-source path and an absolute path in a mount, so this is for
|
|
42
|
+
* control, not for reach. Ignored in compiled mode. */
|
|
43
|
+
readSource?: SourceReader;
|
|
38
44
|
}) => react.JSX.Element;
|
|
39
45
|
|
|
40
46
|
export { Include, IncludeMode, RenderExportedComponent };
|
|
@@ -3,6 +3,7 @@ import { EvaluationContext } from '../sandboxTypes.js';
|
|
|
3
3
|
import { defaultLoadingComponent, defaultErrorComponent } from './defaults.js';
|
|
4
4
|
import { IncludeMode } from './includeContexts.js';
|
|
5
5
|
export { IncludeModeContext, RenderExportedComponentContext, RenderFileContextType } from './includeContexts.js';
|
|
6
|
+
import { SourceReader } from '../sourceCache.js';
|
|
6
7
|
import 'react-error-boundary';
|
|
7
8
|
|
|
8
9
|
/** Low-level: render one export of an already-resolving module evaluation. Most
|
|
@@ -17,7 +18,7 @@ declare const RenderExportedComponent: ({ evaluationContextPromise, exportedSymb
|
|
|
17
18
|
* Under `mode="interpreted"` (or inside an {@link IncludeModeContext} set to it) the file is
|
|
18
19
|
* instead rendered **as data** through the safe renderer — no author JavaScript executes,
|
|
19
20
|
* and the file need not be an evaluable module at all. */
|
|
20
|
-
declare const Include: ({ filename, exportedSymbol, LoadingComponent, ErrorComponent, baseModule, mode, components, }: {
|
|
21
|
+
declare const Include: ({ filename, readSource, exportedSymbol, LoadingComponent, ErrorComponent, baseModule, mode, components, }: {
|
|
21
22
|
filename: string;
|
|
22
23
|
exportedSymbol?: string;
|
|
23
24
|
LoadingComponent?: typeof defaultLoadingComponent;
|
|
@@ -35,6 +36,11 @@ declare const Include: ({ filename, exportedSymbol, LoadingComponent, ErrorCompo
|
|
|
35
36
|
* non-allow-listed props from compiled authors who legitimately pass them. Ignored in
|
|
36
37
|
* compiled mode, where components come from the provider as they always have. */
|
|
37
38
|
components?: Record<string, unknown>;
|
|
39
|
+
/** Interpreted mode only: read the raw bytes yourself — e.g. through a mount fs you
|
|
40
|
+
* already hold, or a cache you share with the rest of your app. The default reader
|
|
41
|
+
* handles both an app-source path and an absolute path in a mount, so this is for
|
|
42
|
+
* control, not for reach. Ignored in compiled mode. */
|
|
43
|
+
readSource?: SourceReader;
|
|
38
44
|
}) => react.JSX.Element;
|
|
39
45
|
|
|
40
46
|
export { Include, IncludeMode, RenderExportedComponent };
|
|
@@ -17,6 +17,7 @@ const RenderExportedComponent = ({
|
|
|
17
17
|
};
|
|
18
18
|
const Include = ({
|
|
19
19
|
filename,
|
|
20
|
+
readSource,
|
|
20
21
|
exportedSymbol = "default",
|
|
21
22
|
LoadingComponent = defaultLoadingComponent,
|
|
22
23
|
ErrorComponent = defaultErrorComponent,
|
|
@@ -32,6 +33,7 @@ const Include = ({
|
|
|
32
33
|
{
|
|
33
34
|
filename,
|
|
34
35
|
components,
|
|
36
|
+
readSource,
|
|
35
37
|
LoadingComponent,
|
|
36
38
|
ErrorComponent
|
|
37
39
|
}
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"sources":["../../src/components/Include.tsx"],"sourcesContent":["import { Suspense, use } from 'react';\nimport { ErrorBoundary } from 'react-error-boundary';\n\nimport { ModuleCacheContext } from '../moduleCache';\nimport { EvaluationContext } from '../sandboxTypes';\nimport { defaultErrorComponent, defaultLoadingComponent } from './defaults';\nimport { IncludeModeContext, RenderExportedComponentContext, type IncludeMode } from './includeContexts';\nimport { SafeInclude } from './SafeInclude';\n\n// The contexts live in `./includeContexts` so `Include` and `SafeInclude` do not import each\n// other (`check:circular`); re-exported here because this is the public entry point and the\n// import path must not change.\nexport { IncludeModeContext, RenderExportedComponentContext } from './includeContexts';\nexport type { IncludeMode, RenderFileContextType } from './includeContexts';\n\n/** Low-level: render one export of an already-resolving module evaluation. Most\n * code should use {@link Include}, which resolves the module and adds Suspense. */\nexport const RenderExportedComponent = ({\n evaluationContextPromise,\n exportedSymbol = 'default',\n}: {\n evaluationContextPromise: Promise<EvaluationContext>;\n exportedSymbol: string;\n}) => {\n const evaluationContext = use(evaluationContextPromise);\n // TODO: handle case where exported symbol not found.\n const Component = exportedSymbol === '*' ? evaluationContext.exports : evaluationContext.exports[exportedSymbol];\n return (\n <RenderExportedComponentContext value={{ evaluationContext }}>\n <Component />\n </RenderExportedComponentContext>\n );\n};\n\n/** Render another repo file's exported component inline, resolving + evaluating it\n * through the module cache (with Suspense + an error boundary).\n *\n * Under `mode=\"interpreted\"` (or inside an {@link IncludeModeContext} set to it) the file is\n * instead rendered **as data** through the safe renderer — no author JavaScript executes,\n * and the file need not be an evaluable module at all. */\nexport const Include = ({\n filename,\n exportedSymbol = 'default',\n LoadingComponent = defaultLoadingComponent,\n ErrorComponent = defaultErrorComponent,\n baseModule,\n mode,\n components,\n}: {\n filename: string;\n exportedSymbol?: string;\n LoadingComponent?: typeof defaultLoadingComponent;\n ErrorComponent?: typeof defaultErrorComponent;\n baseModule?: EvaluationContext;\n /** Override {@link IncludeModeContext} for this one include. */\n mode?: IncludeMode;\n /** Interpreted mode only: components merged OVER the surrounding MDXProvider map.\n *\n * An app's SAFE component set is not always the same as the one it hands\n * `boot({ mdxComponents })`. Grove is the worked example: under the safe renderer it also\n * needs sanitizing wrappers for structural tags (`main`, `section`, …), and it must NOT\n * register those globally, because MDX consults the provider for intrinsics on the\n * COMPILED path too — so a global registration would silently strip `style` and other\n * non-allow-listed props from compiled authors who legitimately pass them. Ignored in\n * compiled mode, where components come from the provider as they always have. */\n components?: Record<string, unknown>;\n}) => {\n // Both contexts are read unconditionally, before the branch, so hook order is stable\n // whichever renderer this include resolves to.\n const contextMode = use(IncludeModeContext);\n const moduleCache = use(ModuleCacheContext);\n // The prop wins over the context so a single file can opt out either way: an interpreter\n // app including one trusted, executable component of its own, or a compiled app rendering\n // one file it does not trust (the shape Grove's non-executable proof page needs).\n if ((mode ?? contextMode) === 'interpreted') {\n return (\n <SafeInclude\n filename={filename}\n components={components}\n LoadingComponent={LoadingComponent}\n ErrorComponent={ErrorComponent}\n />\n );\n }\n // @ts-ignore\n const evaluationContextPromise = moduleCache!.getEvaluationContext(filename, baseModule ?? module);\n return (\n <ErrorBoundary fallbackRender={ErrorComponent}>\n <Suspense fallback={<LoadingComponent />}>\n <RenderExportedComponent evaluationContextPromise={evaluationContextPromise} exportedSymbol={exportedSymbol} />\n </Suspense>\n </ErrorBoundary>\n );\n};\n"],"mappings":";
|
|
1
|
+
{"version":3,"sources":["../../src/components/Include.tsx"],"sourcesContent":["import { Suspense, use } from 'react';\nimport { ErrorBoundary } from 'react-error-boundary';\n\nimport { ModuleCacheContext } from '../moduleCache';\nimport { EvaluationContext } from '../sandboxTypes';\nimport { defaultErrorComponent, defaultLoadingComponent } from './defaults';\nimport { IncludeModeContext, RenderExportedComponentContext, type IncludeMode } from './includeContexts';\nimport { SafeInclude } from './SafeInclude';\nimport type { SourceReader } from '../sourceCache';\n\n// The contexts live in `./includeContexts` so `Include` and `SafeInclude` do not import each\n// other (`check:circular`); re-exported here because this is the public entry point and the\n// import path must not change.\nexport { IncludeModeContext, RenderExportedComponentContext } from './includeContexts';\nexport type { IncludeMode, RenderFileContextType } from './includeContexts';\n\n/** Low-level: render one export of an already-resolving module evaluation. Most\n * code should use {@link Include}, which resolves the module and adds Suspense. */\nexport const RenderExportedComponent = ({\n evaluationContextPromise,\n exportedSymbol = 'default',\n}: {\n evaluationContextPromise: Promise<EvaluationContext>;\n exportedSymbol: string;\n}) => {\n const evaluationContext = use(evaluationContextPromise);\n // TODO: handle case where exported symbol not found.\n const Component = exportedSymbol === '*' ? evaluationContext.exports : evaluationContext.exports[exportedSymbol];\n return (\n <RenderExportedComponentContext value={{ evaluationContext }}>\n <Component />\n </RenderExportedComponentContext>\n );\n};\n\n/** Render another repo file's exported component inline, resolving + evaluating it\n * through the module cache (with Suspense + an error boundary).\n *\n * Under `mode=\"interpreted\"` (or inside an {@link IncludeModeContext} set to it) the file is\n * instead rendered **as data** through the safe renderer — no author JavaScript executes,\n * and the file need not be an evaluable module at all. */\nexport const Include = ({\n filename,\n readSource,\n exportedSymbol = 'default',\n LoadingComponent = defaultLoadingComponent,\n ErrorComponent = defaultErrorComponent,\n baseModule,\n mode,\n components,\n}: {\n filename: string;\n exportedSymbol?: string;\n LoadingComponent?: typeof defaultLoadingComponent;\n ErrorComponent?: typeof defaultErrorComponent;\n baseModule?: EvaluationContext;\n /** Override {@link IncludeModeContext} for this one include. */\n mode?: IncludeMode;\n /** Interpreted mode only: components merged OVER the surrounding MDXProvider map.\n *\n * An app's SAFE component set is not always the same as the one it hands\n * `boot({ mdxComponents })`. Grove is the worked example: under the safe renderer it also\n * needs sanitizing wrappers for structural tags (`main`, `section`, …), and it must NOT\n * register those globally, because MDX consults the provider for intrinsics on the\n * COMPILED path too — so a global registration would silently strip `style` and other\n * non-allow-listed props from compiled authors who legitimately pass them. Ignored in\n * compiled mode, where components come from the provider as they always have. */\n components?: Record<string, unknown>;\n /** Interpreted mode only: read the raw bytes yourself — e.g. through a mount fs you\n * already hold, or a cache you share with the rest of your app. The default reader\n * handles both an app-source path and an absolute path in a mount, so this is for\n * control, not for reach. Ignored in compiled mode. */\n readSource?: SourceReader;\n}) => {\n // Both contexts are read unconditionally, before the branch, so hook order is stable\n // whichever renderer this include resolves to.\n const contextMode = use(IncludeModeContext);\n const moduleCache = use(ModuleCacheContext);\n // The prop wins over the context so a single file can opt out either way: an interpreter\n // app including one trusted, executable component of its own, or a compiled app rendering\n // one file it does not trust (the shape Grove's non-executable proof page needs).\n if ((mode ?? contextMode) === 'interpreted') {\n return (\n <SafeInclude\n filename={filename}\n components={components}\n readSource={readSource}\n LoadingComponent={LoadingComponent}\n ErrorComponent={ErrorComponent}\n />\n );\n }\n // @ts-ignore\n const evaluationContextPromise = moduleCache!.getEvaluationContext(filename, baseModule ?? module);\n return (\n <ErrorBoundary fallbackRender={ErrorComponent}>\n <Suspense fallback={<LoadingComponent />}>\n <RenderExportedComponent evaluationContextPromise={evaluationContextPromise} exportedSymbol={exportedSymbol} />\n </Suspense>\n </ErrorBoundary>\n );\n};\n"],"mappings":";AA8BM;AA9BN,SAAS,UAAU,WAAW;AAC9B,SAAS,qBAAqB;AAE9B,SAAS,0BAA0B;AAEnC,SAAS,uBAAuB,+BAA+B;AAC/D,SAAS,oBAAoB,sCAAwD;AACrF,SAAS,mBAAmB;AAM5B,SAAS,sBAAAA,qBAAoB,kCAAAC,uCAAsC;AAK5D,MAAM,0BAA0B,CAAC;AAAA,EACtC;AAAA,EACA,iBAAiB;AACnB,MAGM;AACJ,QAAM,oBAAoB,IAAI,wBAAwB;AAEtD,QAAM,YAAY,mBAAmB,MAAM,kBAAkB,UAAU,kBAAkB,QAAQ,cAAc;AAC/G,SACE,oBAAC,kCAA+B,OAAO,EAAE,kBAAkB,GACzD,8BAAC,aAAU,GACb;AAEJ;AAQO,MAAM,UAAU,CAAC;AAAA,EACtB;AAAA,EACA;AAAA,EACA,iBAAiB;AAAA,EACjB,mBAAmB;AAAA,EACnB,iBAAiB;AAAA,EACjB;AAAA,EACA;AAAA,EACA;AACF,MAuBM;AAGJ,QAAM,cAAc,IAAI,kBAAkB;AAC1C,QAAM,cAAc,IAAI,kBAAkB;AAI1C,OAAK,QAAQ,iBAAiB,eAAe;AAC3C,WACE;AAAA,MAAC;AAAA;AAAA,QACC;AAAA,QACA;AAAA,QACA;AAAA,QACA;AAAA,QACA;AAAA;AAAA,IACF;AAAA,EAEJ;AAEA,QAAM,2BAA2B,YAAa,qBAAqB,UAAU,cAAc,MAAM;AACjG,SACE,oBAAC,iBAAc,gBAAgB,gBAC7B,8BAAC,YAAS,UAAU,oBAAC,oBAAiB,GACpC,8BAAC,2BAAwB,0BAAoD,gBAAgC,GAC/G,GACF;AAEJ;","names":["IncludeModeContext","RenderExportedComponentContext"]}
|
|
@@ -20,6 +20,7 @@ var SafeInclude_exports = {};
|
|
|
20
20
|
__export(SafeInclude_exports, {
|
|
21
21
|
SafeInclude: () => SafeInclude,
|
|
22
22
|
appMountRelative: () => appMountRelative,
|
|
23
|
+
isForeignMountPath: () => isForeignMountPath,
|
|
23
24
|
stripFrontmatter: () => stripFrontmatter
|
|
24
25
|
});
|
|
25
26
|
module.exports = __toCommonJS(SafeInclude_exports);
|
|
@@ -41,9 +42,21 @@ function appMountRelative(filename) {
|
|
|
41
42
|
const abs = filename.startsWith(root + "/") ? filename.slice(root.length) : filename;
|
|
42
43
|
return abs.replace(/^\/+/, "");
|
|
43
44
|
}
|
|
44
|
-
|
|
45
|
-
|
|
46
|
-
);
|
|
45
|
+
function isForeignMountPath(filename) {
|
|
46
|
+
if (!filename.startsWith("/")) return false;
|
|
47
|
+
const root = (0, import_mounts.getAppMountPath)().replace(/\/+$/, "");
|
|
48
|
+
return !filename.startsWith(`${root}/`) && filename !== root;
|
|
49
|
+
}
|
|
50
|
+
function readInterpretedSource(filename) {
|
|
51
|
+
if (isForeignMountPath(filename)) {
|
|
52
|
+
return (0, import_fs.openFs)({ path: "/", type: "mount" }).readFile(
|
|
53
|
+
filename.replace(/^\/+/, ""),
|
|
54
|
+
"utf8"
|
|
55
|
+
);
|
|
56
|
+
}
|
|
57
|
+
return (0, import_fs.openAppFs)().readFile(appMountRelative(filename), "utf8");
|
|
58
|
+
}
|
|
59
|
+
const defaultSources = (0, import_sourceCache.createSourceCache)(readInterpretedSource);
|
|
47
60
|
function InterpretedBody({
|
|
48
61
|
filename,
|
|
49
62
|
components,
|
|
@@ -53,7 +66,7 @@ function InterpretedBody({
|
|
|
53
66
|
() => readSource ? (0, import_sourceCache.createSourceCache)(readSource) : defaultSources,
|
|
54
67
|
[readSource]
|
|
55
68
|
);
|
|
56
|
-
const raw = (0, import_react.use)(sources.read(
|
|
69
|
+
const raw = (0, import_react.use)(sources.read(filename));
|
|
57
70
|
const provided = (0, import_MDXProvider.useMDXComponents)(components);
|
|
58
71
|
const body = stripFrontmatter(raw);
|
|
59
72
|
return (
|
|
@@ -84,6 +97,7 @@ const SafeInclude = ({
|
|
|
84
97
|
0 && (module.exports = {
|
|
85
98
|
SafeInclude,
|
|
86
99
|
appMountRelative,
|
|
100
|
+
isForeignMountPath,
|
|
87
101
|
stripFrontmatter
|
|
88
102
|
});
|
|
89
103
|
//# sourceMappingURL=SafeInclude.cjs.map
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"sources":["../../src/components/SafeInclude.tsx"],"sourcesContent":["import { Suspense, use, useMemo } from 'react';\nimport { ErrorBoundary } from 'react-error-boundary';\n\nimport { openAppFs } 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// 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(
|
|
1
|
+
{"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(\n () => (readSource ? createSourceCache(readSource) : defaultSources),\n [readSource],\n );\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;AAgHM;AAhHN,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;AAAA,IACd,MAAO,iBAAa,sCAAkB,UAAU,IAAI;AAAA,IACpD,CAAC,UAAU;AAAA,EACb;AACA,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":[]}
|
|
@@ -11,6 +11,9 @@ declare function stripFrontmatter(source: string): string;
|
|
|
11
11
|
* so an absolute module path has to be made mount-relative before it is read. A path that
|
|
12
12
|
* is already relative is passed through untouched. */
|
|
13
13
|
declare function appMountRelative(filename: string): string;
|
|
14
|
+
/** Is this an absolute path that lies OUTSIDE this app's own repo mount — i.e. a file
|
|
15
|
+
* resident in a content mount rather than in the app? */
|
|
16
|
+
declare function isForeignMountPath(filename: string): boolean;
|
|
14
17
|
/** Render another file's Markdown/MDX **as data** — no author JavaScript executes. Reached
|
|
15
18
|
* via `<Include mode="interpreted">` or `<IncludeModeContext value="interpreted">`. */
|
|
16
19
|
declare const SafeInclude: ({ filename, components, readSource, LoadingComponent, ErrorComponent, }: {
|
|
@@ -23,4 +26,4 @@ declare const SafeInclude: ({ filename, components, readSource, LoadingComponent
|
|
|
23
26
|
ErrorComponent?: typeof defaultErrorComponent;
|
|
24
27
|
}) => react.JSX.Element;
|
|
25
28
|
|
|
26
|
-
export { SafeInclude, appMountRelative, stripFrontmatter };
|
|
29
|
+
export { SafeInclude, appMountRelative, isForeignMountPath, stripFrontmatter };
|
|
@@ -11,6 +11,9 @@ declare function stripFrontmatter(source: string): string;
|
|
|
11
11
|
* so an absolute module path has to be made mount-relative before it is read. A path that
|
|
12
12
|
* is already relative is passed through untouched. */
|
|
13
13
|
declare function appMountRelative(filename: string): string;
|
|
14
|
+
/** Is this an absolute path that lies OUTSIDE this app's own repo mount — i.e. a file
|
|
15
|
+
* resident in a content mount rather than in the app? */
|
|
16
|
+
declare function isForeignMountPath(filename: string): boolean;
|
|
14
17
|
/** Render another file's Markdown/MDX **as data** — no author JavaScript executes. Reached
|
|
15
18
|
* via `<Include mode="interpreted">` or `<IncludeModeContext value="interpreted">`. */
|
|
16
19
|
declare const SafeInclude: ({ filename, components, readSource, LoadingComponent, ErrorComponent, }: {
|
|
@@ -23,4 +26,4 @@ declare const SafeInclude: ({ filename, components, readSource, LoadingComponent
|
|
|
23
26
|
ErrorComponent?: typeof defaultErrorComponent;
|
|
24
27
|
}) => react.JSX.Element;
|
|
25
28
|
|
|
26
|
-
export { SafeInclude, appMountRelative, stripFrontmatter };
|
|
29
|
+
export { SafeInclude, appMountRelative, isForeignMountPath, stripFrontmatter };
|
|
@@ -2,7 +2,7 @@ import "../chunk-VHAA22YE.js";
|
|
|
2
2
|
import { jsx } from "react/jsx-runtime";
|
|
3
3
|
import { Suspense, use, useMemo } from "react";
|
|
4
4
|
import { ErrorBoundary } from "react-error-boundary";
|
|
5
|
-
import { openAppFs } from "../fs";
|
|
5
|
+
import { openAppFs, openFs } from "../fs";
|
|
6
6
|
import { getAppMountPath } from "../mounts";
|
|
7
7
|
import { useMDXComponents } from "../MDXProvider";
|
|
8
8
|
import { SafeContent } from "../safeContent/SafeContent";
|
|
@@ -17,9 +17,21 @@ function appMountRelative(filename) {
|
|
|
17
17
|
const abs = filename.startsWith(root + "/") ? filename.slice(root.length) : filename;
|
|
18
18
|
return abs.replace(/^\/+/, "");
|
|
19
19
|
}
|
|
20
|
-
|
|
21
|
-
|
|
22
|
-
);
|
|
20
|
+
function isForeignMountPath(filename) {
|
|
21
|
+
if (!filename.startsWith("/")) return false;
|
|
22
|
+
const root = getAppMountPath().replace(/\/+$/, "");
|
|
23
|
+
return !filename.startsWith(`${root}/`) && filename !== root;
|
|
24
|
+
}
|
|
25
|
+
function readInterpretedSource(filename) {
|
|
26
|
+
if (isForeignMountPath(filename)) {
|
|
27
|
+
return openFs({ path: "/", type: "mount" }).readFile(
|
|
28
|
+
filename.replace(/^\/+/, ""),
|
|
29
|
+
"utf8"
|
|
30
|
+
);
|
|
31
|
+
}
|
|
32
|
+
return openAppFs().readFile(appMountRelative(filename), "utf8");
|
|
33
|
+
}
|
|
34
|
+
const defaultSources = createSourceCache(readInterpretedSource);
|
|
23
35
|
function InterpretedBody({
|
|
24
36
|
filename,
|
|
25
37
|
components,
|
|
@@ -29,7 +41,7 @@ function InterpretedBody({
|
|
|
29
41
|
() => readSource ? createSourceCache(readSource) : defaultSources,
|
|
30
42
|
[readSource]
|
|
31
43
|
);
|
|
32
|
-
const raw = use(sources.read(
|
|
44
|
+
const raw = use(sources.read(filename));
|
|
33
45
|
const provided = useMDXComponents(components);
|
|
34
46
|
const body = stripFrontmatter(raw);
|
|
35
47
|
return (
|
|
@@ -59,6 +71,7 @@ const SafeInclude = ({
|
|
|
59
71
|
export {
|
|
60
72
|
SafeInclude,
|
|
61
73
|
appMountRelative,
|
|
74
|
+
isForeignMountPath,
|
|
62
75
|
stripFrontmatter
|
|
63
76
|
};
|
|
64
77
|
//# sourceMappingURL=SafeInclude.js.map
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"sources":["../../src/components/SafeInclude.tsx"],"sourcesContent":["import { Suspense, use, useMemo } from 'react';\nimport { ErrorBoundary } from 'react-error-boundary';\n\nimport { openAppFs } 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// 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(
|
|
1
|
+
{"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(\n () => (readSource ? createSourceCache(readSource) : defaultSources),\n [readSource],\n );\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":";AAgHM;AAhHN,SAAS,UAAU,KAAK,eAAe;AACvC,SAAS,qBAAqB;AAE9B,SAAS,WAAW,cAAc;AAClC,SAAS,uBAAuB;AAChC,SAAS,wBAAwB;AACjC,SAAS,mBAAmB;AAC5B,SAAS,yBAA4C;AACrD,SAAS,sCAAsC;AAC/C,SAAS,uBAAuB,+BAA+B;AAuBxD,SAAS,iBAAiB,QAAwB;AACvD,SAAO,OAAO,QAAQ,gDAAgD,EAAE;AAC1E;AAKO,SAAS,iBAAiB,UAA0B;AACzD,QAAM,OAAO,gBAAgB,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,OAAO,gBAAgB,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,WAAO,OAAO,EAAE,MAAM,KAAK,MAAM,QAAQ,CAAU,EAAE;AAAA,MACnD,SAAS,QAAQ,QAAQ,EAAE;AAAA,MAC3B;AAAA,IACF;AAAA,EACF;AACA,SAAO,UAAU,EAAE,SAAS,iBAAiB,QAAQ,GAAG,MAAM;AAChE;AAKA,MAAM,iBAAiB,kBAAkB,qBAAqB;AAE9D,SAAS,gBAAgB;AAAA,EACvB;AAAA,EACA;AAAA,EACA;AACF,GAIG;AAGD,QAAM,UAAU;AAAA,IACd,MAAO,aAAa,kBAAkB,UAAU,IAAI;AAAA,IACpD,CAAC,UAAU;AAAA,EACb;AACA,QAAM,MAAM,IAAI,QAAQ,KAAK,QAAQ,CAAC;AACtC,QAAM,WAAW,iBAAiB,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,8BAAC,eAAY,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,oBAAC,iBAAc,gBAAgB,gBAC7B,8BAAC,YAAS,UAAU,oBAAC,oBAAiB,GACpC,8BAAC,mBAAgB,UAAoB,YAAwB,YAAwB,GACvF,GACF;AAAA;","names":[]}
|
package/dist/urlUtils.cjs
CHANGED
|
@@ -41,7 +41,7 @@ const APP_ROOT = "/app";
|
|
|
41
41
|
const underAppRoot = (repoRelativePath) => (0, import_pathUtils.joinPaths)(APP_ROOT, repoRelativePath);
|
|
42
42
|
const getOuterHostname = (outerHref) => {
|
|
43
43
|
const url = new URL(outerHref);
|
|
44
|
-
return `${url.protocol}//${url.
|
|
44
|
+
return `${url.protocol}//${url.host}`;
|
|
45
45
|
};
|
|
46
46
|
const getSearchParams = (search) => Object.fromEntries(
|
|
47
47
|
[...new URLSearchParams(search ?? window.location.search).entries()]
|
|
@@ -73,7 +73,9 @@ const maybeParseUrl = (str) => {
|
|
|
73
73
|
const isAbsolutePath = (sandboxPath) => sandboxPath.startsWith("/");
|
|
74
74
|
const repositoryPrefixURL = (outerHref, navigationState) => constructUrl(outerHref, {
|
|
75
75
|
...navigationState,
|
|
76
|
-
sandboxPath: ""
|
|
76
|
+
sandboxPath: "",
|
|
77
|
+
hash: "",
|
|
78
|
+
search: ""
|
|
77
79
|
});
|
|
78
80
|
const constructOuterUrl = (previousOuterHref, sandboxTarget, navigationState, addFilesPrefix = true) => {
|
|
79
81
|
if (isAbsolutePath(sandboxTarget)) {
|
package/dist/urlUtils.cjs.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"sources":["../src/urlUtils.ts"],"sourcesContent":["import { joinPaths } from \"./pathUtils\";\nimport { NavigationState, PathState } from \"./TinkerableContext\";\n\nexport const FILES_PREFIX = '/files';\n\n/**\n * Mount point of the Git repository inside the sandbox filesystem. The sandbox\n * fs is rooted at `/` (so apps can reach dynamic mounts like `/firestore`), with\n * the repo mounted here. URL subpaths are repo-relative, so the file router\n * resolves them under `APP_ROOT`.\n */\nexport const APP_ROOT = '/app';\n\n/** Resolve a repo-relative path (e.g. a URL subpath) to its absolute sandbox path. */\nexport const underAppRoot = (repoRelativePath: string): string =>\n joinPaths(APP_ROOT, repoRelativePath);\n\nexport const getOuterHostname = (outerHref:string) => {\n const url = new URL(outerHref);\n return `${url.protocol}//${url.hostname}`;\n}\n\nexport const getSearchParams = (search?: string): Record<string, string> => Object.fromEntries(\n [...(new URLSearchParams(search ?? window.location.search).entries())]);\n\n/**\n * Split a link target into its path part and its `#fragment` (the `#` dropped),\n * e.g. `\"FOO.mdx#sec-8-9\"` → `[\"FOO.mdx\", \"sec-8-9\"]`, `\"#sec-3\"` → `[\"\", \"sec-3\"]`,\n * `\"FOO.mdx\"` → `[\"FOO.mdx\", \"\"]`. Only the **first** `#` splits — a fragment never\n * contains another `#`. The seam between wiki-links (§13) and heading ids (§15):\n * existence is resolved on the path part, the fragment is threaded to navigation.\n * MARKDOWN_SYNTAX_SPEC §13.5.\n */\nexport const splitHash = (target: string): [string, string] => {\n const i = target.indexOf('#');\n return i === -1 ? [target, ''] : [target.slice(0, i), target.slice(i + 1)];\n};\n\n\nexport const parseTarget = (target: string, navigation: NavigationState): NavigationState => {\n const newNavigation = { ...navigation };\n let [prehash, hash] = target.split(\"#\")\n if (prehash) {\n let [path, search] = prehash.split(\"?\")\n if (path) {\n newNavigation.sandboxPath = path\n }\n newNavigation.search = search ? search : '';\n }\n newNavigation.hash = hash ? hash : '';\n return newNavigation\n}\n\n\nexport const maybeParseUrl = (str: string): URL | null => {\n try {\n return new URL(str);\n } catch (_) {\n return null;\n }\n}\n\nexport const isAbsolutePath = (sandboxPath: string) => sandboxPath.startsWith('/');\n\nexport const repositoryPrefixURL = (outerHref:string, navigationState: NavigationState) => constructUrl(outerHref, {\n ...navigationState,\n sandboxPath: ''\n });\n\nexport const constructOuterUrl = (previousOuterHref:string, sandboxTarget:string, navigationState: NavigationState, addFilesPrefix=true):string => {\n if (isAbsolutePath(sandboxTarget)) {\n // Split a trailing `#fragment` off before the target is folded into the\n // sandboxPath, and carry it in `hash` instead — a fragment addresses a section,\n // not a file, so it must not leak into the path (MARKDOWN_SYNTAX_SPEC §13.5). An\n // absolute target with no fragment clears any stale hash from the prior state.\n const [pathPart, hash] = splitHash(sandboxTarget);\n return constructUrl(\n previousOuterHref,\n {\n ...navigationState,\n sandboxPath: addFilesPrefix ? joinPaths(FILES_PREFIX, pathPart) : pathPart,\n hash,\n })\n }\n return (\n new URL(\n sandboxTarget,\n constructUrl(\n previousOuterHref,\n navigationState\n )\n )\n ).toString();\n}\n\nexport const isInternalHref = (outerHref:string, target: string, navigationState: NavigationState) => {\n const parsedUrl = maybeParseUrl(target);\n if (parsedUrl) {\n return target.startsWith(repositoryPrefixURL(outerHref, navigationState));\n }\n // if target is not a valid URL, then assume it's relative.\n return true;\n}\n\nexport type PathSegment = {\n name: string,\n pattern: string,\n transform?: (pathSegment: string) => string,\n // When true, the leading slash that delimits this segment is optional, so the\n // whole `/segment` group can be absent. Used for the trailing sandboxPath:\n // an outer href of `/mode/provider/namespace/repository/ref` (no trailing\n // slash, no sub-path) must still parse, otherwise the regex matches nothing\n // and every segment comes back empty.\n optionalLeadingSlash?: boolean\n}\n\nconst PATH_SEGMENTS: PathSegment[] = [\n { name: 'mode', pattern: '\\\\w+' },\n { name: 'provider', pattern: '[a-zA-Z0-9-_]+' },\n { name: 'namespace', pattern: '[a-zA-Z0-9-_]+' },\n { name: 'repository', pattern: '[a-zA-Z0-9-_]+' },\n { name: 'ref', pattern: '[a-zA-Z0-9-_]+' },\n { name: 'sandboxPath', pattern: '.*', transform: s => `/${s}`, optionalLeadingSlash: true }\n];\n\nconst OUTER_HREF_REGEXP = new RegExp(\n '^' +\n PATH_SEGMENTS.map(({ name, pattern, optionalLeadingSlash }) =>\n optionalLeadingSlash\n ? `(?:\\/(?<${name}>${pattern}))?`\n : `\\/(?<${name}>${pattern})`\n ).join('') +\n \"$\"\n);\n\n\nexport const parsePath = (pathname: string): PathState => {\n const matchResults = pathname.match(OUTER_HREF_REGEXP)?.groups ?? {};\n return PATH_SEGMENTS.reduce((acc: Partial<PathState>, { name, transform }: PathSegment) => {\n let value: string | undefined = undefined;\n if (name in matchResults) {\n value = matchResults[name];\n }\n if (!value) {\n // fall back to default value if var not present in\n value = '';\n }\n if (typeof value === 'string') {\n acc[name] = transform ? transform(value) : value;\n }\n return acc;\n }, {}) as PathState;\n}\n\nexport const parseHref = (href: string): NavigationState => {\n const parsedUrl = new URL(href);\n const pathnameState = parsePath(parsedUrl.pathname);\n return {\n ...pathnameState,\n search: parsedUrl.search.substring(1),\n hash: parsedUrl.hash.substring(1),\n } as NavigationState\n}\n\nconst stripSlashPrefix = (s: string): string => s.startsWith('/') ? s.substring(1) : s;\n\nexport const constructUrl = (outerHref:string, navigationState: NavigationState): string => {\n const path = PATH_SEGMENTS.map(({ name }) => {\n let value = navigationState[name];\n return stripSlashPrefix(value ?? '');\n }).join('/');\n const host = getOuterHostname(outerHref);\n let url = `${host}/${path}`\n if (navigationState.search) {\n url += '?' + navigationState.search\n }\n if (navigationState.hash) {\n url += '#' + navigationState.hash\n }\n return url;\n}\n"],"mappings":"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","names":[]}
|
|
1
|
+
{"version":3,"sources":["../src/urlUtils.ts"],"sourcesContent":["import { joinPaths } from \"./pathUtils\";\nimport { NavigationState, PathState } from \"./TinkerableContext\";\n\nexport const FILES_PREFIX = '/files';\n\n/**\n * Mount point of the Git repository inside the sandbox filesystem. The sandbox\n * fs is rooted at `/` (so apps can reach dynamic mounts like `/firestore`), with\n * the repo mounted here. URL subpaths are repo-relative, so the file router\n * resolves them under `APP_ROOT`.\n */\nexport const APP_ROOT = '/app';\n\n/** Resolve a repo-relative path (e.g. a URL subpath) to its absolute sandbox path. */\nexport const underAppRoot = (repoRelativePath: string): string =>\n joinPaths(APP_ROOT, repoRelativePath);\n\n/**\n * The origin every outer URL is rebuilt on — `protocol//host`, **port included**.\n *\n * `url.hostname` drops the port; `url.host` keeps it (and still omits it for the default\n * 80/443, so a production URL is byte-identical either way). Using `hostname` here was\n * invisible on `https://immediately.run` and broke every routed link under local dev on any\n * port but 80: `http://localhost:3100/edit/…` was rebuilt as `http://localhost/edit/…`.\n *\n * Worse than a wrong link, it silently changed link BEHAVIOUR. `repositoryPrefixURL` is\n * built from this, and `isInternalHref` decides by prefix-matching against it — so an\n * absolute in-app URL failed the match, was classified EXTERNAL, and rendered as a plain\n * `<a>`. Clicking it performed a real navigation out of the sandboxed frame instead of\n * routing: the app appeared to \"reload\" on an ordinary internal link.\n */\nexport const getOuterHostname = (outerHref:string) => {\n const url = new URL(outerHref);\n return `${url.protocol}//${url.host}`;\n}\n\nexport const getSearchParams = (search?: string): Record<string, string> => Object.fromEntries(\n [...(new URLSearchParams(search ?? window.location.search).entries())]);\n\n/**\n * Split a link target into its path part and its `#fragment` (the `#` dropped),\n * e.g. `\"FOO.mdx#sec-8-9\"` → `[\"FOO.mdx\", \"sec-8-9\"]`, `\"#sec-3\"` → `[\"\", \"sec-3\"]`,\n * `\"FOO.mdx\"` → `[\"FOO.mdx\", \"\"]`. Only the **first** `#` splits — a fragment never\n * contains another `#`. The seam between wiki-links (§13) and heading ids (§15):\n * existence is resolved on the path part, the fragment is threaded to navigation.\n * MARKDOWN_SYNTAX_SPEC §13.5.\n */\nexport const splitHash = (target: string): [string, string] => {\n const i = target.indexOf('#');\n return i === -1 ? [target, ''] : [target.slice(0, i), target.slice(i + 1)];\n};\n\n\nexport const parseTarget = (target: string, navigation: NavigationState): NavigationState => {\n const newNavigation = { ...navigation };\n let [prehash, hash] = target.split(\"#\")\n if (prehash) {\n let [path, search] = prehash.split(\"?\")\n if (path) {\n newNavigation.sandboxPath = path\n }\n newNavigation.search = search ? search : '';\n }\n newNavigation.hash = hash ? hash : '';\n return newNavigation\n}\n\n\nexport const maybeParseUrl = (str: string): URL | null => {\n try {\n return new URL(str);\n } catch (_) {\n return null;\n }\n}\n\nexport const isAbsolutePath = (sandboxPath: string) => sandboxPath.startsWith('/');\n\n/**\n * The origin+repo prefix every same-app URL starts with — used by {@link isInternalHref} to\n * decide whether an absolute href is \"this app\" or somewhere else.\n *\n * `hash` and `search` are cleared, not just `sandboxPath`. They belong to the CURRENT page,\n * and leaving them in put them on the end of a *prefix*: from a page carrying `#sec-8-9`,\n * the prefix became `…/main/#sec-8-9`, no same-app URL could start with it, every absolute\n * in-app link was classified EXTERNAL, and clicking one navigated the sandboxed frame away\n * instead of routing. A page with a fragment quietly broke its own links.\n */\nexport const repositoryPrefixURL = (outerHref:string, navigationState: NavigationState) => constructUrl(outerHref, {\n ...navigationState,\n sandboxPath: '',\n hash: '',\n search: '',\n });\n\nexport const constructOuterUrl = (previousOuterHref:string, sandboxTarget:string, navigationState: NavigationState, addFilesPrefix=true):string => {\n if (isAbsolutePath(sandboxTarget)) {\n // Split a trailing `#fragment` off before the target is folded into the\n // sandboxPath, and carry it in `hash` instead — a fragment addresses a section,\n // not a file, so it must not leak into the path (MARKDOWN_SYNTAX_SPEC §13.5). An\n // absolute target with no fragment clears any stale hash from the prior state.\n const [pathPart, hash] = splitHash(sandboxTarget);\n return constructUrl(\n previousOuterHref,\n {\n ...navigationState,\n sandboxPath: addFilesPrefix ? joinPaths(FILES_PREFIX, pathPart) : pathPart,\n hash,\n })\n }\n return (\n new URL(\n sandboxTarget,\n constructUrl(\n previousOuterHref,\n navigationState\n )\n )\n ).toString();\n}\n\nexport const isInternalHref = (outerHref:string, target: string, navigationState: NavigationState) => {\n const parsedUrl = maybeParseUrl(target);\n if (parsedUrl) {\n return target.startsWith(repositoryPrefixURL(outerHref, navigationState));\n }\n // if target is not a valid URL, then assume it's relative.\n return true;\n}\n\nexport type PathSegment = {\n name: string,\n pattern: string,\n transform?: (pathSegment: string) => string,\n // When true, the leading slash that delimits this segment is optional, so the\n // whole `/segment` group can be absent. Used for the trailing sandboxPath:\n // an outer href of `/mode/provider/namespace/repository/ref` (no trailing\n // slash, no sub-path) must still parse, otherwise the regex matches nothing\n // and every segment comes back empty.\n optionalLeadingSlash?: boolean\n}\n\nconst PATH_SEGMENTS: PathSegment[] = [\n { name: 'mode', pattern: '\\\\w+' },\n { name: 'provider', pattern: '[a-zA-Z0-9-_]+' },\n { name: 'namespace', pattern: '[a-zA-Z0-9-_]+' },\n { name: 'repository', pattern: '[a-zA-Z0-9-_]+' },\n { name: 'ref', pattern: '[a-zA-Z0-9-_]+' },\n { name: 'sandboxPath', pattern: '.*', transform: s => `/${s}`, optionalLeadingSlash: true }\n];\n\nconst OUTER_HREF_REGEXP = new RegExp(\n '^' +\n PATH_SEGMENTS.map(({ name, pattern, optionalLeadingSlash }) =>\n optionalLeadingSlash\n ? `(?:\\/(?<${name}>${pattern}))?`\n : `\\/(?<${name}>${pattern})`\n ).join('') +\n \"$\"\n);\n\n\nexport const parsePath = (pathname: string): PathState => {\n const matchResults = pathname.match(OUTER_HREF_REGEXP)?.groups ?? {};\n return PATH_SEGMENTS.reduce((acc: Partial<PathState>, { name, transform }: PathSegment) => {\n let value: string | undefined = undefined;\n if (name in matchResults) {\n value = matchResults[name];\n }\n if (!value) {\n // fall back to default value if var not present in\n value = '';\n }\n if (typeof value === 'string') {\n acc[name] = transform ? transform(value) : value;\n }\n return acc;\n }, {}) as PathState;\n}\n\nexport const parseHref = (href: string): NavigationState => {\n const parsedUrl = new URL(href);\n const pathnameState = parsePath(parsedUrl.pathname);\n return {\n ...pathnameState,\n search: parsedUrl.search.substring(1),\n hash: parsedUrl.hash.substring(1),\n } as NavigationState\n}\n\nconst stripSlashPrefix = (s: string): string => s.startsWith('/') ? s.substring(1) : s;\n\nexport const constructUrl = (outerHref:string, navigationState: NavigationState): string => {\n const path = PATH_SEGMENTS.map(({ name }) => {\n let value = navigationState[name];\n return stripSlashPrefix(value ?? '');\n }).join('/');\n const host = getOuterHostname(outerHref);\n let url = `${host}/${path}`\n if (navigationState.search) {\n url += '?' + navigationState.search\n }\n if (navigationState.hash) {\n url += '#' + navigationState.hash\n }\n return url;\n}\n"],"mappings":"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","names":[]}
|
package/dist/urlUtils.d.cts
CHANGED
|
@@ -13,6 +13,20 @@ declare const FILES_PREFIX = "/files";
|
|
|
13
13
|
declare const APP_ROOT = "/app";
|
|
14
14
|
/** Resolve a repo-relative path (e.g. a URL subpath) to its absolute sandbox path. */
|
|
15
15
|
declare const underAppRoot: (repoRelativePath: string) => string;
|
|
16
|
+
/**
|
|
17
|
+
* The origin every outer URL is rebuilt on — `protocol//host`, **port included**.
|
|
18
|
+
*
|
|
19
|
+
* `url.hostname` drops the port; `url.host` keeps it (and still omits it for the default
|
|
20
|
+
* 80/443, so a production URL is byte-identical either way). Using `hostname` here was
|
|
21
|
+
* invisible on `https://immediately.run` and broke every routed link under local dev on any
|
|
22
|
+
* port but 80: `http://localhost:3100/edit/…` was rebuilt as `http://localhost/edit/…`.
|
|
23
|
+
*
|
|
24
|
+
* Worse than a wrong link, it silently changed link BEHAVIOUR. `repositoryPrefixURL` is
|
|
25
|
+
* built from this, and `isInternalHref` decides by prefix-matching against it — so an
|
|
26
|
+
* absolute in-app URL failed the match, was classified EXTERNAL, and rendered as a plain
|
|
27
|
+
* `<a>`. Clicking it performed a real navigation out of the sandboxed frame instead of
|
|
28
|
+
* routing: the app appeared to "reload" on an ordinary internal link.
|
|
29
|
+
*/
|
|
16
30
|
declare const getOuterHostname: (outerHref: string) => string;
|
|
17
31
|
declare const getSearchParams: (search?: string) => Record<string, string>;
|
|
18
32
|
/**
|
|
@@ -27,6 +41,16 @@ declare const splitHash: (target: string) => [string, string];
|
|
|
27
41
|
declare const parseTarget: (target: string, navigation: NavigationState) => NavigationState;
|
|
28
42
|
declare const maybeParseUrl: (str: string) => URL | null;
|
|
29
43
|
declare const isAbsolutePath: (sandboxPath: string) => boolean;
|
|
44
|
+
/**
|
|
45
|
+
* The origin+repo prefix every same-app URL starts with — used by {@link isInternalHref} to
|
|
46
|
+
* decide whether an absolute href is "this app" or somewhere else.
|
|
47
|
+
*
|
|
48
|
+
* `hash` and `search` are cleared, not just `sandboxPath`. They belong to the CURRENT page,
|
|
49
|
+
* and leaving them in put them on the end of a *prefix*: from a page carrying `#sec-8-9`,
|
|
50
|
+
* the prefix became `…/main/#sec-8-9`, no same-app URL could start with it, every absolute
|
|
51
|
+
* in-app link was classified EXTERNAL, and clicking one navigated the sandboxed frame away
|
|
52
|
+
* instead of routing. A page with a fragment quietly broke its own links.
|
|
53
|
+
*/
|
|
30
54
|
declare const repositoryPrefixURL: (outerHref: string, navigationState: NavigationState) => string;
|
|
31
55
|
declare const constructOuterUrl: (previousOuterHref: string, sandboxTarget: string, navigationState: NavigationState, addFilesPrefix?: boolean) => string;
|
|
32
56
|
declare const isInternalHref: (outerHref: string, target: string, navigationState: NavigationState) => boolean;
|
package/dist/urlUtils.d.ts
CHANGED
|
@@ -13,6 +13,20 @@ declare const FILES_PREFIX = "/files";
|
|
|
13
13
|
declare const APP_ROOT = "/app";
|
|
14
14
|
/** Resolve a repo-relative path (e.g. a URL subpath) to its absolute sandbox path. */
|
|
15
15
|
declare const underAppRoot: (repoRelativePath: string) => string;
|
|
16
|
+
/**
|
|
17
|
+
* The origin every outer URL is rebuilt on — `protocol//host`, **port included**.
|
|
18
|
+
*
|
|
19
|
+
* `url.hostname` drops the port; `url.host` keeps it (and still omits it for the default
|
|
20
|
+
* 80/443, so a production URL is byte-identical either way). Using `hostname` here was
|
|
21
|
+
* invisible on `https://immediately.run` and broke every routed link under local dev on any
|
|
22
|
+
* port but 80: `http://localhost:3100/edit/…` was rebuilt as `http://localhost/edit/…`.
|
|
23
|
+
*
|
|
24
|
+
* Worse than a wrong link, it silently changed link BEHAVIOUR. `repositoryPrefixURL` is
|
|
25
|
+
* built from this, and `isInternalHref` decides by prefix-matching against it — so an
|
|
26
|
+
* absolute in-app URL failed the match, was classified EXTERNAL, and rendered as a plain
|
|
27
|
+
* `<a>`. Clicking it performed a real navigation out of the sandboxed frame instead of
|
|
28
|
+
* routing: the app appeared to "reload" on an ordinary internal link.
|
|
29
|
+
*/
|
|
16
30
|
declare const getOuterHostname: (outerHref: string) => string;
|
|
17
31
|
declare const getSearchParams: (search?: string) => Record<string, string>;
|
|
18
32
|
/**
|
|
@@ -27,6 +41,16 @@ declare const splitHash: (target: string) => [string, string];
|
|
|
27
41
|
declare const parseTarget: (target: string, navigation: NavigationState) => NavigationState;
|
|
28
42
|
declare const maybeParseUrl: (str: string) => URL | null;
|
|
29
43
|
declare const isAbsolutePath: (sandboxPath: string) => boolean;
|
|
44
|
+
/**
|
|
45
|
+
* The origin+repo prefix every same-app URL starts with — used by {@link isInternalHref} to
|
|
46
|
+
* decide whether an absolute href is "this app" or somewhere else.
|
|
47
|
+
*
|
|
48
|
+
* `hash` and `search` are cleared, not just `sandboxPath`. They belong to the CURRENT page,
|
|
49
|
+
* and leaving them in put them on the end of a *prefix*: from a page carrying `#sec-8-9`,
|
|
50
|
+
* the prefix became `…/main/#sec-8-9`, no same-app URL could start with it, every absolute
|
|
51
|
+
* in-app link was classified EXTERNAL, and clicking one navigated the sandboxed frame away
|
|
52
|
+
* instead of routing. A page with a fragment quietly broke its own links.
|
|
53
|
+
*/
|
|
30
54
|
declare const repositoryPrefixURL: (outerHref: string, navigationState: NavigationState) => string;
|
|
31
55
|
declare const constructOuterUrl: (previousOuterHref: string, sandboxTarget: string, navigationState: NavigationState, addFilesPrefix?: boolean) => string;
|
|
32
56
|
declare const isInternalHref: (outerHref: string, target: string, navigationState: NavigationState) => boolean;
|
package/dist/urlUtils.js
CHANGED
|
@@ -5,7 +5,7 @@ const APP_ROOT = "/app";
|
|
|
5
5
|
const underAppRoot = (repoRelativePath) => joinPaths(APP_ROOT, repoRelativePath);
|
|
6
6
|
const getOuterHostname = (outerHref) => {
|
|
7
7
|
const url = new URL(outerHref);
|
|
8
|
-
return `${url.protocol}//${url.
|
|
8
|
+
return `${url.protocol}//${url.host}`;
|
|
9
9
|
};
|
|
10
10
|
const getSearchParams = (search) => Object.fromEntries(
|
|
11
11
|
[...new URLSearchParams(search ?? window.location.search).entries()]
|
|
@@ -37,7 +37,9 @@ const maybeParseUrl = (str) => {
|
|
|
37
37
|
const isAbsolutePath = (sandboxPath) => sandboxPath.startsWith("/");
|
|
38
38
|
const repositoryPrefixURL = (outerHref, navigationState) => constructUrl(outerHref, {
|
|
39
39
|
...navigationState,
|
|
40
|
-
sandboxPath: ""
|
|
40
|
+
sandboxPath: "",
|
|
41
|
+
hash: "",
|
|
42
|
+
search: ""
|
|
41
43
|
});
|
|
42
44
|
const constructOuterUrl = (previousOuterHref, sandboxTarget, navigationState, addFilesPrefix = true) => {
|
|
43
45
|
if (isAbsolutePath(sandboxTarget)) {
|
package/dist/urlUtils.js.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"sources":["../src/urlUtils.ts"],"sourcesContent":["import { joinPaths } from \"./pathUtils\";\nimport { NavigationState, PathState } from \"./TinkerableContext\";\n\nexport const FILES_PREFIX = '/files';\n\n/**\n * Mount point of the Git repository inside the sandbox filesystem. The sandbox\n * fs is rooted at `/` (so apps can reach dynamic mounts like `/firestore`), with\n * the repo mounted here. URL subpaths are repo-relative, so the file router\n * resolves them under `APP_ROOT`.\n */\nexport const APP_ROOT = '/app';\n\n/** Resolve a repo-relative path (e.g. a URL subpath) to its absolute sandbox path. */\nexport const underAppRoot = (repoRelativePath: string): string =>\n joinPaths(APP_ROOT, repoRelativePath);\n\nexport const getOuterHostname = (outerHref:string) => {\n const url = new URL(outerHref);\n return `${url.protocol}//${url.hostname}`;\n}\n\nexport const getSearchParams = (search?: string): Record<string, string> => Object.fromEntries(\n [...(new URLSearchParams(search ?? window.location.search).entries())]);\n\n/**\n * Split a link target into its path part and its `#fragment` (the `#` dropped),\n * e.g. `\"FOO.mdx#sec-8-9\"` → `[\"FOO.mdx\", \"sec-8-9\"]`, `\"#sec-3\"` → `[\"\", \"sec-3\"]`,\n * `\"FOO.mdx\"` → `[\"FOO.mdx\", \"\"]`. Only the **first** `#` splits — a fragment never\n * contains another `#`. The seam between wiki-links (§13) and heading ids (§15):\n * existence is resolved on the path part, the fragment is threaded to navigation.\n * MARKDOWN_SYNTAX_SPEC §13.5.\n */\nexport const splitHash = (target: string): [string, string] => {\n const i = target.indexOf('#');\n return i === -1 ? [target, ''] : [target.slice(0, i), target.slice(i + 1)];\n};\n\n\nexport const parseTarget = (target: string, navigation: NavigationState): NavigationState => {\n const newNavigation = { ...navigation };\n let [prehash, hash] = target.split(\"#\")\n if (prehash) {\n let [path, search] = prehash.split(\"?\")\n if (path) {\n newNavigation.sandboxPath = path\n }\n newNavigation.search = search ? search : '';\n }\n newNavigation.hash = hash ? hash : '';\n return newNavigation\n}\n\n\nexport const maybeParseUrl = (str: string): URL | null => {\n try {\n return new URL(str);\n } catch (_) {\n return null;\n }\n}\n\nexport const isAbsolutePath = (sandboxPath: string) => sandboxPath.startsWith('/');\n\nexport const repositoryPrefixURL = (outerHref:string, navigationState: NavigationState) => constructUrl(outerHref, {\n ...navigationState,\n sandboxPath: ''\n });\n\nexport const constructOuterUrl = (previousOuterHref:string, sandboxTarget:string, navigationState: NavigationState, addFilesPrefix=true):string => {\n if (isAbsolutePath(sandboxTarget)) {\n // Split a trailing `#fragment` off before the target is folded into the\n // sandboxPath, and carry it in `hash` instead — a fragment addresses a section,\n // not a file, so it must not leak into the path (MARKDOWN_SYNTAX_SPEC §13.5). An\n // absolute target with no fragment clears any stale hash from the prior state.\n const [pathPart, hash] = splitHash(sandboxTarget);\n return constructUrl(\n previousOuterHref,\n {\n ...navigationState,\n sandboxPath: addFilesPrefix ? joinPaths(FILES_PREFIX, pathPart) : pathPart,\n hash,\n })\n }\n return (\n new URL(\n sandboxTarget,\n constructUrl(\n previousOuterHref,\n navigationState\n )\n )\n ).toString();\n}\n\nexport const isInternalHref = (outerHref:string, target: string, navigationState: NavigationState) => {\n const parsedUrl = maybeParseUrl(target);\n if (parsedUrl) {\n return target.startsWith(repositoryPrefixURL(outerHref, navigationState));\n }\n // if target is not a valid URL, then assume it's relative.\n return true;\n}\n\nexport type PathSegment = {\n name: string,\n pattern: string,\n transform?: (pathSegment: string) => string,\n // When true, the leading slash that delimits this segment is optional, so the\n // whole `/segment` group can be absent. Used for the trailing sandboxPath:\n // an outer href of `/mode/provider/namespace/repository/ref` (no trailing\n // slash, no sub-path) must still parse, otherwise the regex matches nothing\n // and every segment comes back empty.\n optionalLeadingSlash?: boolean\n}\n\nconst PATH_SEGMENTS: PathSegment[] = [\n { name: 'mode', pattern: '\\\\w+' },\n { name: 'provider', pattern: '[a-zA-Z0-9-_]+' },\n { name: 'namespace', pattern: '[a-zA-Z0-9-_]+' },\n { name: 'repository', pattern: '[a-zA-Z0-9-_]+' },\n { name: 'ref', pattern: '[a-zA-Z0-9-_]+' },\n { name: 'sandboxPath', pattern: '.*', transform: s => `/${s}`, optionalLeadingSlash: true }\n];\n\nconst OUTER_HREF_REGEXP = new RegExp(\n '^' +\n PATH_SEGMENTS.map(({ name, pattern, optionalLeadingSlash }) =>\n optionalLeadingSlash\n ? `(?:\\/(?<${name}>${pattern}))?`\n : `\\/(?<${name}>${pattern})`\n ).join('') +\n \"$\"\n);\n\n\nexport const parsePath = (pathname: string): PathState => {\n const matchResults = pathname.match(OUTER_HREF_REGEXP)?.groups ?? {};\n return PATH_SEGMENTS.reduce((acc: Partial<PathState>, { name, transform }: PathSegment) => {\n let value: string | undefined = undefined;\n if (name in matchResults) {\n value = matchResults[name];\n }\n if (!value) {\n // fall back to default value if var not present in\n value = '';\n }\n if (typeof value === 'string') {\n acc[name] = transform ? transform(value) : value;\n }\n return acc;\n }, {}) as PathState;\n}\n\nexport const parseHref = (href: string): NavigationState => {\n const parsedUrl = new URL(href);\n const pathnameState = parsePath(parsedUrl.pathname);\n return {\n ...pathnameState,\n search: parsedUrl.search.substring(1),\n hash: parsedUrl.hash.substring(1),\n } as NavigationState\n}\n\nconst stripSlashPrefix = (s: string): string => s.startsWith('/') ? s.substring(1) : s;\n\nexport const constructUrl = (outerHref:string, navigationState: NavigationState): string => {\n const path = PATH_SEGMENTS.map(({ name }) => {\n let value = navigationState[name];\n return stripSlashPrefix(value ?? '');\n }).join('/');\n const host = getOuterHostname(outerHref);\n let url = `${host}/${path}`\n if (navigationState.search) {\n url += '?' + navigationState.search\n }\n if (navigationState.hash) {\n url += '#' + navigationState.hash\n }\n return url;\n}\n"],"mappings":"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","names":[]}
|
|
1
|
+
{"version":3,"sources":["../src/urlUtils.ts"],"sourcesContent":["import { joinPaths } from \"./pathUtils\";\nimport { NavigationState, PathState } from \"./TinkerableContext\";\n\nexport const FILES_PREFIX = '/files';\n\n/**\n * Mount point of the Git repository inside the sandbox filesystem. The sandbox\n * fs is rooted at `/` (so apps can reach dynamic mounts like `/firestore`), with\n * the repo mounted here. URL subpaths are repo-relative, so the file router\n * resolves them under `APP_ROOT`.\n */\nexport const APP_ROOT = '/app';\n\n/** Resolve a repo-relative path (e.g. a URL subpath) to its absolute sandbox path. */\nexport const underAppRoot = (repoRelativePath: string): string =>\n joinPaths(APP_ROOT, repoRelativePath);\n\n/**\n * The origin every outer URL is rebuilt on — `protocol//host`, **port included**.\n *\n * `url.hostname` drops the port; `url.host` keeps it (and still omits it for the default\n * 80/443, so a production URL is byte-identical either way). Using `hostname` here was\n * invisible on `https://immediately.run` and broke every routed link under local dev on any\n * port but 80: `http://localhost:3100/edit/…` was rebuilt as `http://localhost/edit/…`.\n *\n * Worse than a wrong link, it silently changed link BEHAVIOUR. `repositoryPrefixURL` is\n * built from this, and `isInternalHref` decides by prefix-matching against it — so an\n * absolute in-app URL failed the match, was classified EXTERNAL, and rendered as a plain\n * `<a>`. Clicking it performed a real navigation out of the sandboxed frame instead of\n * routing: the app appeared to \"reload\" on an ordinary internal link.\n */\nexport const getOuterHostname = (outerHref:string) => {\n const url = new URL(outerHref);\n return `${url.protocol}//${url.host}`;\n}\n\nexport const getSearchParams = (search?: string): Record<string, string> => Object.fromEntries(\n [...(new URLSearchParams(search ?? window.location.search).entries())]);\n\n/**\n * Split a link target into its path part and its `#fragment` (the `#` dropped),\n * e.g. `\"FOO.mdx#sec-8-9\"` → `[\"FOO.mdx\", \"sec-8-9\"]`, `\"#sec-3\"` → `[\"\", \"sec-3\"]`,\n * `\"FOO.mdx\"` → `[\"FOO.mdx\", \"\"]`. Only the **first** `#` splits — a fragment never\n * contains another `#`. The seam between wiki-links (§13) and heading ids (§15):\n * existence is resolved on the path part, the fragment is threaded to navigation.\n * MARKDOWN_SYNTAX_SPEC §13.5.\n */\nexport const splitHash = (target: string): [string, string] => {\n const i = target.indexOf('#');\n return i === -1 ? [target, ''] : [target.slice(0, i), target.slice(i + 1)];\n};\n\n\nexport const parseTarget = (target: string, navigation: NavigationState): NavigationState => {\n const newNavigation = { ...navigation };\n let [prehash, hash] = target.split(\"#\")\n if (prehash) {\n let [path, search] = prehash.split(\"?\")\n if (path) {\n newNavigation.sandboxPath = path\n }\n newNavigation.search = search ? search : '';\n }\n newNavigation.hash = hash ? hash : '';\n return newNavigation\n}\n\n\nexport const maybeParseUrl = (str: string): URL | null => {\n try {\n return new URL(str);\n } catch (_) {\n return null;\n }\n}\n\nexport const isAbsolutePath = (sandboxPath: string) => sandboxPath.startsWith('/');\n\n/**\n * The origin+repo prefix every same-app URL starts with — used by {@link isInternalHref} to\n * decide whether an absolute href is \"this app\" or somewhere else.\n *\n * `hash` and `search` are cleared, not just `sandboxPath`. They belong to the CURRENT page,\n * and leaving them in put them on the end of a *prefix*: from a page carrying `#sec-8-9`,\n * the prefix became `…/main/#sec-8-9`, no same-app URL could start with it, every absolute\n * in-app link was classified EXTERNAL, and clicking one navigated the sandboxed frame away\n * instead of routing. A page with a fragment quietly broke its own links.\n */\nexport const repositoryPrefixURL = (outerHref:string, navigationState: NavigationState) => constructUrl(outerHref, {\n ...navigationState,\n sandboxPath: '',\n hash: '',\n search: '',\n });\n\nexport const constructOuterUrl = (previousOuterHref:string, sandboxTarget:string, navigationState: NavigationState, addFilesPrefix=true):string => {\n if (isAbsolutePath(sandboxTarget)) {\n // Split a trailing `#fragment` off before the target is folded into the\n // sandboxPath, and carry it in `hash` instead — a fragment addresses a section,\n // not a file, so it must not leak into the path (MARKDOWN_SYNTAX_SPEC §13.5). An\n // absolute target with no fragment clears any stale hash from the prior state.\n const [pathPart, hash] = splitHash(sandboxTarget);\n return constructUrl(\n previousOuterHref,\n {\n ...navigationState,\n sandboxPath: addFilesPrefix ? joinPaths(FILES_PREFIX, pathPart) : pathPart,\n hash,\n })\n }\n return (\n new URL(\n sandboxTarget,\n constructUrl(\n previousOuterHref,\n navigationState\n )\n )\n ).toString();\n}\n\nexport const isInternalHref = (outerHref:string, target: string, navigationState: NavigationState) => {\n const parsedUrl = maybeParseUrl(target);\n if (parsedUrl) {\n return target.startsWith(repositoryPrefixURL(outerHref, navigationState));\n }\n // if target is not a valid URL, then assume it's relative.\n return true;\n}\n\nexport type PathSegment = {\n name: string,\n pattern: string,\n transform?: (pathSegment: string) => string,\n // When true, the leading slash that delimits this segment is optional, so the\n // whole `/segment` group can be absent. Used for the trailing sandboxPath:\n // an outer href of `/mode/provider/namespace/repository/ref` (no trailing\n // slash, no sub-path) must still parse, otherwise the regex matches nothing\n // and every segment comes back empty.\n optionalLeadingSlash?: boolean\n}\n\nconst PATH_SEGMENTS: PathSegment[] = [\n { name: 'mode', pattern: '\\\\w+' },\n { name: 'provider', pattern: '[a-zA-Z0-9-_]+' },\n { name: 'namespace', pattern: '[a-zA-Z0-9-_]+' },\n { name: 'repository', pattern: '[a-zA-Z0-9-_]+' },\n { name: 'ref', pattern: '[a-zA-Z0-9-_]+' },\n { name: 'sandboxPath', pattern: '.*', transform: s => `/${s}`, optionalLeadingSlash: true }\n];\n\nconst OUTER_HREF_REGEXP = new RegExp(\n '^' +\n PATH_SEGMENTS.map(({ name, pattern, optionalLeadingSlash }) =>\n optionalLeadingSlash\n ? `(?:\\/(?<${name}>${pattern}))?`\n : `\\/(?<${name}>${pattern})`\n ).join('') +\n \"$\"\n);\n\n\nexport const parsePath = (pathname: string): PathState => {\n const matchResults = pathname.match(OUTER_HREF_REGEXP)?.groups ?? {};\n return PATH_SEGMENTS.reduce((acc: Partial<PathState>, { name, transform }: PathSegment) => {\n let value: string | undefined = undefined;\n if (name in matchResults) {\n value = matchResults[name];\n }\n if (!value) {\n // fall back to default value if var not present in\n value = '';\n }\n if (typeof value === 'string') {\n acc[name] = transform ? transform(value) : value;\n }\n return acc;\n }, {}) as PathState;\n}\n\nexport const parseHref = (href: string): NavigationState => {\n const parsedUrl = new URL(href);\n const pathnameState = parsePath(parsedUrl.pathname);\n return {\n ...pathnameState,\n search: parsedUrl.search.substring(1),\n hash: parsedUrl.hash.substring(1),\n } as NavigationState\n}\n\nconst stripSlashPrefix = (s: string): string => s.startsWith('/') ? s.substring(1) : s;\n\nexport const constructUrl = (outerHref:string, navigationState: NavigationState): string => {\n const path = PATH_SEGMENTS.map(({ name }) => {\n let value = navigationState[name];\n return stripSlashPrefix(value ?? '');\n }).join('/');\n const host = getOuterHostname(outerHref);\n let url = `${host}/${path}`\n if (navigationState.search) {\n url += '?' + navigationState.search\n }\n if (navigationState.hash) {\n url += '#' + navigationState.hash\n }\n return url;\n}\n"],"mappings":"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","names":[]}
|
package/dist/version.cjs
CHANGED
|
@@ -21,7 +21,7 @@ __export(version_exports, {
|
|
|
21
21
|
SDK_VERSION: () => SDK_VERSION
|
|
22
22
|
});
|
|
23
23
|
module.exports = __toCommonJS(version_exports);
|
|
24
|
-
const SDK_VERSION = "0.
|
|
24
|
+
const SDK_VERSION = "0.42.0";
|
|
25
25
|
// Annotate the CommonJS export names for ESM import in node:
|
|
26
26
|
0 && (module.exports = {
|
|
27
27
|
SDK_VERSION
|
package/dist/version.cjs.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"sources":["../src/version.ts"],"sourcesContent":["// GENERATED by scripts/gen-version.mjs from package.json — do not edit by hand.\n// Regenerated on every build (prebuild); kept honest by version.test.ts.\n\n/** This SDK's package version, baked from package.json at build (SP2-6). */\nexport const SDK_VERSION = '0.
|
|
1
|
+
{"version":3,"sources":["../src/version.ts"],"sourcesContent":["// GENERATED by scripts/gen-version.mjs from package.json — do not edit by hand.\n// Regenerated on every build (prebuild); kept honest by version.test.ts.\n\n/** This SDK's package version, baked from package.json at build (SP2-6). */\nexport const SDK_VERSION = '0.42.0';\n"],"mappings":";;;;;;;;;;;;;;;;;;AAAA;AAAA;AAAA;AAAA;AAAA;AAIO,MAAM,cAAc;","names":[]}
|
package/dist/version.d.cts
CHANGED
package/dist/version.d.ts
CHANGED
package/dist/version.js
CHANGED
package/dist/version.js.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"sources":["../src/version.ts"],"sourcesContent":["// GENERATED by scripts/gen-version.mjs from package.json — do not edit by hand.\n// Regenerated on every build (prebuild); kept honest by version.test.ts.\n\n/** This SDK's package version, baked from package.json at build (SP2-6). */\nexport const SDK_VERSION = '0.
|
|
1
|
+
{"version":3,"sources":["../src/version.ts"],"sourcesContent":["// GENERATED by scripts/gen-version.mjs from package.json — do not edit by hand.\n// Regenerated on every build (prebuild); kept honest by version.test.ts.\n\n/** This SDK's package version, baked from package.json at build (SP2-6). */\nexport const SDK_VERSION = '0.42.0';\n"],"mappings":";AAIO,MAAM,cAAc;","names":[]}
|
package/package.json
CHANGED