@percy/dom 1.28.9 → 1.29.0-beta.1

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (2) hide show
  1. package/dist/bundle.js +266 -210
  2. package/package.json +3 -3
package/dist/bundle.js CHANGED
@@ -6,48 +6,124 @@
6
6
  process.env = process.env || {};
7
7
  process.env.__PERCY_BROWSERIFIED__ = true;
8
8
 
9
+ // Creates a resource object from an element's unique ID and data URL
10
+ function resourceFromDataURL(uid, dataURL) {
11
+ // split dataURL into desired parts
12
+ let [data, content] = dataURL.split(',');
13
+ let [, mimetype] = data.split(':');
14
+ [mimetype] = mimetype.split(';');
15
+
16
+ // build a URL for the serialized asset
17
+ let [, ext] = mimetype.split('/');
18
+ let path = `/__serialized__/${uid}.${ext}`;
19
+ let url = rewriteLocalhostURL(new URL(path, document.URL).toString());
20
+
21
+ // return the url, base64 content, and mimetype
22
+ return {
23
+ url,
24
+ content,
25
+ mimetype
26
+ };
27
+ }
28
+ function resourceFromText(uid, mimetype, data) {
29
+ // build a URL for the serialized asset
30
+ let [, ext] = mimetype.split('/');
31
+ let path = `/__serialized__/${uid}.${ext}`;
32
+ let url = rewriteLocalhostURL(new URL(path, document.URL).toString());
33
+ // return the url, text content, and mimetype
34
+ return {
35
+ url,
36
+ content: data,
37
+ mimetype
38
+ };
39
+ }
40
+ function styleSheetFromNode(node) {
41
+ /* istanbul ignore if: sanity check */
42
+ if (node.sheet) return node.sheet;
43
+
44
+ // Cloned style nodes don't have a sheet instance unless they are within
45
+ // a document; we get it by temporarily adding the rules to DOM
46
+ const tempStyle = node.cloneNode();
47
+ tempStyle.setAttribute('data-percy-style-helper', '');
48
+ tempStyle.innerHTML = node.innerHTML;
49
+ const clone = document.cloneNode();
50
+ clone.appendChild(tempStyle);
51
+ const sheet = tempStyle.sheet;
52
+ // Cleanup node
53
+ tempStyle.remove();
54
+ return sheet;
55
+ }
56
+ function rewriteLocalhostURL(url) {
57
+ return url.replace(/(http[s]{0,1}:\/\/)(localhost|127.0.0.1)[:\d+]*/, '$1render.percy.local');
58
+ }
59
+
60
+ // Utility function to handle errors
61
+ function handleErrors(error, prefixMessage) {
62
+ let element = arguments.length > 2 && arguments[2] !== undefined ? arguments[2] : null;
63
+ let additionalData = arguments.length > 3 && arguments[3] !== undefined ? arguments[3] : {};
64
+ let elementData = {};
65
+ if (element) {
66
+ elementData = {
67
+ nodeName: element.nodeName,
68
+ classNames: element.className,
69
+ id: element.id
70
+ };
71
+ }
72
+ additionalData = {
73
+ ...additionalData,
74
+ ...elementData
75
+ };
76
+ error.message += `\n${prefixMessage} \n${JSON.stringify(additionalData)}`;
77
+ error.message += '\n Please validate that your DOM is as per W3C standards using any online tool';
78
+ error.handled = true;
79
+ throw error;
80
+ }
81
+
9
82
  // Translates JavaScript properties of inputs into DOM attributes.
