wu-framework 2.1.2 → 2.6.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 (72) hide show
  1. package/README.md +6 -1
  2. package/dist/adapters/alpine/index.d.ts +1 -1
  3. package/dist/adapters/angular/index.d.ts +1 -1
  4. package/dist/adapters/htmx/index.d.ts +1 -1
  5. package/dist/adapters/lit/index.d.ts +1 -1
  6. package/dist/adapters/lit/index.js +2 -2
  7. package/dist/adapters/lit/index.js.map +1 -1
  8. package/dist/adapters/preact/index.d.ts +1 -1
  9. package/dist/adapters/preact/index.js +1 -1
  10. package/dist/adapters/preact/index.js.map +1 -1
  11. package/dist/adapters/qwik/index.d.ts +3 -10
  12. package/dist/adapters/qwik/index.js +1 -1
  13. package/dist/adapters/qwik/index.js.map +1 -1
  14. package/dist/adapters/react/index.js +1 -1
  15. package/dist/adapters/react/index.js.map +1 -1
  16. package/dist/adapters/shared.d.ts +44 -0
  17. package/dist/adapters/shared.js +1 -1
  18. package/dist/adapters/shared.js.map +1 -1
  19. package/dist/adapters/solid/index.d.ts +1 -1
  20. package/dist/adapters/solid/index.js +1 -1
  21. package/dist/adapters/solid/index.js.map +1 -1
  22. package/dist/adapters/stencil/index.d.ts +1 -1
  23. package/dist/adapters/stimulus/index.d.ts +1 -1
  24. package/dist/adapters/svelte/index.d.ts +1 -1
  25. package/dist/adapters/svelte/index.js +1 -1
  26. package/dist/adapters/svelte/index.js.map +1 -1
  27. package/dist/adapters/vanilla/index.d.ts +1 -1
  28. package/dist/adapters/vanilla/index.js +1 -1
  29. package/dist/adapters/vanilla/index.js.map +1 -1
  30. package/dist/adapters/vue/index.js +1 -1
  31. package/dist/adapters/vue/index.js.map +1 -1
  32. package/dist/ai/wu-ai.js +1 -1
  33. package/dist/ai/wu-ai.js.map +1 -1
  34. package/dist/core/wu-devtools.js +2 -0
  35. package/dist/core/wu-devtools.js.map +1 -0
  36. package/dist/core/wu-html-parser.js +1 -1
  37. package/dist/core/wu-html-parser.js.map +1 -1
  38. package/dist/core/wu-iframe-sandbox.js +1 -1
  39. package/dist/core/wu-iframe-sandbox.js.map +1 -1
  40. package/dist/core/wu-loader.js +1 -1
  41. package/dist/core/wu-loader.js.map +1 -1
  42. package/dist/core/wu-logger.js +2 -0
  43. package/dist/core/wu-logger.js.map +1 -0
  44. package/dist/core/wu-mcp-bridge.js +1 -1
  45. package/dist/core/wu-mcp-bridge.js.map +1 -1
  46. package/dist/core/wu-script-executor.js +1 -1
  47. package/dist/core/wu-script-executor.js.map +1 -1
  48. package/dist/core/wu-store-sync.js +2 -0
  49. package/dist/core/wu-store-sync.js.map +1 -0
  50. package/dist/core/wu-timeline.js +2 -0
  51. package/dist/core/wu-timeline.js.map +1 -0
  52. package/dist/index.d.cts +759 -0
  53. package/dist/index.d.ts +315 -1
  54. package/dist/wu-ai-browser-primitives-CaUCk1Xl.js +2 -0
  55. package/dist/wu-ai-browser-primitives-CaUCk1Xl.js.map +1 -0
  56. package/dist/wu-framework.cjs +3 -0
  57. package/dist/wu-framework.cjs.map +1 -0
  58. package/dist/wu-framework.dev.js +1296 -275
  59. package/dist/wu-framework.dev.js.map +1 -1
  60. package/dist/wu-framework.esm.js +2 -2
  61. package/dist/wu-framework.esm.js.map +1 -1
  62. package/dist/wu-framework.umd.js +2 -2
  63. package/dist/wu-framework.umd.js.map +1 -1
  64. package/integrations/astro/WuApp.astro +16 -11
  65. package/integrations/astro/WuShell.astro +11 -3
  66. package/package.json +14 -6
  67. package/dist/wu-ai-browser-primitives-BDKXJlwc.js +0 -2
  68. package/dist/wu-ai-browser-primitives-BDKXJlwc.js.map +0 -1
  69. package/dist/wu-framework.cjs.js +0 -3
  70. package/dist/wu-framework.cjs.js.map +0 -1
  71. package/dist/wu-logger-fJfUHBGA.js +0 -2
  72. package/dist/wu-logger-fJfUHBGA.js.map +0 -1
