@shadow-js/devtools 0.0.0-stage → 1.0.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 (112) hide show
  1. package/CHANGELOG.md +21 -0
  2. package/LICENSE +21 -0
  3. package/README.md +576 -2
  4. package/dist/dev/agent.d.ts +239 -0
  5. package/dist/dev/agent.js +626 -0
  6. package/dist/dev/agent.js.map +1 -0
  7. package/dist/dev/backend.d.ts +53 -0
  8. package/dist/dev/backend.js +53 -0
  9. package/dist/dev/backend.js.map +1 -0
  10. package/dist/dev/hook.d.ts +83 -0
  11. package/dist/dev/hook.js +136 -0
  12. package/dist/dev/hook.js.map +1 -0
  13. package/dist/dev/index.d.ts +17 -0
  14. package/dist/dev/index.js +17 -0
  15. package/dist/dev/inspection.d.ts +226 -0
  16. package/dist/dev/inspection.js +263 -0
  17. package/dist/dev/inspection.js.map +1 -0
  18. package/dist/dev/inspector.d.ts +331 -0
  19. package/dist/dev/inspector.js +429 -0
  20. package/dist/dev/inspector.js.map +1 -0
  21. package/dist/dev/model.d.ts +418 -0
  22. package/dist/dev/model.js +559 -0
  23. package/dist/dev/model.js.map +1 -0
  24. package/dist/dev/mount.d.ts +207 -0
  25. package/dist/dev/mount.js +256 -0
  26. package/dist/dev/mount.js.map +1 -0
  27. package/dist/dev/overlay.d.ts +102 -0
  28. package/dist/dev/overlay.js +176 -0
  29. package/dist/dev/overlay.js.map +1 -0
  30. package/dist/dev/preview.d.ts +74 -0
  31. package/dist/dev/preview.js +122 -0
  32. package/dist/dev/preview.js.map +1 -0
  33. package/dist/dev/protocol.d.ts +288 -0
  34. package/dist/dev/protocol.js +109 -0
  35. package/dist/dev/protocol.js.map +1 -0
  36. package/dist/dev/ring.d.ts +50 -0
  37. package/dist/dev/ring.js +94 -0
  38. package/dist/dev/ring.js.map +1 -0
  39. package/dist/dev/transport.d.ts +347 -0
  40. package/dist/dev/transport.js +394 -0
  41. package/dist/dev/transport.js.map +1 -0
  42. package/dist/dev/ui/details.js +294 -0
  43. package/dist/dev/ui/details.js.map +1 -0
  44. package/dist/dev/ui/inspection-state.d.ts +43 -0
  45. package/dist/dev/ui/inspection-state.js +62 -0
  46. package/dist/dev/ui/inspection-state.js.map +1 -0
  47. package/dist/dev/ui/issues.js +85 -0
  48. package/dist/dev/ui/issues.js.map +1 -0
  49. package/dist/dev/ui/panel.d.ts +55 -0
  50. package/dist/dev/ui/panel.js +160 -0
  51. package/dist/dev/ui/panel.js.map +1 -0
  52. package/dist/dev/ui/rows.d.ts +44 -0
  53. package/dist/dev/ui/rows.js +132 -0
  54. package/dist/dev/ui/rows.js.map +1 -0
  55. package/dist/dev/ui/state-tab.js +88 -0
  56. package/dist/dev/ui/state-tab.js.map +1 -0
  57. package/dist/dev/ui/state.d.ts +192 -0
  58. package/dist/dev/ui/state.js +147 -0
  59. package/dist/dev/ui/state.js.map +1 -0
  60. package/dist/dev/ui/styles.d.ts +31 -0
  61. package/dist/dev/ui/styles.js +113 -0
  62. package/dist/dev/ui/styles.js.map +1 -0
  63. package/dist/dev/ui/timeline.js +135 -0
  64. package/dist/dev/ui/timeline.js.map +1 -0
  65. package/dist/dev/ui/tree.js +186 -0
  66. package/dist/dev/ui/tree.js.map +1 -0
  67. package/dist/prod/agent.js +2 -0
  68. package/dist/prod/agent.js.map +1 -0
  69. package/dist/prod/backend.js +2 -0
  70. package/dist/prod/backend.js.map +1 -0
  71. package/dist/prod/hook.js +2 -0
  72. package/dist/prod/hook.js.map +1 -0
  73. package/dist/prod/index.js +1 -0
  74. package/dist/prod/inspection.js +2 -0
  75. package/dist/prod/inspection.js.map +1 -0
  76. package/dist/prod/inspector.js +2 -0
  77. package/dist/prod/inspector.js.map +1 -0
  78. package/dist/prod/model.js +2 -0
  79. package/dist/prod/model.js.map +1 -0
  80. package/dist/prod/mount.js +2 -0
  81. package/dist/prod/mount.js.map +1 -0
  82. package/dist/prod/overlay.js +11 -0
  83. package/dist/prod/overlay.js.map +1 -0
  84. package/dist/prod/preview.js +2 -0
  85. package/dist/prod/preview.js.map +1 -0
  86. package/dist/prod/protocol.js +2 -0
  87. package/dist/prod/protocol.js.map +1 -0
  88. package/dist/prod/ring.js +2 -0
  89. package/dist/prod/ring.js.map +1 -0
  90. package/dist/prod/transport.js +2 -0
  91. package/dist/prod/transport.js.map +1 -0
  92. package/dist/prod/ui/details.js +2 -0
  93. package/dist/prod/ui/details.js.map +1 -0
  94. package/dist/prod/ui/inspection-state.js +2 -0
  95. package/dist/prod/ui/inspection-state.js.map +1 -0
  96. package/dist/prod/ui/issues.js +2 -0
  97. package/dist/prod/ui/issues.js.map +1 -0
  98. package/dist/prod/ui/panel.js +2 -0
  99. package/dist/prod/ui/panel.js.map +1 -0
  100. package/dist/prod/ui/rows.js +2 -0
  101. package/dist/prod/ui/rows.js.map +1 -0
  102. package/dist/prod/ui/state-tab.js +2 -0
  103. package/dist/prod/ui/state-tab.js.map +1 -0
  104. package/dist/prod/ui/state.js +2 -0
  105. package/dist/prod/ui/state.js.map +1 -0
  106. package/dist/prod/ui/styles.js +82 -0
  107. package/dist/prod/ui/styles.js.map +1 -0
  108. package/dist/prod/ui/timeline.js +2 -0
  109. package/dist/prod/ui/timeline.js.map +1 -0
  110. package/dist/prod/ui/tree.js +2 -0
  111. package/dist/prod/ui/tree.js.map +1 -0
  112. package/package.json +69 -4
