@immediately-run/sdk 0.15.0 → 0.16.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/README.md +27 -3
- package/dist/MDXProvider.cjs.map +1 -1
- package/dist/MDXProvider.d.cts +4 -0
- package/dist/MDXProvider.d.ts +4 -0
- package/dist/MDXProvider.js.map +1 -1
- package/dist/RoutingSpec.cjs.map +1 -1
- package/dist/RoutingSpec.d.cts +20 -3
- package/dist/RoutingSpec.d.ts +20 -3
- package/dist/auth.cjs.map +1 -1
- package/dist/auth.d.cts +2 -0
- package/dist/auth.d.ts +2 -0
- package/dist/auth.js.map +1 -1
- package/dist/boot.cjs +17 -7
- package/dist/boot.cjs.map +1 -1
- package/dist/boot.d.cts +28 -4
- package/dist/boot.d.ts +28 -4
- package/dist/boot.js +16 -7
- package/dist/boot.js.map +1 -1
- package/dist/components/Include.cjs.map +1 -1
- package/dist/components/Include.d.cts +7 -0
- package/dist/components/Include.d.ts +7 -0
- package/dist/components/Include.js.map +1 -1
- package/dist/components/MDXComponents.cjs.map +1 -1
- package/dist/components/MDXComponents.d.cts +6 -0
- package/dist/components/MDXComponents.d.ts +6 -0
- package/dist/components/MDXComponents.js.map +1 -1
- package/dist/components/Routes.cjs +59 -0
- package/dist/components/Routes.cjs.map +1 -0
- package/dist/components/Routes.d.cts +34 -0
- package/dist/components/Routes.d.ts +34 -0
- package/dist/components/Routes.js +34 -0
- package/dist/components/Routes.js.map +1 -0
- package/dist/contribute.cjs.map +1 -1
- package/dist/contribute.d.cts +2 -0
- package/dist/contribute.d.ts +2 -0
- package/dist/contribute.js.map +1 -1
- package/dist/diagnostics.cjs.map +1 -1
- package/dist/diagnostics.d.cts +3 -0
- package/dist/diagnostics.d.ts +3 -0
- package/dist/diagnostics.js.map +1 -1
- package/dist/formFactor.cjs.map +1 -1
- package/dist/formFactor.d.cts +2 -0
- package/dist/formFactor.d.ts +2 -0
- package/dist/formFactor.js.map +1 -1
- package/dist/hooks.cjs +27 -28
- package/dist/hooks.cjs.map +1 -1
- package/dist/hooks.d.cts +39 -4
- package/dist/hooks.d.ts +39 -4
- package/dist/hooks.js +27 -29
- package/dist/hooks.js.map +1 -1
- package/dist/index.cjs +4 -0
- package/dist/index.cjs.map +1 -1
- package/dist/index.d.cts +6 -4
- package/dist/index.d.ts +6 -4
- package/dist/index.js +2 -0
- package/dist/index.js.map +1 -1
- package/dist/irMarkers.cjs.map +1 -1
- package/dist/irMarkers.d.cts +1 -0
- package/dist/irMarkers.d.ts +1 -0
- package/dist/irMarkers.js.map +1 -1
- package/dist/llm.cjs.map +1 -1
- package/dist/llm.d.cts +5 -0
- package/dist/llm.d.ts +5 -0
- package/dist/llm.js.map +1 -1
- package/dist/loading.cjs +186 -0
- package/dist/loading.cjs.map +1 -0
- package/dist/loading.d.cts +48 -0
- package/dist/loading.d.ts +48 -0
- package/dist/loading.js +162 -0
- package/dist/loading.js.map +1 -0
- package/dist/mounts.cjs.map +1 -1
- package/dist/mounts.d.cts +3 -1
- package/dist/mounts.d.ts +3 -1
- package/dist/mounts.js.map +1 -1
- package/dist/netFetch.cjs.map +1 -1
- package/dist/netFetch.d.cts +2 -0
- package/dist/netFetch.d.ts +2 -0
- package/dist/netFetch.js.map +1 -1
- package/dist/onFsChange.cjs.map +1 -1
- package/dist/onFsChange.d.cts +1 -0
- package/dist/onFsChange.d.ts +1 -0
- package/dist/onFsChange.js.map +1 -1
- package/dist/protocolStream.cjs.map +1 -1
- package/dist/protocolStream.d.cts +3 -0
- package/dist/protocolStream.d.ts +3 -0
- package/dist/protocolStream.js.map +1 -1
- package/dist/ready.cjs.map +1 -1
- package/dist/ready.d.cts +7 -0
- package/dist/ready.d.ts +7 -0
- package/dist/ready.js.map +1 -1
- package/dist/routeMatch.cjs +72 -0
- package/dist/routeMatch.cjs.map +1 -0
- package/dist/routeMatch.d.cts +19 -0
- package/dist/routeMatch.d.ts +19 -0
- package/dist/routeMatch.js +46 -0
- package/dist/routeMatch.js.map +1 -0
- package/dist/routing.cjs +35 -14
- package/dist/routing.cjs.map +1 -1
- package/dist/routing.d.cts +33 -4
- package/dist/routing.d.ts +33 -4
- package/dist/routing.js +32 -14
- package/dist/routing.js.map +1 -1
- package/dist/runtime.cjs.map +1 -1
- package/dist/runtime.d.cts +1 -0
- package/dist/runtime.d.ts +1 -0
- package/dist/runtime.js.map +1 -1
- package/dist/sandboxTypes.cjs.map +1 -1
- package/dist/sandboxTypes.d.cts +30 -7
- package/dist/sandboxTypes.d.ts +30 -7
- package/dist/version.cjs +1 -1
- package/dist/version.cjs.map +1 -1
- package/dist/version.d.cts +1 -1
- package/dist/version.d.ts +1 -1
- package/dist/version.js +1 -1
- package/dist/version.js.map +1 -1
- package/package.json +6 -2
package/README.md
CHANGED
|
@@ -21,7 +21,11 @@ also reachable via subpaths (`@immediately-run/sdk/boot`, `@immediately-run/sdk/
|
|
|
21
21
|
- `boot` — entry point that mounts an immediately.run app into the sandbox.
|
|
22
22
|
- `Include` (`components/Include`) — render another file's exported component inline.
|
|
23
23
|
- `MDXComponents` (`Link`, …) — MDX component overrides.
|
|
24
|
-
- `useMetadataQuery`, `useFileMetadata` (`hooks`) — query files by
|
|
24
|
+
- `useMetadataQuery`, `useFileMetadata`, `useAllMetadata` (`hooks`) — query files by
|
|
25
|
+
MDX frontmatter metadata. `useMetadataQuery(fn)` runs a plain JS query and returns
|
|
26
|
+
the matching `{ path, meta }` entries; `useFileMetadata(path)` reads one file's
|
|
27
|
+
frontmatter; `useAllMetadata()` returns the raw reactive map. All take an optional
|
|
28
|
+
type parameter for typed frontmatter access.
|
|
25
29
|
- `getAuthState`, `onAuthChange`, `useAuth` (`auth`) — read or subscribe to the user's
|
|
26
30
|
login / account state (`{ status, user: { login } }`). Poll with `getAuthState()`,
|
|
27
31
|
subscribe with `onAuthChange(listener)` (the listener is called immediately with the
|
|
@@ -32,15 +36,35 @@ also reachable via subpaths (`@immediately-run/sdk/boot`, `@immediately-run/sdk/
|
|
|
32
36
|
`getMounts()` / `findMount({ type })`, subscribe with `onMountsChange(listener)` or
|
|
33
37
|
the `useMounts()` hook, or `await waitForMount({ type: 'firestore' })` before using a
|
|
34
38
|
mount. Access the files via the `fs` module at the mount's `path`.
|
|
35
|
-
- routing
|
|
39
|
+
- routing (`routing`) — define the app-owned URL suffix. Declarative
|
|
40
|
+
`<Routes>`/`<Route path="/posts/:slug" element={…} />` (rendering a `<Route>`
|
|
41
|
+
registers it, so routes can be conditional or data-derived), or a `routingSpec`
|
|
42
|
+
passed to `boot`. `path` accepts a template (`:slug`, `*`) compiled to an
|
|
43
|
+
anchored regex, or a raw `RegExp` as an escape hatch. Read the match with
|
|
44
|
+
`useRouteParams()` / `useRoute()`. Also `Router`, `navigate`, `useTinkerableLink`.
|
|
36
45
|
- `MDXProvider` — the MDX context provider used by transformed `.mdx` files.
|
|
37
46
|
- `sandboxTypes` — shared TypeScript types for the sandbox runtime.
|
|
38
47
|
|
|
39
48
|
## API documentation
|
|
40
49
|
|
|
41
|
-
Full API reference is published to GitHub Pages:
|
|
50
|
+
Full API reference (TypeDoc, human-browsable) is published to GitHub Pages:
|
|
42
51
|
<https://immediately-run.github.io/immediately-run-sdk/>
|
|
43
52
|
|
|
53
|
+
### For coding agents / LLMs
|
|
54
|
+
|
|
55
|
+
Two machine-readable surfaces are published next to the HTML, each fetchable in a
|
|
56
|
+
single request:
|
|
57
|
+
|
|
58
|
+
- **`llms.txt`** — <https://immediately-run.github.io/immediately-run-sdk/llms.txt> —
|
|
59
|
+
a concise, plain-Markdown map of every export grouped by module, with its kind,
|
|
60
|
+
import path, and a one-line description (the llmstxt.org convention). Start here.
|
|
61
|
+
- **`api.json`** — <https://immediately-run.github.io/immediately-run-sdk/api.json> —
|
|
62
|
+
the complete TypeDoc model (exact signatures, parameters, types, and JSDoc) for
|
|
63
|
+
when you need more than the one-liners.
|
|
64
|
+
|
|
65
|
+
The installed npm package also ships `.d.ts` carrying the same JSDoc, so your
|
|
66
|
+
editor/agent tooling can read the typed API inline without any network access.
|
|
67
|
+
|
|
44
68
|
## License
|
|
45
69
|
|
|
46
70
|
[MIT](./LICENSE)
|
package/dist/MDXProvider.cjs.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"sources":["../src/MDXProvider.ts"],"sourcesContent":["// Based on https://github.com/mdx-js/mdx/blob/main/packages/react/lib/index.js\n// since sandpack-bundler cannot import @mdx-js/react as it chokes on the\n// transitive dependency on VFile.\nimport {createContext, useContext, useMemo, createElement} from 'react'\nconst emptyComponents = {}\n\nconst MDXContext = createContext(emptyComponents);\n\nexport function useMDXComponents(components:any) {\n const contextComponents = useContext(MDXContext)\n\n // Memoize to avoid unnecessary top-level context changes\n return useMemo(\n function () {\n // Custom merge via a function prop\n if (typeof components === 'function') {\n return components(contextComponents)\n }\n\n return {...contextComponents, ...components}\n },\n [contextComponents, components]\n )\n}\n\nexport function MDXProvider(properties:any) {\n\n let allComponents: any\n\n if (properties.disableParentContext) {\n allComponents =\n typeof properties.components === 'function'\n ? properties.components(emptyComponents)\n : properties.components || emptyComponents\n } else {\n allComponents = useMDXComponents(properties.components)\n }\n\n return createElement(\n MDXContext.Provider,\n {value: allComponents},\n properties.children\n )\n}\n"],"mappings":";;;;;;;;;;;;;;;;;;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAGA,mBAAgE;AAChE,MAAM,kBAAkB,CAAC;AAEzB,MAAM,iBAAa,4BAAc,eAAe;
|
|
1
|
+
{"version":3,"sources":["../src/MDXProvider.ts"],"sourcesContent":["// Based on https://github.com/mdx-js/mdx/blob/main/packages/react/lib/index.js\n// since sandpack-bundler cannot import @mdx-js/react as it chokes on the\n// transitive dependency on VFile.\nimport {createContext, useContext, useMemo, createElement} from 'react'\nconst emptyComponents = {}\n\nconst MDXContext = createContext(emptyComponents);\n\n/** Merge the caller's MDX component overrides with those from the surrounding\n * {@link MDXProvider} context (a function arg receives the parent set to merge). */\nexport function useMDXComponents(components:any) {\n const contextComponents = useContext(MDXContext)\n\n // Memoize to avoid unnecessary top-level context changes\n return useMemo(\n function () {\n // Custom merge via a function prop\n if (typeof components === 'function') {\n return components(contextComponents)\n }\n\n return {...contextComponents, ...components}\n },\n [contextComponents, components]\n )\n}\n\n/** Provide MDX component overrides (e.g. a custom `a`/`h1`) to the rendered\n * subtree; transformed `.mdx` modules pick them up. */\nexport function MDXProvider(properties:any) {\n\n let allComponents: any\n\n if (properties.disableParentContext) {\n allComponents =\n typeof properties.components === 'function'\n ? properties.components(emptyComponents)\n : properties.components || emptyComponents\n } else {\n allComponents = useMDXComponents(properties.components)\n }\n\n return createElement(\n MDXContext.Provider,\n {value: allComponents},\n properties.children\n )\n}\n"],"mappings":";;;;;;;;;;;;;;;;;;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAGA,mBAAgE;AAChE,MAAM,kBAAkB,CAAC;AAEzB,MAAM,iBAAa,4BAAc,eAAe;AAIzC,SAAS,iBAAiB,YAAgB;AAC/C,QAAM,wBAAoB,yBAAW,UAAU;AAG/C,aAAO;AAAA,IACL,WAAY;AAEV,UAAI,OAAO,eAAe,YAAY;AACpC,eAAO,WAAW,iBAAiB;AAAA,MACrC;AAEA,aAAO,EAAC,GAAG,mBAAmB,GAAG,WAAU;AAAA,IAC7C;AAAA,IACA,CAAC,mBAAmB,UAAU;AAAA,EAChC;AACF;AAIO,SAAS,YAAY,YAAgB;AAE1C,MAAI;AAEJ,MAAI,WAAW,sBAAsB;AACnC,oBACE,OAAO,WAAW,eAAe,aAC7B,WAAW,WAAW,eAAe,IACrC,WAAW,cAAc;AAAA,EACjC,OAAO;AACL,oBAAgB,iBAAiB,WAAW,UAAU;AAAA,EACxD;AAEA,aAAO;AAAA,IACL,WAAW;AAAA,IACX,EAAC,OAAO,cAAa;AAAA,IACrB,WAAW;AAAA,EACb;AACF;","names":[]}
|
package/dist/MDXProvider.d.cts
CHANGED
|
@@ -1,6 +1,10 @@
|
|
|
1
1
|
import * as react from 'react';
|
|
2
2
|
|
|
3
|
+
/** Merge the caller's MDX component overrides with those from the surrounding
|
|
4
|
+
* {@link MDXProvider} context (a function arg receives the parent set to merge). */
|
|
3
5
|
declare function useMDXComponents(components: any): any;
|
|
6
|
+
/** Provide MDX component overrides (e.g. a custom `a`/`h1`) to the rendered
|
|
7
|
+
* subtree; transformed `.mdx` modules pick them up. */
|
|
4
8
|
declare function MDXProvider(properties: any): react.FunctionComponentElement<react.ProviderProps<{}>>;
|
|
5
9
|
|
|
6
10
|
export { MDXProvider, useMDXComponents };
|
package/dist/MDXProvider.d.ts
CHANGED
|
@@ -1,6 +1,10 @@
|
|
|
1
1
|
import * as react from 'react';
|
|
2
2
|
|
|
3
|
+
/** Merge the caller's MDX component overrides with those from the surrounding
|
|
4
|
+
* {@link MDXProvider} context (a function arg receives the parent set to merge). */
|
|
3
5
|
declare function useMDXComponents(components: any): any;
|
|
6
|
+
/** Provide MDX component overrides (e.g. a custom `a`/`h1`) to the rendered
|
|
7
|
+
* subtree; transformed `.mdx` modules pick them up. */
|
|
4
8
|
declare function MDXProvider(properties: any): react.FunctionComponentElement<react.ProviderProps<{}>>;
|
|
5
9
|
|
|
6
10
|
export { MDXProvider, useMDXComponents };
|
package/dist/MDXProvider.js.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"sources":["../src/MDXProvider.ts"],"sourcesContent":["// Based on https://github.com/mdx-js/mdx/blob/main/packages/react/lib/index.js\n// since sandpack-bundler cannot import @mdx-js/react as it chokes on the\n// transitive dependency on VFile.\nimport {createContext, useContext, useMemo, createElement} from 'react'\nconst emptyComponents = {}\n\nconst MDXContext = createContext(emptyComponents);\n\nexport function useMDXComponents(components:any) {\n const contextComponents = useContext(MDXContext)\n\n // Memoize to avoid unnecessary top-level context changes\n return useMemo(\n function () {\n // Custom merge via a function prop\n if (typeof components === 'function') {\n return components(contextComponents)\n }\n\n return {...contextComponents, ...components}\n },\n [contextComponents, components]\n )\n}\n\nexport function MDXProvider(properties:any) {\n\n let allComponents: any\n\n if (properties.disableParentContext) {\n allComponents =\n typeof properties.components === 'function'\n ? properties.components(emptyComponents)\n : properties.components || emptyComponents\n } else {\n allComponents = useMDXComponents(properties.components)\n }\n\n return createElement(\n MDXContext.Provider,\n {value: allComponents},\n properties.children\n )\n}\n"],"mappings":"AAGA,SAAQ,eAAe,YAAY,SAAS,qBAAoB;AAChE,MAAM,kBAAkB,CAAC;AAEzB,MAAM,aAAa,cAAc,eAAe;
|
|
1
|
+
{"version":3,"sources":["../src/MDXProvider.ts"],"sourcesContent":["// Based on https://github.com/mdx-js/mdx/blob/main/packages/react/lib/index.js\n// since sandpack-bundler cannot import @mdx-js/react as it chokes on the\n// transitive dependency on VFile.\nimport {createContext, useContext, useMemo, createElement} from 'react'\nconst emptyComponents = {}\n\nconst MDXContext = createContext(emptyComponents);\n\n/** Merge the caller's MDX component overrides with those from the surrounding\n * {@link MDXProvider} context (a function arg receives the parent set to merge). */\nexport function useMDXComponents(components:any) {\n const contextComponents = useContext(MDXContext)\n\n // Memoize to avoid unnecessary top-level context changes\n return useMemo(\n function () {\n // Custom merge via a function prop\n if (typeof components === 'function') {\n return components(contextComponents)\n }\n\n return {...contextComponents, ...components}\n },\n [contextComponents, components]\n )\n}\n\n/** Provide MDX component overrides (e.g. a custom `a`/`h1`) to the rendered\n * subtree; transformed `.mdx` modules pick them up. */\nexport function MDXProvider(properties:any) {\n\n let allComponents: any\n\n if (properties.disableParentContext) {\n allComponents =\n typeof properties.components === 'function'\n ? properties.components(emptyComponents)\n : properties.components || emptyComponents\n } else {\n allComponents = useMDXComponents(properties.components)\n }\n\n return createElement(\n MDXContext.Provider,\n {value: allComponents},\n properties.children\n )\n}\n"],"mappings":"AAGA,SAAQ,eAAe,YAAY,SAAS,qBAAoB;AAChE,MAAM,kBAAkB,CAAC;AAEzB,MAAM,aAAa,cAAc,eAAe;AAIzC,SAAS,iBAAiB,YAAgB;AAC/C,QAAM,oBAAoB,WAAW,UAAU;AAG/C,SAAO;AAAA,IACL,WAAY;AAEV,UAAI,OAAO,eAAe,YAAY;AACpC,eAAO,WAAW,iBAAiB;AAAA,MACrC;AAEA,aAAO,EAAC,GAAG,mBAAmB,GAAG,WAAU;AAAA,IAC7C;AAAA,IACA,CAAC,mBAAmB,UAAU;AAAA,EAChC;AACF;AAIO,SAAS,YAAY,YAAgB;AAE1C,MAAI;AAEJ,MAAI,WAAW,sBAAsB;AACnC,oBACE,OAAO,WAAW,eAAe,aAC7B,WAAW,WAAW,eAAe,IACrC,WAAW,cAAc;AAAA,EACjC,OAAO;AACL,oBAAgB,iBAAiB,WAAW,UAAU;AAAA,EACxD;AAEA,SAAO;AAAA,IACL,WAAW;AAAA,IACX,EAAC,OAAO,cAAa;AAAA,IACrB,WAAW;AAAA,EACb;AACF;","names":[]}
|
package/dist/RoutingSpec.cjs.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"sources":["../src/RoutingSpec.ts"],"sourcesContent":["import type { ReactNode } from 'react';\n\nexport type RoutingRule = {\n name?: string;\n pattern: string | RegExp;\n
|
|
1
|
+
{"version":3,"sources":["../src/RoutingSpec.ts"],"sourcesContent":["import type { FC, ReactNode } from 'react';\n\n/** Named parameters extracted from a route match (`:name` segments, `*` rest). */\nexport type RouteParams = Record<string, string>;\n\n/** A route target that receives the matched params as a prop. */\nexport type RouteComponent = FC<{ params: RouteParams }>;\n\nexport type RoutingRule = {\n name?: string;\n /**\n * What to match against the app-owned `sandboxPath`. A string is a path\n * template (`/posts/:slug`, `/files/*`, or a literal like `/`) compiled to an\n * anchored regex; a `RegExp` is used as authored (the escape hatch — you own\n * anchoring).\n */\n pattern: string | RegExp;\n /** Element to render for this route. Reads params via `useRouteParams()`. */\n element?: ReactNode;\n /** Component to render for this route; receives the matched params as a prop. */\n component?: RouteComponent;\n /** @deprecated Use `element`. Accepted for backward compatibility. */\n reactNode?: ReactNode;\n};\n\nexport type RoutingSpec = {\n routes: RoutingRule[];\n}\n"],"mappings":";;;;;;;;;;;;;;AAAA;AAAA;","names":[]}
|
package/dist/RoutingSpec.d.cts
CHANGED
|
@@ -1,12 +1,29 @@
|
|
|
1
|
-
import { ReactNode } from 'react';
|
|
1
|
+
import { FC, ReactNode } from 'react';
|
|
2
2
|
|
|
3
|
+
/** Named parameters extracted from a route match (`:name` segments, `*` rest). */
|
|
4
|
+
type RouteParams = Record<string, string>;
|
|
5
|
+
/** A route target that receives the matched params as a prop. */
|
|
6
|
+
type RouteComponent = FC<{
|
|
7
|
+
params: RouteParams;
|
|
8
|
+
}>;
|
|
3
9
|
type RoutingRule = {
|
|
4
10
|
name?: string;
|
|
11
|
+
/**
|
|
12
|
+
* What to match against the app-owned `sandboxPath`. A string is a path
|
|
13
|
+
* template (`/posts/:slug`, `/files/*`, or a literal like `/`) compiled to an
|
|
14
|
+
* anchored regex; a `RegExp` is used as authored (the escape hatch — you own
|
|
15
|
+
* anchoring).
|
|
16
|
+
*/
|
|
5
17
|
pattern: string | RegExp;
|
|
6
|
-
|
|
18
|
+
/** Element to render for this route. Reads params via `useRouteParams()`. */
|
|
19
|
+
element?: ReactNode;
|
|
20
|
+
/** Component to render for this route; receives the matched params as a prop. */
|
|
21
|
+
component?: RouteComponent;
|
|
22
|
+
/** @deprecated Use `element`. Accepted for backward compatibility. */
|
|
23
|
+
reactNode?: ReactNode;
|
|
7
24
|
};
|
|
8
25
|
type RoutingSpec = {
|
|
9
26
|
routes: RoutingRule[];
|
|
10
27
|
};
|
|
11
28
|
|
|
12
|
-
export type { RoutingRule, RoutingSpec };
|
|
29
|
+
export type { RouteComponent, RouteParams, RoutingRule, RoutingSpec };
|
package/dist/RoutingSpec.d.ts
CHANGED
|
@@ -1,12 +1,29 @@
|
|
|
1
|
-
import { ReactNode } from 'react';
|
|
1
|
+
import { FC, ReactNode } from 'react';
|
|
2
2
|
|
|
3
|
+
/** Named parameters extracted from a route match (`:name` segments, `*` rest). */
|
|
4
|
+
type RouteParams = Record<string, string>;
|
|
5
|
+
/** A route target that receives the matched params as a prop. */
|
|
6
|
+
type RouteComponent = FC<{
|
|
7
|
+
params: RouteParams;
|
|
8
|
+
}>;
|
|
3
9
|
type RoutingRule = {
|
|
4
10
|
name?: string;
|
|
11
|
+
/**
|
|
12
|
+
* What to match against the app-owned `sandboxPath`. A string is a path
|
|
13
|
+
* template (`/posts/:slug`, `/files/*`, or a literal like `/`) compiled to an
|
|
14
|
+
* anchored regex; a `RegExp` is used as authored (the escape hatch — you own
|
|
15
|
+
* anchoring).
|
|
16
|
+
*/
|
|
5
17
|
pattern: string | RegExp;
|
|
6
|
-
|
|
18
|
+
/** Element to render for this route. Reads params via `useRouteParams()`. */
|
|
19
|
+
element?: ReactNode;
|
|
20
|
+
/** Component to render for this route; receives the matched params as a prop. */
|
|
21
|
+
component?: RouteComponent;
|
|
22
|
+
/** @deprecated Use `element`. Accepted for backward compatibility. */
|
|
23
|
+
reactNode?: ReactNode;
|
|
7
24
|
};
|
|
8
25
|
type RoutingSpec = {
|
|
9
26
|
routes: RoutingRule[];
|
|
10
27
|
};
|
|
11
28
|
|
|
12
|
-
export type { RoutingRule, RoutingSpec };
|
|
29
|
+
export type { RouteComponent, RouteParams, RoutingRule, RoutingSpec };
|
package/dist/auth.cjs.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"sources":["../src/auth.ts"],"sourcesContent":["import { createPushChannel } from './pushChannel';\n\n/**\n * Login / account state of the immediately.run user, mirrored from the host\n * window into the sandbox.\n *\n * `status` is `'unknown'` until the host has reported a value (use it to\n * distinguish \"still loading\" from a confirmed signed-out session).\n */\nexport type AuthStatus = 'unknown' | 'signed-in' | 'signed-out';\n\nexport interface SandboxUser {\n /** GitHub login (handle) of the signed-in user. */\n login: string;\n}\n\nexport interface AuthState {\n status: AuthStatus;\n user: SandboxUser | null;\n}\n\nconst isAuthState = (v: unknown): v is AuthState => {\n const s = v as Partial<AuthState> | null;\n return (\n !!s &&\n (s.status === 'unknown' || s.status === 'signed-in' || s.status === 'signed-out') &&\n (s.user === null || (typeof s.user === 'object' && typeof (s.user as SandboxUser).login === 'string'))\n );\n};\n\n// Read over the transport (SDK_PACKAGING_SPEC §4): the host pushes `auth-state`\n// and answers `request-auth-state` (wire format: site-main channelBridge.ts).\nconst channel = createPushChannel<AuthState>({\n pushType: 'auth-state',\n requestType: 'request-auth-state',\n initial: { status: 'unknown', user: null },\n parse: (msg) => (isAuthState(msg.state) ? (msg.state as AuthState) : undefined),\n});\n\n/**\n * Returns the current login / account state. Poll this whenever you need a\n * one-off read; use {@link onAuthChange} or {@link useAuth} to react to changes.\n */\nexport const getAuthState = (): AuthState => channel.get();\n\n/**\n * Subscribe to login / logout changes. The listener is invoked immediately with\n * the current state, then again on every change. Returns an unsubscribe fn.\n */\nexport const onAuthChange = (listener: (state: AuthState) => void): (() => void) =>\n channel.onChange(listener);\n\n/**\n * React hook returning the current login / account state, re-rendering on\n * login / logout.\n */\nexport const useAuth = (): AuthState => channel.use();\n"],"mappings":";;;;;;;;;;;;;;;;;;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA,yBAAkC;
|
|
1
|
+
{"version":3,"sources":["../src/auth.ts"],"sourcesContent":["import { createPushChannel } from './pushChannel';\n\n/**\n * Login / account state of the immediately.run user, mirrored from the host\n * window into the sandbox.\n *\n * `status` is `'unknown'` until the host has reported a value (use it to\n * distinguish \"still loading\" from a confirmed signed-out session).\n */\nexport type AuthStatus = 'unknown' | 'signed-in' | 'signed-out';\n\n/** The signed-in immediately.run user, as seen by the sandbox (no token, ever). */\nexport interface SandboxUser {\n /** GitHub login (handle) of the signed-in user. */\n login: string;\n}\n\n/** The user's login / account state: a `status` plus the `user` when signed in. */\nexport interface AuthState {\n status: AuthStatus;\n user: SandboxUser | null;\n}\n\nconst isAuthState = (v: unknown): v is AuthState => {\n const s = v as Partial<AuthState> | null;\n return (\n !!s &&\n (s.status === 'unknown' || s.status === 'signed-in' || s.status === 'signed-out') &&\n (s.user === null || (typeof s.user === 'object' && typeof (s.user as SandboxUser).login === 'string'))\n );\n};\n\n// Read over the transport (SDK_PACKAGING_SPEC §4): the host pushes `auth-state`\n// and answers `request-auth-state` (wire format: site-main channelBridge.ts).\nconst channel = createPushChannel<AuthState>({\n pushType: 'auth-state',\n requestType: 'request-auth-state',\n initial: { status: 'unknown', user: null },\n parse: (msg) => (isAuthState(msg.state) ? (msg.state as AuthState) : undefined),\n});\n\n/**\n * Returns the current login / account state. Poll this whenever you need a\n * one-off read; use {@link onAuthChange} or {@link useAuth} to react to changes.\n */\nexport const getAuthState = (): AuthState => channel.get();\n\n/**\n * Subscribe to login / logout changes. The listener is invoked immediately with\n * the current state, then again on every change. Returns an unsubscribe fn.\n */\nexport const onAuthChange = (listener: (state: AuthState) => void): (() => void) =>\n channel.onChange(listener);\n\n/**\n * React hook returning the current login / account state, re-rendering on\n * login / logout.\n */\nexport const useAuth = (): AuthState => channel.use();\n"],"mappings":";;;;;;;;;;;;;;;;;;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA,yBAAkC;AAuBlC,MAAM,cAAc,CAAC,MAA+B;AAClD,QAAM,IAAI;AACV,SACE,CAAC,CAAC,MACD,EAAE,WAAW,aAAa,EAAE,WAAW,eAAe,EAAE,WAAW,kBACnE,EAAE,SAAS,QAAS,OAAO,EAAE,SAAS,YAAY,OAAQ,EAAE,KAAqB,UAAU;AAEhG;AAIA,MAAM,cAAU,sCAA6B;AAAA,EAC3C,UAAU;AAAA,EACV,aAAa;AAAA,EACb,SAAS,EAAE,QAAQ,WAAW,MAAM,KAAK;AAAA,EACzC,OAAO,CAAC,QAAS,YAAY,IAAI,KAAK,IAAK,IAAI,QAAsB;AACvE,CAAC;AAMM,MAAM,eAAe,MAAiB,QAAQ,IAAI;AAMlD,MAAM,eAAe,CAAC,aAC3B,QAAQ,SAAS,QAAQ;AAMpB,MAAM,UAAU,MAAiB,QAAQ,IAAI;","names":[]}
|
package/dist/auth.d.cts
CHANGED
|
@@ -6,10 +6,12 @@
|
|
|
6
6
|
* distinguish "still loading" from a confirmed signed-out session).
|
|
7
7
|
*/
|
|
8
8
|
type AuthStatus = 'unknown' | 'signed-in' | 'signed-out';
|
|
9
|
+
/** The signed-in immediately.run user, as seen by the sandbox (no token, ever). */
|
|
9
10
|
interface SandboxUser {
|
|
10
11
|
/** GitHub login (handle) of the signed-in user. */
|
|
11
12
|
login: string;
|
|
12
13
|
}
|
|
14
|
+
/** The user's login / account state: a `status` plus the `user` when signed in. */
|
|
13
15
|
interface AuthState {
|
|
14
16
|
status: AuthStatus;
|
|
15
17
|
user: SandboxUser | null;
|
package/dist/auth.d.ts
CHANGED
|
@@ -6,10 +6,12 @@
|
|
|
6
6
|
* distinguish "still loading" from a confirmed signed-out session).
|
|
7
7
|
*/
|
|
8
8
|
type AuthStatus = 'unknown' | 'signed-in' | 'signed-out';
|
|
9
|
+
/** The signed-in immediately.run user, as seen by the sandbox (no token, ever). */
|
|
9
10
|
interface SandboxUser {
|
|
10
11
|
/** GitHub login (handle) of the signed-in user. */
|
|
11
12
|
login: string;
|
|
12
13
|
}
|
|
14
|
+
/** The user's login / account state: a `status` plus the `user` when signed in. */
|
|
13
15
|
interface AuthState {
|
|
14
16
|
status: AuthStatus;
|
|
15
17
|
user: SandboxUser | null;
|
package/dist/auth.js.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"sources":["../src/auth.ts"],"sourcesContent":["import { createPushChannel } from './pushChannel';\n\n/**\n * Login / account state of the immediately.run user, mirrored from the host\n * window into the sandbox.\n *\n * `status` is `'unknown'` until the host has reported a value (use it to\n * distinguish \"still loading\" from a confirmed signed-out session).\n */\nexport type AuthStatus = 'unknown' | 'signed-in' | 'signed-out';\n\nexport interface SandboxUser {\n /** GitHub login (handle) of the signed-in user. */\n login: string;\n}\n\nexport interface AuthState {\n status: AuthStatus;\n user: SandboxUser | null;\n}\n\nconst isAuthState = (v: unknown): v is AuthState => {\n const s = v as Partial<AuthState> | null;\n return (\n !!s &&\n (s.status === 'unknown' || s.status === 'signed-in' || s.status === 'signed-out') &&\n (s.user === null || (typeof s.user === 'object' && typeof (s.user as SandboxUser).login === 'string'))\n );\n};\n\n// Read over the transport (SDK_PACKAGING_SPEC §4): the host pushes `auth-state`\n// and answers `request-auth-state` (wire format: site-main channelBridge.ts).\nconst channel = createPushChannel<AuthState>({\n pushType: 'auth-state',\n requestType: 'request-auth-state',\n initial: { status: 'unknown', user: null },\n parse: (msg) => (isAuthState(msg.state) ? (msg.state as AuthState) : undefined),\n});\n\n/**\n * Returns the current login / account state. Poll this whenever you need a\n * one-off read; use {@link onAuthChange} or {@link useAuth} to react to changes.\n */\nexport const getAuthState = (): AuthState => channel.get();\n\n/**\n * Subscribe to login / logout changes. The listener is invoked immediately with\n * the current state, then again on every change. Returns an unsubscribe fn.\n */\nexport const onAuthChange = (listener: (state: AuthState) => void): (() => void) =>\n channel.onChange(listener);\n\n/**\n * React hook returning the current login / account state, re-rendering on\n * login / logout.\n */\nexport const useAuth = (): AuthState => channel.use();\n"],"mappings":"AAAA,SAAS,yBAAyB;
|
|
1
|
+
{"version":3,"sources":["../src/auth.ts"],"sourcesContent":["import { createPushChannel } from './pushChannel';\n\n/**\n * Login / account state of the immediately.run user, mirrored from the host\n * window into the sandbox.\n *\n * `status` is `'unknown'` until the host has reported a value (use it to\n * distinguish \"still loading\" from a confirmed signed-out session).\n */\nexport type AuthStatus = 'unknown' | 'signed-in' | 'signed-out';\n\n/** The signed-in immediately.run user, as seen by the sandbox (no token, ever). */\nexport interface SandboxUser {\n /** GitHub login (handle) of the signed-in user. */\n login: string;\n}\n\n/** The user's login / account state: a `status` plus the `user` when signed in. */\nexport interface AuthState {\n status: AuthStatus;\n user: SandboxUser | null;\n}\n\nconst isAuthState = (v: unknown): v is AuthState => {\n const s = v as Partial<AuthState> | null;\n return (\n !!s &&\n (s.status === 'unknown' || s.status === 'signed-in' || s.status === 'signed-out') &&\n (s.user === null || (typeof s.user === 'object' && typeof (s.user as SandboxUser).login === 'string'))\n );\n};\n\n// Read over the transport (SDK_PACKAGING_SPEC §4): the host pushes `auth-state`\n// and answers `request-auth-state` (wire format: site-main channelBridge.ts).\nconst channel = createPushChannel<AuthState>({\n pushType: 'auth-state',\n requestType: 'request-auth-state',\n initial: { status: 'unknown', user: null },\n parse: (msg) => (isAuthState(msg.state) ? (msg.state as AuthState) : undefined),\n});\n\n/**\n * Returns the current login / account state. Poll this whenever you need a\n * one-off read; use {@link onAuthChange} or {@link useAuth} to react to changes.\n */\nexport const getAuthState = (): AuthState => channel.get();\n\n/**\n * Subscribe to login / logout changes. The listener is invoked immediately with\n * the current state, then again on every change. Returns an unsubscribe fn.\n */\nexport const onAuthChange = (listener: (state: AuthState) => void): (() => void) =>\n channel.onChange(listener);\n\n/**\n * React hook returning the current login / account state, re-rendering on\n * login / logout.\n */\nexport const useAuth = (): AuthState => channel.use();\n"],"mappings":"AAAA,SAAS,yBAAyB;AAuBlC,MAAM,cAAc,CAAC,MAA+B;AAClD,QAAM,IAAI;AACV,SACE,CAAC,CAAC,MACD,EAAE,WAAW,aAAa,EAAE,WAAW,eAAe,EAAE,WAAW,kBACnE,EAAE,SAAS,QAAS,OAAO,EAAE,SAAS,YAAY,OAAQ,EAAE,KAAqB,UAAU;AAEhG;AAIA,MAAM,UAAU,kBAA6B;AAAA,EAC3C,UAAU;AAAA,EACV,aAAa;AAAA,EACb,SAAS,EAAE,QAAQ,WAAW,MAAM,KAAK;AAAA,EACzC,OAAO,CAAC,QAAS,YAAY,IAAI,KAAK,IAAK,IAAI,QAAsB;AACvE,CAAC;AAMM,MAAM,eAAe,MAAiB,QAAQ,IAAI;AAMlD,MAAM,eAAe,CAAC,aAC3B,QAAQ,SAAS,QAAQ;AAMpB,MAAM,UAAU,MAAiB,QAAQ,IAAI;","names":[]}
|
package/dist/boot.cjs
CHANGED
|
@@ -18,6 +18,7 @@ var __copyProps = (to, from, except, desc) => {
|
|
|
18
18
|
var __toCommonJS = (mod) => __copyProps(__defProp({}, "__esModule", { value: true }), mod);
|
|
19
19
|
var boot_exports = {};
|
|
20
20
|
__export(boot_exports, {
|
|
21
|
+
CATCH_ALL_ROUTING_SPEC: () => CATCH_ALL_ROUTING_SPEC,
|
|
21
22
|
DEFAULT_ROUTING_SPEC: () => DEFAULT_ROUTING_SPEC,
|
|
22
23
|
TinkerableApp: () => TinkerableApp,
|
|
23
24
|
boot: () => boot
|
|
@@ -47,7 +48,10 @@ const updateAlreadyApplied = (filesMetadata, update) => {
|
|
|
47
48
|
}
|
|
48
49
|
return true;
|
|
49
50
|
};
|
|
50
|
-
const TinkerableApp = ({
|
|
51
|
+
const TinkerableApp = ({
|
|
52
|
+
routingSpec,
|
|
53
|
+
children
|
|
54
|
+
}) => {
|
|
51
55
|
const [context, setContext] = (0, import_react.useState)((0, import_contextUtils.getInitialContext)(routingSpec));
|
|
52
56
|
(0, import_react.useEffect)(() => {
|
|
53
57
|
const removeListener = (0, import_sandboxUtils.addListener)("urlchange", ({ url }) => {
|
|
@@ -84,7 +88,7 @@ const TinkerableApp = ({ routingSpec }) => {
|
|
|
84
88
|
source.enable();
|
|
85
89
|
return dispose;
|
|
86
90
|
}, [setContext]);
|
|
87
|
-
return /* @__PURE__ */ (0, import_jsx_runtime.jsx)(import_TinkerableContext.TinkerableContext, { value: context, children: /* @__PURE__ */ (0, import_jsx_runtime.jsx)(import_routing.Router, {}) });
|
|
91
|
+
return /* @__PURE__ */ (0, import_jsx_runtime.jsx)(import_TinkerableContext.TinkerableContext, { value: context, children: children ?? /* @__PURE__ */ (0, import_jsx_runtime.jsx)(import_routing.Router, {}) });
|
|
88
92
|
};
|
|
89
93
|
const BootMarkers = () => {
|
|
90
94
|
(0, import_react.useLayoutEffect)(() => {
|
|
@@ -96,34 +100,40 @@ const BootMarkers = () => {
|
|
|
96
100
|
const escapeForRegexp = (str) => str.replace(/[.*+\-?^${}()|[\]\\]/g, "\\$&");
|
|
97
101
|
const DEFAULT_ROUTING_SPEC = {
|
|
98
102
|
routes: [
|
|
99
|
-
{ name: "MainContent", pattern: /^\/$/,
|
|
103
|
+
{ name: "MainContent", pattern: /^\/$/, element: /* @__PURE__ */ (0, import_jsx_runtime.jsx)(import_MainContent.MainContent, {}) },
|
|
100
104
|
{
|
|
101
105
|
name: "FileRouter",
|
|
102
106
|
pattern: new RegExp(`^${escapeForRegexp(import_urlUtils.FILES_PREFIX)}(?<filename>/.+)$`),
|
|
103
|
-
|
|
107
|
+
element: /* @__PURE__ */ (0, import_jsx_runtime.jsx)(import_FileRouter.FileRouter, {})
|
|
104
108
|
},
|
|
105
|
-
{ name: "ErrorNotFound", pattern: /^(?<path>.+)$/,
|
|
109
|
+
{ name: "ErrorNotFound", pattern: /^(?<path>.+)$/, element: /* @__PURE__ */ (0, import_jsx_runtime.jsx)(import_errors.ErrorNotFound, {}) }
|
|
106
110
|
]
|
|
107
111
|
};
|
|
112
|
+
const CATCH_ALL_ROUTING_SPEC = {
|
|
113
|
+
routes: [{ name: "AppRoot", pattern: /^.*$/, element: null }]
|
|
114
|
+
};
|
|
108
115
|
const boot = ({
|
|
109
116
|
mdxComponents = import_MDXComponents.DEFAULT_MDX_COMPONENTS,
|
|
110
|
-
routingSpec
|
|
117
|
+
routingSpec,
|
|
118
|
+
children
|
|
111
119
|
} = {}) => {
|
|
112
120
|
const rootElement = document.getElementById("root");
|
|
113
121
|
if (!rootElement) {
|
|
114
122
|
throw new Error("boot requires root HTML element to exist");
|
|
115
123
|
}
|
|
124
|
+
const spec = routingSpec ?? (children ? CATCH_ALL_ROUTING_SPEC : DEFAULT_ROUTING_SPEC);
|
|
116
125
|
const moduleCache = new import_moduleCache.ModuleCache();
|
|
117
126
|
const root = (0, import_client.createRoot)(rootElement);
|
|
118
127
|
root.render(
|
|
119
128
|
/* @__PURE__ */ (0, import_jsx_runtime.jsx)(import_react.StrictMode, { children: /* @__PURE__ */ (0, import_jsx_runtime.jsx)(import_moduleCache.ModuleCacheContextProvider, { moduleCache, children: /* @__PURE__ */ (0, import_jsx_runtime.jsxs)(import_MDXProvider.MDXProvider, { components: mdxComponents, children: [
|
|
120
129
|
/* @__PURE__ */ (0, import_jsx_runtime.jsx)(BootMarkers, {}),
|
|
121
|
-
/* @__PURE__ */ (0, import_jsx_runtime.jsx)(TinkerableApp, { routingSpec })
|
|
130
|
+
/* @__PURE__ */ (0, import_jsx_runtime.jsx)(TinkerableApp, { routingSpec: spec, children })
|
|
122
131
|
] }) }) })
|
|
123
132
|
);
|
|
124
133
|
};
|
|
125
134
|
// Annotate the CommonJS export names for ESM import in node:
|
|
126
135
|
0 && (module.exports = {
|
|
136
|
+
CATCH_ALL_ROUTING_SPEC,
|
|
127
137
|
DEFAULT_ROUTING_SPEC,
|
|
128
138
|
TinkerableApp,
|
|
129
139
|
boot
|
package/dist/boot.cjs.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"sources":["../src/boot.tsx"],"sourcesContent":["import { FC, StrictMode, useEffect, useLayoutEffect, useState } from 'react';\nimport { createRoot } from 'react-dom/client';\n\nimport { emitMarkerOnce } from './markers';\n\nimport { ErrorNotFound } from './components/errors';\nimport { FileRouter } from './components/FileRouter';\nimport { MainContent } from './components/MainContent';\nimport { DEFAULT_MDX_COMPONENTS } from './components/MDXComponents';\nimport { getInitialContext, updateContext } from './contextUtils';\nimport { getInjectedMetadataEmitter, resolveMetadataSource } from './injectedBundler';\nimport { MDXProvider } from './MDXProvider';\nimport { ModuleCache, ModuleCacheContextProvider } from './moduleCache';\nimport { Router } from './routing';\nimport type { RoutingSpec } from './RoutingSpec';\nimport { FilesMetadata } from './sandboxTypes';\nimport { addListener } from './sandboxUtils';\nimport { TinkerableContext, TinkerableState } from './TinkerableContext';\nimport { FILES_PREFIX } from './urlUtils';\n\nexport type BootProps = {\n mdxComponents?: Record<string, FC>;\n routingSpec?: RoutingSpec;\n};\n\nconst updateAlreadyApplied = (filesMetadata: FilesMetadata, update: FilesMetadata) => {\n for (let [key, value] of Object.entries(update)) {\n if (filesMetadata[key] !== value) {\n return false;\n }\n }\n return true;\n};\n\nexport const TinkerableApp = ({
|
|
1
|
+
{"version":3,"sources":["../src/boot.tsx"],"sourcesContent":["import { FC, ReactNode, StrictMode, useEffect, useLayoutEffect, useState } from 'react';\nimport { createRoot } from 'react-dom/client';\n\nimport { emitMarkerOnce } from './markers';\n\nimport { ErrorNotFound } from './components/errors';\nimport { FileRouter } from './components/FileRouter';\nimport { MainContent } from './components/MainContent';\nimport { DEFAULT_MDX_COMPONENTS } from './components/MDXComponents';\nimport { getInitialContext, updateContext } from './contextUtils';\nimport { getInjectedMetadataEmitter, resolveMetadataSource } from './injectedBundler';\nimport { MDXProvider } from './MDXProvider';\nimport { ModuleCache, ModuleCacheContextProvider } from './moduleCache';\nimport { Router } from './routing';\nimport type { RoutingSpec } from './RoutingSpec';\nimport { FilesMetadata } from './sandboxTypes';\nimport { addListener } from './sandboxUtils';\nimport { TinkerableContext, TinkerableState } from './TinkerableContext';\nimport { FILES_PREFIX } from './urlUtils';\n\n/** Options for {@link boot}: MDX overrides, a route table, or an app root. */\nexport type BootProps = {\n mdxComponents?: Record<string, FC>;\n routingSpec?: RoutingSpec;\n /**\n * App root rendered directly inside the providers (with full navigation\n * context), instead of dispatching through a `routingSpec`. Render\n * `<Routes>`/`<Route>` here for fully dynamic routing — no catch-all rule\n * boilerplate. Takes precedence over `routingSpec` for what is rendered.\n */\n children?: ReactNode;\n};\n\nconst updateAlreadyApplied = (filesMetadata: FilesMetadata, update: FilesMetadata) => {\n for (let [key, value] of Object.entries(update)) {\n if (filesMetadata[key] !== value) {\n return false;\n }\n }\n return true;\n};\n\n/** The app shell {@link boot} renders: holds navigation state, subscribes to host\n * URL + metadata pushes, and renders `children` or the route `<Router />`. */\nexport const TinkerableApp = ({\n routingSpec,\n children,\n}: {\n routingSpec: RoutingSpec;\n children?: ReactNode;\n}) => {\n const [context, setContext] = useState<TinkerableState>(getInitialContext(routingSpec));\n useEffect(() => {\n const removeListener = addListener('urlchange', ({ url }) => {\n setContext((context) => {\n const updatedContext = updateContext(context, url);\n if (updatedContext !== context) {\n console.log(\n `[Sandbox] Updating path from ${context.navigationState.sandboxPath} to ${updatedContext.navigationState.sandboxPath}`\n );\n }\n return updatedContext;\n });\n });\n return removeListener;\n }, [setContext]);\n useEffect(() => {\n // Phase 5 dual-mode (SDK_PACKAGING_SPEC §4/§8): prefer the injected bundler's\n // metadata emitter (the live path, byte-identical); when the SDK is npm-fetched\n // with no injection, `event` is undefined so `addListener` receives\n // 'metadata-update' over the §4 transport instead, and `enable` is a no-op.\n const source = resolveMetadataSource(getInjectedMetadataEmitter());\n const dispose = addListener(\n 'metadata-update',\n ({ update }: Record<string, any>) => {\n setContext((prevContext) =>\n updateAlreadyApplied(prevContext.filesMetadata, update)\n ? prevContext\n : {\n ...prevContext,\n filesMetadata: {\n // TODO: file deletion!\n ...prevContext.filesMetadata,\n ...update,\n },\n }\n );\n },\n source.event\n );\n source.enable();\n return dispose;\n }, [setContext]);\n\n return (\n <TinkerableContext value={context}>\n {children ?? <Router />}\n </TinkerableContext>\n );\n};\n\n// Boot marker emitter (LOAD_PROFILING_SPEC §3, R3-46). Rendered at the top of the\n// app tree so its layout effect fires on the FIRST root-render commit: that instant\n// is `ir.fmp` (the content is in the DOM, about to paint) and the baseline for\n// `ir.interactive` (the host treats a forwarded `ir.interactive` as the root-commit\n// signal and resolves `max(commit, reportReady)` — LP2-3 — so this can only ever be\n// delayed by an app's `reportReady()`, never advanced). Emitted in canonical stream\n// order (fmp then interactive); idempotent per name (StrictMode-safe). Renders null.\nconst BootMarkers = (): null => {\n useLayoutEffect(() => {\n emitMarkerOnce('ir.fmp');\n emitMarkerOnce('ir.interactive');\n }, []);\n return null;\n};\n\n// from: https://stackoverflow.com/a/63838890\nconst escapeForRegexp = (str: string) => str.replace(/[.*+\\-?^${}()|[\\]\\\\]/g, '\\\\$&');\n\n/** The default route table when `boot` is called with no `routingSpec`/`children`:\n * `/` → main content, `/files/<path>` → the file router, else not-found. */\nexport const DEFAULT_ROUTING_SPEC: RoutingSpec = {\n routes: [\n { name: 'MainContent', pattern: /^\\/$/, element: <MainContent /> },\n {\n name: 'FileRouter',\n pattern: new RegExp(`^${escapeForRegexp(FILES_PREFIX)}(?<filename>\\/.+)$`),\n element: <FileRouter />,\n },\n { name: 'ErrorNotFound', pattern: /^(?<path>.+)$/, element: <ErrorNotFound /> },\n ],\n};\n\n/**\n * Matches any `sandboxPath` so navigation context can be built without a route\n * table. Used when {@link boot} is given `children` (the app owns dispatch via\n * `<Routes>`); the catch-all's `element` is never rendered (children are).\n */\nexport const CATCH_ALL_ROUTING_SPEC: RoutingSpec = {\n routes: [{ name: 'AppRoot', pattern: /^.*$/, element: null }],\n};\n\n/**\n * Mount an immediately.run app into the sandbox `#root`. The entry point every\n * app calls from `index.tsx`: wires the MDX, module-cache, and navigation\n * providers, then renders the route table (`routingSpec`) or your `children`.\n */\nexport const boot = ({\n mdxComponents = DEFAULT_MDX_COMPONENTS,\n routingSpec,\n children,\n}: BootProps = {}) => {\n const rootElement = document.getElementById('root');\n if (!rootElement) {\n throw new Error('boot requires root HTML element to exist');\n }\n // `children` own dispatch, so a catch-all keeps navigation working without a\n // table; otherwise fall back to the default file/main-content routes.\n const spec = routingSpec ?? (children ? CATCH_ALL_ROUTING_SPEC : DEFAULT_ROUTING_SPEC);\n const moduleCache = new ModuleCache();\n const root = createRoot(rootElement);\n root.render(\n <StrictMode>\n <ModuleCacheContextProvider moduleCache={moduleCache}>\n <MDXProvider components={mdxComponents}>\n <BootMarkers />\n <TinkerableApp routingSpec={spec}>{children}</TinkerableApp>\n </MDXProvider>\n </ModuleCacheContextProvider>\n </StrictMode>\n );\n};\n"],"mappings":"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","names":["context"]}
|
package/dist/boot.d.cts
CHANGED
|
@@ -1,15 +1,39 @@
|
|
|
1
1
|
import * as react_jsx_runtime from 'react/jsx-runtime';
|
|
2
|
-
import { FC } from 'react';
|
|
2
|
+
import { FC, ReactNode } from 'react';
|
|
3
3
|
import { RoutingSpec } from './RoutingSpec.cjs';
|
|
4
4
|
|
|
5
|
+
/** Options for {@link boot}: MDX overrides, a route table, or an app root. */
|
|
5
6
|
type BootProps = {
|
|
6
7
|
mdxComponents?: Record<string, FC>;
|
|
7
8
|
routingSpec?: RoutingSpec;
|
|
9
|
+
/**
|
|
10
|
+
* App root rendered directly inside the providers (with full navigation
|
|
11
|
+
* context), instead of dispatching through a `routingSpec`. Render
|
|
12
|
+
* `<Routes>`/`<Route>` here for fully dynamic routing — no catch-all rule
|
|
13
|
+
* boilerplate. Takes precedence over `routingSpec` for what is rendered.
|
|
14
|
+
*/
|
|
15
|
+
children?: ReactNode;
|
|
8
16
|
};
|
|
9
|
-
|
|
17
|
+
/** The app shell {@link boot} renders: holds navigation state, subscribes to host
|
|
18
|
+
* URL + metadata pushes, and renders `children` or the route `<Router />`. */
|
|
19
|
+
declare const TinkerableApp: ({ routingSpec, children, }: {
|
|
10
20
|
routingSpec: RoutingSpec;
|
|
21
|
+
children?: ReactNode;
|
|
11
22
|
}) => react_jsx_runtime.JSX.Element;
|
|
23
|
+
/** The default route table when `boot` is called with no `routingSpec`/`children`:
|
|
24
|
+
* `/` → main content, `/files/<path>` → the file router, else not-found. */
|
|
12
25
|
declare const DEFAULT_ROUTING_SPEC: RoutingSpec;
|
|
13
|
-
|
|
26
|
+
/**
|
|
27
|
+
* Matches any `sandboxPath` so navigation context can be built without a route
|
|
28
|
+
* table. Used when {@link boot} is given `children` (the app owns dispatch via
|
|
29
|
+
* `<Routes>`); the catch-all's `element` is never rendered (children are).
|
|
30
|
+
*/
|
|
31
|
+
declare const CATCH_ALL_ROUTING_SPEC: RoutingSpec;
|
|
32
|
+
/**
|
|
33
|
+
* Mount an immediately.run app into the sandbox `#root`. The entry point every
|
|
34
|
+
* app calls from `index.tsx`: wires the MDX, module-cache, and navigation
|
|
35
|
+
* providers, then renders the route table (`routingSpec`) or your `children`.
|
|
36
|
+
*/
|
|
37
|
+
declare const boot: ({ mdxComponents, routingSpec, children, }?: BootProps) => void;
|
|
14
38
|
|
|
15
|
-
export { type BootProps, DEFAULT_ROUTING_SPEC, TinkerableApp, boot };
|
|
39
|
+
export { type BootProps, CATCH_ALL_ROUTING_SPEC, DEFAULT_ROUTING_SPEC, TinkerableApp, boot };
|
package/dist/boot.d.ts
CHANGED
|
@@ -1,15 +1,39 @@
|
|
|
1
1
|
import * as react_jsx_runtime from 'react/jsx-runtime';
|
|
2
|
-
import { FC } from 'react';
|
|
2
|
+
import { FC, ReactNode } from 'react';
|
|
3
3
|
import { RoutingSpec } from './RoutingSpec.js';
|
|
4
4
|
|
|
5
|
+
/** Options for {@link boot}: MDX overrides, a route table, or an app root. */
|
|
5
6
|
type BootProps = {
|
|
6
7
|
mdxComponents?: Record<string, FC>;
|
|
7
8
|
routingSpec?: RoutingSpec;
|
|
9
|
+
/**
|
|
10
|
+
* App root rendered directly inside the providers (with full navigation
|
|
11
|
+
* context), instead of dispatching through a `routingSpec`. Render
|
|
12
|
+
* `<Routes>`/`<Route>` here for fully dynamic routing — no catch-all rule
|
|
13
|
+
* boilerplate. Takes precedence over `routingSpec` for what is rendered.
|
|
14
|
+
*/
|
|
15
|
+
children?: ReactNode;
|
|
8
16
|
};
|
|
9
|
-
|
|
17
|
+
/** The app shell {@link boot} renders: holds navigation state, subscribes to host
|
|
18
|
+
* URL + metadata pushes, and renders `children` or the route `<Router />`. */
|
|
19
|
+
declare const TinkerableApp: ({ routingSpec, children, }: {
|
|
10
20
|
routingSpec: RoutingSpec;
|
|
21
|
+
children?: ReactNode;
|
|
11
22
|
}) => react_jsx_runtime.JSX.Element;
|
|
23
|
+
/** The default route table when `boot` is called with no `routingSpec`/`children`:
|
|
24
|
+
* `/` → main content, `/files/<path>` → the file router, else not-found. */
|
|
12
25
|
declare const DEFAULT_ROUTING_SPEC: RoutingSpec;
|
|
13
|
-
|
|
26
|
+
/**
|
|
27
|
+
* Matches any `sandboxPath` so navigation context can be built without a route
|
|
28
|
+
* table. Used when {@link boot} is given `children` (the app owns dispatch via
|
|
29
|
+
* `<Routes>`); the catch-all's `element` is never rendered (children are).
|
|
30
|
+
*/
|
|
31
|
+
declare const CATCH_ALL_ROUTING_SPEC: RoutingSpec;
|
|
32
|
+
/**
|
|
33
|
+
* Mount an immediately.run app into the sandbox `#root`. The entry point every
|
|
34
|
+
* app calls from `index.tsx`: wires the MDX, module-cache, and navigation
|
|
35
|
+
* providers, then renders the route table (`routingSpec`) or your `children`.
|
|
36
|
+
*/
|
|
37
|
+
declare const boot: ({ mdxComponents, routingSpec, children, }?: BootProps) => void;
|
|
14
38
|
|
|
15
|
-
export { type BootProps, DEFAULT_ROUTING_SPEC, TinkerableApp, boot };
|
|
39
|
+
export { type BootProps, CATCH_ALL_ROUTING_SPEC, DEFAULT_ROUTING_SPEC, TinkerableApp, boot };
|
package/dist/boot.js
CHANGED
|
@@ -22,7 +22,10 @@ const updateAlreadyApplied = (filesMetadata, update) => {
|
|
|
22
22
|
}
|
|
23
23
|
return true;
|
|
24
24
|
};
|
|
25
|
-
const TinkerableApp = ({
|
|
25
|
+
const TinkerableApp = ({
|
|
26
|
+
routingSpec,
|
|
27
|
+
children
|
|
28
|
+
}) => {
|
|
26
29
|
const [context, setContext] = useState(getInitialContext(routingSpec));
|
|
27
30
|
useEffect(() => {
|
|
28
31
|
const removeListener = addListener("urlchange", ({ url }) => {
|
|
@@ -59,7 +62,7 @@ const TinkerableApp = ({ routingSpec }) => {
|
|
|
59
62
|
source.enable();
|
|
60
63
|
return dispose;
|
|
61
64
|
}, [setContext]);
|
|
62
|
-
return /* @__PURE__ */ jsx(TinkerableContext, { value: context, children: /* @__PURE__ */ jsx(Router, {}) });
|
|
65
|
+
return /* @__PURE__ */ jsx(TinkerableContext, { value: context, children: children ?? /* @__PURE__ */ jsx(Router, {}) });
|
|
63
66
|
};
|
|
64
67
|
const BootMarkers = () => {
|
|
65
68
|
useLayoutEffect(() => {
|
|
@@ -71,33 +74,39 @@ const BootMarkers = () => {
|
|
|
71
74
|
const escapeForRegexp = (str) => str.replace(/[.*+\-?^${}()|[\]\\]/g, "\\$&");
|
|
72
75
|
const DEFAULT_ROUTING_SPEC = {
|
|
73
76
|
routes: [
|
|
74
|
-
{ name: "MainContent", pattern: /^\/$/,
|
|
77
|
+
{ name: "MainContent", pattern: /^\/$/, element: /* @__PURE__ */ jsx(MainContent, {}) },
|
|
75
78
|
{
|
|
76
79
|
name: "FileRouter",
|
|
77
80
|
pattern: new RegExp(`^${escapeForRegexp(FILES_PREFIX)}(?<filename>/.+)$`),
|
|
78
|
-
|
|
81
|
+
element: /* @__PURE__ */ jsx(FileRouter, {})
|
|
79
82
|
},
|
|
80
|
-
{ name: "ErrorNotFound", pattern: /^(?<path>.+)$/,
|
|
83
|
+
{ name: "ErrorNotFound", pattern: /^(?<path>.+)$/, element: /* @__PURE__ */ jsx(ErrorNotFound, {}) }
|
|
81
84
|
]
|
|
82
85
|
};
|
|
86
|
+
const CATCH_ALL_ROUTING_SPEC = {
|
|
87
|
+
routes: [{ name: "AppRoot", pattern: /^.*$/, element: null }]
|
|
88
|
+
};
|
|
83
89
|
const boot = ({
|
|
84
90
|
mdxComponents = DEFAULT_MDX_COMPONENTS,
|
|
85
|
-
routingSpec
|
|
91
|
+
routingSpec,
|
|
92
|
+
children
|
|
86
93
|
} = {}) => {
|
|
87
94
|
const rootElement = document.getElementById("root");
|
|
88
95
|
if (!rootElement) {
|
|
89
96
|
throw new Error("boot requires root HTML element to exist");
|
|
90
97
|
}
|
|
98
|
+
const spec = routingSpec ?? (children ? CATCH_ALL_ROUTING_SPEC : DEFAULT_ROUTING_SPEC);
|
|
91
99
|
const moduleCache = new ModuleCache();
|
|
92
100
|
const root = createRoot(rootElement);
|
|
93
101
|
root.render(
|
|
94
102
|
/* @__PURE__ */ jsx(StrictMode, { children: /* @__PURE__ */ jsx(ModuleCacheContextProvider, { moduleCache, children: /* @__PURE__ */ jsxs(MDXProvider, { components: mdxComponents, children: [
|
|
95
103
|
/* @__PURE__ */ jsx(BootMarkers, {}),
|
|
96
|
-
/* @__PURE__ */ jsx(TinkerableApp, { routingSpec })
|
|
104
|
+
/* @__PURE__ */ jsx(TinkerableApp, { routingSpec: spec, children })
|
|
97
105
|
] }) }) })
|
|
98
106
|
);
|
|
99
107
|
};
|
|
100
108
|
export {
|
|
109
|
+
CATCH_ALL_ROUTING_SPEC,
|
|
101
110
|
DEFAULT_ROUTING_SPEC,
|
|
102
111
|
TinkerableApp,
|
|
103
112
|
boot
|
package/dist/boot.js.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"sources":["../src/boot.tsx"],"sourcesContent":["import { FC, StrictMode, useEffect, useLayoutEffect, useState } from 'react';\nimport { createRoot } from 'react-dom/client';\n\nimport { emitMarkerOnce } from './markers';\n\nimport { ErrorNotFound } from './components/errors';\nimport { FileRouter } from './components/FileRouter';\nimport { MainContent } from './components/MainContent';\nimport { DEFAULT_MDX_COMPONENTS } from './components/MDXComponents';\nimport { getInitialContext, updateContext } from './contextUtils';\nimport { getInjectedMetadataEmitter, resolveMetadataSource } from './injectedBundler';\nimport { MDXProvider } from './MDXProvider';\nimport { ModuleCache, ModuleCacheContextProvider } from './moduleCache';\nimport { Router } from './routing';\nimport type { RoutingSpec } from './RoutingSpec';\nimport { FilesMetadata } from './sandboxTypes';\nimport { addListener } from './sandboxUtils';\nimport { TinkerableContext, TinkerableState } from './TinkerableContext';\nimport { FILES_PREFIX } from './urlUtils';\n\nexport type BootProps = {\n mdxComponents?: Record<string, FC>;\n routingSpec?: RoutingSpec;\n};\n\nconst updateAlreadyApplied = (filesMetadata: FilesMetadata, update: FilesMetadata) => {\n for (let [key, value] of Object.entries(update)) {\n if (filesMetadata[key] !== value) {\n return false;\n }\n }\n return true;\n};\n\nexport const TinkerableApp = ({
|
|
1
|
+
{"version":3,"sources":["../src/boot.tsx"],"sourcesContent":["import { FC, ReactNode, StrictMode, useEffect, useLayoutEffect, useState } from 'react';\nimport { createRoot } from 'react-dom/client';\n\nimport { emitMarkerOnce } from './markers';\n\nimport { ErrorNotFound } from './components/errors';\nimport { FileRouter } from './components/FileRouter';\nimport { MainContent } from './components/MainContent';\nimport { DEFAULT_MDX_COMPONENTS } from './components/MDXComponents';\nimport { getInitialContext, updateContext } from './contextUtils';\nimport { getInjectedMetadataEmitter, resolveMetadataSource } from './injectedBundler';\nimport { MDXProvider } from './MDXProvider';\nimport { ModuleCache, ModuleCacheContextProvider } from './moduleCache';\nimport { Router } from './routing';\nimport type { RoutingSpec } from './RoutingSpec';\nimport { FilesMetadata } from './sandboxTypes';\nimport { addListener } from './sandboxUtils';\nimport { TinkerableContext, TinkerableState } from './TinkerableContext';\nimport { FILES_PREFIX } from './urlUtils';\n\n/** Options for {@link boot}: MDX overrides, a route table, or an app root. */\nexport type BootProps = {\n mdxComponents?: Record<string, FC>;\n routingSpec?: RoutingSpec;\n /**\n * App root rendered directly inside the providers (with full navigation\n * context), instead of dispatching through a `routingSpec`. Render\n * `<Routes>`/`<Route>` here for fully dynamic routing — no catch-all rule\n * boilerplate. Takes precedence over `routingSpec` for what is rendered.\n */\n children?: ReactNode;\n};\n\nconst updateAlreadyApplied = (filesMetadata: FilesMetadata, update: FilesMetadata) => {\n for (let [key, value] of Object.entries(update)) {\n if (filesMetadata[key] !== value) {\n return false;\n }\n }\n return true;\n};\n\n/** The app shell {@link boot} renders: holds navigation state, subscribes to host\n * URL + metadata pushes, and renders `children` or the route `<Router />`. */\nexport const TinkerableApp = ({\n routingSpec,\n children,\n}: {\n routingSpec: RoutingSpec;\n children?: ReactNode;\n}) => {\n const [context, setContext] = useState<TinkerableState>(getInitialContext(routingSpec));\n useEffect(() => {\n const removeListener = addListener('urlchange', ({ url }) => {\n setContext((context) => {\n const updatedContext = updateContext(context, url);\n if (updatedContext !== context) {\n console.log(\n `[Sandbox] Updating path from ${context.navigationState.sandboxPath} to ${updatedContext.navigationState.sandboxPath}`\n );\n }\n return updatedContext;\n });\n });\n return removeListener;\n }, [setContext]);\n useEffect(() => {\n // Phase 5 dual-mode (SDK_PACKAGING_SPEC §4/§8): prefer the injected bundler's\n // metadata emitter (the live path, byte-identical); when the SDK is npm-fetched\n // with no injection, `event` is undefined so `addListener` receives\n // 'metadata-update' over the §4 transport instead, and `enable` is a no-op.\n const source = resolveMetadataSource(getInjectedMetadataEmitter());\n const dispose = addListener(\n 'metadata-update',\n ({ update }: Record<string, any>) => {\n setContext((prevContext) =>\n updateAlreadyApplied(prevContext.filesMetadata, update)\n ? prevContext\n : {\n ...prevContext,\n filesMetadata: {\n // TODO: file deletion!\n ...prevContext.filesMetadata,\n ...update,\n },\n }\n );\n },\n source.event\n );\n source.enable();\n return dispose;\n }, [setContext]);\n\n return (\n <TinkerableContext value={context}>\n {children ?? <Router />}\n </TinkerableContext>\n );\n};\n\n// Boot marker emitter (LOAD_PROFILING_SPEC §3, R3-46). Rendered at the top of the\n// app tree so its layout effect fires on the FIRST root-render commit: that instant\n// is `ir.fmp` (the content is in the DOM, about to paint) and the baseline for\n// `ir.interactive` (the host treats a forwarded `ir.interactive` as the root-commit\n// signal and resolves `max(commit, reportReady)` — LP2-3 — so this can only ever be\n// delayed by an app's `reportReady()`, never advanced). Emitted in canonical stream\n// order (fmp then interactive); idempotent per name (StrictMode-safe). Renders null.\nconst BootMarkers = (): null => {\n useLayoutEffect(() => {\n emitMarkerOnce('ir.fmp');\n emitMarkerOnce('ir.interactive');\n }, []);\n return null;\n};\n\n// from: https://stackoverflow.com/a/63838890\nconst escapeForRegexp = (str: string) => str.replace(/[.*+\\-?^${}()|[\\]\\\\]/g, '\\\\$&');\n\n/** The default route table when `boot` is called with no `routingSpec`/`children`:\n * `/` → main content, `/files/<path>` → the file router, else not-found. */\nexport const DEFAULT_ROUTING_SPEC: RoutingSpec = {\n routes: [\n { name: 'MainContent', pattern: /^\\/$/, element: <MainContent /> },\n {\n name: 'FileRouter',\n pattern: new RegExp(`^${escapeForRegexp(FILES_PREFIX)}(?<filename>\\/.+)$`),\n element: <FileRouter />,\n },\n { name: 'ErrorNotFound', pattern: /^(?<path>.+)$/, element: <ErrorNotFound /> },\n ],\n};\n\n/**\n * Matches any `sandboxPath` so navigation context can be built without a route\n * table. Used when {@link boot} is given `children` (the app owns dispatch via\n * `<Routes>`); the catch-all's `element` is never rendered (children are).\n */\nexport const CATCH_ALL_ROUTING_SPEC: RoutingSpec = {\n routes: [{ name: 'AppRoot', pattern: /^.*$/, element: null }],\n};\n\n/**\n * Mount an immediately.run app into the sandbox `#root`. The entry point every\n * app calls from `index.tsx`: wires the MDX, module-cache, and navigation\n * providers, then renders the route table (`routingSpec`) or your `children`.\n */\nexport const boot = ({\n mdxComponents = DEFAULT_MDX_COMPONENTS,\n routingSpec,\n children,\n}: BootProps = {}) => {\n const rootElement = document.getElementById('root');\n if (!rootElement) {\n throw new Error('boot requires root HTML element to exist');\n }\n // `children` own dispatch, so a catch-all keeps navigation working without a\n // table; otherwise fall back to the default file/main-content routes.\n const spec = routingSpec ?? (children ? CATCH_ALL_ROUTING_SPEC : DEFAULT_ROUTING_SPEC);\n const moduleCache = new ModuleCache();\n const root = createRoot(rootElement);\n root.render(\n <StrictMode>\n <ModuleCacheContextProvider moduleCache={moduleCache}>\n <MDXProvider components={mdxComponents}>\n <BootMarkers />\n <TinkerableApp routingSpec={spec}>{children}</TinkerableApp>\n </MDXProvider>\n </ModuleCacheContextProvider>\n </StrictMode>\n );\n};\n"],"mappings":"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","names":["context"]}
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"sources":["../../src/components/Include.tsx"],"sourcesContent":["import { Suspense, createContext, use } from 'react';\nimport { ErrorBoundary } from 'react-error-boundary';\n\nimport { ModuleCacheContext } from '../moduleCache';\nimport { EvaluationContext } from '../sandboxTypes';\nimport { defaultErrorComponent, defaultLoadingComponent } from './defaults';\n\nexport type RenderFileContextType = {\n evaluationContext: EvaluationContext;\n};\n\nexport const RenderExportedComponentContext = createContext<RenderFileContextType | null>(null);\n\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\nexport const Include = ({\n filename,\n exportedSymbol = 'default',\n LoadingComponent = defaultLoadingComponent,\n ErrorComponent = defaultErrorComponent,\n baseModule,\n}: {\n filename: string;\n exportedSymbol?: string;\n LoadingComponent?: typeof defaultLoadingComponent;\n ErrorComponent?: typeof defaultErrorComponent;\n baseModule?: EvaluationContext;\n}) => {\n const moduleCache = use(ModuleCacheContext);\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;
|
|
1
|
+
{"version":3,"sources":["../../src/components/Include.tsx"],"sourcesContent":["import { Suspense, createContext, use } from 'react';\nimport { ErrorBoundary } from 'react-error-boundary';\n\nimport { ModuleCacheContext } from '../moduleCache';\nimport { EvaluationContext } from '../sandboxTypes';\nimport { defaultErrorComponent, defaultLoadingComponent } from './defaults';\n\n/** The value exposed on {@link RenderExportedComponentContext}: the evaluation\n * context of the module {@link Include} resolved. */\nexport type RenderFileContextType = {\n evaluationContext: EvaluationContext;\n};\n\n/** Context carrying the included module's {@link EvaluationContext} to its subtree. */\nexport const RenderExportedComponentContext = createContext<RenderFileContextType | null>(null);\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). */\nexport const Include = ({\n filename,\n exportedSymbol = 'default',\n LoadingComponent = defaultLoadingComponent,\n ErrorComponent = defaultErrorComponent,\n baseModule,\n}: {\n filename: string;\n exportedSymbol?: string;\n LoadingComponent?: typeof defaultLoadingComponent;\n ErrorComponent?: typeof defaultErrorComponent;\n baseModule?: EvaluationContext;\n}) => {\n const moduleCache = use(ModuleCacheContext);\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;AA8BM;AA9BN,mBAA6C;AAC7C,kCAA8B;AAE9B,yBAAmC;AAEnC,sBAA+D;AASxD,MAAM,qCAAiC,4BAA4C,IAAI;AAIvF,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,kCAA+B,OAAO,EAAE,kBAAkB,GACzD,sDAAC,aAAU,GACb;AAEJ;AAIO,MAAM,UAAU,CAAC;AAAA,EACtB;AAAA,EACA,iBAAiB;AAAA,EACjB,mBAAmB;AAAA,EACnB,iBAAiB;AAAA,EACjB;AACF,MAMM;AACJ,QAAM,kBAAc,kBAAI,qCAAkB;AAE1C,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":[]}
|
|
@@ -4,14 +4,21 @@ import { EvaluationContext } from '../sandboxTypes.cjs';
|
|
|
4
4
|
import { defaultLoadingComponent, defaultErrorComponent } from './defaults.cjs';
|
|
5
5
|
import 'react-error-boundary';
|
|
6
6
|
|
|
7
|
+
/** The value exposed on {@link RenderExportedComponentContext}: the evaluation
|
|
8
|
+
* context of the module {@link Include} resolved. */
|
|
7
9
|
type RenderFileContextType = {
|
|
8
10
|
evaluationContext: EvaluationContext;
|
|
9
11
|
};
|
|
12
|
+
/** Context carrying the included module's {@link EvaluationContext} to its subtree. */
|
|
10
13
|
declare const RenderExportedComponentContext: react.Context<RenderFileContextType | null>;
|
|
14
|
+
/** Low-level: render one export of an already-resolving module evaluation. Most
|
|
15
|
+
* code should use {@link Include}, which resolves the module and adds Suspense. */
|
|
11
16
|
declare const RenderExportedComponent: ({ evaluationContextPromise, exportedSymbol, }: {
|
|
12
17
|
evaluationContextPromise: Promise<EvaluationContext>;
|
|
13
18
|
exportedSymbol: string;
|
|
14
19
|
}) => react_jsx_runtime.JSX.Element;
|
|
20
|
+
/** Render another repo file's exported component inline, resolving + evaluating it
|
|
21
|
+
* through the module cache (with Suspense + an error boundary). */
|
|
15
22
|
declare const Include: ({ filename, exportedSymbol, LoadingComponent, ErrorComponent, baseModule, }: {
|
|
16
23
|
filename: string;
|
|
17
24
|
exportedSymbol?: string;
|