@e2edev/web 0.11.0-canary-20260921180210
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/LICENSE +202 -0
- package/NOTICE +5 -0
- package/README.md +112 -0
- package/dist/.build.json +1 -0
- package/dist/actions.d.ts +23 -0
- package/dist/actions.d.ts.map +1 -0
- package/dist/actions.js +174 -0
- package/dist/actions.js.map +1 -0
- package/dist/attempt-session.d.ts +76 -0
- package/dist/attempt-session.d.ts.map +1 -0
- package/dist/attempt-session.js +290 -0
- package/dist/attempt-session.js.map +1 -0
- package/dist/browser-connection.d.ts +34 -0
- package/dist/browser-connection.d.ts.map +1 -0
- package/dist/browser-connection.js +87 -0
- package/dist/browser-connection.js.map +1 -0
- package/dist/capture-scope.d.ts +21 -0
- package/dist/capture-scope.d.ts.map +1 -0
- package/dist/capture-scope.js +61 -0
- package/dist/capture-scope.js.map +1 -0
- package/dist/cdp-recovery.d.ts +29 -0
- package/dist/cdp-recovery.d.ts.map +1 -0
- package/dist/cdp-recovery.js +84 -0
- package/dist/cdp-recovery.js.map +1 -0
- package/dist/cdp-selectors.d.ts +14 -0
- package/dist/cdp-selectors.d.ts.map +1 -0
- package/dist/cdp-selectors.js +48 -0
- package/dist/cdp-selectors.js.map +1 -0
- package/dist/dialogs.d.ts +37 -0
- package/dist/dialogs.d.ts.map +1 -0
- package/dist/dialogs.js +78 -0
- package/dist/dialogs.js.map +1 -0
- package/dist/engine.d.ts +26 -0
- package/dist/engine.d.ts.map +1 -0
- package/dist/engine.js +166 -0
- package/dist/engine.js.map +1 -0
- package/dist/evaluation.d.ts +11 -0
- package/dist/evaluation.d.ts.map +1 -0
- package/dist/evaluation.js +27 -0
- package/dist/evaluation.js.map +1 -0
- package/dist/index.d.ts +21 -0
- package/dist/index.d.ts.map +1 -0
- package/dist/index.js +14 -0
- package/dist/index.js.map +1 -0
- package/dist/install.d.ts +40 -0
- package/dist/install.d.ts.map +1 -0
- package/dist/install.js +117 -0
- package/dist/install.js.map +1 -0
- package/dist/locators.d.ts +74 -0
- package/dist/locators.d.ts.map +1 -0
- package/dist/locators.js +260 -0
- package/dist/locators.js.map +1 -0
- package/dist/observation-capture.d.ts +12 -0
- package/dist/observation-capture.d.ts.map +1 -0
- package/dist/observation-capture.js +93 -0
- package/dist/observation-capture.js.map +1 -0
- package/dist/observation.d.ts +63 -0
- package/dist/observation.d.ts.map +1 -0
- package/dist/observation.js +262 -0
- package/dist/observation.js.map +1 -0
- package/dist/observe.d.ts +51 -0
- package/dist/observe.d.ts.map +1 -0
- package/dist/observe.js +104 -0
- package/dist/observe.js.map +1 -0
- package/dist/operation-budget.d.ts +11 -0
- package/dist/operation-budget.d.ts.map +1 -0
- package/dist/operation-budget.js +40 -0
- package/dist/operation-budget.js.map +1 -0
- package/dist/protected-app.d.ts +32 -0
- package/dist/protected-app.d.ts.map +1 -0
- package/dist/protected-app.js +39 -0
- package/dist/protected-app.js.map +1 -0
- package/dist/read-node.d.ts +170 -0
- package/dist/read-node.d.ts.map +1 -0
- package/dist/read-node.js +823 -0
- package/dist/read-node.js.map +1 -0
- package/dist/refs.d.ts +43 -0
- package/dist/refs.d.ts.map +1 -0
- package/dist/refs.js +85 -0
- package/dist/refs.js.map +1 -0
- package/dist/route-pattern.d.ts +15 -0
- package/dist/route-pattern.d.ts.map +1 -0
- package/dist/route-pattern.js +68 -0
- package/dist/route-pattern.js.map +1 -0
- package/dist/support.d.ts +119 -0
- package/dist/support.d.ts.map +1 -0
- package/dist/support.js +299 -0
- package/dist/support.js.map +1 -0
- package/dist/surface.d.ts +257 -0
- package/dist/surface.d.ts.map +1 -0
- package/dist/surface.js +587 -0
- package/dist/surface.js.map +1 -0
- package/dist/video.d.ts +59 -0
- package/dist/video.d.ts.map +1 -0
- package/dist/video.js +115 -0
- package/dist/video.js.map +1 -0
- package/dist/web.d.ts +191 -0
- package/dist/web.d.ts.map +1 -0
- package/dist/web.js +354 -0
- package/dist/web.js.map +1 -0
- package/package.json +67 -0
|
@@ -0,0 +1,290 @@
|
|
|
1
|
+
/** Owns one attempt's live binding, recovery, references, and recordings. */
|
|
2
|
+
import { mkdirSync } from 'node:fs';
|
|
3
|
+
import path from 'node:path';
|
|
4
|
+
import { EngineError, raceAbort, withinCleanupBudget } from 'e2e/engine';
|
|
5
|
+
import { attachPersistent, recoveryFailed, targetIdentity } from './cdp-recovery.js';
|
|
6
|
+
import { connectionAbort, withConnectionBudget } from './operation-budget.js';
|
|
7
|
+
import { RefRegistry } from './refs.js';
|
|
8
|
+
import { invalidState, translatePwError } from './support.js';
|
|
9
|
+
import { VideoRecorder } from './video.js';
|
|
10
|
+
const TRACE_OPTIONS = { screenshots: true, snapshots: true };
|
|
11
|
+
export class AttemptSession {
|
|
12
|
+
options;
|
|
13
|
+
refs = new RefRegistry();
|
|
14
|
+
lifetime = new AbortController();
|
|
15
|
+
video;
|
|
16
|
+
state = { kind: 'empty' };
|
|
17
|
+
generation = {};
|
|
18
|
+
observed = true;
|
|
19
|
+
tracing = false;
|
|
20
|
+
traceSegments = 0;
|
|
21
|
+
traceParts = [];
|
|
22
|
+
constructor(options) {
|
|
23
|
+
this.options = options;
|
|
24
|
+
this.video = new VideoRecorder(options.viewport, options.artifactsDir);
|
|
25
|
+
}
|
|
26
|
+
/** Captures an immutable connection generation for publication after asynchronous reads. */
|
|
27
|
+
token() { return this.generation; }
|
|
28
|
+
/** Rejects work belonging to a superseded connection or an ended attempt. */
|
|
29
|
+
check(token) {
|
|
30
|
+
if (this.generation !== token || this.state.kind !== 'ready') {
|
|
31
|
+
throw new EngineError('NODE_STALE', 'the connection changed while reading the screen', { retryable: true });
|
|
32
|
+
}
|
|
33
|
+
}
|
|
34
|
+
/** An observation commits its references and freshness together against the same generation. */
|
|
35
|
+
observedGeneration(token) {
|
|
36
|
+
this.check(token);
|
|
37
|
+
this.observed = true;
|
|
38
|
+
}
|
|
39
|
+
/** Observation-backed pointer and keyboard input needs evidence captured after recovery. */
|
|
40
|
+
requireObservation() {
|
|
41
|
+
if (!this.observed)
|
|
42
|
+
throw new EngineError('NODE_STALE', 'observe the screen again after CDP recovery before acting', { retryable: true });
|
|
43
|
+
}
|
|
44
|
+
/** Reads the only published binding. Pending work never replaces it halfway through setup. */
|
|
45
|
+
current() {
|
|
46
|
+
if (this.state.kind === 'failed')
|
|
47
|
+
throw this.state.error;
|
|
48
|
+
if (this.state.kind !== 'ready')
|
|
49
|
+
throw invalidState('no attempt connection is ready');
|
|
50
|
+
return this.state.binding;
|
|
51
|
+
}
|
|
52
|
+
/** Invalidates every asynchronous read and reference at a connection or page transition. */
|
|
53
|
+
invalidate() {
|
|
54
|
+
this.generation = {};
|
|
55
|
+
this.refs.clear();
|
|
56
|
+
}
|
|
57
|
+
/** Opens a context for this attempt, publishing only after its handlers are installed. */
|
|
58
|
+
start(signal) {
|
|
59
|
+
return withConnectionBudget({ signal: AbortSignal.any([signal, this.lifetime.signal]), timeoutMs: 60_000 }, 'connection', (remaining) => this.transition(undefined, remaining(), async () => {
|
|
60
|
+
const persistent = this.options.persistent;
|
|
61
|
+
if (persistent === undefined) {
|
|
62
|
+
const browser = await this.options.acquire(remaining().signal);
|
|
63
|
+
remaining();
|
|
64
|
+
const context = await browser.newContext(this.options.contextOptions);
|
|
65
|
+
return { browser, context, page: null };
|
|
66
|
+
}
|
|
67
|
+
const binding = await attachPersistent(persistent.provision, remaining());
|
|
68
|
+
const contextId = binding.identity.contextId;
|
|
69
|
+
if (persistent.usedContexts.has(contextId)) {
|
|
70
|
+
await binding.browser.close().catch(() => undefined);
|
|
71
|
+
throw recoveryFailed('cdpEndpoint reused a browser from a previous attempt; provision a fresh browser');
|
|
72
|
+
}
|
|
73
|
+
persistent.usedContexts.add(contextId);
|
|
74
|
+
return binding;
|
|
75
|
+
}));
|
|
76
|
+
}
|
|
77
|
+
/** Shares one reconnect, then dispatches once with the time that remains. */
|
|
78
|
+
async run(operation, label, work) {
|
|
79
|
+
const signal = AbortSignal.any([operation.signal, this.lifetime.signal]);
|
|
80
|
+
if (signal.aborted)
|
|
81
|
+
throw connectionAbort(signal, label);
|
|
82
|
+
if (this.state.kind === 'failed')
|
|
83
|
+
throw this.state.error;
|
|
84
|
+
const persistent = this.options.persistent;
|
|
85
|
+
const reconnect = (this.state.kind === 'pending' || (this.state.kind === 'ready' && !this.state.binding.browser.isConnected()));
|
|
86
|
+
if (persistent === undefined || !reconnect)
|
|
87
|
+
return raceAbort(() => work({ ...operation, signal }), signal, label);
|
|
88
|
+
return withConnectionBudget({ ...operation, signal }, label, async (remaining) => {
|
|
89
|
+
if (this.state.kind === 'pending') {
|
|
90
|
+
await raceAbort(this.state.work, remaining().signal, 'CDP recovery');
|
|
91
|
+
}
|
|
92
|
+
else {
|
|
93
|
+
const previous = this.current();
|
|
94
|
+
this.observed = false;
|
|
95
|
+
await this.transition(previous, remaining(), async () => {
|
|
96
|
+
await this.video.pageClosing();
|
|
97
|
+
return attachPersistent(persistent.reconnect, remaining(), previous.identity);
|
|
98
|
+
}, true);
|
|
99
|
+
}
|
|
100
|
+
const current = remaining();
|
|
101
|
+
return raceAbort(() => work({ ...operation, ...current }), current.signal, label);
|
|
102
|
+
});
|
|
103
|
+
}
|
|
104
|
+
/** Owns a candidate through configuration and recording setup, then publishes it once. */
|
|
105
|
+
async transition(previous, budget, open, recover = false) {
|
|
106
|
+
if (budget.signal.aborted)
|
|
107
|
+
throw connectionAbort(budget.signal, 'connection');
|
|
108
|
+
this.invalidate();
|
|
109
|
+
const resumeTrace = recover && this.tracing;
|
|
110
|
+
if (recover)
|
|
111
|
+
this.tracing = false;
|
|
112
|
+
const running = Promise.resolve().then(async () => {
|
|
113
|
+
if (budget.signal.aborted)
|
|
114
|
+
throw connectionAbort(budget.signal, 'connection');
|
|
115
|
+
const candidate = await open();
|
|
116
|
+
const close = () => { void this.release(candidate).catch(() => undefined); };
|
|
117
|
+
budget.signal.addEventListener('abort', close, { once: true });
|
|
118
|
+
try {
|
|
119
|
+
if (budget.signal.aborted)
|
|
120
|
+
throw connectionAbort(budget.signal, 'connection');
|
|
121
|
+
await this.options.configure(candidate.context);
|
|
122
|
+
if (recover && candidate.page !== null) {
|
|
123
|
+
await candidate.page.setViewportSize(previous?.page?.viewportSize() ?? this.options.viewport);
|
|
124
|
+
await this.video.pageOpened(candidate.page);
|
|
125
|
+
}
|
|
126
|
+
if (resumeTrace)
|
|
127
|
+
await candidate.context.tracing.start(TRACE_OPTIONS);
|
|
128
|
+
if (budget.signal.aborted)
|
|
129
|
+
throw connectionAbort(budget.signal, 'connection');
|
|
130
|
+
if (this.state !== pending)
|
|
131
|
+
throw connectionAbort(this.lifetime.signal, 'connection');
|
|
132
|
+
this.tracing = resumeTrace;
|
|
133
|
+
this.state = { kind: 'ready', binding: candidate };
|
|
134
|
+
}
|
|
135
|
+
catch (cause) {
|
|
136
|
+
await this.release(candidate).catch(() => undefined);
|
|
137
|
+
throw cause;
|
|
138
|
+
}
|
|
139
|
+
finally {
|
|
140
|
+
budget.signal.removeEventListener('abort', close);
|
|
141
|
+
}
|
|
142
|
+
});
|
|
143
|
+
const work = raceAbort(running, budget.signal, 'connection').catch((cause) => {
|
|
144
|
+
const error = budget.signal.aborted ? connectionAbort(budget.signal, 'connection') : translatePwError(cause, 'connection');
|
|
145
|
+
if (this.state === pending)
|
|
146
|
+
this.state = { kind: 'failed', binding: previous, error };
|
|
147
|
+
throw error;
|
|
148
|
+
});
|
|
149
|
+
const pending = { kind: 'pending', binding: previous, work };
|
|
150
|
+
this.state = pending;
|
|
151
|
+
await work;
|
|
152
|
+
}
|
|
153
|
+
/** Creates the attempt's active page and records its exact target before exposing it. */
|
|
154
|
+
async ensurePage() {
|
|
155
|
+
const binding = this.current();
|
|
156
|
+
if (binding.page !== null && !binding.page.isClosed())
|
|
157
|
+
return binding.page;
|
|
158
|
+
this.invalidate();
|
|
159
|
+
const token = this.token();
|
|
160
|
+
const page = await binding.context.newPage();
|
|
161
|
+
try {
|
|
162
|
+
let identity = binding.identity;
|
|
163
|
+
if (identity !== undefined) {
|
|
164
|
+
await page.setViewportSize(this.options.viewport);
|
|
165
|
+
identity = { ...identity, target: await targetIdentity(page) };
|
|
166
|
+
}
|
|
167
|
+
this.check(token);
|
|
168
|
+
await this.video.pageOpened(page);
|
|
169
|
+
this.check(token);
|
|
170
|
+
this.state = { kind: 'ready', binding: { ...binding, page, ...(identity === undefined ? {} : { identity }) } };
|
|
171
|
+
return page;
|
|
172
|
+
}
|
|
173
|
+
catch (cause) {
|
|
174
|
+
await page.close().catch(() => undefined);
|
|
175
|
+
throw cause;
|
|
176
|
+
}
|
|
177
|
+
}
|
|
178
|
+
/** Restarts the document while retaining this context's storage. */
|
|
179
|
+
async restart() {
|
|
180
|
+
const binding = this.current();
|
|
181
|
+
this.invalidate();
|
|
182
|
+
const token = this.token();
|
|
183
|
+
await this.video.pageClosing();
|
|
184
|
+
const resume = this.video.isArmed ? await this.closeTraceSegment(binding.context) : false;
|
|
185
|
+
for (const page of binding.context.pages())
|
|
186
|
+
await page.close();
|
|
187
|
+
this.check(token);
|
|
188
|
+
this.state = { kind: 'ready', binding: { ...binding, page: null } };
|
|
189
|
+
await this.ensurePage();
|
|
190
|
+
if (resume)
|
|
191
|
+
await this.startTrace();
|
|
192
|
+
}
|
|
193
|
+
/** Replaces an ordinary context; persistent recovery never advertises this capability. */
|
|
194
|
+
async replace(storageState, operation) {
|
|
195
|
+
const previous = this.current();
|
|
196
|
+
const resume = await this.closeTraceSegment(previous.context);
|
|
197
|
+
await this.video.pageClosing();
|
|
198
|
+
await this.transition(previous, operation, async () => {
|
|
199
|
+
await previous.context.close();
|
|
200
|
+
const context = await previous.browser.newContext({ ...this.options.contextOptions, ...(storageState === undefined ? {} : { storageState }) });
|
|
201
|
+
return { browser: previous.browser, context, page: null };
|
|
202
|
+
});
|
|
203
|
+
if (this.video.isArmed)
|
|
204
|
+
await this.ensurePage();
|
|
205
|
+
if (resume)
|
|
206
|
+
await this.startTrace();
|
|
207
|
+
}
|
|
208
|
+
/** Ends this attempt immediately; late work can only access this retired owner. */
|
|
209
|
+
async close(budget) {
|
|
210
|
+
const state = this.state;
|
|
211
|
+
this.state = { kind: 'closed' };
|
|
212
|
+
this.lifetime.abort();
|
|
213
|
+
this.invalidate();
|
|
214
|
+
if (state.kind === 'pending')
|
|
215
|
+
await withinCleanupBudget(state.work, budget);
|
|
216
|
+
const binding = 'binding' in state ? state.binding : undefined;
|
|
217
|
+
if (binding === undefined)
|
|
218
|
+
return;
|
|
219
|
+
if (this.video.isRecording)
|
|
220
|
+
await withinCleanupBudget(this.video.pageClosing(), budget);
|
|
221
|
+
if (this.tracing)
|
|
222
|
+
await withinCleanupBudget(binding.context.tracing.stop(), budget);
|
|
223
|
+
await withinCleanupBudget(this.release(binding), budget);
|
|
224
|
+
}
|
|
225
|
+
/** Ordinary contexts are engine-owned; persistent browser processes belong to the host. */
|
|
226
|
+
release(binding) {
|
|
227
|
+
return this.options.persistent === undefined ? binding.context.close() : binding.browser.close();
|
|
228
|
+
}
|
|
229
|
+
/** Allocates trace paths inside this attempt's immutable artifact directory. */
|
|
230
|
+
tracePath(name) {
|
|
231
|
+
const relative = path.posix.join('trace', `${name}.zip`);
|
|
232
|
+
const absolute = path.join(this.options.artifactsDir, relative);
|
|
233
|
+
mkdirSync(path.dirname(absolute), { recursive: true });
|
|
234
|
+
return { relative, absolute };
|
|
235
|
+
}
|
|
236
|
+
/** Saves a replaced context's trace when it can still flush it. */
|
|
237
|
+
async closeTraceSegment(context) {
|
|
238
|
+
if (!this.tracing)
|
|
239
|
+
return false;
|
|
240
|
+
this.tracing = false;
|
|
241
|
+
this.traceSegments += 1;
|
|
242
|
+
const { relative, absolute } = this.tracePath(`trace-part${this.traceSegments}`);
|
|
243
|
+
try {
|
|
244
|
+
await context.tracing.stop({ path: absolute });
|
|
245
|
+
this.traceParts.push(relative);
|
|
246
|
+
}
|
|
247
|
+
catch { /* A disconnected context may have lost its final trace segment. */ }
|
|
248
|
+
return true;
|
|
249
|
+
}
|
|
250
|
+
/** Begins tracing the currently committed context. */
|
|
251
|
+
async startTrace() {
|
|
252
|
+
const token = this.token();
|
|
253
|
+
await this.current().context.tracing.start(TRACE_OPTIONS);
|
|
254
|
+
this.check(token);
|
|
255
|
+
this.tracing = true;
|
|
256
|
+
}
|
|
257
|
+
/** Returns finalized segments, including any retained before context replacement failed. */
|
|
258
|
+
async stopTrace() {
|
|
259
|
+
const parts = this.traceParts;
|
|
260
|
+
this.traceParts = [];
|
|
261
|
+
if (parts.length > 0 && !this.tracing)
|
|
262
|
+
return parts;
|
|
263
|
+
const { relative, absolute } = this.tracePath('trace');
|
|
264
|
+
await this.current().context.tracing.stop({ path: absolute });
|
|
265
|
+
this.tracing = false;
|
|
266
|
+
return parts.length === 0 ? relative : [...parts, relative];
|
|
267
|
+
}
|
|
268
|
+
/** Starts video before tracing can choose the page's screencast size. */
|
|
269
|
+
async startVideo() { await this.video.arm(await this.ensurePage()); }
|
|
270
|
+
/** Collects finalized trace segments even when connection replacement failed. */
|
|
271
|
+
collectTrace(operation) {
|
|
272
|
+
return this.finalize(operation, 'trace', () => this.stopTrace());
|
|
273
|
+
}
|
|
274
|
+
/** Collects this attempt's video independently of a failed connection. */
|
|
275
|
+
collectVideo(operation) {
|
|
276
|
+
return this.finalize(operation, 'video', () => this.video.stop());
|
|
277
|
+
}
|
|
278
|
+
/** Terminal artifact collection needs its own budget, but no successful UI dispatch. */
|
|
279
|
+
async finalize(operation, label, collect) {
|
|
280
|
+
try {
|
|
281
|
+
return this.state.kind === 'failed' || this.state.kind === 'closed'
|
|
282
|
+
? await withConnectionBudget(operation, label, (remaining) => raceAbort(collect, remaining().signal, label))
|
|
283
|
+
: await this.run(operation, label, collect);
|
|
284
|
+
}
|
|
285
|
+
catch (cause) {
|
|
286
|
+
throw translatePwError(cause, label);
|
|
287
|
+
}
|
|
288
|
+
}
|
|
289
|
+
}
|
|
290
|
+
//# sourceMappingURL=attempt-session.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"attempt-session.js","sourceRoot":"","sources":["../src/attempt-session.ts"],"names":[],"mappings":"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"}
|
|
@@ -0,0 +1,34 @@
|
|
|
1
|
+
/** Shares one browser process connection across a worker's attempts. */
|
|
2
|
+
import type { Browser } from 'playwright';
|
|
3
|
+
import { chromium } from 'playwright';
|
|
4
|
+
export type BrowserName = 'chromium' | 'firefox' | 'webkit';
|
|
5
|
+
/**
|
|
6
|
+
* Launching a browser process costs hundreds of milliseconds; per-attempt
|
|
7
|
+
* isolation lives in browser contexts, so every attempt a worker runs can
|
|
8
|
+
* share the process. The connection relaunches a browser that crashed or
|
|
9
|
+
* disconnected and is emptied by `dispose` (wired to the engine `dispose`
|
|
10
|
+
* hook).
|
|
11
|
+
*/
|
|
12
|
+
export declare class BrowserConnection {
|
|
13
|
+
private pending;
|
|
14
|
+
/**
|
|
15
|
+
* Returns a connected shared browser, launching or relaunching as needed.
|
|
16
|
+
* When `connect` is given the connection attaches to a remote browser through it
|
|
17
|
+
* instead of launching a local one; `connect` is re-invoked on a relaunch,
|
|
18
|
+
* so a caller that resolves a fresh per-run endpoint reconnects cleanly
|
|
19
|
+
* after a dropped session.
|
|
20
|
+
*/
|
|
21
|
+
acquire(name: BrowserName, headed: boolean, timeoutMs: number, connect?: () => Promise<Browser>): Promise<Browser>;
|
|
22
|
+
/** Closes the connection, including a launch still in flight; idempotent and best-effort. */
|
|
23
|
+
dispose(): Promise<void>;
|
|
24
|
+
}
|
|
25
|
+
/** Maps a browser name to its Playwright BrowserType. */
|
|
26
|
+
export declare function browserType(name: BrowserName): typeof chromium;
|
|
27
|
+
/**
|
|
28
|
+
* Attaches to a remote browser over the Chrome DevTools Protocol. CDP attach
|
|
29
|
+
* is chromium-only; a hosted-browser engine (a per-run cloud session) resolves
|
|
30
|
+
* the endpoint itself and hands it here. `browser.close()` on the result
|
|
31
|
+
* detaches the CDP session without killing the remote process the host owns.
|
|
32
|
+
*/
|
|
33
|
+
export declare function connectCdp(endpoint: string, timeoutMs: number): Promise<Browser>;
|
|
34
|
+
//# sourceMappingURL=browser-connection.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"browser-connection.d.ts","sourceRoot":"","sources":["../src/browser-connection.ts"],"names":[],"mappings":"AAAA,wEAAwE;AAExE,OAAO,KAAK,EAAE,OAAO,EAAE,MAAM,YAAY,CAAC;AAC1C,OAAO,EAAE,QAAQ,EAA8B,MAAM,YAAY,CAAC;AAGlE,MAAM,MAAM,WAAW,GAAG,UAAU,GAAG,SAAS,GAAG,QAAQ,CAAC;AAE5D;;;;;;GAMG;AACH,qBAAa,iBAAiB;IAC5B,OAAO,CAAC,OAAO,CAA+B;IAE9C;;;;;;OAMG;IACG,OAAO,CACX,IAAI,EAAE,WAAW,EACjB,MAAM,EAAE,OAAO,EACf,SAAS,EAAE,MAAM,EACjB,OAAO,CAAC,EAAE,MAAM,OAAO,CAAC,OAAO,CAAC,GAC/B,OAAO,CAAC,OAAO,CAAC,CAkBlB;IAED,6FAA6F;IACvF,OAAO,IAAI,OAAO,CAAC,IAAI,CAAC,CAQ7B;CACF;AAED,yDAAyD;AACzD,wBAAgB,WAAW,CAAC,IAAI,EAAE,WAAW,GAAG,OAAO,QAAQ,CAI9D;AAED;;;;;GAKG;AACH,wBAAsB,UAAU,CAAC,QAAQ,EAAE,MAAM,EAAE,SAAS,EAAE,MAAM,GAAG,OAAO,CAAC,OAAO,CAAC,CAGtF"}
|
|
@@ -0,0 +1,87 @@
|
|
|
1
|
+
/** Shares one browser process connection across a worker's attempts. */
|
|
2
|
+
import { chromium, firefox, selectors, webkit } from 'playwright';
|
|
3
|
+
import { CLOSED_SHADOW_SELECTOR_ENGINE, CLOSED_SHADOW_SELECTOR_ENGINE_SOURCE } from './read-node.js';
|
|
4
|
+
/**
|
|
5
|
+
* Launching a browser process costs hundreds of milliseconds; per-attempt
|
|
6
|
+
* isolation lives in browser contexts, so every attempt a worker runs can
|
|
7
|
+
* share the process. The connection relaunches a browser that crashed or
|
|
8
|
+
* disconnected and is emptied by `dispose` (wired to the engine `dispose`
|
|
9
|
+
* hook).
|
|
10
|
+
*/
|
|
11
|
+
export class BrowserConnection {
|
|
12
|
+
pending;
|
|
13
|
+
/**
|
|
14
|
+
* Returns a connected shared browser, launching or relaunching as needed.
|
|
15
|
+
* When `connect` is given the connection attaches to a remote browser through it
|
|
16
|
+
* instead of launching a local one; `connect` is re-invoked on a relaunch,
|
|
17
|
+
* so a caller that resolves a fresh per-run endpoint reconnects cleanly
|
|
18
|
+
* after a dropped session.
|
|
19
|
+
*/
|
|
20
|
+
async acquire(name, headed, timeoutMs, connect) {
|
|
21
|
+
const cached = this.pending;
|
|
22
|
+
if (cached !== undefined) {
|
|
23
|
+
const browser = await cached.catch(() => null);
|
|
24
|
+
if (browser !== null && browser.isConnected())
|
|
25
|
+
return browser;
|
|
26
|
+
if (this.pending !== cached)
|
|
27
|
+
return this.acquire(name, headed, timeoutMs, connect);
|
|
28
|
+
this.pending = undefined;
|
|
29
|
+
}
|
|
30
|
+
await registerSelectorEngines();
|
|
31
|
+
const launching = connect !== undefined ? connect() : browserType(name).launch({ headless: !headed, timeout: timeoutMs });
|
|
32
|
+
this.pending = launching;
|
|
33
|
+
try {
|
|
34
|
+
return await launching;
|
|
35
|
+
}
|
|
36
|
+
catch (cause) {
|
|
37
|
+
if (this.pending === launching)
|
|
38
|
+
this.pending = undefined;
|
|
39
|
+
throw cause;
|
|
40
|
+
}
|
|
41
|
+
}
|
|
42
|
+
/** Closes the connection, including a launch still in flight; idempotent and best-effort. */
|
|
43
|
+
async dispose() {
|
|
44
|
+
const pending = this.pending;
|
|
45
|
+
this.pending = undefined;
|
|
46
|
+
try {
|
|
47
|
+
await (await pending)?.close();
|
|
48
|
+
}
|
|
49
|
+
catch {
|
|
50
|
+
// Disposal still owns a failed or abandoned launch.
|
|
51
|
+
}
|
|
52
|
+
}
|
|
53
|
+
}
|
|
54
|
+
/** Maps a browser name to its Playwright BrowserType. */
|
|
55
|
+
export function browserType(name) {
|
|
56
|
+
if (name === 'firefox')
|
|
57
|
+
return firefox;
|
|
58
|
+
if (name === 'webkit')
|
|
59
|
+
return webkit;
|
|
60
|
+
return chromium;
|
|
61
|
+
}
|
|
62
|
+
/**
|
|
63
|
+
* Attaches to a remote browser over the Chrome DevTools Protocol. CDP attach
|
|
64
|
+
* is chromium-only; a hosted-browser engine (a per-run cloud session) resolves
|
|
65
|
+
* the endpoint itself and hands it here. `browser.close()` on the result
|
|
66
|
+
* detaches the CDP session without killing the remote process the host owns.
|
|
67
|
+
*/
|
|
68
|
+
export async function connectCdp(endpoint, timeoutMs) {
|
|
69
|
+
await registerSelectorEngines();
|
|
70
|
+
return chromium.connectOverCDP(endpoint, { timeout: timeoutMs });
|
|
71
|
+
}
|
|
72
|
+
/** Registration is process-wide and rejected twice; one shared promise serves every connection. */
|
|
73
|
+
let selectorEngines;
|
|
74
|
+
/**
|
|
75
|
+
* Registers the engine's selector engines. Playwright requires it before the
|
|
76
|
+
* first page of the process exists, and a name registers once, so every
|
|
77
|
+
* acquire awaits the same registration.
|
|
78
|
+
*/
|
|
79
|
+
function registerSelectorEngines() {
|
|
80
|
+
// Playwright serializes a function argument with `toString()` and invokes it
|
|
81
|
+
// in the page, so the factory is materialized from its source here to keep the
|
|
82
|
+
// in-page code self-contained, the same way the reader is assembled.
|
|
83
|
+
const factory = new Function(`return ${CLOSED_SHADOW_SELECTOR_ENGINE_SOURCE};`)();
|
|
84
|
+
selectorEngines ??= selectors.register(CLOSED_SHADOW_SELECTOR_ENGINE, factory);
|
|
85
|
+
return selectorEngines;
|
|
86
|
+
}
|
|
87
|
+
//# sourceMappingURL=browser-connection.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"browser-connection.js","sourceRoot":"","sources":["../src/browser-connection.ts"],"names":[],"mappings":"AAAA,wEAAwE;AAGxE,OAAO,EAAE,QAAQ,EAAE,OAAO,EAAE,SAAS,EAAE,MAAM,EAAE,MAAM,YAAY,CAAC;AAClE,OAAO,EAAE,6BAA6B,EAAE,oCAAoC,EAAE,MAAM,gBAAgB,CAAC;AAIrG;;;;;;GAMG;AACH,MAAM,OAAO,iBAAiB;IACpB,OAAO,CAA+B;IAE9C;;;;;;OAMG;IACH,KAAK,CAAC,OAAO,CACX,IAAiB,EACjB,MAAe,EACf,SAAiB,EACjB,OAAgC;QAEhC,MAAM,MAAM,GAAG,IAAI,CAAC,OAAO,CAAC;QAC5B,IAAI,MAAM,KAAK,SAAS,EAAE,CAAC;YACzB,MAAM,OAAO,GAAG,MAAM,MAAM,CAAC,KAAK,CAAC,GAAG,EAAE,CAAC,IAAI,CAAC,CAAC;YAC/C,IAAI,OAAO,KAAK,IAAI,IAAI,OAAO,CAAC,WAAW,EAAE;gBAAE,OAAO,OAAO,CAAC;YAC9D,IAAI,IAAI,CAAC,OAAO,KAAK,MAAM;gBAAE,OAAO,IAAI,CAAC,OAAO,CAAC,IAAI,EAAE,MAAM,EAAE,SAAS,EAAE,OAAO,CAAC,CAAC;YACnF,IAAI,CAAC,OAAO,GAAG,SAAS,CAAC;QAC3B,CAAC;QACD,MAAM,uBAAuB,EAAE,CAAC;QAChC,MAAM,SAAS,GACb,OAAO,KAAK,SAAS,CAAC,CAAC,CAAC,OAAO,EAAE,CAAC,CAAC,CAAC,WAAW,CAAC,IAAI,CAAC,CAAC,MAAM,CAAC,EAAE,QAAQ,EAAE,CAAC,MAAM,EAAE,OAAO,EAAE,SAAS,EAAE,CAAC,CAAC;QAC1G,IAAI,CAAC,OAAO,GAAG,SAAS,CAAC;QACzB,IAAI,CAAC;YACH,OAAO,MAAM,SAAS,CAAC;QACzB,CAAC;QAAC,OAAO,KAAK,EAAE,CAAC;YACf,IAAI,IAAI,CAAC,OAAO,KAAK,SAAS;gBAAE,IAAI,CAAC,OAAO,GAAG,SAAS,CAAC;YACzD,MAAM,KAAK,CAAC;QACd,CAAC;IACH,CAAC;IAED,6FAA6F;IAC7F,KAAK,CAAC,OAAO;QACX,MAAM,OAAO,GAAG,IAAI,CAAC,OAAO,CAAC;QAC7B,IAAI,CAAC,OAAO,GAAG,SAAS,CAAC;QACzB,IAAI,CAAC;YACH,MAAM,CAAC,MAAM,OAAO,CAAC,EAAE,KAAK,EAAE,CAAC;QACjC,CAAC;QAAC,MAAM,CAAC;YACP,oDAAoD;QACtD,CAAC;IACH,CAAC;CACF;AAED,yDAAyD;AACzD,MAAM,UAAU,WAAW,CAAC,IAAiB;IAC3C,IAAI,IAAI,KAAK,SAAS;QAAE,OAAO,OAAO,CAAC;IACvC,IAAI,IAAI,KAAK,QAAQ;QAAE,OAAO,MAAM,CAAC;IACrC,OAAO,QAAQ,CAAC;AAClB,CAAC;AAED;;;;;GAKG;AACH,MAAM,CAAC,KAAK,UAAU,UAAU,CAAC,QAAgB,EAAE,SAAiB;IAClE,MAAM,uBAAuB,EAAE,CAAC;IAChC,OAAO,QAAQ,CAAC,cAAc,CAAC,QAAQ,EAAE,EAAE,OAAO,EAAE,SAAS,EAAE,CAAC,CAAC;AACnE,CAAC;AAED,mGAAmG;AACnG,IAAI,eAA0C,CAAC;AAE/C;;;;GAIG;AACH,SAAS,uBAAuB;IAC9B,6EAA6E;IAC7E,+EAA+E;IAC/E,qEAAqE;IACrE,MAAM,OAAO,GAAG,IAAI,QAAQ,CAAC,UAAU,oCAAoC,GAAG,CAAC,EAAmB,CAAC;IACnG,eAAe,KAAK,SAAS,CAAC,QAAQ,CAAC,6BAA6B,EAAE,OAAO,CAAC,CAAC;IAC/E,OAAO,eAAe,CAAC;AACzB,CAAC"}
|
|
@@ -0,0 +1,21 @@
|
|
|
1
|
+
/** Deadline and handle ownership for one observation capture operation. */
|
|
2
|
+
import type { JSHandle } from 'playwright';
|
|
3
|
+
/** Releases acquired and late-arriving handles without waiting on the transport. */
|
|
4
|
+
export declare class CaptureScope {
|
|
5
|
+
readonly deadline: number;
|
|
6
|
+
private readonly signal;
|
|
7
|
+
private active;
|
|
8
|
+
private readonly handles;
|
|
9
|
+
constructor(deadline: number, signal: AbortSignal);
|
|
10
|
+
/** Runs the complete operation, including readback, within one absolute deadline. */
|
|
11
|
+
run<T>(work: () => Promise<T>): Promise<T>;
|
|
12
|
+
/** Stops abandoned work before its next read or mutation; receives late handles for disposal. */
|
|
13
|
+
read<T>(work: () => Promise<T>, receive?: (value: T) => void): Promise<T>;
|
|
14
|
+
/** Takes ownership even when the operation ended before the handle arrived. */
|
|
15
|
+
own(handle: JSHandle): boolean;
|
|
16
|
+
/** Transfers a successfully captured element to the enclosing capture or published generation. */
|
|
17
|
+
release(handle: JSHandle): void;
|
|
18
|
+
/** Refuses further work after cancellation, expiry, or completion. */
|
|
19
|
+
check(): void;
|
|
20
|
+
}
|
|
21
|
+
//# sourceMappingURL=capture-scope.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"capture-scope.d.ts","sourceRoot":"","sources":["../src/capture-scope.ts"],"names":[],"mappings":"AAAA,2EAA2E;AAE3E,OAAO,KAAK,EAAE,QAAQ,EAAE,MAAM,YAAY,CAAC;AAI3C,oFAAoF;AACpF,qBAAa,YAAY;IAIX,QAAQ,CAAC,QAAQ,EAAE,MAAM;IAAE,OAAO,CAAC,QAAQ,CAAC,MAAM;IAH9D,OAAO,CAAC,MAAM,CAAQ;IACtB,OAAO,CAAC,QAAQ,CAAC,OAAO,CAAuB;IAE/C,YAAqB,QAAQ,EAAE,MAAM,EAAmB,MAAM,EAAE,WAAW,EAAI;IAE/E,qFAAqF;IAC/E,GAAG,CAAC,CAAC,EAAE,IAAI,EAAE,MAAM,OAAO,CAAC,CAAC,CAAC,GAAG,OAAO,CAAC,CAAC,CAAC,CAe/C;IAED,iGAAiG;IAC3F,IAAI,CAAC,CAAC,EAAE,IAAI,EAAE,MAAM,OAAO,CAAC,CAAC,CAAC,EAAE,OAAO,CAAC,EAAE,CAAC,KAAK,EAAE,CAAC,KAAK,IAAI,GAAG,OAAO,CAAC,CAAC,CAAC,CAM9E;IAED,+EAA+E;IAC/E,GAAG,CAAC,MAAM,EAAE,QAAQ,GAAG,OAAO,CAI7B;IAED,kGAAkG;IAClG,OAAO,CAAC,MAAM,EAAE,QAAQ,GAAG,IAAI,CAE9B;IAED,sEAAsE;IACtE,KAAK,IAAI,IAAI,CAGZ;CACF"}
|
|
@@ -0,0 +1,61 @@
|
|
|
1
|
+
/** Deadline and handle ownership for one observation capture operation. */
|
|
2
|
+
import { EngineError, raceAbort, withTimeout } from 'e2e/engine';
|
|
3
|
+
import { cancelled } from './support.js';
|
|
4
|
+
/** Releases acquired and late-arriving handles without waiting on the transport. */
|
|
5
|
+
export class CaptureScope {
|
|
6
|
+
deadline;
|
|
7
|
+
signal;
|
|
8
|
+
active = true;
|
|
9
|
+
handles = new Set();
|
|
10
|
+
constructor(deadline, signal) {
|
|
11
|
+
this.deadline = deadline;
|
|
12
|
+
this.signal = signal;
|
|
13
|
+
}
|
|
14
|
+
/** Runs the complete operation, including readback, within one absolute deadline. */
|
|
15
|
+
async run(work) {
|
|
16
|
+
try {
|
|
17
|
+
this.check();
|
|
18
|
+
const result = await withTimeout(raceAbort(work, this.signal, 'observe'), this.deadline - Date.now(), captureTimeout);
|
|
19
|
+
this.check();
|
|
20
|
+
return result;
|
|
21
|
+
}
|
|
22
|
+
finally {
|
|
23
|
+
this.active = false;
|
|
24
|
+
for (const handle of this.handles)
|
|
25
|
+
void handle.dispose().catch(() => undefined);
|
|
26
|
+
this.handles.clear();
|
|
27
|
+
}
|
|
28
|
+
}
|
|
29
|
+
/** Stops abandoned work before its next read or mutation; receives late handles for disposal. */
|
|
30
|
+
async read(work, receive) {
|
|
31
|
+
this.check();
|
|
32
|
+
const value = await work();
|
|
33
|
+
receive?.(value);
|
|
34
|
+
this.check();
|
|
35
|
+
return value;
|
|
36
|
+
}
|
|
37
|
+
/** Takes ownership even when the operation ended before the handle arrived. */
|
|
38
|
+
own(handle) {
|
|
39
|
+
if (this.active)
|
|
40
|
+
this.handles.add(handle);
|
|
41
|
+
else
|
|
42
|
+
void handle.dispose().catch(() => undefined);
|
|
43
|
+
return this.active;
|
|
44
|
+
}
|
|
45
|
+
/** Transfers a successfully captured element to the enclosing capture or published generation. */
|
|
46
|
+
release(handle) {
|
|
47
|
+
this.handles.delete(handle);
|
|
48
|
+
}
|
|
49
|
+
/** Refuses further work after cancellation, expiry, or completion. */
|
|
50
|
+
check() {
|
|
51
|
+
if (this.signal.aborted)
|
|
52
|
+
throw cancelled('observe cancelled');
|
|
53
|
+
if (!this.active || Date.now() >= this.deadline)
|
|
54
|
+
throw captureTimeout();
|
|
55
|
+
}
|
|
56
|
+
}
|
|
57
|
+
/** A capture timeout is recoverable only through the caller's explicit pixel policy. */
|
|
58
|
+
function captureTimeout() {
|
|
59
|
+
return new EngineError('OPERATION_TIMEOUT', 'observation capture timed out', { retryable: false });
|
|
60
|
+
}
|
|
61
|
+
//# sourceMappingURL=capture-scope.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"capture-scope.js","sourceRoot":"","sources":["../src/capture-scope.ts"],"names":[],"mappings":"AAAA,2EAA2E;AAG3E,OAAO,EAAE,WAAW,EAAE,SAAS,EAAE,WAAW,EAAE,MAAM,YAAY,CAAC;AACjE,OAAO,EAAE,SAAS,EAAE,MAAM,cAAc,CAAC;AAEzC,oFAAoF;AACpF,MAAM,OAAO,YAAY;IAIF,QAAQ;IAA2B,MAAM;IAHtD,MAAM,GAAG,IAAI,CAAC;IACL,OAAO,GAAG,IAAI,GAAG,EAAY,CAAC;IAE/C,YAAqB,QAAgB,EAAmB,MAAmB;wBAAtD,QAAQ;sBAA2B,MAAM;IAAgB,CAAC;IAE/E,qFAAqF;IACrF,KAAK,CAAC,GAAG,CAAI,IAAsB;QACjC,IAAI,CAAC;YACH,IAAI,CAAC,KAAK,EAAE,CAAC;YACb,MAAM,MAAM,GAAG,MAAM,WAAW,CAC9B,SAAS,CAAC,IAAI,EAAE,IAAI,CAAC,MAAM,EAAE,SAAS,CAAC,EACvC,IAAI,CAAC,QAAQ,GAAG,IAAI,CAAC,GAAG,EAAE,EAC1B,cAAc,CACf,CAAC;YACF,IAAI,CAAC,KAAK,EAAE,CAAC;YACb,OAAO,MAAM,CAAC;QAChB,CAAC;gBAAS,CAAC;YACT,IAAI,CAAC,MAAM,GAAG,KAAK,CAAC;YACpB,KAAK,MAAM,MAAM,IAAI,IAAI,CAAC,OAAO;gBAAE,KAAK,MAAM,CAAC,OAAO,EAAE,CAAC,KAAK,CAAC,GAAG,EAAE,CAAC,SAAS,CAAC,CAAC;YAChF,IAAI,CAAC,OAAO,CAAC,KAAK,EAAE,CAAC;QACvB,CAAC;IACH,CAAC;IAED,iGAAiG;IACjG,KAAK,CAAC,IAAI,CAAI,IAAsB,EAAE,OAA4B;QAChE,IAAI,CAAC,KAAK,EAAE,CAAC;QACb,MAAM,KAAK,GAAG,MAAM,IAAI,EAAE,CAAC;QAC3B,OAAO,EAAE,CAAC,KAAK,CAAC,CAAC;QACjB,IAAI,CAAC,KAAK,EAAE,CAAC;QACb,OAAO,KAAK,CAAC;IACf,CAAC;IAED,+EAA+E;IAC/E,GAAG,CAAC,MAAgB;QAClB,IAAI,IAAI,CAAC,MAAM;YAAE,IAAI,CAAC,OAAO,CAAC,GAAG,CAAC,MAAM,CAAC,CAAC;;YACrC,KAAK,MAAM,CAAC,OAAO,EAAE,CAAC,KAAK,CAAC,GAAG,EAAE,CAAC,SAAS,CAAC,CAAC;QAClD,OAAO,IAAI,CAAC,MAAM,CAAC;IACrB,CAAC;IAED,kGAAkG;IAClG,OAAO,CAAC,MAAgB;QACtB,IAAI,CAAC,OAAO,CAAC,MAAM,CAAC,MAAM,CAAC,CAAC;IAC9B,CAAC;IAED,sEAAsE;IACtE,KAAK;QACH,IAAI,IAAI,CAAC,MAAM,CAAC,OAAO;YAAE,MAAM,SAAS,CAAC,mBAAmB,CAAC,CAAC;QAC9D,IAAI,CAAC,IAAI,CAAC,MAAM,IAAI,IAAI,CAAC,GAAG,EAAE,IAAI,IAAI,CAAC,QAAQ;YAAE,MAAM,cAAc,EAAE,CAAC;IAC1E,CAAC;CACF;AAED,wFAAwF;AACxF,SAAS,cAAc;IACrB,OAAO,IAAI,WAAW,CAAC,mBAAmB,EAAE,+BAA+B,EAAE,EAAE,SAAS,EAAE,KAAK,EAAE,CAAC,CAAC;AACrG,CAAC"}
|
|
@@ -0,0 +1,29 @@
|
|
|
1
|
+
/** Validates a persistent CDP binding without publishing or retaining it. */
|
|
2
|
+
import type { Browser, BrowserContext, Page } from 'playwright';
|
|
3
|
+
import { EngineError } from 'e2e/engine';
|
|
4
|
+
import { type ConnectionBudget } from './operation-budget.ts';
|
|
5
|
+
export type CdpEndpointResolver = (signal: AbortSignal) => string | Promise<string>;
|
|
6
|
+
interface TargetIdentity {
|
|
7
|
+
readonly targetId: string;
|
|
8
|
+
readonly browserContextId?: string;
|
|
9
|
+
}
|
|
10
|
+
export interface PersistentIdentity {
|
|
11
|
+
readonly contextId: string;
|
|
12
|
+
readonly target?: TargetIdentity;
|
|
13
|
+
}
|
|
14
|
+
export interface SessionBinding {
|
|
15
|
+
readonly browser: Browser;
|
|
16
|
+
readonly context: BrowserContext;
|
|
17
|
+
readonly page: Page | null;
|
|
18
|
+
readonly identity?: PersistentIdentity;
|
|
19
|
+
}
|
|
20
|
+
/** A failed reconnect must never quietly provision another session. */
|
|
21
|
+
export declare function recoveryFailed(detail: string): EngineError;
|
|
22
|
+
/** Reads protocol identity, independent of URL, document contents, and tab order. */
|
|
23
|
+
export declare function targetIdentity(page: Page): Promise<TargetIdentity>;
|
|
24
|
+
/** Owns an uncommitted connection until its identity is proven; aborted and late connections detach. */
|
|
25
|
+
export declare function attachPersistent(resolve: CdpEndpointResolver, budget: ConnectionBudget, previous?: PersistentIdentity): Promise<SessionBinding & {
|
|
26
|
+
readonly identity: PersistentIdentity;
|
|
27
|
+
}>;
|
|
28
|
+
export {};
|
|
29
|
+
//# sourceMappingURL=cdp-recovery.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"cdp-recovery.d.ts","sourceRoot":"","sources":["../src/cdp-recovery.ts"],"names":[],"mappings":"AAAA,6EAA6E;AAC7E,OAAO,KAAK,EAAE,OAAO,EAAE,cAAc,EAAE,IAAI,EAAE,MAAM,YAAY,CAAC;AAChE,OAAO,EAAE,WAAW,EAAE,MAAM,YAAY,CAAC;AAGzC,OAAO,EAAmB,KAAK,gBAAgB,EAAE,MAAM,uBAAuB,CAAC;AAE/E,MAAM,MAAM,mBAAmB,GAAG,CAAC,MAAM,EAAE,WAAW,KAAK,MAAM,GAAG,OAAO,CAAC,MAAM,CAAC,CAAC;AAEpF,UAAU,cAAc;IACtB,QAAQ,CAAC,QAAQ,EAAE,MAAM,CAAC;IAC1B,QAAQ,CAAC,gBAAgB,CAAC,EAAE,MAAM,CAAC;CACpC;AAED,MAAM,WAAW,kBAAkB;IACjC,QAAQ,CAAC,SAAS,EAAE,MAAM,CAAC;IAC3B,QAAQ,CAAC,MAAM,CAAC,EAAE,cAAc,CAAC;CAClC;AAED,MAAM,WAAW,cAAc;IAC7B,QAAQ,CAAC,OAAO,EAAE,OAAO,CAAC;IAC1B,QAAQ,CAAC,OAAO,EAAE,cAAc,CAAC;IACjC,QAAQ,CAAC,IAAI,EAAE,IAAI,GAAG,IAAI,CAAC;IAC3B,QAAQ,CAAC,QAAQ,CAAC,EAAE,kBAAkB,CAAC;CACxC;AAED,uEAAuE;AACvE,wBAAgB,cAAc,CAAC,MAAM,EAAE,MAAM,GAAG,WAAW,CAE1D;AAED,qFAAqF;AACrF,wBAAsB,cAAc,CAAC,IAAI,EAAE,IAAI,GAAG,OAAO,CAAC,cAAc,CAAC,CAOxE;AAED,wGAAwG;AACxG,wBAAsB,gBAAgB,CACpC,OAAO,EAAE,mBAAmB,EAC5B,MAAM,EAAE,gBAAgB,EACxB,QAAQ,CAAC,EAAE,kBAAkB,GAC5B,OAAO,CAAC,cAAc,GAAG;IAAE,QAAQ,CAAC,QAAQ,EAAE,kBAAkB,CAAA;CAAE,CAAC,CAqDrE"}
|