10
- function serializeInputElements(_ref) {
83
+ function serializeInputElements(ctx) {
11
84
  let {
12
85
  dom,
13
- clone,
14
- warnings
15
- } = _ref;
86
+ clone
87
+ } = ctx;
16
88
  for (let elem of dom.querySelectorAll('input, textarea, select')) {
17
- let inputId = elem.getAttribute('data-percy-element-id');
18
- let cloneEl = clone.querySelector(`[data-percy-element-id="${inputId}"]`);
19
- switch (elem.type) {
20
- case 'checkbox':
21
- case 'radio':
22
- /*
23
- here we are removing the checked attr if present by default,
24
- so that only the current selected radio-button will have the checked attr present in the dom
25
- this happens because in html,
26
- when the checked attribute is present in the multiple radio-buttons for which only one can be selected at a time,
27
- the browser will only render the last checked radio-button by default,
28
- when a user selects any particular radio-button, the checked attribute on other buttons is not removed,
29
- hence sometimes it shows inconsistent state as html will still show the last radio as selected.
30
- */
31
- cloneEl.removeAttribute('checked');
32
- if (elem.checked) {
33
- cloneEl.setAttribute('checked', '');
34
- }
35
- break;
36
- case 'select-one':
37
- if (elem.selectedIndex !== -1) {
38
- cloneEl.options[elem.selectedIndex].setAttribute('selected', 'true');
39
- }
40
- break;
41
- case 'select-multiple':
42
- for (let option of elem.selectedOptions) {
43
- cloneEl.options[option.index].setAttribute('selected', 'true');
44
- }
45
- break;
46
- case 'textarea':
47
- cloneEl.innerHTML = elem.value;
48
- break;
49
- default:
50
- cloneEl.setAttribute('value', elem.value);
89
+ try {
90
+ let inputId = elem.getAttribute('data-percy-element-id');
91
+ let cloneEl = clone.querySelector(`[data-percy-element-id="${inputId}"]`);
92
+ switch (elem.type) {
93
+ case 'checkbox':
94
+ case 'radio':
95
+ /*
96
+ here we are removing the checked attr if present by default,
97
+ so that only the current selected radio-button will have the checked attr present in the dom
98
+ this happens because in html,
99
+ when the checked attribute is present in the multiple radio-buttons for which only one can be selected at a time,
100
+ the browser will only render the last checked radio-button by default,
101
+ when a user selects any particular radio-button, the checked attribute on other buttons is not removed,
102
+ hence sometimes it shows inconsistent state as html will still show the last radio as selected.
103
+ */
104
+ cloneEl.removeAttribute('checked');
105
+ if (elem.checked) {
106
+ cloneEl.setAttribute('checked', '');
107
+ }
108
+ break;
109
+ case 'select-one':
110
+ if (elem.selectedIndex !== -1) {
111
+ cloneEl.options[elem.selectedIndex].setAttribute('selected', 'true');
112
+ }
113
+ break;
114
+ case 'select-multiple':
115
+ for (let option of elem.selectedOptions) {
116
+ cloneEl.options[option.index].setAttribute('selected', 'true');
117
+ }
118
+ break;
119
+ case 'textarea':
120
+ cloneEl.innerHTML = elem.value;
121
+ break;
122
+ default:
123
+ cloneEl.setAttribute('value', elem.value);
124
+ }
125
+ } catch (err) {
126
+ handleErrors(err, 'Error serializing input element: ', elem);
51
127
  }
52
128
  }
53
129
  }
@@ -117,57 +193,6 @@
117
193
  }
118
194
  }
119
195
 
120
- // Creates a resource object from an element's unique ID and data URL
121
- function resourceFromDataURL(uid, dataURL) {
122
- // split dataURL into desired parts
123
- let [data, content] = dataURL.split(',');
124
- let [, mimetype] = data.split(':');
125
- [mimetype] = mimetype.split(';');
126
-
127
- // build a URL for the serialized asset
128
- let [, ext] = mimetype.split('/');
129
- let path = `/__serialized__/${uid}.${ext}`;
130
- let url = rewriteLocalhostURL(new URL(path, document.URL).toString());
131
-
132
- // return the url, base64 content, and mimetype
133
- return {
134
- url,
135
- content,
136
- mimetype
137
- };
138
- }
139
- function resourceFromText(uid, mimetype, data) {
140
- // build a URL for the serialized asset
141
- let [, ext] = mimetype.split('/');
142
- let path = `/__serialized__/${uid}.${ext}`;
143
- let url = rewriteLocalhostURL(new URL(path, document.URL).toString());
144
- // return the url, text content, and mimetype
145
- return {
146
- url,
147
- content: data,
148
- mimetype
149
- };
150
- }
151
- function styleSheetFromNode(node) {
152
- /* istanbul ignore if: sanity check */
153
- if (node.sheet) return node.sheet;
154
-
155
- // Cloned style nodes don't have a sheet instance unless they are within
156
- // a document; we get it by temporarily adding the rules to DOM
157
- const tempStyle = node.cloneNode();
158
- tempStyle.setAttribute('data-percy-style-helper', '');
159
- tempStyle.innerHTML = node.innerHTML;
160
- const clone = document.cloneNode();
161
- clone.appendChild(tempStyle);
162
- const sheet = tempStyle.sheet;
163
- // Cleanup node
164
- tempStyle.remove();
165
- return sheet;
166
- }
167
- function rewriteLocalhostURL(url) {
168
- return url.replace(/(http[s]{0,1}:\/\/)(localhost|127.0.0.1)[:\d+]*/, '$1render.percy.local');
169
- }
170
-
171
196
  // Returns a mostly random uid.
