wu-framework 1.2.1 → 2.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 (164) hide show
  1. package/LICENSE +39 -39
  2. package/README.md +570 -489
  3. package/dist/adapters/alpine/index.js +2 -0
  4. package/dist/adapters/alpine/index.js.map +1 -0
  5. package/{src → dist}/adapters/angular/index.d.ts +154 -154
  6. package/dist/adapters/angular/index.js +2 -0
  7. package/dist/adapters/angular/index.js.map +1 -0
  8. package/{src → dist}/adapters/angular.d.ts +3 -3
  9. package/dist/adapters/htmx/index.js +2 -0
  10. package/dist/adapters/htmx/index.js.map +1 -0
  11. package/dist/adapters/index.js +2 -0
  12. package/dist/adapters/index.js.map +1 -0
  13. package/{src → dist}/adapters/lit/index.d.ts +120 -120
  14. package/dist/adapters/lit/index.js +44 -0
  15. package/dist/adapters/lit/index.js.map +1 -0
  16. package/{src → dist}/adapters/lit.d.ts +3 -3
  17. package/{src → dist}/adapters/preact/index.d.ts +108 -108
  18. package/dist/adapters/preact/index.js +2 -0
  19. package/dist/adapters/preact/index.js.map +1 -0
  20. package/{src → dist}/adapters/preact.d.ts +3 -3
  21. package/dist/adapters/qwik/index.js +2 -0
  22. package/dist/adapters/qwik/index.js.map +1 -0
  23. package/{src → dist}/adapters/react/index.d.ts +246 -246
  24. package/dist/adapters/react/index.js +2 -0
  25. package/dist/adapters/react/index.js.map +1 -0
  26. package/{src → dist}/adapters/react.d.ts +3 -3
  27. package/dist/adapters/shared.js +2 -0
  28. package/dist/adapters/shared.js.map +1 -0
  29. package/{src → dist}/adapters/solid/index.d.ts +101 -101
  30. package/dist/adapters/solid/index.js +2 -0
  31. package/dist/adapters/solid/index.js.map +1 -0
  32. package/{src → dist}/adapters/solid.d.ts +3 -3
  33. package/dist/adapters/stencil/index.js +2 -0
  34. package/dist/adapters/stencil/index.js.map +1 -0
  35. package/dist/adapters/stimulus/index.js +2 -0
  36. package/dist/adapters/stimulus/index.js.map +1 -0
  37. package/{src → dist}/adapters/svelte/index.d.ts +166 -166
  38. package/dist/adapters/svelte/index.js +2 -0
  39. package/dist/adapters/svelte/index.js.map +1 -0
  40. package/{src → dist}/adapters/svelte.d.ts +3 -3
  41. package/{src → dist}/adapters/vanilla/index.d.ts +179 -179
  42. package/dist/adapters/vanilla/index.js +2 -0
  43. package/dist/adapters/vanilla/index.js.map +1 -0
  44. package/{src → dist}/adapters/vanilla.d.ts +3 -3
  45. package/{src → dist}/adapters/vue/index.d.ts +299 -299
  46. package/dist/adapters/vue/index.js +2 -0
  47. package/dist/adapters/vue/index.js.map +1 -0
  48. package/{src → dist}/adapters/vue.d.ts +3 -3
  49. package/dist/ai/wu-ai.js +2 -0
  50. package/dist/ai/wu-ai.js.map +1 -0
  51. package/dist/core/wu-html-parser.js +2 -0
  52. package/dist/core/wu-html-parser.js.map +1 -0
  53. package/dist/core/wu-iframe-sandbox.js +2 -0
  54. package/dist/core/wu-iframe-sandbox.js.map +1 -0
  55. package/dist/core/wu-loader.js +2 -0
  56. package/dist/core/wu-loader.js.map +1 -0
  57. package/dist/core/wu-mcp-bridge.js +2 -0
  58. package/dist/core/wu-mcp-bridge.js.map +1 -0
  59. package/dist/core/wu-script-executor.js +2 -0
  60. package/dist/core/wu-script-executor.js.map +1 -0
  61. package/{src → dist}/index.d.ts +445 -317
  62. package/dist/wu-ai-browser-primitives-BDKXJlwc.js +2 -0
  63. package/dist/wu-ai-browser-primitives-BDKXJlwc.js.map +1 -0
  64. package/dist/wu-framework.cjs.js +2 -2
  65. package/dist/wu-framework.cjs.js.map +1 -1
  66. package/dist/wu-framework.dev.js +8681 -15683
  67. package/dist/wu-framework.dev.js.map +1 -1
  68. package/dist/wu-framework.esm.js +2 -2
  69. package/dist/wu-framework.esm.js.map +1 -1
  70. package/dist/wu-framework.umd.js +2 -2
  71. package/dist/wu-framework.umd.js.map +1 -1
  72. package/dist/wu-logger-fJfUHBGA.js +2 -0
  73. package/dist/wu-logger-fJfUHBGA.js.map +1 -0
  74. package/integrations/astro/README.md +127 -127
  75. package/integrations/astro/WuApp.astro +63 -63
  76. package/integrations/astro/WuShell.astro +39 -39
  77. package/integrations/astro/index.js +68 -68
  78. package/integrations/astro/package.json +38 -38
  79. package/integrations/astro/types.d.ts +53 -53
  80. package/package.json +218 -209
  81. package/src/adapters/alpine/index.js +0 -231
  82. package/src/adapters/alpine.js +0 -3
  83. package/src/adapters/angular/ai.js +0 -30
  84. package/src/adapters/angular/index.js +0 -932
  85. package/src/adapters/angular.js +0 -3
  86. package/src/adapters/htmx/index.js +0 -242
  87. package/src/adapters/htmx.js +0 -3
  88. package/src/adapters/index.js +0 -225
  89. package/src/adapters/lit/ai.js +0 -20
  90. package/src/adapters/lit/index.js +0 -721
  91. package/src/adapters/lit.js +0 -3
  92. package/src/adapters/preact/ai.js +0 -33
  93. package/src/adapters/preact/index.js +0 -661
  94. package/src/adapters/preact.js +0 -3
  95. package/src/adapters/qwik/index.js +0 -108
  96. package/src/adapters/qwik.js +0 -3
  97. package/src/adapters/react/ai.js +0 -135
  98. package/src/adapters/react/index.js +0 -695
  99. package/src/adapters/react.js +0 -3
  100. package/src/adapters/shared.js +0 -64
  101. package/src/adapters/solid/ai.js +0 -32
  102. package/src/adapters/solid/index.js +0 -586
  103. package/src/adapters/solid.js +0 -3
  104. package/src/adapters/stencil/index.js +0 -228
  105. package/src/adapters/stencil.js +0 -3
  106. package/src/adapters/stimulus/index.js +0 -255
  107. package/src/adapters/stimulus.js +0 -3
  108. package/src/adapters/svelte/ai.js +0 -31
  109. package/src/adapters/svelte/index.js +0 -798
  110. package/src/adapters/svelte.js +0 -3
  111. package/src/adapters/vanilla/ai.js +0 -30
  112. package/src/adapters/vanilla/index.js +0 -785
  113. package/src/adapters/vanilla.js +0 -3
  114. package/src/adapters/vue/ai.js +0 -52
  115. package/src/adapters/vue/index.js +0 -618
  116. package/src/adapters/vue.js +0 -3
  117. package/src/ai/wu-ai-actions.js +0 -261
  118. package/src/ai/wu-ai-agent.js +0 -546
  119. package/src/ai/wu-ai-browser-primitives.js +0 -354
  120. package/src/ai/wu-ai-browser.js +0 -380
  121. package/src/ai/wu-ai-context.js +0 -332
  122. package/src/ai/wu-ai-conversation.js +0 -613
  123. package/src/ai/wu-ai-orchestrate.js +0 -1021
  124. package/src/ai/wu-ai-permissions.js +0 -381
  125. package/src/ai/wu-ai-provider.js +0 -700
  126. package/src/ai/wu-ai-schema.js +0 -225
  127. package/src/ai/wu-ai-triggers.js +0 -396
  128. package/src/ai/wu-ai.js +0 -804
  129. package/src/core/wu-app.js +0 -236
  130. package/src/core/wu-cache.js +0 -498
  131. package/src/core/wu-core.js +0 -1412
  132. package/src/core/wu-error-boundary.js +0 -396
  133. package/src/core/wu-event-bus.js +0 -390
  134. package/src/core/wu-hooks.js +0 -350
  135. package/src/core/wu-html-parser.js +0 -199
  136. package/src/core/wu-iframe-sandbox.js +0 -328
  137. package/src/core/wu-loader.js +0 -450
  138. package/src/core/wu-logger.js +0 -143
  139. package/src/core/wu-manifest.js +0 -533
  140. package/src/core/wu-mcp-bridge.js +0 -432
  141. package/src/core/wu-overrides.js +0 -510
  142. package/src/core/wu-performance.js +0 -228
  143. package/src/core/wu-plugin.js +0 -401
  144. package/src/core/wu-prefetch.js +0 -414
  145. package/src/core/wu-proxy-sandbox.js +0 -477
  146. package/src/core/wu-sandbox.js +0 -779
  147. package/src/core/wu-script-executor.js +0 -161
  148. package/src/core/wu-sentinel-client.js +0 -311
  149. package/src/core/wu-snapshot-sandbox.js +0 -227
  150. package/src/core/wu-store.js +0 -307
  151. package/src/core/wu-strategies.js +0 -256
  152. package/src/core/wu-style-bridge.js +0 -477
  153. package/src/index.js +0 -234
  154. package/src/utils/dependency-resolver.js +0 -328
  155. /package/{src → dist}/adapters/alpine/index.d.ts +0 -0
  156. /package/{src → dist}/adapters/alpine.d.ts +0 -0
  157. /package/{src → dist}/adapters/htmx/index.d.ts +0 -0
  158. /package/{src → dist}/adapters/htmx.d.ts +0 -0
  159. /package/{src → dist}/adapters/qwik/index.d.ts +0 -0
  160. /package/{src → dist}/adapters/qwik.d.ts +0 -0
  161. /package/{src → dist}/adapters/stencil/index.d.ts +0 -0
  162. /package/{src → dist}/adapters/stencil.d.ts +0 -0
  163. /package/{src → dist}/adapters/stimulus/index.d.ts +0 -0
  164. /package/{src → dist}/adapters/stimulus.d.ts +0 -0
