@ai-matrx/rich-content 0.0.0-stage → 0.2.2
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/CHANGELOG.md +72 -0
- package/LICENSE +21 -0
- package/README.md +61 -2
- package/dist/display/blocks/csv/CsvBlock.d.ts +10 -0
- package/dist/display/blocks/csv/CsvBlock.js +245 -0
- package/dist/display/blocks/table/parseMarkdownTable.d.ts +20 -0
- package/dist/display/blocks/table/parseMarkdownTable.js +35 -0
- package/dist/display/chat-markdown/citations/remarkMatrxCite.d.ts +33 -0
- package/dist/display/chat-markdown/citations/remarkMatrxCite.js +71 -0
- package/dist/display/chat-markdown/matrx-variables/remarkMatrxVariable.d.ts +29 -0
- package/dist/display/chat-markdown/matrx-variables/remarkMatrxVariable.js +71 -0
- package/dist/display/chat-markdown/page-break/remarkMatrxPageBreak.d.ts +55 -0
- package/dist/display/chat-markdown/page-break/remarkMatrxPageBreak.js +108 -0
- package/dist/display/chat-markdown/rehypeSafeRawHtml.d.ts +59 -0
- package/dist/display/chat-markdown/rehypeSafeRawHtml.js +140 -0
- package/dist/display/markdown-classification/processors/bock-processors/parse-markdown-table.d.ts +14 -0
- package/dist/display/markdown-classification/processors/bock-processors/parse-markdown-table.js +171 -0
- package/dist/display/markdown-classification/processors/types.d.ts +120 -0
- package/dist/display/markdown-classification/processors/types.js +10 -0
- package/dist/display/markdown-classification/processors/utils/client-blocks.d.ts +169 -0
- package/dist/display/markdown-classification/processors/utils/client-blocks.js +0 -0
- package/dist/display/markdown-classification/processors/utils/content-splitter-core.d.ts +223 -0
- package/dist/display/markdown-classification/processors/utils/content-splitter-core.js +1791 -0
- package/dist/display/markdown-classification/processors/utils/content-splitter-v2.d.ts +15 -0
- package/dist/display/markdown-classification/processors/utils/content-splitter-v2.js +19 -0
- package/dist/display/markdown-classification/processors/utils/expand-text-blocks.d.ts +9 -0
- package/dist/display/markdown-classification/processors/utils/expand-text-blocks.js +36 -0
- package/dist/display/markdown-classification/processors/utils/gfm-table-lines.d.ts +5 -0
- package/dist/display/markdown-classification/processors/utils/gfm-table-lines.js +40 -0
- package/dist/display/markdown-classification/processors/utils/gfm-table-vector-inputs.d.ts +16 -0
- package/dist/display/markdown-classification/processors/utils/gfm-table-vector-inputs.js +385 -0
- package/dist/display/markdown-classification/processors/utils/gfm-table-vectors.d.ts +43 -0
- package/dist/display/markdown-classification/processors/utils/gfm-table-vectors.js +33 -0
- package/dist/display/markdown-classification/processors/utils/table-data-parser.d.ts +9 -0
- package/dist/display/markdown-classification/processors/utils/table-data-parser.js +30 -0
- package/dist/display/markdown-classification/processors/utils/thinking-parser.d.ts +7 -0
- package/dist/display/markdown-classification/processors/utils/thinking-parser.js +70 -0
- package/dist/display/render-block.d.ts +23 -0
- package/dist/display/render-block.js +0 -0
- package/dist/display/themes.d.ts +1023 -0
- package/dist/display/themes.js +1105 -0
- package/dist/display/types.d.ts +32 -0
- package/dist/display/types.js +0 -0
- package/dist/host/ContentIrHostBoundary.d.ts +8 -0
- package/dist/host/ContentIrHostBoundary.js +15 -0
- package/dist/host/ErrorActions.d.ts +4 -0
- package/dist/host/ErrorActions.js +11 -0
- package/dist/host/NestedContent.d.ts +3 -0
- package/dist/host/NestedContent.js +12 -0
- package/dist/host/ResourcePeek.d.ts +6 -0
- package/dist/host/ResourcePeek.js +14 -0
- package/dist/host/component-registry.d.ts +2 -0
- package/dist/host/component-registry.js +25 -0
- package/dist/host/diagnostics.d.ts +2 -0
- package/dist/host/diagnostics.js +15 -0
- package/dist/host/index.d.ts +3 -0
- package/dist/host/index.js +18 -0
- package/dist/host/kind-incident.d.ts +3 -0
- package/dist/host/kind-incident.js +12 -0
- package/dist/host/kind-registry.d.ts +2 -0
- package/dist/host/kind-registry.js +35 -0
- package/dist/host/people.d.ts +3 -0
- package/dist/host/people.js +12 -0
- package/dist/host/registry.d.ts +27 -0
- package/dist/host/registry.js +55 -0
- package/dist/host/splitter-envelopes.d.ts +2 -0
- package/dist/host/splitter-envelopes.js +7 -0
- package/dist/host/tables.d.ts +6 -0
- package/dist/host/tables.js +8 -0
- package/dist/host/toast.d.ts +2 -0
- package/dist/host/toast.js +57 -0
- package/dist/host/types.d.ts +157 -0
- package/dist/host/types.js +0 -0
- package/dist/host/wikilinks.d.ts +15 -0
- package/dist/host/wikilinks.js +23 -0
- package/dist/kinds/host/route-env.d.ts +33 -0
- package/dist/kinds/host/route-env.js +16 -0
- package/dist/kinds/react/KindEscapedNotice.d.ts +14 -0
- package/dist/kinds/react/KindEscapedNotice.js +72 -0
- package/dist/kinds/react/ProvisionalKindBoundary.d.ts +19 -0
- package/dist/kinds/react/ProvisionalKindBoundary.js +17 -0
- package/dist/kinds/react/ensure-kind-renderable.d.ts +14 -0
- package/dist/kinds/react/ensure-kind-renderable.js +45 -0
- package/dist/kinds/react/kind-problems.d.ts +62 -0
- package/dist/kinds/react/kind-problems.js +134 -0
- package/dist/kinds/react/kind-route.d.ts +23 -0
- package/dist/kinds/react/kind-route.js +24 -0
- package/dist/kinds/react/loading/infer-loading-slug.d.ts +58 -0
- package/dist/kinds/react/loading/infer-loading-slug.js +100 -0
- package/dist/kinds/react/loading/kind-loading-components.d.ts +48 -0
- package/dist/kinds/react/loading/kind-loading-components.js +447 -0
- package/dist/kinds/react/loading/kind-loading-registry.d.ts +21 -0
- package/dist/kinds/react/loading/kind-loading-registry.js +62 -0
- package/dist/kinds/react/loading/kind-loading-slugs.d.ts +18 -0
- package/dist/kinds/react/loading/kind-loading-slugs.js +34 -0
- package/dist/kinds/react/loading/kind-loading.types.d.ts +79 -0
- package/dist/kinds/react/loading/kind-loading.types.js +31 -0
- package/dist/kinds/react/loading/resolve-loading-slug.d.ts +29 -0
- package/dist/kinds/react/loading/resolve-loading-slug.js +51 -0
- package/dist/kinds/react/partial-kind-route.d.ts +32 -0
- package/dist/kinds/react/partial-kind-route.js +27 -0
- package/dist/kinds/react/registry-versioned.d.ts +54 -0
- package/dist/kinds/react/registry-versioned.js +18 -0
- package/dist/kinds/react/route-at-version.d.ts +38 -0
- package/dist/kinds/react/route-at-version.js +78 -0
- package/dist/kinds/react/slot/KindSlot.d.ts +87 -0
- package/dist/kinds/react/slot/KindSlot.js +65 -0
- package/dist/kinds/react/use-registry-repaint.d.ts +6 -0
- package/dist/kinds/react/use-registry-repaint.js +36 -0
- package/dist/kinds/react/useIrNode.d.ts +9 -0
- package/dist/kinds/react/useIrNode.js +46 -0
- package/dist/kinds/react/useLiveJsonRegion.d.ts +15 -0
- package/dist/kinds/react/useLiveJsonRegion.js +84 -0
- package/dist/kinds/redux/render-block-envelope.d.ts +14 -0
- package/dist/kinds/redux/render-block-envelope.js +26 -0
- package/dist/kinds/registry/kind-correctors.d.ts +63 -0
- package/dist/kinds/registry/kind-correctors.js +94 -0
- package/dist/kinds/registry/legacy-quiz-envelope.d.ts +1 -0
- package/dist/kinds/registry/legacy-quiz-envelope.js +1 -0
- package/dist/kinds/registry/region-envelope-memo.d.ts +45 -0
- package/dist/kinds/registry/region-envelope-memo.js +94 -0
- package/dist/kinds/registry/registry-debug.d.ts +38 -0
- package/dist/kinds/registry/registry-debug.js +39 -0
- package/dist/markdown-core/MarkdownCore.d.ts +6 -0
- package/dist/markdown-core/MarkdownCore.js +32 -0
- package/dist/markdown-core/MarkdownCoreImpl.d.ts +3 -0
- package/dist/markdown-core/MarkdownCoreImpl.js +27 -0
- package/dist/markdown-core/MarkdownCoreServer.d.ts +4 -0
- package/dist/markdown-core/MarkdownCoreServer.js +26 -0
- package/dist/markdown-core/heading-anchors-context.d.ts +2 -0
- package/dist/markdown-core/heading-anchors-context.js +11 -0
- package/dist/markdown-core/heading-anchors-props.d.ts +2 -0
- package/dist/markdown-core/heading-anchors-props.js +6 -0
- package/dist/markdown-core/markdown-core-html.d.ts +3 -0
- package/dist/markdown-core/markdown-core-html.js +33 -0
- package/dist/markdown-core/markdown-core-presets.d.ts +22 -0
- package/dist/markdown-core/markdown-core-presets.js +118 -0
- package/dist/markdown-core/markdown-core-types.d.ts +43 -0
- package/dist/markdown-core/markdown-core-types.js +0 -0
- package/dist/markdown-core/math/vendor/micromark-math-math-flow.d.ts +15 -0
- package/dist/markdown-core/math/vendor/micromark-math-math-flow.js +143 -0
- package/dist/markdown-core/math/vendor/micromark-math-math-text.d.ts +24 -0
- package/dist/markdown-core/math/vendor/micromark-math-math-text.js +127 -0
- package/dist/markdown-core/math/vendor/micromark-math-syntax.d.ts +30 -0
- package/dist/markdown-core/math/vendor/micromark-math-syntax.js +15 -0
- package/dist/markdown-core/math/vendor/rehype-katex.d.ts +15 -0
- package/dist/markdown-core/math/vendor/rehype-katex.js +83 -0
- package/dist/markdown-core/math/vendor/remark-math.d.ts +9 -0
- package/dist/markdown-core/math/vendor/remark-math.js +20 -0
- package/dist/markdown-core/math-normalizer.d.ts +57 -0
- package/dist/markdown-core/math-normalizer.js +315 -0
- package/dist/markdown-core/plain-title.d.ts +2 -0
- package/dist/markdown-core/plain-title.js +1 -0
- package/dist/markdown-core/stream-heal.d.ts +2 -0
- package/dist/markdown-core/stream-heal.js +184 -0
- package/dist/markdown-core/streaming-context.d.ts +2 -0
- package/dist/markdown-core/streaming-context.js +11 -0
- package/dist/markdown-core/syntax/callout-types.d.ts +9 -0
- package/dist/markdown-core/syntax/callout-types.js +101 -0
- package/dist/markdown-core/syntax/containers.d.ts +17 -0
- package/dist/markdown-core/syntax/containers.js +353 -0
- package/dist/markdown-core/syntax/document-numbering.d.ts +52 -0
- package/dist/markdown-core/syntax/document-numbering.js +184 -0
- package/dist/markdown-core/syntax/elements/CalloutIcon.d.ts +3 -0
- package/dist/markdown-core/syntax/elements/CalloutIcon.js +41 -0
- package/dist/markdown-core/syntax/elements/CrossRef.d.ts +12 -0
- package/dist/markdown-core/syntax/elements/CrossRef.js +57 -0
- package/dist/markdown-core/syntax/elements/CsvFence.d.ts +4 -0
- package/dist/markdown-core/syntax/elements/CsvFence.js +18 -0
- package/dist/markdown-core/syntax/elements/DetailsElements.d.ts +12 -0
- package/dist/markdown-core/syntax/elements/DetailsElements.js +38 -0
- package/dist/markdown-core/syntax/elements/DocumentNumbering.d.ts +20 -0
- package/dist/markdown-core/syntax/elements/DocumentNumbering.js +37 -0
- package/dist/markdown-core/syntax/elements/DocumentPropertiesPanel.d.ts +4 -0
- package/dist/markdown-core/syntax/elements/DocumentPropertiesPanel.js +46 -0
- package/dist/markdown-core/syntax/elements/InDocAnchor.d.ts +11 -0
- package/dist/markdown-core/syntax/elements/InDocAnchor.js +87 -0
- package/dist/markdown-core/syntax/elements/MarkdownSourceEdit.d.ts +24 -0
- package/dist/markdown-core/syntax/elements/MarkdownSourceEdit.js +28 -0
- package/dist/markdown-core/syntax/elements/MatrxTabs.d.ts +10 -0
- package/dist/markdown-core/syntax/elements/MatrxTabs.js +59 -0
- package/dist/markdown-core/syntax/elements/MentionChip.d.ts +7 -0
- package/dist/markdown-core/syntax/elements/MentionChip.js +69 -0
- package/dist/markdown-core/syntax/elements/NestedBody.d.ts +3 -0
- package/dist/markdown-core/syntax/elements/NestedBody.js +13 -0
- package/dist/markdown-core/syntax/elements/TableOfContents.d.ts +5 -0
- package/dist/markdown-core/syntax/elements/TableOfContents.js +44 -0
- package/dist/markdown-core/syntax/elements/TaskCheckbox.d.ts +7 -0
- package/dist/markdown-core/syntax/elements/TaskCheckbox.js +63 -0
- package/dist/markdown-core/syntax/elements/WikiEmbed.d.ts +7 -0
- package/dist/markdown-core/syntax/elements/WikiEmbed.js +68 -0
- package/dist/markdown-core/syntax/elements/WikiLink.d.ts +10 -0
- package/dist/markdown-core/syntax/elements/WikiLink.js +114 -0
- package/dist/markdown-core/syntax/elements/core-syntax-elements.d.ts +22 -0
- package/dist/markdown-core/syntax/elements/core-syntax-elements.js +70 -0
- package/dist/markdown-core/syntax/elements/find-in-document.d.ts +3 -0
- package/dist/markdown-core/syntax/elements/find-in-document.js +20 -0
- package/dist/markdown-core/syntax/elements/wiki-target.d.ts +5 -0
- package/dist/markdown-core/syntax/elements/wiki-target.js +8 -0
- package/dist/markdown-core/syntax/frontmatter.d.ts +26 -0
- package/dist/markdown-core/syntax/frontmatter.js +72 -0
- package/dist/markdown-core/syntax/gfm-cell-pipes.d.ts +11 -0
- package/dist/markdown-core/syntax/gfm-cell-pipes.js +4 -0
- package/dist/markdown-core/syntax/inline-syntax.d.ts +26 -0
- package/dist/markdown-core/syntax/inline-syntax.js +163 -0
- package/dist/markdown-core/syntax/linear-scan.d.ts +46 -0
- package/dist/markdown-core/syntax/linear-scan.js +129 -0
- package/dist/markdown-core/syntax/mdast-helpers.d.ts +48 -0
- package/dist/markdown-core/syntax/mdast-helpers.js +48 -0
- package/dist/markdown-core/syntax/mentions.d.ts +2 -0
- package/dist/markdown-core/syntax/mentions.js +42 -0
- package/dist/markdown-core/syntax/names.d.ts +6 -0
- package/dist/markdown-core/syntax/names.js +18 -0
- package/dist/markdown-core/syntax/prepare-syntax-source.d.ts +1 -0
- package/dist/markdown-core/syntax/prepare-syntax-source.js +78 -0
- package/dist/markdown-core/syntax/rehype-matrx-syntax.d.ts +9 -0
- package/dist/markdown-core/syntax/rehype-matrx-syntax.js +180 -0
- package/dist/markdown-core/syntax/remark-inline-only.d.ts +23 -0
- package/dist/markdown-core/syntax/remark-inline-only.js +25 -0
- package/dist/markdown-core/syntax/remark-matrx-syntax.d.ts +7 -0
- package/dist/markdown-core/syntax/remark-matrx-syntax.js +351 -0
- package/dist/markdown-core/syntax/remark-table-code-pipes.d.ts +7 -0
- package/dist/markdown-core/syntax/remark-table-code-pipes.js +23 -0
- package/dist/markdown-core/syntax/stream-heal-syntax.d.ts +2 -0
- package/dist/markdown-core/syntax/stream-heal-syntax.js +108 -0
- package/dist/markdown-core/syntax/task-source.d.ts +10 -0
- package/dist/markdown-core/syntax/task-source.js +34 -0
- package/dist/markdown-core/syntax/useDocumentProperties.d.ts +3 -0
- package/dist/markdown-core/syntax/useDocumentProperties.js +8 -0
- package/dist/styles.css +0 -0
- package/dist/utils/addressWithoutNavigating.d.ts +68 -0
- package/dist/utils/addressWithoutNavigating.js +60 -0
- package/dist/utils/client-lazy.d.ts +13 -0
- package/dist/utils/client-lazy.js +24 -0
- package/dist/utils/decision-options.d.ts +21 -0
- package/dist/utils/decision-options.js +32 -0
- package/dist/utils/gfm-lexer.d.ts +5 -0
- package/dist/utils/gfm-lexer.js +10 -0
- package/dist/utils/json.d.ts +63 -0
- package/dist/utils/json.js +22 -0
- package/dist/utils/plain-title.d.ts +25 -0
- package/dist/utils/plain-title.js +51 -0
- package/dist/utils/table-source.d.ts +62 -0
- package/dist/utils/table-source.js +191 -0
- package/dist/utils/youtube.d.ts +52 -0
- package/dist/utils/youtube.js +137 -0
- package/package.json +134 -4
|
@@ -0,0 +1,46 @@
|
|
|
1
|
+
"use client";
|
|
2
|
+
import { useRef, useSyncExternalStore } from "react";
|
|
3
|
+
import { irPathKey } from "@ai-matrx/content-ir";
|
|
4
|
+
import { getParseSession } from "@ai-matrx/content-ir";
|
|
5
|
+
const noopSubscribe = () => () => {
|
|
6
|
+
};
|
|
7
|
+
function useIrNode(identity, path) {
|
|
8
|
+
const pathKey = typeof path === "string" ? path : irPathKey(path);
|
|
9
|
+
const subscribe = identity ? (onStoreChange) => {
|
|
10
|
+
const session = getParseSession(identity);
|
|
11
|
+
if (!session) return () => {
|
|
12
|
+
};
|
|
13
|
+
return session.subscribe(pathKey, onStoreChange);
|
|
14
|
+
} : noopSubscribe;
|
|
15
|
+
const getSnapshot = () => identity ? getParseSession(identity)?.getNode(pathKey) ?? null : null;
|
|
16
|
+
return useSyncExternalStore(subscribe, getSnapshot, () => null);
|
|
17
|
+
}
|
|
18
|
+
function useIrNodePaths(identity) {
|
|
19
|
+
const subscribe = identity ? (onStoreChange) => {
|
|
20
|
+
const session = getParseSession(identity);
|
|
21
|
+
if (!session) return () => {
|
|
22
|
+
};
|
|
23
|
+
return session.subscribeAny(onStoreChange);
|
|
24
|
+
} : noopSubscribe;
|
|
25
|
+
const cache = useRef({
|
|
26
|
+
key: null,
|
|
27
|
+
value: EMPTY_PATHS
|
|
28
|
+
});
|
|
29
|
+
const getSnapshot = () => {
|
|
30
|
+
if (!identity) return EMPTY_PATHS;
|
|
31
|
+
const session = getParseSession(identity);
|
|
32
|
+
if (!session) return EMPTY_PATHS;
|
|
33
|
+
const paths = session.listNodes().map((node) => node.pathKey);
|
|
34
|
+
const key = paths.join("\0");
|
|
35
|
+
if (key !== cache.current.key) {
|
|
36
|
+
cache.current = { key, value: paths };
|
|
37
|
+
}
|
|
38
|
+
return cache.current.value;
|
|
39
|
+
};
|
|
40
|
+
return useSyncExternalStore(subscribe, getSnapshot, () => EMPTY_PATHS);
|
|
41
|
+
}
|
|
42
|
+
const EMPTY_PATHS = [];
|
|
43
|
+
export {
|
|
44
|
+
useIrNode,
|
|
45
|
+
useIrNodePaths
|
|
46
|
+
};
|
|
@@ -0,0 +1,15 @@
|
|
|
1
|
+
import type { IrTreeNode } from "@ai-matrx/content-ir";
|
|
2
|
+
import type { CanonicalBlockIR } from "@ai-matrx/content-ir";
|
|
3
|
+
export interface UseLiveJsonRegionOptions {
|
|
4
|
+
/** Known-context root prediction (e.g. "flashcard_set" for the cards agent). */
|
|
5
|
+
expectedRootKind?: string;
|
|
6
|
+
/** True once the source stream has finished — ends the region. */
|
|
7
|
+
done?: boolean;
|
|
8
|
+
}
|
|
9
|
+
export interface LiveJsonRegion {
|
|
10
|
+
/** The root kind node — identity bumps on every tree change (COW spine). */
|
|
11
|
+
rootNode: IrTreeNode | null;
|
|
12
|
+
/** Current canonical envelope, or null before the region opens. */
|
|
13
|
+
envelope: CanonicalBlockIR | null;
|
|
14
|
+
}
|
|
15
|
+
export declare function useLiveJsonRegion(identity: string | null, text: string | null | undefined, options?: UseLiveJsonRegionOptions): LiveJsonRegion;
|
|
@@ -0,0 +1,84 @@
|
|
|
1
|
+
"use client";
|
|
2
|
+
import { sessionEnvelope } from "../registry/kind-correctors.js";
|
|
3
|
+
import { useEffect, useRef } from "react";
|
|
4
|
+
import {
|
|
5
|
+
disposeParseSession,
|
|
6
|
+
getParseSession,
|
|
7
|
+
openParseSession
|
|
8
|
+
} from "@ai-matrx/content-ir";
|
|
9
|
+
import { kindRegistry } from "../../host/kind-registry.js";
|
|
10
|
+
import { componentRegistry } from "../../host/component-registry.js";
|
|
11
|
+
import { useIrNode } from "./useIrNode.js";
|
|
12
|
+
function useLiveJsonRegion(identity, text, options) {
|
|
13
|
+
const openedRef = useRef(null);
|
|
14
|
+
const fedLenRef = useRef(0);
|
|
15
|
+
const startedRef = useRef(false);
|
|
16
|
+
const expectedRootKind = options?.expectedRootKind;
|
|
17
|
+
const done = options?.done ?? false;
|
|
18
|
+
useEffect(() => {
|
|
19
|
+
if (!identity) return;
|
|
20
|
+
if (openedRef.current !== identity) {
|
|
21
|
+
if (openedRef.current) disposeParseSession(openedRef.current);
|
|
22
|
+
openedRef.current = identity;
|
|
23
|
+
fedLenRef.current = 0;
|
|
24
|
+
startedRef.current = false;
|
|
25
|
+
if (expectedRootKind) {
|
|
26
|
+
void kindRegistry.ensureWarm();
|
|
27
|
+
void componentRegistry.ensureWarm();
|
|
28
|
+
}
|
|
29
|
+
try {
|
|
30
|
+
openParseSession({
|
|
31
|
+
identity,
|
|
32
|
+
schemas: kindRegistry.resolver(),
|
|
33
|
+
expectedRootKind,
|
|
34
|
+
onSchemaArrived: (deliver) => kindRegistry.onSchemaArrived(deliver),
|
|
35
|
+
onEvent: (event) => {
|
|
36
|
+
if (event.type === "kind_identified" || event.type === "pending_schema") {
|
|
37
|
+
void kindRegistry.ensureWarm();
|
|
38
|
+
void componentRegistry.ensureWarm();
|
|
39
|
+
kindRegistry.requestSchema(event.kind);
|
|
40
|
+
componentRegistry.requestComponent(event.kind, "web", "output");
|
|
41
|
+
}
|
|
42
|
+
}
|
|
43
|
+
});
|
|
44
|
+
} catch {
|
|
45
|
+
return;
|
|
46
|
+
}
|
|
47
|
+
}
|
|
48
|
+
const session = getParseSession(identity);
|
|
49
|
+
if (!session) return;
|
|
50
|
+
if (session.isEnded) return;
|
|
51
|
+
const full = text ?? "";
|
|
52
|
+
if (!startedRef.current) {
|
|
53
|
+
const openIndex = full.indexOf("{");
|
|
54
|
+
if (openIndex === -1) {
|
|
55
|
+
return;
|
|
56
|
+
}
|
|
57
|
+
fedLenRef.current = openIndex;
|
|
58
|
+
startedRef.current = true;
|
|
59
|
+
}
|
|
60
|
+
if (full.length > fedLenRef.current) {
|
|
61
|
+
session.write(full.slice(fedLenRef.current));
|
|
62
|
+
fedLenRef.current = full.length;
|
|
63
|
+
session.flushNotify();
|
|
64
|
+
}
|
|
65
|
+
if (done) {
|
|
66
|
+
session.end();
|
|
67
|
+
session.flushNotify();
|
|
68
|
+
}
|
|
69
|
+
}, [identity, text, done, expectedRootKind]);
|
|
70
|
+
useEffect(() => {
|
|
71
|
+
return () => {
|
|
72
|
+
if (openedRef.current) {
|
|
73
|
+
disposeParseSession(openedRef.current);
|
|
74
|
+
openedRef.current = null;
|
|
75
|
+
}
|
|
76
|
+
};
|
|
77
|
+
}, []);
|
|
78
|
+
const rootNode = useIrNode(identity, "");
|
|
79
|
+
const envelope = identity && rootNode ? sessionEnvelope(getParseSession(identity)) : null;
|
|
80
|
+
return { rootNode, envelope };
|
|
81
|
+
}
|
|
82
|
+
export {
|
|
83
|
+
useLiveJsonRegion
|
|
84
|
+
};
|
|
@@ -0,0 +1,14 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Envelope helpers for hosts (accumulator / splitter / renderers):
|
|
3
|
+
* reading `metadata.__ir` off render blocks, reconstructing the full source
|
|
4
|
+
* object (schema values + residues merged back), and the Phase-2 shadow
|
|
5
|
+
* parity check that proves the kind parser and JSON.parse agree byte-for-
|
|
6
|
+
* byte on real traffic before any rendering flips.
|
|
7
|
+
*/
|
|
8
|
+
import { readEnvelope } from "@ai-matrx/content-ir";
|
|
9
|
+
export { readEnvelope };
|
|
10
|
+
export declare function sanitizeInboundEnvelopeMetadata(metadata: Record<string, unknown> | null | undefined, context: {
|
|
11
|
+
blockId: string;
|
|
12
|
+
}): Record<string, unknown> | undefined;
|
|
13
|
+
export { reconstructRegionValue, stripKindDeep } from "@ai-matrx/content-ir";
|
|
14
|
+
export { envelopeMatchesParsedSource } from "@ai-matrx/content-ir/surfaces";
|
|
@@ -0,0 +1,26 @@
|
|
|
1
|
+
import { readEnvelope } from "@ai-matrx/content-ir";
|
|
2
|
+
import { sanitizeInboundEnvelopeMetadata as sanitizeInboundEnvelopeMetadataPure } from "@ai-matrx/content-ir";
|
|
3
|
+
import { seedEnvelope } from "../registry/region-envelope-memo.js";
|
|
4
|
+
import { captureError } from "../../host/diagnostics.js";
|
|
5
|
+
function sanitizeInboundEnvelopeMetadata(metadata, context) {
|
|
6
|
+
return sanitizeInboundEnvelopeMetadataPure(metadata, context, {
|
|
7
|
+
seedEnvelope: (envelope) => seedEnvelope(envelope),
|
|
8
|
+
reportMalformed: ({ blockId, engine, raw }) => {
|
|
9
|
+
captureError({
|
|
10
|
+
source: "content-ir",
|
|
11
|
+
message: `render_block "${blockId}" carried a malformed metadata.__ir envelope (engine "${engine}") \u2014 dropped before Redux so it can't poison the pipeline`,
|
|
12
|
+
relation: engine,
|
|
13
|
+
raw
|
|
14
|
+
});
|
|
15
|
+
}
|
|
16
|
+
});
|
|
17
|
+
}
|
|
18
|
+
import { reconstructRegionValue, stripKindDeep } from "@ai-matrx/content-ir";
|
|
19
|
+
import { envelopeMatchesParsedSource } from "@ai-matrx/content-ir/surfaces";
|
|
20
|
+
export {
|
|
21
|
+
envelopeMatchesParsedSource,
|
|
22
|
+
readEnvelope,
|
|
23
|
+
reconstructRegionValue,
|
|
24
|
+
sanitizeInboundEnvelopeMetadata,
|
|
25
|
+
stripKindDeep
|
|
26
|
+
};
|
|
@@ -0,0 +1,63 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Kind correctors — a registered kind's value made to agree with its own rules BEFORE any
|
|
3
|
+
* renderer sees it. The client twin of aidream's
|
|
4
|
+
* `matrx_ai/processing/blocks/kind_correctors.py`.
|
|
5
|
+
*
|
|
6
|
+
* `draft_critique` (the Tough Editor) is the first: "the scale mapping is applied by code
|
|
7
|
+
* from the points, so the score can never disagree with the rubric". A renderer is never the
|
|
8
|
+
* place to fix it — a kind can be drawn by a compiled bridge, a db component, or the generic
|
|
9
|
+
* floor, and any one that forgot would show the model's arithmetic.
|
|
10
|
+
*
|
|
11
|
+
* THE ONE STEP. Every envelope this app builds comes from one of three kernel constructors —
|
|
12
|
+
* `envelopeFromCompleteValue` (stored values: reload, partial, nested kinds, XML finalize,
|
|
13
|
+
* progress data), `normalizeJsonRegion` (complete text: DB-loaded messages, the re-split) and
|
|
14
|
+
* a `ParseSession`'s `buildEnvelope()` (the live stream, live previews). This module owns the
|
|
15
|
+
* corrected form of all three, and `kind-correctors.guard.test.ts` refuses any host file that
|
|
16
|
+
* calls a raw constructor — so a new render path inherits the correction or fails CI.
|
|
17
|
+
* Direct-object renders (`KindInstanceRender`, the shape preview's "direct" path, every
|
|
18
|
+
* kind-instance load) correct their value in the host binding, and the db-component reader
|
|
19
|
+
* corrects whatever still reaches it uncorrected (a pasted block with no envelope).
|
|
20
|
+
*
|
|
21
|
+
* NEVER SILENT. A correction travels ON the envelope as a `residue.notices` entry with code
|
|
22
|
+
* `kind_corrected` — the envelope's own structured-warning channel, so it survives
|
|
23
|
+
* serialization, persistence and reload — and `kindCorrectionsOf(metadata)` reads those plus
|
|
24
|
+
* the server's `metadata.kindCorrections`. A corrector that throws leaves the value as written
|
|
25
|
+
* and says it could not be checked; it never blocks a render.
|
|
26
|
+
*/
|
|
27
|
+
import { envelopeFromCompleteValue as rawEnvelopeFromCompleteValue, normalizeJsonRegion as rawNormalizeJsonRegion, type CanonicalBlockIR } from "@ai-matrx/content-ir";
|
|
28
|
+
/** Block metadata key the SERVER uses for the corrections it made (same as aidream). */
|
|
29
|
+
export declare const KIND_CORRECTIONS_KEY = "kindCorrections";
|
|
30
|
+
/** The `residue.notices` code a client-side correction is recorded under. */
|
|
31
|
+
export declare const KIND_CORRECTED_NOTICE = "kind_corrected";
|
|
32
|
+
export type KindCorrector = (value: Record<string, unknown>) => {
|
|
33
|
+
value: Record<string, unknown>;
|
|
34
|
+
corrections: string[];
|
|
35
|
+
};
|
|
36
|
+
/** Register the corrector for one kind (replaces an earlier one for the same kind). */
|
|
37
|
+
export declare function registerKindCorrector(kind: string, corrector: KindCorrector): void;
|
|
38
|
+
export declare function hasKindCorrector(kind: string | null | undefined): boolean;
|
|
39
|
+
/**
|
|
40
|
+
* The value made to agree with its kind's rules, plus one line per change. Returns the SAME
|
|
41
|
+
* reference and no lines when there is no corrector or nothing to change.
|
|
42
|
+
*/
|
|
43
|
+
export declare function correctKindValue(kind: string | null | undefined, value: unknown): {
|
|
44
|
+
value: unknown;
|
|
45
|
+
corrections: string[];
|
|
46
|
+
};
|
|
47
|
+
/**
|
|
48
|
+
* The envelope with its COMPLETE root value corrected and each change recorded as a
|
|
49
|
+
* `kind_corrected` notice. Idempotent (an envelope already carrying the notice, or with
|
|
50
|
+
* nothing to change, comes back by reference); a streaming root is never touched — half a
|
|
51
|
+
* value cannot be scored.
|
|
52
|
+
*/
|
|
53
|
+
export declare function correctKindEnvelope<T extends CanonicalBlockIR | null | undefined>(envelope: T): T;
|
|
54
|
+
/** `envelopeFromCompleteValue`, corrected. The only form host code may call. */
|
|
55
|
+
export declare function envelopeFromCompleteValue(...args: Parameters<typeof rawEnvelopeFromCompleteValue>): CanonicalBlockIR;
|
|
56
|
+
/** `normalizeJsonRegion`, corrected. The only form host code may call. */
|
|
57
|
+
export declare function normalizeJsonRegion(...args: Parameters<typeof rawNormalizeJsonRegion>): CanonicalBlockIR;
|
|
58
|
+
/** A `ParseSession`'s envelope, corrected once it is complete. Wrap every `buildEnvelope()`. */
|
|
59
|
+
export declare function sessionEnvelope(session: {
|
|
60
|
+
buildEnvelope(): CanonicalBlockIR;
|
|
61
|
+
} | null | undefined): CanonicalBlockIR | null;
|
|
62
|
+
/** Every correction a block carries: the server's list plus the envelope's own notices. */
|
|
63
|
+
export declare function kindCorrectionsOf(metadata: Record<string, unknown> | null | undefined): string[];
|
|
@@ -0,0 +1,94 @@
|
|
|
1
|
+
import {
|
|
2
|
+
envelopeFromCompleteValue as rawEnvelopeFromCompleteValue,
|
|
3
|
+
normalizeJsonRegion as rawNormalizeJsonRegion,
|
|
4
|
+
IR_ENVELOPE_KEY,
|
|
5
|
+
isCanonicalBlockIR
|
|
6
|
+
} from "@ai-matrx/content-ir";
|
|
7
|
+
const KIND_CORRECTIONS_KEY = "kindCorrections";
|
|
8
|
+
const KIND_CORRECTED_NOTICE = "kind_corrected";
|
|
9
|
+
const CORRECTORS_KEY = /* @__PURE__ */ Symbol.for("ai-matrx.rich-content.kind-correctors");
|
|
10
|
+
const CORRECTORS = globalThis[CORRECTORS_KEY] ??= {};
|
|
11
|
+
function registerKindCorrector(kind, corrector) {
|
|
12
|
+
CORRECTORS[kind] = corrector;
|
|
13
|
+
}
|
|
14
|
+
function hasKindCorrector(kind) {
|
|
15
|
+
return typeof kind === "string" && kind in CORRECTORS;
|
|
16
|
+
}
|
|
17
|
+
function correctKindValue(kind, value) {
|
|
18
|
+
if (!value || typeof value !== "object" || Array.isArray(value)) return { value, corrections: [] };
|
|
19
|
+
const slug = kind ?? value.__kind;
|
|
20
|
+
const corrector = typeof slug === "string" ? CORRECTORS[slug] : void 0;
|
|
21
|
+
if (!corrector) return { value, corrections: [] };
|
|
22
|
+
try {
|
|
23
|
+
const out = corrector(value);
|
|
24
|
+
if (out.corrections.length === 0) return { value, corrections: [] };
|
|
25
|
+
console.warn(`[content-ir] ${slug} corrected before render: ${out.corrections.join("; ")}`);
|
|
26
|
+
return { value: out.value, corrections: out.corrections };
|
|
27
|
+
} catch (err) {
|
|
28
|
+
const reason = err instanceof Error ? err.message : String(err);
|
|
29
|
+
console.warn(`[content-ir] ${slug} corrector failed: ${reason} \u2014 shown as written`);
|
|
30
|
+
return {
|
|
31
|
+
value,
|
|
32
|
+
corrections: [`${slug} could not be checked against its own rules (${reason}); shown as written`]
|
|
33
|
+
};
|
|
34
|
+
}
|
|
35
|
+
}
|
|
36
|
+
function correctKindEnvelope(envelope) {
|
|
37
|
+
if (!envelope || !isCanonicalBlockIR(envelope)) return envelope;
|
|
38
|
+
const root = envelope.root;
|
|
39
|
+
if (root.status !== "complete" || !hasKindCorrector(root.kind)) return envelope;
|
|
40
|
+
if (root.residue?.notices?.some((n) => n.code === KIND_CORRECTED_NOTICE)) return envelope;
|
|
41
|
+
const { value, corrections } = correctKindValue(root.kind, root.value);
|
|
42
|
+
if (corrections.length === 0) return envelope;
|
|
43
|
+
const notices = [
|
|
44
|
+
...root.residue?.notices ?? [],
|
|
45
|
+
...corrections.map((message) => ({ code: KIND_CORRECTED_NOTICE, message }))
|
|
46
|
+
];
|
|
47
|
+
return {
|
|
48
|
+
...envelope,
|
|
49
|
+
root: {
|
|
50
|
+
...root,
|
|
51
|
+
value,
|
|
52
|
+
residue: {
|
|
53
|
+
extra: root.residue?.extra ?? null,
|
|
54
|
+
optionalMissing: root.residue?.optionalMissing ?? null,
|
|
55
|
+
notices
|
|
56
|
+
}
|
|
57
|
+
}
|
|
58
|
+
};
|
|
59
|
+
}
|
|
60
|
+
function envelopeFromCompleteValue(...args) {
|
|
61
|
+
return correctKindEnvelope(rawEnvelopeFromCompleteValue(...args));
|
|
62
|
+
}
|
|
63
|
+
function normalizeJsonRegion(...args) {
|
|
64
|
+
return correctKindEnvelope(rawNormalizeJsonRegion(...args));
|
|
65
|
+
}
|
|
66
|
+
function sessionEnvelope(session) {
|
|
67
|
+
return session ? correctKindEnvelope(session.buildEnvelope()) : null;
|
|
68
|
+
}
|
|
69
|
+
function kindCorrectionsOf(metadata) {
|
|
70
|
+
const out = [];
|
|
71
|
+
const server = metadata?.[KIND_CORRECTIONS_KEY];
|
|
72
|
+
if (Array.isArray(server)) {
|
|
73
|
+
for (const line of server) if (typeof line === "string" && line.trim()) out.push(line);
|
|
74
|
+
}
|
|
75
|
+
const envelope = metadata?.[IR_ENVELOPE_KEY];
|
|
76
|
+
if (isCanonicalBlockIR(envelope)) {
|
|
77
|
+
for (const n of envelope.root.residue?.notices ?? []) {
|
|
78
|
+
if (n.code === KIND_CORRECTED_NOTICE && !out.includes(n.message)) out.push(n.message);
|
|
79
|
+
}
|
|
80
|
+
}
|
|
81
|
+
return out;
|
|
82
|
+
}
|
|
83
|
+
export {
|
|
84
|
+
KIND_CORRECTED_NOTICE,
|
|
85
|
+
KIND_CORRECTIONS_KEY,
|
|
86
|
+
correctKindEnvelope,
|
|
87
|
+
correctKindValue,
|
|
88
|
+
envelopeFromCompleteValue,
|
|
89
|
+
hasKindCorrector,
|
|
90
|
+
kindCorrectionsOf,
|
|
91
|
+
normalizeJsonRegion,
|
|
92
|
+
registerKindCorrector,
|
|
93
|
+
sessionEnvelope
|
|
94
|
+
};
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
export * from "@ai-matrx/content-ir/surfaces";
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
export * from "@ai-matrx/content-ir/surfaces";
|
|
@@ -0,0 +1,45 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Memoized one-shot envelopes for the STATIC path (content-splitter-v2).
|
|
3
|
+
*
|
|
4
|
+
* The splitter runs on DB-loaded messages AND on the hot re-split path while
|
|
5
|
+
* a message streams, so this must be cheap and idempotent:
|
|
6
|
+
* - The hot splitter normalizes complete JSON only. Terminal renderers can
|
|
7
|
+
* explicitly rehydrate interrupted kinds with the same parser as the stream,
|
|
8
|
+
* retaining their error status and original bytes after a refresh.
|
|
9
|
+
* - Results are memoized by source text, so repeated re-splits of the same
|
|
10
|
+
* message return the SAME envelope object (reference equality → React
|
|
11
|
+
* bail-outs) and never re-parse.
|
|
12
|
+
*
|
|
13
|
+
* Phase 5 adds the PERSISTED-envelope seed: envelopes stamped on message
|
|
14
|
+
* parts at commit time (`core/envelope-cache.ts`) — or arriving pre-built on
|
|
15
|
+
* server render_blocks — are seeded here by fingerprint. A memo miss then
|
|
16
|
+
* consults the seed through `normalizeJsonRegion`'s `existing` fast path
|
|
17
|
+
* (`reuseEnvelopeIfCurrent`: exact fingerprint match of the region source),
|
|
18
|
+
* so a reload reuses the stream's envelope BY REFERENCE instead of parsing.
|
|
19
|
+
*/
|
|
20
|
+
import { type CanonicalBlockIR } from "@ai-matrx/content-ir";
|
|
21
|
+
/**
|
|
22
|
+
* Seed a single already-validated envelope (e.g. a server render_block's
|
|
23
|
+
* `metadata.__ir` accepted by `sanitizeInboundEnvelopeMetadata`). Incomplete
|
|
24
|
+
* envelopes are ignored — they can never be reused.
|
|
25
|
+
*/
|
|
26
|
+
export declare function seedEnvelope(envelope: CanonicalBlockIR): void;
|
|
27
|
+
/**
|
|
28
|
+
* Seed every envelope from a message part's persisted `metadata.__ir` cache
|
|
29
|
+
* (the `IrEnvelopeCache` stamped by `assembleMessageParts`). Call from the
|
|
30
|
+
* read boundaries that consume text parts — the subsequent splitter pass then
|
|
31
|
+
* reuses the persisted envelopes instead of re-parsing. Returns the number of
|
|
32
|
+
* envelopes seeded.
|
|
33
|
+
*
|
|
34
|
+
* A present-but-malformed cache is a write-side bug (only our commit path and
|
|
35
|
+
* aidream write this key) — it seeds NOTHING and screams via captureError,
|
|
36
|
+
* never poisoning the pipeline with half-trusted envelopes.
|
|
37
|
+
*/
|
|
38
|
+
export declare function seedPersistedEnvelopeCache(metadata: Record<string, unknown> | null | undefined): number;
|
|
39
|
+
export declare function memoizedRegionEnvelope(source: string, options?: {
|
|
40
|
+
allowTerminalError?: boolean;
|
|
41
|
+
}): CanonicalBlockIR | null;
|
|
42
|
+
/** Merge an envelope into a block's metadata (no-op when not attachable). */
|
|
43
|
+
export declare function withIrEnvelope(source: string, metadata: Record<string, unknown> | undefined, options?: {
|
|
44
|
+
allowTerminalError?: boolean;
|
|
45
|
+
}): Record<string, unknown> | undefined;
|
|
@@ -0,0 +1,94 @@
|
|
|
1
|
+
import { IR_ENVELOPE_KEY } from "@ai-matrx/content-ir";
|
|
2
|
+
import { isIrEnvelopeCache } from "@ai-matrx/content-ir";
|
|
3
|
+
import { fingerprintText } from "@ai-matrx/content-ir";
|
|
4
|
+
import { captureError } from "../../host/diagnostics.js";
|
|
5
|
+
import { kindRegistry } from "../../host/kind-registry.js";
|
|
6
|
+
import { componentRegistry } from "../../host/component-registry.js";
|
|
7
|
+
import { normalizeJsonRegion } from "./kind-correctors.js";
|
|
8
|
+
import { canonicalizeCompletedLegacyQuizEnvelope } from "./legacy-quiz-envelope.js";
|
|
9
|
+
const memo = /* @__PURE__ */ new Map();
|
|
10
|
+
const MEMO_CAP = 200;
|
|
11
|
+
const seededByFingerprint = /* @__PURE__ */ new Map();
|
|
12
|
+
const SEED_CAP = 300;
|
|
13
|
+
const seenSeedSources = /* @__PURE__ */ new WeakSet();
|
|
14
|
+
function seedOne(envelope) {
|
|
15
|
+
if (envelope.root.status !== "complete") return;
|
|
16
|
+
if (seededByFingerprint.size >= SEED_CAP) seededByFingerprint.clear();
|
|
17
|
+
seededByFingerprint.set(envelope.fingerprint, envelope);
|
|
18
|
+
}
|
|
19
|
+
function seedEnvelope(envelope) {
|
|
20
|
+
if (seenSeedSources.has(envelope)) return;
|
|
21
|
+
seenSeedSources.add(envelope);
|
|
22
|
+
seedOne(envelope);
|
|
23
|
+
}
|
|
24
|
+
function seedPersistedEnvelopeCache(metadata) {
|
|
25
|
+
const candidate = metadata?.[IR_ENVELOPE_KEY];
|
|
26
|
+
if (candidate === void 0 || candidate === null) return 0;
|
|
27
|
+
if (typeof candidate !== "object") return 0;
|
|
28
|
+
if (seenSeedSources.has(candidate)) return 0;
|
|
29
|
+
seenSeedSources.add(candidate);
|
|
30
|
+
if (!isIrEnvelopeCache(candidate)) {
|
|
31
|
+
captureError({
|
|
32
|
+
source: "content-ir",
|
|
33
|
+
message: "persisted metadata.__ir envelope cache failed validation \u2014 ignored (no envelopes seeded); the writer that stamped it has a bug",
|
|
34
|
+
raw: candidate
|
|
35
|
+
});
|
|
36
|
+
return 0;
|
|
37
|
+
}
|
|
38
|
+
const envelopes = Object.values(candidate.blocks);
|
|
39
|
+
for (const envelope of envelopes) seedOne(envelope);
|
|
40
|
+
return envelopes.length;
|
|
41
|
+
}
|
|
42
|
+
function seededEnvelopeFor(source) {
|
|
43
|
+
if (seededByFingerprint.size === 0) return void 0;
|
|
44
|
+
return seededByFingerprint.get(fingerprintText(source));
|
|
45
|
+
}
|
|
46
|
+
function looksLikeCompleteJsonObject(trimmed) {
|
|
47
|
+
if (!trimmed.startsWith("{") || !trimmed.endsWith("}")) return false;
|
|
48
|
+
try {
|
|
49
|
+
const parsed = JSON.parse(trimmed);
|
|
50
|
+
return typeof parsed === "object" && parsed !== null && !Array.isArray(parsed);
|
|
51
|
+
} catch {
|
|
52
|
+
return false;
|
|
53
|
+
}
|
|
54
|
+
}
|
|
55
|
+
function memoizedRegionEnvelope(source, options = {}) {
|
|
56
|
+
const trimmed = source.trim();
|
|
57
|
+
if (!trimmed.startsWith("{")) return null;
|
|
58
|
+
const cached = memo.get(source);
|
|
59
|
+
if (cached && (cached.root.status === "complete" || options.allowTerminalError))
|
|
60
|
+
return cached;
|
|
61
|
+
const completeJson = looksLikeCompleteJsonObject(trimmed);
|
|
62
|
+
if (!completeJson && (!options.allowTerminalError || !trimmed.includes("__kind")))
|
|
63
|
+
return null;
|
|
64
|
+
const parseSource = source;
|
|
65
|
+
const existing = seededEnvelopeFor(parseSource);
|
|
66
|
+
const parsedEnvelope = normalizeJsonRegion(parseSource, {
|
|
67
|
+
schemas: kindRegistry.resolver(),
|
|
68
|
+
existing
|
|
69
|
+
});
|
|
70
|
+
const envelope = parsedEnvelope === existing ? parsedEnvelope : canonicalizeCompletedLegacyQuizEnvelope(parsedEnvelope, parseSource);
|
|
71
|
+
if (!completeJson && !envelope.root.kind) return null;
|
|
72
|
+
if (envelope.root.kind) {
|
|
73
|
+
void kindRegistry.ensureWarm();
|
|
74
|
+
void componentRegistry.ensureWarm();
|
|
75
|
+
}
|
|
76
|
+
const rootKind = envelope.root.kind;
|
|
77
|
+
const schemaStillUnknown = envelope.root.kindState === "pending_schema" || (envelope.root.kindState === "raw" || envelope.root.kindState === "unverified") && !!rootKind && kindRegistry.getSchema(rootKind) === void 0;
|
|
78
|
+
if (!schemaStillUnknown) {
|
|
79
|
+
if (memo.size >= MEMO_CAP) memo.clear();
|
|
80
|
+
memo.set(source, envelope);
|
|
81
|
+
}
|
|
82
|
+
return envelope;
|
|
83
|
+
}
|
|
84
|
+
function withIrEnvelope(source, metadata, options = {}) {
|
|
85
|
+
const envelope = memoizedRegionEnvelope(source, options);
|
|
86
|
+
if (!envelope) return metadata;
|
|
87
|
+
return { ...metadata ?? {}, [IR_ENVELOPE_KEY]: envelope };
|
|
88
|
+
}
|
|
89
|
+
export {
|
|
90
|
+
memoizedRegionEnvelope,
|
|
91
|
+
seedEnvelope,
|
|
92
|
+
seedPersistedEnvelopeCache,
|
|
93
|
+
withIrEnvelope
|
|
94
|
+
};
|
|
@@ -0,0 +1,38 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* THE INSTRUMENT — a read-only snapshot of the component resolver's own state,
|
|
3
|
+
* on the page, in production.
|
|
4
|
+
*
|
|
5
|
+
* WHY THIS EXISTS. Between 2026-09-13 and 2026-09-14, four lanes chased one
|
|
6
|
+
* live defect: on `/shapes/<kind>/instances` a reader was handed the platform's
|
|
7
|
+
* bundled component while their organization's authored one was already in the
|
|
8
|
+
* browser. Every lane reasoned from tests and server logs because nobody could
|
|
9
|
+
* see what the resolver actually held at the moment of the wrong render, and
|
|
10
|
+
* three of the resulting fixes were proven by a clean-root test and disproven
|
|
11
|
+
* by production. The missing thing was never analysis, it was an instrument.
|
|
12
|
+
*
|
|
13
|
+
* So: with `?matrxKindDebug=1` on any page (or once per tab, after the flag has
|
|
14
|
+
* been used once), `window.__matrxKindRegistryDebug(kind?)` answers with what
|
|
15
|
+
* the resolver holds RIGHT NOW — which tier answered, whether a body is bound,
|
|
16
|
+
* whether the kind's read was refused, whether the warm list has landed, and
|
|
17
|
+
* the repaint counter the render seam keys on.
|
|
18
|
+
*
|
|
19
|
+
* Rules it keeps:
|
|
20
|
+
* - READ-ONLY. It resolves, counts and copies; it never fetches, ingests,
|
|
21
|
+
* clears a verdict or mutates a registry. Calling it cannot change a render.
|
|
22
|
+
* - NEVER THROWS. Every field is guarded; a field it cannot read comes back
|
|
23
|
+
* `null` rather than taking the page down.
|
|
24
|
+
* - NO PAYLOADS. Component bodies are reported as LENGTHS, never as text, and
|
|
25
|
+
* no kind instance value is read at all — this is registry state, not data.
|
|
26
|
+
* - OFF BY DEFAULT. No flag, no global: `window.__matrxKindRegistryDebug` is
|
|
27
|
+
* simply absent, so nothing ships an always-on hook into a reader's page.
|
|
28
|
+
*/
|
|
29
|
+
import type { RichContentComponentRegistry as ComponentRegistry } from "../../host/types.js";
|
|
30
|
+
/** Query flag that arms the snapshot: `?matrxKindDebug=1`. */
|
|
31
|
+
export declare const KIND_REGISTRY_DEBUG_FLAG = "matrxKindDebug";
|
|
32
|
+
/** The global the flag installs. Named once, here. */
|
|
33
|
+
export declare const KIND_REGISTRY_DEBUG_GLOBAL = "__matrxKindRegistryDebug";
|
|
34
|
+
/**
|
|
35
|
+
* Install the snapshot global when the flag is armed. Idempotent, and a no-op
|
|
36
|
+
* on the server and on every un-flagged page.
|
|
37
|
+
*/
|
|
38
|
+
export declare function installKindRegistryDebug(registry: ComponentRegistry): void;
|
|
@@ -0,0 +1,39 @@
|
|
|
1
|
+
"use client";
|
|
2
|
+
const KIND_REGISTRY_DEBUG_FLAG = "matrxKindDebug";
|
|
3
|
+
const KIND_REGISTRY_DEBUG_GLOBAL = "__matrxKindRegistryDebug";
|
|
4
|
+
const DEBUG_LATCH_KEY = "matrx:kind-registry-debug";
|
|
5
|
+
function armed() {
|
|
6
|
+
if (typeof window === "undefined") return false;
|
|
7
|
+
try {
|
|
8
|
+
const flag = new URLSearchParams(window.location.search).get(
|
|
9
|
+
KIND_REGISTRY_DEBUG_FLAG
|
|
10
|
+
);
|
|
11
|
+
if (flag !== null && flag !== "0" && flag !== "false") {
|
|
12
|
+
try {
|
|
13
|
+
window.sessionStorage.setItem(DEBUG_LATCH_KEY, "1");
|
|
14
|
+
} catch {
|
|
15
|
+
}
|
|
16
|
+
return true;
|
|
17
|
+
}
|
|
18
|
+
return window.sessionStorage.getItem(DEBUG_LATCH_KEY) === "1";
|
|
19
|
+
} catch {
|
|
20
|
+
return false;
|
|
21
|
+
}
|
|
22
|
+
}
|
|
23
|
+
function installKindRegistryDebug(registry) {
|
|
24
|
+
if (!armed()) return;
|
|
25
|
+
const host = window;
|
|
26
|
+
if (typeof host[KIND_REGISTRY_DEBUG_GLOBAL] === "function") return;
|
|
27
|
+
host[KIND_REGISTRY_DEBUG_GLOBAL] = (kind) => {
|
|
28
|
+
try {
|
|
29
|
+
return registry.debugSnapshot(kind ?? null);
|
|
30
|
+
} catch (error) {
|
|
31
|
+
return { error: error instanceof Error ? error.message : String(error) };
|
|
32
|
+
}
|
|
33
|
+
};
|
|
34
|
+
}
|
|
35
|
+
export {
|
|
36
|
+
KIND_REGISTRY_DEBUG_FLAG,
|
|
37
|
+
KIND_REGISTRY_DEBUG_GLOBAL,
|
|
38
|
+
installKindRegistryDebug
|
|
39
|
+
};
|
|
@@ -0,0 +1,6 @@
|
|
|
1
|
+
import type { MarkdownCoreProps } from "./markdown-core-types.js";
|
|
2
|
+
export type { MarkdownCoreProps, MarkdownPreset } from "./markdown-core-types.js";
|
|
3
|
+
export declare function MarkdownCoreLoading({ error }: {
|
|
4
|
+
error?: Error | null;
|
|
5
|
+
}): import("react").JSX.Element | null;
|
|
6
|
+
export default function MarkdownCore({ streaming, children, ...rest }: MarkdownCoreProps): import("react").JSX.Element;
|
|
@@ -0,0 +1,32 @@
|
|
|
1
|
+
"use client";
|
|
2
|
+
import { jsx } from "react/jsx-runtime";
|
|
3
|
+
import { clientLazy } from "../utils/client-lazy.js";
|
|
4
|
+
import { healStreamingMarkdown } from "./stream-heal.js";
|
|
5
|
+
import { useMarkdownStreaming } from "./streaming-context.js";
|
|
6
|
+
function MarkdownCoreLoading({ error }) {
|
|
7
|
+
if (error) return null;
|
|
8
|
+
return /* @__PURE__ */ jsx(
|
|
9
|
+
"span",
|
|
10
|
+
{
|
|
11
|
+
"aria-hidden": true,
|
|
12
|
+
"data-markdown-loading": true,
|
|
13
|
+
className: "inline-block h-[1em] w-2/3 max-w-full animate-pulse rounded bg-muted align-middle"
|
|
14
|
+
}
|
|
15
|
+
);
|
|
16
|
+
}
|
|
17
|
+
const MarkdownCoreLeaf = clientLazy(() => import("./MarkdownCoreImpl.js"), {
|
|
18
|
+
loading: MarkdownCoreLoading
|
|
19
|
+
});
|
|
20
|
+
function MarkdownCore({
|
|
21
|
+
streaming,
|
|
22
|
+
children,
|
|
23
|
+
...rest
|
|
24
|
+
}) {
|
|
25
|
+
const inLiveStream = useMarkdownStreaming();
|
|
26
|
+
const isStreaming = streaming ?? inLiveStream;
|
|
27
|
+
return /* @__PURE__ */ jsx(MarkdownCoreLeaf, { ...rest, children: isStreaming ? healStreamingMarkdown(children) : children });
|
|
28
|
+
}
|
|
29
|
+
export {
|
|
30
|
+
MarkdownCoreLoading,
|
|
31
|
+
MarkdownCore as default
|
|
32
|
+
};
|
|
@@ -0,0 +1,27 @@
|
|
|
1
|
+
"use client";
|
|
2
|
+
import { jsx } from "react/jsx-runtime";
|
|
3
|
+
import ReactMarkdown from "react-markdown";
|
|
4
|
+
import "katex/dist/katex.min.css";
|
|
5
|
+
import { MARKDOWN_PRESETS, prepareCoreSource, rehypeWithNumbering, remarkWithNumbering } from "./markdown-core-presets.js";
|
|
6
|
+
import { useDocumentNumbering } from "./syntax/elements/DocumentNumbering.js";
|
|
7
|
+
import { withCoreSyntaxElements } from "./syntax/elements/core-syntax-elements.js";
|
|
8
|
+
function MarkdownCoreImpl({
|
|
9
|
+
children,
|
|
10
|
+
preset = "gfm",
|
|
11
|
+
components
|
|
12
|
+
}) {
|
|
13
|
+
const plugins = MARKDOWN_PRESETS[preset];
|
|
14
|
+
const numbering = useDocumentNumbering();
|
|
15
|
+
return /* @__PURE__ */ jsx(
|
|
16
|
+
ReactMarkdown,
|
|
17
|
+
{
|
|
18
|
+
remarkPlugins: remarkWithNumbering(plugins.remark, numbering),
|
|
19
|
+
rehypePlugins: rehypeWithNumbering(plugins.rehype, numbering),
|
|
20
|
+
components: withCoreSyntaxElements(components),
|
|
21
|
+
children: prepareCoreSource(children, preset, numbering)
|
|
22
|
+
}
|
|
23
|
+
);
|
|
24
|
+
}
|
|
25
|
+
export {
|
|
26
|
+
MarkdownCoreImpl as default
|
|
27
|
+
};
|