@braidlabs/core 0.1.1

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 (80) hide show
  1. package/README.md +123 -0
  2. package/package.json +37 -0
  3. package/src/adapters/adapter.d.ts +75 -0
  4. package/src/adapters/adapter.js +35 -0
  5. package/src/adapters/adapter.js.map +1 -0
  6. package/src/adapters/compat-adapter.d.ts +27 -0
  7. package/src/adapters/compat-adapter.js +113 -0
  8. package/src/adapters/compat-adapter.js.map +1 -0
  9. package/src/adapters/custom-element-adapter.d.ts +21 -0
  10. package/src/adapters/custom-element-adapter.js +91 -0
  11. package/src/adapters/custom-element-adapter.js.map +1 -0
  12. package/src/compat/born-inert-scripts.d.ts +30 -0
  13. package/src/compat/born-inert-scripts.js +85 -0
  14. package/src/compat/born-inert-scripts.js.map +1 -0
  15. package/src/compat/document-facade.d.ts +44 -0
  16. package/src/compat/document-facade.js +104 -0
  17. package/src/compat/document-facade.js.map +1 -0
  18. package/src/compat/document-member-classification.d.ts +30 -0
  19. package/src/compat/document-member-classification.js +64 -0
  20. package/src/compat/document-member-classification.js.map +1 -0
  21. package/src/compat/document-overrides.d.ts +44 -0
  22. package/src/compat/document-overrides.js +225 -0
  23. package/src/compat/document-overrides.js.map +1 -0
  24. package/src/compat/document-surface.generated.d.ts +21 -0
  25. package/src/compat/document-surface.generated.js +292 -0
  26. package/src/compat/document-surface.generated.js.map +1 -0
  27. package/src/compat/fragment-boundary.d.ts +14 -0
  28. package/src/compat/fragment-boundary.js +335 -0
  29. package/src/compat/fragment-boundary.js.map +1 -0
  30. package/src/compat/metadata.d.ts +15 -0
  31. package/src/compat/metadata.js +21 -0
  32. package/src/compat/metadata.js.map +1 -0
  33. package/src/compat/navigation-bus.d.ts +29 -0
  34. package/src/compat/navigation-bus.js +92 -0
  35. package/src/compat/navigation-bus.js.map +1 -0
  36. package/src/compat/realm-patches.d.ts +21 -0
  37. package/src/compat/realm-patches.js +573 -0
  38. package/src/compat/realm-patches.js.map +1 -0
  39. package/src/compat/register-worker.d.ts +45 -0
  40. package/src/compat/register-worker.js +57 -0
  41. package/src/compat/register-worker.js.map +1 -0
  42. package/src/compat/script-execution.d.ts +65 -0
  43. package/src/compat/script-execution.js +361 -0
  44. package/src/compat/script-execution.js.map +1 -0
  45. package/src/compat/service-worker.d.ts +22 -0
  46. package/src/compat/service-worker.js +104 -0
  47. package/src/compat/service-worker.js.map +1 -0
  48. package/src/config.d.ts +37 -0
  49. package/src/config.js +26 -0
  50. package/src/config.js.map +1 -0
  51. package/src/context/context-bus.d.ts +67 -0
  52. package/src/context/context-bus.js +117 -0
  53. package/src/context/context-bus.js.map +1 -0
  54. package/src/elements/fragment-slot.d.ts +39 -0
  55. package/src/elements/fragment-slot.js +281 -0
  56. package/src/elements/fragment-slot.js.map +1 -0
  57. package/src/env/create-env.d.ts +31 -0
  58. package/src/env/create-env.js +91 -0
  59. package/src/env/create-env.js.map +1 -0
  60. package/src/env/fragment-env.d.ts +56 -0
  61. package/src/env/fragment-env.js +14 -0
  62. package/src/env/fragment-env.js.map +1 -0
  63. package/src/errors.d.ts +21 -0
  64. package/src/errors.js +21 -0
  65. package/src/errors.js.map +1 -0
  66. package/src/index.d.ts +36 -0
  67. package/src/index.js +40 -0
  68. package/src/index.js.map +1 -0
  69. package/src/protocol.d.ts +38 -0
  70. package/src/protocol.js +45 -0
  71. package/src/protocol.js.map +1 -0
  72. package/src/realm/realm-manager.d.ts +60 -0
  73. package/src/realm/realm-manager.js +296 -0
  74. package/src/realm/realm-manager.js.map +1 -0
  75. package/src/utils/assert.d.ts +7 -0
  76. package/src/utils/assert.js +10 -0
  77. package/src/utils/assert.js.map +1 -0
  78. package/src/utils/selector-helpers.d.ts +10 -0
  79. package/src/utils/selector-helpers.js +13 -0
  80. package/src/utils/selector-helpers.js.map +1 -0
