@atolljs/devtools 0.1.7 → 0.1.9
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/README.md +408 -71
- package/app/api.js +68 -0
- package/app/fw-logos.js +14 -0
- package/app/index.html +161 -2
- package/app/main.js +897 -222
- package/app/panels/actions.js +324 -0
- package/app/panels/audit-rules.js +728 -0
- package/app/panels/audits.js +438 -0
- package/app/panels/inspect-island.js +351 -0
- package/app/panels/memory-values.js +287 -0
- package/app/panels/performance.js +304 -0
- package/app/panels/reactivity.js +271 -0
- package/app/panels/recorder.js +344 -0
- package/app/panels/recording-format.js +166 -0
- package/app/panels/route.d.ts +44 -0
- package/app/panels/route.js +264 -0
- package/app/panels/shell.js +789 -0
- package/app/panels/toast.js +38 -0
- package/dist/bin.js +704 -5
- package/dist/chunk-57NGHQUL.js +344 -0
- package/dist/chunk-6E54FXKS.js +495 -0
- package/dist/chunk-WIL2P7HG.js +661 -0
- package/dist/client.d.ts +7 -0
- package/dist/control.d.ts +4 -0
- package/dist/index.js +2 -1
- package/dist/node.js +2 -1
- package/dist/nodeWs.d.ts +1 -0
- package/dist/otel.d.ts +35 -0
- package/dist/otel.js +87 -0
- package/dist/otelMap.d.ts +232 -0
- package/dist/otelTransport.d.ts +69 -0
- package/dist/overlay.d.ts +16 -2
- package/dist/probes.d.ts +7 -0
- package/dist/protocol.d.ts +46 -4
- package/dist/server.d.ts +19 -0
- package/dist/server.js +61 -3
- package/package.json +6 -2
- package/src/bin.ts +27 -2
- package/src/broadcast.ts +6 -0
- package/src/client.ts +26 -2
- package/src/control.ts +51 -0
- package/src/nodeWs.ts +7 -1
- package/src/otel.ts +140 -0
- package/src/otelMap.ts +661 -0
- package/src/otelTransport.ts +286 -0
- package/src/overlay.ts +239 -47
- package/src/probes.ts +155 -0
- package/src/protocol.ts +52 -4
- package/src/server.ts +83 -3
- package/dist/chunk-4N3NBFL3.js +0 -474
package/dist/chunk-4N3NBFL3.js
DELETED
|
@@ -1,474 +0,0 @@
|
|
|
1
|
-
// ../../src/devtools.ts
|
|
2
|
-
var THREAD = typeof WorkerGlobalScope !== "undefined" && self instanceof WorkerGlobalScope ? "worker" : "main";
|
|
3
|
-
var sink = null;
|
|
4
|
-
var setDevtoolsSink = (custom) => {
|
|
5
|
-
sink = custom;
|
|
6
|
-
};
|
|
7
|
-
var emitDevtools = (event) => {
|
|
8
|
-
if (sink) sink({ ...event, at: performance.now(), thread: THREAD });
|
|
9
|
-
};
|
|
10
|
-
var PROBED = /* @__PURE__ */ Symbol.for("atoll.devtools.fetch");
|
|
11
|
-
var BODY_PREVIEW = 8 * 1024;
|
|
12
|
-
var TEXTISH = /text|json|javascript|xml|html|css|svg|csv|urlencoded|graphql/;
|
|
13
|
-
var headerList = (h) => h ? [...h.entries()].slice(0, 64) : void 0;
|
|
14
|
-
var bodyPreview = (body) => {
|
|
15
|
-
if (body === null || body === void 0) return void 0;
|
|
16
|
-
if (typeof body === "string") return body.slice(0, BODY_PREVIEW);
|
|
17
|
-
if (body instanceof URLSearchParams) return String(body).slice(0, BODY_PREVIEW);
|
|
18
|
-
if (body instanceof Blob) return `[${body.type || "blob"} ${body.size}B]`;
|
|
19
|
-
if (body instanceof ArrayBuffer) return `[ArrayBuffer ${body.byteLength}B]`;
|
|
20
|
-
if (ArrayBuffer.isView(body)) return `[${body.constructor.name} ${body.byteLength}B]`;
|
|
21
|
-
if (typeof FormData !== "undefined" && body instanceof FormData) return "[FormData]";
|
|
22
|
-
return "[stream]";
|
|
23
|
-
};
|
|
24
|
-
var readPreview = async (res, cap) => {
|
|
25
|
-
const reader = res.body?.getReader();
|
|
26
|
-
if (!reader) return void 0;
|
|
27
|
-
const chunks = [];
|
|
28
|
-
let n = 0;
|
|
29
|
-
try {
|
|
30
|
-
while (n < cap) {
|
|
31
|
-
const { done, value } = await reader.read();
|
|
32
|
-
if (done || !value) break;
|
|
33
|
-
chunks.push(value);
|
|
34
|
-
n += value.byteLength;
|
|
35
|
-
}
|
|
36
|
-
} catch {
|
|
37
|
-
}
|
|
38
|
-
if (!n) return void 0;
|
|
39
|
-
const all = new Uint8Array(n);
|
|
40
|
-
let off = 0;
|
|
41
|
-
for (const c of chunks) {
|
|
42
|
-
all.set(c, off);
|
|
43
|
-
off += c.byteLength;
|
|
44
|
-
}
|
|
45
|
-
return new TextDecoder().decode(all) + (n >= cap ? "\u2026" : "");
|
|
46
|
-
};
|
|
47
|
-
var findTiming = async (absUrl, t0) => {
|
|
48
|
-
const perf = globalThis.performance;
|
|
49
|
-
if (!perf?.getEntriesByType) return void 0;
|
|
50
|
-
for (let tries = 0; tries < 12; tries++) {
|
|
51
|
-
let best;
|
|
52
|
-
for (const e of perf.getEntriesByType("resource")) {
|
|
53
|
-
if (e.name !== absUrl || e.startTime < t0 - 5) continue;
|
|
54
|
-
if (!best || e.startTime < best.startTime) best = e;
|
|
55
|
-
}
|
|
56
|
-
if (best) {
|
|
57
|
-
const seg = (a, b) => b > a && a > 0 ? b - a : 0;
|
|
58
|
-
return {
|
|
59
|
-
queue: seg(best.fetchStart, best.domainLookupStart),
|
|
60
|
-
dns: seg(best.domainLookupStart, best.domainLookupEnd),
|
|
61
|
-
tcp: best.secureConnectionStart > 0 ? seg(best.connectStart, best.secureConnectionStart) : seg(best.connectStart, best.connectEnd),
|
|
62
|
-
tls: best.secureConnectionStart > 0 ? seg(best.secureConnectionStart, best.connectEnd) : 0,
|
|
63
|
-
wait: seg(best.requestStart, best.responseStart),
|
|
64
|
-
download: seg(best.responseStart, best.responseEnd),
|
|
65
|
-
transferSize: best.transferSize,
|
|
66
|
-
encodedSize: best.encodedBodySize,
|
|
67
|
-
decodedSize: best.decodedBodySize
|
|
68
|
-
};
|
|
69
|
-
}
|
|
70
|
-
await new Promise((r) => setTimeout(r, 250));
|
|
71
|
-
}
|
|
72
|
-
return void 0;
|
|
73
|
-
};
|
|
74
|
-
var installFetchProbe = (scope) => {
|
|
75
|
-
const original = scope.fetch;
|
|
76
|
-
if (!original || original[PROBED]) return;
|
|
77
|
-
let seq = 0;
|
|
78
|
-
const wrapped = async (input, init) => {
|
|
79
|
-
const t0 = performance.now();
|
|
80
|
-
const id = ++seq;
|
|
81
|
-
const isReq = typeof Request !== "undefined" && input instanceof Request;
|
|
82
|
-
const url = isReq ? input.url : String(input);
|
|
83
|
-
const abs = (() => {
|
|
84
|
-
try {
|
|
85
|
-
return new URL(url, self.location?.href).href;
|
|
86
|
-
} catch {
|
|
87
|
-
return url;
|
|
88
|
-
}
|
|
89
|
-
})();
|
|
90
|
-
const method = (init?.method ?? (isReq ? input.method : "GET")).toUpperCase();
|
|
91
|
-
const reqClone = isReq && !init?.body ? input.clone() : null;
|
|
92
|
-
const reqHeaders = headerList(
|
|
93
|
-
init?.headers ? new Headers(init.headers) : isReq ? input.headers : void 0
|
|
94
|
-
);
|
|
95
|
-
let reqBody = bodyPreview(init?.body);
|
|
96
|
-
try {
|
|
97
|
-
const res = await original.call(scope, input, init);
|
|
98
|
-
const len = res.headers.get("content-length");
|
|
99
|
-
emitDevtools({
|
|
100
|
-
type: "net:fetch",
|
|
101
|
-
id,
|
|
102
|
-
url: url.slice(0, 300),
|
|
103
|
-
method,
|
|
104
|
-
status: res.status,
|
|
105
|
-
ms: performance.now() - t0,
|
|
106
|
-
bytes: len === null ? void 0 : Number(len),
|
|
107
|
-
reqHeaders,
|
|
108
|
-
reqBody
|
|
109
|
-
});
|
|
110
|
-
const resClone = res.clone();
|
|
111
|
-
void (async () => {
|
|
112
|
-
reqBody ??= reqClone ? await reqClone.text().then((t2) => t2.slice(0, BODY_PREVIEW)).catch(() => void 0) : void 0;
|
|
113
|
-
const ct = res.headers.get("content-type") ?? "";
|
|
114
|
-
const resBody = TEXTISH.test(ct) ? await readPreview(resClone, BODY_PREVIEW).catch(() => void 0) : void 0;
|
|
115
|
-
const t = await findTiming(abs, t0);
|
|
116
|
-
emitDevtools({
|
|
117
|
-
type: "net:fetch-detail",
|
|
118
|
-
id,
|
|
119
|
-
reqBody,
|
|
120
|
-
resHeaders: headerList(res.headers),
|
|
121
|
-
resBody,
|
|
122
|
-
timing: t,
|
|
123
|
-
transferSize: t?.transferSize,
|
|
124
|
-
encodedSize: t?.encodedSize,
|
|
125
|
-
decodedSize: t?.decodedSize
|
|
126
|
-
});
|
|
127
|
-
})();
|
|
128
|
-
return res;
|
|
129
|
-
} catch (err) {
|
|
130
|
-
emitDevtools({
|
|
131
|
-
type: "net:fetch",
|
|
132
|
-
id,
|
|
133
|
-
url: url.slice(0, 300),
|
|
134
|
-
method,
|
|
135
|
-
ms: performance.now() - t0,
|
|
136
|
-
error: err instanceof Error ? err.message : String(err),
|
|
137
|
-
reqHeaders,
|
|
138
|
-
reqBody
|
|
139
|
-
});
|
|
140
|
-
throw err;
|
|
141
|
-
}
|
|
142
|
-
};
|
|
143
|
-
wrapped[PROBED] = true;
|
|
144
|
-
scope.fetch = wrapped;
|
|
145
|
-
};
|
|
146
|
-
var memProbed = /* @__PURE__ */ new WeakSet();
|
|
147
|
-
var installMemoryProbe = (scope, intervalMs = 2500) => {
|
|
148
|
-
if (memProbed.has(scope)) return;
|
|
149
|
-
const perf = scope.performance;
|
|
150
|
-
if (!perf) return;
|
|
151
|
-
const mem = perf.memory;
|
|
152
|
-
const inWorker = typeof WorkerGlobalScope !== "undefined" && globalThis.self instanceof WorkerGlobalScope;
|
|
153
|
-
const measure = perf.measureUserAgentSpecificMemory?.bind(perf);
|
|
154
|
-
const procMem = globalThis.process?.memoryUsage;
|
|
155
|
-
if (!mem && (!measure || inWorker) && !procMem) return;
|
|
156
|
-
memProbed.add(scope);
|
|
157
|
-
if (measure && !inWorker) {
|
|
158
|
-
const timer2 = setInterval(() => {
|
|
159
|
-
measure().then((res) => {
|
|
160
|
-
const contexts = (res.breakdown ?? []).map((b) => ({
|
|
161
|
-
bytes: b.bytes,
|
|
162
|
-
scope: b.attribution?.[0]?.scope,
|
|
163
|
-
url: b.attribution?.[0]?.url
|
|
164
|
-
})).sort((a, b) => b.bytes - a.bytes).slice(0, 24);
|
|
165
|
-
emitDevtools({
|
|
166
|
-
type: "runtime:memory",
|
|
167
|
-
heapBytes: res.bytes,
|
|
168
|
-
heapLimitBytes: mem?.jsHeapSizeLimit,
|
|
169
|
-
contexts
|
|
170
|
-
});
|
|
171
|
-
}).catch(() => {
|
|
172
|
-
if (mem) {
|
|
173
|
-
emitDevtools({
|
|
174
|
-
type: "runtime:memory",
|
|
175
|
-
heapBytes: mem.usedJSHeapSize,
|
|
176
|
-
heapLimitBytes: mem.jsHeapSizeLimit
|
|
177
|
-
});
|
|
178
|
-
}
|
|
179
|
-
});
|
|
180
|
-
}, Math.max(intervalMs, 4e3));
|
|
181
|
-
timer2.unref?.();
|
|
182
|
-
return;
|
|
183
|
-
}
|
|
184
|
-
const timer = setInterval(() => {
|
|
185
|
-
if (mem) {
|
|
186
|
-
emitDevtools({
|
|
187
|
-
type: "runtime:memory",
|
|
188
|
-
heapBytes: mem.usedJSHeapSize,
|
|
189
|
-
heapLimitBytes: mem.jsHeapSizeLimit
|
|
190
|
-
});
|
|
191
|
-
} else if (procMem) {
|
|
192
|
-
const u = procMem();
|
|
193
|
-
emitDevtools({ type: "runtime:memory", heapBytes: u.heapUsed, rssBytes: u.rss });
|
|
194
|
-
}
|
|
195
|
-
}, intervalMs);
|
|
196
|
-
timer.unref?.();
|
|
197
|
-
};
|
|
198
|
-
|
|
199
|
-
// src/protocol.ts
|
|
200
|
-
var DEVTOOLS_CHANNEL = "atoll-devtools";
|
|
201
|
-
|
|
202
|
-
// src/broadcast.ts
|
|
203
|
-
function connectBroadcast(opts, session) {
|
|
204
|
-
const bc = new BroadcastChannel(DEVTOOLS_CHANNEL);
|
|
205
|
-
const cap = opts.bufferCap ?? 5e4;
|
|
206
|
-
const tailCap = opts.replayBatches ?? 500;
|
|
207
|
-
const pending = [];
|
|
208
|
-
const tail = [];
|
|
209
|
-
let closed = false;
|
|
210
|
-
const post = (msg) => {
|
|
211
|
-
try {
|
|
212
|
-
bc.postMessage(msg);
|
|
213
|
-
} catch {
|
|
214
|
-
}
|
|
215
|
-
};
|
|
216
|
-
const hello = () => post({ type: "hello", session });
|
|
217
|
-
const flush = () => {
|
|
218
|
-
if (closed || pending.length === 0) return;
|
|
219
|
-
const events = pending.splice(0, pending.length);
|
|
220
|
-
tail.push(events);
|
|
221
|
-
if (tail.length > tailCap) tail.shift();
|
|
222
|
-
post({ type: "batch", session, events });
|
|
223
|
-
};
|
|
224
|
-
bc.onmessage = (m) => {
|
|
225
|
-
if (m.data?.type === "view") {
|
|
226
|
-
hello();
|
|
227
|
-
for (const events of tail) post({ type: "batch", session, events });
|
|
228
|
-
}
|
|
229
|
-
};
|
|
230
|
-
const timer = setInterval(flush, opts.flushMs ?? 100);
|
|
231
|
-
timer.unref?.();
|
|
232
|
-
const bye = () => {
|
|
233
|
-
flush();
|
|
234
|
-
post({ type: "bye", sessionId: session.id });
|
|
235
|
-
};
|
|
236
|
-
const onHide = () => bye();
|
|
237
|
-
if (typeof addEventListener === "function") addEventListener("pagehide", onHide);
|
|
238
|
-
if (opts.network !== false) installFetchProbe(globalThis);
|
|
239
|
-
if (opts.memory !== false) installMemoryProbe(globalThis);
|
|
240
|
-
setDevtoolsSink((event) => {
|
|
241
|
-
if (closed) return;
|
|
242
|
-
pending.push(event);
|
|
243
|
-
if (pending.length > cap) pending.shift();
|
|
244
|
-
if (pending.length >= 1e3) flush();
|
|
245
|
-
});
|
|
246
|
-
hello();
|
|
247
|
-
return {
|
|
248
|
-
session,
|
|
249
|
-
get open() {
|
|
250
|
-
return !closed;
|
|
251
|
-
},
|
|
252
|
-
close() {
|
|
253
|
-
if (closed) return;
|
|
254
|
-
closed = true;
|
|
255
|
-
bye();
|
|
256
|
-
setDevtoolsSink(null);
|
|
257
|
-
clearInterval(timer);
|
|
258
|
-
if (typeof removeEventListener === "function") removeEventListener("pagehide", onHide);
|
|
259
|
-
bc.close();
|
|
260
|
-
}
|
|
261
|
-
};
|
|
262
|
-
}
|
|
263
|
-
|
|
264
|
-
// src/client.ts
|
|
265
|
-
var sessionSeq = 0;
|
|
266
|
-
var makeSession = (opts) => {
|
|
267
|
-
const runtime = typeof window !== "undefined" && typeof window.document !== "undefined" ? "browser" : "node";
|
|
268
|
-
const hint = opts.session?.hint ?? (runtime === "browser" ? globalThis.location?.href : globalThis.process?.title);
|
|
269
|
-
return {
|
|
270
|
-
id: `s-${Date.now().toString(36)}-${++sessionSeq}`,
|
|
271
|
-
name: opts.session?.name,
|
|
272
|
-
runtime,
|
|
273
|
-
hint
|
|
274
|
-
};
|
|
275
|
-
};
|
|
276
|
-
var autoBroadcast = () => typeof BroadcastChannel !== "undefined" && typeof window !== "undefined" && typeof window.document !== "undefined";
|
|
277
|
-
function connectDevtools(opts = {}) {
|
|
278
|
-
const session = makeSession(opts);
|
|
279
|
-
const t = opts.url !== void 0 ? "websocket" : opts.transport ?? "auto";
|
|
280
|
-
const useBc = t === "broadcast" ? typeof BroadcastChannel !== "undefined" : t === "auto" && autoBroadcast();
|
|
281
|
-
return useBc ? connectBroadcast(opts, session) : connectWebSocket(opts, session);
|
|
282
|
-
}
|
|
283
|
-
function connectWebSocket(opts, session) {
|
|
284
|
-
const url = opts.url ?? "ws://127.0.0.1:4780/events";
|
|
285
|
-
const cap = opts.bufferCap ?? 5e4;
|
|
286
|
-
const pending = [];
|
|
287
|
-
let closed = false;
|
|
288
|
-
let sock = null;
|
|
289
|
-
const send = (msg) => {
|
|
290
|
-
if (sock?.open) sock.send(JSON.stringify(msg));
|
|
291
|
-
};
|
|
292
|
-
const flush = () => {
|
|
293
|
-
if (!sock?.open || pending.length === 0) return;
|
|
294
|
-
const events = pending.splice(0, pending.length);
|
|
295
|
-
send({ type: "batch", events });
|
|
296
|
-
};
|
|
297
|
-
const onOpen = () => {
|
|
298
|
-
send({ type: "hello", session });
|
|
299
|
-
flush();
|
|
300
|
-
};
|
|
301
|
-
const isNode = typeof window === "undefined" || typeof window.document === "undefined";
|
|
302
|
-
if (typeof WebSocket !== "undefined") {
|
|
303
|
-
const ws = new WebSocket(url);
|
|
304
|
-
sock = {
|
|
305
|
-
get open() {
|
|
306
|
-
return ws.readyState === ws.OPEN;
|
|
307
|
-
},
|
|
308
|
-
send: (t) => ws.send(t),
|
|
309
|
-
close: () => ws.close()
|
|
310
|
-
};
|
|
311
|
-
ws.onopen = onOpen;
|
|
312
|
-
ws.onclose = () => clearInterval(timer);
|
|
313
|
-
ws.onerror = () => ws.close();
|
|
314
|
-
} else if (isNode) {
|
|
315
|
-
const mod = "./nodeWs.ts";
|
|
316
|
-
void import(
|
|
317
|
-
/* @vite-ignore */
|
|
318
|
-
mod
|
|
319
|
-
).then((m) => {
|
|
320
|
-
if (closed) return;
|
|
321
|
-
const ws = m.connectNodeWebSocket(url);
|
|
322
|
-
sock = ws;
|
|
323
|
-
ws.onOpen = onOpen;
|
|
324
|
-
ws.onClose = () => clearInterval(timer);
|
|
325
|
-
}).catch(() => {
|
|
326
|
-
});
|
|
327
|
-
}
|
|
328
|
-
const timer = setInterval(flush, opts.flushMs ?? 100);
|
|
329
|
-
timer.unref?.();
|
|
330
|
-
if (opts.network !== false) installFetchProbe(globalThis);
|
|
331
|
-
if (opts.memory !== false) installMemoryProbe(globalThis);
|
|
332
|
-
setDevtoolsSink((event) => {
|
|
333
|
-
if (closed) return;
|
|
334
|
-
pending.push(event);
|
|
335
|
-
if (pending.length > cap) pending.shift();
|
|
336
|
-
if (pending.length >= 1e3) flush();
|
|
337
|
-
});
|
|
338
|
-
return {
|
|
339
|
-
session,
|
|
340
|
-
get open() {
|
|
341
|
-
return sock?.open ?? false;
|
|
342
|
-
},
|
|
343
|
-
close() {
|
|
344
|
-
closed = true;
|
|
345
|
-
setDevtoolsSink(null);
|
|
346
|
-
flush();
|
|
347
|
-
sock?.close();
|
|
348
|
-
clearInterval(timer);
|
|
349
|
-
}
|
|
350
|
-
};
|
|
351
|
-
}
|
|
352
|
-
|
|
353
|
-
// src/overlay.ts
|
|
354
|
-
var BTN_STYLE = "position:fixed;z-index:2147483646;font:11px ui-monospace,monospace;color:#c9d1d9;background:#161b22;border:1px solid #30363d;border-radius:6px;padding:5px 9px;cursor:pointer";
|
|
355
|
-
var PANEL_STYLE = "position:fixed;z-index:2147483646;display:flex;flex-direction:column;background:#0d1117;border:1px solid #30363d;border-radius:8px;box-shadow:0 12px 40px #000c;overflow:hidden;min-width:340px;min-height:220px";
|
|
356
|
-
var ANCHOR = {
|
|
357
|
-
topleft: (m) => `left:${m}px;top:${m}px`,
|
|
358
|
-
topcenter: (m) => `left:50%;top:${m}px;transform:translateX(-50%)`,
|
|
359
|
-
topright: (m) => `right:${m}px;top:${m}px`,
|
|
360
|
-
bottomleft: (m) => `left:${m}px;bottom:${m}px`,
|
|
361
|
-
bottomcenter: (m) => `left:50%;bottom:${m}px;transform:translateX(-50%)`,
|
|
362
|
-
bottomright: (m) => `right:${m}px;bottom:${m}px`
|
|
363
|
-
};
|
|
364
|
-
function mountDevtoolsOverlay(opts = {}) {
|
|
365
|
-
const src = opts.src ?? "/__atoll/?mini=1";
|
|
366
|
-
const W = opts.width ?? 760;
|
|
367
|
-
const H = opts.height ?? 580;
|
|
368
|
-
const anchor = ANCHOR[opts.position ?? "bottomright"];
|
|
369
|
-
let open = false;
|
|
370
|
-
const btn = document.createElement("button");
|
|
371
|
-
btn.textContent = "atoll devtools";
|
|
372
|
-
btn.style.cssText = `${BTN_STYLE};${anchor(12)}`;
|
|
373
|
-
const panel = document.createElement("div");
|
|
374
|
-
panel.style.cssText = `${PANEL_STYLE};width:${W}px;height:${H}px;display:none;${anchor(16)}`;
|
|
375
|
-
const head = document.createElement("div");
|
|
376
|
-
head.style.cssText = "display:flex;align-items:center;gap:8px;padding:5px 10px;flex:none;border-bottom:1px solid #21262d;font:11px ui-monospace,monospace;color:#8b949e;background:#161b22;cursor:move;user-select:none";
|
|
377
|
-
head.textContent = "atoll devtools";
|
|
378
|
-
const pop = document.createElement("a");
|
|
379
|
-
pop.href = "/__atoll/";
|
|
380
|
-
pop.target = "_blank";
|
|
381
|
-
pop.rel = "noopener";
|
|
382
|
-
pop.textContent = "full page \u2197";
|
|
383
|
-
pop.style.cssText = "color:#58a6ff;text-decoration:none;margin-left:auto";
|
|
384
|
-
const x = document.createElement("button");
|
|
385
|
-
x.textContent = "\u2014";
|
|
386
|
-
x.title = "collapse";
|
|
387
|
-
x.style.cssText = "color:#8b949e;background:none;border:none;cursor:pointer;font:inherit;padding:0 2px";
|
|
388
|
-
head.append(pop, x);
|
|
389
|
-
const frame = document.createElement("iframe");
|
|
390
|
-
frame.src = src;
|
|
391
|
-
frame.style.cssText = "flex:1;border:0;background:#0d1117;min-height:0";
|
|
392
|
-
const grip = document.createElement("div");
|
|
393
|
-
grip.style.cssText = "position:absolute;right:0;bottom:0;width:16px;height:16px;cursor:nwse-resize;background:linear-gradient(135deg,transparent 50%,#30363d 50%);border-radius:0 0 7px";
|
|
394
|
-
panel.append(head, frame, grip);
|
|
395
|
-
document.body.append(panel, btn);
|
|
396
|
-
const drag = (e, move) => {
|
|
397
|
-
e.preventDefault();
|
|
398
|
-
let lx = e.clientX, ly = e.clientY;
|
|
399
|
-
const mm = (ev) => {
|
|
400
|
-
move(ev.clientX - lx, ev.clientY - ly);
|
|
401
|
-
lx = ev.clientX;
|
|
402
|
-
ly = ev.clientY;
|
|
403
|
-
};
|
|
404
|
-
const up = () => {
|
|
405
|
-
removeEventListener("pointermove", mm);
|
|
406
|
-
removeEventListener("pointerup", up);
|
|
407
|
-
};
|
|
408
|
-
addEventListener("pointermove", mm);
|
|
409
|
-
addEventListener("pointerup", up);
|
|
410
|
-
};
|
|
411
|
-
head.onpointerdown = (e) => {
|
|
412
|
-
if (e.target.closest("a,button")) return;
|
|
413
|
-
drag(e, (dx, dy) => {
|
|
414
|
-
const r = panel.getBoundingClientRect();
|
|
415
|
-
const left = Math.min(Math.max(0, r.left + dx), innerWidth - 60);
|
|
416
|
-
const top = Math.min(Math.max(0, r.top + dy), innerHeight - 40);
|
|
417
|
-
panel.style.left = `${left}px`;
|
|
418
|
-
panel.style.top = `${top}px`;
|
|
419
|
-
panel.style.right = "auto";
|
|
420
|
-
panel.style.bottom = "auto";
|
|
421
|
-
panel.style.transform = "none";
|
|
422
|
-
});
|
|
423
|
-
};
|
|
424
|
-
grip.onpointerdown = (e) => {
|
|
425
|
-
e.stopPropagation();
|
|
426
|
-
drag(e, (dx, dy) => {
|
|
427
|
-
const r = panel.getBoundingClientRect();
|
|
428
|
-
panel.style.width = `${Math.max(340, r.width + dx)}px`;
|
|
429
|
-
panel.style.height = `${Math.max(220, r.height + dy)}px`;
|
|
430
|
-
});
|
|
431
|
-
};
|
|
432
|
-
const set = (v) => {
|
|
433
|
-
open = v;
|
|
434
|
-
panel.style.display = v ? "flex" : "none";
|
|
435
|
-
btn.style.display = v ? "none" : "block";
|
|
436
|
-
};
|
|
437
|
-
btn.onclick = () => set(true);
|
|
438
|
-
x.onclick = () => set(false);
|
|
439
|
-
set(opts.startOpen === true);
|
|
440
|
-
return {
|
|
441
|
-
open: () => set(true),
|
|
442
|
-
close: () => set(false),
|
|
443
|
-
toggle: () => set(!open),
|
|
444
|
-
unmount: () => {
|
|
445
|
-
panel.remove();
|
|
446
|
-
btn.remove();
|
|
447
|
-
}
|
|
448
|
-
};
|
|
449
|
-
}
|
|
450
|
-
|
|
451
|
-
// src/init.ts
|
|
452
|
-
var DEVTOOLS_PARAM = "__atoll_devtools";
|
|
453
|
-
var devtoolsEnabled2 = (enabled) => {
|
|
454
|
-
if (enabled !== void 0) return enabled;
|
|
455
|
-
if (typeof location !== "undefined" && typeof location.search === "string") {
|
|
456
|
-
return new URLSearchParams(location.search).has(DEVTOOLS_PARAM);
|
|
457
|
-
}
|
|
458
|
-
return !!globalThis.process?.env?.ATOLL_DEVTOOLS;
|
|
459
|
-
};
|
|
460
|
-
function initDevtools(opts = {}) {
|
|
461
|
-
if (!devtoolsEnabled2(opts.enabled)) return null;
|
|
462
|
-
const conn = connectDevtools(opts);
|
|
463
|
-
const inWindow = typeof window !== "undefined" && typeof window.document !== "undefined";
|
|
464
|
-
const overlay = inWindow && opts.overlay !== false ? mountDevtoolsOverlay(typeof opts.overlay === "object" ? opts.overlay : {}) : null;
|
|
465
|
-
return { conn, overlay };
|
|
466
|
-
}
|
|
467
|
-
|
|
468
|
-
export {
|
|
469
|
-
connectDevtools,
|
|
470
|
-
mountDevtoolsOverlay,
|
|
471
|
-
DEVTOOLS_PARAM,
|
|
472
|
-
devtoolsEnabled2 as devtoolsEnabled,
|
|
473
|
-
initDevtools
|
|
474
|
-
};
|