@@ -0,0 +1,347 @@
1
+ import { WireEvent } from "./protocol.js";
2
+ import { ModelLimits } from "./model.js";
3
+ import { Agent, AgentRequest, AgentResponse } from "./agent.js";
4
+ import { Backend, PageHooks } from "./backend.js";
5
+ //#region src/transport.d.ts
6
+ /**
7
+ * The `channel` field every devtools message carries. It lets the messages share a `postMessage`
8
+ * or `BroadcastChannel` with other traffic: anything without this value is ignored.
9
+ *
10
+ * @example
11
+ * import { CHANNEL } from "@shadow-js/devtools";
12
+ * window.addEventListener("message", (event: MessageEvent) => {
13
+ * if (event.data?.channel === CHANNEL) console.log("devtools message", event.data.type);
14
+ * });
15
+ * @since 1.0.0
16
+ */
17
+ export declare const CHANNEL = "shadowjs-devtools";
18
+ /**
19
+ * A message the agent side sends to the panel: the answer to a `hello`, a batch of events, or the
20
+ * answer to a request. All fields are plain data.
21
+ *
22
+ * @since 1.0.0
23
+ */
24
+ export type AgentMessage = {
25
+ channel: typeof CHANNEL;
26
+ v: number;
27
+ from: "agent";
28
+ type: "hello";
29
+ } | {
30
+ channel: typeof CHANNEL;
31
+ v: number;
32
+ from: "agent";
33
+ type: "events";
34
+ events: WireEvent[];
35
+ } | {
36
+ channel: typeof CHANNEL;
37
+ v: number;
38
+ from: "agent";
39
+ type: "response";
40
+ id: number;
41
+ response: AgentResponse;
42
+ };
43
+ /**
44
+ * A message the panel side sends to the agent: a `hello`, or a request. The agent answers a request
45
+ * with a `response` that carries the same `id`. All fields are plain data.
46
+ *
47
+ * @since 1.0.0
48
+ */
49
+ export type PanelMessage = {
50
+ channel: typeof CHANNEL;
51
+ v: number;
52
+ from: "panel";
53
+ type: "hello";
54
+ } | {
55
+ channel: typeof CHANNEL;
56
+ v: number;
57
+ from: "panel";
58
+ type: "request";
59
+ id: number;
60
+ request: AgentRequest;
61
+ };
62
+ /**
63
+ * A duplex channel of plain messages. Implementations must deliver messages in order; they need not
64
+ * be synchronous. `postMessage`, `MessagePort` and `BroadcastChannel` adapters are provided.
65
+ *
66
+ * @since 1.0.0
67
+ */
68
+ export interface Transport {
69
+ /**
70
+ * Sends a message to the other end. The message must be plain data that can be structured-cloned.
71
+ */
72
+ send(message: unknown): void;
73
+ /**
74
+ * Starts delivering incoming messages to `handler`, in order.
75
+ *
76
+ * @returns A function that stops this listener.
77
+ */
78
+ listen(handler: (message: unknown) => void): () => void;
79
+ /**
80
+ * Releases what the transport holds. Closing a port or a `BroadcastChannel` closes it; a window
81
+ * transport holds nothing and does nothing.
82
+ */
83
+ close(): void;
84
+ }
85
+ /**
86
+ * True for a well-formed message sent by an agent. Anything else on the channel is ignored. The check
87
+ * covers the envelope (`channel`, `from`, `v`, `type`) and the fields each message type needs. It does
88
+ * not validate every event inside an `events` message.
89
+ *
90
+ * @param value A received message.
91
+ * @returns True when `value` is an {@link AgentMessage}.
92
+ * @example
93
+ * import { CHANNEL, isAgentMessage } from "@shadow-js/devtools";
94
+ * isAgentMessage({ channel: CHANNEL, v: 1, from: "agent", type: "hello" }); // true
95
+ * isAgentMessage({ channel: CHANNEL, v: 1, from: "panel", type: "hello" }); // false
96
+ * @since 1.0.0
97
+ */
98
+ export declare function isAgentMessage(value: unknown): value is AgentMessage;
99
+ /**
100
+ * True for a well-formed message sent by a panel. Anything else on the channel is ignored. The check
101
+ * covers the envelope and the fields each message type needs, including the request's `type`.
102
+ *
103
+ * @param value A received message.
104
+ * @returns True when `value` is a {@link PanelMessage}.
105
+ * @example
106
+ * import { CHANNEL, isPanelMessage } from "@shadow-js/devtools";
107
+ * isPanelMessage({ channel: CHANNEL, v: 1, from: "panel", type: "hello" }); // true
108
+ * isPanelMessage({ channel: CHANNEL, v: 1, from: "agent", type: "hello" }); // false
109
+ * @since 1.0.0
110
+ */
111
+ export declare function isPanelMessage(value: unknown): value is PanelMessage;
112
+ /**
113
+ * Two connected in-memory transports, for tests and for connecting an agent and a panel inside one
114
+ * page. Messages are structured-cloned, so anything that is not plain serializable data fails here
115
+ * exactly as it would over `postMessage`. Closing either end closes both.
116
+ *
117
+ * @returns `[agentSide, panelSide]`.
118
+ * @example
119
+ * import { connectRemote, createAgent, createMemoryTransportPair, serveAgent } from "@shadow-js/devtools";
120
+ * const [agentSide, panelSide] = createMemoryTransportPair();
121
+ * const stop = serveAgent(createAgent(), agentSide);
122
+ * const backend = connectRemote(panelSide);
123
+ * await backend.ready;
124
+ * stop();
125
+ * @since 1.0.0
126
+ */
127
+ export declare function createMemoryTransportPair(): [Transport, Transport];
128
+ /**
129
+ * The part of a `MessagePort` the adapter uses. A `MessageChannel` end, a worker port and an
130
+ * extension port all fit this shape.
131
+ *
132
+ * @since 1.0.0
133
+ */
134
+ export interface MessagePortLike {
135
+ /**
136
+ * Posts a message to the other end of the port.
137
+ */
138
+ postMessage(message: unknown): void;
139
+ /**
140
+ * Adds a listener for incoming messages.
141
+ */
142
+ addEventListener(type: "message", listener: (event: {
143
+ data: unknown;
144
+ }) => void): void;
145
+ /**
146
+ * Removes a listener added with `addEventListener`.
147
+ */
148
+ removeEventListener(type: "message", listener: (event: {
149
+ data: unknown;
150
+ }) => void): void;
151
+ /**
152
+ * Starts the port. The adapter calls it after it adds a listener. Optional.
153
+ */
154
+ start?(): void;
155
+ /**
156
+ * Closes the port. Optional.
157
+ */
158
+ close?(): void;
159
+ }
160
+ /**
161
+ * A transport over a `MessagePort`: a `MessageChannel` end, a worker port or an extension port.
162
+ * Incoming messages reach the listeners registered with `listen`. `close` closes the port when it
163
+ * supports closing.
164
+ *
165
+ * @param port The port.
166
+ * @returns The transport.
167
+ * @example
168
+ * import { connectRemote, createAgent, createPortTransport, serveAgent } from "@shadow-js/devtools";
169
+ * const channel = new MessageChannel();
170
+ * serveAgent(createAgent(), createPortTransport(channel.port1));
171
+ * const backend = connectRemote(createPortTransport(channel.port2));
172
+ * await backend.ready;
173
+ * @since 1.0.0
174
+ */
175
+ export declare function createPortTransport(port: MessagePortLike): Transport;
176
+ /**
177
+ * The part of a `Window` the adapter uses: its `postMessage`. A `WindowProxy` such as
178
+ * `iframe.contentWindow` fits this shape.
179
+ *
180
+ * @since 1.0.0
181
+ */
182
+ export interface WindowLike {
183
+ /**
184
+ * Posts a message to the window. The adapter always passes a real origin as `targetOrigin`.
185
+ */
186
+ postMessage(message: unknown, targetOrigin: string): void;
187
+ }
188
+ /**
189
+ * The part of the receiving window the adapter uses: its `message` listeners. `globalThis` in a page
190
+ * or a frame fits this shape.
191
+ *
192
+ * @since 1.0.0
193
+ */
194
+ export interface WindowEvents {
195
+ /**
196
+ * Adds a listener for `message` events.
197
+ */
198
+ addEventListener(type: "message", listener: (event: MessageEvent) => void): void;
199
+ /**
200
+ * Removes a listener added with `addEventListener`.
201
+ */
202
+ removeEventListener(type: "message", listener: (event: MessageEvent) => void): void;
203
+ }
204
+ /**
205
+ * Options of {@link createWindowTransport}.
206
+ *
207
+ * @since 1.0.0
208
+ */
209
+ export interface WindowTransportOptions {
210
+ /**
211
+ * The window to talk to: the page being inspected, or the panel's frame.
212
+ */
213
+ target: WindowLike;
214
+ /**
215
+ * The origin of `target`. It is used as `targetOrigin` and to check where messages come from. Never
216
+ * `"*"`: {@link createWindowTransport} refuses it.
217
+ */
218
+ origin: string;
219
+ /**
220
+ * Where messages arrive.
221
+ *
222
+ * @default globalThis
223
+ */
224
+ receiver?: WindowEvents;
225
+ }
226
+ /**
227
+ * A transport over `window.postMessage` between a page and a panel in another window or frame (a
228
+ * DevTools extension page, a popup). Both sides call it, each naming the other window and its origin.
229
+ * Messages are sent only to `target`, with `origin` as the target origin. Incoming messages are
230
+ * delivered only when their origin equals `origin` and their source is `target`; all others are
231
+ * ignored.
232
+ *
233
+ * @param options Target window, its origin and the receiving window.
234
+ * @returns The transport.
235
+ * @throws {TypeError} When `origin` is `"*"`: the messages would reach any origin.
236
+ * @example
237
+ * import { createAgent, createWindowTransport, serveAgent } from "@shadow-js/devtools";
238
+ * const frame = document.querySelector("iframe");
239
+ * if (frame?.contentWindow) {
240
+ * const transport = createWindowTransport({ target: frame.contentWindow, origin: "https://panel.example" });
241
+ * serveAgent(createAgent(), transport);
242
+ * }
243
+ * @since 1.0.0
244
+ */
245
+ export declare function createWindowTransport(options: WindowTransportOptions): Transport;
246
+ /**
247
+ * The part of `BroadcastChannel` the adapter uses.
248
+ *
249
+ * @since 1.0.0
250
+ */
251
+ export interface BroadcastChannelLike {
252
+ /**
253
+ * Posts a message to every other channel object with the same name.
254
+ */
255
+ postMessage(message: unknown): void;
256
+ /**
257
+ * Adds a listener for incoming messages.
258
+ */
259
+ addEventListener(type: "message", listener: (event: {
260
+ data: unknown;
261
+ }) => void): void;
262
+ /**
263
+ * Removes a listener added with `addEventListener`.
264
+ */
265
+ removeEventListener(type: "message", listener: (event: {
266
+ data: unknown;
267
+ }) => void): void;
268
+ /**
269
+ * Closes the channel object.
270
+ */
271
+ close(): void;
272
+ }
273
+ /**
274
+ * A transport over a `BroadcastChannel`, for a panel in another tab or window of the same origin.
275
+ * Several panels can listen to one agent; each message goes to all of them.
276
+ *
277
+ * @param name Channel name. Both sides use the same.
278
+ * @param factory Creates the channel (default `new BroadcastChannel(name)`).
279
+ * @returns The transport.
280
+ * @example
281
+ * import { connectRemote, createBroadcastChannelTransport } from "@shadow-js/devtools";
282
+ * const backend = connectRemote(createBroadcastChannelTransport("shadowjs-devtools"));
283
+ * await backend.ready;
284
+ * @since 1.0.0
285
+ */
286
+ export declare function createBroadcastChannelTransport(name: string, factory?: (name: string) => BroadcastChannelLike): Transport;
287
+ /**
288
+ * Options of {@link serveAgent}: the page-side hooks and the batch size.
289
+ *
290
+ * @since 1.0.0
291
+ */
292
+ export interface ServeOptions extends PageHooks {
293
+ /**
294
+ * Largest event batch sent in one message.
295
+ *
296
+ * @default 2000
297
+ */
298
+ batch?: number;
299
+ }
300
+ /**
301
+ * Exposes an agent over a transport: forwards its event stream to the panel and answers the panel's
302
+ * requests. The agent keeps recording while no panel listens, and the stream is sent regardless. What
303
+ * happens to events nobody receives depends on the transport. A `highlight` request is passed to
304
+ * `options.highlight` and answered without reaching the agent. Stop serving with the returned function.
305
+ *
306
+ * @param agent The agent in the inspected page.
307
+ * @param transport The channel to the panel.
308
+ * @param options Page-side behavior (highlight overlay) and batch size.
309
+ * @returns A function that stops serving.
310
+ * @example
311
+ * import { createAgent, createMemoryTransportPair, serveAgent } from "@shadow-js/devtools";
312
+ * const [pageSide] = createMemoryTransportPair();
313
+ * const stop = serveAgent(createAgent(), pageSide, { highlight: (id) => console.log("highlight", id) });
314
+ * stop();
315
+ * @since 1.0.0
316
+ */
317
+ export declare function serveAgent(agent: Agent, transport: Transport, options?: ServeOptions): () => void;
318
+ /**
319
+ * Options of {@link connectRemote}.
320
+ *
321
+ * @since 1.0.0
322
+ */
323
+ export interface RemoteOptions {
324
+ /**
325
+ * Capacities of the panel's copy of the model (see {@link ModelLimits}). Fields that are not set keep
326
+ * their defaults.
327
+ */
328
+ limits?: Partial<ModelLimits>;
329
+ }
330
+ /**
331
+ * Connects a panel to a remote agent: asks for the complete state, then applies the event stream
332
+ * to a local model. Events that arrive before the state are buffered, and the ones the state already
333
+ * contains are skipped (sequence numbers), so no event is lost or applied twice. Disposing the backend
334
+ * closes the transport.
335
+ *
336
+ * @param transport The channel to the agent.
337
+ * @param options Model limits.
338
+ * @returns A {@link Backend}.
339
+ * @example
340
+ * import { connectRemote, createBroadcastChannelTransport } from "@shadow-js/devtools";
341
+ * const backend = connectRemote(createBroadcastChannelTransport("shadowjs-devtools"));
342
+ * await backend.ready;
343
+ * @since 1.0.0
344
+ */
345
+ export declare function connectRemote(transport: Transport, options?: RemoteOptions): Backend;
346
+ //#endregion
347
+ //# sourceMappingURL=transport.d.ts.map