@checkly/playwright-core 1.42.17 → 1.47.20-alpha
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/ThirdPartyNotices.txt +144 -109
- package/browsers.json +15 -25
- package/lib/androidServerImpl.js +1 -1
- package/lib/browserServerImpl.js +1 -1
- package/lib/cli/driver.js +1 -3
- package/lib/cli/program.js +5 -10
- package/lib/client/android.js +1 -1
- package/lib/client/api.js +7 -0
- package/lib/client/browserContext.js +37 -5
- package/lib/client/browserType.js +19 -11
- package/lib/client/channelOwner.js +19 -16
- package/lib/client/clientInstrumentation.js +17 -7
- package/lib/client/clock.js +68 -0
- package/lib/client/connection.js +9 -6
- package/lib/client/electron.js +7 -5
- package/lib/client/elementHandle.js +44 -14
- package/lib/client/eventEmitter.js +314 -0
- package/lib/client/fetch.js +81 -28
- package/lib/client/frame.js +2 -4
- package/lib/client/jsHandle.js +7 -1
- package/lib/client/locator.js +9 -0
- package/lib/client/network.js +12 -9
- package/lib/client/page.js +45 -23
- package/lib/client/playwright.js +3 -0
- package/lib/client/tracing.js +7 -4
- package/lib/common/socksProxy.js +2 -2
- package/lib/generated/clockSource.js +7 -0
- package/lib/generated/injectedScriptSource.js +1 -1
- package/lib/generated/recorderSource.js +1 -1
- package/lib/generated/utilityScriptSource.js +1 -1
- package/lib/protocol/serializers.js +12 -11
- package/lib/protocol/validator.js +137 -55
- package/lib/server/bidi/bidiBrowser.js +296 -0
- package/lib/server/bidi/bidiConnection.js +206 -0
- package/lib/server/bidi/bidiExecutionContext.js +162 -0
- package/lib/server/bidi/bidiFirefox.js +110 -0
- package/lib/server/bidi/bidiInput.js +174 -0
- package/lib/server/bidi/bidiNetworkManager.js +304 -0
- package/lib/server/bidi/bidiPage.js +456 -0
- package/lib/server/bidi/third_party/bidiDeserializer.js +93 -0
- package/lib/server/bidi/third_party/bidiKeyboard.js +238 -0
- package/lib/server/bidi/third_party/bidiProtocol.js +139 -0
- package/lib/server/bidi/third_party/bidiSerializer.js +144 -0
- package/lib/server/browser.js +9 -1
- package/lib/server/browserContext.js +97 -22
- package/lib/server/browserType.js +27 -20
- package/lib/server/chromium/chromium.js +30 -15
- package/lib/server/chromium/chromiumSwitches.js +6 -3
- package/lib/server/chromium/crBrowser.js +11 -17
- package/lib/server/chromium/crConnection.js +2 -2
- package/lib/server/chromium/crDragDrop.js +28 -29
- package/lib/server/chromium/crNetworkManager.js +130 -84
- package/lib/server/chromium/crPage.js +34 -79
- package/lib/server/chromium/crProtocolHelper.js +3 -1
- package/lib/server/chromium/crServiceWorker.js +20 -23
- package/lib/server/chromium/videoRecorder.js +1 -1
- package/lib/server/clock.js +125 -0
- package/lib/server/codegen/csharp.js +299 -0
- package/lib/server/codegen/java.js +235 -0
- package/lib/server/codegen/javascript.js +223 -0
- package/lib/server/codegen/jsonl.js +47 -0
- package/lib/server/codegen/language.js +76 -0
- package/lib/server/codegen/languages.js +30 -0
- package/lib/server/codegen/python.js +265 -0
- package/lib/server/codegen/types.js +5 -0
- package/lib/server/debugController.js +3 -5
- package/lib/server/deviceDescriptors.js +9 -4
- package/lib/server/deviceDescriptorsSource.json +239 -119
- package/lib/server/dispatchers/androidDispatcher.js +1 -1
- package/lib/server/dispatchers/browserContextDispatcher.js +51 -7
- package/lib/server/dispatchers/dispatcher.js +36 -40
- package/lib/server/dispatchers/frameDispatcher.js +1 -2
- package/lib/server/dispatchers/jsHandleDispatcher.js +1 -1
- package/lib/server/dispatchers/jsonPipeDispatcher.js +4 -6
- package/lib/server/dispatchers/localUtilsDispatcher.js +19 -5
- package/lib/server/dispatchers/networkDispatchers.js +2 -2
- package/lib/server/dispatchers/pageDispatcher.js +5 -2
- package/lib/server/dispatchers/playwrightDispatcher.js +1 -0
- package/lib/server/dispatchers/writableStreamDispatcher.js +8 -5
- package/lib/server/dom.js +90 -53
- package/lib/server/electron/electron.js +21 -4
- package/lib/server/fetch.js +74 -25
- package/lib/server/fileUploadUtils.js +7 -3
- package/lib/server/firefox/ffBrowser.js +36 -25
- package/lib/server/firefox/ffConnection.js +2 -2
- package/lib/server/firefox/ffNetworkManager.js +6 -4
- package/lib/server/firefox/ffPage.js +22 -24
- package/lib/server/firefox/firefox.js +25 -6
- package/lib/server/frameSelectors.js +2 -2
- package/lib/server/frames.js +205 -159
- package/lib/server/har/harTracer.js +4 -12
- package/lib/server/helper.js +3 -3
- package/lib/server/index.js +18 -0
- package/lib/server/input.js +18 -8
- package/lib/server/instrumentation.js +0 -4
- package/lib/server/isomorphic/utilityScriptSerializers.js +19 -5
- package/lib/server/javascript.js +3 -2
- package/lib/server/launchApp.js +3 -2
- package/lib/server/network.js +14 -4
- package/lib/server/page.js +75 -46
- package/lib/server/playwright.js +5 -2
- package/lib/server/recorder/codeGenerator.js +2 -1
- package/lib/server/recorder/contextRecorder.js +316 -0
- package/lib/server/recorder/csharp.js +2 -1
- package/lib/server/recorder/java.js +2 -1
- package/lib/server/recorder/javascript.js +2 -1
- package/lib/server/recorder/jsonl.js +2 -1
- package/lib/server/recorder/language.js +2 -1
- package/lib/server/recorder/python.js +2 -1
- package/lib/server/recorder/recorderApp.js +14 -5
- package/lib/server/recorder/recorderCollection.js +127 -0
- package/lib/server/recorder/recorderRunner.js +177 -0
- package/lib/server/recorder/recorderUtils.js +23 -0
- package/lib/server/recorder/throttledFile.js +46 -0
- package/lib/server/recorder/utils.js +2 -1
- package/lib/server/recorder.js +42 -418
- package/lib/server/registry/index.js +99 -100
- package/lib/server/registry/nativeDeps.js +107 -0
- package/lib/server/screenshotter.js +6 -12
- package/lib/server/socksClientCertificatesInterceptor.js +328 -0
- package/lib/server/trace/recorder/snapshotter.js +4 -1
- package/lib/server/trace/recorder/tracing.js +27 -96
- package/lib/server/trace/viewer/traceViewer.js +54 -67
- package/lib/server/transport.js +1 -1
- package/lib/server/webkit/webkit.js +5 -5
- package/lib/server/webkit/wkBrowser.js +14 -14
- package/lib/server/webkit/wkConnection.js +3 -3
- package/lib/server/webkit/wkInterceptableRequest.js +8 -4
- package/lib/server/webkit/wkPage.js +52 -34
- package/lib/server/webkit/wkProvisionalPage.js +36 -1
- package/lib/utils/crypto.js +141 -0
- package/lib/utils/debugLogger.js +2 -0
- package/lib/utils/env.js +4 -2
- package/lib/utils/expectUtils.js +33 -0
- package/lib/utils/fileUtils.js +140 -1
- package/lib/utils/glob.js +2 -1
- package/lib/utils/happy-eyeballs.js +29 -2
- package/lib/utils/hostPlatform.js +13 -4
- package/lib/utils/httpServer.js +54 -13
- package/lib/utils/index.js +53 -31
- package/lib/utils/isomorphic/cssTokenizer.js +1 -1
- package/lib/utils/isomorphic/locatorParser.js +1 -1
- package/lib/utils/isomorphic/mimeType.js +29 -0
- package/lib/utils/isomorphic/stringUtils.js +28 -1
- package/lib/utils/isomorphic/urlMatch.js +120 -0
- package/lib/utils/mimeType.js +2 -1
- package/lib/utils/network.js +7 -35
- package/lib/utils/stackTrace.js +2 -4
- package/lib/utils/timeoutRunner.js +11 -76
- package/lib/utils/zones.js +23 -60
- package/lib/utilsBundle.js +2 -1
- package/lib/utilsBundleImpl/index.js +33 -31
- package/lib/vite/htmlReport/index.html +12 -12
- package/lib/vite/recorder/assets/codeMirrorModule-C-fQ5QZD.js +24 -0
- package/lib/vite/recorder/assets/{codicon-zGuYmc9o.ttf → codicon-DCmgc-ay.ttf} +0 -0
- package/lib/vite/recorder/assets/index-B-MT5gKo.css +1 -0
- package/lib/vite/recorder/assets/index-D-5S5PPN.js +47 -0
- package/lib/vite/recorder/index.html +2 -2
- package/lib/vite/traceViewer/assets/codeMirrorModule-5yiV-3wl.js +16831 -0
- package/lib/vite/traceViewer/assets/codeMirrorModule-B7Z3vq11.js +24 -0
- package/lib/vite/traceViewer/assets/codeMirrorModule-C6p3E9Zg.js +24 -0
- package/lib/vite/traceViewer/assets/codeMirrorModule-CqYUz5ms.js +24 -0
- package/lib/vite/traceViewer/assets/codeMirrorModule-Dx6AXgMV.js +16838 -0
- package/lib/vite/traceViewer/assets/codeMirrorModule-T_sdMrbM.js +24 -0
- package/lib/vite/traceViewer/assets/codeMirrorModule-V7N6ppkd.js +15585 -0
- package/lib/vite/traceViewer/assets/testServerConnection-D-tXL3sj.js +224 -0
- package/lib/vite/traceViewer/assets/testServerConnection-DeE2kSzz.js +1 -0
- package/lib/vite/traceViewer/assets/workbench-Bjkiwcr1.js +19119 -0
- package/lib/vite/traceViewer/assets/workbench-C43LWZEX.js +72 -0
- package/lib/vite/traceViewer/assets/workbench-C5OQh9VX.js +19119 -0
- package/lib/vite/traceViewer/assets/workbench-DrQjKdyE.js +72 -0
- package/lib/vite/traceViewer/assets/workbench-caTaZnzx.js +72 -0
- package/lib/vite/traceViewer/assets/workbench-u2lRPMOT.js +72 -0
- package/lib/vite/traceViewer/assets/wsPort-EUvw-dwH.js +18540 -0
- package/lib/vite/traceViewer/assets/xtermModule-CZ7sDYXB.js +6529 -0
- package/lib/vite/traceViewer/assets/xtermModule-_6TC5FYT.js +6529 -0
- package/lib/vite/traceViewer/codeMirrorModule.Cy8X9Wtw.css +344 -0
- package/lib/vite/traceViewer/codeMirrorModule.svF_VrcJ.css +344 -0
- package/lib/vite/traceViewer/codicon.DCmgc-ay.ttf +0 -0
- package/lib/vite/traceViewer/embedded.BQq6Psnz.js +104 -0
- package/lib/vite/traceViewer/embedded.BVDVQOzc.js +2 -0
- package/lib/vite/traceViewer/embedded.Bn8Ptzv6.js +2 -0
- package/lib/vite/traceViewer/embedded.CvhnUgIi.js +2 -0
- package/lib/vite/traceViewer/embedded.D27cnKiB.js +104 -0
- package/lib/vite/traceViewer/embedded.DPqrDeET.js +2 -0
- package/lib/vite/traceViewer/embedded.DjZq4InJ.css +68 -0
- package/lib/vite/traceViewer/embedded.html +16 -0
- package/lib/vite/traceViewer/embedded.w7WN2u1R.css +1 -0
- package/lib/vite/traceViewer/index.5mge2rY_.css +124 -0
- package/lib/vite/traceViewer/index.6KJ-JQ0L.js +180 -0
- package/lib/vite/traceViewer/index.B8dgQwuN.js +2 -0
- package/lib/vite/traceViewer/index.BGj8jY3H.js +2 -0
- package/lib/vite/traceViewer/index.C0EgJ4oW.js +195 -0
- package/lib/vite/traceViewer/index.CUpI-BFe.js +195 -0
- package/lib/vite/traceViewer/{index.-g_5lMbJ.css → index.CrbWWHbf.css} +1 -1
- package/lib/vite/traceViewer/index.QanXxRUb.css +131 -0
- package/lib/vite/traceViewer/index._cX8k4co.js +2 -0
- package/lib/vite/traceViewer/index.html +5 -4
- package/lib/vite/traceViewer/index.pMAN88y-.js +2 -0
- package/lib/vite/traceViewer/snapshot.html +1 -1
- package/lib/vite/traceViewer/sw.bundle.js +3 -4
- package/lib/vite/traceViewer/uiMode.D-tg1Oci.js +1730 -0
- package/lib/vite/traceViewer/uiMode.D3cNFP6u.css +1 -0
- package/lib/vite/traceViewer/uiMode.DKjMBMlc.js +1730 -0
- package/lib/vite/traceViewer/uiMode.DVWUEIHq.css +1424 -0
- package/lib/vite/traceViewer/uiMode.DVrL7a1K.js +10 -0
- package/lib/vite/traceViewer/uiMode.Dg9oJCQU.js +10 -0
- package/lib/vite/traceViewer/uiMode.DwZAzstF.js +10 -0
- package/lib/vite/traceViewer/uiMode.html +5 -4
- package/lib/vite/traceViewer/uiMode.iq7CyYy7.js +1490 -0
- package/lib/vite/traceViewer/uiMode.jY2s-9ps.js +10 -0
- package/lib/vite/traceViewer/uiMode.xvJHbkzl.css +1324 -0
- package/lib/vite/traceViewer/workbench.B3X2QtYa.css +3702 -0
- package/lib/vite/traceViewer/workbench.DyTpxWVb.css +1 -0
- package/lib/vite/traceViewer/wsPort.p5jUwABW.css +3450 -0
- package/lib/vite/traceViewer/xtermModule.4oRVGWQ-.css +209 -0
- package/lib/vite/traceViewer/xtermModule.OKEVRlkP.css +209 -0
- package/package.json +2 -2
- package/types/protocol.d.ts +960 -78
- package/types/structs.d.ts +1 -1
- package/types/types.d.ts +3083 -2448
- package/lib/vite/recorder/assets/codeMirrorModule-I9ks4y7D.js +0 -24
- package/lib/vite/recorder/assets/index-ljsTwXtJ.css +0 -1
- package/lib/vite/recorder/assets/index-yg8ypzl6.js +0 -47
- package/lib/vite/traceViewer/assets/codeMirrorModule-0bpaqixv.js +0 -24
- package/lib/vite/traceViewer/assets/wsPort-_JBDEilC.js +0 -69
- package/lib/vite/traceViewer/index.u51inEcm.js +0 -2
- package/lib/vite/traceViewer/uiMode.Fb0bNA4H.js +0 -10
- package/lib/vite/traceViewer/uiMode.pWy0Re7G.css +0 -1
- package/lib/vite/traceViewer/wsPort.zR1WIy9-.css +0 -1
- /package/lib/vite/recorder/assets/{codeMirrorModule-Hs9-1ZG4.css → codeMirrorModule-ez37Vkbh.css} +0 -0
- /package/lib/vite/traceViewer/assets/{xtermModule-Yt6xwiJ_.js → xtermModule-BeNbaIVa.js} +0 -0
- /package/lib/vite/traceViewer/{codeMirrorModule.Hs9-1ZG4.css → codeMirrorModule.ez37Vkbh.css} +0 -0
- /package/lib/vite/traceViewer/{xtermModule.0lwXJFHT.css → xtermModule.DSXBckUd.css} +0 -0
|
@@ -0,0 +1,328 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
|
|
3
|
+
Object.defineProperty(exports, "__esModule", {
|
|
4
|
+
value: true
|
|
5
|
+
});
|
|
6
|
+
exports.ClientCertificatesProxy = void 0;
|
|
7
|
+
exports.getMatchingTLSOptionsForOrigin = getMatchingTLSOptionsForOrigin;
|
|
8
|
+
exports.rewriteOpenSSLErrorIfNeeded = rewriteOpenSSLErrorIfNeeded;
|
|
9
|
+
var _net = _interopRequireDefault(require("net"));
|
|
10
|
+
var _http = _interopRequireDefault(require("http2"));
|
|
11
|
+
var _tls = _interopRequireDefault(require("tls"));
|
|
12
|
+
var _stream = _interopRequireDefault(require("stream"));
|
|
13
|
+
var _happyEyeballs = require("../utils/happy-eyeballs");
|
|
14
|
+
var _utils = require("../utils");
|
|
15
|
+
var _socksProxy = require("../common/socksProxy");
|
|
16
|
+
var _debugLogger = require("../utils/debugLogger");
|
|
17
|
+
function _interopRequireDefault(obj) { return obj && obj.__esModule ? obj : { default: obj }; }
|
|
18
|
+
/**
|
|
19
|
+
* Copyright (c) Microsoft Corporation.
|
|
20
|
+
*
|
|
21
|
+
* Licensed under the Apache License, Version 2.0 (the 'License");
|
|
22
|
+
* you may not use this file except in compliance with the License.
|
|
23
|
+
* You may obtain a copy of the License at
|
|
24
|
+
*
|
|
25
|
+
* http://www.apache.org/licenses/LICENSE-2.0
|
|
26
|
+
*
|
|
27
|
+
* Unless required by applicable law or agreed to in writing, software
|
|
28
|
+
* distributed under the License is distributed on an "AS IS" BASIS,
|
|
29
|
+
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
|
30
|
+
* See the License for the specific language governing permissions and
|
|
31
|
+
* limitations under the License.
|
|
32
|
+
*/
|
|
33
|
+
|
|
34
|
+
let dummyServerTlsOptions = undefined;
|
|
35
|
+
function loadDummyServerCertsIfNeeded() {
|
|
36
|
+
if (dummyServerTlsOptions) return;
|
|
37
|
+
const {
|
|
38
|
+
cert,
|
|
39
|
+
key
|
|
40
|
+
} = (0, _utils.generateSelfSignedCertificate)();
|
|
41
|
+
dummyServerTlsOptions = {
|
|
42
|
+
key,
|
|
43
|
+
cert
|
|
44
|
+
};
|
|
45
|
+
}
|
|
46
|
+
class ALPNCache {
|
|
47
|
+
constructor() {
|
|
48
|
+
this._cache = new Map();
|
|
49
|
+
}
|
|
50
|
+
get(host, port, success) {
|
|
51
|
+
const cacheKey = `${host}:${port}`;
|
|
52
|
+
{
|
|
53
|
+
const result = this._cache.get(cacheKey);
|
|
54
|
+
if (result) {
|
|
55
|
+
result.then(success);
|
|
56
|
+
return;
|
|
57
|
+
}
|
|
58
|
+
}
|
|
59
|
+
const result = new _utils.ManualPromise();
|
|
60
|
+
this._cache.set(cacheKey, result);
|
|
61
|
+
result.then(success);
|
|
62
|
+
(0, _happyEyeballs.createTLSSocket)({
|
|
63
|
+
host,
|
|
64
|
+
port,
|
|
65
|
+
servername: _net.default.isIP(host) ? undefined : host,
|
|
66
|
+
ALPNProtocols: ['h2', 'http/1.1'],
|
|
67
|
+
rejectUnauthorized: false
|
|
68
|
+
}).then(socket => {
|
|
69
|
+
// The server may not respond with ALPN, in which case we default to http/1.1.
|
|
70
|
+
result.resolve(socket.alpnProtocol || 'http/1.1');
|
|
71
|
+
socket.end();
|
|
72
|
+
}).catch(error => {
|
|
73
|
+
_debugLogger.debugLogger.log('client-certificates', `ALPN error: ${error.message}`);
|
|
74
|
+
result.resolve('http/1.1');
|
|
75
|
+
});
|
|
76
|
+
}
|
|
77
|
+
}
|
|
78
|
+
class SocksProxyConnection {
|
|
79
|
+
constructor(socksProxy, uid, host, port) {
|
|
80
|
+
this.socksProxy = void 0;
|
|
81
|
+
this.uid = void 0;
|
|
82
|
+
this.host = void 0;
|
|
83
|
+
this.port = void 0;
|
|
84
|
+
this.firstPackageReceived = false;
|
|
85
|
+
this.target = void 0;
|
|
86
|
+
// In case of http, we just pipe data to the target socket and they are |undefined|.
|
|
87
|
+
this.internal = void 0;
|
|
88
|
+
this.internalTLS = void 0;
|
|
89
|
+
this._targetCloseEventListener = void 0;
|
|
90
|
+
this._dummyServer = void 0;
|
|
91
|
+
this._closed = false;
|
|
92
|
+
this.socksProxy = socksProxy;
|
|
93
|
+
this.uid = uid;
|
|
94
|
+
this.host = host;
|
|
95
|
+
this.port = port;
|
|
96
|
+
this._targetCloseEventListener = () => {
|
|
97
|
+
var _this$internalTLS, _this$_dummyServer;
|
|
98
|
+
// Close the other end and cleanup TLS resources.
|
|
99
|
+
this.socksProxy._socksProxy.sendSocketEnd({
|
|
100
|
+
uid: this.uid
|
|
101
|
+
});
|
|
102
|
+
(_this$internalTLS = this.internalTLS) === null || _this$internalTLS === void 0 || _this$internalTLS.destroy();
|
|
103
|
+
(_this$_dummyServer = this._dummyServer) === null || _this$_dummyServer === void 0 || _this$_dummyServer.close();
|
|
104
|
+
};
|
|
105
|
+
}
|
|
106
|
+
async connect() {
|
|
107
|
+
this.target = await (0, _happyEyeballs.createSocket)(rewriteToLocalhostIfNeeded(this.host), this.port);
|
|
108
|
+
this.target.once('close', this._targetCloseEventListener);
|
|
109
|
+
this.target.once('error', error => this.socksProxy._socksProxy.sendSocketError({
|
|
110
|
+
uid: this.uid,
|
|
111
|
+
error: error.message
|
|
112
|
+
}));
|
|
113
|
+
if (this._closed) {
|
|
114
|
+
this.target.destroy();
|
|
115
|
+
return;
|
|
116
|
+
}
|
|
117
|
+
this.socksProxy._socksProxy.socketConnected({
|
|
118
|
+
uid: this.uid,
|
|
119
|
+
host: this.target.localAddress,
|
|
120
|
+
port: this.target.localPort
|
|
121
|
+
});
|
|
122
|
+
}
|
|
123
|
+
onClose() {
|
|
124
|
+
var _this$internalTLS2, _this$_dummyServer2;
|
|
125
|
+
// Close the other end and cleanup TLS resources.
|
|
126
|
+
this.target.destroy();
|
|
127
|
+
(_this$internalTLS2 = this.internalTLS) === null || _this$internalTLS2 === void 0 || _this$internalTLS2.destroy();
|
|
128
|
+
(_this$_dummyServer2 = this._dummyServer) === null || _this$_dummyServer2 === void 0 || _this$_dummyServer2.close();
|
|
129
|
+
this._closed = true;
|
|
130
|
+
}
|
|
131
|
+
onData(data) {
|
|
132
|
+
// HTTP / TLS are client-hello based protocols. This allows us to detect
|
|
133
|
+
// the protocol on the first package and attach appropriate listeners.
|
|
134
|
+
if (!this.firstPackageReceived) {
|
|
135
|
+
this.firstPackageReceived = true;
|
|
136
|
+
// 0x16 is SSLv3/TLS "handshake" content type: https://en.wikipedia.org/wiki/Transport_Layer_Security#TLS_record
|
|
137
|
+
if (data[0] === 0x16) this._attachTLSListeners();else this.target.on('data', data => this.socksProxy._socksProxy.sendSocketData({
|
|
138
|
+
uid: this.uid,
|
|
139
|
+
data
|
|
140
|
+
}));
|
|
141
|
+
}
|
|
142
|
+
if (this.internal) this.internal.push(data);else this.target.write(data);
|
|
143
|
+
}
|
|
144
|
+
_attachTLSListeners() {
|
|
145
|
+
this.internal = new _stream.default.Duplex({
|
|
146
|
+
read: () => {},
|
|
147
|
+
write: (data, encoding, callback) => {
|
|
148
|
+
this.socksProxy._socksProxy.sendSocketData({
|
|
149
|
+
uid: this.uid,
|
|
150
|
+
data
|
|
151
|
+
});
|
|
152
|
+
callback();
|
|
153
|
+
}
|
|
154
|
+
});
|
|
155
|
+
this.socksProxy.alpnCache.get(rewriteToLocalhostIfNeeded(this.host), this.port, alpnProtocolChosenByServer => {
|
|
156
|
+
_debugLogger.debugLogger.log('client-certificates', `Proxy->Target ${this.host}:${this.port} chooses ALPN ${alpnProtocolChosenByServer}`);
|
|
157
|
+
if (this._closed) return;
|
|
158
|
+
this._dummyServer = _tls.default.createServer({
|
|
159
|
+
...dummyServerTlsOptions,
|
|
160
|
+
ALPNProtocols: alpnProtocolChosenByServer === 'h2' ? ['h2', 'http/1.1'] : ['http/1.1']
|
|
161
|
+
});
|
|
162
|
+
this._dummyServer.emit('connection', this.internal);
|
|
163
|
+
this._dummyServer.once('secureConnection', internalTLS => {
|
|
164
|
+
this.internalTLS = internalTLS;
|
|
165
|
+
_debugLogger.debugLogger.log('client-certificates', `Browser->Proxy ${this.host}:${this.port} chooses ALPN ${internalTLS.alpnProtocol}`);
|
|
166
|
+
let targetTLS = undefined;
|
|
167
|
+
const handleError = error => {
|
|
168
|
+
_debugLogger.debugLogger.log('client-certificates', `error when connecting to target: ${error.message.replaceAll('\n', ' ')}`);
|
|
169
|
+
const responseBody = (0, _utils.escapeHTML)('Playwright client-certificate error: ' + error.message).replaceAll('\n', ' <br>');
|
|
170
|
+
if ((internalTLS === null || internalTLS === void 0 ? void 0 : internalTLS.alpnProtocol) === 'h2') {
|
|
171
|
+
// This method is available only in Node.js 20+
|
|
172
|
+
if ('performServerHandshake' in _http.default) {
|
|
173
|
+
// In case of an 'error' event on the target connection, we still need to perform the http2 handshake on the browser side.
|
|
174
|
+
// This is an async operation, so we need to remove the listener to prevent the socket from being closed too early.
|
|
175
|
+
// This means we call this._targetCloseEventListener manually.
|
|
176
|
+
this.target.removeListener('close', this._targetCloseEventListener);
|
|
177
|
+
// @ts-expect-error
|
|
178
|
+
const session = _http.default.performServerHandshake(internalTLS);
|
|
179
|
+
session.on('error', () => {
|
|
180
|
+
this.target.destroy();
|
|
181
|
+
this._targetCloseEventListener();
|
|
182
|
+
});
|
|
183
|
+
session.once('stream', stream => {
|
|
184
|
+
stream.respond({
|
|
185
|
+
'content-type': 'text/html',
|
|
186
|
+
[_http.default.constants.HTTP2_HEADER_STATUS]: 503
|
|
187
|
+
});
|
|
188
|
+
const cleanup = () => {
|
|
189
|
+
session.close();
|
|
190
|
+
this.target.destroy();
|
|
191
|
+
this._targetCloseEventListener();
|
|
192
|
+
};
|
|
193
|
+
stream.end(responseBody, cleanup);
|
|
194
|
+
stream.once('error', cleanup);
|
|
195
|
+
});
|
|
196
|
+
} else {
|
|
197
|
+
this.target.destroy();
|
|
198
|
+
}
|
|
199
|
+
} else {
|
|
200
|
+
internalTLS.end(['HTTP/1.1 503 Internal Server Error', 'Content-Type: text/html; charset=utf-8', 'Content-Length: ' + Buffer.byteLength(responseBody), '', responseBody].join('\r\n'));
|
|
201
|
+
this.target.destroy();
|
|
202
|
+
}
|
|
203
|
+
};
|
|
204
|
+
if (this._closed) {
|
|
205
|
+
internalTLS.destroy();
|
|
206
|
+
return;
|
|
207
|
+
}
|
|
208
|
+
targetTLS = _tls.default.connect({
|
|
209
|
+
socket: this.target,
|
|
210
|
+
host: this.host,
|
|
211
|
+
port: this.port,
|
|
212
|
+
rejectUnauthorized: !this.socksProxy.ignoreHTTPSErrors,
|
|
213
|
+
ALPNProtocols: [internalTLS.alpnProtocol || 'http/1.1'],
|
|
214
|
+
servername: !_net.default.isIP(this.host) ? this.host : undefined,
|
|
215
|
+
secureContext: this.socksProxy.secureContextMap.get(new URL(`https://${this.host}:${this.port}`).origin)
|
|
216
|
+
});
|
|
217
|
+
targetTLS.once('secureConnect', () => {
|
|
218
|
+
internalTLS.pipe(targetTLS);
|
|
219
|
+
targetTLS.pipe(internalTLS);
|
|
220
|
+
});
|
|
221
|
+
internalTLS.once('error', () => this.target.destroy());
|
|
222
|
+
targetTLS.once('error', handleError);
|
|
223
|
+
});
|
|
224
|
+
});
|
|
225
|
+
}
|
|
226
|
+
}
|
|
227
|
+
class ClientCertificatesProxy {
|
|
228
|
+
constructor(contextOptions) {
|
|
229
|
+
this._socksProxy = void 0;
|
|
230
|
+
this._connections = new Map();
|
|
231
|
+
this.ignoreHTTPSErrors = void 0;
|
|
232
|
+
this.secureContextMap = new Map();
|
|
233
|
+
this.alpnCache = void 0;
|
|
234
|
+
this.alpnCache = new ALPNCache();
|
|
235
|
+
this.ignoreHTTPSErrors = contextOptions.ignoreHTTPSErrors;
|
|
236
|
+
this._initSecureContexts(contextOptions.clientCertificates);
|
|
237
|
+
this._socksProxy = new _socksProxy.SocksProxy();
|
|
238
|
+
this._socksProxy.setPattern('*');
|
|
239
|
+
this._socksProxy.addListener(_socksProxy.SocksProxy.Events.SocksRequested, async payload => {
|
|
240
|
+
try {
|
|
241
|
+
const connection = new SocksProxyConnection(this, payload.uid, payload.host, payload.port);
|
|
242
|
+
await connection.connect();
|
|
243
|
+
this._connections.set(payload.uid, connection);
|
|
244
|
+
} catch (error) {
|
|
245
|
+
this._socksProxy.socketFailed({
|
|
246
|
+
uid: payload.uid,
|
|
247
|
+
errorCode: error.code
|
|
248
|
+
});
|
|
249
|
+
}
|
|
250
|
+
});
|
|
251
|
+
this._socksProxy.addListener(_socksProxy.SocksProxy.Events.SocksData, async payload => {
|
|
252
|
+
var _this$_connections$ge;
|
|
253
|
+
(_this$_connections$ge = this._connections.get(payload.uid)) === null || _this$_connections$ge === void 0 || _this$_connections$ge.onData(payload.data);
|
|
254
|
+
});
|
|
255
|
+
this._socksProxy.addListener(_socksProxy.SocksProxy.Events.SocksClosed, payload => {
|
|
256
|
+
var _this$_connections$ge2;
|
|
257
|
+
(_this$_connections$ge2 = this._connections.get(payload.uid)) === null || _this$_connections$ge2 === void 0 || _this$_connections$ge2.onClose();
|
|
258
|
+
this._connections.delete(payload.uid);
|
|
259
|
+
});
|
|
260
|
+
loadDummyServerCertsIfNeeded();
|
|
261
|
+
}
|
|
262
|
+
_initSecureContexts(clientCertificates) {
|
|
263
|
+
// Step 1. Group certificates by origin.
|
|
264
|
+
const origin2certs = new Map();
|
|
265
|
+
for (const cert of clientCertificates || []) {
|
|
266
|
+
const origin = normalizeOrigin(cert.origin);
|
|
267
|
+
const certs = origin2certs.get(origin) || [];
|
|
268
|
+
certs.push(cert);
|
|
269
|
+
origin2certs.set(origin, certs);
|
|
270
|
+
}
|
|
271
|
+
|
|
272
|
+
// Step 2. Create secure contexts for each origin.
|
|
273
|
+
for (const [origin, certs] of origin2certs) {
|
|
274
|
+
try {
|
|
275
|
+
this.secureContextMap.set(origin, _tls.default.createSecureContext(convertClientCertificatesToTLSOptions(certs)));
|
|
276
|
+
} catch (error) {
|
|
277
|
+
error = rewriteOpenSSLErrorIfNeeded(error);
|
|
278
|
+
throw (0, _utils.rewriteErrorMessage)(error, `Failed to load client certificate: ${error.message}`);
|
|
279
|
+
}
|
|
280
|
+
}
|
|
281
|
+
}
|
|
282
|
+
async listen() {
|
|
283
|
+
const port = await this._socksProxy.listen(0, '127.0.0.1');
|
|
284
|
+
return `socks5://127.0.0.1:${port}`;
|
|
285
|
+
}
|
|
286
|
+
async close() {
|
|
287
|
+
await this._socksProxy.close();
|
|
288
|
+
}
|
|
289
|
+
}
|
|
290
|
+
exports.ClientCertificatesProxy = ClientCertificatesProxy;
|
|
291
|
+
function normalizeOrigin(origin) {
|
|
292
|
+
try {
|
|
293
|
+
return new URL(origin).origin;
|
|
294
|
+
} catch (error) {
|
|
295
|
+
return origin;
|
|
296
|
+
}
|
|
297
|
+
}
|
|
298
|
+
function convertClientCertificatesToTLSOptions(clientCertificates) {
|
|
299
|
+
if (!clientCertificates || !clientCertificates.length) return;
|
|
300
|
+
const tlsOptions = {
|
|
301
|
+
pfx: [],
|
|
302
|
+
key: [],
|
|
303
|
+
cert: []
|
|
304
|
+
};
|
|
305
|
+
for (const cert of clientCertificates) {
|
|
306
|
+
if (cert.cert) tlsOptions.cert.push(cert.cert);
|
|
307
|
+
if (cert.key) tlsOptions.key.push({
|
|
308
|
+
pem: cert.key,
|
|
309
|
+
passphrase: cert.passphrase
|
|
310
|
+
});
|
|
311
|
+
if (cert.pfx) tlsOptions.pfx.push({
|
|
312
|
+
buf: cert.pfx,
|
|
313
|
+
passphrase: cert.passphrase
|
|
314
|
+
});
|
|
315
|
+
}
|
|
316
|
+
return tlsOptions;
|
|
317
|
+
}
|
|
318
|
+
function getMatchingTLSOptionsForOrigin(clientCertificates, origin) {
|
|
319
|
+
const matchingCerts = clientCertificates === null || clientCertificates === void 0 ? void 0 : clientCertificates.filter(c => normalizeOrigin(c.origin) === origin);
|
|
320
|
+
return convertClientCertificatesToTLSOptions(matchingCerts);
|
|
321
|
+
}
|
|
322
|
+
function rewriteToLocalhostIfNeeded(host) {
|
|
323
|
+
return host === 'local.playwright' ? 'localhost' : host;
|
|
324
|
+
}
|
|
325
|
+
function rewriteOpenSSLErrorIfNeeded(error) {
|
|
326
|
+
if (error.message !== 'unsupported') return error;
|
|
327
|
+
return (0, _utils.rewriteErrorMessage)(error, ['Unsupported TLS certificate.', 'Most likely, the security algorithm of the given certificate was deprecated by OpenSSL.', 'For more details, see https://github.com/openssl/openssl/blob/master/README-PROVIDERS.md#the-legacy-provider', 'You could probably modernize the certificate by following the steps at https://github.com/nodejs/node/issues/40672#issuecomment-1243648223'].join('\n'));
|
|
328
|
+
}
|
|
@@ -64,7 +64,10 @@ class Snapshotter {
|
|
|
64
64
|
async _initialize() {
|
|
65
65
|
for (const page of this._context.pages()) this._onPage(page);
|
|
66
66
|
this._eventListeners = [_eventsHelper.eventsHelper.addEventListener(this._context, _browserContext.BrowserContext.Events.Page, this._onPage.bind(this))];
|
|
67
|
-
const
|
|
67
|
+
const {
|
|
68
|
+
javaScriptEnabled
|
|
69
|
+
} = this._context._options;
|
|
70
|
+
const initScript = `(${_snapshotterInjected.frameSnapshotStreamer})("${this._snapshotStreamer}", ${javaScriptEnabled || javaScriptEnabled === undefined})`;
|
|
68
71
|
await this._context.addInitScript(initScript);
|
|
69
72
|
await this._runInAllFrames(initScript);
|
|
70
73
|
}
|
|
@@ -9,18 +9,15 @@ var _fs = _interopRequireDefault(require("fs"));
|
|
|
9
9
|
var _os = _interopRequireDefault(require("os"));
|
|
10
10
|
var _path = _interopRequireDefault(require("path"));
|
|
11
11
|
var _debug = require("../../../protocol/debug");
|
|
12
|
-
var _manualPromise = require("../../../utils/manualPromise");
|
|
13
|
-
var _eventsHelper = require("../../../utils/eventsHelper");
|
|
14
12
|
var _utils = require("../../../utils");
|
|
15
|
-
var _fileUtils = require("../../../utils/fileUtils");
|
|
16
13
|
var _artifact = require("../../artifact");
|
|
17
14
|
var _browserContext = require("../../browserContext");
|
|
18
15
|
var _instrumentation = require("../../instrumentation");
|
|
19
16
|
var _page = require("../../page");
|
|
20
17
|
var _harTracer = require("../../har/harTracer");
|
|
21
18
|
var _snapshotter = require("./snapshotter");
|
|
22
|
-
var _zipBundle = require("../../../zipBundle");
|
|
23
19
|
var _dispatcher = require("../../dispatchers/dispatcher");
|
|
20
|
+
var _errors = require("../../errors");
|
|
24
21
|
function _interopRequireDefault(obj) { return obj && obj.__esModule ? obj : { default: obj }; }
|
|
25
22
|
/**
|
|
26
23
|
* Copyright (c) Microsoft Corporation.
|
|
@@ -38,7 +35,7 @@ function _interopRequireDefault(obj) { return obj && obj.__esModule ? obj : { de
|
|
|
38
35
|
* limitations under the License.
|
|
39
36
|
*/
|
|
40
37
|
|
|
41
|
-
const version =
|
|
38
|
+
const version = 7;
|
|
42
39
|
const kScreencastOptions = {
|
|
43
40
|
width: 800,
|
|
44
41
|
height: 600,
|
|
@@ -47,7 +44,7 @@ const kScreencastOptions = {
|
|
|
47
44
|
class Tracing extends _instrumentation.SdkObject {
|
|
48
45
|
constructor(context, tracesDir) {
|
|
49
46
|
super(context, 'tracing');
|
|
50
|
-
this._fs = new SerializedFS();
|
|
47
|
+
this._fs = new _utils.SerializedFS();
|
|
51
48
|
this._snapshotter = void 0;
|
|
52
49
|
this._harTracer = void 0;
|
|
53
50
|
this._screencastListeners = [];
|
|
@@ -73,10 +70,12 @@ class Tracing extends _instrumentation.SdkObject {
|
|
|
73
70
|
this._contextCreatedEvent = {
|
|
74
71
|
version,
|
|
75
72
|
type: 'context-options',
|
|
73
|
+
origin: 'library',
|
|
76
74
|
browserName: '',
|
|
77
75
|
options: {},
|
|
78
76
|
platform: process.platform,
|
|
79
77
|
wallTime: 0,
|
|
78
|
+
monotonicTime: 0,
|
|
80
79
|
sdkLanguage: context.attribution.playwright.options.sdkLanguage,
|
|
81
80
|
testIdAttributeName
|
|
82
81
|
};
|
|
@@ -144,11 +143,12 @@ class Tracing extends _instrumentation.SdkObject {
|
|
|
144
143
|
const event = {
|
|
145
144
|
...this._contextCreatedEvent,
|
|
146
145
|
title: options.title,
|
|
147
|
-
wallTime: Date.now()
|
|
146
|
+
wallTime: Date.now(),
|
|
147
|
+
monotonicTime: (0, _utils.monotonicTime)()
|
|
148
148
|
};
|
|
149
149
|
this._fs.appendFile(this._state.traceFile, JSON.stringify(event) + '\n');
|
|
150
150
|
this._context.instrumentation.addListener(this, this._context);
|
|
151
|
-
this._eventListeners.push(
|
|
151
|
+
this._eventListeners.push(_utils.eventsHelper.addEventListener(this._context, _browserContext.BrowserContext.Events.Console, this._onConsoleMessage.bind(this)), _utils.eventsHelper.addEventListener(this._context, _browserContext.BrowserContext.Events.PageError, this._onPageError.bind(this)));
|
|
152
152
|
if (this._state.options.screenshots) this._startScreencast();
|
|
153
153
|
if (this._state.options.snapshots) await ((_this$_snapshotter2 = this._snapshotter) === null || _this$_snapshotter2 === void 0 ? void 0 : _this$_snapshotter2.start());
|
|
154
154
|
return {
|
|
@@ -158,10 +158,10 @@ class Tracing extends _instrumentation.SdkObject {
|
|
|
158
158
|
_startScreencast() {
|
|
159
159
|
if (!(this._context instanceof _browserContext.BrowserContext)) return;
|
|
160
160
|
for (const page of this._context.pages()) this._startScreencastInPage(page);
|
|
161
|
-
this._screencastListeners.push(
|
|
161
|
+
this._screencastListeners.push(_utils.eventsHelper.addEventListener(this._context, _browserContext.BrowserContext.Events.Page, this._startScreencastInPage.bind(this)));
|
|
162
162
|
}
|
|
163
163
|
_stopScreencast() {
|
|
164
|
-
|
|
164
|
+
_utils.eventsHelper.removeEventListeners(this._screencastListeners);
|
|
165
165
|
if (!(this._context instanceof _browserContext.BrowserContext)) return;
|
|
166
166
|
for (const page of this._context.pages()) page.setScreencastOptions(null);
|
|
167
167
|
}
|
|
@@ -190,7 +190,7 @@ class Tracing extends _instrumentation.SdkObject {
|
|
|
190
190
|
this._state = undefined;
|
|
191
191
|
}
|
|
192
192
|
async deleteTmpTracesDir() {
|
|
193
|
-
if (this._tracesTmpDir) await (0,
|
|
193
|
+
if (this._tracesTmpDir) await (0, _utils.removeFolders)([this._tracesTmpDir]);
|
|
194
194
|
}
|
|
195
195
|
_createTracesDirIfNeeded() {
|
|
196
196
|
if (this._precreatedTracesDir) return this._precreatedTracesDir;
|
|
@@ -216,7 +216,7 @@ class Tracing extends _instrumentation.SdkObject {
|
|
|
216
216
|
return {};
|
|
217
217
|
}
|
|
218
218
|
this._context.instrumentation.removeListener(this);
|
|
219
|
-
|
|
219
|
+
_utils.eventsHelper.removeEventListeners(this._eventListeners);
|
|
220
220
|
if (this._state.options.screenshots) this._stopScreencast();
|
|
221
221
|
if (this._state.options.snapshots) await ((_this$_snapshotter4 = this._snapshotter) === null || _this$_snapshotter4 === void 0 ? void 0 : _this$_snapshotter4.stop());
|
|
222
222
|
this.flushHarEntries();
|
|
@@ -321,14 +321,6 @@ class Tracing extends _instrumentation.SdkObject {
|
|
|
321
321
|
this._appendTraceEvent(event);
|
|
322
322
|
return this._captureSnapshot(event.afterSnapshot, sdkObject, metadata);
|
|
323
323
|
}
|
|
324
|
-
onEvent(sdkObject, event) {
|
|
325
|
-
if (!sdkObject.attribution.context) return;
|
|
326
|
-
if (event.method === 'console' || event.method === '__create__' && event.class === 'ConsoleMessage' || event.method === '__create__' && event.class === 'JSHandle') {
|
|
327
|
-
// Console messages are handled separately.
|
|
328
|
-
return;
|
|
329
|
-
}
|
|
330
|
-
this._appendTraceEvent(event);
|
|
331
|
-
}
|
|
332
324
|
onEntryStarted(entry) {
|
|
333
325
|
this._pendingHarEntries.add(entry);
|
|
334
326
|
}
|
|
@@ -382,10 +374,23 @@ class Tracing extends _instrumentation.SdkObject {
|
|
|
382
374
|
};
|
|
383
375
|
this._appendTraceEvent(event);
|
|
384
376
|
}
|
|
377
|
+
_onPageError(error, page) {
|
|
378
|
+
const event = {
|
|
379
|
+
type: 'event',
|
|
380
|
+
time: (0, _utils.monotonicTime)(),
|
|
381
|
+
class: 'BrowserContext',
|
|
382
|
+
method: 'pageError',
|
|
383
|
+
params: {
|
|
384
|
+
error: (0, _errors.serializeError)(error)
|
|
385
|
+
},
|
|
386
|
+
pageId: page.guid
|
|
387
|
+
};
|
|
388
|
+
this._appendTraceEvent(event);
|
|
389
|
+
}
|
|
385
390
|
_startScreencastInPage(page) {
|
|
386
391
|
page.setScreencastOptions(kScreencastOptions);
|
|
387
392
|
const prefix = page.guid;
|
|
388
|
-
this._screencastListeners.push(
|
|
393
|
+
this._screencastListeners.push(_utils.eventsHelper.addEventListener(page, _page.Page.Events.ScreencastFrame, params => {
|
|
389
394
|
const suffix = params.timestamp || Date.now();
|
|
390
395
|
const sha1 = `${prefix}-${suffix}.jpeg`;
|
|
391
396
|
const event = {
|
|
@@ -446,7 +451,7 @@ function createBeforeActionTraceEvent(metadata) {
|
|
|
446
451
|
class: metadata.type,
|
|
447
452
|
method: metadata.method,
|
|
448
453
|
params: metadata.params,
|
|
449
|
-
|
|
454
|
+
stepId: metadata.stepId,
|
|
450
455
|
pageId: metadata.pageId
|
|
451
456
|
};
|
|
452
457
|
}
|
|
@@ -478,78 +483,4 @@ function createAfterActionTraceEvent(metadata) {
|
|
|
478
483
|
result: metadata.result,
|
|
479
484
|
point: metadata.point
|
|
480
485
|
};
|
|
481
|
-
}
|
|
482
|
-
class SerializedFS {
|
|
483
|
-
constructor() {
|
|
484
|
-
this._writeChain = Promise.resolve();
|
|
485
|
-
this._buffers = new Map();
|
|
486
|
-
// Should never be accessed from within appendOperation.
|
|
487
|
-
this._error = void 0;
|
|
488
|
-
}
|
|
489
|
-
mkdir(dir) {
|
|
490
|
-
this._appendOperation(() => _fs.default.promises.mkdir(dir, {
|
|
491
|
-
recursive: true
|
|
492
|
-
}));
|
|
493
|
-
}
|
|
494
|
-
writeFile(file, content, skipIfExists) {
|
|
495
|
-
this._buffers.delete(file); // No need to flush the buffer since we'll overwrite anyway.
|
|
496
|
-
|
|
497
|
-
// Note: 'wx' flag only writes when the file does not exist.
|
|
498
|
-
// See https://nodejs.org/api/fs.html#file-system-flags.
|
|
499
|
-
// This way tracing never have to write the same resource twice.
|
|
500
|
-
this._appendOperation(async () => {
|
|
501
|
-
if (skipIfExists) await _fs.default.promises.writeFile(file, content, {
|
|
502
|
-
flag: 'wx'
|
|
503
|
-
}).catch(() => {});else await _fs.default.promises.writeFile(file, content);
|
|
504
|
-
});
|
|
505
|
-
}
|
|
506
|
-
appendFile(file, text, flush) {
|
|
507
|
-
if (!this._buffers.has(file)) this._buffers.set(file, []);
|
|
508
|
-
this._buffers.get(file).push(text);
|
|
509
|
-
if (flush) this._flushFile(file);
|
|
510
|
-
}
|
|
511
|
-
_flushFile(file) {
|
|
512
|
-
const buffer = this._buffers.get(file);
|
|
513
|
-
if (buffer === undefined) return;
|
|
514
|
-
const text = buffer.join('');
|
|
515
|
-
this._buffers.delete(file);
|
|
516
|
-
this._appendOperation(() => _fs.default.promises.appendFile(file, text));
|
|
517
|
-
}
|
|
518
|
-
copyFile(from, to) {
|
|
519
|
-
this._flushFile(from);
|
|
520
|
-
this._buffers.delete(to); // No need to flush the buffer since we'll overwrite anyway.
|
|
521
|
-
this._appendOperation(() => _fs.default.promises.copyFile(from, to));
|
|
522
|
-
}
|
|
523
|
-
async syncAndGetError() {
|
|
524
|
-
for (const file of this._buffers.keys()) this._flushFile(file);
|
|
525
|
-
await this._writeChain;
|
|
526
|
-
return this._error;
|
|
527
|
-
}
|
|
528
|
-
zip(entries, zipFileName) {
|
|
529
|
-
for (const file of this._buffers.keys()) this._flushFile(file);
|
|
530
|
-
|
|
531
|
-
// Chain the export operation against write operations,
|
|
532
|
-
// so that files do not change during the export.
|
|
533
|
-
this._appendOperation(async () => {
|
|
534
|
-
const zipFile = new _zipBundle.yazl.ZipFile();
|
|
535
|
-
const result = new _manualPromise.ManualPromise();
|
|
536
|
-
zipFile.on('error', error => result.reject(error));
|
|
537
|
-
for (const entry of entries) zipFile.addFile(entry.value, entry.name);
|
|
538
|
-
zipFile.end();
|
|
539
|
-
zipFile.outputStream.pipe(_fs.default.createWriteStream(zipFileName)).on('close', () => result.resolve()).on('error', error => result.reject(error));
|
|
540
|
-
await result;
|
|
541
|
-
});
|
|
542
|
-
}
|
|
543
|
-
_appendOperation(cb) {
|
|
544
|
-
// This method serializes all writes to the trace.
|
|
545
|
-
this._writeChain = this._writeChain.then(async () => {
|
|
546
|
-
// Ignore all operations after the first error.
|
|
547
|
-
if (this._error) return;
|
|
548
|
-
try {
|
|
549
|
-
await cb();
|
|
550
|
-
} catch (e) {
|
|
551
|
-
this._error = e;
|
|
552
|
-
}
|
|
553
|
-
});
|
|
554
|
-
}
|
|
555
486
|
}
|