package/dist/index.d.ts CHANGED
@@ -52,6 +52,200 @@ export interface WuLifecycle {
52
52
  unmount?: (container: HTMLElement) => void | Promise<void>;
53
53
  activate?: (container: HTMLElement) => void | Promise<void>;
54
54
  deactivate?: (container: HTMLElement) => void | Promise<void>;
55
+ /**
56
+ * Live-props slot (v2.2+). Called by `wu.update(appName, props)` to push new
57
+ * props into a mounted app without remounting. Adapters built on
58
+ * `createWuAdapter` expose this when their framework can re-render in place.
59
+ */
60
+ update?: (container: HTMLElement, props: Record<string, any>) => void | Promise<void>;
61
+ }
62
+
63
+ /** Full-page diagnostic snapshot returned by `wu.inspect()` (v2.2+). */
64
+ export interface WuInspectSnapshot {
65
+ version: string | null;
66
+ timestamp: number;
67
+ summary: { registered: number; defined: number; mounted: number; hidden: number };
68
+ apps: Array<{
69
+ name: string;
70
+ status: 'mounted' | 'hidden';
71
+ framework: string | null;
72
+ containerSelector: string | null;
73
+ mountedAt: number | null;
74
+ liveProps: boolean;
75
+ props: Record<string, any> | null;
76
+ sandbox: WuSandboxInfo | null;
77
+ }>;
78
+ defined: string[];
79
+ registered: string[];
80
+ /** Registered capability contracts (v2.5+). */
81
+ capabilities: Array<{ name: string; version: string; app: string | null }>;
82
+ events: { recent: Array<{ type: string; appName?: string; timestamp?: number }>; stats: any };
83
+ store: { snapshot: any; metrics: any };
84
+ }
85
+
86
+ /** Options for `wu.provide()` (v2.5+). */
87
+ export interface WuProvideOptions {
88
+ /** Semver version the implementation satisfies (default '0.0.0'). */
89
+ version?: string;
90
+ /** Required keys (array) or key→typeof map; verified at provide() time. */
91
+ shape?: string[] | Record<string, string>;
92
+ /** Providing app — the capability auto-revokes when this app unmounts. */
93
+ app?: string;
94
+ }
95
+
96
+ /** Options for `wu.consume()` (v2.5+). */
97
+ export interface WuConsumeOptions {
98
+ /** Return a Promise that resolves once a satisfying provider appears. */
99
+ wait?: boolean;
100
+ /** ms; rejects the wait promise if exceeded. */
101
+ timeout?: number;
102
+ }
103
+
104
+ /** Handle returned by `wu.provide()` (v2.5+). */
105
+ export interface WuCapabilityHandle {
106
+ revoke(): void;
107
+ }
108
+
109
+ /**
110
+ * Typed, versioned, runtime-verified capability contracts (v2.5+). Apps
111
+ * declare what they provide and consume; the runtime negotiates semver and
112
+ * verifies shape — replacing Module Federation's fragile shared singletons.
113
+ */
114
+ export class WuContracts {
115
+ constructor(core: WuCore);
116
+ provide<T extends object>(name: string, impl: T, opts?: WuProvideOptions): WuCapabilityHandle;
117
+ consume<T = any>(name: string, range?: string, opts?: { wait?: false; timeout?: number }): T;
118
+ consume<T = any>(name: string, range: string, opts: { wait: true; timeout?: number }): Promise<T>;
119
+ has(name: string, range?: string): boolean;
120
+ revoke(name: string): boolean;
121
+ list(): Array<{ name: string; version: string; app: string | null }>;
122
+ cleanup(): void;
123
+ }
124
+
125
+ /** A single journal entry recorded by WuTimeline (v2.3+). */
126
+ export interface WuTimelineEntry {
127
+ /** Lamport clock — the (l, site) pair is the CRDT total order. */
128
+ l: number;
129
+ /** Originating site id. */
130
+ site: string;
131
+ /** Wall-clock timestamp (ms). */
132
+ t: number;
133
+ kind: 'store' | 'event';
134
+ /** store: ring-buffer sequence number */
135
+ seq?: number;
136
+ /** store: dot-path written ('' = full-state replace) */
137
+ path?: string;
138
+ /** store: written value (deep-cloned) */
139
+ value?: any;
140
+ /** event: event name */
141
+ name?: string;
142
+ /** event: source app */
143
+ appName?: string;
144
+ /** event (app:mounted): container selector */
145
+ container?: string | null;
146
+ /** event (app:updated): live props pushed */
147
+ props?: Record<string, any> | null;
148
+ }
149
+
150
+ /** Status of the time-travel recorder (v2.3+). */
151
+ export interface WuTimelineStatus {
152
+ loaded: boolean;
153
+ recording: boolean;
154
+ /** true when positioned at the journal end (the present) */
155
+ live: boolean;
156
+ /** number of journal entries applied */
157
+ position: number;
158
+ /** total journal length */
159
+ length: number;
160
+ site: string | null;
161
+ lamport: number;
162
+ snapshots: number;
163
+ }
164
+
165
+ /** Serializable journal — the reproducible bug report (v2.3+). */
166
+ export interface WuTimelineExport {
167
+ format: string;
168
+ wu: string | null;
169
+ site: string;
170
+ exportedAt: number;
171
+ baselineApps: Array<{ name: string; container: string | null; props: Record<string, any> | null }>;
172
+ entries: WuTimelineEntry[];
173
+ snapshots: Array<{ at: number; state: any }>;
174
+ }
175
+
176
+ /**
177
+ * The `wu.timeline` facade (v2.3+) — cross-framework time travel. Records every
178
+ * store write, event-bus emit, and app lifecycle change into one journal;
179
+ * seek() rewinds the whole multi-framework page in lockstep (store hydrate +
180
+ * live-props replay + app diff). Synchronous + chainable for the fire-and-forget
181
+ * controls (record/stop/clear); the seek family returns Promises. The recorder
182
+ * chunk is lazy-loaded on first use — `await wu.timelineReady()` to force it.
183
+ * See ROADMAP.md.
184
+ */
185
+ export interface WuTimelineFacade {
186
+ record(opts?: { snapshotEvery?: number; maxEntries?: number }): WuTimelineFacade;
187
+ stop(): WuTimelineFacade;
188
+ clear(): WuTimelineFacade;
189
+ /** Rewind/forward to a journal position (0..length). */
190
+ seek(pos: number, opts?: { store?: boolean; apps?: boolean; props?: boolean }): Promise<WuTimelineStatus>;
191
+ /** Return to the present (seek to journal end). */
192
+ live(): Promise<WuTimelineStatus>;
193
+ stepBack(): Promise<WuTimelineStatus>;
194
+ stepForward(): Promise<WuTimelineStatus>;
195
+ export(): Promise<WuTimelineExport>;
196
+ import(data: WuTimelineExport): Promise<WuTimelineStatus>;
197
+ /** Merge remote journal entries (CRDT seed for multiplayer sync, #2). */
198
+ ingest(remoteEntries: WuTimelineEntry[]): Promise<WuTimelineStatus>;
199
+ entries(): WuTimelineEntry[];
200
+ status(): WuTimelineStatus;
201
+ readonly loaded: boolean;
202
+ /** The underlying WuTimeline instance once loaded (lazy), else null. */
203
+ readonly instance: any;
204
+ }
205
+
206
+ /** A duck-typed sync transport (v2.4+). Bring your own, or use 'broadcast' / a WebSocket. */
207
+ export interface WuSyncTransport {
208
+ send(message: any): void;
209
+ onMessage(cb: (message: any) => void): void;
210
+ close(): void;
211
+ }
212
+
213
+ /** Options for `wu.store.sync()` (v2.4+). */
214
+ export interface WuSyncOptions {
215
+ /** 'broadcast' (cross-tab), a WebSocket / ws(s):// URL, or a custom transport. Default 'broadcast'. */
216
+ transport?: 'broadcast' | WuSyncTransport | WebSocket | string;
217
+ /** Channel name for the broadcast transport. Default 'default'. */
218
+ room?: string;
219
+ }
220
+
221
+ /** Live status of a store-sync session (v2.4+). */
222
+ export interface WuSyncStatus {
223
+ connected: boolean;
224
+ site: string | null;
225
+ lamport: number;
226
+ peers: number;
227
+ tracked?: number;
228
+ sent?: number;
229
+ received?: number;
230
+ applied?: number;
231
+ ignored?: number;
232
+ /** Local writes skipped because the value wasn't serializable. */
233
+ dropped?: number;
234
+ loading?: boolean;
235
+ stopped?: boolean;
236
+ /** Set if the connection failed (e.g. unknown transport). */
237
+ error?: string | null;
238
+ }
239
+
240
+ /** Handle returned by `wu.store.sync()` (v2.4+). */
241
+ export interface WuSyncHandle {
242
+ /** Stop syncing — detaches the store tap and closes the transport. */
243
+ stop(): void;
244
+ status(): WuSyncStatus;
245
+ /** Resolves once the sync chunk has loaded and the transport is connected. */
246
+ ready(): Promise<any>;
247
+ readonly connected: boolean;
248
+ readonly instance: any;
55
249
  }