@@ -0,0 +1,335 @@
1
+ /* eslint-disable @typescript-eslint/no-unsafe-function-type, prefer-rest-params --
2
+ * ported from the matrix-tested web-fragments fork: the wrappers must forward the exact
3
+ * original `arguments` object to native DOM methods, and accept any native function shape. */
4
+ import { compatDomInsertion, compatMultiNodeDomInsertion, executeInertScript, executeInertPreloadLink, restoreScriptType, alreadyExecutedScriptsAndLinks, } from './script-execution.js';
5
+ import { removeBornInertShadowing, unwrapBornInertScriptToLive } from './born-inert-scripts.js';
6
+ import { isDevMode } from '../config.js';
7
+ /**
8
+ * The fragment boundary: all main-realm interception is confined here — the
9
+ * host page's `Node`/`Element` prototypes are never touched.
10
+ *
11
+ * Every node inside a fragment's DOM is "stamped" with a per-fragment prototype spliced above
12
+ * its native prototype (`Object.create(nativeProto, overrides)` + `Object.setPrototypeOf(node, …)`).
13
+ * The overrides provide script/preload activation on insertion and virtualized
14
+ * `ownerDocument`/`getRootNode` — but only for nodes that belong to the fragment. The host page
15
+ * runs on pristine prototypes.
16
+ *
17
+ * Stamping is applied synchronously at every point where nodes enter the fragment world, and
18
+ * stamped entry points propagate the stamp to whatever they create or admit (insertion methods,
19
+ * `cloneNode`, `innerHTML`, `insertAdjacentHTML`), so the stamped set is closed under the
20
+ * operations fragment code can perform on it.
21
+ *
22
+ * A `MutationObserver` scoped to the fragment's shadow root acts as the safety net for
23
+ * insertions that bypass stamped methods (e.g. code calling captured native functions): scripts
24
+ * reaching the DOM through such paths are inert by construction (see `born-inert-scripts.ts`
25
+ * and the gateway's SSR neutralization), and the observer activates them — one microtask later —
26
+ * in the fragment's realm, stamps the stray subtree, and reports the bypass in dev mode.
27
+ */
28
+ // Native main-realm references, captured at module load.
29
+ const native = {
30
+ appendChild: Node.prototype.appendChild,
31
+ insertBefore: Node.prototype.insertBefore,
32
+ replaceChild: Node.prototype.replaceChild,
33
+ getRootNode: Node.prototype.getRootNode,
34
+ cloneNode: Node.prototype.cloneNode,
35
+ ownerDocument: Object.getOwnPropertyDescriptor(Node.prototype, 'ownerDocument').get,
36
+ elementAppend: Element.prototype.append,
37
+ elementPrepend: Element.prototype.prepend,
38
+ elementReplaceChildren: Element.prototype.replaceChildren,
39
+ elementReplaceWith: Element.prototype.replaceWith,
40
+ insertAdjacentElement: Element.prototype.insertAdjacentElement,
41
+ insertAdjacentHTML: Element.prototype.insertAdjacentHTML,
42
+ elementInnerHTML: Object.getOwnPropertyDescriptor(Element.prototype, 'innerHTML'),
43
+ fragmentAppend: DocumentFragment.prototype.append,
44
+ fragmentPrepend: DocumentFragment.prototype.prepend,
45
+ fragmentReplaceChildren: DocumentFragment.prototype.replaceChildren,
46
+ shadowRootInnerHTML: Object.getOwnPropertyDescriptor(ShadowRoot.prototype, 'innerHTML'),
47
+ };
48
+ export function createFragmentBoundary(options) {
49
+ const { realmDocument, shadowRoot, braidDocumentElement, abortSignal } = options;
50
+ const stampedNodes = new WeakSet();
51
+ const stampedProtos = new Map();
52
+ const stampedProtoSet = new WeakSet();
53
+ let warnedAboutUnstampedEntry = false;
54
+ /** A node is inside this fragment's DOM iff its plain root is the fragment's shadow root. */
55
+ function isInFragmentDom(node) {
56
+ return native.getRootNode.call(node) === shadowRoot;
57
+ }
58
+ /**
59
+ * Reverts any born-inert scripts in the given node (or its subtree) to their live form, so
60
+ * the standard insertion handling below can process them like any other insertion.
61
+ *
62
+ * This also covers *clones* of born-inert scripts: clones carry the `type="inert"` +
63
+ * `data-script-type` attributes (attributes copy with cloneNode) but not the WeakSet
64
+ * membership. Reviving them here restores standalone-behavior parity.
65
+ */
66
+ function reviveInertScript(script) {
67
+ unwrapBornInertScriptToLive(script);
68
+ if (script.getAttribute('type') === 'inert' && !alreadyExecutedScriptsAndLinks.has(script)) {
69
+ restoreScriptType(script);
70
+ }
71
+ }
72
+ function prepareForInsertion(node) {
73
+ if (node instanceof HTMLScriptElement) {
74
+ reviveInertScript(node);
75
+ }
76
+ else if (node.nodeType === Node.ELEMENT_NODE || node.nodeType === Node.DOCUMENT_FRAGMENT_NODE) {
77
+ node.querySelectorAll?.('script').forEach((script) => {
78
+ reviveInertScript(script);
79
+ });
80
+ }
81
+ return node;
82
+ }
83
+ /**
84
+ * Nodes to stamp after an insertion: the node itself, or — for a DocumentFragment, whose
85
+ * children move into the target during insertion — its current children.
86
+ */
87
+ function nodesToStampAfterInsertion(node) {
88
+ return node.nodeType === Node.DOCUMENT_FRAGMENT_NODE ? [...node.childNodes] : [node];
89
+ }
90
+ /**
91
+ * Creates a wrapper for a single-child insertion method (appendChild, insertBefore).
92
+ *
93
+ * When the target is inside the fragment's DOM, the insertion gets script handling (via
94
+ * `compatDomInsertion`). In all cases the inserted subtree is stamped so the stamped set
95
+ * stays closed.
96
+ */
97
+ function makeSingleNodeInsertion(nativeFn) {
98
+ return function boundaryInsertion(childNode) {
99
+ const args = arguments;
100
+ const futureStamps = nodesToStampAfterInsertion(childNode);
101
+ const doInsertTheNode = () => {
102
+ const result = nativeFn.apply(this, args);
103
+ futureStamps.forEach(stampTree);
104
+ return result;
105
+ };
106
+ if (!isInFragmentDom(this)) {
107
+ // insertions into unattached trees are not script-processed; scripts are handled when
108
+ // the tree itself is inserted into the fragment's DOM
109
+ return doInsertTheNode();
110
+ }
111
+ return compatDomInsertion(prepareForInsertion(childNode), doInsertTheNode, realmDocument);
112
+ };
113
+ }
114
+ function boundaryReplaceChild(newChild, oldChild) {
115
+ const args = arguments;
116
+ const futureStamps = nodesToStampAfterInsertion(newChild);
117
+ const doInsertTheNode = () => {
118
+ const result = native.replaceChild.apply(this, args);
119
+ futureStamps.forEach(stampTree);
120
+ return result;
121
+ };
122
+ if (!isInFragmentDom(this)) {
123
+ doInsertTheNode();
124
+ }
125
+ else {
126
+ compatDomInsertion(prepareForInsertion(newChild), doInsertTheNode, realmDocument);
127
+ }
128
+ return oldChild;
129
+ }
130
+ function boundaryInsertAdjacentElement(where, element) {
131
+ const args = arguments;
132
+ const doInsertTheNode = () => {
133
+ const result = native.insertAdjacentElement.apply(this, args);
134
+ stampTree(element);
135
+ return result;
136
+ };
137
+ if (!isInFragmentDom(this)) {
138
+ return doInsertTheNode();
139
+ }
140
+ return compatDomInsertion(prepareForInsertion(element), doInsertTheNode, realmDocument);
141
+ }
142
+ /**
143
+ * Creates a wrapper for the multi-node insertion methods (append, prepend, replaceChildren,
144
+ * replaceWith): the native insertion runs once, after every node argument has been
145
+ * preprocessed.
146
+ */
147
+ function makeMultiNodeInsertion(nativeFn) {
148
+ return function boundaryMultiInsertion(...nodes) {
149
+ const args = arguments;
150
+ const nodeArgs = nodes.filter((node) => typeof node !== 'string');
151
+ const futureStamps = nodeArgs.flatMap(nodesToStampAfterInsertion);
152
+ const doInsertTheNodes = () => {
153
+ nativeFn.apply(this, args);
154
+ futureStamps.forEach(stampTree);
155
+ };
156
+ if (!isInFragmentDom(this)) {
157
+ return doInsertTheNodes();
158
+ }
159
+ nodeArgs.forEach(prepareForInsertion);
160
+ compatMultiNodeDomInsertion(nodes, doInsertTheNodes, realmDocument);
161
+ };
162
+ }
163
+ function makeHtmlParsingOverrides(innerHTMLDescriptor) {
164
+ return {
165
+ // scripts parsed from html never execute (per spec), so parsing only needs stamp propagation
166
+ innerHTML: {
167
+ configurable: true,
168
+ enumerable: true,
169
+ get() {
170
+ return innerHTMLDescriptor.get.call(this);
171
+ },
172
+ set(value) {
173
+ innerHTMLDescriptor.set.call(this, value);
174
+ stampTree(this);
175
+ },
176
+ },
177
+ };
178
+ }
179
+ const elementOverrides = {
180
+ appendChild: { configurable: true, writable: true, value: makeSingleNodeInsertion(native.appendChild) },
181
+ insertBefore: { configurable: true, writable: true, value: makeSingleNodeInsertion(native.insertBefore) },
182
+ replaceChild: { configurable: true, writable: true, value: boundaryReplaceChild },
183
+ insertAdjacentElement: { configurable: true, writable: true, value: boundaryInsertAdjacentElement },
184
+ append: { configurable: true, writable: true, value: makeMultiNodeInsertion(native.elementAppend) },
185
+ prepend: { configurable: true, writable: true, value: makeMultiNodeInsertion(native.elementPrepend) },
186
+ replaceChildren: {
187
+ configurable: true,
188
+ writable: true,
189
+ value: makeMultiNodeInsertion(native.elementReplaceChildren),
190
+ },
191
+ replaceWith: { configurable: true, writable: true, value: makeMultiNodeInsertion(native.elementReplaceWith) },
192
+ insertAdjacentHTML: {
193
+ configurable: true,
194
+ writable: true,
195
+ value: function boundaryInsertAdjacentHTML(position, text) {
196
+ const result = native.insertAdjacentHTML.call(this, position, text);
197
+ const lowercasePosition = String(position).toLowerCase();
198
+ stampTree(lowercasePosition === 'afterbegin' || lowercasePosition === 'beforeend' ? this : this.parentNode ?? this);
199
+ return result;
200
+ },
201
+ },
202
+ cloneNode: {
203
+ configurable: true,
204
+ writable: true,
205
+ value: function boundaryCloneNode(deep) {
206
+ const clone = native.cloneNode.call(this, deep);
207
+ stampTree(clone);
208
+ return clone;
209
+ },
210
+ },
211
+ ownerDocument: {
212
+ configurable: true,
213
+ enumerable: true,
214
+ get() {
215
+ return isInFragmentDom(this) ? realmDocument : native.ownerDocument.call(this);
216
+ },
217
+ },
218
+ getRootNode: {
219
+ configurable: true,
220
+ writable: true,
221
+ value: function boundaryGetRootNode(getRootNodeOptions) {
222
+ const plainRoot = native.getRootNode.call(this);
223
+ if (plainRoot === shadowRoot) {
224
+ // nodes in a fragment report the fragment's document as their root
225
+ return realmDocument;
226
+ }
227
+ return getRootNodeOptions ? native.getRootNode.call(this, getRootNodeOptions) : plainRoot;
228
+ },
229
+ },
230
+ ...makeHtmlParsingOverrides(native.elementInnerHTML),
231
+ };
232
+ function stampNode(node) {
233
+ if (node.nodeType !== Node.ELEMENT_NODE)
234
+ return;
235
+ if (stampedNodes.has(node))
236
+ return;
237
+ const proto = Object.getPrototypeOf(node);
238
+ if (proto === null || stampedProtoSet.has(proto)) {
239
+ stampedNodes.add(node);
240
+ return;
241
+ }
242
+ let stampedProto = stampedProtos.get(proto);
243
+ if (!stampedProto) {
244
+ stampedProto = Object.create(proto, elementOverrides);
245
+ stampedProtos.set(proto, stampedProto);
246
+ stampedProtoSet.add(stampedProto);
247
+ }
248
+ Object.setPrototypeOf(node, stampedProto);
249
+ stampedNodes.add(node);
250
+ }
251
+ function stampTree(root) {
252
+ if (root.nodeType === Node.ELEMENT_NODE) {
253
+ stampNode(root);
254
+ }
255
+ else if (root.nodeType !== Node.DOCUMENT_FRAGMENT_NODE) {
256
+ return;
257
+ }
258
+ root.querySelectorAll('*').forEach(stampNode);
259
+ }
260
+ /**
261
+ * Stamp the shadow root itself with own-property overrides (a shadow root is a per-fragment
262
+ * singleton, so instance properties are simpler than a spliced prototype and just as
263
+ * effective). The shadow root keeps its native `ownerDocument`/`getRootNode` behavior
264
+ * (reporting the main document) — only insertions are intercepted.
265
+ */
266
+ Object.defineProperties(shadowRoot, {
267
+ appendChild: { configurable: true, writable: true, value: makeSingleNodeInsertion(native.appendChild) },
268
+ insertBefore: { configurable: true, writable: true, value: makeSingleNodeInsertion(native.insertBefore) },
269
+ replaceChild: { configurable: true, writable: true, value: boundaryReplaceChild },
270
+ append: { configurable: true, writable: true, value: makeMultiNodeInsertion(native.fragmentAppend) },
271
+ prepend: { configurable: true, writable: true, value: makeMultiNodeInsertion(native.fragmentPrepend) },
272
+ replaceChildren: {
273
+ configurable: true,
274
+ writable: true,
275
+ value: makeMultiNodeInsertion(native.fragmentReplaceChildren),
276
+ },
277
+ ...makeHtmlParsingOverrides(native.shadowRootInnerHTML),
278
+ });
279
+ // stamp the initial fragment DOM (for pierced fragments this includes the SSR'ed content;
280
+ // for slot-fetched fragments this is the already-inserted, neutralized content)
281
+ stampTree(braidDocumentElement);
282
+ /**
283
+ * The boundary observer: activates inert scripts/preload-links that entered the fragment's
284
+ * DOM through unstamped paths, stamps stray subtrees, and reports bypasses in dev mode.
285
+ * Everything it does is idempotent with the synchronous stamped-insertion handling.
286
+ */
287
+ const observer = new MutationObserver((records) => {
288
+ for (const record of records) {
289
+ for (const addedNode of record.addedNodes) {
290
+ if (addedNode.nodeType !== Node.ELEMENT_NODE)
291
+ continue;
292
+ const addedElement = addedNode;
293
+ if (!stampedNodes.has(addedElement)) {
294
+ if (isDevMode() && !warnedAboutUnstampedEntry) {
295
+ warnedAboutUnstampedEntry = true;
296
+ console.warn(`Braid compat: a node entered a fragment's DOM through a code path the fragment boundary doesn't intercept synchronously (e.g. a captured native DOM function).\n` +
297
+ `Scripts inserted this way still execute in the fragment's realm, but one microtask later than usual. Node:`, addedElement);
298
+ }
299
+ stampTree(addedElement);
300
+ }
301
+ activateInertScriptsAndLinks(addedElement);
302
+ }
303
+ }
304
+ });
305
+ function activateInertScriptsAndLinks(root) {
306
+ const inertSelector = 'script[type="inert"],link[rel="inert-preload"],link[rel="inert-prefetch"],link[rel="inert-modulepreload"]';
307
+ const candidates = [];
308
+ if (root.matches(inertSelector)) {
309
+ candidates.push(root);
310
+ }
311
+ candidates.push(...root.querySelectorAll(inertSelector));
312
+ for (const candidate of candidates) {
313
+ if (candidate instanceof HTMLLinkElement) {
314
+ executeInertPreloadLink(candidate, realmDocument);
315
+ }
316
+ else {
317
+ if (!candidate.src && !candidate.textContent) {
318
+ // an empty inert script can't execute; leave it be
319
+ continue;
320
+ }
321
+ removeBornInertShadowing(candidate);
322
+ restoreScriptType(candidate);
323
+ executeInertScript(candidate, realmDocument);
324
+ }
325
+ }
326
+ }
327
+ observer.observe(shadowRoot, { childList: true, subtree: true });
328
+ abortSignal.addEventListener('abort', () => observer.disconnect());
329
+ return {
330
+ stampNode,
331
+ stampTree,
332
+ disconnect: () => observer.disconnect(),
333
+ };
334
+ }
335
+ //# sourceMappingURL=fragment-boundary.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"fragment-boundary.js","sourceRoot":"","sources":["../../../../../libs/core/src/compat/fragment-boundary.ts"],"names":[],"mappings":"AAAA;;8FAE8F;AAC9F,OAAO,EACL,kBAAkB,EAClB,2BAA2B,EAC3B,kBAAkB,EAClB,uBAAuB,EACvB,iBAAiB,EACjB,8BAA8B,GAC/B,MAAM,uBAAuB,CAAC;AAC/B,OAAO,EAAE,wBAAwB,EAAE,2BAA2B,EAAE,MAAM,yBAAyB,CAAC;AAChG,OAAO,EAAE,SAAS,EAAE,MAAM,cAAc,CAAC;AAEzC;;;;;;;;;;;;;;;;;;;;GAoBG;AAEH,yDAAyD;AACzD,MAAM,MAAM,GAAG;IACb,WAAW,EAAE,IAAI,CAAC,SAAS,CAAC,WAAW;IACvC,YAAY,EAAE,IAAI,CAAC,SAAS,CAAC,YAAY;IACzC,YAAY,EAAE,IAAI,CAAC,SAAS,CAAC,YAAY;IACzC,WAAW,EAAE,IAAI,CAAC,SAAS,CAAC,WAAW;IACvC,SAAS,EAAE,IAAI,CAAC,SAAS,CAAC,SAAS;IACnC,aAAa,EAAE,MAAM,CAAC,wBAAwB,CAAC,IAAI,CAAC,SAAS,EAAE,eAAe,CAAE,CAAC,GAAI;IACrF,aAAa,EAAE,OAAO,CAAC,SAAS,CAAC,MAAM;IACvC,cAAc,EAAE,OAAO,CAAC,SAAS,CAAC,OAAO;IACzC,sBAAsB,EAAE,OAAO,CAAC,SAAS,CAAC,eAAe;IACzD,kBAAkB,EAAE,OAAO,CAAC,SAAS,CAAC,WAAW;IACjD,qBAAqB,EAAE,OAAO,CAAC,SAAS,CAAC,qBAAqB;IAC9D,kBAAkB,EAAE,OAAO,CAAC,SAAS,CAAC,kBAAkB;IACxD,gBAAgB,EAAE,MAAM,CAAC,wBAAwB,CAAC,OAAO,CAAC,SAAS,EAAE,WAAW,CAAE;IAClF,cAAc,EAAE,gBAAgB,CAAC,SAAS,CAAC,MAAM;IACjD,eAAe,EAAE,gBAAgB,CAAC,SAAS,CAAC,OAAO;IACnD,uBAAuB,EAAE,gBAAgB,CAAC,SAAS,CAAC,eAAe;IACnE,mBAAmB,EAAE,MAAM,CAAC,wBAAwB,CAAC,UAAU,CAAC,SAAS,EAAE,WAAW,CAAE;CACzF,CAAC;AAWF,MAAM,UAAU,sBAAsB,CAAC,OAKtC;IACC,MAAM,EAAE,aAAa,EAAE,UAAU,EAAE,oBAAoB,EAAE,WAAW,EAAE,GAAG,OAAO,CAAC;IAEjF,MAAM,YAAY,GAAG,IAAI,OAAO,EAAQ,CAAC;IACzC,MAAM,aAAa,GAAG,IAAI,GAAG,EAAkB,CAAC;IAChD,MAAM,eAAe,GAAG,IAAI,OAAO,EAAU,CAAC;IAC9C,IAAI,yBAAyB,GAAG,KAAK,CAAC;IAEtC,6FAA6F;IAC7F,SAAS,eAAe,CAAC,IAAU;QACjC,OAAO,MAAM,CAAC,WAAW,CAAC,IAAI,CAAC,IAAI,CAAC,KAAK,UAAU,CAAC;IACtD,CAAC;IAED;;;;;;;OAOG;IACH,SAAS,iBAAiB,CAAC,MAAyB;QAClD,2BAA2B,CAAC,MAAM,CAAC,CAAC;QACpC,IAAI,MAAM,CAAC,YAAY,CAAC,MAAM,CAAC,KAAK,OAAO,IAAI,CAAC,8BAA8B,CAAC,GAAG,CAAC,MAAM,CAAC,EAAE,CAAC;YAC3F,iBAAiB,CAAC,MAAM,CAAC,CAAC;QAC5B,CAAC;IACH,CAAC;IAED,SAAS,mBAAmB,CAAiB,IAAO;QAClD,IAAI,IAAI,YAAY,iBAAiB,EAAE,CAAC;YACtC,iBAAiB,CAAC,IAAI,CAAC,CAAC;QAC1B,CAAC;aAAM,IAAI,IAAI,CAAC,QAAQ,KAAK,IAAI,CAAC,YAAY,IAAI,IAAI,CAAC,QAAQ,KAAK,IAAI,CAAC,sBAAsB,EAAE,CAAC;YAC/F,IAA2B,CAAC,gBAAgB,EAAE,CAAC,QAAQ,CAAC,CAAC,OAAO,CAAC,CAAC,MAAM,EAAE,EAAE;gBAC3E,iBAAiB,CAAC,MAA2B,CAAC,CAAC;YACjD,CAAC,CAAC,CAAC;QACL,CAAC;QACD,OAAO,IAAI,CAAC;IACd,CAAC;IAED;;;OAGG;IACH,SAAS,0BAA0B,CAAC,IAAU;QAC5C,OAAO,IAAI,CAAC,QAAQ,KAAK,IAAI,CAAC,sBAAsB,CAAC,CAAC,CAAC,CAAC,GAAG,IAAI,CAAC,UAAU,CAAC,CAAC,CAAC,CAAC,CAAC,IAAI,CAAC,CAAC;IACvF,CAAC;IAED;;;;;;OAMG;IACH,SAAS,uBAAuB,CAAC,QAAkB;QACjD,OAAO,SAAS,iBAAiB,CAA6B,SAAY;YACxE,MAAM,IAAI,GAAG,SAAS,CAAC;YACvB,MAAM,YAAY,GAAG,0BAA0B,CAAC,SAAS,CAAC,CAAC;YAC3D,MAAM,eAAe,GAAG,GAAG,EAAE;gBAC3B,MAAM,MAAM,GAAG,QAAQ,CAAC,KAAK,CAAC,IAAI,EAAE,IAAI,CAAC,CAAC;gBAC1C,YAAY,CAAC,OAAO,CAAC,SAAS,CAAC,CAAC;gBAChC,OAAO,MAAW,CAAC;YACrB,CAAC,CAAC;YAEF,IAAI,CAAC,eAAe,CAAC,IAAI,CAAC,EAAE,CAAC;gBAC3B,sFAAsF;gBACtF,sDAAsD;gBACtD,OAAO,eAAe,EAAE,CAAC;YAC3B,CAAC;YAED,OAAO,kBAAkB,CAAC,mBAAmB,CAAC,SAAS,CAAC,EAAE,eAAe,EAAE,aAAa,CAAC,CAAC;QAC5F,CAAC,CAAC;IACJ,CAAC;IAED,SAAS,oBAAoB,CAA6B,QAAc,EAAE,QAAW;QACnF,MAAM,IAAI,GAAG,SAAS,CAAC;QACvB,MAAM,YAAY,GAAG,0BAA0B,CAAC,QAAQ,CAAC,CAAC;QAC1D,MAAM,eAAe,GAAG,GAAG,EAAE;YAC3B,MAAM,MAAM,GAAG,MAAM,CAAC,YAAY,CAAC,KAAK,CAAC,IAAI,EAAE,IAAW,CAAC,CAAC;YAC5D,YAAY,CAAC,OAAO,CAAC,SAAS,CAAC,CAAC;YAChC,OAAO,MAAM,CAAC;QAChB,CAAC,CAAC;QAEF,IAAI,CAAC,eAAe,CAAC,IAAI,CAAC,EAAE,CAAC;YAC3B,eAAe,EAAE,CAAC;QACpB,CAAC;aAAM,CAAC;YACN,kBAAkB,CAAC,mBAAmB,CAAC,QAAQ,CAAC,EAAE,eAAe,EAAE,aAAa,CAAC,CAAC;QACpF,CAAC;QACD,OAAO,QAAQ,CAAC;IAClB,CAAC;IAED,SAAS,6BAA6B,CAAgB,KAAqB,EAAE,OAAgB;QAC3F,MAAM,IAAI,GAAG,SAAS,CAAC;QACvB,MAAM,eAAe,GAAG,GAAG,EAAE;YAC3B,MAAM,MAAM,GAAG,MAAM,CAAC,qBAAqB,CAAC,KAAK,CAAC,IAAI,EAAE,IAAW,CAAC,CAAC;YACrE,SAAS,CAAC,OAAO,CAAC,CAAC;YACnB,OAAO,MAAM,CAAC;QAChB,CAAC,CAAC;QAEF,IAAI,CAAC,eAAe,CAAC,IAAI,CAAC,EAAE,CAAC;YAC3B,OAAO,eAAe,EAAE,CAAC;QAC3B,CAAC;QACD,OAAO,kBAAkB,CAAC,mBAAmB,CAAC,OAAO,CAAC,EAAE,eAAe,EAAE,aAAa,CAAmB,CAAC;IAC5G,CAAC;IAED;;;;OAIG;IACH,SAAS,sBAAsB,CAAC,QAAkB;QAChD,OAAO,SAAS,sBAAsB,CAAa,GAAG,KAAwB;YAC5E,MAAM,IAAI,GAAG,SAAS,CAAC;YACvB,MAAM,QAAQ,GAAG,KAAK,CAAC,MAAM,CAAC,CAAC,IAAI,EAAgB,EAAE,CAAC,OAAO,IAAI,KAAK,QAAQ,CAAC,CAAC;YAChF,MAAM,YAAY,GAAG,QAAQ,CAAC,OAAO,CAAC,0BAA0B,CAAC,CAAC;YAElE,MAAM,gBAAgB,GAAG,GAAG,EAAE;gBAC5B,QAAQ,CAAC,KAAK,CAAC,IAAI,EAAE,IAAI,CAAC,CAAC;gBAC3B,YAAY,CAAC,OAAO,CAAC,SAAS,CAAC,CAAC;YAClC,CAAC,CAAC;YAEF,IAAI,CAAC,eAAe,CAAC,IAAI,CAAC,EAAE,CAAC;gBAC3B,OAAO,gBAAgB,EAAE,CAAC;YAC5B,CAAC;YAED,QAAQ,CAAC,OAAO,CAAC,mBAAmB,CAAC,CAAC;YACtC,2BAA2B,CAAC,KAAK,EAAE,gBAAgB,EAAE,aAAa,CAAC,CAAC;QACtE,CAAC,CAAC;IACJ,CAAC;IAED,SAAS,wBAAwB,CAAC,mBAAuC;QACvE,OAAO;YACL,6FAA6F;YAC7F,SAAS,EAAE;gBACT,YAAY,EAAE,IAAI;gBAClB,UAAU,EAAE,IAAI;gBAChB,GAAG;oBACD,OAAO,mBAAmB,CAAC,GAAI,CAAC,IAAI,CAAC,IAAI,CAAC,CAAC;gBAC7C,CAAC;gBACD,GAAG,CAAgB,KAAa;oBAC9B,mBAAmB,CAAC,GAAI,CAAC,IAAI,CAAC,IAAI,EAAE,KAAK,CAAC,CAAC;oBAC3C,SAAS,CAAC,IAAI,CAAC,CAAC;gBAClB,CAAC;aACF;SACF,CAAC;IACJ,CAAC;IAED,MAAM,gBAAgB,GAA0B;QAC9C,WAAW,EAAE,EAAE,YAAY,EAAE,IAAI,EAAE,QAAQ,EAAE,IAAI,EAAE,KAAK,EAAE,uBAAuB,CAAC,MAAM,CAAC,WAAW,CAAC,EAAE;QACvG,YAAY,EAAE,EAAE,YAAY,EAAE,IAAI,EAAE,QAAQ,EAAE,IAAI,EAAE,KAAK,EAAE,uBAAuB,CAAC,MAAM,CAAC,YAAY,CAAC,EAAE;QACzG,YAAY,EAAE,EAAE,YAAY,EAAE,IAAI,EAAE,QAAQ,EAAE,IAAI,EAAE,KAAK,EAAE,oBAAoB,EAAE;QACjF,qBAAqB,EAAE,EAAE,YAAY,EAAE,IAAI,EAAE,QAAQ,EAAE,IAAI,EAAE,KAAK,EAAE,6BAA6B,EAAE;QACnG,MAAM,EAAE,EAAE,YAAY,EAAE,IAAI,EAAE,QAAQ,EAAE,IAAI,EAAE,KAAK,EAAE,sBAAsB,CAAC,MAAM,CAAC,aAAa,CAAC,EAAE;QACnG,OAAO,EAAE,EAAE,YAAY,EAAE,IAAI,EAAE,QAAQ,EAAE,IAAI,EAAE,KAAK,EAAE,sBAAsB,CAAC,MAAM,CAAC,cAAc,CAAC,EAAE;QACrG,eAAe,EAAE;YACf,YAAY,EAAE,IAAI;YAClB,QAAQ,EAAE,IAAI;YACd,KAAK,EAAE,sBAAsB,CAAC,MAAM,CAAC,sBAAsB,CAAC;SAC7D;QACD,WAAW,EAAE,EAAE,YAAY,EAAE,IAAI,EAAE,QAAQ,EAAE,IAAI,EAAE,KAAK,EAAE,sBAAsB,CAAC,MAAM,CAAC,kBAAkB,CAAC,EAAE;QAC7G,kBAAkB,EAAE;YAClB,YAAY,EAAE,IAAI;YAClB,QAAQ,EAAE,IAAI;YACd,KAAK,EAAE,SAAS,0BAA0B,CAAgB,QAAwB,EAAE,IAAY;gBAC9F,MAAM,MAAM,GAAG,MAAM,CAAC,kBAAkB,CAAC,IAAI,CAAC,IAAI,EAAE,QAAQ,EAAE,IAAI,CAAC,CAAC;gBACpE,MAAM,iBAAiB,GAAG,MAAM,CAAC,QAAQ,CAAC,CAAC,WAAW,EAAE,CAAC;gBACzD,SAAS,CACP,iBAAiB,KAAK,YAAY,IAAI,iBAAiB,KAAK,WAAW,CAAC,CAAC,CAAC,IAAI,CAAC,CAAC,CAAC,IAAI,CAAC,UAAU,IAAI,IAAI,CACzG,CAAC;gBACF,OAAO,MAAM,CAAC;YAChB,CAAC;SACF;QACD,SAAS,EAAE;YACT,YAAY,EAAE,IAAI;YAClB,QAAQ,EAAE,IAAI;YACd,KAAK,EAAE,SAAS,iBAAiB,CAAa,IAAc;gBAC1D,MAAM,KAAK,GAAG,MAAM,CAAC,SAAS,CAAC,IAAI,CAAC,IAAI,EAAE,IAAI,CAAC,CAAC;gBAChD,SAAS,CAAC,KAAK,CAAC,CAAC;gBACjB,OAAO,KAAK,CAAC;YACf,CAAC;SACF;QACD,aAAa,EAAE;YACb,YAAY,EAAE,IAAI;YAClB,UAAU,EAAE,IAAI;YAChB,GAAG;gBACD,OAAO,eAAe,CAAC,IAAI,CAAC,CAAC,CAAC,CAAC,aAAa,CAAC,CAAC,CAAC,MAAM,CAAC,aAAa,CAAC,IAAI,CAAC,IAAI,CAAC,CAAC;YACjF,CAAC;SACF;QACD,WAAW,EAAE;YACX,YAAY,EAAE,IAAI;YAClB,QAAQ,EAAE,IAAI;YACd,KAAK,EAAE,SAAS,mBAAmB,CAAa,kBAAuC;gBACrF,MAAM,SAAS,GAAG,MAAM,CAAC,WAAW,CAAC,IAAI,CAAC,IAAI,CAAC,CAAC;gBAChD,IAAI,SAAS,KAAK,UAAU,EAAE,CAAC;oBAC7B,mEAAmE;oBACnE,OAAO,aAAa,CAAC;gBACvB,CAAC;gBACD,OAAO,kBAAkB,CAAC,CAAC,CAAC,MAAM,CAAC,WAAW,CAAC,IAAI,CAAC,IAAI,EAAE,kBAAkB,CAAC,CAAC,CAAC,CAAC,SAAS,CAAC;YAC5F,CAAC;SACF;QACD,GAAG,wBAAwB,CAAC,MAAM,CAAC,gBAAgB,CAAC;KACrD,CAAC;IAEF,SAAS,SAAS,CAAC,IAAU;QAC3B,IAAI,IAAI,CAAC,QAAQ,KAAK,IAAI,CAAC,YAAY;YAAE,OAAO;QAChD,IAAI,YAAY,CAAC,GAAG,CAAC,IAAI,CAAC;YAAE,OAAO;QAEnC,MAAM,KAAK,GAAG,MAAM,CAAC,cAAc,CAAC,IAAI,CAAC,CAAC;QAC1C,IAAI,KAAK,KAAK,IAAI,IAAI,eAAe,CAAC,GAAG,CAAC,KAAK,CAAC,EAAE,CAAC;YACjD,YAAY,CAAC,GAAG,CAAC,IAAI,CAAC,CAAC;YACvB,OAAO;QACT,CAAC;QAED,IAAI,YAAY,GAAG,aAAa,CAAC,GAAG,CAAC,KAAK,CAAC,CAAC;QAC5C,IAAI,CAAC,YAAY,EAAE,CAAC;YAClB,YAAY,GAAG,MAAM,CAAC,MAAM,CAAC,KAAK,EAAE,gBAAgB,CAAC,CAAC;YACtD,aAAa,CAAC,GAAG,CAAC,KAAK,EAAE,YAAa,CAAC,CAAC;YACxC,eAAe,CAAC,GAAG,CAAC,YAAa,CAAC,CAAC;QACrC,CAAC;QACD,MAAM,CAAC,cAAc,CAAC,IAAI,EAAE,YAAa,CAAC,CAAC;QAC3C,YAAY,CAAC,GAAG,CAAC,IAAI,CAAC,CAAC;IACzB,CAAC;IAED,SAAS,SAAS,CAAC,IAAU;QAC3B,IAAI,IAAI,CAAC,QAAQ,KAAK,IAAI,CAAC,YAAY,EAAE,CAAC;YACxC,SAAS,CAAC,IAAI,CAAC,CAAC;QAClB,CAAC;aAAM,IAAI,IAAI,CAAC,QAAQ,KAAK,IAAI,CAAC,sBAAsB,EAAE,CAAC;YACzD,OAAO;QACT,CAAC;QACA,IAAmC,CAAC,gBAAgB,CAAC,GAAG,CAAC,CAAC,OAAO,CAAC,SAAS,CAAC,CAAC;IAChF,CAAC;IAED;;;;;OAKG;IACH,MAAM,CAAC,gBAAgB,CAAC,UAAU,EAAE;QAClC,WAAW,EAAE,EAAE,YAAY,EAAE,IAAI,EAAE,QAAQ,EAAE,IAAI,EAAE,KAAK,EAAE,uBAAuB,CAAC,MAAM,CAAC,WAAW,CAAC,EAAE;QACvG,YAAY,EAAE,EAAE,YAAY,EAAE,IAAI,EAAE,QAAQ,EAAE,IAAI,EAAE,KAAK,EAAE,uBAAuB,CAAC,MAAM,CAAC,YAAY,CAAC,EAAE;QACzG,YAAY,EAAE,EAAE,YAAY,EAAE,IAAI,EAAE,QAAQ,EAAE,IAAI,EAAE,KAAK,EAAE,oBAAoB,EAAE;QACjF,MAAM,EAAE,EAAE,YAAY,EAAE,IAAI,EAAE,QAAQ,EAAE,IAAI,EAAE,KAAK,EAAE,sBAAsB,CAAC,MAAM,CAAC,cAAc,CAAC,EAAE;QACpG,OAAO,EAAE,EAAE,YAAY,EAAE,IAAI,EAAE,QAAQ,EAAE,IAAI,EAAE,KAAK,EAAE,sBAAsB,CAAC,MAAM,CAAC,eAAe,CAAC,EAAE;QACtG,eAAe,EAAE;YACf,YAAY,EAAE,IAAI;YAClB,QAAQ,EAAE,IAAI;YACd,KAAK,EAAE,sBAAsB,CAAC,MAAM,CAAC,uBAAuB,CAAC;SAC9D;QACD,GAAG,wBAAwB,CAAC,MAAM,CAAC,mBAAmB,CAAC;KACxD,CAAC,CAAC;IAEH,0FAA0F;IAC1F,gFAAgF;IAChF,SAAS,CAAC,oBAAoB,CAAC,CAAC;IAEhC;;;;OAIG;IACH,MAAM,QAAQ,GAAG,IAAI,gBAAgB,CAAC,CAAC,OAAO,EAAE,EAAE;QAChD,KAAK,MAAM,MAAM,IAAI,OAAO,EAAE,CAAC;YAC7B,KAAK,MAAM,SAAS,IAAI,MAAM,CAAC,UAAU,EAAE,CAAC;gBAC1C,IAAI,SAAS,CAAC,QAAQ,KAAK,IAAI,CAAC,YAAY;oBAAE,SAAS;gBACvD,MAAM,YAAY,GAAG,SAAoB,CAAC;gBAE1C,IAAI,CAAC,YAAY,CAAC,GAAG,CAAC,YAAY,CAAC,EAAE,CAAC;oBACpC,IAAI,SAAS,EAAE,IAAI,CAAC,yBAAyB,EAAE,CAAC;wBAC9C,yBAAyB,GAAG,IAAI,CAAC;wBACjC,OAAO,CAAC,IAAI,CACV,kKAAkK;4BAChK,4GAA4G,EAC9G,YAAY,CACb,CAAC;oBACJ,CAAC;oBACD,SAAS,CAAC,YAAY,CAAC,CAAC;gBAC1B,CAAC;gBAED,4BAA4B,CAAC,YAAY,CAAC,CAAC;YAC7C,CAAC;QACH,CAAC;IACH,CAAC,CAAC,CAAC;IAEH,SAAS,4BAA4B,CAAC,IAAa;QACjD,MAAM,aAAa,GACjB,2GAA2G,CAAC;QAC9G,MAAM,UAAU,GAA4C,EAAE,CAAC;QAC/D,IAAI,IAAI,CAAC,OAAO,CAAC,aAAa,CAAC,EAAE,CAAC;YAChC,UAAU,CAAC,IAAI,CAAC,IAA2C,CAAC,CAAC;QAC/D,CAAC;QACD,UAAU,CAAC,IAAI,CAAC,GAAI,IAAI,CAAC,gBAAgB,CAAC,aAAa,CAAqD,CAAC,CAAC;QAE9G,KAAK,MAAM,SAAS,IAAI,UAAU,EAAE,CAAC;YACnC,IAAI,SAAS,YAAY,eAAe,EAAE,CAAC;gBACzC,uBAAuB,CAAC,SAAS,EAAE,aAAa,CAAC,CAAC;YACpD,CAAC;iBAAM,CAAC;gBACN,IAAI,CAAC,SAAS,CAAC,GAAG,IAAI,CAAC,SAAS,CAAC,WAAW,EAAE,CAAC;oBAC7C,mDAAmD;oBACnD,SAAS;gBACX,CAAC;gBACD,wBAAwB,CAAC,SAAS,CAAC,CAAC;gBACpC,iBAAiB,CAAC,SAAS,CAAC,CAAC;gBAC7B,kBAAkB,CAAC,SAAS,EAAE,aAAa,CAAC,CAAC;YAC/C,CAAC;QACH,CAAC;IACH,CAAC;IAED,QAAQ,CAAC,OAAO,CAAC,UAAU,EAAE,EAAE,SAAS,EAAE,IAAI,EAAE,OAAO,EAAE,IAAI,EAAE,CAAC,CAAC;IACjE,WAAW,CAAC,gBAAgB,CAAC,OAAO,EAAE,GAAG,EAAE,CAAC,QAAQ,CAAC,UAAU,EAAE,CAAC,CAAC;IAEnE,OAAO;QACL,SAAS;QACT,SAAS;QACT,UAAU,EAAE,GAAG,EAAE,CAAC,QAAQ,CAAC,UAAU,EAAE;KACxC,CAAC;AACJ,CAAC"}
@@ -0,0 +1,15 @@
1
+ /**
2
+ * Per-fragment metadata the compat adapter attaches to the fragment's shadow root.
3
+ *
4
+ * The virtualized `document.readyState` can't be delegated to either document (the fragment
5
+ * needs its own lifecycle), so the adapter manages it here and the document facade reads it.
6
+ */
7
+ export interface CompatMetadata {
8
+ documentReadyState: DocumentReadyState;
9
+ }
10
+ export declare const compatMetadataSymbol: unique symbol;
11
+ export type CompatShadowRoot = ShadowRoot & {
12
+ [compatMetadataSymbol]: CompatMetadata;
13
+ };
14
+ export declare function setInternalReference<T extends object>(target: T, key: keyof T): void;
15
+ export declare function getInternalReference<T extends object, K extends keyof T>(target: T, key: K): T[K];
@@ -0,0 +1,21 @@
1
+ /**
2
+ * Per-fragment metadata the compat adapter attaches to the fragment's shadow root.
3
+ *
4
+ * The virtualized `document.readyState` can't be delegated to either document (the fragment
5
+ * needs its own lifecycle), so the adapter manages it here and the document facade reads it.
6
+ */
7
+ export const compatMetadataSymbol = Symbol('braid-compat:metadata');
8
+ /** Internal-reference bookkeeping: native members captured before facade/patch installation. */
9
+ const compatReferencesSymbol = Symbol('braid-compat:references');
10
+ export function setInternalReference(target, key) {
11
+ target[compatReferencesSymbol] ??= {};
12
+ target[compatReferencesSymbol][key] = Reflect.get(target, key);
13
+ }
14
+ export function getInternalReference(target, key) {
15
+ const references = target[compatReferencesSymbol];
16
+ if (!references || references[key] === undefined) {
17
+ throw new Error(`Attempted to access internal reference "${String(key)}" before it was set.`);
18
+ }
19
+ return references[key];
20
+ }
21
+ //# sourceMappingURL=metadata.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"metadata.js","sourceRoot":"","sources":["../../../../../libs/core/src/compat/metadata.ts"],"names":[],"mappings":"AAAA;;;;;GAKG;AAMH,MAAM,CAAC,MAAM,oBAAoB,GAAG,MAAM,CAAC,uBAAuB,CAAC,CAAC;AAMpE,gGAAgG;AAChG,MAAM,sBAAsB,GAAG,MAAM,CAAC,yBAAyB,CAAC,CAAC;AAEjE,MAAM,UAAU,oBAAoB,CAAmB,MAAS,EAAE,GAAY;IAC3E,MAAc,CAAC,sBAAsB,CAAC,KAAK,EAAE,CAAC;IAC9C,MAAc,CAAC,sBAAsB,CAAC,CAAC,GAAG,CAAC,GAAG,OAAO,CAAC,GAAG,CAAC,MAAM,EAAE,GAAG,CAAC,CAAC;AAC1E,CAAC;AAED,MAAM,UAAU,oBAAoB,CAAsC,MAAS,EAAE,GAAM;IACzF,MAAM,UAAU,GAAI,MAAc,CAAC,sBAAsB,CAAC,CAAC;IAC3D,IAAI,CAAC,UAAU,IAAI,UAAU,CAAC,GAAG,CAAC,KAAK,SAAS,EAAE,CAAC;QACjD,MAAM,IAAI,KAAK,CAAC,2CAA2C,MAAM,CAAC,GAAG,CAAC,sBAAsB,CAAC,CAAC;IAChG,CAAC;IAED,OAAO,UAAU,CAAC,GAAG,CAAC,CAAC;AACzB,CAAC"}
@@ -0,0 +1,29 @@
1
+ export declare const navigationBus: {
2
+ /** Subscribes to host-initiated navigations. Returns an unsubscribe function. */
3
+ subscribe(subscriber: () => void): () => void;
4
+ /**
5
+ * Applies a fragment-initiated history mutation, suppressing the automatic host navigation
6
+ * sources for its (synchronous) duration so the mutation isn't re-reported as a host
7
+ * navigation.
8
+ */
9
+ withFragmentNavigation<T>(applyNavigation: () => T): T;
10
+ /**
11
+ * Reports a host-initiated navigation (from an adapter or an automatic source).
12
+ *
13
+ * The first detection is delivered to fragments synchronously (fragments must observe the new
14
+ * location before the host performs any follow-up history operations — delayed delivery can
15
+ * cancel pending history traversals in some browsers). Further detections of the same
16
+ * navigation by other sources — e.g. the Navigation API firing synchronously during
17
+ * `pushState` plus the host router calling the `onHostNavigation` notify callback right after
18
+ * — are swallowed until the current microtask queue drains.
19
+ *
20
+ * Suppression is keyed on the location, not on time alone. Routers report navigation in
21
+ * several phases, and the early ones fire *before* the URL changes: Angular's `NavigationStart`
22
+ * is the common case. Time-only suppression would deliver that stale phase and then swallow
23
+ * the one that actually moved the page, leaving fragments a navigation behind — so a detection
24
+ * that finds a location we haven't delivered yet always gets through.
25
+ */
26
+ hostNavigationDetected(): void;
27
+ };
28
+ /** Installs the host navigation sources (idempotent). Neither source mutates any host global. */
29
+ export declare function ensureHostNavigationSources(): void;
@@ -0,0 +1,92 @@
1
+ import { getBraidConfig } from '../config.js';
2
+ /**
3
+ * Host navigation detection — without host patches, ever.
4
+ *
5
+ * Fragment-initiated navigations are broadcast via a synthetic popstate event dispatched on the
6
+ * main window — that mechanism mutates no host globals and is part of the observable contract
7
+ * (the host application can react to fragment-driven URL changes through a regular popstate
8
+ * listener).
9
+ *
10
+ * Host-initiated `pushState`/`replaceState` calls are detected through patch-free sources:
11
+ *
12
+ * 1. the `onHostNavigation` adapter from the library config: the host wires its router's
13
+ * after-navigation hook to our notify callback;
14
+ * 2. the Navigation API's `currententrychange` event, where available. Traversals are ignored
15
+ * (covered natively by `popstate`), and fragment-initiated mutations are suppressed via
16
+ * {@link navigationBus.withFragmentNavigation} so they aren't double-reported.
17
+ */
18
+ const hostNavigationSubscribers = new Set();
19
+ /** True while a fragment-initiated history mutation is being applied. */
20
+ let fragmentNavigationInProgress = false;
21
+ /** True right after a host navigation was delivered, until the current microtask queue drains. */
22
+ let suppressDuplicateDetections = false;
23
+ /** The location as of the last delivered detection, used to tell duplicates from real moves. */
24
+ let lastDeliveredHref;
25
+ export const navigationBus = {
26
+ /** Subscribes to host-initiated navigations. Returns an unsubscribe function. */
27
+ subscribe(subscriber) {
28
+ hostNavigationSubscribers.add(subscriber);
29
+ return () => hostNavigationSubscribers.delete(subscriber);
30
+ },
31
+ /**
32
+ * Applies a fragment-initiated history mutation, suppressing the automatic host navigation
33
+ * sources for its (synchronous) duration so the mutation isn't re-reported as a host
34
+ * navigation.
35
+ */
36
+ withFragmentNavigation(applyNavigation) {
37
+ fragmentNavigationInProgress = true;
38
+ try {
39
+ return applyNavigation();
40
+ }
41
+ finally {
42
+ fragmentNavigationInProgress = false;
43
+ }
44
+ },
45
+ /**
46
+ * Reports a host-initiated navigation (from an adapter or an automatic source).
47
+ *
48
+ * The first detection is delivered to fragments synchronously (fragments must observe the new
49
+ * location before the host performs any follow-up history operations — delayed delivery can
50
+ * cancel pending history traversals in some browsers). Further detections of the same
51
+ * navigation by other sources — e.g. the Navigation API firing synchronously during
52
+ * `pushState` plus the host router calling the `onHostNavigation` notify callback right after
53
+ * — are swallowed until the current microtask queue drains.
54
+ *
55
+ * Suppression is keyed on the location, not on time alone. Routers report navigation in
56
+ * several phases, and the early ones fire *before* the URL changes: Angular's `NavigationStart`
57
+ * is the common case. Time-only suppression would deliver that stale phase and then swallow
58
+ * the one that actually moved the page, leaving fragments a navigation behind — so a detection
59
+ * that finds a location we haven't delivered yet always gets through.
60
+ */
61
+ hostNavigationDetected() {
62
+ if (fragmentNavigationInProgress)
63
+ return;
64
+ const href = typeof location === 'undefined' ? undefined : location.href;
65
+ if (suppressDuplicateDetections && href === lastDeliveredHref)
66
+ return;
67
+ lastDeliveredHref = href;
68
+ suppressDuplicateDetections = true;
69
+ queueMicrotask(() => {
70
+ suppressDuplicateDetections = false;
71
+ });
72
+ hostNavigationSubscribers.forEach((subscriber) => subscriber());
73
+ },
74
+ };
75
+ let hostNavigationSourcesInstalled = false;
76
+ /** Installs the host navigation sources (idempotent). Neither source mutates any host global. */
77
+ export function ensureHostNavigationSources() {
78
+ if (hostNavigationSourcesInstalled)
79
+ return;
80
+ hostNavigationSourcesInstalled = true;
81
+ const { onHostNavigation } = getBraidConfig();
82
+ onHostNavigation?.(() => navigationBus.hostNavigationDetected());
83
+ const navigation = window.navigation;
84
+ if (navigation?.addEventListener) {
85
+ navigation.addEventListener('currententrychange', (event) => {
86
+ if (event?.navigationType === 'traverse')
87
+ return;
88
+ navigationBus.hostNavigationDetected();
89
+ });
90
+ }
91
+ }
92
+ //# sourceMappingURL=navigation-bus.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"navigation-bus.js","sourceRoot":"","sources":["../../../../../libs/core/src/compat/navigation-bus.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,cAAc,EAAE,MAAM,cAAc,CAAC;AAE9C;;;;;;;;;;;;;;;GAeG;AAEH,MAAM,yBAAyB,GAAG,IAAI,GAAG,EAAc,CAAC;AAExD,yEAAyE;AACzE,IAAI,4BAA4B,GAAG,KAAK,CAAC;AAEzC,kGAAkG;AAClG,IAAI,2BAA2B,GAAG,KAAK,CAAC;AAExC,gGAAgG;AAChG,IAAI,iBAAqC,CAAC;AAE1C,MAAM,CAAC,MAAM,aAAa,GAAG;IAC3B,iFAAiF;IACjF,SAAS,CAAC,UAAsB;QAC9B,yBAAyB,CAAC,GAAG,CAAC,UAAU,CAAC,CAAC;QAC1C,OAAO,GAAG,EAAE,CAAC,yBAAyB,CAAC,MAAM,CAAC,UAAU,CAAC,CAAC;IAC5D,CAAC;IAED;;;;OAIG;IACH,sBAAsB,CAAI,eAAwB;QAChD,4BAA4B,GAAG,IAAI,CAAC;QACpC,IAAI,CAAC;YACH,OAAO,eAAe,EAAE,CAAC;QAC3B,CAAC;gBAAS,CAAC;YACT,4BAA4B,GAAG,KAAK,CAAC;QACvC,CAAC;IACH,CAAC;IAED;;;;;;;;;;;;;;;OAeG;IACH,sBAAsB;QACpB,IAAI,4BAA4B;YAAE,OAAO;QAEzC,MAAM,IAAI,GAAG,OAAO,QAAQ,KAAK,WAAW,CAAC,CAAC,CAAC,SAAS,CAAC,CAAC,CAAC,QAAQ,CAAC,IAAI,CAAC;QACzE,IAAI,2BAA2B,IAAI,IAAI,KAAK,iBAAiB;YAAE,OAAO;QAEtE,iBAAiB,GAAG,IAAI,CAAC;QACzB,2BAA2B,GAAG,IAAI,CAAC;QACnC,cAAc,CAAC,GAAG,EAAE;YAClB,2BAA2B,GAAG,KAAK,CAAC;QACtC,CAAC,CAAC,CAAC;QACH,yBAAyB,CAAC,OAAO,CAAC,CAAC,UAAU,EAAE,EAAE,CAAC,UAAU,EAAE,CAAC,CAAC;IAClE,CAAC;CACF,CAAC;AAEF,IAAI,8BAA8B,GAAG,KAAK,CAAC;AAE3C,iGAAiG;AACjG,MAAM,UAAU,2BAA2B;IACzC,IAAI,8BAA8B;QAAE,OAAO;IAC3C,8BAA8B,GAAG,IAAI,CAAC;IAEtC,MAAM,EAAE,gBAAgB,EAAE,GAAG,cAAc,EAAE,CAAC;IAC9C,gBAAgB,EAAE,CAAC,GAAG,EAAE,CAAC,aAAa,CAAC,sBAAsB,EAAE,CAAC,CAAC;IAEjE,MAAM,UAAU,GAAI,MAAc,CAAC,UAAU,CAAC;IAC9C,IAAI,UAAU,EAAE,gBAAgB,EAAE,CAAC;QACjC,UAAU,CAAC,gBAAgB,CAAC,oBAAoB,EAAE,CAAC,KAAU,EAAE,EAAE;YAC/D,IAAI,KAAK,EAAE,cAAc,KAAK,UAAU;gBAAE,OAAO;YACjD,aAAa,CAAC,sBAAsB,EAAE,CAAC;QACzC,CAAC,CAAC,CAAC;IACL,CAAC;AACH,CAAC"}
@@ -0,0 +1,21 @@
1
+ import { CompatShadowRoot } from './metadata.js';
2
+ import { FragmentBoundary } from './fragment-boundary.js';
3
+ import { RealmHandle } from '../realm/realm-manager.js';
4
+ /**
5
+ * Realm-side monkey patches: applied to the fragment's own realm window so
6
+ * that code running in it behaves as if it were running in the main frame.
7
+ *
8
+ * Everything here patches objects the runtime itself created (the hidden realm iframe) or nodes
9
+ * confined to the fragment's boundary — the host page's globals and prototypes are never
10
+ * touched.
11
+ */
12
+ export interface RealmContext extends FragmentBoundary {
13
+ /**
14
+ * Ends the boot window, after which a bound fragment's navigations may drive the host URL.
15
+ *
16
+ * Called by the adapter once the fragment's own scripts have run. See the boot-window note in
17
+ * the history patches: a router resolving its initial route is not the user navigating.
18
+ */
19
+ bootComplete(): void;
20
+ }
21
+ export declare function initializeRealmContext(realm: RealmHandle, fragmentShadowRoot: CompatShadowRoot, braidDocumentElement: HTMLElement, boundNavigation: boolean, fragmentAbortController: AbortController): RealmContext;