172
197
  function uid() {
173
198
  return `_${Math.random().toString(36).substr(2, 9)}`;
@@ -211,14 +236,14 @@
211
236
  let resource = resourceFromText(uid(), 'text/css', styles);
212
237
  return resource;
213
238
  }
214
- function serializeCSSOM(_ref) {
239
+ function serializeCSSOM(ctx) {
215
240
  let {
216
241
  dom,
217
242
  clone,
218
243
  resources,
219
244
  cache,
220
245
  warnings
221
- } = _ref;
246
+ } = ctx;
222
247
  // in-memory CSSOM into their respective DOM nodes.
223
248
  let styleSheets = null;
224
249
  // catch error in case styleSheets property is not available (overwritten to throw error)
@@ -231,30 +256,44 @@
231
256
  for (let styleSheet of styleSheets) {
232
257
  var _styleSheet$href;
233
258
  if (isCSSOM(styleSheet)) {
234
- let styleId = styleSheet.ownerNode.getAttribute('data-percy-element-id');
235
- let cloneOwnerNode = clone.querySelector(`[data-percy-element-id="${styleId}"]`);
236
- if (styleSheetsMatch(styleSheet, styleSheetFromNode(cloneOwnerNode))) continue;
237
- let style = document.createElement('style');
238
- style.type = 'text/css';
239
- style.setAttribute('data-percy-element-id', styleId);
240
- style.setAttribute('data-percy-cssom-serialized', 'true');
241
- style.innerHTML = Array.from(styleSheet.cssRules).map(cssRule => cssRule.cssText).join('\n');
242
- cloneOwnerNode.parentNode.insertBefore(style, cloneOwnerNode.nextSibling);
243
- cloneOwnerNode.remove();
259
+ let styleId;
260
+ let cloneOwnerNode;
261
+ try {
262
+ styleId = styleSheet.ownerNode.getAttribute('data-percy-element-id');
263
+ cloneOwnerNode = clone.querySelector(`[data-percy-element-id="${styleId}"]`);
264
+ if (styleSheetsMatch(styleSheet, styleSheetFromNode(cloneOwnerNode))) continue;
265
+ let style = document.createElement('style');
266
+ style.type = 'text/css';
267
+ style.setAttribute('data-percy-element-id', styleId);
268
+ style.setAttribute('data-percy-cssom-serialized', 'true');
269
+ style.innerHTML = Array.from(styleSheet.cssRules).map(cssRule => cssRule.cssText).join('\n');
270
+ cloneOwnerNode.parentNode.insertBefore(style, cloneOwnerNode.nextSibling);
271
+ cloneOwnerNode.remove();
272
+ } catch (err) {
273
+ handleErrors(err, 'Error serializing stylesheet: ', cloneOwnerNode, {
274
+ styleId: styleId
275
+ });
276
+ }
244
277
  } else if ((_styleSheet$href = styleSheet.href) !== null && _styleSheet$href !== void 0 && _styleSheet$href.startsWith('blob:')) {
245
- const styleLink = document.createElement('link');
246
- styleLink.setAttribute('rel', 'stylesheet');
247
- let resource = createStyleResource(styleSheet);
248
- resources.add(resource);
249
- styleLink.setAttribute('data-percy-blob-stylesheets-serialized', 'true');
250
- styleLink.setAttribute('data-percy-serialized-attribute-href', resource.url);
251
-
252
- /* istanbul ignore next: tested, but coverage is stripped */
253
- if (clone.constructor.name === 'HTMLDocument' || clone.constructor.name === 'DocumentFragment') {
254
- // handle document and iframe
255
- clone.body.prepend(styleLink);
256
- } else if (clone.constructor.name === 'ShadowRoot') {
257
- clone.prepend(styleLink);
278
+ try {
279
+ const styleLink = document.createElement('link');
280
+ styleLink.setAttribute('rel', 'stylesheet');
281
+ let resource = createStyleResource(styleSheet);
282
+ resources.add(resource);
283
+ styleLink.setAttribute('data-percy-blob-stylesheets-serialized', 'true');
284
+ styleLink.setAttribute('data-percy-serialized-attribute-href', resource.url);
285
+
286
+ /* istanbul ignore next: tested, but coverage is stripped */
287
+ if (clone.constructor.name === 'HTMLDocument' || clone.constructor.name === 'DocumentFragment') {
288
+ // handle document and iframe
289
+ clone.body.prepend(styleLink);
290
+ } else if (clone.constructor.name === 'ShadowRoot') {
291
+ clone.prepend(styleLink);
292
+ }
293
+ } catch (err) {
294
+ handleErrors(err, 'Error serializing stylesheet from blob: ', null, {
295
+ stylesheetHref: styleSheet.href
296
+ });
258
297
  }
259
298
  }
260
299
  }
@@ -289,90 +328,98 @@
289
328
  }
290
329
 
291
330
  // Serialize in-memory canvas elements into images.
292
- function serializeCanvas(_ref) {
331
+ function serializeCanvas(ctx) {
293
332
  let {
294
333
  dom,
295
334
  clone,
296
335
  resources
297
- } = _ref;
336
+ } = ctx;
298
337
  for (let canvas of dom.querySelectorAll('canvas')) {
299
- // Note: the `.toDataURL` API requires WebGL canvas elements to use
300
- // `preserveDrawingBuffer: true`. This is because `.toDataURL` uses the
301
- // drawing buffer, which is cleared after each render for WebGL by default.
302
- let dataUrl = canvas.toDataURL();
303
-
304
- // skip empty canvases
305
- if (!dataUrl || dataUrl === 'data:,') continue;
306
-
307
- // get the element's percy id and create a resource for it
308
- let percyElementId = canvas.getAttribute('data-percy-element-id');
309
- let resource = resourceFromDataURL(percyElementId, dataUrl);
310
- resources.add(resource);
311
-
312
- // create an image element in the cloned dom
313
- let img = document.createElement('img');
314
- // use a data attribute to avoid making a real request
315
- img.setAttribute('data-percy-serialized-attribute-src', resource.url);
316
-
317
- // copy canvas element attributes to the image element such as style, class,
318
- // or data attributes that may be targeted by CSS
319
- for (let {
320
- name,
321
- value
322
- } of canvas.attributes) {
323
- img.setAttribute(name, value);
324
- }
338
+ try {
339
+ // Note: the `.toDataURL` API requires WebGL canvas elements to use
340
+ // `preserveDrawingBuffer: true`. This is because `.toDataURL` uses the
341
+ // drawing buffer, which is cleared after each render for WebGL by default.
342
+ let dataUrl = canvas.toDataURL();
343
+
344
+ // skip empty canvases
345
+ if (!dataUrl || dataUrl === 'data:,') continue;
346
+
347
+ // get the element's percy id and create a resource for it
348
+ let percyElementId = canvas.getAttribute('data-percy-element-id');
349
+ let resource = resourceFromDataURL(percyElementId, dataUrl);
350
+ resources.add(resource);
351
+
352
+ // create an image element in the cloned dom
353
+ let img = document.createElement('img');
354
+ // use a data attribute to avoid making a real request
355
+ img.setAttribute('data-percy-serialized-attribute-src', resource.url);
356
+
357
+ // copy canvas element attributes to the image element such as style, class,
358
+ // or data attributes that may be targeted by CSS
359
+ for (let {
360
+ name,
361
+ value
362
+ } of canvas.attributes) {
363
+ img.setAttribute(name, value);
364
+ }
325
365
 
326
- // mark the image as serialized (can be targeted by CSS)
327
- img.setAttribute('data-percy-canvas-serialized', '');
328
- // set a default max width to account for canvases that might resize with JS
329
- img.style.maxWidth = img.style.maxWidth || '100%';
366
+ // mark the image as serialized (can be targeted by CSS)
367
+ img.setAttribute('data-percy-canvas-serialized', '');
368
+ // set a default max width to account for canvases that might resize with JS
369
+ img.style.maxWidth = img.style.maxWidth || '100%';
330
370
 
331
- // insert the image into the cloned DOM and remove the cloned canvas element
332
- let cloneEl = clone.querySelector(`[data-percy-element-id=${percyElementId}]`);
333
- // `parentElement` for elements directly under shadow root is `null` -> Incase of Nested Shadow DOM.
334
- if (cloneEl.parentElement) {
335
- cloneEl.parentElement.insertBefore(img, cloneEl);
336
- } else {
337
- clone.insertBefore(img, cloneEl);
371
+ // insert the image into the cloned DOM and remove the cloned canvas element
372
+ let cloneEl = clone.querySelector(`[data-percy-element-id=${percyElementId}]`);
373
+ // `parentElement` for elements directly under shadow root is `null` -> Incase of Nested Shadow DOM.
374
+ if (cloneEl.parentElement) {
375
+ cloneEl.parentElement.insertBefore(img, cloneEl);
376
+ } else {
377
+ clone.insertBefore(img, cloneEl);
378
+ }
379
+ cloneEl.remove();
380
+ } catch (err) {
381
+ handleErrors(err, 'Error serializing canvas element: ', canvas);
338
382
  }
339
- cloneEl.remove();
340
383
  }
341
384
  }
342
385
 
343
386
  // Captures the current frame of videos and sets the poster image
344
- function serializeVideos(_ref) {
387
+ function serializeVideos(ctx) {
345
388
  let {
346
389
  dom,
347
390
  clone,
348
391
  resources,
349
392
  warnings
350
- } = _ref;
393
+ } = ctx;
351
394
  for (let video of dom.querySelectorAll('video')) {
352
- // if the video already has a poster image, no work for us to do
353
- if (video.getAttribute('poster')) continue;
354
- let videoId = video.getAttribute('data-percy-element-id');
355
- let cloneEl = clone.querySelector(`[data-percy-element-id="${videoId}"]`);
356
- let canvas = document.createElement('canvas');
357
- let width = canvas.width = video.videoWidth;
358
- let height = canvas.height = video.videoHeight;
359
- let dataUrl;
360
- canvas.getContext('2d').drawImage(video, 0, 0, width, height);
361
395
  try {
362
- dataUrl = canvas.toDataURL();
363
- } catch (e) {
364
- warnings.add(`data-percy-element-id="${videoId}" : ${e.toString()}`);
365
- }
396
+ // if the video already has a poster image, no work for us to do
397
+ if (video.getAttribute('poster')) continue;
398
+ let videoId = video.getAttribute('data-percy-element-id');
399
+ let cloneEl = clone.querySelector(`[data-percy-element-id="${videoId}"]`);
400
+ let canvas = document.createElement('canvas');
401
+ let width = canvas.width = video.videoWidth;
402
+ let height = canvas.height = video.videoHeight;
403
+ let dataUrl;
404
+ canvas.getContext('2d').drawImage(video, 0, 0, width, height);
405
+ try {
406
+ dataUrl = canvas.toDataURL();
407
+ } catch (e) {
408
+ warnings.add(`data-percy-element-id="${videoId}" : ${e.toString()}`);
409
+ }
366
410
 
367
- // if the canvas produces a blank image, skip
368
- if (!dataUrl || dataUrl === 'data:,') continue;
411
+ // if the canvas produces a blank image, skip
412
+ if (!dataUrl || dataUrl === 'data:,') continue;
369
413
 
370
- // create a resource from the serialized data url
371
- let resource = resourceFromDataURL(videoId, dataUrl);
372
- resources.add(resource);
414
+ // create a resource from the serialized data url
415
+ let resource = resourceFromDataURL(videoId, dataUrl);
416
+ resources.add(resource);
373
417
 
374
- // use a data attribute to avoid making a real request
375
- cloneEl.setAttribute('data-percy-serialized-attribute-poster', resource.url);
418
+ // use a data attribute to avoid making a real request
419
+ cloneEl.setAttribute('data-percy-serialized-attribute-poster', resource.url);
420
+ } catch (err) {
421
+ handleErrors(err, 'Error serializing video element: ', video);
422
+ }
376
423
  }
377
424
  }
378
425
 
@@ -434,54 +481,62 @@
434
481
  */
435
482
 
436
483
  const ignoreTags = ['NOSCRIPT'];
437
- function cloneNodeAndShadow(_ref) {
484
+ function cloneNodeAndShadow(ctx) {
438
485
  let {
439
486
  dom,
440
487
  disableShadowDOM,
441
488
  resources
442
- } = _ref;
489
+ } = ctx;
443
490
  // clones shadow DOM and light DOM for a given node
444
491
  let cloneNode = (node, parent) => {
445
- let walkTree = (nextn, nextp) => {
446
- while (nextn) {
447
- if (!ignoreTags.includes(nextn.nodeName)) {
448
- cloneNode(nextn, nextp);
492
+ try {
493
+ let walkTree = (nextn, nextp) => {
494
+ while (nextn) {
495
+ if (!ignoreTags.includes(nextn.nodeName)) {
496
+ cloneNode(nextn, nextp);
497
+ }
498
+ nextn = nextn.nextSibling;
449
499
  }
450
- nextn = nextn.nextSibling;
451
- }
452
- };
500
+ };
453
501
 
454
- // mark the node before cloning
455
- markElement(node, disableShadowDOM);
456
- let clone = node.cloneNode();
502
+ // mark the node before cloning
503
+ markElement(node, disableShadowDOM);
504
+ let clone = node.cloneNode();
457
505
 
458
- // We apply any element transformations here to avoid another treeWalk
459
- applyElementTransformations(clone);
460
- serializeBase64(clone, resources);
461
- parent.appendChild(clone);
506
+ // We apply any element transformations here to avoid another treeWalk
507
+ applyElementTransformations(clone);
508
+ serializeBase64(clone, resources);
509
+ parent.appendChild(clone);
462
510
 
463
- // shallow clone should not contain children
464
- if (clone.children) {
465
- Array.from(clone.children).forEach(child => clone.removeChild(child));
466
- }
511
+ // shallow clone should not contain children
512
+ if (clone.children) {
513
+ Array.from(clone.children).forEach(child => clone.removeChild(child));
514
+ }
467
515
 
468
- // clone shadow DOM
469
- if (node.shadowRoot && !disableShadowDOM) {
470
- // create shadowRoot
471
- if (clone.shadowRoot) {
472
- // it may be set up in a custom element's constructor
473
- clone.shadowRoot.innerHTML = '';
516
+ // clone shadow DOM
517
+ if (node.shadowRoot && !disableShadowDOM) {
518
+ // create shadowRoot
519
+ if (clone.shadowRoot) {
520
+ // it may be set up in a custom element's constructor
521
+ clone.shadowRoot.innerHTML = '';
522
+ } else {
523
+ clone.attachShadow({
524
+ mode: 'open'
525
+ });
526
+ }
527
+ // clone dom elements
528
+ walkTree(node.shadowRoot.firstChild, clone.shadowRoot);
529
+ }
530
+
531
+ // clone light DOM
532
+ walkTree(node.firstChild, clone);
533
+ } catch (err) {
534
+ if (!err.handled) {
535
+ handleErrors(err, 'Error cloning node: ', node);
474
536
  } else {
475
- clone.attachShadow({
476
- mode: 'open'
477
- });
537
+ throw err;
478
538
  }
479
- // clone dom elements
480
- walkTree(node.shadowRoot.firstChild, clone.shadowRoot);
481
539
  }
482
-
483
- // clone light DOM
484
- walkTree(node.firstChild, clone);
485
540
  };
486
541
  let fragment = dom.createDocumentFragment();
487
542
  cloneNode(dom.documentElement, fragment);
@@ -604,6 +659,7 @@
604
659
  }
605
660
  let result = {
606
661
  html: serializeHTML(ctx),
662
+ cookies: dom.cookie,
607
663
  warnings: Array.from(ctx.warnings),
608
664
  resources: Array.from(ctx.resources),
609
665
  hints: Array.from(ctx.hints)
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@percy/dom",
3
- "version": "1.28.9",
3
+ "version": "1.29.0-beta.1",
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": "latest"
12
+ "tag": "beta"
13
13
  },
14
14
  "main": "dist/bundle.js",
15
15
  "browser": "dist/bundle.js",
@@ -35,5 +35,5 @@
35
35
  "devDependencies": {
36
36
  "interactor.js": "^2.0.0-beta.10"
37
37
  },
38
- "gitHead": "03253ef16a5125469773797b4ff126649371d133"
38
+ "gitHead": "719cb9b3c5e50cfe23b2e27ebfa2410f30443cd8"
39
39
  }