@microsoft/webui-framework 0.0.19 → 0.0.21

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.
Files changed (46) hide show
  1. package/README.md +73 -22
  2. package/dist/component-asset/asset.d.ts +22 -0
  3. package/dist/component-asset/asset.js +171 -0
  4. package/dist/component-asset/loader.d.ts +1 -0
  5. package/dist/component-asset/loader.js +104 -0
  6. package/dist/component-asset/manifest.d.ts +20 -0
  7. package/dist/component-asset/manifest.js +1 -0
  8. package/dist/component-asset/resources.d.ts +4 -0
  9. package/dist/component-asset/resources.js +83 -0
  10. package/dist/component-asset.d.ts +3 -29
  11. package/dist/component-asset.js +1 -135
  12. package/dist/element.d.ts +0 -4
  13. package/dist/element.js +8 -67
  14. package/dist/lifecycle.d.ts +17 -0
  15. package/dist/lifecycle.js +66 -3
  16. package/dist/static-host.js +4 -2
  17. package/dist/streaming-activation.d.ts +2 -0
  18. package/dist/streaming-activation.js +13 -0
  19. package/dist/streaming-bootstrap.d.ts +2 -0
  20. package/dist/streaming-bootstrap.js +48 -0
  21. package/dist/streaming-cleanup.d.ts +4 -0
  22. package/dist/streaming-cleanup.js +66 -0
  23. package/dist/streaming-coordinator.d.ts +7 -0
  24. package/dist/streaming-coordinator.js +364 -0
  25. package/dist/streaming-deferred.d.ts +22 -0
  26. package/dist/streaming-deferred.js +287 -0
  27. package/dist/streaming-dom.d.ts +32 -0
  28. package/dist/streaming-dom.js +148 -0
  29. package/dist/streaming-entry.d.ts +1 -0
  30. package/dist/streaming-entry.js +2 -0
  31. package/dist/streaming-install.d.ts +2 -0
  32. package/dist/streaming-install.js +25 -0
  33. package/dist/streaming-mode.d.ts +5 -0
  34. package/dist/streaming-mode.js +14 -0
  35. package/dist/streaming-protocol.d.ts +32 -0
  36. package/dist/streaming-protocol.js +27 -0
  37. package/dist/streaming-state.d.ts +1 -0
  38. package/dist/streaming-state.js +13 -0
  39. package/dist/streaming.d.ts +5 -0
  40. package/dist/streaming.js +9 -0
  41. package/dist/template-element.d.ts +9 -1
  42. package/dist/template-element.js +112 -42
  43. package/dist/template-types.d.ts +1 -1
  44. package/dist/template.d.ts +2 -0
  45. package/dist/template.js +74 -25
  46. package/package.json +9 -3
@@ -1,12 +1,4 @@
1
- import { getTemplate, registerTemplateData, } from './template.js';
2
- const ASSET_TYPE = 'webui-component-asset';
3
- const ASSET_VERSION = 1;
4
- const injectedAssetStyles = new Set();
5
- const assetLoadPromises = new Map();
6
- let assetStylesSeeded = false;
7
- function assetGlobal() {
8
- return window.__webui;
9
- }
1
+ import { loadComponentAsset } from './component-asset/loader.js';
10
2
  export function defineComponentAssets(manifest) {
11
3
  const preloads = new Map();
12
4
  function preload(tag) {
@@ -85,129 +77,3 @@ function dataWithTimeout(data, timeoutMs) {
85
77
  }),
86
78
  ]);
87
79
  }