56
250
 
57
251
  export interface WuPlugin {
@@ -152,6 +346,8 @@ export class WuCore {
152
346
  errorBoundary: WuErrorBoundary;
153
347
  sandbox: WuSandbox;
154
348
  cache: WuCache;
349
+ /** Capability-contract registry (v2.5+). */
350
+ contracts: WuContracts;
155
351
 
156
352
  /**
157
353
  * Lazy AI proxy. Auto-loads the AI chunk on first method call.
@@ -177,6 +373,23 @@ export class WuCore {
177
373
  }): Promise<void>;
178
374
  mount(appName: string, containerSelector: string): Promise<void>;
179
375
  unmount(appName: string, options?: { force?: boolean; keepAlive?: boolean }): Promise<void>;
376
+ /**
377
+ * RBAC (v2.6+): fija el principal actual. Las apps que declaran `roles` (en su
378
+ * config de `init` o en su manifest `wu.roles`) solo se montan si el principal
379
+ * está autorizado; un `mount()` no autorizado rechaza con `code:'WU_ACCESS_DENIED'`
380
+ * y emite `wu:access:denied` (DOM) + `access:denied` (bus).
381
+ */
382
+ setPrincipal(principal: WuPrincipal | null): WuPrincipal | null;
383
+ getPrincipal(): WuPrincipal | null;
384
+ /** ¿El principal actual puede montar/acceder a `appName`? Apps sin `roles` → true. */
385
+ can(appName: string): boolean;
386
+ /**
387
+ * Push new props into an already-mounted app without remounting (v2.2+).
388
+ * Resolves `true` if the app's adapter supports live props; resolves `false`
389
+ * (an honest no-op, never throws) when the app is not mounted or its adapter
390
+ * has no `update` slot.
391
+ */
392
+ update(appName: string, props: Record<string, any>): Promise<boolean>;
180
393
  define(appName: string, lifecycle: WuLifecycle): void;
181
394
  app(name: string, config: Partial<WuAppConfig>): WuApp;
182
395
  hide(appName: string): Promise<void>;
@@ -192,6 +405,44 @@ export class WuCore {
192
405
  */
193
406
  getSandboxInfo(appName: string): WuSandboxInfo | null;
194
407
 
408
+ /**
409
+ * Register a capability another app can consume (typed/versioned contract, v2.5+).
410
+ */
411
+ provide<T extends object>(name: string, impl: T, opts?: WuProvideOptions): WuCapabilityHandle;
412
+ /**
413
+ * Consume a capability from another app (v2.5+). Returns a live proxy that
414
+ * fails loudly on access if unsatisfied, or a Promise with { wait: true }.
415
+ */
416
+ consume<T = any>(name: string, range?: string, opts?: { wait?: false; timeout?: number }): T;
417
+ consume<T = any>(name: string, range: string, opts: { wait: true; timeout?: number }): Promise<T>;
418
+
419
+ /**
420
+ * Full-page diagnostic snapshot — every mounted app, its sandbox mode and
421
+ * live-props capability, recent events, and a store snapshot in one object
422
+ * (v2.2+). Backs `wu.showInspector()` and `window.__WU_DEVTOOLS__`.
423
+ */
424
+ inspect(opts?: { events?: number }): WuInspectSnapshot;
425
+
426
+ /** Open the lazy, Shadow-DOM-isolated inspector overlay (v2.2+). */
427
+ showInspector(): Promise<{ close: () => void } | null>;
428
+ /** Close the inspector overlay if open (v2.2+). */
429
+ hideInspector(): Promise<void>;
430
+
431
+ /**
432
+ * Cross-framework time travel (v2.3+). Record store/event/lifecycle
433
+ * mutations and scrub the whole multi-framework page back and forth. The
434
+ * recorder is a lazy chunk loaded on first `wu.timeline.*` call — zero
435
+ * overhead until used. See ROADMAP.md.
436
+ */
437
+ timeline: WuTimelineFacade;
438
+
439
+ /**
440
+ * Force-load the timeline chunk and resolve the real WuTimeline (v2.3+).
441
+ * `await wu.timelineReady()` before the first write you want captured — after
442
+ * it resolves, `wu.timeline.record()` arms synchronously. Mirrors aiReady().
443
+ */
444
+ timelineReady(): Promise<any>;
445
+
195
446
  /**
196
447
  * Tag a <style> or <link> element as belonging to a specific app (v2.1+).
197
448
  * Makes `fully-isolated` / `own-only` styleMode detect the style regardless
@@ -225,7 +476,7 @@ export class WuEventBus {
225
476
  trustedApps: Set<string>;
226
477
  history: WuEvent[];
227
478
 
228
- emit(eventName: string, data?: any, options?: { appName?: string; token?: string; meta?: any }): boolean;
479
+ emit(eventName: string, data?: any, options?: { appName?: string; token?: string; meta?: any; history?: boolean }): boolean;
229
480
  on(eventName: string, callback: (event: WuEvent) => void): () => void;
230
481
  once(eventName: string, callback: (event: WuEvent) => void): () => void;
231
482
  off(eventName: string, callback: (event: WuEvent) => void): void;
@@ -234,6 +485,12 @@ export class WuEventBus {
234
485
  replay(eventNameOrPattern: string, callback: (event: WuEvent) => void): void;
235
486
  clearHistory(eventNameOrPattern?: string): void;
236
487
  matchesWildcard(eventName: string, pattern: string): boolean;
488
+ /**
489
+ * Low-level emit tap (v2.3+). Fires for every emitted event (after history,
490
+ * before listeners), bypassing wildcard matching and authorization — the
491
+ * internal firehose WuTimeline journals from. Returns an unsubscribe fn.
492
+ */
493
+ tap(fn: (event: WuEvent) => void): () => void;
237
494
  enableStrictMode(): void;
238
495
  disableStrictMode(): void;
239
496
  removeAll(): void;
@@ -248,6 +505,23 @@ export class WuStore {
248
505
  set(path: string, value: any): number;
249
506
  on(pattern: string, callback: (value: any, path?: string) => void): () => void;
250
507
  batch(updates: Record<string, any>): number[];
508
+ /**
509
+ * Low-level write tap (v2.3+). Fires synchronously inside set() for every
510
+ * write with the ring-buffer sequence — the substrate WuTimeline journals
511
+ * from. Returns an unsubscribe function.
512
+ */
513
+ tap(fn: (sequence: number, path: string, value: any) => void): () => void;
514
+ /**
515
+ * Replace the whole state and re-notify listeners (v2.3+) — the seek
516
+ * primitive for WuTimeline. Does not touch the ring buffer or taps.
517
+ */
518
+ hydrate(newState: any, opts?: { notifyPaths?: string[] }): void;
519
+ /**
520
+ * Start real-time collaborative sync across replicas (tabs/workers/clients)
521
+ * via a per-path Last-Writer-Wins CRDT (v2.4+). Lazy-loads the sync chunk.
522
+ * See ROADMAP.md (#2).
523
+ */
524
+ sync(opts?: WuSyncOptions): WuSyncHandle;
251
525
  clear(): void;
252
526
  getMetrics(): {
253
527
  reads: number;
@@ -402,6 +676,16 @@ export default wu;
402
676
  export function init(apps: WuAppConfig[]): Promise<void>;
403
677
  export function mount(name: string, container: string): Promise<void>;
404
678
  export function unmount(name: string, opts?: any): Promise<void>;
679
+ /** RBAC (v2.6+): principal actual (rol/permisos de quien usa el sistema). */
680
+ export interface WuPrincipal {
681
+ role?: string;
682
+ roles?: string[];
683
+ permissions?: string[];
684
+ [k: string]: unknown;
685
+ }
686
+ export function setPrincipal(principal: WuPrincipal | null): WuPrincipal | null;
687
+ export function getPrincipal(): WuPrincipal | null;
688
+ export function can(appName: string): boolean;
405
689
  export function define(name: string, lifecycle: WuLifecycle): void;
406
690
  export function app(name: string, config: Partial<WuAppConfig>): WuApp;
407
691
  export function destroy(): Promise<void>;
@@ -417,6 +701,11 @@ export function off(event: string, cb: (event: WuEvent) => void): void;
417
701
  export function getState(path?: string): any;
418
702
  export function setState(path: string, value: any): number;
419
703
  export function onStateChange(pattern: string, cb: (value: any) => void): () => void;
704
+ export function syncStore(opts?: WuSyncOptions): WuSyncHandle;
705
+
706
+ export function provide<T extends object>(name: string, impl: T, opts?: WuProvideOptions): WuCapabilityHandle;
707
+ export function consume<T = any>(name: string, range?: string, opts?: { wait?: false; timeout?: number }): T;
708
+ export function consume<T = any>(name: string, range: string, opts: { wait: true; timeout?: number }): Promise<T>;
420
709
 
421
710
  export function startMeasure(name: string, app?: string): void;
422
711
  export function endMeasure(name: string, app?: string): number;
@@ -436,6 +725,11 @@ export function useHook(phase: string, middleware: Function, opts?: any): void;
436
725
  export function silenceAllLogs(): void;
437
726
  export function enableAllLogs(): void;
438
727
 
728
+ // --- Semver (capability-contract range matching, v2.5+) ---
729
+ export function satisfies(version: string, range: string): boolean;
730
+ export function parseVersion(v: string): [number, number, number];
731
+ export function compareVersions(a: string | number[], b: string | number[]): number;
732
+
439
733
  /**
440
734
  * Canonicalize styleMode aliases (v2.1+).
441
735
  * - `'none'` → `'isolated'`
@@ -443,3 +737,23 @@ export function enableAllLogs(): void;
443
737
  * - Other inputs pass through unchanged.
444
738
  */
445
739
  export function normalizeStyleMode(mode: string | undefined): string | undefined;
740
+
741
+ /**
742
+ * DevTools bridge (v2.2+). A tiny always-present global so external inspectors
743
+ * and the built-in overlay can detect Wu and pull a full-page snapshot.
744
+ */
745
+ export interface WuDevtoolsBridge {
746
+ version: string;
747
+ isWu: true;
748
+ inspect(opts?: { events?: number }): WuInspectSnapshot;
749
+ show(): Promise<{ close: () => void } | null>;
750
+ hide(): Promise<void>;
751
+ subscribe(cb: (event: WuEvent) => void): () => void;
752
+ }
753
+
754
+ declare global {
755
+ interface Window {
756
+ wu?: WuCore;
757
+ __WU_DEVTOOLS__?: WuDevtoolsBridge;
758
+ }
759
+ }
@@ -0,0 +1,2 @@
1
+ const t=[],e=300,n=[];let o=!1;function r(){o||(!function(){const n=window.fetch;window.fetch=async function(...o){const r=Date.now(),i=o[0],s="string"==typeof i?i:i?.url||"",a=(o[1]?.method||i?.method||"GET").toUpperCase();try{const i=await n.apply(window,o),l=parseInt(i.headers?.get("content-length")||"0",10);return t.push({type:"fetch",method:a,url:s,status:i.status,statusText:i.statusText,duration:Date.now()-r,size:l,timestamp:r}),t.length>e&&t.shift(),i}catch(n){throw t.push({type:"fetch",method:a,url:s,status:0,error:n.message,duration:Date.now()-r,timestamp:r}),t.length>e&&t.shift(),n}};const o=XMLHttpRequest.prototype.open,r=XMLHttpRequest.prototype.send;XMLHttpRequest.prototype.open=function(t,e,...n){return this._wuAi={method:(t||"GET").toUpperCase(),url:String(e)},o.call(this,t,e,...n)},XMLHttpRequest.prototype.send=function(...n){return this._wuAi&&(this._wuAi.start=Date.now(),this.addEventListener("loadend",()=>{t.push({type:"xhr",method:this._wuAi.method,url:this._wuAi.url,status:this.status,statusText:this.statusText,duration:Date.now()-this._wuAi.start,size:parseInt(this.getResponseHeader("content-length")||"0",10),timestamp:this._wuAi.start}),t.length>e&&t.shift()})),r.apply(this,n)}}(),function(){const t=["log","warn","error"];for(const e of t){const t=console[e];console[e]=(...o)=>{n.push({level:e,message:o.map(t=>{if("object"!=typeof t)return String(t);try{return JSON.stringify(t)}catch(e){return String(t)}}).join(" "),timestamp:Date.now()}),n.length>500&&n.shift(),t.apply(console,o)}}}(),o=!0)}function i(t,e=0,n=5){if(e>n||!t)return"";const o=" ".repeat(e),r=t.tagName?.toLowerCase()||"",s=t.getAttribute?.("role")||"",a=t.getAttribute?.("aria-label")||"",l=1===t.childNodes?.length&&3===t.childNodes[0].nodeType?t.textContent?.trim().slice(0,80):"";let c=`${o}<${r}`;if(t.id&&(c+=` id="${t.id}"`),s&&(c+=` role="${s}"`),a&&(c+=` aria-label="${a}"`),t.className&&"string"==typeof t.className){const e=t.className.trim().slice(0,60);e&&(c+=` class="${e}"`)}c+=">",l&&(c+=` "${l}"`);let u=c+"\n";const h=(t.shadowRoot||t).children||[];for(let t=0;t<h.length&&t<50;t++)u+=i(h[t],e+1,n);return u}function s(t,e){const n=["color","background","background-color","font-family","font-size","font-weight","border","border-radius","padding","margin","display","flex-direction","align-items","justify-content","gap","width","height","max-width","max-height","overflow","opacity","box-shadow","text-align","line-height","position","top","left","right","bottom","z-index","transform","visibility"];try{const o=window.getComputedStyle(t);for(const t of n){const n=o.getPropertyValue(t);n&&e.style?.setProperty(t,n)}}catch(t){}const o=t.children||[],r=e.children||[],i=Math.min(o.length,r.length,200);for(let t=0;t<i;t++)s(o[t],r[t])}async function a(t,e=.8){const n=t?document.querySelector(t):document.documentElement;if(!n)return{error:`Element not found: ${t}`};const o=n.getBoundingClientRect(),r=Math.ceil(Math.min(o.width||window.innerWidth,1920)),i=Math.ceil(Math.min(o.height||window.innerHeight,1080)),a=n.cloneNode(!0);s(n,a);const l=(new XMLSerializer).serializeToString(a),c=[`<svg xmlns="http://www.w3.org/2000/svg" width="${r}" height="${i}">`,'<foreignObject width="100%" height="100%">',`<div xmlns="http://www.w3.org/1999/xhtml" style="width:${r}px;height:${i}px;overflow:hidden;">`,l,"</div>","</foreignObject>","</svg>"].join(""),u=new Blob([c],{type:"image/svg+xml;charset=utf-8"}),h=URL.createObjectURL(u),d=await new Promise(t=>{const n=new Image;n.onload=()=>{try{const o=document.createElement("canvas");o.width=r,o.height=i;o.getContext("2d").drawImage(n,0,0),t(o.toDataURL("image/png",e))}catch(e){t(null)}finally{URL.revokeObjectURL(h)}},n.onerror=()=>{URL.revokeObjectURL(h),t(null)},n.src=h});if(!d)return{error:"Canvas rendering failed"};const p=d.split(",")[1];return{width:r,height:i,format:"png",base64:p,sizeKB:Math.round(3*p.length/4/1024)}}function l(t,e){let n=null;if(t&&(n=document.querySelector(t)),!n&&e){const t=document.querySelectorAll('button, a, [role="button"], input[type="submit"], input[type="button"], [data-click], label, [onclick]'),o=e.toLowerCase();for(const e of t)if(e.textContent?.trim().toLowerCase().includes(o)){n=e;break}}if(!n)return{error:`Element not found: ${t||`text="${e}"`}`};n.scrollIntoView({behavior:"instant",block:"center"}),n.click();const o=n.tagName?.toLowerCase();return{clicked:`${o}${n.id?`#${n.id}`:""}`,text:n.textContent?.trim().slice(0,100)||"",rect:n.getBoundingClientRect().toJSON?.()||null}}function c(t,e,{clear:n=!1,submit:o=!1}={}){if(!t)return{error:"selector is required"};if(void 0===e)return{error:"text is required"};const r=document.querySelector(t);if(!r)return{error:`Element not found: ${t}`};r.focus(),n&&(r.value="",r.dispatchEvent(new Event("input",{bubbles:!0})));const i=Object.getOwnPropertyDescriptor(window.HTMLInputElement.prototype,"value")?.set||Object.getOwnPropertyDescriptor(window.HTMLTextAreaElement.prototype,"value")?.set,s=n?e:(r.value||"")+e;if(i?i.call(r,s):r.value=s,r.dispatchEvent(new Event("input",{bubbles:!0})),r.dispatchEvent(new Event("change",{bubbles:!0})),o){const t=r.closest("form");t?t.dispatchEvent(new Event("submit",{bubbles:!0,cancelable:!0})):r.dispatchEvent(new KeyboardEvent("keydown",{key:"Enter",code:"Enter",bubbles:!0}))}return{selector:t,typed:e,currentValue:r.value?.slice(0,200),submitted:!!o}}function u(e,n,o=30){let r=t;return e&&(r=r.filter(t=>t.method===e.toUpperCase())),n&&(r="error"===n?r.filter(t=>0===t.status||t.status>=400):r.filter(t=>String(t.status).startsWith(String(n)))),{requests:r.slice(-o),total:t.length,showing:Math.min(r.length,o)}}function h(t,e=30){const o=t&&"all"!==t?n.filter(e=>e.level===t):n;return{messages:o.slice(-e),total:n.length,showing:Math.min(o.length,e)}}export{a,i as b,l as c,h as d,r as e,n as f,u as g,t as n,c as t};
2
+ //# sourceMappingURL=wu-ai-browser-primitives-CaUCk1Xl.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"wu-ai-browser-primitives-CaUCk1Xl.js","sources":["../src/ai/wu-ai-browser-primitives.js"],"sourcesContent":["/**\n * WU-AI Browser Primitives\n *\n * Shared browser capabilities used by both wu-ai-browser.js (Paradigm 1/2)\n * and wu-mcp-bridge.js (Paradigm 3). Single source of truth to avoid\n * duplicating interceptors, DOM traversal, and Canvas rendering.\n */\n\n// ── Shared capture buffers (singleton) ──\n\nexport const networkLog = [];\nexport const MAX_NETWORK_LOG = 300;\nexport const consoleLog = [];\nexport const MAX_CONSOLE_LOG = 500;\n\nlet _interceptorsInstalled = false;\n\n/**\n * Install network + console interceptors (idempotent — only runs once).\n */\nexport function ensureInterceptors() {\n if (_interceptorsInstalled) return;\n _installNetworkInterceptor();\n _installConsoleInterceptor();\n _interceptorsInstalled = true;\n}\n\n/**\n * Build an accessibility tree representation of a DOM element.\n * Traverses into Shadow DOM if present.\n */\nexport function buildA11yTree(el, depth = 0, maxDepth = 5) {\n if (depth > maxDepth || !el) return '';\n\n const indent = ' '.repeat(depth);\n const tag = el.tagName?.toLowerCase() || '';\n const role = el.getAttribute?.('role') || '';\n const ariaLabel = el.getAttribute?.('aria-label') || '';\n const text = el.childNodes?.length === 1 && el.childNodes[0].nodeType === 3\n ? el.textContent?.trim().slice(0, 80) : '';\n\n let line = `${indent}<${tag}`;\n if (el.id) line += ` id=\"${el.id}\"`;\n if (role) line += ` role=\"${role}\"`;\n if (ariaLabel) line += ` aria-label=\"${ariaLabel}\"`;\n if (el.className && typeof el.className === 'string') {\n const cls = el.className.trim().slice(0, 60);\n if (cls) line += ` class=\"${cls}\"`;\n }\n line += '>';\n if (text) line += ` \"${text}\"`;\n\n let result = line + '\\n';\n const root = el.shadowRoot || el;\n const children = root.children || [];\n\n for (let i = 0; i < children.length && i < 50; i++) {\n result += buildA11yTree(children[i], depth + 1, maxDepth);\n }\n return result;\n}\n\n/**\n * Recursively inline computed styles from source to clone for Canvas rendering.\n */\nexport function inlineComputedStyles(source, clone) {\n const props = ['color', 'background', 'background-color', 'font-family',\n 'font-size', 'font-weight', 'border', 'border-radius', 'padding', 'margin',\n 'display', 'flex-direction', 'align-items', 'justify-content', 'gap',\n 'width', 'height', 'max-width', 'max-height', 'overflow', 'opacity',\n 'box-shadow', 'text-align', 'line-height', 'position', 'top', 'left',\n 'right', 'bottom', 'z-index', 'transform', 'visibility'];\n\n try {\n const style = window.getComputedStyle(source);\n for (const prop of props) {\n const val = style.getPropertyValue(prop);\n if (val) clone.style?.setProperty(prop, val);\n }\n } catch (_) { /* skip */ }\n\n const srcKids = source.children || [];\n const cloneKids = clone.children || [];\n const max = Math.min(srcKids.length, cloneKids.length, 200);\n for (let i = 0; i < max; i++) {\n inlineComputedStyles(srcKids[i], cloneKids[i]);\n }\n}\n\n/**\n * Capture a screenshot of a DOM element via Canvas API (SVG foreignObject).\n * @returns {Promise<{ width, height, format, base64, sizeKB } | { error: string }>}\n */\nexport async function captureScreenshot(selector, quality = 0.8) {\n const target = selector\n ? document.querySelector(selector)\n : document.documentElement;\n\n if (!target) return { error: `Element not found: ${selector}` };\n\n const rect = target.getBoundingClientRect();\n const w = Math.ceil(Math.min(rect.width || window.innerWidth, 1920));\n const h = Math.ceil(Math.min(rect.height || window.innerHeight, 1080));\n\n const clone = target.cloneNode(true);\n inlineComputedStyles(target, clone);\n\n const serializer = new XMLSerializer();\n const xhtml = serializer.serializeToString(clone);\n\n const svgStr = [\n `<svg xmlns=\"http://www.w3.org/2000/svg\" width=\"${w}\" height=\"${h}\">`,\n '<foreignObject width=\"100%\" height=\"100%\">',\n `<div xmlns=\"http://www.w3.org/1999/xhtml\" style=\"width:${w}px;height:${h}px;overflow:hidden;\">`,\n xhtml,\n '</div>',\n '</foreignObject>',\n '</svg>',\n ].join('');\n\n const svgBlob = new Blob([svgStr], { type: 'image/svg+xml;charset=utf-8' });\n const url = URL.createObjectURL(svgBlob);\n\n const dataUrl = await new Promise((resolve) => {\n const img = new Image();\n img.onload = () => {\n try {\n const canvas = document.createElement('canvas');\n canvas.width = w;\n canvas.height = h;\n const ctx = canvas.getContext('2d');\n ctx.drawImage(img, 0, 0);\n resolve(canvas.toDataURL('image/png', quality));\n } catch (_) {\n // toDataURL throws SecurityError on tainted canvases — fail gracefully\n resolve(null);\n } finally {\n URL.revokeObjectURL(url);\n }\n };\n img.onerror = () => {\n URL.revokeObjectURL(url);\n resolve(null);\n };\n img.src = url;\n });\n\n if (!dataUrl) return { error: 'Canvas rendering failed' };\n\n const base64 = dataUrl.split(',')[1];\n return {\n width: w,\n height: h,\n format: 'png',\n base64,\n sizeKB: Math.round((base64.length * 3) / 4 / 1024),\n };\n}\n\n/**\n * Click an element by CSS selector or visible text content.\n * @returns {{ clicked, text } | { error }}\n */\nexport function clickElement(selector, text) {\n let el = null;\n\n if (selector) {\n el = document.querySelector(selector);\n }\n\n if (!el && text) {\n const candidates = document.querySelectorAll(\n 'button, a, [role=\"button\"], input[type=\"submit\"], input[type=\"button\"], [data-click], label, [onclick]'\n );\n const searchText = text.toLowerCase();\n for (const candidate of candidates) {\n if (candidate.textContent?.trim().toLowerCase().includes(searchText)) {\n el = candidate;\n break;\n }\n }\n }\n\n if (!el) return { error: `Element not found: ${selector || `text=\"${text}\"`}` };\n\n el.scrollIntoView({ behavior: 'instant', block: 'center' });\n el.click();\n\n const tag = el.tagName?.toLowerCase();\n const id = el.id ? `#${el.id}` : '';\n return {\n clicked: `${tag}${id}`,\n text: el.textContent?.trim().slice(0, 100) || '',\n rect: el.getBoundingClientRect().toJSON?.() || null,\n };\n}\n\n/**\n * Type into an input, textarea, or contenteditable element.\n * Works with React, Vue, Angular, and other frameworks.\n * @returns {{ selector, typed, currentValue, submitted } | { error }}\n */\nexport function typeIntoElement(selector, text, { clear = false, submit = false } = {}) {\n if (!selector) return { error: 'selector is required' };\n if (text === undefined) return { error: 'text is required' };\n\n const el = document.querySelector(selector);\n if (!el) return { error: `Element not found: ${selector}` };\n\n el.focus();\n\n if (clear) {\n el.value = '';\n el.dispatchEvent(new Event('input', { bubbles: true }));\n }\n\n // Use native setter to trigger framework reactivity (React, Vue, etc.)\n const nativeSetter = Object.getOwnPropertyDescriptor(\n window.HTMLInputElement.prototype, 'value'\n )?.set || Object.getOwnPropertyDescriptor(\n window.HTMLTextAreaElement.prototype, 'value'\n )?.set;\n\n const newValue = clear ? text : (el.value || '') + text;\n if (nativeSetter) {\n nativeSetter.call(el, newValue);\n } else {\n el.value = newValue;\n }\n\n el.dispatchEvent(new Event('input', { bubbles: true }));\n el.dispatchEvent(new Event('change', { bubbles: true }));\n\n if (submit) {\n const form = el.closest('form');\n if (form) {\n form.dispatchEvent(new Event('submit', { bubbles: true, cancelable: true }));\n } else {\n el.dispatchEvent(new KeyboardEvent('keydown', { key: 'Enter', code: 'Enter', bubbles: true }));\n }\n }\n\n return {\n selector,\n typed: text,\n currentValue: el.value?.slice(0, 200),\n submitted: !!submit,\n };\n}\n\n/**\n * Filter and return network log entries.\n */\nexport function getFilteredNetwork(method, status, limit = 30) {\n let filtered = networkLog;\n if (method) {\n filtered = filtered.filter((r) => r.method === method.toUpperCase());\n }\n if (status) {\n if (status === 'error') {\n filtered = filtered.filter((r) => r.status === 0 || r.status >= 400);\n } else {\n filtered = filtered.filter((r) => String(r.status).startsWith(String(status)));\n }\n }\n return {\n requests: filtered.slice(-limit),\n total: networkLog.length,\n showing: Math.min(filtered.length, limit),\n };\n}\n\n/**\n * Filter and return console log entries.\n */\nexport function getFilteredConsole(level, limit = 30) {\n const filtered = level && level !== 'all'\n ? consoleLog.filter((m) => m.level === level)\n : consoleLog;\n return {\n messages: filtered.slice(-limit),\n total: consoleLog.length,\n showing: Math.min(filtered.length, limit),\n };\n}\n\n// ── Private: Interceptors ──\n\nfunction _installNetworkInterceptor() {\n // Intercept fetch\n const originalFetch = window.fetch;\n window.fetch = async function (...args) {\n const start = Date.now();\n const req = args[0];\n const url = typeof req === 'string' ? req : req?.url || '';\n const method = (args[1]?.method || req?.method || 'GET').toUpperCase();\n\n try {\n const response = await originalFetch.apply(window, args);\n const size = parseInt(response.headers?.get('content-length') || '0', 10);\n networkLog.push({\n type: 'fetch', method, url,\n status: response.status, statusText: response.statusText,\n duration: Date.now() - start, size, timestamp: start,\n });\n if (networkLog.length > MAX_NETWORK_LOG) networkLog.shift();\n return response;\n } catch (err) {\n networkLog.push({\n type: 'fetch', method, url,\n status: 0, error: err.message,\n duration: Date.now() - start, timestamp: start,\n });\n if (networkLog.length > MAX_NETWORK_LOG) networkLog.shift();\n throw err;\n }\n };\n\n // Intercept XMLHttpRequest\n const origOpen = XMLHttpRequest.prototype.open;\n const origSend = XMLHttpRequest.prototype.send;\n\n XMLHttpRequest.prototype.open = function (method, url, ...rest) {\n this._wuAi = { method: (method || 'GET').toUpperCase(), url: String(url) };\n return origOpen.call(this, method, url, ...rest);\n };\n\n XMLHttpRequest.prototype.send = function (...args) {\n if (this._wuAi) {\n this._wuAi.start = Date.now();\n this.addEventListener('loadend', () => {\n networkLog.push({\n type: 'xhr', method: this._wuAi.method, url: this._wuAi.url,\n status: this.status, statusText: this.statusText,\n duration: Date.now() - this._wuAi.start,\n size: parseInt(this.getResponseHeader('content-length') || '0', 10),\n timestamp: this._wuAi.start,\n });\n if (networkLog.length > MAX_NETWORK_LOG) networkLog.shift();\n });\n }\n return origSend.apply(this, args);\n };\n}\n\nfunction _installConsoleInterceptor() {\n const levels = ['log', 'warn', 'error'];\n for (const level of levels) {\n const original = console[level];\n console[level] = (...args) => {\n consoleLog.push({\n level,\n message: args.map((a) => {\n if (typeof a !== 'object') return String(a);\n try { return JSON.stringify(a); } catch (_) { return String(a); }\n }).join(' '),\n timestamp: Date.now(),\n });\n if (consoleLog.length > MAX_CONSOLE_LOG) consoleLog.shift();\n original.apply(console, args);\n };\n }\n}\n"],"names":["networkLog","MAX_NETWORK_LOG","consoleLog","_interceptorsInstalled","ensureInterceptors","originalFetch","window","fetch","async","args","start","Date","now","req","url","method","toUpperCase","response","apply","size","parseInt","headers","get","push","type","status","statusText","duration","timestamp","length","shift","err","error","message","origOpen","XMLHttpRequest","prototype","open","origSend","send","rest","this","_wuAi","String","call","addEventListener","getResponseHeader","_installNetworkInterceptor","levels","level","original","console","map","a","JSON","stringify","_","join","_installConsoleInterceptor","buildA11yTree","el","depth","maxDepth","indent","repeat","tag","tagName","toLowerCase","role","getAttribute","ariaLabel","text","childNodes","nodeType","textContent","trim","slice","line","id","className","cls","result","children","shadowRoot","i","inlineComputedStyles","source","clone","props","style","getComputedStyle","prop","val","getPropertyValue","setProperty","srcKids","cloneKids","max","Math","min","captureScreenshot","selector","quality","target","document","querySelector","documentElement","rect","getBoundingClientRect","w","ceil","width","innerWidth","h","height","innerHeight","cloneNode","xhtml","XMLSerializer","serializeToString","svgStr","svgBlob","Blob","URL","createObjectURL","dataUrl","Promise","resolve","img","Image","onload","canvas","createElement","getContext","drawImage","toDataURL","revokeObjectURL","onerror","src","base64","split","format","sizeKB","round","clickElement","candidates","querySelectorAll","searchText","candidate","includes","scrollIntoView","behavior","block","click","clicked","toJSON","typeIntoElement","clear","submit","undefined","focus","value","dispatchEvent","Event","bubbles","nativeSetter","Object","getOwnPropertyDescriptor","HTMLInputElement","set","HTMLTextAreaElement","newValue","form","closest","cancelable","KeyboardEvent","key","code","typed","currentValue","submitted","getFilteredNetwork","limit","filtered","filter","r","startsWith","requests","total","showing","getFilteredConsole","m","messages"],"mappings":"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"}