wu-framework 1.2.0 → 2.1.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (154) hide show
  1. package/README.md +99 -18
  2. package/dist/adapters/alpine/index.js +2 -0
  3. package/dist/adapters/alpine/index.js.map +1 -0
  4. package/dist/adapters/angular/index.js +2 -0
  5. package/dist/adapters/angular/index.js.map +1 -0
  6. package/dist/adapters/htmx/index.js +2 -0
  7. package/dist/adapters/htmx/index.js.map +1 -0
  8. package/dist/adapters/index.js +2 -0
  9. package/dist/adapters/index.js.map +1 -0
  10. package/dist/adapters/lit/index.js +44 -0
  11. package/dist/adapters/lit/index.js.map +1 -0
  12. package/dist/adapters/preact/index.js +2 -0
  13. package/dist/adapters/preact/index.js.map +1 -0
  14. package/dist/adapters/qwik/index.js +2 -0
  15. package/dist/adapters/qwik/index.js.map +1 -0
  16. package/dist/adapters/react/index.js +2 -0
  17. package/dist/adapters/react/index.js.map +1 -0
  18. package/dist/adapters/shared.js +2 -0
  19. package/dist/adapters/shared.js.map +1 -0
  20. package/dist/adapters/solid/index.js +2 -0
  21. package/dist/adapters/solid/index.js.map +1 -0
  22. package/dist/adapters/stencil/index.js +2 -0
  23. package/dist/adapters/stencil/index.js.map +1 -0
  24. package/dist/adapters/stimulus/index.js +2 -0
  25. package/dist/adapters/stimulus/index.js.map +1 -0
  26. package/dist/adapters/svelte/index.js +2 -0
  27. package/dist/adapters/svelte/index.js.map +1 -0
  28. package/dist/adapters/vanilla/index.js +2 -0
  29. package/dist/adapters/vanilla/index.js.map +1 -0
  30. package/dist/adapters/vue/index.js +2 -0
  31. package/dist/adapters/vue/index.js.map +1 -0
  32. package/dist/ai/wu-ai.js +2 -0
  33. package/dist/ai/wu-ai.js.map +1 -0
  34. package/dist/core/wu-mcp-bridge.js +2 -0
  35. package/dist/core/wu-mcp-bridge.js.map +1 -0
  36. package/{src → dist}/index.d.ts +445 -317
  37. package/dist/wu-ai-browser-primitives-BDKXJlwc.js +2 -0
  38. package/dist/wu-ai-browser-primitives-BDKXJlwc.js.map +1 -0
  39. package/dist/wu-framework.cjs.js +3 -0
  40. package/dist/wu-framework.cjs.js.map +1 -0
  41. package/dist/wu-framework.dev.js +9175 -0
  42. package/dist/wu-framework.dev.js.map +1 -0
  43. package/dist/wu-framework.esm.js +3 -0
  44. package/dist/wu-framework.esm.js.map +1 -0
  45. package/dist/wu-framework.umd.js +3 -0
  46. package/dist/wu-framework.umd.js.map +1 -0
  47. package/dist/wu-html-parser.js +2 -0
  48. package/dist/wu-html-parser.js.map +1 -0
  49. package/dist/wu-iframe-sandbox.js +2 -0
  50. package/dist/wu-iframe-sandbox.js.map +1 -0
  51. package/dist/wu-logger-fJfUHBGA.js +2 -0
  52. package/dist/wu-logger-fJfUHBGA.js.map +1 -0
  53. package/dist/wu-script-executor.js +2 -0
  54. package/dist/wu-script-executor.js.map +1 -0
  55. package/package.json +43 -34
  56. package/src/adapters/alpine/index.js +0 -231
  57. package/src/adapters/alpine.js +0 -3
  58. package/src/adapters/angular/ai.js +0 -30
  59. package/src/adapters/angular/index.js +0 -932
  60. package/src/adapters/angular.js +0 -3
  61. package/src/adapters/htmx/index.js +0 -242
  62. package/src/adapters/htmx.js +0 -3
  63. package/src/adapters/index.js +0 -225
  64. package/src/adapters/lit/ai.js +0 -20
  65. package/src/adapters/lit/index.js +0 -721
  66. package/src/adapters/lit.js +0 -3
  67. package/src/adapters/preact/ai.js +0 -33
  68. package/src/adapters/preact/index.js +0 -661
  69. package/src/adapters/preact.js +0 -3
  70. package/src/adapters/qwik/index.js +0 -108
  71. package/src/adapters/qwik.js +0 -3
  72. package/src/adapters/react/ai.js +0 -135
  73. package/src/adapters/react/index.js +0 -695
  74. package/src/adapters/react.js +0 -3
  75. package/src/adapters/shared.js +0 -64
  76. package/src/adapters/solid/ai.js +0 -32
  77. package/src/adapters/solid/index.js +0 -586
  78. package/src/adapters/solid.js +0 -3
  79. package/src/adapters/stencil/index.js +0 -228
  80. package/src/adapters/stencil.js +0 -3
  81. package/src/adapters/stimulus/index.js +0 -255
  82. package/src/adapters/stimulus.js +0 -3
  83. package/src/adapters/svelte/ai.js +0 -31
  84. package/src/adapters/svelte/index.js +0 -798
  85. package/src/adapters/svelte.js +0 -3
  86. package/src/adapters/vanilla/ai.js +0 -30
  87. package/src/adapters/vanilla/index.js +0 -785
  88. package/src/adapters/vanilla.js +0 -3
  89. package/src/adapters/vue/ai.js +0 -52
  90. package/src/adapters/vue/index.js +0 -618
  91. package/src/adapters/vue.js +0 -3
  92. package/src/ai/wu-ai-actions.js +0 -261
  93. package/src/ai/wu-ai-agent.js +0 -546
  94. package/src/ai/wu-ai-browser-primitives.js +0 -354
  95. package/src/ai/wu-ai-browser.js +0 -380
  96. package/src/ai/wu-ai-context.js +0 -332
  97. package/src/ai/wu-ai-conversation.js +0 -613
  98. package/src/ai/wu-ai-orchestrate.js +0 -1021
  99. package/src/ai/wu-ai-permissions.js +0 -381
  100. package/src/ai/wu-ai-provider.js +0 -700
  101. package/src/ai/wu-ai-schema.js +0 -225
  102. package/src/ai/wu-ai-triggers.js +0 -396
  103. package/src/ai/wu-ai.js +0 -804
  104. package/src/core/wu-app.js +0 -236
  105. package/src/core/wu-cache.js +0 -498
  106. package/src/core/wu-core.js +0 -1412
  107. package/src/core/wu-error-boundary.js +0 -396
  108. package/src/core/wu-event-bus.js +0 -390
  109. package/src/core/wu-hooks.js +0 -350
  110. package/src/core/wu-html-parser.js +0 -199
  111. package/src/core/wu-iframe-sandbox.js +0 -328
  112. package/src/core/wu-loader.js +0 -385
  113. package/src/core/wu-logger.js +0 -143
  114. package/src/core/wu-manifest.js +0 -533
  115. package/src/core/wu-mcp-bridge.js +0 -432
  116. package/src/core/wu-overrides.js +0 -510
  117. package/src/core/wu-performance.js +0 -228
  118. package/src/core/wu-plugin.js +0 -401
  119. package/src/core/wu-prefetch.js +0 -414
  120. package/src/core/wu-proxy-sandbox.js +0 -477
  121. package/src/core/wu-sandbox.js +0 -779
  122. package/src/core/wu-script-executor.js +0 -161
  123. package/src/core/wu-snapshot-sandbox.js +0 -227
  124. package/src/core/wu-store.js +0 -307
  125. package/src/core/wu-strategies.js +0 -256
  126. package/src/core/wu-style-bridge.js +0 -477
  127. package/src/index.js +0 -234
  128. package/src/utils/dependency-resolver.js +0 -328
  129. /package/{src → dist}/adapters/alpine/index.d.ts +0 -0
  130. /package/{src → dist}/adapters/alpine.d.ts +0 -0
  131. /package/{src → dist}/adapters/angular/index.d.ts +0 -0
  132. /package/{src → dist}/adapters/angular.d.ts +0 -0
  133. /package/{src → dist}/adapters/htmx/index.d.ts +0 -0
  134. /package/{src → dist}/adapters/htmx.d.ts +0 -0
  135. /package/{src → dist}/adapters/lit/index.d.ts +0 -0
  136. /package/{src → dist}/adapters/lit.d.ts +0 -0
  137. /package/{src → dist}/adapters/preact/index.d.ts +0 -0
  138. /package/{src → dist}/adapters/preact.d.ts +0 -0
  139. /package/{src → dist}/adapters/qwik/index.d.ts +0 -0
  140. /package/{src → dist}/adapters/qwik.d.ts +0 -0
  141. /package/{src → dist}/adapters/react/index.d.ts +0 -0
  142. /package/{src → dist}/adapters/react.d.ts +0 -0
  143. /package/{src → dist}/adapters/solid/index.d.ts +0 -0
  144. /package/{src → dist}/adapters/solid.d.ts +0 -0
  145. /package/{src → dist}/adapters/stencil/index.d.ts +0 -0
  146. /package/{src → dist}/adapters/stencil.d.ts +0 -0
  147. /package/{src → dist}/adapters/stimulus/index.d.ts +0 -0
  148. /package/{src → dist}/adapters/stimulus.d.ts +0 -0
  149. /package/{src → dist}/adapters/svelte/index.d.ts +0 -0
  150. /package/{src → dist}/adapters/svelte.d.ts +0 -0
  151. /package/{src → dist}/adapters/vanilla/index.d.ts +0 -0
  152. /package/{src → dist}/adapters/vanilla.d.ts +0 -0
  153. /package/{src → dist}/adapters/vue/index.d.ts +0 -0
  154. /package/{src → dist}/adapters/vue.d.ts +0 -0