88
- function loadComponentAsset(tag, url) {
89
- if (getTemplate(tag))
90
- return Promise.resolve();
91
- const assetUrl = new URL(url, document.baseURI);
92
- const href = assetUrl.href;
93
- let promise = assetLoadPromises.get(href);
94
- if (promise)
95
- return promise;
96
- promise = importAndRegisterComponentAsset(assetUrl)
97
- .finally(() => {
98
- assetLoadPromises.delete(href);
99
- });
100
- assetLoadPromises.set(href, promise);
101
- return promise;
102
- }
103
- function registerComponentAsset(asset) {
104
- validateAsset(asset);
105
- if (asset.templates && templatesAlreadyRegistered(asset.templates))
106
- return;
107
- registerAssetStyles(asset.templateStyles, readNonce());
108
- if (asset.templates) {
109
- registerTemplateData(asset.templates, asset.templateFunctions);
110
- }
111
- }
112
- async function importAndRegisterComponentAsset(assetUrl) {
113
- const imported = await import(assetUrl.href);
114
- registerComponentAsset(readComponentAssetModule(imported));
115
- }
116
- function readComponentAssetModule(module) {
117
- if (!isObject(module) || !isObject(module.default)) {
118
- throw new Error('[WebUI] Component asset module must default-export an asset object.');
119
- }
120
- return module.default;
121
- }
122
- function isObject(value) {
123
- return typeof value === 'object' && value !== null;
124
- }
125
- function validateAsset(asset) {
126
- if (asset.type !== ASSET_TYPE) {
127
- throw new Error(`[WebUI] Invalid component asset type: ${String(asset.type)}`);
128
- }
129
- if (asset.version !== ASSET_VERSION) {
130
- throw new Error(`[WebUI] Unsupported component asset version: ${String(asset.version)}`);
131
- }
132
- }
133
- function templatesAlreadyRegistered(templates) {
134
- const tags = Object.keys(templates);
135
- if (tags.length === 0)
136
- return false;
137
- for (let i = 0; i < tags.length; i++) {
138
- if (!getTemplate(tags[i]))
139
- return false;
140
- }
141
- return true;
142
- }
143
- function readNonce() {
144
- const nonce = assetGlobal()?.nonce;
145
- if (nonce)
146
- return nonce;
147
- const meta = document.querySelector('meta[name="webui-nonce"]');
148
- return meta?.content ?? '';
149
- }
150
- function seedAssetStyleSet() {
151
- if (assetStylesSeeded)
152
- return;
153
- assetStylesSeeded = true;
154
- const styles = assetGlobal()?.styles;
155
- if (!styles)
156
- return;
157
- for (let i = 0; i < styles.length; i++) {
158
- injectedAssetStyles.add(styles[i]);
159
- }
160
- }
161
- function registerAssetStyles(templateStyles, nonce) {
162
- if (!templateStyles || templateStyles.length === 0)
163
- return;
164
- seedAssetStyleSet();
165
- for (let i = 0; i < templateStyles.length; i++) {
166
- const imports = parseImportMap(templateStyles[i]);
167
- const nextImports = {};
168
- let hasNewImport = false;
169
- const specifiers = Object.keys(imports);
170
- for (let j = 0; j < specifiers.length; j++) {
171
- const specifier = specifiers[j];
172
- if (injectedAssetStyles.has(specifier))
173
- continue;
174
- injectedAssetStyles.add(specifier);
175
- nextImports[specifier] = imports[specifier];
176
- hasNewImport = true;
177
- }
178
- if (!hasNewImport)
179
- continue;
180
- const script = document.createElement('script');
181
- script.type = 'importmap';
182
- if (nonce)
183
- script.nonce = nonce;
184
- script.textContent = JSON.stringify({ imports: nextImports });
185
- document.head.appendChild(script);
186
- }
187
- }
188
- function parseImportMap(scriptMarkup) {
189
- const trimmed = scriptMarkup.trim();
190
- if (!trimmed.startsWith('<script')) {
191
- throw new Error('[WebUI] Component asset templateStyles entry must be a <script type="importmap"> tag.');
192
- }
193
- const openTagEnd = trimmed.indexOf('>');
194
- const closeTagStart = trimmed.lastIndexOf('</script>');
195
- if (openTagEnd < 0 || closeTagStart <= openTagEnd) {
196
- throw new Error('[WebUI] Component asset importmap tag is malformed.');
197
- }
198
- const parsed = JSON.parse(trimmed.substring(openTagEnd + 1, closeTagStart));
199
- if (!parsed.imports || typeof parsed.imports !== 'object') {
200
- throw new Error('[WebUI] Component asset importmap is missing an imports object.');
201
- }
202
- const imports = {};
203
- const specifiers = Object.keys(parsed.imports);
204
- for (let i = 0; i < specifiers.length; i++) {
205
- const specifier = specifiers[i];
206
- const uri = parsed.imports[specifier];
207
- if (typeof uri !== 'string' || !uri.startsWith('data:text/css,')) {
208
- throw new Error(`[WebUI] Component asset importmap entry "${specifier}" must be a data:text/css URI.`);
209
- }
210
- imports[specifier] = uri;
211
- }
212
- return imports;
213
- }
package/dist/element.d.ts CHANGED
@@ -8,14 +8,10 @@ export declare class WebUIElement extends TemplateElement {
8
8
  $emit(name: string, detail?: unknown): boolean;
9
9
  protected $finalize(instance: TemplateInstance, root: Node, meta: TemplateBlockMeta, resolver: (root: Node, path: TemplateNodePath) => Node | null, scope?: ScopeFrame): void;
10
10
  private $wireEvents;
11
- private $resolveDelegatedEvents;
12
11
  private $wireRoot;
13
- private $addDelegatedEvent;
14
- private $dispatchDelegatedEvent;
15
12
  private $addEvent;
16
13
  private $addCleanup;
17
14
  private $callEventHandler;
18
- private $callEventHandlerWithCurrentTarget;
19
15
  private $resolveEventArgs;
20
16
  private $resolveEventArg;
21
17
  private $wireRefs;
package/dist/element.js CHANGED
@@ -29,32 +29,16 @@ export class WebUIElement extends TemplateElement {
29
29
  const groups = meta.eg;
30
30
  if (!groups)
31
31
  return;
32
- const delegateTarget = this.shadowRoot ?? this;
33
32
  for (let i = 0; i < groups.length; i++) {
34
33
  const [eventName, bindings] = groups[i];
35
- const bucket = this.$resolveDelegatedEvents(root, bindings, resolver, scope);
36
- this.$addDelegatedEvent(instance, delegateTarget, eventName, bucket);
37
- }
38
- }
39
- $resolveDelegatedEvents(root, bindings, resolver, scope) {
40
- const entries = [];
41
- for (let i = 0; i < bindings.length; i++) {
42
- const [handlerName, args, target, usesEvent] = bindings[i];
43
- const el = resolver(root, target);
44
- if (!el || el.nodeType !== 1)
45
- continue;
46
- const method = this[handlerName];
47
- if (typeof method !== 'function')
48
- continue;
49
- entries.push({
50
- target: el,
51
- method: method,
52
- args,
53
- usesEvent: usesEvent === 1,
54
- scope,
55
- });
34
+ for (let j = 0; j < bindings.length; j++) {
35
+ const [handlerName, args, target] = bindings[j];
36
+ const el = resolver(root, target);
37
+ if (el && el.nodeType === 1) {
38
+ this.$addEvent(instance, el, eventName, handlerName, args, scope);
39
+ }
40
+ }
56
41
  }
57
- return entries;
58
42
  }
59
43
  $wireRoot(instance, re) {
60
44
  const target = this.shadowRoot ?? this;
@@ -62,27 +46,6 @@ export class WebUIElement extends TemplateElement {
62
46
  this.$addEvent(instance, target, re[i][0], re[i][1], re[i][2], undefined);
63
47
  }
64
48
  }
65
- $addDelegatedEvent(instance, target, eventName, entries) {
66
- if (entries.length === 0)
67
- return;
68
- const listener = (event) => {
69
- this.$dispatchDelegatedEvent(entries, event);
70
- };
71
- target.addEventListener(eventName, listener);
72
- this.$addCleanup(instance, () => target.removeEventListener(eventName, listener));
73
- }
74
- $dispatchDelegatedEvent(entries, event) {
75
- let current = event.target;
76
- while (current) {
77
- for (let i = 0; i < entries.length; i++) {
78
- const entry = entries[i];
79
- if (entry.target === current) {
80
- this.$callEventHandler(entry.method, entry.args, event, entry.scope, entry.target, entry.usesEvent);
81
- }
82
- }
83
- current = current.parentNode;
84
- }
85
- }
86
49
  $addEvent(instance, target, eventName, handlerName, args, scope) {
87
50
  const method = this[handlerName];
88
51
  if (typeof method !== 'function')
@@ -94,11 +57,7 @@ export class WebUIElement extends TemplateElement {
94
57
  $addCleanup(instance, cleanup) {
95
58
  (instance.cleanups ??= []).push(cleanup);
96
59
  }
97
- $callEventHandler(method, args, event, scope, currentTarget, usesEvent = false) {
98
- if (currentTarget && usesEvent) {
99
- this.$callEventHandlerWithCurrentTarget(method, args, event, scope, currentTarget);
100
- return;
101
- }
60
+ $callEventHandler(method, args, event, scope) {
102
61
  switch (args.length) {
103
62
  case 0:
104
63
  method.call(this);
@@ -119,24 +78,6 @@ export class WebUIElement extends TemplateElement {
119
78
  method.apply(this, this.$resolveEventArgs(args, event, scope));
120
79
  }
121
80
  }
122
- $callEventHandlerWithCurrentTarget(method, args, event, scope, currentTarget) {
123
- const descriptor = Object.getOwnPropertyDescriptor(event, 'currentTarget');
124
- Object.defineProperty(event, 'currentTarget', {
125
- configurable: true,
126
- value: currentTarget,
127
- });
128
- try {
129
- this.$callEventHandler(method, args, event, scope);
130
- }
131
- finally {
132
- if (descriptor) {
133
- Object.defineProperty(event, 'currentTarget', descriptor);
134
- }
135
- else {
136
- delete event.currentTarget;
137
- }
138
- }
139
- }
140
81
  $resolveEventArgs(args, event, scope) {
141
82
  const resolved = [];
142
83
  for (let i = 0; i < args.length; i++) {
@@ -1,2 +1,19 @@
1
1
  export declare function hydrationStart(): void;
2
2
  export declare function hydrationEnd(): void;
3
+ export declare function beginStreamingGate(): void;
4
+ export declare function abortStreamingGate(): void;
5
+ export declare function markBoundaryPending(): void;
6
+ export declare function markBoundaryCommitted(terminal: boolean): void;
7
+ export declare function markLateActivationPending(): void;
8
+ export declare function settleLateActivation(): void;
9
+ export declare function __getLifecycleStateForTests(): {
10
+ pendingCount: number;
11
+ started: boolean;
12
+ completed: boolean;
13
+ streamingGateActive: boolean;
14
+ streamingGateAborted: boolean;
15
+ terminalReached: boolean;
16
+ pendingBoundaries: number;
17
+ pendingLateActivations: number;
18
+ };
19
+ export declare function __resetLifecycleForTests(): void;
package/dist/lifecycle.js CHANGED
@@ -1,6 +1,11 @@
1
1
  let pendingCount = 0;
2
2
  let started = false;
3
3
  let completed = false;
4
+ let streamingGateActive = false;
5
+ let terminalReached = false;
6
+ let streamingGateAborted = false;
7
+ let pendingBoundaries = 0;
8
+ let pendingLateActivations = 0;
4
9
  export function hydrationStart() {
5
10
  if (!started) {
6
11
  performance.mark('webui:hydrate:total:start');
@@ -9,11 +14,69 @@ export function hydrationStart() {
9
14
  pendingCount++;
10
15
  }
11
16
  export function hydrationEnd() {
17
+ if (pendingCount === 0)
18
+ return;
12
19
  pendingCount--;
13
- if (pendingCount <= 0 && !completed) {
14
- completed = true;
20
+ tryComplete();
21
+ }
22
+ export function beginStreamingGate() {
23
+ streamingGateActive = true;
24
+ }
25
+ export function abortStreamingGate() {
26
+ streamingGateAborted = true;
27
+ }
28
+ export function markBoundaryPending() {
29
+ pendingBoundaries++;
30
+ }
31
+ export function markBoundaryCommitted(terminal) {
32
+ if (pendingBoundaries === 0)
33
+ return;
34
+ pendingBoundaries--;
35
+ if (terminal)
36
+ terminalReached = true;
37
+ tryComplete();
38
+ }
39
+ export function markLateActivationPending() {
40
+ pendingLateActivations++;
41
+ }
42
+ export function settleLateActivation() {
43
+ if (pendingLateActivations === 0)
44
+ return;
45
+ pendingLateActivations--;
46
+ tryComplete();
47
+ }
48
+ function tryComplete() {
49
+ if (completed || streamingGateAborted || pendingCount !== 0)
50
+ return;
51
+ if (streamingGateActive &&
52
+ (!terminalReached || pendingBoundaries !== 0 || pendingLateActivations !== 0))
53
+ return;
54
+ completed = true;
55
+ if (started) {
15
56
  performance.mark('webui:hydrate:total:end');
16
57
  performance.measure('webui:hydrate:total', 'webui:hydrate:total:start', 'webui:hydrate:total:end');
17
- window.dispatchEvent(new Event('webui:hydration-complete'));
18
58
  }
59
+ window.dispatchEvent(new Event('webui:hydration-complete'));
60
+ }
61
+ export function __getLifecycleStateForTests() {
62
+ return {
63
+ pendingCount,
64
+ started,
65
+ completed,
66
+ streamingGateActive,
67
+ streamingGateAborted,
68
+ terminalReached,
69
+ pendingBoundaries,
70
+ pendingLateActivations,
71
+ };
72
+ }
73
+ export function __resetLifecycleForTests() {
74
+ pendingCount = 0;
75
+ started = false;
76
+ completed = false;
77
+ streamingGateActive = false;
78
+ streamingGateAborted = false;
79
+ terminalReached = false;
80
+ pendingBoundaries = 0;
81
+ pendingLateActivations = 0;
19
82
  }
@@ -22,6 +22,9 @@ function defineTemplateHost(tag, meta) {
22
22
  $shouldApplySSRBootstrapState() {
23
23
  return false;
24
24
  }
25
+ $shouldActivateOnBoundaryCommit() {
26
+ return false;
27
+ }
25
28
  }
26
29
  StaticTemplateHost.define(tag);
27
30
  }
@@ -58,9 +61,8 @@ export function installTemplateElementRuntime() {
58
61
  return;
59
62
  defineTemplateHosts(detail.templates);
60
63
  });
64
+ defineTemplateHosts();
61
65
  if (document.readyState === 'loading') {
62
66
  document.addEventListener('DOMContentLoaded', () => defineTemplateHosts(), { once: true });
63
- return;
64
67
  }
65
- defineTemplateHosts();
66
68
  }
@@ -0,0 +1,2 @@
1
+ import type { PendingBoundaryUpdates } from './streaming-deferred.js';
2
+ export declare function activateRootsBetween(startMarker: Comment, endMarker: Comment, state: Record<string, unknown> | undefined, updates?: PendingBoundaryUpdates): void;
@@ -0,0 +1,13 @@
1
+ import { abandonDeferredRange, } from './streaming-cleanup.js';
2
+ import { activateDeferredTree, } from './streaming-deferred.js';
3
+ export function activateRootsBetween(startMarker, endMarker, state, updates) {
4
+ const root = startMarker.parentNode;
5
+ if (!root) {
6
+ throw new Error('boundary start marker was detached before activation');
7
+ }
8
+ const failure = activateDeferredTree(startMarker.nextSibling, root, endMarker, state, updates ? { updates, countRetention: true } : undefined);
9
+ if (!failure)
10
+ return;
11
+ abandonDeferredRange(startMarker, endMarker);
12
+ throw new Error(failure);
13
+ }
@@ -0,0 +1,2 @@
1
+ import type { BoundaryBootstrap } from './streaming-protocol.js';
2
+ export declare function applyBoundaryBootstrap(bootstrap: BoundaryBootstrap): void;
@@ -0,0 +1,48 @@
1
+ import { registerTemplateData } from './template.js';
2
+ export function applyBoundaryBootstrap(bootstrap) {
3
+ if (bootstrap.templates)
4
+ registerTemplateData(bootstrap.templates);
5
+ const w = window;
6
+ if (!w.__webui)
7
+ w.__webui = {};
8
+ const keys = Object.keys(bootstrap);
9
+ for (let i = 0; i < keys.length; i++) {
10
+ const key = keys[i];
11
+ if (key === 'templates' || key === 'state')
12
+ continue;
13
+ if (key === 'inventory') {
14
+ w.__webui.inventory = mergeInventory(w.__webui.inventory, bootstrap.inventory);
15
+ continue;
16
+ }
17
+ if (key === 'css' || key === 'styles') {
18
+ appendUniqueStrings(w.__webui, key, bootstrap[key]);
19
+ continue;
20
+ }
21
+ w.__webui[key] = bootstrap[key];
22
+ }
23
+ }
24
+ function mergeInventory(existing, delta) {
25
+ const current = typeof existing === 'string' ? existing : '';
26
+ const next = delta ?? '';
27
+ const length = Math.max(current.length, next.length);
28
+ let merged = '';
29
+ for (let i = 0; i < length; i++) {
30
+ const a = i < current.length ? parseInt(current[i], 16) : 0;
31
+ const b = i < next.length ? parseInt(next[i], 16) : 0;
32
+ merged += (a | b).toString(16);
33
+ }
34
+ return merged;
35
+ }
36
+ function appendUniqueStrings(target, key, delta) {
37
+ if (!delta)
38
+ return;
39
+ const existing = target[key];
40
+ const cumulative = Array.isArray(existing) ? existing : [];
41
+ for (let i = 0; i < delta.length; i++) {
42
+ if (cumulative.indexOf(delta[i]) === -1) {
43
+ cumulative.push(delta[i]);
44
+ }
45
+ }
46
+ if (cumulative !== existing)
47
+ target[key] = cumulative;
48
+ }
@@ -0,0 +1,4 @@
1
+ export declare function abandonDeferredElement(el: Element): void;
2
+ export declare function abandonDeferredDescendants(root: Element): void;
3
+ export declare function abandonDeferredRange(startMarker: Comment, endMarker: Node): void;
4
+ export declare function abandonDeferredDocumentRoots(): void;
@@ -0,0 +1,66 @@
1
+ import { firstNodeWithin, MAX_MARKER_SCAN_NODES, nextWithinRoot, safeRemoveAttribute, streamingErrorMessage, } from './streaming-dom.js';
2
+ import { STREAMED_HOST_ATTR } from './streaming-mode.js';
3
+ const STREAMING_BOUNDARY_ABANDON = Symbol.for('microsoft.webui.boundaryAbandon');
4
+ export function abandonDeferredElement(el) {
5
+ try {
6
+ if (!el.hasAttribute(STREAMED_HOST_ATTR))
7
+ return;
8
+ }
9
+ catch {
10
+ safeRemoveAttribute(el, STREAMED_HOST_ATTR);
11
+ return;
12
+ }
13
+ try {
14
+ const hook = el[STREAMING_BOUNDARY_ABANDON];
15
+ if (typeof hook === 'function')
16
+ hook.call(el);
17
+ }
18
+ catch (error) {
19
+ console.error(`[WebUI] streaming: abandon failed for <${el.tagName?.toLowerCase?.() ?? '?'}>: ${streamingErrorMessage(error)}`);
20
+ }
21
+ finally {
22
+ safeRemoveAttribute(el, STREAMED_HOST_ATTR);
23
+ }
24
+ }
25
+ export function abandonDeferredDescendants(root) {
26
+ abandonDeferredNodes(firstNodeWithin(root), root, null);
27
+ }
28
+ export function abandonDeferredRange(startMarker, endMarker) {
29
+ const root = startMarker.parentNode;
30
+ if (root) {
31
+ abandonDeferredNodes(startMarker.nextSibling, root, endMarker);
32
+ }
33
+ }
34
+ function abandonDeferredNodes(first, root, end) {
35
+ let node = first;
36
+ let visited = 0;
37
+ while (node && node !== end && visited < MAX_MARKER_SCAN_NODES) {
38
+ visited++;
39
+ if (node.nodeType === 1) {
40
+ abandonDeferredElement(node);
41
+ }
42
+ node = nextWithinRoot(node, root);
43
+ }
44
+ }
45
+ export function abandonDeferredDocumentRoots() {
46
+ if (typeof document === 'undefined' ||
47
+ typeof document.getElementsByTagName !== 'function') {
48
+ return;
49
+ }
50
+ const elements = document.getElementsByTagName('*');
51
+ let visited = 0;
52
+ for (let i = 0; i < elements.length && visited < MAX_MARKER_SCAN_NODES; i++) {
53
+ const el = elements[i];
54
+ visited++;
55
+ abandonDeferredElement(el);
56
+ const shadowRoot = el.shadowRoot;
57
+ let node = shadowRoot?.firstChild ?? null;
58
+ while (node && visited < MAX_MARKER_SCAN_NODES) {
59
+ visited++;
60
+ if (node.nodeType === 1) {
61
+ abandonDeferredElement(node);
62
+ }
63
+ node = nextWithinRoot(node, shadowRoot);
64
+ }
65
+ }
66
+ }
@@ -0,0 +1,7 @@
1
+ import { elementHasPendingStateForTests, pendingTagWaiterCountForTests, pendingUndefinedRootCountForTests } from './streaming-deferred.js';
2
+ export declare function enqueueStreamingSentinel(sentinel: Element): void;
3
+ export declare function installStreamingTruncationGuard(): void;
4
+ export declare function resetStreamingCoordinatorStateForTests(): void;
5
+ export declare function isStreamingHaltedForTests(): boolean;
6
+ export declare function streamingRetentionStateForTests(): readonly [number, number];
7
+ export { elementHasPendingStateForTests, pendingTagWaiterCountForTests, pendingUndefinedRootCountForTests, };