@devvit/ui-renderer 0.10.10-next-2023-11-14-d6fe14bf4.0 → 0.10.10-next-2023-11-14-fabd613d1.0
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.
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"renderImageBlock.d.ts","sourceRoot":"","sources":["../../../library/src/blocks/templates/renderImageBlock.ts"],"names":[],"mappings":"AAIA,OAAO,EAAE,KAAK,EAAE,MAAM,gBAAgB,CAAC;AAGvC,OAAO,EAAE,aAAa,EAAE,MAAM,oBAAoB,CAAC;AACnD,OAAO,
|
|
1
|
+
{"version":3,"file":"renderImageBlock.d.ts","sourceRoot":"","sources":["../../../library/src/blocks/templates/renderImageBlock.ts"],"names":[],"mappings":"AAIA,OAAO,EAAE,KAAK,EAAE,MAAM,gBAAgB,CAAC;AAGvC,OAAO,EAAE,aAAa,EAAE,MAAM,oBAAoB,CAAC;AACnD,OAAO,EAAyD,YAAY,EAAE,MAAM,WAAW,CAAC;AAKhG,wBAAgB,gBAAgB,CAAC,KAAK,EAAE,KAAK,EAAE,GAAG,EAAE,aAAa,GAAG,YAAY,CAiD/E"}
|
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
import { nothing } from 'lit';
|
|
2
2
|
import { getTemplateRenderingStrategy } from '@reddit/faceplate-ui/faceplateUIConfig.js';
|
|
3
3
|
import { defaultClasses, defaultStyles, onClickAction, resizeModeClass } from '../attributes.js';
|
|
4
|
-
import { classMap, isValidImageURL } from './util.js';
|
|
4
|
+
import { classMap, isDataUrl, isValidImageURL, sanitizeDataUrl } from './util.js';
|
|
5
5
|
import { VerifiedPublicImageHosts } from './constants.js';
|
|
6
6
|
const FALLBACK_IMG_URL = 'https://i.redd.it/p1vmc5ulmpib1.png';
|
|
7
7
|
export function renderImageBlock(block, ctx) {
|
|
@@ -27,7 +27,7 @@ export function renderImageBlock(block, ctx) {
|
|
|
27
27
|
const onClick = onClickAction(block, ctx);
|
|
28
28
|
return html `
|
|
29
29
|
<img
|
|
30
|
-
src="${imageUrl}"
|
|
30
|
+
src="${isDataUrl(imageUrl) ? sanitizeDataUrl(imageUrl) : imageUrl}"
|
|
31
31
|
width="${width}"
|
|
32
32
|
height="${height}"
|
|
33
33
|
alt="${description}"
|
|
@@ -36,7 +36,10 @@ export function renderImageBlock(block, ctx) {
|
|
|
36
36
|
@click="${ifDefined(onClick)}"
|
|
37
37
|
data-debug-block-type="image"
|
|
38
38
|
@error="${{
|
|
39
|
-
handleEvent: (event) =>
|
|
39
|
+
handleEvent: (event) => {
|
|
40
|
+
console.error(`An error rendering the image with url:`, imageUrl);
|
|
41
|
+
event.target.src = FALLBACK_IMG_URL;
|
|
42
|
+
},
|
|
40
43
|
once: true,
|
|
41
44
|
}}"
|
|
42
45
|
/>
|
|
@@ -1,8 +1,8 @@
|
|
|
1
|
+
import { TemplateResult, nothing } from 'lit';
|
|
1
2
|
import type { DirectiveClass, DirectiveResult } from 'lit/directive.js';
|
|
2
3
|
import { ClassInfo, classMap as clientClassMap } from 'lit/directives/class-map.js';
|
|
3
|
-
import { ref as clientRef
|
|
4
|
+
import { RefOrCallback, ref as clientRef } from 'lit/directives/ref.js';
|
|
4
5
|
import { StyleInfo } from 'lit/directives/style-map.js';
|
|
5
|
-
import { nothing, TemplateResult } from 'lit';
|
|
6
6
|
import type { UnsafeString } from '@reddit/baseplate/html.js';
|
|
7
7
|
import { Block, BlockColor, BlockSizes, BlockSizes_Dimension_Value, BlockSizeUnit } from '@devvit/protos';
|
|
8
8
|
export type TemplateLike = TemplateResult | typeof nothing;
|
|
@@ -16,6 +16,23 @@ export declare function resolveIcon(name: string): TemplateResult;
|
|
|
16
16
|
* @param styleInfo
|
|
17
17
|
*/
|
|
18
18
|
export declare function sanitizeStyleInfo(styleInfo: StyleInfo): StyleInfo;
|
|
19
|
+
export declare function isDataUrl(input: string): boolean;
|
|
20
|
+
export declare function parseDataUrl(dataUrl: string): {
|
|
21
|
+
mimeType: string | undefined;
|
|
22
|
+
charset: string | undefined;
|
|
23
|
+
isBase64: boolean;
|
|
24
|
+
data: string;
|
|
25
|
+
} | null;
|
|
26
|
+
export declare function isAcceptableDataUrl(maybeDataUrl: string): boolean;
|
|
27
|
+
/**
|
|
28
|
+
* Attempts to sanitize data URLs to prevent two things:
|
|
29
|
+
*
|
|
30
|
+
* 1. XSS attacks
|
|
31
|
+
* 2. Allowing images to be shown to users that bypass Reddit's safety checks
|
|
32
|
+
*
|
|
33
|
+
* NOTE: We only allow a mime type of image/svg+xml at this time.
|
|
34
|
+
*/
|
|
35
|
+
export declare function sanitizeDataUrl(dataUrl: string): string;
|
|
19
36
|
export declare function isValidImageURL(imageUrl: string): boolean;
|
|
20
37
|
/**
|
|
21
38
|
* Returns a BlockSizes object either directly from the block or constructs
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"util.d.ts","sourceRoot":"","sources":["../../../library/src/blocks/templates/util.ts"],"names":[],"mappings":"
|
|
1
|
+
{"version":3,"file":"util.d.ts","sourceRoot":"","sources":["../../../library/src/blocks/templates/util.ts"],"names":[],"mappings":"AACA,OAAO,EAAE,cAAc,EAAE,OAAO,EAAE,MAAM,KAAK,CAAC;AAC9C,OAAO,KAAK,EAAE,cAAc,EAAE,eAAe,EAAE,MAAM,kBAAkB,CAAC;AACxE,OAAO,EAAE,SAAS,EAAE,QAAQ,IAAI,cAAc,EAAE,MAAM,6BAA6B,CAAC;AACpF,OAAO,EAAE,aAAa,EAAE,GAAG,IAAI,SAAS,EAAE,MAAM,uBAAuB,CAAC;AACxE,OAAO,EAAE,SAAS,EAAE,MAAM,6BAA6B,CAAC;AAGxD,OAAO,KAAK,EAAE,YAAY,EAAE,MAAM,2BAA2B,CAAC;AAK9D,OAAO,EACL,KAAK,EACL,UAAU,EACV,UAAU,EACV,0BAA0B,EAC1B,aAAa,EACd,MAAM,gBAAgB,CAAC;AAExB,MAAM,MAAM,YAAY,GAAG,cAAc,GAAG,OAAO,OAAO,CAAC;AAE3D,wBAAgB,QAAQ,CACtB,SAAS,EAAE,SAAS,EACpB,WAAW,CAAC,EAAE,OAAO,GACpB,MAAM,GAAG,UAAU,CAAC,OAAO,cAAc,CAAC,CAW5C;AAED,wBAAgB,UAAU,CAAC,KAAK,EAAE,MAAM,GAAG,eAAe,CAAC,cAAc,CAAC,GAAG,YAAY,CAMxF;AAED,wBAAgB,GAAG,CAAC,GAAG,EAAE,aAAa,GAAG,UAAU,CAAC,OAAO,SAAS,CAAC,GAAG,MAAM,CAM7E;AAED,wBAAgB,aAAa,CAAC,EAAE,EAAE,WAAW,GAAG,OAAO,GAAG,SAAS,GAAG,EAAE,IAAI,WAAW,CAEtF;AAED,wBAAgB,WAAW,CAAC,IAAI,EAAE,MAAM,GAAG,cAAc,CAiBxD;AAED;;;GAGG;AACH,wBAAgB,iBAAiB,CAAC,SAAS,EAAE,SAAS,GAAG,SAAS,CASjE;AAcD,wBAAgB,SAAS,CAAC,KAAK,EAAE,MAAM,GAAG,OAAO,CAEhD;AAED,wBAAgB,YAAY,CAAC,OAAO,EAAE,MAAM,GAAG;IAC7C,QAAQ,EAAE,MAAM,GAAG,SAAS,CAAC;IAC7B,OAAO,EAAE,MAAM,GAAG,SAAS,CAAC;IAC5B,QAAQ,EAAE,OAAO,CAAC;IAClB,IAAI,EAAE,MAAM,CAAC;CACd,GAAG,IAAI,CAWP;AASD,wBAAgB,mBAAmB,CAAC,YAAY,EAAE,MAAM,GAAG,OAAO,CAMjE;AAED;;;;;;;GAOG;AACH,wBAAgB,eAAe,CAAC,OAAO,EAAE,MAAM,GAAG,MAAM,CAyIvD;AAED,wBAAgB,eAAe,CAAC,QAAQ,EAAE,MAAM,GAAG,OAAO,CAazD;AAED;;;;GAIG;AACH,wBAAgB,QAAQ,CAAC,KAAK,EAAE,KAAK,GAAG,UAAU,GAAG,SAAS,CA2B7D;AAED,wBAAgB,cAAc,CAAC,KAAK,EAAE,0BAA0B,GAAG,SAAS,GAAG,MAAM,GAAG,SAAS,CAKhG;AAED,wBAAgB,YAAY,CAAC,IAAI,EAAE,aAAa,GAAG,SAAS,GAAG,MAAM,CAUpE;AAED;;;;;;;;;GASG;AACH,wBAAgB,aAAa,CAC3B,MAAM,EAAE,UAAU,GAAG,SAAS,EAC9B,WAAW,CAAC,EAAE,MAAM,GAAG,SAAS,GAC/B,CAAC,KAAK,CAAC,EAAE,MAAM,GAAG,SAAS,EAAE,IAAI,CAAC,EAAE,MAAM,GAAG,SAAS,CAAC,CAIzD"}
|
package/blocks/templates/util.js
CHANGED
|
@@ -1,6 +1,7 @@
|
|
|
1
|
+
import DOMPurify from 'isomorphic-dompurify';
|
|
1
2
|
import { classMap as clientClassMap } from 'lit/directives/class-map.js';
|
|
2
|
-
import { unsafeHTML as clientUnsafeHTML } from 'lit/directives/unsafe-html.js';
|
|
3
3
|
import { ref as clientRef } from 'lit/directives/ref.js';
|
|
4
|
+
import { unsafeHTML as clientUnsafeHTML } from 'lit/directives/unsafe-html.js';
|
|
4
5
|
import { unsafeHTML as serverUnsafeHTML } from '@reddit/baseplate/html.js';
|
|
5
6
|
import { getTemplateRenderingStrategy } from '@reddit/faceplate-ui/faceplateUIConfig.js';
|
|
6
7
|
import faceplateIcons from '@reddit/faceplate-ui/svgs/svg-manifest.js';
|
|
@@ -67,8 +68,183 @@ export function sanitizeStyleInfo(styleInfo) {
|
|
|
67
68
|
}
|
|
68
69
|
return styleInfo;
|
|
69
70
|
}
|
|
71
|
+
const DATA_URL_REGEX =
|
|
72
|
+
// eslint-disable-next-line security/detect-unsafe-regex
|
|
73
|
+
/^data:([a-zA-Z]+\/[a-zA-Z0-9.+_-]+)?(;charset=[a-zA-Z0-9._+-]+)?(;base64)?,(.*)/;
|
|
74
|
+
function preprocessDataUrl(input) {
|
|
75
|
+
/**
|
|
76
|
+
* This can be submitted to us as multi-line and that will break the parser
|
|
77
|
+
* so we remove all newlines here
|
|
78
|
+
*/
|
|
79
|
+
return input.trim().replace(/[\r\n]+/g, '');
|
|
80
|
+
}
|
|
81
|
+
export function isDataUrl(input) {
|
|
82
|
+
return !!preprocessDataUrl(input).match(DATA_URL_REGEX);
|
|
83
|
+
}
|
|
84
|
+
export function parseDataUrl(dataUrl) {
|
|
85
|
+
const matches = DATA_URL_REGEX.exec(preprocessDataUrl(dataUrl));
|
|
86
|
+
if (!matches)
|
|
87
|
+
return null;
|
|
88
|
+
return {
|
|
89
|
+
mimeType: matches[1],
|
|
90
|
+
charset: matches[2]?.split('=')[1],
|
|
91
|
+
isBase64: !!matches[3],
|
|
92
|
+
data: matches[4].trim(),
|
|
93
|
+
};
|
|
94
|
+
}
|
|
95
|
+
function isAcceptableDataUrlMimeType(mimeType) {
|
|
96
|
+
// https://developer.mozilla.org/en-US/docs/Web/HTTP/Basics_of_HTTP/MIME_types#image_types
|
|
97
|
+
const ACCEPTABLE_MIME_TYPES = ['image/svg+xml'];
|
|
98
|
+
return ACCEPTABLE_MIME_TYPES.includes(mimeType);
|
|
99
|
+
}
|
|
100
|
+
export function isAcceptableDataUrl(maybeDataUrl) {
|
|
101
|
+
const parsedDataUrl = parseDataUrl(maybeDataUrl);
|
|
102
|
+
if (!parsedDataUrl?.mimeType)
|
|
103
|
+
return false;
|
|
104
|
+
return isAcceptableDataUrlMimeType(parsedDataUrl.mimeType);
|
|
105
|
+
}
|
|
106
|
+
/**
|
|
107
|
+
* Attempts to sanitize data URLs to prevent two things:
|
|
108
|
+
*
|
|
109
|
+
* 1. XSS attacks
|
|
110
|
+
* 2. Allowing images to be shown to users that bypass Reddit's safety checks
|
|
111
|
+
*
|
|
112
|
+
* NOTE: We only allow a mime type of image/svg+xml at this time.
|
|
113
|
+
*/
|
|
114
|
+
export function sanitizeDataUrl(dataUrl) {
|
|
115
|
+
const parsedDataUrl = parseDataUrl(dataUrl);
|
|
116
|
+
if (!parsedDataUrl || !parsedDataUrl.data || !parsedDataUrl.mimeType)
|
|
117
|
+
return '';
|
|
118
|
+
if (!isAcceptableDataUrlMimeType(parsedDataUrl.mimeType))
|
|
119
|
+
return '';
|
|
120
|
+
try {
|
|
121
|
+
let dataToSanitize;
|
|
122
|
+
if (parsedDataUrl.isBase64) {
|
|
123
|
+
dataToSanitize = decodeURIComponent(atob(parsedDataUrl.data));
|
|
124
|
+
}
|
|
125
|
+
else {
|
|
126
|
+
dataToSanitize = decodeURIComponent(parsedDataUrl.data);
|
|
127
|
+
}
|
|
128
|
+
const sanitizeCss = (cssText) => {
|
|
129
|
+
// Define a regex pattern that matches CSS properties that can include URLs
|
|
130
|
+
const urlPattern =
|
|
131
|
+
// eslint-disable-next-line security/detect-unsafe-regex
|
|
132
|
+
/(?:background(-image)?|border-image(-source)?)\s*:\s*(url\(['"]?(data:image\/(?:png|jpeg|gif);base64,[^)]+|https?:\/\/[^)]+)['"]?\))(?:;\s*)?/gi;
|
|
133
|
+
// Remove any matching URL patterns from the CSS text
|
|
134
|
+
return cssText.replace(urlPattern, '');
|
|
135
|
+
};
|
|
136
|
+
// This is for <style> tags
|
|
137
|
+
DOMPurify.addHook('uponSanitizeElement', (node) => {
|
|
138
|
+
if (node.tagName === 'style') {
|
|
139
|
+
if (node.textContent) {
|
|
140
|
+
node.textContent = sanitizeCss(node.textContent);
|
|
141
|
+
}
|
|
142
|
+
}
|
|
143
|
+
/**
|
|
144
|
+
* xmlns is optional when using a SVG inside of the DOM. However,
|
|
145
|
+
* since we are using it within a data url, it is required.
|
|
146
|
+
*
|
|
147
|
+
* https://stackoverflow.com/questions/18467982/are-svg-parameters-such-as-xmlns-and-version-needed
|
|
148
|
+
*/
|
|
149
|
+
if (node.tagName === 'svg') {
|
|
150
|
+
if (!node.getAttribute('xmlns')) {
|
|
151
|
+
node.setAttribute('xmlns', 'http://www.w3.org/2000/svg');
|
|
152
|
+
}
|
|
153
|
+
}
|
|
154
|
+
});
|
|
155
|
+
// This is for style attribute tags
|
|
156
|
+
DOMPurify.addHook('uponSanitizeAttribute', (_node, data) => {
|
|
157
|
+
if (data.attrName === 'style') {
|
|
158
|
+
data.attrValue = sanitizeCss(data.attrValue);
|
|
159
|
+
}
|
|
160
|
+
});
|
|
161
|
+
const sanitized = DOMPurify.sanitize(dataToSanitize, {
|
|
162
|
+
// Only allow svg and associated tags
|
|
163
|
+
// Note that these are some of the big offenders that are left out:
|
|
164
|
+
// 'script', 'image', 'foreignObject', 'object', 'use'
|
|
165
|
+
//
|
|
166
|
+
// To support more mimeTypes, remove the ALLOWED_TAGS array fully.
|
|
167
|
+
//
|
|
168
|
+
// src: https://github.com/cure53/DOMPurify/blob/2c66eb1f6ae39cc7001a97889a9bb78b688a6f99/src/tags.js#L124
|
|
169
|
+
ALLOWED_TAGS: [
|
|
170
|
+
'svg',
|
|
171
|
+
'altglyph',
|
|
172
|
+
'altglyphdef',
|
|
173
|
+
'altglyphitem',
|
|
174
|
+
'animatecolor',
|
|
175
|
+
'animatemotion',
|
|
176
|
+
'animatetransform',
|
|
177
|
+
'circle',
|
|
178
|
+
'clippath',
|
|
179
|
+
'defs',
|
|
180
|
+
'desc',
|
|
181
|
+
'ellipse',
|
|
182
|
+
'filter',
|
|
183
|
+
'font',
|
|
184
|
+
'g',
|
|
185
|
+
'glyph',
|
|
186
|
+
'glyphref',
|
|
187
|
+
'hkern',
|
|
188
|
+
'line',
|
|
189
|
+
'lineargradient',
|
|
190
|
+
'marker',
|
|
191
|
+
'mask',
|
|
192
|
+
'metadata',
|
|
193
|
+
'mpath',
|
|
194
|
+
'path',
|
|
195
|
+
'pattern',
|
|
196
|
+
'polygon',
|
|
197
|
+
'polyline',
|
|
198
|
+
'radialgradient',
|
|
199
|
+
'rect',
|
|
200
|
+
'stop',
|
|
201
|
+
'style',
|
|
202
|
+
'switch',
|
|
203
|
+
'symbol',
|
|
204
|
+
'text',
|
|
205
|
+
'textpath',
|
|
206
|
+
'title',
|
|
207
|
+
'tref',
|
|
208
|
+
'tspan',
|
|
209
|
+
'view',
|
|
210
|
+
'vkern',
|
|
211
|
+
],
|
|
212
|
+
// These are required for svg animate tags
|
|
213
|
+
ADD_ATTR: ['from', 'to', 'animate'],
|
|
214
|
+
FORBID_ATTR: ['image'],
|
|
215
|
+
});
|
|
216
|
+
// eslint-disable-next-line @reddit/i18n-shreddit/no-unwrapped-strings
|
|
217
|
+
let sanitizedDataUrl = `data:${parsedDataUrl.mimeType}`;
|
|
218
|
+
if (parsedDataUrl.charset) {
|
|
219
|
+
sanitizedDataUrl += `;charset=${parsedDataUrl.charset}`;
|
|
220
|
+
}
|
|
221
|
+
if (parsedDataUrl.isBase64) {
|
|
222
|
+
// eslint-disable-next-line @reddit/i18n-shreddit/no-unwrapped-strings
|
|
223
|
+
sanitizedDataUrl += `;base64`;
|
|
224
|
+
}
|
|
225
|
+
/**
|
|
226
|
+
* In data url land there are characters that need to be encoded that
|
|
227
|
+
* a user may have passed in like hex-code colors that will break
|
|
228
|
+
* the image without giving any relevant messages. To be safe, we
|
|
229
|
+
* encode the entire sanitized string.
|
|
230
|
+
*
|
|
231
|
+
* More info:
|
|
232
|
+
* https://stackoverflow.com/questions/69216560/why-hexadecimal-color-dont-work-with-utf8-data-url-s-for-svg
|
|
233
|
+
*
|
|
234
|
+
* You may be able to get away with just replacing # with %23 in case
|
|
235
|
+
* people complain about the data url being hard to read.
|
|
236
|
+
*/
|
|
237
|
+
sanitizedDataUrl += `,${parsedDataUrl.isBase64 ? btoa(sanitized) : encodeURIComponent(sanitized)}`;
|
|
238
|
+
return sanitizedDataUrl;
|
|
239
|
+
}
|
|
240
|
+
catch (error) {
|
|
241
|
+
return '';
|
|
242
|
+
}
|
|
243
|
+
}
|
|
70
244
|
export function isValidImageURL(imageUrl) {
|
|
71
245
|
try {
|
|
246
|
+
if (isDataUrl(imageUrl))
|
|
247
|
+
return isAcceptableDataUrl(imageUrl);
|
|
72
248
|
// The second "base" param helps to handle relative paths to local files
|
|
73
249
|
// https://developer.mozilla.org/en-US/docs/Web/API/URL/URL#parameters
|
|
74
250
|
const hostName = new URL(imageUrl, `https://i.${REDD_IT}`)?.hostname;
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@devvit/ui-renderer",
|
|
3
|
-
"version": "0.10.10-next-2023-11-14-
|
|
3
|
+
"version": "0.10.10-next-2023-11-14-fabd613d1.0",
|
|
4
4
|
"license": "BSD-3-Clause",
|
|
5
5
|
"repository": {
|
|
6
6
|
"type": "git",
|
|
@@ -54,10 +54,11 @@
|
|
|
54
54
|
},
|
|
55
55
|
"types": "./index.d.ts",
|
|
56
56
|
"dependencies": {
|
|
57
|
-
"@devvit/protos": "0.10.10-next-2023-11-14-
|
|
58
|
-
"@devvit/runtime-lite": "0.10.10-next-2023-11-14-
|
|
59
|
-
"@devvit/runtimes": "0.10.10-next-2023-11-14-
|
|
57
|
+
"@devvit/protos": "0.10.10-next-2023-11-14-fabd613d1.0",
|
|
58
|
+
"@devvit/runtime-lite": "0.10.10-next-2023-11-14-fabd613d1.0",
|
|
59
|
+
"@devvit/runtimes": "0.10.10-next-2023-11-14-fabd613d1.0",
|
|
60
60
|
"@lottiefiles/lottie-player": "1.7.1",
|
|
61
|
+
"isomorphic-dompurify": "1.9.0",
|
|
61
62
|
"p-queue": "7.3.4",
|
|
62
63
|
"rxjs": "7.5.7"
|
|
63
64
|
},
|
|
@@ -83,11 +84,12 @@
|
|
|
83
84
|
"devDependencies": {
|
|
84
85
|
"@devvit/eslint-config": "0.10.9",
|
|
85
86
|
"@devvit/repo-tools": "0.10.9",
|
|
86
|
-
"@devvit/tsconfig": "0.10.10-next-2023-11-14-
|
|
87
|
+
"@devvit/tsconfig": "0.10.10-next-2023-11-14-fabd613d1.0",
|
|
87
88
|
"@lit/localize": "0.11.4",
|
|
88
89
|
"@open-wc/testing-helpers": "2.3.0",
|
|
89
90
|
"@reddit/baseplate": "0.14.0",
|
|
90
91
|
"@reddit/eslint-plugin-i18n-shreddit": "0.1.0",
|
|
92
|
+
"@types/dompurify": "3.0.5",
|
|
91
93
|
"autoprefixer": "10.4.14",
|
|
92
94
|
"backstopjs": "6.2.1",
|
|
93
95
|
"chokidar": "3.5.3",
|
|
@@ -112,5 +114,5 @@
|
|
|
112
114
|
"directory": "dist"
|
|
113
115
|
},
|
|
114
116
|
"source": "./src/index.ts",
|
|
115
|
-
"gitHead": "
|
|
117
|
+
"gitHead": "6f6cadcdc83bf711b273e7359ae4976bbaea29b5"
|
|
116
118
|
}
|