@@ -1,477 +0,0 @@
1
- /**
2
- * WU-PROXY-SANDBOX: Hardened JavaScript Isolation
3
- *
4
- * ES6 Proxy-based sandbox with side-effect tracking:
5
- * - Timer hijacking (setTimeout, setInterval, requestAnimationFrame)
6
- * - Event listener tracking (window + document addEventListener)
7
- * - DOM scoping (querySelector/querySelectorAll → shadow root)
8
- * - Storage scoping (localStorage/sessionStorage → prefixed keys)
9
- *
10
- * All tracked side effects are automatically cleaned up on deactivate().
11
- */
12
-
13
- import { logger } from './wu-logger.js';
14
-
15
- export class WuProxySandbox {
16
- constructor(appName, options = {}) {
17
- this.appName = appName;
18
- this.options = options;
19
- this.proxy = null;
20
- this.fakeWindow = Object.create(null);
21
- this.active = false;
22
- this.modifiedKeys = new Set();
23
-
24
- // --- Side-effect tracking ---
25
- this._timers = new Set();
26
- this._intervals = new Set();
27
- this._rafs = new Set();
28
- this._eventListeners = []; // [{target, event, handler, options}]
29
-
30
- // --- DOM & Storage scoping ---
31
- this._container = null;
32
- this._shadowRoot = null;
33
- this._scopedDocument = null;
34
- this._scopedLocalStorage = null;
35
- this._scopedSessionStorage = null;
36
-
37
- // --- Window patching state ---
38
- this._patched = false;
39
- this._originals = null;
40
- }
41
-
42
- /**
43
- * Set the DOM scope for this sandbox.
44
- * Must be called before activate() for DOM scoping to work.
45
- * @param {HTMLElement} container - App container element
46
- * @param {ShadowRoot} shadowRoot - Shadow root containing the container
47
- */
48
- setContainer(container, shadowRoot) {
49
- this._container = container;
50
- this._shadowRoot = shadowRoot;
51
- }
52
-
53
- /**
54
- * Activate the sandbox. Creates the Proxy and starts tracking.
55
- * @returns {Proxy} The sandboxed window proxy
56
- */
57
- activate() {
58
- if (this.active) return this.proxy;
59
-
60
- const self = this;
61
-
62
- this.proxy = new Proxy(window, {
63
- get(target, prop) {
64
- // 1. App's own isolated globals
65
- if (prop in self.fakeWindow) {
66
- return self.fakeWindow[prop];
67
- }
68
-
69
- // 2. Intercepted APIs
70
- const intercepted = self._intercept(prop, target);
71
- if (intercepted !== undefined) {
72
- return intercepted;
73
- }
74
-
75
- // 3. Real window value with correct binding
76
- const value = target[prop];
77
- if (typeof value === 'function' && !self._isConstructor(value)) {
78
- return value.bind(target);
79
- }
80
- return value;
81
- },
82
-
83
- set(target, prop, value) {
84
- self.fakeWindow[prop] = value;
85
- self.modifiedKeys.add(prop);
86
- return true;
87
- },
88
-
89
- has(target, prop) {
90
- return prop in self.fakeWindow || prop in target;
91
- },
92
-
93
- deleteProperty(target, prop) {
94
- if (prop in self.fakeWindow) {
95
- delete self.fakeWindow[prop];
96
- self.modifiedKeys.delete(prop);
97
- return true;
98
- }
99
- return false;
100
- }
101
- });
102
-
103
- this.active = true;
104
- logger.wuDebug(`[ProxySandbox] Activated for ${this.appName}`);
105
- return this.proxy;
106
- }
107
-
108
- /**
109
- * Deactivate the sandbox. Cleans up ALL tracked side effects.
110
- */
111
- deactivate() {
112
- if (!this.active) return;
113
-
114
- // Unpatch window if patched
115
- this.unpatchWindow();
116
-
117
- // --- Clean timers ---
118
- for (const id of this._timers) {
119
- try { clearTimeout(id); } catch {}
120
- }
121
- for (const id of this._intervals) {
122
- try { clearInterval(id); } catch {}
123
- }
124
- for (const id of this._rafs) {
125
- try { cancelAnimationFrame(id); } catch {}
126
- }
127
-
128
- const timerCount = this._timers.size + this._intervals.size + this._rafs.size;
129
- this._timers.clear();
130
- this._intervals.clear();
131
- this._rafs.clear();
132
-
133
- // --- Clean event listeners ---
134
- const listenerCount = this._eventListeners.length;
135
- for (const { target, event, handler, options } of this._eventListeners) {
136
- try { target.removeEventListener(event, handler, options); } catch {}
137
- }
138
- this._eventListeners = [];
139
-
140
- // --- Clean namespace ---
141
- this.fakeWindow = Object.create(null);
142
- this.modifiedKeys.clear();
143
- this._scopedDocument = null;
144
- this._scopedLocalStorage = null;
145
- this._scopedSessionStorage = null;
146
- this.proxy = null;
147
- this.active = false;
148
-
149
- if (timerCount > 0 || listenerCount > 0) {
150
- logger.wuDebug(
151
- `[ProxySandbox] ${this.appName} cleanup: ${timerCount} timers, ${listenerCount} listeners`
152
- );
153
- }
154
- logger.wuDebug(`[ProxySandbox] Deactivated for ${this.appName}`);
155
- }
156
-
157
- // ================================================================
158
- // WINDOW PATCHING - patches real window APIs during module loading
159
- // ================================================================
160
-
161
- /**
162
- * Patch real window APIs to track side effects from global code.
163
- * Call before loading app module, unpatch after.
164
- *
165
- * IMPORTANT: Uses closure over originals so patched functions remain
166
- * valid even after unpatchWindow() — prevents crashes when frameworks
167
- * (React 19, etc.) cache references to patched setTimeout during import.
168
- */
169
- patchWindow() {
170
- if (this._patched) return;
171
-
172
- const self = this;
173
-
174
- // Capture originals in a local closure that survives unpatch
175
- const originals = {
176
- setTimeout: window.setTimeout,
177
- clearTimeout: window.clearTimeout,
178
- setInterval: window.setInterval,
179
- clearInterval: window.clearInterval,
180
- requestAnimationFrame: window.requestAnimationFrame,
181
- cancelAnimationFrame: window.cancelAnimationFrame,
182
- addEventListener: window.addEventListener,
183
- removeEventListener: window.removeEventListener
184
- };
185
-
186
- // Store reference (used by unpatchWindow to restore)
187
- this._originals = originals;
188
-
189
- // Patch timers — closure captures `originals`, not `self._originals`
190
- window.setTimeout = function(fn, delay, ...args) {
191
- const id = originals.setTimeout.call(window, fn, delay, ...args);
192
- if (self._patched) self._timers.add(id);
193
- return id;
194
- };
195
- window.clearTimeout = function(id) {
196
- self._timers.delete(id);
197
- return originals.clearTimeout.call(window, id);
198
- };
199
- window.setInterval = function(fn, delay, ...args) {
200
- const id = originals.setInterval.call(window, fn, delay, ...args);
201
- if (self._patched) self._intervals.add(id);
202
- return id;
203
- };
204
- window.clearInterval = function(id) {
205
- self._intervals.delete(id);
206
- return originals.clearInterval.call(window, id);
207
- };
208
- window.requestAnimationFrame = function(fn) {
209
- const id = originals.requestAnimationFrame.call(window, fn);
210
- if (self._patched) self._rafs.add(id);
211
- return id;
212
- };
213
- window.cancelAnimationFrame = function(id) {
214
- self._rafs.delete(id);
215
- return originals.cancelAnimationFrame.call(window, id);
216
- };
217
-
218
- // Patch event listeners
219
- window.addEventListener = function(event, handler, options) {
220
- if (self._patched) self._eventListeners.push({ target: window, event, handler, options });
221
- return originals.addEventListener.call(window, event, handler, options);
222
- };
223
- window.removeEventListener = function(event, handler, options) {
224
- self._eventListeners = self._eventListeners.filter(
225
- l => !(l.target === window && l.event === event && l.handler === handler)
226
- );
227
- return originals.removeEventListener.call(window, event, handler, options);
228
- };
229
-
230
- this._patched = true;
231
- logger.wuDebug(`[ProxySandbox] Window patched for ${this.appName}`);
232
- }
233
-
234
- /**
235
- * Restore original window APIs.
236
- * Safe: patched functions still work via closure even after restore.
237
- */
238
- unpatchWindow() {
239
- if (!this._patched || !this._originals) return;
240
-
241
- window.setTimeout = this._originals.setTimeout;
242
- window.clearTimeout = this._originals.clearTimeout;
243
- window.setInterval = this._originals.setInterval;
244
- window.clearInterval = this._originals.clearInterval;
245
- window.requestAnimationFrame = this._originals.requestAnimationFrame;
246
- window.cancelAnimationFrame = this._originals.cancelAnimationFrame;
247
- window.addEventListener = this._originals.addEventListener;
248
- window.removeEventListener = this._originals.removeEventListener;
249
-
250
- // NOTE: Do NOT null _originals — patched closures may still reference
251
- // the sandbox instance (e.g. React scheduler caches setTimeout).
252
- // The closure uses `originals` (local const), not `this._originals`.
253
- this._patched = false;
254
- logger.wuDebug(`[ProxySandbox] Window unpatched for ${this.appName}`);
255
- }
256
-
257
- // ================================================================
258
- // PROXY INTERCEPTS - for code running through the proxy
259
- // ================================================================
260
-
261
- /**
262
- * Intercept property access on the proxy.
263
- * Returns wrapped API or undefined to fall through.
264
- */
265
- _intercept(prop, target) {
266
- const self = this;
267
-
268
- switch (prop) {
269
- // --- Timer hijacking ---
270
- case 'setTimeout':
271
- return function(fn, delay, ...args) {
272
- const id = target.setTimeout(fn, delay, ...args);
273
- self._timers.add(id);
274
- return id;
275
- };
276
- case 'clearTimeout':
277
- return function(id) {
278
- self._timers.delete(id);
279
- target.clearTimeout(id);
280
- };
281
- case 'setInterval':
282
- return function(fn, delay, ...args) {
283
- const id = target.setInterval(fn, delay, ...args);
284
- self._intervals.add(id);
285
- return id;
286
- };
287
- case 'clearInterval':
288
- return function(id) {
289
- self._intervals.delete(id);
290
- target.clearInterval(id);
291
- };
292
- case 'requestAnimationFrame':
293
- return function(fn) {
294
- const id = target.requestAnimationFrame(fn);
295
- self._rafs.add(id);
296
- return id;
297
- };
298
- case 'cancelAnimationFrame':
299
- return function(id) {
300
- self._rafs.delete(id);
301
- target.cancelAnimationFrame(id);
302
- };
303
-
304
- // --- Event listener tracking ---
305
- case 'addEventListener':
306
- return function(event, handler, options) {
307
- self._eventListeners.push({ target, event, handler, options });
308
- target.addEventListener(event, handler, options);
309
- };
310
- case 'removeEventListener':
311
- return function(event, handler, options) {
312
- self._eventListeners = self._eventListeners.filter(
313
- l => !(l.target === target && l.event === event && l.handler === handler)
314
- );
315
- target.removeEventListener(event, handler, options);
316
- };
317
-
318
- // --- DOM scoping ---
319
- case 'document':
320
- return this._getScopedDocument();
321
-
322
- // --- Storage scoping ---
323
- case 'localStorage':
324
- return this._getScopedStorage('local');
325
- case 'sessionStorage':
326
- return this._getScopedStorage('session');
327
- }
328
-
329
- return undefined;
330
- }
331
-
332
- // ================================================================
333
- // DOM SCOPING - querySelector searches inside shadow root
334
- // ================================================================
335
-
336
- _getScopedDocument() {
337
- if (this._scopedDocument) return this._scopedDocument;
338
-
339
- const root = this._shadowRoot || this._container;
340
- if (!root) return document; // No container set, pass through
341
-
342
- const self = this;
343
-
344
- this._scopedDocument = new Proxy(document, {
345
- get(target, prop) {
346
- switch (prop) {
347
- case 'querySelector':
348
- return (selector) => root.querySelector(selector);
349
- case 'querySelectorAll':
350
- return (selector) => root.querySelectorAll(selector);
351
- case 'getElementById':
352
- return (id) => root.querySelector(`#${CSS.escape(id)}`);
353
- case 'getElementsByClassName':
354
- return (className) => root.querySelectorAll(`.${CSS.escape(className)}`);
355
- case 'getElementsByTagName':
356
- return (tag) => root.querySelectorAll(tag);
357
-
358
- // Track document event listeners too
359
- case 'addEventListener':
360
- return function(event, handler, options) {
361
- self._eventListeners.push({ target, event, handler, options });
362
- target.addEventListener(event, handler, options);
363
- };
364
- case 'removeEventListener':
365
- return function(event, handler, options) {
366
- self._eventListeners = self._eventListeners.filter(
367
- l => !(l.target === target && l.event === event && l.handler === handler)
368
- );
369
- target.removeEventListener(event, handler, options);
370
- };
371
-
372
- // createElement, createTextNode, etc. - pass through
373
- default: {
374
- const value = target[prop];
375
- if (typeof value === 'function') {
376
- return value.bind(target);
377
- }
378
- return value;
379
- }
380
- }
381
- }
382
- });
383
-
384
- return this._scopedDocument;
385
- }
386
-
387
- // ================================================================
388
- // STORAGE SCOPING - localStorage/sessionStorage with app prefix
389
- // ================================================================
390
-
391
- _getScopedStorage(type) {
392
- const cacheKey = type === 'local' ? '_scopedLocalStorage' : '_scopedSessionStorage';
393
- if (this[cacheKey]) return this[cacheKey];
394
-
395
- const realStorage = type === 'local' ? window.localStorage : window.sessionStorage;
396
- if (!realStorage) return realStorage;
397
-
398
- const prefix = `wu_${this.appName}_`;
399
-
400
- this[cacheKey] = {
401
- getItem(key) {
402
- return realStorage.getItem(prefix + key);
403
- },
404
- setItem(key, value) {
405
- realStorage.setItem(prefix + key, String(value));
406
- },
407
- removeItem(key) {
408
- realStorage.removeItem(prefix + key);
409
- },
410
- clear() {
411
- // Only clear this app's keys
412
- const toRemove = [];
413
- for (let i = 0; i < realStorage.length; i++) {
414
- const k = realStorage.key(i);
415
- if (k && k.startsWith(prefix)) toRemove.push(k);
416
- }
417
- toRemove.forEach(k => realStorage.removeItem(k));
418
- },
419
- key(index) {
420
- let count = 0;
421
- for (let i = 0; i < realStorage.length; i++) {
422
- const k = realStorage.key(i);
423
- if (k && k.startsWith(prefix)) {
424
- if (count === index) return k.slice(prefix.length);
425
- count++;
426
- }
427
- }
428
- return null;
429
- },
430
- get length() {
431
- let count = 0;
432
- for (let i = 0; i < realStorage.length; i++) {
433
- if (realStorage.key(i)?.startsWith(prefix)) count++;
434
- }
435
- return count;
436
- }
437
- };
438
-
439
- return this[cacheKey];
440
- }
441
-
442
- // ================================================================
443
- // UTILITIES
444
- // ================================================================
445
-
446
- _isConstructor(fn) {
447
- try {
448
- return fn.prototype && fn.prototype.constructor === fn;
449
- } catch {
450
- return false;
451
- }
452
- }
453
-
454
- getProxy() {
455
- return this.active ? this.proxy : null;
456
- }
457
-
458
- isActive() {
459
- return this.active;
460
- }
461
-
462
- getStats() {
463
- return {
464
- appName: this.appName,
465
- active: this.active,
466
- patched: this._patched,
467
- modifiedKeys: Array.from(this.modifiedKeys),
468
- isolatedPropsCount: Object.keys(this.fakeWindow).length,
469
- trackedTimers: this._timers.size,
470
- trackedIntervals: this._intervals.size,
471
- trackedRAFs: this._rafs.size,
472
- trackedEventListeners: this._eventListeners.length,
473
- hasContainer: !!this._container,
474
- hasShadowRoot: !!this._shadowRoot
475
- };
476
- }
477
- }