@percy/core 1.27.5-beta.0 → 1.27.5-beta.2
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/dist/config.js +7 -0
- package/dist/discovery.js +3 -1
- package/dist/network.js +66 -38
- package/dist/queue.js +10 -4
- package/dist/snapshot.js +2 -1
- package/dist/utils.js +20 -1
- package/package.json +8 -8
- package/types/index.d.ts +1 -0
package/dist/config.js
CHANGED
|
@@ -176,6 +176,10 @@ export const configSchema = {
|
|
|
176
176
|
disableCache: {
|
|
177
177
|
type: 'boolean'
|
|
178
178
|
},
|
|
179
|
+
captureMockedServiceWorker: {
|
|
180
|
+
type: 'boolean',
|
|
181
|
+
default: false
|
|
182
|
+
},
|
|
179
183
|
requestHeaders: {
|
|
180
184
|
type: 'object',
|
|
181
185
|
normalize: false,
|
|
@@ -311,6 +315,9 @@ export const snapshotSchema = {
|
|
|
311
315
|
disableCache: {
|
|
312
316
|
$ref: '/config/discovery#/properties/disableCache'
|
|
313
317
|
},
|
|
318
|
+
captureMockedServiceWorker: {
|
|
319
|
+
$ref: '/config/discovery#/properties/captureMockedServiceWorker'
|
|
320
|
+
},
|
|
314
321
|
userAgent: {
|
|
315
322
|
$ref: '/config/discovery#/properties/userAgent'
|
|
316
323
|
},
|
package/dist/discovery.js
CHANGED
|
@@ -42,6 +42,7 @@ function debugSnapshotOptions(snapshot) {
|
|
|
42
42
|
debugProp(snapshot, 'discovery.requestHeaders', JSON.stringify);
|
|
43
43
|
debugProp(snapshot, 'discovery.authorization', JSON.stringify);
|
|
44
44
|
debugProp(snapshot, 'discovery.disableCache');
|
|
45
|
+
debugProp(snapshot, 'discovery.captureMockedServiceWorker');
|
|
45
46
|
debugProp(snapshot, 'discovery.userAgent');
|
|
46
47
|
debugProp(snapshot, 'clientInfo');
|
|
47
48
|
debugProp(snapshot, 'environmentInfo');
|
|
@@ -279,7 +280,7 @@ export function createDiscoveryQueue(percy) {
|
|
|
279
280
|
let {
|
|
280
281
|
concurrency
|
|
281
282
|
} = percy.config.discovery;
|
|
282
|
-
let queue = new Queue();
|
|
283
|
+
let queue = new Queue('discovery');
|
|
283
284
|
let cache;
|
|
284
285
|
return queue.set({
|
|
285
286
|
concurrency
|
|
@@ -322,6 +323,7 @@ export function createDiscoveryQueue(percy) {
|
|
|
322
323
|
requestHeaders: snapshot.discovery.requestHeaders,
|
|
323
324
|
authorization: snapshot.discovery.authorization,
|
|
324
325
|
userAgent: snapshot.discovery.userAgent,
|
|
326
|
+
captureMockedServiceWorker: snapshot.discovery.captureMockedServiceWorker,
|
|
325
327
|
meta: snapshot.meta,
|
|
326
328
|
// enable network inteception
|
|
327
329
|
intercept: {
|
package/dist/network.js
CHANGED
|
@@ -1,20 +1,31 @@
|
|
|
1
1
|
import { request as makeRequest } from '@percy/client/utils';
|
|
2
2
|
import logger from '@percy/logger';
|
|
3
3
|
import mime from 'mime-types';
|
|
4
|
-
import { createResource, hostnameMatches, normalizeURL, waitFor } from './utils.js';
|
|
4
|
+
import { DefaultMap, createResource, hostnameMatches, normalizeURL, waitFor } from './utils.js';
|
|
5
5
|
const MAX_RESOURCE_SIZE = 25 * 1024 ** 2; // 25MB
|
|
6
6
|
const ALLOWED_STATUSES = [200, 201, 301, 302, 304, 307, 308];
|
|
7
7
|
const ALLOWED_RESOURCES = ['Document', 'Stylesheet', 'Image', 'Media', 'Font', 'Other'];
|
|
8
8
|
const ABORTED_MESSAGE = 'Request was aborted by browser';
|
|
9
9
|
|
|
10
|
+
// RequestLifeCycleHandler handles life cycle of a requestId
|
|
11
|
+
// Ideal flow: requestWillBeSent -> requestPaused -> responseReceived -> loadingFinished / loadingFailed
|
|
12
|
+
// ServiceWorker flow: requestWillBeSent -> responseReceived -> loadingFinished / loadingFailed
|
|
13
|
+
class RequestLifeCycleHandler {
|
|
14
|
+
constructor() {
|
|
15
|
+
this.resolveRequestWillBeSent = null;
|
|
16
|
+
this.resolveResponseReceived = null;
|
|
17
|
+
this.requestWillBeSent = new Promise(resolve => this.resolveRequestWillBeSent = resolve);
|
|
18
|
+
this.responseReceived = new Promise(resolve => this.resolveResponseReceived = resolve);
|
|
19
|
+
}
|
|
20
|
+
}
|
|
10
21
|
// The Interceptor class creates common handlers for dealing with intercepting asset requests
|
|
11
22
|
// for a given page using various devtools protocol events and commands.
|
|
12
23
|
export class Network {
|
|
13
24
|
static TIMEOUT = undefined;
|
|
14
25
|
log = logger('core:discovery');
|
|
26
|
+
#requestsLifeCycleHandler = new DefaultMap(() => new RequestLifeCycleHandler());
|
|
15
27
|
#pending = new Map();
|
|
16
28
|
#requests = new Map();
|
|
17
|
-
#intercepts = new Map();
|
|
18
29
|
#authentications = new Set();
|
|
19
30
|
#aborted = new Set();
|
|
20
31
|
constructor(page, options) {
|
|
@@ -22,6 +33,7 @@ export class Network {
|
|
|
22
33
|
this.timeout = options.networkIdleTimeout ?? 100;
|
|
23
34
|
this.authorization = options.authorization;
|
|
24
35
|
this.requestHeaders = options.requestHeaders ?? {};
|
|
36
|
+
this.captureMockedServiceWorker = options.captureMockedServiceWorker ?? false;
|
|
25
37
|
this.userAgent = options.userAgent ??
|
|
26
38
|
// by default, emulate a non-headless browser
|
|
27
39
|
page.session.browser.version.userAgent.replace('Headless', '');
|
|
@@ -36,7 +48,7 @@ export class Network {
|
|
|
36
48
|
session.on('Network.loadingFinished', this._handleLoadingFinished);
|
|
37
49
|
session.on('Network.loadingFailed', this._handleLoadingFailed);
|
|
38
50
|
let commands = [session.send('Network.enable'), session.send('Network.setBypassServiceWorker', {
|
|
39
|
-
bypass:
|
|
51
|
+
bypass: !this.captureMockedServiceWorker
|
|
40
52
|
}), session.send('Network.setCacheDisabled', {
|
|
41
53
|
cacheDisabled: true
|
|
42
54
|
}), session.send('Network.setUserAgentOverride', {
|
|
@@ -114,7 +126,6 @@ export class Network {
|
|
|
114
126
|
this.#authentications.delete(interceptId);
|
|
115
127
|
if (!keepPending) {
|
|
116
128
|
this.#pending.delete(requestId);
|
|
117
|
-
this.#intercepts.delete(requestId);
|
|
118
129
|
}
|
|
119
130
|
}
|
|
120
131
|
|
|
@@ -153,23 +164,18 @@ export class Network {
|
|
|
153
164
|
requestId: interceptId,
|
|
154
165
|
resourceType
|
|
155
166
|
} = event;
|
|
167
|
+
|
|
168
|
+
// wait for request to be sent
|
|
169
|
+
await this.#requestsLifeCycleHandler.get(requestId).requestWillBeSent;
|
|
156
170
|
let pending = this.#pending.get(requestId);
|
|
157
171
|
this.#pending.delete(requestId);
|
|
158
172
|
|
|
159
173
|
// guard against redirects with the same requestId
|
|
160
|
-
|
|
161
|
-
|
|
162
|
-
|
|
163
|
-
|
|
164
|
-
|
|
165
|
-
});
|
|
166
|
-
} else {
|
|
167
|
-
// track the session that intercepted the request
|
|
168
|
-
this.#intercepts.set(requestId, {
|
|
169
|
-
...event,
|
|
170
|
-
session
|
|
171
|
-
});
|
|
172
|
-
}
|
|
174
|
+
(pending === null || pending === void 0 ? void 0 : pending.request.url) === event.request.url && pending.request.method === event.request.method && (await this._handleRequest(session, {
|
|
175
|
+
...pending,
|
|
176
|
+
resourceType,
|
|
177
|
+
interceptId
|
|
178
|
+
}));
|
|
173
179
|
};
|
|
174
180
|
|
|
175
181
|
// Called when a request will be sent. If the request has already been intercepted, handle it;
|
|
@@ -177,35 +183,32 @@ export class Network {
|
|
|
177
183
|
_handleRequestWillBeSent = async event => {
|
|
178
184
|
let {
|
|
179
185
|
requestId,
|
|
180
|
-
request
|
|
186
|
+
request,
|
|
187
|
+
type
|
|
181
188
|
} = event;
|
|
182
189
|
|
|
183
190
|
// do not handle data urls
|
|
184
191
|
if (request.url.startsWith('data:')) return;
|
|
185
192
|
if (this.intercept) {
|
|
186
|
-
let intercept = this.#intercepts.get(requestId);
|
|
187
193
|
this.#pending.set(requestId, event);
|
|
188
|
-
if (
|
|
189
|
-
|
|
190
|
-
let {
|
|
191
|
-
session,
|
|
192
|
-
requestId: interceptId,
|
|
193
|
-
resourceType
|
|
194
|
-
} = intercept;
|
|
195
|
-
await this._handleRequest(session, {
|
|
194
|
+
if (this.captureMockedServiceWorker) {
|
|
195
|
+
await this._handleRequest(undefined, {
|
|
196
196
|
...event,
|
|
197
|
-
resourceType,
|
|
198
|
-
interceptId
|
|
199
|
-
});
|
|
200
|
-
this.#intercepts.delete(requestId);
|
|
197
|
+
resourceType: type,
|
|
198
|
+
interceptId: requestId
|
|
199
|
+
}, true);
|
|
201
200
|
}
|
|
202
201
|
}
|
|
202
|
+
// release request
|
|
203
|
+
// note: we are releasing this, even if intercept is not set for network.js
|
|
204
|
+
// since, we want to process all-requests in-order doesn't matter if it should be intercepted or not
|
|
205
|
+
this.#requestsLifeCycleHandler.get(requestId).resolveRequestWillBeSent();
|
|
203
206
|
};
|
|
204
207
|
|
|
205
208
|
// Called when a pending request is paused. Handles associating redirected requests with
|
|
206
209
|
// responses and calls this.onrequest with request info and callbacks to continue, respond,
|
|
207
210
|
// or abort a request. One of the callbacks is required to be called and only one.
|
|
208
|
-
_handleRequest = async (session, event) => {
|
|
211
|
+
_handleRequest = async (session, event, serviceWorker = false) => {
|
|
209
212
|
let {
|
|
210
213
|
request,
|
|
211
214
|
requestId,
|
|
@@ -226,16 +229,21 @@ export class Network {
|
|
|
226
229
|
request.interceptId = interceptId;
|
|
227
230
|
request.redirectChain = redirectChain;
|
|
228
231
|
this.#requests.set(requestId, request);
|
|
229
|
-
|
|
232
|
+
if (!serviceWorker) {
|
|
233
|
+
await sendResponseResource(this, request, session);
|
|
234
|
+
}
|
|
230
235
|
};
|
|
231
236
|
|
|
232
237
|
// Called when a response has been received for a specific request. Associates the response with
|
|
233
238
|
// the request data and adds a buffer method to fetch the response body when needed.
|
|
234
|
-
_handleResponseReceived = (session, event) => {
|
|
239
|
+
_handleResponseReceived = async (session, event) => {
|
|
235
240
|
let {
|
|
236
241
|
requestId,
|
|
237
242
|
response
|
|
238
243
|
} = event;
|
|
244
|
+
// await on requestWillBeSent
|
|
245
|
+
// no explicitly wait on requestWillBePaused as we implictly wait on it, since it manipulates the lifeCycle of request using Fetch module
|
|
246
|
+
await this.#requestsLifeCycleHandler.get(requestId).requestWillBeSent;
|
|
239
247
|
let request = this.#requests.get(requestId);
|
|
240
248
|
/* istanbul ignore if: race condition paranioa */
|
|
241
249
|
if (!request) return;
|
|
@@ -246,12 +254,19 @@ export class Network {
|
|
|
246
254
|
});
|
|
247
255
|
return Buffer.from(result.body, result.base64Encoded ? 'base64' : 'utf-8');
|
|
248
256
|
};
|
|
257
|
+
// release response
|
|
258
|
+
this.#requestsLifeCycleHandler.get(requestId).resolveResponseReceived();
|
|
249
259
|
};
|
|
250
260
|
|
|
251
261
|
// Called when a request streams events. These types of requests break asset discovery because
|
|
252
262
|
// they never finish loading, so we untrack them to signal idle after the first event.
|
|
253
|
-
_handleEventSourceMessageReceived = event => {
|
|
254
|
-
let
|
|
263
|
+
_handleEventSourceMessageReceived = async event => {
|
|
264
|
+
let {
|
|
265
|
+
requestId
|
|
266
|
+
} = event;
|
|
267
|
+
// wait for request to be sent
|
|
268
|
+
await this.#requestsLifeCycleHandler.get(requestId).requestWillBeSent;
|
|
269
|
+
let request = this.#requests.get(requestId);
|
|
255
270
|
/* istanbul ignore else: race condition paranioa */
|
|
256
271
|
if (request) this._forgetRequest(request);
|
|
257
272
|
};
|
|
@@ -259,7 +274,12 @@ export class Network {
|
|
|
259
274
|
// Called when a request has finished loading which triggers the this.onrequestfinished
|
|
260
275
|
// callback. The request should have an associated response and be finished with any redirects.
|
|
261
276
|
_handleLoadingFinished = async event => {
|
|
262
|
-
let
|
|
277
|
+
let {
|
|
278
|
+
requestId
|
|
279
|
+
} = event;
|
|
280
|
+
// wait for upto 2 seconds or check if response has been sent
|
|
281
|
+
await this.#requestsLifeCycleHandler.get(requestId).responseReceived;
|
|
282
|
+
let request = this.#requests.get(requestId);
|
|
263
283
|
/* istanbul ignore if: race condition paranioa */
|
|
264
284
|
if (!request) return;
|
|
265
285
|
await saveResponseResource(this, request);
|
|
@@ -267,7 +287,15 @@ export class Network {
|
|
|
267
287
|
};
|
|
268
288
|
|
|
269
289
|
// Called when a request has failed loading and triggers the this.onrequestfailed callback.
|
|
270
|
-
_handleLoadingFailed = event => {
|
|
290
|
+
_handleLoadingFailed = async event => {
|
|
291
|
+
let {
|
|
292
|
+
requestId
|
|
293
|
+
} = event;
|
|
294
|
+
// wait for request to be sent
|
|
295
|
+
// note: we are waiting on requestWillBeSent and NOT responseReceived
|
|
296
|
+
// since, requests can be cancelled in-flight without Network.responseReceived having been triggered
|
|
297
|
+
// and in any case, order of processing for responseReceived and loadingFailed does not matter, as response capturing is done in loadingFinished
|
|
298
|
+
await this.#requestsLifeCycleHandler.get(requestId).requestWillBeSent;
|
|
271
299
|
let request = this.#requests.get(event.requestId);
|
|
272
300
|
/* istanbul ignore if: race condition paranioa */
|
|
273
301
|
if (!request) return;
|
package/dist/queue.js
CHANGED
|
@@ -9,6 +9,7 @@ function _classPrivateFieldGet(receiver, privateMap) { var descriptor = _classEx
|
|
|
9
9
|
function _classExtractFieldDescriptor(receiver, privateMap, action) { if (!privateMap.has(receiver)) { throw new TypeError("attempted to " + action + " private field on non-instance"); } return privateMap.get(receiver); }
|
|
10
10
|
function _classApplyDescriptorGet(receiver, descriptor) { if (descriptor.get) { return descriptor.get.call(receiver); } return descriptor.value; }
|
|
11
11
|
import { yieldFor, generatePromise, AbortController } from './utils.js';
|
|
12
|
+
import logger from '@percy/logger';
|
|
12
13
|
|
|
13
14
|
// Assigns a deffered promise and resolve & reject functions to an object
|
|
14
15
|
function deferred(obj) {
|
|
@@ -46,12 +47,15 @@ var _end = /*#__PURE__*/new WeakMap();
|
|
|
46
47
|
var _process = /*#__PURE__*/new WeakSet();
|
|
47
48
|
var _until = /*#__PURE__*/new WeakSet();
|
|
48
49
|
export class Queue {
|
|
49
|
-
|
|
50
|
+
// item concurrency
|
|
51
|
+
|
|
52
|
+
constructor(name) {
|
|
50
53
|
_classPrivateMethodInitSpec(this, _until);
|
|
51
54
|
_classPrivateMethodInitSpec(this, _process);
|
|
52
55
|
_classPrivateMethodInitSpec(this, _find);
|
|
53
56
|
_classPrivateMethodInitSpec(this, _dequeue);
|
|
54
57
|
_defineProperty(this, "concurrency", 10);
|
|
58
|
+
_defineProperty(this, "log", logger('core:queue'));
|
|
55
59
|
_classPrivateFieldInitSpec(this, _handlers, {
|
|
56
60
|
writable: true,
|
|
57
61
|
value: {}
|
|
@@ -73,7 +77,9 @@ export class Queue {
|
|
|
73
77
|
value: null
|
|
74
78
|
});
|
|
75
79
|
_defineProperty(this, "readyState", 0);
|
|
80
|
+
this.name = name;
|
|
76
81
|
}
|
|
82
|
+
|
|
77
83
|
// Configure queue properties
|
|
78
84
|
set({
|
|
79
85
|
concurrency
|
|
@@ -201,6 +207,7 @@ export class Queue {
|
|
|
201
207
|
// clear and abort any queued tasks
|
|
202
208
|
clear() {
|
|
203
209
|
let tasks = [..._classPrivateFieldGet(this, _queued)];
|
|
210
|
+
this.log.debug(`Clearing ${this.name} queue, queued state: ${_classPrivateFieldGet(this, _queued).size}, pending state: ${_classPrivateFieldGet(this, _pending).size}`);
|
|
204
211
|
_classPrivateFieldGet(this, _queued).clear();
|
|
205
212
|
for (let task of tasks) {
|
|
206
213
|
task.ctrl.abort();
|
|
@@ -235,6 +242,7 @@ export class Queue {
|
|
|
235
242
|
// process items up to the latest queued item, starting the queue if necessary;
|
|
236
243
|
// returns a generator that yields until the flushed item has finished processing
|
|
237
244
|
flush(callback) {
|
|
245
|
+
this.log.debug(`Flushing ${this.name} queue, queued state: ${_classPrivateFieldGet(this, _queued).size}, pending state: ${_classPrivateFieldGet(this, _pending).size}`);
|
|
238
246
|
let interrupt =
|
|
239
247
|
// check for existing interrupts
|
|
240
248
|
[..._classPrivateFieldGet(this, _pending)].find(t => t.stop) ?? [..._classPrivateFieldGet(this, _queued)].find(t => t.stop);
|
|
@@ -316,10 +324,8 @@ async function* _until2(task, callback) {
|
|
|
316
324
|
pending = _classPrivateFieldGet(this, _pending).size;
|
|
317
325
|
// calculate the position within queued when not pending
|
|
318
326
|
if (task && task.pending == null) queued = positionOf(_classPrivateFieldGet(this, _queued), task);
|
|
319
|
-
// calculate the position within pending when not stopping
|
|
320
|
-
if (!(task !== null && task !== void 0 && task.stop) && (task === null || task === void 0 ? void 0 : task.pending) != null) pending = positionOf(_classPrivateFieldGet(this, _pending), task);
|
|
321
327
|
// call the callback and return true when not queued or pending
|
|
322
|
-
let position = (queued ?? 0) +
|
|
328
|
+
let position = (queued ?? 0) + pending;
|
|
323
329
|
callback === null || callback === void 0 ? void 0 : callback(position);
|
|
324
330
|
return !position;
|
|
325
331
|
}, {
|
package/dist/snapshot.js
CHANGED
|
@@ -125,6 +125,7 @@ function getSnapshotOptions(options, {
|
|
|
125
125
|
requestHeaders: config.discovery.requestHeaders,
|
|
126
126
|
authorization: config.discovery.authorization,
|
|
127
127
|
disableCache: config.discovery.disableCache,
|
|
128
|
+
captureMockedServiceWorker: config.discovery.captureMockedServiceWorker,
|
|
128
129
|
userAgent: config.discovery.userAgent
|
|
129
130
|
}
|
|
130
131
|
}, options], (path, prev, next) => {
|
|
@@ -318,7 +319,7 @@ export function createSnapshotsQueue(percy) {
|
|
|
318
319
|
let {
|
|
319
320
|
concurrency
|
|
320
321
|
} = percy.config.discovery;
|
|
321
|
-
let queue = new Queue();
|
|
322
|
+
let queue = new Queue('snapshot');
|
|
322
323
|
let build;
|
|
323
324
|
return queue.set({
|
|
324
325
|
concurrency
|
package/dist/utils.js
CHANGED
|
@@ -324,4 +324,23 @@ export function serializeFunction(fn) {
|
|
|
324
324
|
fnbody = fnbody.replace(/cov_.*?(;\n?|,)\s*/g, '');
|
|
325
325
|
}
|
|
326
326
|
return fnbody;
|
|
327
|
-
}
|
|
327
|
+
}
|
|
328
|
+
|
|
329
|
+
// DefaultMap, which returns a default value for an uninitialized key
|
|
330
|
+
// Similar to defaultDict in python
|
|
331
|
+
export class DefaultMap extends Map {
|
|
332
|
+
constructor(getDefaultValue, ...mapConstructorArgs) {
|
|
333
|
+
super(...mapConstructorArgs);
|
|
334
|
+
if (typeof getDefaultValue !== 'function') {
|
|
335
|
+
throw new Error('getDefaultValue must be a function');
|
|
336
|
+
}
|
|
337
|
+
this.getDefaultValue = getDefaultValue;
|
|
338
|
+
}
|
|
339
|
+
get = key => {
|
|
340
|
+
if (!this.has(key)) {
|
|
341
|
+
this.set(key, this.getDefaultValue(key));
|
|
342
|
+
}
|
|
343
|
+
return super.get(key);
|
|
344
|
+
};
|
|
345
|
+
}
|
|
346
|
+
;
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@percy/core",
|
|
3
|
-
"version": "1.27.5-beta.
|
|
3
|
+
"version": "1.27.5-beta.2",
|
|
4
4
|
"license": "MIT",
|
|
5
5
|
"repository": {
|
|
6
6
|
"type": "git",
|
|
@@ -9,7 +9,7 @@
|
|
|
9
9
|
},
|
|
10
10
|
"publishConfig": {
|
|
11
11
|
"access": "public",
|
|
12
|
-
"tag": "
|
|
12
|
+
"tag": "beta"
|
|
13
13
|
},
|
|
14
14
|
"engines": {
|
|
15
15
|
"node": ">=14"
|
|
@@ -43,11 +43,11 @@
|
|
|
43
43
|
"test:types": "tsd"
|
|
44
44
|
},
|
|
45
45
|
"dependencies": {
|
|
46
|
-
"@percy/client": "1.27.5-beta.
|
|
47
|
-
"@percy/config": "1.27.5-beta.
|
|
48
|
-
"@percy/dom": "1.27.5-beta.
|
|
49
|
-
"@percy/logger": "1.27.5-beta.
|
|
50
|
-
"@percy/webdriver-utils": "1.27.5-beta.
|
|
46
|
+
"@percy/client": "1.27.5-beta.2",
|
|
47
|
+
"@percy/config": "1.27.5-beta.2",
|
|
48
|
+
"@percy/dom": "1.27.5-beta.2",
|
|
49
|
+
"@percy/logger": "1.27.5-beta.2",
|
|
50
|
+
"@percy/webdriver-utils": "1.27.5-beta.2",
|
|
51
51
|
"content-disposition": "^0.5.4",
|
|
52
52
|
"cross-spawn": "^7.0.3",
|
|
53
53
|
"extract-zip": "^2.0.1",
|
|
@@ -58,5 +58,5 @@
|
|
|
58
58
|
"rimraf": "^3.0.2",
|
|
59
59
|
"ws": "^8.0.0"
|
|
60
60
|
},
|
|
61
|
-
"gitHead": "
|
|
61
|
+
"gitHead": "9ea4b1f10c134e2c8135f7dddda764a9edafb336"
|
|
62
62
|
}
|