@@ -1,414 +0,0 @@
1
- /**
2
- * WU-PREFETCH: Intelligent Prefetching with Speculation Rules API
3
- *
4
- * Prefetches microfrontend modules BEFORE they're needed using:
5
- * 1. Speculation Rules API (Chrome 121+) — browser-native prerender/prefetch
6
- * 2. <link rel="modulepreload"> — ES module prefetch (all modern browsers)
7
- * 3. <link rel="prefetch"> — generic fallback
8
- *
9
- * Trigger modes:
10
- * - immediate: prefetch now
11
- * - hover: prefetch when user hovers a target element
12
- * - visible: prefetch when target element enters viewport (IntersectionObserver)
13
- * - idle: prefetch during browser idle time (requestIdleCallback)
14
- *
15
- * @example
16
- * // Prefetch immediately
17
- * wu.prefetch('cart');
18
- *
19
- * // Prefetch when user hovers the cart link
20
- * wu.prefetch('cart', { on: 'hover', target: '#cart-link' });
21
- *
22
- * // Prefetch when the section becomes visible
23
- * wu.prefetch('cart', { on: 'visible', target: '#cart-section' });
24
- *
25
- * // Prefetch during idle time
26
- * wu.prefetch('cart', { on: 'idle' });
27
- *
28
- * // Prefetch multiple apps with eagerness control
29
- * wu.prefetch(['cart', 'profile'], { eagerness: 'moderate' });
30
- */
31
-
32
- import { logger } from './wu-logger.js';
33
-
34
- export class WuPrefetch {
35
- constructor(core) {
36
- this.core = core;
37
-
38
- // Track what we've already prefetched to avoid duplicates
39
- this.prefetched = new Set();
40
-
41
- // Active observers and listeners (for cleanup)
42
- this._observers = new Map();
43
- this._listeners = [];
44
-
45
- // Speculation Rules script element (one per page, updated dynamically)
46
- this._speculationScript = null;
47
- this._speculationRules = { prefetch: [], prerender: [] };
48
-
49
- // Detect browser support
50
- this.supportsSpeculationRules = this._detectSpeculationRules();
51
- this.supportsModulePreload = this._detectModulePreload();
52
-
53
- logger.wuDebug(
54
- `[WuPrefetch] Initialized — ` +
55
- `Speculation Rules: ${this.supportsSpeculationRules ? 'yes' : 'no'}, ` +
56
- `Module Preload: ${this.supportsModulePreload ? 'yes' : 'no'}`
57
- );
58
- }
59
-
60
- // ─── Detection ───────────────────────────────────────────────
61
-
62
- _detectSpeculationRules() {
63
- if (typeof HTMLScriptElement === 'undefined') return false;
64
- return HTMLScriptElement.supports?.('speculationrules') ?? false;
65
- }
66
-
67
- _detectModulePreload() {
68
- if (typeof document === 'undefined') return false;
69
- const link = document.createElement('link');
70
- return link.relList?.supports?.('modulepreload') ?? false;
71
- }
72
-
73
- // ─── Main API ────────────────────────────────────────────────
74
-
75
- /**
76
- * Prefetch one or more apps.
77
- *
78
- * @param {string|string[]} appNames - App name(s) to prefetch
79
- * @param {Object} [options]
80
- * @param {'immediate'|'hover'|'visible'|'idle'} [options.on='immediate'] - Trigger mode
81
- * @param {string|Element} [options.target] - CSS selector or element (for hover/visible)
82
- * @param {'conservative'|'moderate'|'eager'} [options.eagerness='moderate'] - Speculation Rules eagerness
83
- * @returns {Promise<void>|Function} Promise for immediate, cleanup function for deferred
84
- */
85
- async prefetch(appNames, options = {}) {
86
- const names = Array.isArray(appNames) ? appNames : [appNames];
87
- const trigger = options.on || 'immediate';
88
-
89
- switch (trigger) {
90
- case 'immediate':
91
- return this._prefetchImmediate(names, options);
92
-
93
- case 'hover':
94
- return this._prefetchOnHover(names, options);
95
-
96
- case 'visible':
97
- return this._prefetchOnVisible(names, options);
98
-
99
- case 'idle':
100
- return this._prefetchOnIdle(names, options);
101
-
102
- default:
103
- logger.wuWarn(`[WuPrefetch] Unknown trigger "${trigger}", using immediate`);
104
- return this._prefetchImmediate(names, options);
105
- }
106
- }
107
-
108
- // ─── Immediate Prefetch ──────────────────────────────────────
109
-
110
- async _prefetchImmediate(appNames, options) {
111
- const urls = await this._resolveAppUrls(appNames);
112
- if (urls.length === 0) return;
113
-
114
- // Mark all as prefetched by name (prevents duplicate resolution)
115
- urls.forEach(({ name }) => this.prefetched.add(name));
116
-
117
- // Strategy 1: Speculation Rules API (Chrome 121+)
118
- if (this.supportsSpeculationRules) {
119
- this._addSpeculationRules(urls, options.eagerness || 'moderate');
120
- return;
121
- }
122
-
123
- // Strategy 2: <link rel="modulepreload"> for ES modules
124
- if (this.supportsModulePreload) {
125
- urls.forEach(({ url }) => this._injectModulePreload(url));
126
- return;
127
- }
128
-
129
- // Strategy 3: <link rel="prefetch"> fallback
130
- urls.forEach(({ url }) => this._injectPrefetch(url));
131
- }
132
-
133
- // ─── Hover Trigger ───────────────────────────────────────────
134
-
135
- _prefetchOnHover(appNames, options) {
136
- const target = this._resolveTarget(options.target);
137
- if (!target) {
138
- logger.wuWarn('[WuPrefetch] hover trigger requires a target element or selector');
139
- return () => {};
140
- }
141
-
142
- let done = false;
143
-
144
- const handler = () => {
145
- if (done) return;
146
- done = true;
147
- this._prefetchImmediate(appNames, options);
148
- // One-shot: remove after first trigger
149
- target.removeEventListener('mouseenter', handler);
150
- target.removeEventListener('focusin', handler);
151
- };
152
-
153
- // Mouse hover OR keyboard focus
154
- target.addEventListener('mouseenter', handler, { passive: true });
155
- target.addEventListener('focusin', handler, { passive: true });
156
-
157
- const cleanup = () => {
158
- target.removeEventListener('mouseenter', handler);
159
- target.removeEventListener('focusin', handler);
160
- };
161
-
162
- this._listeners.push(cleanup);
163
- return cleanup;
164
- }
165
-
166
- // ─── Visibility Trigger (IntersectionObserver) ───────────────
167
-
168
- _prefetchOnVisible(appNames, options) {
169
- const target = this._resolveTarget(options.target);
170
- if (!target) {
171
- logger.wuWarn('[WuPrefetch] visible trigger requires a target element or selector');
172
- return () => {};
173
- }
174
-
175
- if (typeof IntersectionObserver === 'undefined') {
176
- // No IntersectionObserver → prefetch immediately
177
- this._prefetchImmediate(appNames, options);
178
- return () => {};
179
- }
180
-
181
- const observer = new IntersectionObserver(
182
- (entries) => {
183
- for (const entry of entries) {
184
- if (entry.isIntersecting) {
185
- this._prefetchImmediate(appNames, options);
186
- observer.disconnect();
187
- this._observers.delete(target);
188
- break;
189
- }
190
- }
191
- },
192
- { rootMargin: '200px' } // Start prefetching 200px before visible
193
- );
194
-
195
- observer.observe(target);
196
- this._observers.set(target, observer);
197
-
198
- const cleanup = () => {
199
- observer.disconnect();
200
- this._observers.delete(target);
201
- };
202
-
203
- return cleanup;
204
- }
205
-
206
- // ─── Idle Trigger ────────────────────────────────────────────
207
-
208
- _prefetchOnIdle(appNames, options) {
209
- const callback = () => this._prefetchImmediate(appNames, options);
210
-
211
- if ('requestIdleCallback' in window) {
212
- const id = requestIdleCallback(callback, { timeout: 3000 });
213
- const cleanup = () => cancelIdleCallback(id);
214
- this._listeners.push(cleanup);
215
- return cleanup;
216
- }
217
-
218
- // Fallback: setTimeout 2s
219
- const id = setTimeout(callback, 2000);
220
- const cleanup = () => clearTimeout(id);
221
- this._listeners.push(cleanup);
222
- return cleanup;
223
- }
224
-
225
- // ─── Speculation Rules API ───────────────────────────────────
226
-
227
- _addSpeculationRules(urls, eagerness) {
228
- const newEntries = urls.filter(({ name }) => !this.prefetched.has(name));
229
- if (newEntries.length === 0) return;
230
-
231
- // Mark as prefetched
232
- newEntries.forEach(({ name }) => this.prefetched.add(name));
233
-
234
- // Build URL list for speculation rules
235
- const urlList = newEntries.map(({ url }) => url);
236
-
237
- // Add prefetch rule
238
- this._speculationRules.prefetch.push({
239
- source: 'list',
240
- urls: urlList,
241
- eagerness
242
- });
243
-
244
- // Inject or update the speculation rules script
245
- this._updateSpeculationScript();
246
-
247
- logger.wuDebug(
248
- `[WuPrefetch] Speculation Rules: prefetch ${newEntries.map(e => e.name).join(', ')} ` +
249
- `(eagerness: ${eagerness})`
250
- );
251
- }
252
-
253
- _updateSpeculationScript() {
254
- // Remove existing script (spec requires replacing, not updating)
255
- if (this._speculationScript) {
256
- this._speculationScript.remove();
257
- }
258
-
259
- const script = document.createElement('script');
260
- script.type = 'speculationrules';
261
- script.textContent = JSON.stringify(this._speculationRules);
262
- document.head.appendChild(script);
263
-
264
- this._speculationScript = script;
265
- }
266
-
267
- // ─── Module Preload ──────────────────────────────────────────
268
-
269
- _injectModulePreload(url) {
270
- if (this.prefetched.has(url)) return;
271
- this.prefetched.add(url);
272
-
273
- const link = document.createElement('link');
274
- link.rel = 'modulepreload';
275
- link.href = url;
276
- document.head.appendChild(link);
277
-
278
- logger.wuDebug(`[WuPrefetch] modulepreload: ${url}`);
279
- }
280
-
281
- // ─── Generic Prefetch ────────────────────────────────────────
282
-
283
- _injectPrefetch(url) {
284
- if (this.prefetched.has(url)) return;
285
- this.prefetched.add(url);
286
-
287
- const link = document.createElement('link');
288
- link.rel = 'prefetch';
289
- link.href = url;
290
- link.as = 'script';
291
- document.head.appendChild(link);
292
-
293
- logger.wuDebug(`[WuPrefetch] prefetch: ${url}`);
294
- }
295
-
296
- // ─── URL Resolution ──────────────────────────────────────────
297
-
298
- /**
299
- * Resolve app names to their module URLs.
300
- * Skips apps that are already mounted, already prefetched, or not registered.
301
- */
302
- async _resolveAppUrls(appNames) {
303
- const results = [];
304
-
305
- for (const name of appNames) {
306
- // Skip if already prefetched
307
- if (this.prefetched.has(name)) {
308
- logger.wuDebug(`[WuPrefetch] ${name} already prefetched, skipping`);
309
- continue;
310
- }
311
-
312
- // Skip if already mounted (no need to prefetch)
313
- if (this.core.mounted.has(name)) {
314
- logger.wuDebug(`[WuPrefetch] ${name} already mounted, skipping`);
315
- continue;
316
- }
317
-
318
- // Skip if already loaded (definition exists)
319
- if (this.core.definitions.has(name)) {
320
- logger.wuDebug(`[WuPrefetch] ${name} already defined, skipping`);
321
- continue;
322
- }
323
-
324
- const app = this.core.apps.get(name);
325
- if (!app) {
326
- logger.wuWarn(`[WuPrefetch] App "${name}" not registered, cannot prefetch`);
327
- continue;
328
- }
329
-
330
- try {
331
- const url = await this.core.resolveModulePath(app);
332
- results.push({ name, url });
333
- } catch (error) {
334
- logger.wuWarn(`[WuPrefetch] Failed to resolve URL for "${name}":`, error.message);
335
- }
336
- }
337
-
338
- return results;
339
- }
340
-
341
- // ─── Helpers ─────────────────────────────────────────────────
342
-
343
- _resolveTarget(target) {
344
- if (!target) return null;
345
- if (typeof target === 'string') return document.querySelector(target);
346
- if (target instanceof Element) return target;
347
- return null;
348
- }
349
-
350
- // ─── Prefetch All Registered (utility) ───────────────────────
351
-
352
- /**
353
- * Prefetch all registered but not-yet-mounted apps.
354
- * Useful for aggressive prefetching after initial load.
355
- *
356
- * @param {Object} [options] - Same options as prefetch()
357
- */
358
- async prefetchAll(options = {}) {
359
- const unmountedApps = [];
360
- for (const [name] of this.core.apps) {
361
- if (!this.core.mounted.has(name) && !this.prefetched.has(name)) {
362
- unmountedApps.push(name);
363
- }
364
- }
365
-
366
- if (unmountedApps.length === 0) {
367
- logger.wuDebug('[WuPrefetch] No apps to prefetch');
368
- return;
369
- }
370
-
371
- logger.wuDebug(`[WuPrefetch] Prefetching all: ${unmountedApps.join(', ')}`);
372
- return this.prefetch(unmountedApps, options);
373
- }
374
-
375
- // ─── Stats ───────────────────────────────────────────────────
376
-
377
- getStats() {
378
- return {
379
- prefetched: [...this.prefetched],
380
- activeObservers: this._observers.size,
381
- activeListeners: this._listeners.length,
382
- speculationRulesSupported: this.supportsSpeculationRules,
383
- modulePreloadSupported: this.supportsModulePreload,
384
- speculationRules: this._speculationRules
385
- };
386
- }
387
-
388
- // ─── Cleanup ─────────────────────────────────────────────────
389
-
390
- cleanup() {
391
- // Disconnect all IntersectionObservers
392
- for (const [, observer] of this._observers) {
393
- observer.disconnect();
394
- }
395
- this._observers.clear();
396
-
397
- // Remove all event listeners
398
- for (const cleanup of this._listeners) {
399
- cleanup();
400
- }
401
- this._listeners = [];
402
-
403
- // Remove speculation rules script
404
- if (this._speculationScript) {
405
- this._speculationScript.remove();
406
- this._speculationScript = null;
407
- }
408
-
409
- this._speculationRules = { prefetch: [], prerender: [] };
410
- this.prefetched.clear();
411
-
412
- logger.wuDebug('[WuPrefetch] Cleaned up');
413
- }
414
- }