@ai-markdown/core 3.2.2 → 3.3.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/LICENSE +72 -0
- package/components/package.json +8 -0
- package/dist/components/index.cjs +555 -0
- package/dist/components/index.cjs.map +1 -0
- package/dist/components/index.d.cts +233 -0
- package/dist/components/index.d.ts +233 -0
- package/dist/components/index.js +528 -0
- package/dist/components/index.js.map +1 -0
- package/dist/index.cjs +932 -979
- package/dist/index.cjs.map +1 -1
- package/dist/index.d.cts +260 -326
- package/dist/index.d.ts +260 -326
- package/dist/index.dev.cjs +929 -979
- package/dist/index.dev.cjs.map +1 -1
- package/dist/index.dev.js +907 -944
- package/dist/index.dev.js.map +1 -1
- package/dist/index.js +910 -944
- package/dist/index.js.map +1 -1
- package/package.json +21 -5
package/dist/index.d.cts
CHANGED
|
@@ -1,116 +1,108 @@
|
|
|
1
|
-
import { Element,
|
|
2
|
-
import { Root } from
|
|
3
|
-
import {
|
|
4
|
-
export { isFootnoteSection } from '@ai-markdown/engine';
|
|
5
|
-
|
|
6
|
-
/** Framework-neutral block planning and dependency fingerprints.
|
|
7
|
-
* Cache ownership and conversion to framework nodes belong to adapters.
|
|
8
|
-
* See apps/docs/content/guides/architecture.md and packages/core/README.md for the contract.
|
|
9
|
-
*/
|
|
10
|
-
|
|
1
|
+
import { Element, Nodes, Root, RootContent } from "hast";
|
|
2
|
+
import { Root as Root$1 } from "mdast";
|
|
3
|
+
import { AdvanceOptions, ChunkData, PipelineOptions, Registry, isFootnoteSection } from "@ai-markdown/engine";
|
|
11
4
|
/** Source-level identity of one renderable hast block. */
|
|
12
5
|
interface BlockInfo {
|
|
13
|
-
|
|
14
|
-
|
|
15
|
-
|
|
16
|
-
|
|
17
|
-
|
|
18
|
-
|
|
19
|
-
|
|
20
|
-
|
|
21
|
-
|
|
22
|
-
|
|
23
|
-
|
|
24
|
-
|
|
25
|
-
|
|
26
|
-
|
|
27
|
-
|
|
28
|
-
|
|
29
|
-
|
|
30
|
-
|
|
31
|
-
|
|
32
|
-
|
|
33
|
-
|
|
34
|
-
|
|
35
|
-
|
|
36
|
-
|
|
37
|
-
|
|
38
|
-
|
|
39
|
-
|
|
40
|
-
|
|
41
|
-
|
|
42
|
-
|
|
43
|
-
|
|
44
|
-
|
|
45
|
-
|
|
46
|
-
|
|
47
|
-
|
|
48
|
-
|
|
49
|
-
|
|
50
|
-
|
|
51
|
-
|
|
52
|
-
|
|
53
|
-
|
|
54
|
-
|
|
55
|
-
|
|
56
|
-
|
|
57
|
-
|
|
58
|
-
|
|
59
|
-
|
|
60
|
-
|
|
61
|
-
|
|
62
|
-
|
|
63
|
-
|
|
64
|
-
|
|
65
|
-
|
|
66
|
-
|
|
67
|
-
|
|
68
|
-
|
|
69
|
-
|
|
70
|
-
|
|
71
|
-
|
|
72
|
-
|
|
73
|
-
|
|
74
|
-
|
|
75
|
-
|
|
76
|
-
|
|
77
|
-
|
|
78
|
-
|
|
79
|
-
|
|
80
|
-
|
|
81
|
-
|
|
82
|
-
|
|
83
|
-
|
|
84
|
-
|
|
85
|
-
|
|
86
|
-
|
|
87
|
-
|
|
88
|
-
|
|
89
|
-
|
|
90
|
-
|
|
91
|
-
|
|
92
|
-
|
|
93
|
-
|
|
94
|
-
|
|
95
|
-
|
|
96
|
-
|
|
97
|
-
|
|
98
|
-
|
|
99
|
-
|
|
100
|
-
|
|
101
|
-
|
|
102
|
-
|
|
6
|
+
raw: string;
|
|
7
|
+
startOffset: number;
|
|
8
|
+
endOffset: number;
|
|
9
|
+
/**
|
|
10
|
+
* Line and column at the block's start. Tracked alongside `startOffset`
|
|
11
|
+
* because two different source documents can produce the same byte offset
|
|
12
|
+
* for the "same" content (`A\n\nB\n\nTarget` vs `ABCD\n\nTarget` — both
|
|
13
|
+
* have `Target` starting at offset 6 but on different lines). Custom
|
|
14
|
+
* components that read `node.position.start.line` would otherwise see
|
|
15
|
+
* stale data from a false-positive cache hit.
|
|
16
|
+
*/
|
|
17
|
+
startLine: number;
|
|
18
|
+
startColumn: number;
|
|
19
|
+
/** True if the block contains any TAINT_TYPES node — invalidate on globalCtx change. */
|
|
20
|
+
hasReference: boolean;
|
|
21
|
+
/**
|
|
22
|
+
* Structural digest of the block's hast subtree, computed ONLY for blocks
|
|
23
|
+
* that originate from raw HTML (mdast `html` nodes, or blocks resolved via
|
|
24
|
+
* the range-containment fallback). Undefined for markdown-native blocks.
|
|
25
|
+
*
|
|
26
|
+
* Why it exists: rehype-raw applies the HTML parsing algorithm, so an
|
|
27
|
+
* UNCLOSED container tag (`<details>` mid-stream, before its `</details>`
|
|
28
|
+
* arrives) swallows every FOLLOWING top-level sibling into itself —
|
|
29
|
+
* including the synthetic `<section data-footnotes>`. The block's mdast
|
|
30
|
+
* identity (raw, position, ctx) is byte-identical across all those frames,
|
|
31
|
+
* so without this digest the first swallowed snapshot would be a permanent
|
|
32
|
+
* cache hit: content rendered inside the container freezes, and when the
|
|
33
|
+
* close tag finally arrives the real nodes re-render at top level while the
|
|
34
|
+
* stale copies stay trapped in the cached container (the "duplicate
|
|
35
|
+
* footnote section inside <details>" bug).
|
|
36
|
+
*
|
|
37
|
+
* Digest composition — `maxEnd:descendantCount:hasFootnoteSection:swallowedHash`:
|
|
38
|
+
* - max end offset over the subtree catches swallowed POSITIONED siblings
|
|
39
|
+
* (their offsets lie beyond the mdast node's own range);
|
|
40
|
+
* - descendant count catches position-less synthetic content moving in or
|
|
41
|
+
* out (the footnote section's own element carries no position, and its
|
|
42
|
+
* li contents point BACK at the definitions' offsets, which can be
|
|
43
|
+
* smaller than the container's end — maxEnd alone misses that case);
|
|
44
|
+
* - the explicit dataFootnotes bit closes the degenerate corner where a
|
|
45
|
+
* swallowed section and later real children tie on both numbers;
|
|
46
|
+
* - a hash of the swallowed extent's SOURCE (`[ownEnd, maxEnd)`) quickly
|
|
47
|
+
* rejects most equal-length, equal-shape replacements. A matching hash
|
|
48
|
+
* still requires an exact {@link BlockInfo.swallowedSource} comparison.
|
|
49
|
+
*
|
|
50
|
+
* Markdown-native blocks (paragraph/list/math/code/…) never receive
|
|
51
|
+
* reparented content — every hast descendant derives from their own mdast
|
|
52
|
+
* source range — so they skip the subtree walk entirely. This keeps the
|
|
53
|
+
* per-frame cost away from huge deterministic subtrees like KaTeX output.
|
|
54
|
+
*/
|
|
55
|
+
hastDigest?: string;
|
|
56
|
+
/**
|
|
57
|
+
* Exact source in the swallowed interval `[ownEnd, maxEnd)` of a raw-HTML
|
|
58
|
+
* block. The FNV-1a 32-bit hash in `hastDigest` can collide for different
|
|
59
|
+
* equal-length contents, so a cache hit must compare this string too.
|
|
60
|
+
* Empty when the block swallowed no source; absent for markdown-native
|
|
61
|
+
* blocks. Optional to keep existing public block-plan producers compatible.
|
|
62
|
+
*/
|
|
63
|
+
swallowedSource?: string;
|
|
64
|
+
/** A raw-HTML container that swallowed the synthesized
|
|
65
|
+
* `<section data-footnotes>` (rehype-raw reparents the following siblings
|
|
66
|
+
* into an unclosed `<details>` / `<div>` mid-stream). The footer is then
|
|
67
|
+
* NOT a top-level plan item, so coordinated mode's "skip the local
|
|
68
|
+
* footer, the aggregate renders it" rule never fired and the document
|
|
69
|
+
* showed two `<section data-footnotes>` with colliding li ids (2026-08-19
|
|
70
|
+
* review r2 P2-9). Coordinated renders strip it from this block's subtree;
|
|
71
|
+
* standalone renders keep it exactly where the full parse puts it. */
|
|
72
|
+
containsFootnoteSection?: boolean;
|
|
73
|
+
/** TAINT-block 专属:按节点类型分桶的 label set。Normalized 形态(uppercase)。
|
|
74
|
+
* Undefined when hasReference === false. */
|
|
75
|
+
taintLabels?: {
|
|
76
|
+
footnoteRefLabels: string[];
|
|
77
|
+
linkRefLabels: string[];
|
|
78
|
+
imageRefLabels: string[];
|
|
79
|
+
footnoteDefLabels: string[];
|
|
80
|
+
/** Chunk-local footnote state the engine baked into this block's
|
|
81
|
+
* `footnote-sup` placeholders (`localOccurrence` / `localNumber` come
|
|
82
|
+
* from a per-chunk counter over all PRECEDING refs, customMdastHandlers):
|
|
83
|
+
* per ref label, refs-before-this-block count and first-appearance
|
|
84
|
+
* rank. Same raw + same registry answers but a different prefix (an
|
|
85
|
+
* in-place `[^x]`→`[^w]` edit upstream) must miss the cache, or the
|
|
86
|
+
* stale occurrence resolves to a null global occurrence and the mark
|
|
87
|
+
* vanishes (2026-08-19 review P2-4). Absent when the block has no refs. */
|
|
88
|
+
footnoteRefLocalCtx?: string;
|
|
89
|
+
/** Baked `localUrl` / `localTitle` of swallowed `cross-chunk-link` /
|
|
90
|
+
* `-image` placeholders, as `[[label, url, title|null]…]` (JSON). The
|
|
91
|
+
* render falls back to these when the registry has no canonical def,
|
|
92
|
+
* where the fingerprint's `lr:`/`ir:` part is the constant `null` —
|
|
93
|
+
* see scanSwallowedSubtree. Absent when nothing was swallowed. */
|
|
94
|
+
swallowedDefCtx?: string;
|
|
95
|
+
};
|
|
103
96
|
}
|
|
104
|
-
|
|
105
97
|
/** Dev invariant: every block hast child must retain its mdast `position`. */
|
|
106
|
-
declare function hasMdastSource(node: Element): boolean;
|
|
98
|
+
export declare function hasMdastSource(node: Element): boolean;
|
|
107
99
|
/**
|
|
108
100
|
* Compute {@link BlockInfo.hastDigest} for a raw-HTML block: iterative walk
|
|
109
101
|
* over the hast subtree collecting (max end offset, descendant count,
|
|
110
102
|
* contains-footnote-section). See the field's JSDoc for why each component
|
|
111
103
|
* is load-bearing. Exported for tests.
|
|
112
104
|
*/
|
|
113
|
-
declare function computeHtmlBlockDigest(el: Element, source?: string, ownEnd?: number): string;
|
|
105
|
+
export declare function computeHtmlBlockDigest(el: Element, source?: string, ownEnd?: number): string;
|
|
114
106
|
/** {@link computeHtmlBlockDigest} plus the subtree's max end offset — the end
|
|
115
107
|
* of the SWALLOWED extent, which callers need to ask what fell inside.
|
|
116
108
|
*
|
|
@@ -124,9 +116,9 @@ declare function computeHtmlBlockDigest(el: Element, source?: string, ownEnd?: n
|
|
|
124
116
|
* opening tag. The descendant walk covers it a second time. Verified in
|
|
125
117
|
* 2026-08-20 A1 across 162 container/tail shapes: destroying either source
|
|
126
118
|
* alone changes nothing, destroying both under-taints 130 of them. */
|
|
127
|
-
declare function computeHtmlBlockDigestWithExtent(el: Element, source?: string, ownEnd?: number): {
|
|
128
|
-
|
|
129
|
-
|
|
119
|
+
export declare function computeHtmlBlockDigestWithExtent(el: Element, source?: string, ownEnd?: number): {
|
|
120
|
+
digest: string;
|
|
121
|
+
maxEnd: number;
|
|
130
122
|
};
|
|
131
123
|
/**
|
|
132
124
|
* One step of the document render plan, in source order.
|
|
@@ -145,45 +137,45 @@ declare function computeHtmlBlockDigestWithExtent(el: Element, source?: string,
|
|
|
145
137
|
* in a single slot keyed by `globalCtx`.
|
|
146
138
|
*/
|
|
147
139
|
type RenderItem = {
|
|
148
|
-
|
|
149
|
-
|
|
150
|
-
|
|
151
|
-
|
|
140
|
+
kind: 'block';
|
|
141
|
+
el: Element;
|
|
142
|
+
key: string;
|
|
143
|
+
info: BlockInfo;
|
|
152
144
|
} | {
|
|
153
|
-
|
|
154
|
-
|
|
155
|
-
|
|
145
|
+
kind: 'inline';
|
|
146
|
+
el: RootContent;
|
|
147
|
+
key: string;
|
|
156
148
|
} | {
|
|
157
|
-
|
|
158
|
-
|
|
159
|
-
|
|
149
|
+
kind: 'synthetic';
|
|
150
|
+
el: Element;
|
|
151
|
+
key: string;
|
|
160
152
|
};
|
|
161
153
|
/** Extra render-time facts {@link buildBlocks} cannot read off the trees. */
|
|
162
154
|
interface BuildBlocksOptions {
|
|
163
|
-
|
|
164
|
-
|
|
165
|
-
|
|
166
|
-
|
|
167
|
-
|
|
168
|
-
|
|
169
|
-
|
|
170
|
-
|
|
171
|
-
|
|
172
|
-
|
|
173
|
-
|
|
155
|
+
/** Full document when planning only a tail. Its ordered reference and
|
|
156
|
+
* definition context seeds numbering and invalidation for tail blocks. */
|
|
157
|
+
contextMdast?: Root$1;
|
|
158
|
+
/**
|
|
159
|
+
* Labels this chunk phantom-injected because another chunk defines them
|
|
160
|
+
* (already normalized). The coordinated handlers keep these out of
|
|
161
|
+
* `state.footnoteOrder`, so the cache key's rank must keep them out too —
|
|
162
|
+
* see the note in the rank pass. Empty / omitted in standalone mode, where
|
|
163
|
+
* no phantom injection happened.
|
|
164
|
+
*/
|
|
165
|
+
phantomFootnoteLabels?: ReadonlySet<string>;
|
|
174
166
|
}
|
|
175
167
|
/** Result of {@link buildBlocks}. */
|
|
176
168
|
interface BuildBlocksResult {
|
|
177
|
-
|
|
178
|
-
|
|
179
|
-
|
|
180
|
-
|
|
181
|
-
|
|
182
|
-
|
|
183
|
-
|
|
184
|
-
|
|
185
|
-
|
|
186
|
-
|
|
169
|
+
/** Render plan in document order — drives the adapter’s block cache. */
|
|
170
|
+
plan: RenderItem[];
|
|
171
|
+
/** JSON-stringified ordered list of TAINT-typed nodes in document order. */
|
|
172
|
+
globalCtx: string;
|
|
173
|
+
/** Flat list of `BlockInfo` for cacheable blocks, in document order. */
|
|
174
|
+
blocks: BlockInfo[];
|
|
175
|
+
/** 1:1 with `blocks` — the hast Element each BlockInfo refers to. */
|
|
176
|
+
blockHasts: Element[];
|
|
177
|
+
/** Synthesized footnote section, if present. */
|
|
178
|
+
synthetic?: Element;
|
|
187
179
|
}
|
|
188
180
|
/**
|
|
189
181
|
* Build the document render plan + ctx digest from a parsed mdast and its
|
|
@@ -217,7 +209,7 @@ interface BuildBlocksResult {
|
|
|
217
209
|
* numbering), then JSON-stringifies the collected tuples. That string is the
|
|
218
210
|
* invalidation key for tainted blocks and the synthetic footnote section.
|
|
219
211
|
*/
|
|
220
|
-
declare function buildBlocks(mdast: Root, hast: Root
|
|
212
|
+
export declare function buildBlocks(mdast: Root$1, hast: Root, source: string, options?: BuildBlocksOptions): BuildBlocksResult;
|
|
221
213
|
/**
|
|
222
214
|
* Compute a per-block cache fingerprint from the registry slice this block
|
|
223
215
|
* actually depends on (footnote/link/image refs and footnote defs). Two blocks
|
|
@@ -232,9 +224,8 @@ declare function buildBlocks(mdast: Root, hast: Root$1, source: string, options?
|
|
|
232
224
|
* @param thisChunkSym- The Symbol of the chunk this rendering belongs to (for canonical-vs-this comparison).
|
|
233
225
|
* @param clobberPrefix - The documentId-derived id prefix; included so href/id changes invalidate.
|
|
234
226
|
*/
|
|
235
|
-
declare function computeBlockFingerprint(taintLabels: NonNullable<BlockInfo['taintLabels']>, registry: Registry, thisChunkSym: symbol, clobberPrefix: string): string;
|
|
236
|
-
|
|
237
|
-
type BlockPlanner = (mdast: Root, hast: Root$1, source: string, options?: BuildBlocksOptions) => BuildBlocksResult;
|
|
227
|
+
export declare function computeBlockFingerprint(taintLabels: NonNullable<BlockInfo['taintLabels']>, registry: Registry, thisChunkSym: symbol, clobberPrefix: string): string;
|
|
228
|
+
type BlockPlanner = (mdast: Root$1, hast: Root, source: string, options?: BuildBlocksOptions) => BuildBlocksResult;
|
|
238
229
|
/** Reuse the engine's retained prefix plans, including reference blocks.
|
|
239
230
|
* Reference prefixes require full-document context when planning the tail.
|
|
240
231
|
* Raw HTML and definition regions retain complete planning: their ownership
|
|
@@ -242,42 +233,40 @@ type BlockPlanner = (mdast: Root, hast: Root$1, source: string, options?: BuildB
|
|
|
242
233
|
* guesses, establish which trees the incremental engine actually retained.
|
|
243
234
|
* Top-level traversal remains O(blocks); reference context still visits the
|
|
244
235
|
* full mdast when needed, while per-block HAST planning is tail-only. */
|
|
245
|
-
declare function createBlockPlanner(): BlockPlanner;
|
|
246
|
-
|
|
236
|
+
export declare function createBlockPlanner(): BlockPlanner;
|
|
247
237
|
/** Minimal write capability; registration and cleanup remain with the adapter. */
|
|
248
238
|
interface ContributionRegistry {
|
|
249
|
-
|
|
239
|
+
contributeChunkData(symbol: symbol, data: ChunkData): void;
|
|
250
240
|
}
|
|
251
241
|
interface ContributionOptions {
|
|
252
|
-
|
|
253
|
-
|
|
254
|
-
|
|
255
|
-
|
|
256
|
-
|
|
257
|
-
|
|
258
|
-
|
|
259
|
-
|
|
260
|
-
|
|
261
|
-
|
|
262
|
-
|
|
263
|
-
|
|
264
|
-
|
|
265
|
-
|
|
266
|
-
|
|
267
|
-
|
|
268
|
-
|
|
269
|
-
|
|
242
|
+
pipeline: {
|
|
243
|
+
mdast: Root$1;
|
|
244
|
+
hast: Root;
|
|
245
|
+
};
|
|
246
|
+
ownLabels: {
|
|
247
|
+
footnoteLabels: Set<string>;
|
|
248
|
+
linkLabels: Set<string>;
|
|
249
|
+
};
|
|
250
|
+
registry: ContributionRegistry | null;
|
|
251
|
+
targetPhantoms: {
|
|
252
|
+
missingFootnotes: Set<string>;
|
|
253
|
+
missingLinks: Set<string>;
|
|
254
|
+
};
|
|
255
|
+
sym: symbol | null;
|
|
256
|
+
clobberPrefix: string;
|
|
257
|
+
/** Stable identity tuple of parse inputs. Source equality alone cannot
|
|
258
|
+
* validate definition bodies after a plugin or schema change. */
|
|
259
|
+
chain: readonly unknown[];
|
|
270
260
|
}
|
|
271
261
|
interface ContributionSession {
|
|
272
|
-
|
|
262
|
+
commit(options: ContributionOptions): void;
|
|
273
263
|
}
|
|
274
264
|
/** Create one contribution publisher per mounted chunk.
|
|
275
265
|
* Call commit only in the host's commit/effect phase, after registration.
|
|
276
266
|
* Constructing a session does not register or publish anything. A discarded
|
|
277
267
|
* render must never call commit. The host owns registration and cleanup.
|
|
278
268
|
*/
|
|
279
|
-
declare function createContributionSession(): ContributionSession;
|
|
280
|
-
|
|
269
|
+
export declare function createContributionSession(): ContributionSession;
|
|
281
270
|
/**
|
|
282
271
|
* Turn-taking coordinator for smooth-streaming chunks that share a
|
|
283
272
|
* `documentId` under `<AIMarkdownDocuments>`.
|
|
@@ -307,42 +296,42 @@ declare function createContributionSession(): ContributionSession;
|
|
|
307
296
|
* @module components/smoothStream/coordinator
|
|
308
297
|
*/
|
|
309
298
|
interface SmoothCoordinator {
|
|
310
|
-
|
|
311
|
-
|
|
312
|
-
|
|
313
|
-
|
|
314
|
-
|
|
315
|
-
|
|
316
|
-
|
|
317
|
-
|
|
318
|
-
|
|
319
|
-
|
|
320
|
-
|
|
321
|
-
|
|
322
|
-
|
|
323
|
-
|
|
324
|
-
|
|
325
|
-
|
|
326
|
-
|
|
327
|
-
|
|
328
|
-
|
|
329
|
-
|
|
330
|
-
|
|
331
|
-
|
|
332
|
-
|
|
333
|
-
|
|
334
|
-
|
|
335
|
-
|
|
336
|
-
|
|
337
|
-
|
|
338
|
-
|
|
339
|
-
|
|
340
|
-
|
|
341
|
-
|
|
342
|
-
|
|
343
|
-
|
|
344
|
-
|
|
345
|
-
|
|
299
|
+
/** Chunk mount-order chunkId list. **Read-only** — mutation corrupts the
|
|
300
|
+
* release predicate for every successor. */
|
|
301
|
+
readonly order: readonly string[];
|
|
302
|
+
/** Chunk IDs that have reported done. Sticky: entries are only removed
|
|
303
|
+
* when the chunk unregisters. **Read-only.** */
|
|
304
|
+
readonly done: ReadonlySet<string>;
|
|
305
|
+
/** Reveal-progress heartbeat, ms timestamps from the reporting chunk's
|
|
306
|
+
* clock. Written WITHOUT a version bump (see module doc). */
|
|
307
|
+
readonly lastProgressAt: ReadonlyMap<string, number>;
|
|
308
|
+
/** Monotonic counter bumped by every gating-relevant mutation
|
|
309
|
+
* (register / unregister / done transition). */
|
|
310
|
+
readonly version: number;
|
|
311
|
+
subscribe(cb: () => void): () => void;
|
|
312
|
+
/** Allocate (or refcount-reuse, for Strict Mode remounts) this chunk's
|
|
313
|
+
* slot at the current end of the mount order. */
|
|
314
|
+
register(chunkId: string): void;
|
|
315
|
+
/** Refcount decrement with microtask-deferred reclaim; the last release
|
|
316
|
+
* removes the chunk from the order (waking successors) and, when the
|
|
317
|
+
* coordinator empties, fires the container's `onEmpty`. */
|
|
318
|
+
release(chunkId: string): void;
|
|
319
|
+
/** Sticky, idempotent: the first call per chunk bumps the version; the
|
|
320
|
+
* transition is never retracted while the chunk stays mounted (a
|
|
321
|
+
* predecessor that un-finishes must not re-gate successors). */
|
|
322
|
+
markDone(chunkId: string): void;
|
|
323
|
+
/** Heartbeat stamp — no version bump, no fanout. */
|
|
324
|
+
stampProgress(chunkId: string, at: number): void;
|
|
325
|
+
/** True when every registered chunk BEFORE `chunkId` in the order has
|
|
326
|
+
* reported done. Unregistered predecessors don't exist here, so they
|
|
327
|
+
* never block. A `chunkId` that is not (yet) registered itself is
|
|
328
|
+
* treated as sitting AFTER every registered chunk — a pre-registration
|
|
329
|
+
* query must not release a chunk whose predecessors are still
|
|
330
|
+
* revealing. */
|
|
331
|
+
isReleased(chunkId: string): boolean;
|
|
332
|
+
/** The earliest not-done registered chunk before `chunkId`, or null.
|
|
333
|
+
* Read by the dev-only stuck-flag warning timer. */
|
|
334
|
+
earliestBlockerOf(chunkId: string): string | null;
|
|
346
335
|
}
|
|
347
336
|
/** Outcome of one stuck-flag warning timer firing (dev-only diagnostics). */
|
|
348
337
|
type GateWarnVerdict = 'warn' | 'rearm' | 'clear';
|
|
@@ -360,54 +349,30 @@ type GateWarnVerdict = 'warn' | 'rearm' | 'clear';
|
|
|
360
349
|
* threshold while this chunk stayed gated — the predecessor's
|
|
361
350
|
* `streaming` flag is likely stuck.
|
|
362
351
|
*/
|
|
363
|
-
declare function evaluateGateWarn(coordinator: SmoothCoordinator, chunkId: string, nowMs: number, thresholdMs: number): GateWarnVerdict;
|
|
364
|
-
|
|
352
|
+
export declare function evaluateGateWarn(coordinator: SmoothCoordinator, chunkId: string, nowMs: number, thresholdMs: number): GateWarnVerdict;
|
|
365
353
|
/** Create one turn-taking scope.
|
|
366
354
|
* Why: sibling chunks coordinate reveal without a framework or DOM dependency.
|
|
367
355
|
* Recommended pattern: register after mount, report sticky completion, release on unmount.
|
|
368
356
|
* Footguns: registration order controls reveal; completion cannot be retracted.
|
|
369
357
|
*/
|
|
370
|
-
declare function createSmoothCoordinator(onEmpty?: () => void): SmoothCoordinator;
|
|
371
|
-
|
|
372
|
-
/**
|
|
373
|
-
* Source-tail classification for the streaming cursor.
|
|
374
|
-
*
|
|
375
|
-
* The cursor's DOM walk cannot know whether the source tail is in the body
|
|
376
|
-
* or inside a footnote definition — mdast-util-to-hast relocates every
|
|
377
|
-
* definition into the synthetic end-of-document footer, decoupling the
|
|
378
|
-
* footer's DOM position from source position. This module answers the
|
|
379
|
-
* question at the mdast level, where micromark has already made every
|
|
380
|
-
* grammar decision (lazy continuation lines, container nesting, blank-line
|
|
381
|
-
* attachment, label escapes): the renderer derives a signal per frame from
|
|
382
|
-
* the tree it is about to render and stamps it on a DOM marker the cursor
|
|
383
|
-
* shell reads in the same commit.
|
|
384
|
-
*
|
|
385
|
-
* Deliberately NOT a text scan of the trailing lines: a hand-rolled
|
|
386
|
-
* back-walk would be a third parallel grammar in the repo and provably
|
|
387
|
-
* mis-classifies lazy continuations (`[^1]: line\nline2` keeps line2 in
|
|
388
|
-
* the definition with zero indentation), resurfacing the exact bug this
|
|
389
|
-
* exists to fix.
|
|
390
|
-
*
|
|
391
|
-
* @module components/streamingCursor/tailSignal
|
|
392
|
-
*/
|
|
393
|
-
|
|
394
|
-
type TailSignal =
|
|
358
|
+
export declare function createSmoothCoordinator(onEmpty?: () => void): SmoothCoordinator;
|
|
359
|
+
type TailSignal =
|
|
395
360
|
/** The source tail is inside a footnote definition — its text renders in
|
|
396
361
|
* the footnote footer's `<li>` for `identifier` (mdast's case-folded
|
|
397
362
|
* form), not at the body tail. */
|
|
398
363
|
{
|
|
399
|
-
|
|
400
|
-
|
|
401
|
-
}
|
|
364
|
+
kind: 'footnote-def';
|
|
365
|
+
identifier: string;
|
|
366
|
+
} |
|
|
402
367
|
/** The source tail is inside a link-reference definition — it renders
|
|
403
368
|
* nothing at all; the cursor should hide rather than point at stale
|
|
404
369
|
* body text. */
|
|
405
|
-
|
|
406
|
-
|
|
407
|
-
}
|
|
370
|
+
{
|
|
371
|
+
kind: 'invisible-def';
|
|
372
|
+
} |
|
|
408
373
|
/** The source tail is ordinary body content — the DOM-tail heuristic is
|
|
409
374
|
* correct as-is. */
|
|
410
|
-
|
|
375
|
+
null;
|
|
411
376
|
/**
|
|
412
377
|
* Classify the source tail of `mdast`.
|
|
413
378
|
*
|
|
@@ -422,114 +387,83 @@ type TailSignal =
|
|
|
422
387
|
* several phantoms is a normal shape) and classifies the first real
|
|
423
388
|
* node.
|
|
424
389
|
*/
|
|
425
|
-
declare function deriveTailSignal(mdast: Root, contentLength: number): TailSignal;
|
|
426
|
-
|
|
427
|
-
/** Assemble document footnotes as HAST without framework nodes or DOM access. */
|
|
428
|
-
|
|
429
|
-
declare function buildAggregateTree(registry: Registry, clobberPrefix: string, preserveOrphanReferences?: boolean): Element | null;
|
|
430
|
-
|
|
431
|
-
/**
|
|
432
|
-
* Structural clone of a hast subtree for render-time use.
|
|
433
|
-
*
|
|
434
|
-
* Copies exactly what the render-time mutators touch — every node object,
|
|
435
|
-
* its `children` array (the allow/disallow filters splice it), and its
|
|
436
|
-
* `properties` object (`urlTransform` overwrites `href`/`src`) — while
|
|
437
|
-
* SHARING `position`, arbitrary nested plugin data, string values, and individual property values
|
|
438
|
-
* by reference. This is both cheaper than a JSON round-trip (no string
|
|
439
|
-
* intermediate; `position` objects, typically over half of a serialized
|
|
440
|
-
* hast, are never materialized) and exact for any tree the pipeline
|
|
441
|
-
* produces (no lossy JSON semantics to reason about).
|
|
442
|
-
*
|
|
443
|
-
* @module components/cloneHastForRender
|
|
444
|
-
*/
|
|
445
|
-
|
|
390
|
+
export declare function deriveTailSignal(mdast: Root$1, contentLength: number): TailSignal;
|
|
391
|
+
export declare function buildAggregateTree(registry: Registry, clobberPrefix: string, preserveOrphanReferences?: boolean): Element | null;
|
|
446
392
|
/** See module docs. Safe for any hast node union member. */
|
|
447
|
-
declare function cloneHastForRender<T extends Nodes>(node: T): T;
|
|
448
|
-
|
|
449
|
-
/** Per-consumer parse state and full/incremental fallback policy.
|
|
450
|
-
* The host decides whether a next frame is expected (false for SSR), owns
|
|
451
|
-
* this session, and resets it when render policy invalidates retained trees.
|
|
452
|
-
* Parsing does not register chunks or publish document contributions.
|
|
453
|
-
* Fallback order: incremental → full pipeline → plain-text frame, the last
|
|
454
|
-
* step ONLY for the engine's raw-depth signal (see plainTextTrees); any
|
|
455
|
-
* other full-pipeline throw, a consumer plugin's included, escapes `parse`.
|
|
456
|
-
*/
|
|
457
|
-
|
|
393
|
+
export declare function cloneHastForRender<T extends Nodes>(node: T): T;
|
|
458
394
|
interface PipelineTrees {
|
|
459
|
-
|
|
460
|
-
|
|
395
|
+
mdast: Root$1;
|
|
396
|
+
hast: Root;
|
|
461
397
|
}
|
|
462
398
|
interface PipelineSession {
|
|
463
|
-
|
|
464
|
-
|
|
465
|
-
|
|
466
|
-
|
|
399
|
+
/** Drop retained incremental state. Does not dispose host subscriptions. */
|
|
400
|
+
reset(): void;
|
|
401
|
+
/** Read-only borrowed trees: clone before destructive rendering. */
|
|
402
|
+
parse(options: PipelineFrameOptions): PipelineTrees;
|
|
467
403
|
}
|
|
468
404
|
type RemarkRehypeOptions = NonNullable<PipelineOptions['remarkRehypeOptions']>;
|
|
469
405
|
interface PipelineFrameOptions {
|
|
470
|
-
|
|
471
|
-
|
|
472
|
-
|
|
473
|
-
|
|
474
|
-
|
|
475
|
-
|
|
476
|
-
|
|
477
|
-
|
|
478
|
-
|
|
479
|
-
|
|
480
|
-
|
|
481
|
-
|
|
482
|
-
|
|
483
|
-
|
|
484
|
-
|
|
485
|
-
|
|
486
|
-
|
|
487
|
-
|
|
488
|
-
|
|
489
|
-
|
|
490
|
-
|
|
491
|
-
|
|
492
|
-
|
|
493
|
-
|
|
494
|
-
|
|
495
|
-
|
|
496
|
-
|
|
497
|
-
|
|
498
|
-
|
|
499
|
-
|
|
500
|
-
|
|
501
|
-
|
|
502
|
-
|
|
406
|
+
content: string;
|
|
407
|
+
targetPhantoms: {
|
|
408
|
+
missingFootnotes: Set<string>;
|
|
409
|
+
missingLinks: Set<string>;
|
|
410
|
+
};
|
|
411
|
+
remarkPlugins: PipelineOptions['remarkPlugins'];
|
|
412
|
+
rehypePlugins: PipelineOptions['rehypePlugins'];
|
|
413
|
+
remarkRehypeOptions: PipelineOptions['remarkRehypeOptions'];
|
|
414
|
+
handlers?: RemarkRehypeOptions['handlers'];
|
|
415
|
+
preserveForBodyHarvest: boolean;
|
|
416
|
+
documentId: string;
|
|
417
|
+
provenance: string;
|
|
418
|
+
/** False for a one-shot server render; no browser-global probe is needed. */
|
|
419
|
+
incrementalParse: boolean;
|
|
420
|
+
defListEnabled: boolean;
|
|
421
|
+
/** Whether `remarkPlugins` parses GFM task-list items. Default `false`
|
|
422
|
+
* (the boundary scanner keeps every `[x]` as reference taint). The
|
|
423
|
+
* adapters pass `true` because they build the chain with
|
|
424
|
+
* `buildCoreRemarkPlugins`, which always includes remark-gfm. A box
|
|
425
|
+
* whose paragraph a `$$` opener closed is released only when
|
|
426
|
+
* `mathFlow` is `true` as well. */
|
|
427
|
+
gfmTaskListItems?: boolean;
|
|
428
|
+
/** Whether `remarkPlugins` parses `$$` flow math (remark-math). Passed
|
|
429
|
+
* through to the engine in all three states: `true` declares it (a
|
|
430
|
+
* `$$` region is verbatim math), `false` declares its absence (`$$`
|
|
431
|
+
* lines are paragraph text), and omitted leaves it unknown — the
|
|
432
|
+
* scanner then takes the union of both grammars, which is correct for
|
|
433
|
+
* either chain and freezes less around `$$`. The adapters pass `true`
|
|
434
|
+
* because `buildCoreRemarkPlugins` always includes remark-math; a
|
|
435
|
+
* caller with its own chain should declare the real value and may
|
|
436
|
+
* leave it out when unsure. */
|
|
437
|
+
mathFlow?: boolean;
|
|
438
|
+
measure?: AdvanceOptions['measure'];
|
|
503
439
|
}
|
|
504
|
-
declare function createPipelineSession(): PipelineSession;
|
|
505
|
-
|
|
440
|
+
export declare function createPipelineSession(): PipelineSession;
|
|
506
441
|
interface DefinitionLabels {
|
|
507
|
-
|
|
508
|
-
|
|
442
|
+
footnoteLabels: ReadonlySet<string>;
|
|
443
|
+
linkLabels: ReadonlySet<string>;
|
|
509
444
|
}
|
|
510
445
|
type PhantomTargets = PipelineFrameOptions['targetPhantoms'];
|
|
511
|
-
declare function derivePhantomTargets({ content, ownLabels, labels }: {
|
|
512
|
-
|
|
513
|
-
|
|
514
|
-
|
|
446
|
+
export declare function derivePhantomTargets({ content, ownLabels, labels }: {
|
|
447
|
+
content: string;
|
|
448
|
+
ownLabels: DefinitionLabels;
|
|
449
|
+
labels: DefinitionLabels | null;
|
|
515
450
|
}, previous?: PhantomTargets): PhantomTargets;
|
|
516
451
|
interface CoordinationPolicy {
|
|
517
|
-
|
|
518
|
-
|
|
519
|
-
|
|
452
|
+
mode: 'coordinated' | 'orphan' | 'standalone';
|
|
453
|
+
handlers: PipelineFrameOptions['handlers'];
|
|
454
|
+
preserveForBodyHarvest: boolean;
|
|
520
455
|
}
|
|
521
|
-
declare function deriveCoordinationPolicy({ coordinated, registered, preserveOrphanReferences
|
|
522
|
-
|
|
523
|
-
|
|
524
|
-
|
|
525
|
-
|
|
456
|
+
export declare function deriveCoordinationPolicy({ coordinated, registered, preserveOrphanReferences }: {
|
|
457
|
+
coordinated: boolean;
|
|
458
|
+
registered: boolean;
|
|
459
|
+
/** The host has already resolved any wrapper-level override. */
|
|
460
|
+
preserveOrphanReferences: boolean;
|
|
526
461
|
}, previous?: CoordinationPolicy): CoordinationPolicy;
|
|
527
462
|
type ContributionPolicyInputs = Pick<PipelineFrameOptions, 'remarkPlugins' | 'rehypePlugins' | 'remarkRehypeOptions' | 'handlers' | 'preserveForBodyHarvest' | 'documentId' | 'provenance'> & {
|
|
528
|
-
|
|
463
|
+
clobberPrefix: string;
|
|
529
464
|
};
|
|
530
465
|
/** Source/phantom/registry/symbol changes are compared by the publisher itself.
|
|
531
466
|
* This tuple covers the remaining inputs that can alter harvested bodies.
|
|
532
467
|
*/
|
|
533
|
-
declare function buildContributionChain(inputs: ContributionPolicyInputs): readonly unknown[];
|
|
534
|
-
|
|
535
|
-
export { type BlockInfo, type BlockPlanner, type BuildBlocksOptions, type BuildBlocksResult, type ContributionOptions, type ContributionPolicyInputs, type ContributionRegistry, type ContributionSession, type CoordinationPolicy, type DefinitionLabels, type GateWarnVerdict, type PhantomTargets, type PipelineFrameOptions, type PipelineSession, type PipelineTrees, type RenderItem, type SmoothCoordinator, type TailSignal, buildAggregateTree, buildBlocks, buildContributionChain, cloneHastForRender, computeBlockFingerprint, computeHtmlBlockDigest, computeHtmlBlockDigestWithExtent, createBlockPlanner, createContributionSession, createPipelineSession, createSmoothCoordinator, deriveCoordinationPolicy, derivePhantomTargets, deriveTailSignal, evaluateGateWarn, hasMdastSource };
|
|
468
|
+
export declare function buildContributionChain(inputs: ContributionPolicyInputs): readonly unknown[];
|
|
469
|
+
export { type BlockInfo, type BlockPlanner, type BuildBlocksOptions, type BuildBlocksResult, type ContributionOptions, type ContributionPolicyInputs, type ContributionRegistry, type ContributionSession, type CoordinationPolicy, type DefinitionLabels, type GateWarnVerdict, type PhantomTargets, type PipelineFrameOptions, type PipelineSession, type PipelineTrees, type RenderItem, type SmoothCoordinator, type TailSignal, isFootnoteSection };
|