@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.
- package/README.md +123 -0
- package/package.json +37 -0
- package/src/adapters/adapter.d.ts +75 -0
- package/src/adapters/adapter.js +35 -0
- package/src/adapters/adapter.js.map +1 -0
- package/src/adapters/compat-adapter.d.ts +27 -0
- package/src/adapters/compat-adapter.js +113 -0
- package/src/adapters/compat-adapter.js.map +1 -0
- package/src/adapters/custom-element-adapter.d.ts +21 -0
- package/src/adapters/custom-element-adapter.js +91 -0
- package/src/adapters/custom-element-adapter.js.map +1 -0
- package/src/compat/born-inert-scripts.d.ts +30 -0
- package/src/compat/born-inert-scripts.js +85 -0
- package/src/compat/born-inert-scripts.js.map +1 -0
- package/src/compat/document-facade.d.ts +44 -0
- package/src/compat/document-facade.js +104 -0
- package/src/compat/document-facade.js.map +1 -0
- package/src/compat/document-member-classification.d.ts +30 -0
- package/src/compat/document-member-classification.js +64 -0
- package/src/compat/document-member-classification.js.map +1 -0
- package/src/compat/document-overrides.d.ts +44 -0
- package/src/compat/document-overrides.js +225 -0
- package/src/compat/document-overrides.js.map +1 -0
- package/src/compat/document-surface.generated.d.ts +21 -0
- package/src/compat/document-surface.generated.js +292 -0
- package/src/compat/document-surface.generated.js.map +1 -0
- package/src/compat/fragment-boundary.d.ts +14 -0
- package/src/compat/fragment-boundary.js +335 -0
- package/src/compat/fragment-boundary.js.map +1 -0
- package/src/compat/metadata.d.ts +15 -0
- package/src/compat/metadata.js +21 -0
- package/src/compat/metadata.js.map +1 -0
- package/src/compat/navigation-bus.d.ts +29 -0
- package/src/compat/navigation-bus.js +92 -0
- package/src/compat/navigation-bus.js.map +1 -0
- package/src/compat/realm-patches.d.ts +21 -0
- package/src/compat/realm-patches.js +573 -0
- package/src/compat/realm-patches.js.map +1 -0
- package/src/compat/register-worker.d.ts +45 -0
- package/src/compat/register-worker.js +57 -0
- package/src/compat/register-worker.js.map +1 -0
- package/src/compat/script-execution.d.ts +65 -0
- package/src/compat/script-execution.js +361 -0
- package/src/compat/script-execution.js.map +1 -0
- package/src/compat/service-worker.d.ts +22 -0
- package/src/compat/service-worker.js +104 -0
- package/src/compat/service-worker.js.map +1 -0
- package/src/config.d.ts +37 -0
- package/src/config.js +26 -0
- package/src/config.js.map +1 -0
- package/src/context/context-bus.d.ts +67 -0
- package/src/context/context-bus.js +117 -0
- package/src/context/context-bus.js.map +1 -0
- package/src/elements/fragment-slot.d.ts +39 -0
- package/src/elements/fragment-slot.js +281 -0
- package/src/elements/fragment-slot.js.map +1 -0
- package/src/env/create-env.d.ts +31 -0
- package/src/env/create-env.js +91 -0
- package/src/env/create-env.js.map +1 -0
- package/src/env/fragment-env.d.ts +56 -0
- package/src/env/fragment-env.js +14 -0
- package/src/env/fragment-env.js.map +1 -0
- package/src/errors.d.ts +21 -0
- package/src/errors.js +21 -0
- package/src/errors.js.map +1 -0
- package/src/index.d.ts +36 -0
- package/src/index.js +40 -0
- package/src/index.js.map +1 -0
- package/src/protocol.d.ts +38 -0
- package/src/protocol.js +45 -0
- package/src/protocol.js.map +1 -0
- package/src/realm/realm-manager.d.ts +60 -0
- package/src/realm/realm-manager.js +296 -0
- package/src/realm/realm-manager.js.map +1 -0
- package/src/utils/assert.d.ts +7 -0
- package/src/utils/assert.js +10 -0
- package/src/utils/assert.js.map +1 -0
- package/src/utils/selector-helpers.d.ts +10 -0
- package/src/utils/selector-helpers.js +13 -0
- package/src/utils/selector-helpers.js.map +1 -0
|
@@ -0,0 +1,573 @@
|
|
|
1
|
+
/* eslint-disable @typescript-eslint/no-unsafe-function-type --
|
|
2
|
+
* ported from the matrix-tested web-fragments fork: constructor and History-method interception
|
|
3
|
+
* operates on arbitrary native function shapes. */
|
|
4
|
+
import { compatMetadataSymbol, setInternalReference, getInternalReference } from './metadata.js';
|
|
5
|
+
import { execToInertScriptMap } from './script-execution.js';
|
|
6
|
+
import { assert } from '../utils/assert.js';
|
|
7
|
+
import { installDocumentFacade } from './document-facade.js';
|
|
8
|
+
import { createDocumentOverrides } from './document-overrides.js';
|
|
9
|
+
import { createFragmentBoundary } from './fragment-boundary.js';
|
|
10
|
+
import { makeScriptBornInert } from './born-inert-scripts.js';
|
|
11
|
+
import { navigationBus, ensureHostNavigationSources } from './navigation-bus.js';
|
|
12
|
+
import { createRealmNavigator } from './service-worker.js';
|
|
13
|
+
export function initializeRealmContext(realm, fragmentShadowRoot, braidDocumentElement, boundNavigation, fragmentAbortController) {
|
|
14
|
+
assert(realm.window !== null && realm.document !== null, 'attempted to patch the realm before it was ready');
|
|
15
|
+
const realmWindow = realm.window;
|
|
16
|
+
const realmDocument = realm.document;
|
|
17
|
+
const mainDocument = fragmentShadowRoot.host.ownerDocument;
|
|
18
|
+
const mainWindow = mainDocument.defaultView;
|
|
19
|
+
// cleanup event listeners attached to the window when the realm iframe gets destroyed.
|
|
20
|
+
// TODO: "pagehide" would be preferred over the discouraged "unload" event, but we'd need to
|
|
21
|
+
// figure out how to restore the previously attached listeners if the page resumes from bfcache
|
|
22
|
+
realmWindow.addEventListener('unload', () => fragmentAbortController.abort());
|
|
23
|
+
/**
|
|
24
|
+
* All main-realm interception is confined to the fragment boundary: nodes inside the
|
|
25
|
+
* fragment's DOM are stamped with per-fragment prototypes and a shadow-root-scoped
|
|
26
|
+
* MutationObserver acts as the activation safety net.
|
|
27
|
+
*/
|
|
28
|
+
const fragmentBoundary = createFragmentBoundary({
|
|
29
|
+
realmDocument,
|
|
30
|
+
shadowRoot: fragmentShadowRoot,
|
|
31
|
+
braidDocumentElement,
|
|
32
|
+
abortSignal: fragmentAbortController.signal,
|
|
33
|
+
});
|
|
34
|
+
/** ---------------------------------------------- Window Patches ------------------------------------------------ */
|
|
35
|
+
/**
|
|
36
|
+
* START> WINDOW: GLOBAL CONSTRUCTORS PATCHES
|
|
37
|
+
*/
|
|
38
|
+
const globalConstructors = Object.entries(Object.getOwnPropertyDescriptors(realmWindow)).flatMap(([property, descriptor]) => /^[A-Z]/.test(property) && typeof descriptor.value === 'function' ? descriptor.value : []);
|
|
39
|
+
function hasInstance(instance) {
|
|
40
|
+
const parentContextConstructor = mainWindow[this.name];
|
|
41
|
+
return (Function.prototype[Symbol.hasInstance].call(this, instance) ||
|
|
42
|
+
(typeof parentContextConstructor === 'function' && instance instanceof parentContextConstructor));
|
|
43
|
+
}
|
|
44
|
+
// extend global constructors to support instanceof checks using
|
|
45
|
+
// their equivalent constructor from the parent execution context
|
|
46
|
+
globalConstructors.forEach((constructor) => {
|
|
47
|
+
try {
|
|
48
|
+
Object.defineProperty(constructor, Symbol.hasInstance, {
|
|
49
|
+
value: hasInstance,
|
|
50
|
+
});
|
|
51
|
+
}
|
|
52
|
+
catch (e) {
|
|
53
|
+
console.warn(`Braid compat: failed to patch \`${constructor.name}[Symbol.hasInstance]\`\nA browser extension might be interfering with the browser APIs...\nSome application functionality may not work as expected!`, '\nError:', e, `\nDescriptor:`, Object.getOwnPropertyDescriptor(constructor, Symbol.hasInstance));
|
|
54
|
+
}
|
|
55
|
+
});
|
|
56
|
+
// END> WINDOW: GLOBAL CONSTRUCTORS PATCHES
|
|
57
|
+
/**
|
|
58
|
+
* START> WINDOW: MISC PATCHES
|
|
59
|
+
*/
|
|
60
|
+
realmWindow.IntersectionObserver = mainWindow.IntersectionObserver;
|
|
61
|
+
realmWindow.MutationObserver = mainWindow.MutationObserver;
|
|
62
|
+
realmWindow.ResizeObserver = mainWindow.ResizeObserver;
|
|
63
|
+
// CSSStyleSheets don't work across documents, so we need to use the constructor from the main context
|
|
64
|
+
realmWindow.CSSStyleSheet = mainWindow.CSSStyleSheet;
|
|
65
|
+
realmWindow.matchMedia = mainWindow.matchMedia.bind(mainWindow); // needs to be bound to mainWindow otherwise operates on the realm window
|
|
66
|
+
// The realm's navigator is the host's, with one member contained: a service worker attaches to
|
|
67
|
+
// the whole origin and outlives the fragment, so a fragment must not be able to install one.
|
|
68
|
+
// See service-worker.ts — the realm isolates JavaScript, and a worker is not JavaScript state.
|
|
69
|
+
const realmNavigator = createRealmNavigator(mainWindow.navigator, realm.fragmentId);
|
|
70
|
+
// the navigator API is defined as an enumerable and configurable property with a getter and an undefined setter
|
|
71
|
+
Object.defineProperty(realmWindow, 'navigator', {
|
|
72
|
+
set: undefined,
|
|
73
|
+
get: () => realmNavigator,
|
|
74
|
+
configurable: true,
|
|
75
|
+
enumerable: true,
|
|
76
|
+
});
|
|
77
|
+
// dispatch events onto the shadowRoot if the event is not one of the special realm events
|
|
78
|
+
const originalDispatchEvent = realmWindow.dispatchEvent.bind(realmWindow);
|
|
79
|
+
realmWindow.dispatchEvent = function compatDispatchEvent(event) {
|
|
80
|
+
if (realmEvents.includes(event?.type)) {
|
|
81
|
+
return originalDispatchEvent(event);
|
|
82
|
+
}
|
|
83
|
+
else {
|
|
84
|
+
return fragmentShadowRoot.dispatchEvent(event);
|
|
85
|
+
}
|
|
86
|
+
};
|
|
87
|
+
const windowSizeProperties = ['innerHeight', 'innerWidth', 'outerHeight', 'outerWidth', 'visualViewport'];
|
|
88
|
+
for (const windowSizeProperty of windowSizeProperties) {
|
|
89
|
+
Object.defineProperty(realmWindow, windowSizeProperty, {
|
|
90
|
+
get: function compatWindowSizeGetter() {
|
|
91
|
+
return mainWindow[windowSizeProperty];
|
|
92
|
+
},
|
|
93
|
+
});
|
|
94
|
+
}
|
|
95
|
+
// END> WINDOW: MISC PATCHES
|
|
96
|
+
/**
|
|
97
|
+
* START> WINDOW: HISTORY PATCHES
|
|
98
|
+
*/
|
|
99
|
+
// WARNING: Be sure this class stays declared inside of this function!
|
|
100
|
+
// We rely on each compat context having its own instance of this constructor
|
|
101
|
+
// so we can use an instanceof check to avoid double-handling the event inside
|
|
102
|
+
// the same context it was dispatched from.
|
|
103
|
+
class SyntheticPopStateEvent extends PopStateEvent {
|
|
104
|
+
}
|
|
105
|
+
/**
|
|
106
|
+
* True until the fragment's own scripts have finished running.
|
|
107
|
+
*
|
|
108
|
+
* A framework's router performs an initial navigation as it starts — resolving a default route,
|
|
109
|
+
* following a `redirectTo`, normalizing a trailing slash. That is the fragment settling into the
|
|
110
|
+
* route it was *given*, not the user navigating, and letting it reach the host's History API
|
|
111
|
+
* means a fragment can rewrite the host's URL the instant it mounts.
|
|
112
|
+
*/
|
|
113
|
+
let booting = true;
|
|
114
|
+
/**
|
|
115
|
+
* Whether the user has acted inside this fragment.
|
|
116
|
+
*
|
|
117
|
+
* **Scripts having run is not the same as the router having settled**, and assuming it was is
|
|
118
|
+
* what let this bug survive its first fix. Angular resolves its initial route asynchronously —
|
|
119
|
+
* measured at ~170ms after mount, long after the last `<script>` returned — so a window that
|
|
120
|
+
* closed when boot finished was already open again by the time the redirect landed, and a
|
|
121
|
+
* fragment mounted on a page it does not own dragged the host to one of its own routes.
|
|
122
|
+
*
|
|
123
|
+
* No timing fix survives that honestly: the next router is slower than whatever delay we pick.
|
|
124
|
+
* So the gate is causal rather than temporal — a navigation the user did not ask for stays
|
|
125
|
+
* inside the realm, whenever it happens. The fragment still navigates itself; it just cannot
|
|
126
|
+
* move the address bar until someone touches it.
|
|
127
|
+
*
|
|
128
|
+
* The cost is deliberate: a bound fragment that redirects with no user input (an async auth
|
|
129
|
+
* check, say) now changes only its own location. That is the safer default of the two, and the
|
|
130
|
+
* host URL staying where the host put it is the property worth keeping.
|
|
131
|
+
*/
|
|
132
|
+
let userHasActed = false;
|
|
133
|
+
// Capture phase, so a fragment that stops propagation on its own handlers cannot also suppress
|
|
134
|
+
// the signal that it is being used.
|
|
135
|
+
for (const eventName of ['pointerdown', 'keydown', 'touchstart']) {
|
|
136
|
+
braidDocumentElement.addEventListener(eventName, () => void (userHasActed = true), {
|
|
137
|
+
capture: true,
|
|
138
|
+
signal: fragmentAbortController.signal,
|
|
139
|
+
});
|
|
140
|
+
}
|
|
141
|
+
if (boundNavigation) {
|
|
142
|
+
setInternalReference(realmWindow, 'history');
|
|
143
|
+
const historyProxy = new Proxy(mainWindow.history, {
|
|
144
|
+
get(target, property, receiver) {
|
|
145
|
+
if (typeof Object.getOwnPropertyDescriptor(History.prototype, property)?.value === 'function') {
|
|
146
|
+
return function (...args) {
|
|
147
|
+
// During boot, a bound fragment's navigation is confined to its own realm: the host
|
|
148
|
+
// keeps the URL it navigated to, and the fragment still gets the location it asked for.
|
|
149
|
+
if ((booting || !userHasActed) && MUTATING_HISTORY_METHODS.has(property)) {
|
|
150
|
+
return Reflect.apply(History.prototype.replaceState, getInternalReference(realmWindow, 'history'), [args[0], args[1] ?? '', args[2] ?? realmWindow.location.href]);
|
|
151
|
+
}
|
|
152
|
+
const applyNavigation = () => Reflect.apply(History.prototype[property], this === receiver ? target : this, args);
|
|
153
|
+
// suppress the automatic host navigation sources while we apply the mutation, so
|
|
154
|
+
// this fragment-initiated navigation isn't re-reported as a host navigation
|
|
155
|
+
const result = navigationBus.withFragmentNavigation(applyNavigation);
|
|
156
|
+
// dispatch a popstate event on the main window to inform listeners of a location change
|
|
157
|
+
// (both the host application and the other fragments observe navigations this way)
|
|
158
|
+
mainWindow.dispatchEvent(new SyntheticPopStateEvent('popstate'));
|
|
159
|
+
return result;
|
|
160
|
+
};
|
|
161
|
+
}
|
|
162
|
+
return Reflect.get(target, property, target);
|
|
163
|
+
},
|
|
164
|
+
set(target, property, receiver) {
|
|
165
|
+
return Reflect.set(target, property, receiver);
|
|
166
|
+
},
|
|
167
|
+
});
|
|
168
|
+
Object.defineProperties(realmWindow, {
|
|
169
|
+
history: {
|
|
170
|
+
get() {
|
|
171
|
+
return historyProxy;
|
|
172
|
+
},
|
|
173
|
+
},
|
|
174
|
+
});
|
|
175
|
+
}
|
|
176
|
+
else {
|
|
177
|
+
const standaloneHistoryStack = [
|
|
178
|
+
{ state: realmWindow.history.state, title: realmDocument.title, url: realmWindow.location.href },
|
|
179
|
+
];
|
|
180
|
+
let standaloneHistoryCursor = 0;
|
|
181
|
+
// for standalone fragments we should always use replaceState instead of pushState so that we
|
|
182
|
+
// don't create unexpected history entries in the joint session history. In order for back()
|
|
183
|
+
// and forward() to work correctly, we implement our own history stack with behavior similar
|
|
184
|
+
// to window.history
|
|
185
|
+
Object.defineProperties(realmWindow.history, {
|
|
186
|
+
pushState: {
|
|
187
|
+
value: function compatStandalonePushState(state, title, url) {
|
|
188
|
+
if (standaloneHistoryCursor !== standaloneHistoryStack.length - 1) {
|
|
189
|
+
standaloneHistoryStack.splice(standaloneHistoryCursor + 1);
|
|
190
|
+
}
|
|
191
|
+
standaloneHistoryStack.push({ state, title, url: url ?? null });
|
|
192
|
+
standaloneHistoryCursor++;
|
|
193
|
+
realmWindow.history.replaceState(state, title, url);
|
|
194
|
+
},
|
|
195
|
+
},
|
|
196
|
+
/**
|
|
197
|
+
* Traverses the virtual stack and tells the fragment about it.
|
|
198
|
+
*
|
|
199
|
+
* The `popstate` is not decoration: a router only learns it has moved by hearing one, so
|
|
200
|
+
* without it `back()` changed the URL and left the application rendering the previous route.
|
|
201
|
+
*/
|
|
202
|
+
go: {
|
|
203
|
+
value: function compatStandaloneGo(delta) {
|
|
204
|
+
// Unpatched, this reached the real `go()` — which traverses the **joint** session
|
|
205
|
+
// history and drags the top document with it. That is the whole hazard this branch
|
|
206
|
+
// exists to avoid, and it was reachable by any router calling `go(-1)`.
|
|
207
|
+
const steps = Math.trunc(delta ?? 0);
|
|
208
|
+
if (steps === 0)
|
|
209
|
+
return;
|
|
210
|
+
const next = Math.min(Math.max(standaloneHistoryCursor + steps, 0), standaloneHistoryStack.length - 1);
|
|
211
|
+
if (next === standaloneHistoryCursor)
|
|
212
|
+
return;
|
|
213
|
+
standaloneHistoryCursor = next;
|
|
214
|
+
const { state, title, url } = standaloneHistoryStack[standaloneHistoryCursor];
|
|
215
|
+
realmWindow.history.replaceState(state, title, url);
|
|
216
|
+
realmWindow.dispatchEvent(new PopStateEvent('popstate', { state }));
|
|
217
|
+
},
|
|
218
|
+
},
|
|
219
|
+
back: {
|
|
220
|
+
value: function compatStandaloneBack() {
|
|
221
|
+
realmWindow.history.go(-1);
|
|
222
|
+
},
|
|
223
|
+
},
|
|
224
|
+
forward: {
|
|
225
|
+
value: function compatStandaloneForward() {
|
|
226
|
+
realmWindow.history.go(1);
|
|
227
|
+
},
|
|
228
|
+
},
|
|
229
|
+
length: {
|
|
230
|
+
get() {
|
|
231
|
+
return standaloneHistoryStack.length;
|
|
232
|
+
},
|
|
233
|
+
},
|
|
234
|
+
});
|
|
235
|
+
}
|
|
236
|
+
if (boundNavigation) {
|
|
237
|
+
// When a navigation event occurs on the main window, either programmatically through the
|
|
238
|
+
// History API or by the back/forward button, we need to reflect those changes onto the
|
|
239
|
+
// realm's location via history.replaceState(), then dispatch a PopStateEvent so that
|
|
240
|
+
// fragments listening to popstate are made aware of the location change and retrigger
|
|
241
|
+
// their render updates.
|
|
242
|
+
const handleNavigate = (e) => {
|
|
243
|
+
getInternalReference(realmWindow, 'history').replaceState(window.history.state, '', window.location.href);
|
|
244
|
+
if (e instanceof SyntheticPopStateEvent) {
|
|
245
|
+
return;
|
|
246
|
+
}
|
|
247
|
+
realmWindow.dispatchEvent(new PopStateEvent('popstate', e instanceof PopStateEvent ? e : undefined));
|
|
248
|
+
};
|
|
249
|
+
// host-initiated pushState/replaceState calls are detected without patching the host's
|
|
250
|
+
// History API: via the onHostNavigation adapter and/or the Navigation API
|
|
251
|
+
const unsubscribe = navigationBus.subscribe(() => handleNavigate(new Event('braid:host-navigation')));
|
|
252
|
+
fragmentAbortController.signal.addEventListener('abort', unsubscribe);
|
|
253
|
+
ensureHostNavigationSources();
|
|
254
|
+
// Forward the popstate event triggered on the main window to every registered realm window.
|
|
255
|
+
// This covers native back/forward navigations as well as the synthetic popstate events
|
|
256
|
+
// dispatched by any fragment's history proxy.
|
|
257
|
+
window.addEventListener('popstate', handleNavigate, {
|
|
258
|
+
signal: fragmentAbortController.signal,
|
|
259
|
+
});
|
|
260
|
+
}
|
|
261
|
+
// END> WINDOW: HISTORY PATCHES
|
|
262
|
+
/** ---------------------------------------------- Document Patches ------------------------------------------------ */
|
|
263
|
+
/**
|
|
264
|
+
* START> DOCUMENT PATCHES
|
|
265
|
+
*
|
|
266
|
+
* The Document API surface is virtualized via a proxy facade spliced into the document's
|
|
267
|
+
* prototype chain. The virtualized member implementations live in document-overrides.ts, and
|
|
268
|
+
* every Document member's audit status is recorded in document-member-classification.ts.
|
|
269
|
+
*
|
|
270
|
+
* Note: native references (body, currentScript) must be captured before the facade is installed.
|
|
271
|
+
*/
|
|
272
|
+
setInternalReference(realmDocument, 'body');
|
|
273
|
+
const getUnpatchedRealmDocumentCurrentScript = Object.getOwnPropertyDescriptor(Object.getPrototypeOf(Object.getPrototypeOf(realmDocument)), 'currentScript').get.bind(realmDocument);
|
|
274
|
+
installDocumentFacade(realmDocument, createDocumentOverrides({
|
|
275
|
+
realmDocument,
|
|
276
|
+
mainDocument,
|
|
277
|
+
braidDocumentElement,
|
|
278
|
+
fragmentShadowRoot,
|
|
279
|
+
boundNavigation,
|
|
280
|
+
getRealmDocumentReadyState: () => fragmentShadowRoot[compatMetadataSymbol].documentReadyState,
|
|
281
|
+
// grab the currently executing script in the realm, and map it to its clone in the main document
|
|
282
|
+
getCurrentScript: () => execToInertScriptMap.get(getUnpatchedRealmDocumentCurrentScript()),
|
|
283
|
+
boundary: {
|
|
284
|
+
stampNode: fragmentBoundary.stampNode,
|
|
285
|
+
makeScriptBornInert,
|
|
286
|
+
},
|
|
287
|
+
}));
|
|
288
|
+
// END> DOCUMENT PATCHES
|
|
289
|
+
/** ---------------------------------------------- Event System Patches ------------------------------------------------ */
|
|
290
|
+
/**
|
|
291
|
+
* START> EVENT SYSTEM PATCHES
|
|
292
|
+
*/
|
|
293
|
+
// A list of events for which we don't want to retarget listeners as these events are dispatched in the realm.
|
|
294
|
+
const realmEvents = ['load', 'popstate', 'beforeunload', 'unload'];
|
|
295
|
+
// Maps realm EventTargets (window and document) to a target in the main context
|
|
296
|
+
const realmTargetToFragmentTarget = (target) => {
|
|
297
|
+
switch (target) {
|
|
298
|
+
case realmWindow:
|
|
299
|
+
return fragmentShadowRoot;
|
|
300
|
+
case realmDocument:
|
|
301
|
+
return braidDocumentElement;
|
|
302
|
+
default:
|
|
303
|
+
return target;
|
|
304
|
+
}
|
|
305
|
+
};
|
|
306
|
+
const mainTargetToRealmTarget = (target) => {
|
|
307
|
+
switch (target) {
|
|
308
|
+
case mainWindow:
|
|
309
|
+
return realmWindow;
|
|
310
|
+
case mainDocument:
|
|
311
|
+
return realmDocument;
|
|
312
|
+
case mainDocument.documentElement:
|
|
313
|
+
return realmDocument.documentElement;
|
|
314
|
+
case mainDocument.body:
|
|
315
|
+
return realmDocument.body;
|
|
316
|
+
default:
|
|
317
|
+
console.warn('Braid compat events: Unknown main context target: ', target);
|
|
318
|
+
return target;
|
|
319
|
+
}
|
|
320
|
+
};
|
|
321
|
+
const fragmentTargetToMainTarget = (target) => {
|
|
322
|
+
switch (target) {
|
|
323
|
+
case fragmentShadowRoot:
|
|
324
|
+
return mainWindow;
|
|
325
|
+
case braidDocumentElement:
|
|
326
|
+
return mainDocument;
|
|
327
|
+
case realmDocument.documentElement:
|
|
328
|
+
return mainDocument.documentElement;
|
|
329
|
+
case realmDocument.body:
|
|
330
|
+
return mainDocument.body;
|
|
331
|
+
default:
|
|
332
|
+
console.warn('Braid compat events: Unknown fragment context target: ', target);
|
|
333
|
+
return target;
|
|
334
|
+
}
|
|
335
|
+
};
|
|
336
|
+
// Weak map that maps app-provided listeners to listeners actually registered with the DOM.
|
|
337
|
+
// The main purpose of this map is to facilitate deregistration of event listeners
|
|
338
|
+
const appToCompatListenerMap = new WeakMap();
|
|
339
|
+
// Redirect event listeners (except for `realmEvents` defined above)
|
|
340
|
+
// from the realm window or document to the shadow root.
|
|
341
|
+
const compatAddEventListener = new Proxy(realmWindow.EventTarget.prototype.addEventListener, {
|
|
342
|
+
apply(originalAddEventListener, originalListenerTarget, argumentsList) {
|
|
343
|
+
const [eventName, appListenerOrObject, optionsOrCapture] = argumentsList;
|
|
344
|
+
// if the app didn't pass a listener, ignore the call
|
|
345
|
+
if (!appListenerOrObject)
|
|
346
|
+
return;
|
|
347
|
+
if (!originalListenerTarget) {
|
|
348
|
+
// addEventListener can be called unbound, in which case the target is the realm window
|
|
349
|
+
originalListenerTarget = realmWindow;
|
|
350
|
+
}
|
|
351
|
+
// if the event is a realm event, then skip everything and register the listener directly on the realm window
|
|
352
|
+
if (realmEvents.includes(eventName) && originalListenerTarget === realmWindow) {
|
|
353
|
+
originalAddEventListener.call(realmWindow, eventName, appListenerOrObject, optionsOrCapture);
|
|
354
|
+
return;
|
|
355
|
+
}
|
|
356
|
+
// normalize the options object
|
|
357
|
+
const options = typeof optionsOrCapture === 'boolean'
|
|
358
|
+
? { capture: optionsOrCapture }
|
|
359
|
+
: typeof optionsOrCapture === 'object'
|
|
360
|
+
? optionsOrCapture ?? {}
|
|
361
|
+
: {};
|
|
362
|
+
// browsers default to passive events for the following events
|
|
363
|
+
// https://dom.spec.whatwg.org/#default-passive-value
|
|
364
|
+
if (!('passive' in options) &&
|
|
365
|
+
(eventName === 'mousewheel' ||
|
|
366
|
+
eventName === 'touchstart' ||
|
|
367
|
+
eventName === 'touchmove' ||
|
|
368
|
+
eventName === 'wheel') &&
|
|
369
|
+
(originalListenerTarget === realmWindow ||
|
|
370
|
+
originalListenerTarget === realmDocument ||
|
|
371
|
+
originalListenerTarget === realmDocument.documentElement ||
|
|
372
|
+
originalListenerTarget === realmDocument.body)) {
|
|
373
|
+
options.passive = true;
|
|
374
|
+
}
|
|
375
|
+
// normalize appListener
|
|
376
|
+
const appListener = typeof appListenerOrObject === 'object' ? appListenerOrObject?.handleEvent : appListenerOrObject;
|
|
377
|
+
if (!appListener) {
|
|
378
|
+
// this is some kind of unknown listener, possibly feature detection for passive event
|
|
379
|
+
// support like the one performed by react
|
|
380
|
+
Reflect.apply(originalAddEventListener, originalListenerTarget, argumentsList);
|
|
381
|
+
return;
|
|
382
|
+
}
|
|
383
|
+
// reuse or create if needed a wrapper around the appListener that will patch the event to
|
|
384
|
+
// make it look like an event the app receives in standalone mode.
|
|
385
|
+
let { compatListener, mainProxyListener } = appToCompatListenerMap.get(appListener) ?? {};
|
|
386
|
+
if (!compatListener || !mainProxyListener) {
|
|
387
|
+
// create the compat listener
|
|
388
|
+
compatListener = function compatListener(event) {
|
|
389
|
+
// capture properties of the original event
|
|
390
|
+
const originalEventProps = {
|
|
391
|
+
target: event.target,
|
|
392
|
+
currentTarget: event.currentTarget,
|
|
393
|
+
// TODO(perf): could we defer the composedPath() call until we actually need it
|
|
394
|
+
composedPath: event.composedPath(),
|
|
395
|
+
};
|
|
396
|
+
// rewrite the composedPath by removing any references to the main or fragment objects
|
|
397
|
+
let compatComposedPath = [...originalEventProps.composedPath];
|
|
398
|
+
if (compatComposedPath.length === 1 && compatComposedPath[0] === fragmentShadowRoot) {
|
|
399
|
+
compatComposedPath = [realmWindow];
|
|
400
|
+
}
|
|
401
|
+
else {
|
|
402
|
+
compatComposedPath.splice(
|
|
403
|
+
// remove braidDocumentElement and everything above it
|
|
404
|
+
originalEventProps.composedPath.indexOf(braidDocumentElement), Infinity,
|
|
405
|
+
// and add the realmDocument and realmWindow to the list
|
|
406
|
+
realmDocument, realmWindow);
|
|
407
|
+
}
|
|
408
|
+
// patch the event
|
|
409
|
+
const originalEventPrototype = Object.getPrototypeOf(event);
|
|
410
|
+
const eventPatch = Object.create(originalEventPrototype, {
|
|
411
|
+
currentTarget: {
|
|
412
|
+
get() {
|
|
413
|
+
return originalListenerTarget;
|
|
414
|
+
},
|
|
415
|
+
},
|
|
416
|
+
composedPath: {
|
|
417
|
+
value: () => {
|
|
418
|
+
return compatComposedPath;
|
|
419
|
+
},
|
|
420
|
+
},
|
|
421
|
+
target: {
|
|
422
|
+
get() {
|
|
423
|
+
return originalEventProps.target === fragmentShadowRoot ? realmWindow : originalEventProps.target;
|
|
424
|
+
},
|
|
425
|
+
},
|
|
426
|
+
});
|
|
427
|
+
if (event instanceof UIEvent) {
|
|
428
|
+
Object.defineProperty(eventPatch, 'view', {
|
|
429
|
+
get() {
|
|
430
|
+
return realmWindow;
|
|
431
|
+
},
|
|
432
|
+
});
|
|
433
|
+
}
|
|
434
|
+
// splice the patched event object into the prototype chain, this ensures that:
|
|
435
|
+
// - the instanceof checks keep on working
|
|
436
|
+
// - the isTrusted property is preserved
|
|
437
|
+
// - the properties we need to patch get overshadowed in the prototypical lookup
|
|
438
|
+
// - unpatching the event is as simple as re-splicing the prototype chain later
|
|
439
|
+
Object.setPrototypeOf(event, eventPatch);
|
|
440
|
+
try {
|
|
441
|
+
appListener.call(originalListenerTarget, event);
|
|
442
|
+
}
|
|
443
|
+
finally {
|
|
444
|
+
// unpatch the event
|
|
445
|
+
Object.setPrototypeOf(event, originalEventPrototype);
|
|
446
|
+
}
|
|
447
|
+
};
|
|
448
|
+
// create the proxy listener retargeting the events from the main context
|
|
449
|
+
mainProxyListener = function compatProxyListener(event) {
|
|
450
|
+
if (event.target !== mainWindow &&
|
|
451
|
+
event.target !== mainDocument &&
|
|
452
|
+
event.target !== mainDocument.documentElement &&
|
|
453
|
+
event.target !== mainDocument.body) {
|
|
454
|
+
// if the event doesn't target any of the main top level EventTargets then we can ignore it —
|
|
455
|
+
// it is either not relevant for us or it targets an element in the fragment DOM and
|
|
456
|
+
// we'll handle it once it trickles down there
|
|
457
|
+
return;
|
|
458
|
+
}
|
|
459
|
+
// capture properties of the original event
|
|
460
|
+
const originalEventProps = {
|
|
461
|
+
target: event.target,
|
|
462
|
+
currentTarget: event.currentTarget,
|
|
463
|
+
};
|
|
464
|
+
// rewrite the composedPath by removing any references to the main or fragment objects
|
|
465
|
+
const compatComposedPath = event.composedPath().map(mainTargetToRealmTarget);
|
|
466
|
+
// patch the event
|
|
467
|
+
const originalEventPrototype = Object.getPrototypeOf(event);
|
|
468
|
+
const eventPatch = Object.create(originalEventPrototype, {
|
|
469
|
+
currentTarget: {
|
|
470
|
+
get() {
|
|
471
|
+
return originalListenerTarget;
|
|
472
|
+
},
|
|
473
|
+
},
|
|
474
|
+
target: {
|
|
475
|
+
get() {
|
|
476
|
+
return mainTargetToRealmTarget(originalEventProps.target);
|
|
477
|
+
},
|
|
478
|
+
},
|
|
479
|
+
composedPath: {
|
|
480
|
+
value: () => {
|
|
481
|
+
return compatComposedPath;
|
|
482
|
+
},
|
|
483
|
+
},
|
|
484
|
+
});
|
|
485
|
+
if (event instanceof UIEvent) {
|
|
486
|
+
Object.defineProperty(eventPatch, 'view', {
|
|
487
|
+
get() {
|
|
488
|
+
return realmWindow;
|
|
489
|
+
},
|
|
490
|
+
});
|
|
491
|
+
}
|
|
492
|
+
// splice the patched event object into the prototype chain (see compatListener above)
|
|
493
|
+
Object.setPrototypeOf(event, eventPatch);
|
|
494
|
+
try {
|
|
495
|
+
appListener.call(originalListenerTarget, event);
|
|
496
|
+
}
|
|
497
|
+
finally {
|
|
498
|
+
// unpatch the event
|
|
499
|
+
Object.setPrototypeOf(event, originalEventPrototype);
|
|
500
|
+
}
|
|
501
|
+
};
|
|
502
|
+
appToCompatListenerMap.set(appListener, {
|
|
503
|
+
compatListener,
|
|
504
|
+
mainProxyListener,
|
|
505
|
+
});
|
|
506
|
+
}
|
|
507
|
+
// determine the actual registration target within the fragment DOM tree
|
|
508
|
+
const compatListenerTarget = realmTargetToFragmentTarget(originalListenerTarget);
|
|
509
|
+
const modifiedArgumentsList = [eventName, compatListener, options];
|
|
510
|
+
Reflect.apply(originalAddEventListener, compatListenerTarget, modifiedArgumentsList);
|
|
511
|
+
if (eventName === 'DOMContentLoaded' || eventName === 'readystatechange') {
|
|
512
|
+
// DOMContentLoaded and readystatechange events are special in that they don't require
|
|
513
|
+
// shadow listeners — we dispatch them ourselves on the fragment document
|
|
514
|
+
return;
|
|
515
|
+
}
|
|
516
|
+
// and now let's register the shadow listener onto the main window
|
|
517
|
+
const mainProxyListenerTarget = fragmentTargetToMainTarget(compatListenerTarget);
|
|
518
|
+
// coalesce any provided signal with the one from our abort controller so that we can
|
|
519
|
+
// remove this listener when the fragment is destroyed
|
|
520
|
+
const mainProxyListenerAbortSignal = AbortSignal.any([fragmentAbortController.signal, options?.signal].filter((signal) => signal != null));
|
|
521
|
+
const mainProxyListenerOptions = {
|
|
522
|
+
...options,
|
|
523
|
+
signal: mainProxyListenerAbortSignal,
|
|
524
|
+
};
|
|
525
|
+
// register the listener on the main window, document, <html>, or <body> target
|
|
526
|
+
mainProxyListenerTarget.addEventListener(eventName, mainProxyListener, mainProxyListenerOptions);
|
|
527
|
+
},
|
|
528
|
+
});
|
|
529
|
+
const compatRemoveEventListener = new Proxy(realmWindow.EventTarget.prototype.removeEventListener, {
|
|
530
|
+
apply(originalRemoveEventListener, originalListenerTarget, argumentsList) {
|
|
531
|
+
const [eventName, appListenerOrObject, optionsOrCapture] = argumentsList;
|
|
532
|
+
if (!appListenerOrObject)
|
|
533
|
+
return;
|
|
534
|
+
if (!originalListenerTarget) {
|
|
535
|
+
// removeEventListener can be called unbound, in which case the target is the realm window
|
|
536
|
+
originalListenerTarget = realmWindow;
|
|
537
|
+
}
|
|
538
|
+
// if the event is a realm event, then skip everything and remove the listener directly on the realm window
|
|
539
|
+
if (realmEvents.includes(eventName) && originalListenerTarget === realmWindow) {
|
|
540
|
+
originalRemoveEventListener.call(realmWindow, eventName, appListenerOrObject, optionsOrCapture);
|
|
541
|
+
return;
|
|
542
|
+
}
|
|
543
|
+
const appListener = typeof appListenerOrObject === 'object' ? appListenerOrObject?.handleEvent : appListenerOrObject;
|
|
544
|
+
if (!appListener) {
|
|
545
|
+
// this is some kind of unknown listener, possibly feature detection for passive event support
|
|
546
|
+
Reflect.apply(originalRemoveEventListener, originalListenerTarget, argumentsList);
|
|
547
|
+
return;
|
|
548
|
+
}
|
|
549
|
+
const compatListenerTarget = realmTargetToFragmentTarget(originalListenerTarget);
|
|
550
|
+
const compatListeners = appToCompatListenerMap.get(appListener);
|
|
551
|
+
if (!compatListeners) {
|
|
552
|
+
// we never added this listener, so it likely isn't registered, pass it through just in case
|
|
553
|
+
Reflect.apply(originalRemoveEventListener, originalListenerTarget, argumentsList);
|
|
554
|
+
return;
|
|
555
|
+
}
|
|
556
|
+
const { compatListener, mainProxyListener } = compatListeners;
|
|
557
|
+
const modifiedArgumentsList = [eventName, compatListener, optionsOrCapture];
|
|
558
|
+
Reflect.apply(originalRemoveEventListener, compatListenerTarget, modifiedArgumentsList);
|
|
559
|
+
mainWindow.removeEventListener(eventName, mainProxyListener, optionsOrCapture);
|
|
560
|
+
},
|
|
561
|
+
});
|
|
562
|
+
realmWindow.addEventListener = realmDocument.addEventListener = compatAddEventListener;
|
|
563
|
+
realmWindow.removeEventListener = realmDocument.removeEventListener = compatRemoveEventListener;
|
|
564
|
+
// END: EVENT SYSTEM PATCHES
|
|
565
|
+
return Object.assign(fragmentBoundary, {
|
|
566
|
+
bootComplete() {
|
|
567
|
+
booting = false;
|
|
568
|
+
},
|
|
569
|
+
});
|
|
570
|
+
}
|
|
571
|
+
/** History methods that move the user, as opposed to reading state. */
|
|
572
|
+
const MUTATING_HISTORY_METHODS = new Set(['pushState', 'replaceState', 'back', 'forward', 'go']);
|
|
573
|
+
//# sourceMappingURL=realm-patches.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"realm-patches.js","sourceRoot":"","sources":["../../../../../libs/core/src/compat/realm-patches.ts"],"names":[],"mappings":"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"}
|
|
@@ -0,0 +1,45 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Registering Braid's service worker, from the shell.
|
|
3
|
+
*
|
|
4
|
+
* This is the shell's job rather than the runtime's, and that is a deliberate line. Braid is
|
|
5
|
+
* unopinionated about shells — prescribing one turns a library into a framework — so what ships here
|
|
6
|
+
* is the *wiring*, not the shell: one call, with the failure modes named.
|
|
7
|
+
*
|
|
8
|
+
* Note the asymmetry with everything else in this package. A fragment must **not** register a
|
|
9
|
+
* worker (compat realms refuse it, see `service-worker.ts`) because a fragment installing
|
|
10
|
+
* origin-wide persistent state outlives the fragment. The host may, because the origin is the
|
|
11
|
+
* host's.
|
|
12
|
+
*/
|
|
13
|
+
export interface RegisterBraidServiceWorkerOptions {
|
|
14
|
+
/** Where the gateway serves the script. Matches `serviceWorker: true` on the gateway. */
|
|
15
|
+
url?: string;
|
|
16
|
+
/**
|
|
17
|
+
* The scope to claim. Must be allowed by the script response's `Service-Worker-Allowed` header,
|
|
18
|
+
* which is exactly what the gateway sends.
|
|
19
|
+
*/
|
|
20
|
+
scope?: string;
|
|
21
|
+
/**
|
|
22
|
+
* Tell the worker what build this page is, so it can report disagreement.
|
|
23
|
+
*
|
|
24
|
+
* Sent as a message rather than baked into the script URL: a URL that changes per build is a new
|
|
25
|
+
* worker every deploy, with a fresh install-and-wait lifecycle each time.
|
|
26
|
+
*/
|
|
27
|
+
buildId?: string;
|
|
28
|
+
snapshotId?: string;
|
|
29
|
+
/** Called with the worker's answer, including any skew diagnosis. */
|
|
30
|
+
onVersion?: (report: unknown) => void;
|
|
31
|
+
}
|
|
32
|
+
/**
|
|
33
|
+
* Registers the worker and introduces the page to it.
|
|
34
|
+
*
|
|
35
|
+
* ```ts
|
|
36
|
+
* import { registerBraidServiceWorker } from '@braidlabs/core';
|
|
37
|
+
* await registerBraidServiceWorker({ buildId: BUILD_ID });
|
|
38
|
+
* ```
|
|
39
|
+
*
|
|
40
|
+
* Resolves to the registration, or `null` where service workers are unavailable — a non-secure
|
|
41
|
+
* origin, a browser without them, or SSR. That is a `null` rather than a throw because a worker is
|
|
42
|
+
* an enhancement: a page that works without one should not fail to start because it could not have
|
|
43
|
+
* one.
|
|
44
|
+
*/
|
|
45
|
+
export declare function registerBraidServiceWorker(options?: RegisterBraidServiceWorkerOptions): Promise<ServiceWorkerRegistration | null>;
|