Skip to content

Commit 1fdafab

Browse files
authored
fix: Everything (#184)
1 parent 864b67a commit 1fdafab

6 files changed

Lines changed: 68 additions & 44 deletions

File tree

client/src/views/Home.tsx

Lines changed: 15 additions & 13 deletions
Original file line numberDiff line numberDiff line change
@@ -7,13 +7,13 @@ const VALIDATE_URL = import.meta.env.REACT_APP_VALIDATE_URL;
77
const TARGET_URL_PLACEHOLDER = 'http://code.jquery.com/jquery-1.9.1.min.js';
88

99
interface ExampleProps {
10-
name: string,
11-
url: string,
12-
version: string,
13-
onClick: React.MouseEventHandler<HTMLAnchorElement>,
10+
name: string;
11+
url: string;
12+
version: string;
13+
onClick: React.MouseEventHandler<HTMLAnchorElement>;
1414
}
1515

16-
function Example({name, url, version, onClick}: ExampleProps) {
16+
function Example({ name, url, version, onClick }: ExampleProps) {
1717
return (
1818
<li>
1919
<a href={url} onClick={onClick}>
@@ -51,13 +51,12 @@ export default function Home() {
5151
const [isLoading, setIsLoading] = useState(false);
5252

5353
const navigate = useNavigate();
54-
54+
5555
const handleSubmit = useCallback(() => {
56-
const url = encodeURIComponent(targetUrl || TARGET_URL_PLACEHOLDER);
56+
const url = targetUrl || TARGET_URL_PLACEHOLDER;
5757

5858
setIsLoading(true);
5959

60-
// Encode the url again to match whats saved on the server
6160
fetch(`${VALIDATE_URL}?url=${encodeURIComponent(url)}`, {
6261
method: 'POST'
6362
}).then(response => {
@@ -74,10 +73,13 @@ export default function Home() {
7473
return (
7574
<div>
7675
<div className="row">
77-
<form action="/validate" onSubmit={(event: React.FormEvent) => {
78-
event.preventDefault();
79-
handleSubmit();
80-
}}>
76+
<form
77+
action="/validate"
78+
onSubmit={(event: React.FormEvent) => {
79+
event.preventDefault();
80+
handleSubmit();
81+
}}
82+
>
8183
<div className="col-md-10 form-group">
8284
<input
8385
type="text"
@@ -101,7 +103,7 @@ export default function Home() {
101103
<Example
102104
key={index}
103105
{...example}
104-
onClick={(event) => {
106+
onClick={event => {
105107
event.preventDefault();
106108

107109
setTargetUrl(example.url);

server/src/index.ts

Lines changed: 4 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -10,7 +10,7 @@ Sentry.init({
1010
import path from 'path';
1111
import { Request, Response } from 'express';
1212
import { Storage } from '@google-cloud/storage';
13-
import _validateGeneratedFile from './lib/validateGeneratedFile';
13+
import { validateMinifiedFileAtUrl } from './lib/validateGeneratedFile';
1414

1515
let config: { [key: string]: string } = {};
1616
try {
@@ -53,7 +53,7 @@ export function validateGeneratedFile(req: Request, res: Response) {
5353

5454
Sentry.setTag('sourcemap_url', url);
5555

56-
_validateGeneratedFile(url, report => {
56+
validateMinifiedFileAtUrl(url, report => {
5757
const bucket = storage.bucket(config.STORAGE_BUCKET);
5858

5959
// object names can't contain most symbols, so encode as a URI component
@@ -66,10 +66,12 @@ export function validateGeneratedFile(req: Request, res: Response) {
6666
contentType: 'text/plain; charset=utf-8'
6767
}
6868
});
69+
6970
stream.on('error', async err => {
7071
res.status(500).send(err.message);
7172
Sentry.captureException(err);
7273
});
74+
7375
stream.on('finish', async () => {
7476
res.status(200).send(encodeURIComponent(objectName));
7577
});

server/src/lib/__tests__/validateGeneratedFile.spec.ts

Lines changed: 20 additions & 20 deletions
Original file line numberDiff line numberDiff line change
@@ -3,7 +3,7 @@ import fs from 'fs';
33
import path from 'path';
44
import nock from 'nock';
55

6-
import validateGeneratedFile from '../validateGeneratedFile';
6+
import { validateMinifiedFileAtUrl } from '../validateGeneratedFile';
77

88
const {
99
HOST,
@@ -27,7 +27,7 @@ it('should download the target minified file, source maps, and external source f
2727
.get('/static/two.js')
2828
.reply(200, TWO_JS);
2929

30-
validateGeneratedFile(url, report => {
30+
validateMinifiedFileAtUrl(url, report => {
3131
// verify all mocked requests satisfied
3232
scope.done();
3333

@@ -53,7 +53,7 @@ describe('source map location', () => {
5353
.get('/static/app.js.map')
5454
.reply(200, RAW_INLINE_SOURCE_MAP);
5555

56-
validateGeneratedFile(url, report => {
56+
validateMinifiedFileAtUrl(url, report => {
5757
expect(report.errors).toHaveLength(0);
5858
done();
5959
});
@@ -71,7 +71,7 @@ describe('source map location', () => {
7171
.get(appPath)
7272
.reply(200, fs.readFileSync(minFilePath, 'utf-8'));
7373

74-
validateGeneratedFile(url, report => {
74+
validateMinifiedFileAtUrl(url, report => {
7575
expect(report.errors).toHaveLength(0);
7676
done();
7777
});
@@ -85,7 +85,7 @@ describe('source map location', () => {
8585
nock(HOST)
8686
.get('/static/app.js.map')
8787
.reply(200, RAW_INLINE_SOURCE_MAP);
88-
validateGeneratedFile(url, report => {
88+
validateMinifiedFileAtUrl(url, report => {
8989
expect(report.errors).toHaveLength(0);
9090
done();
9191
});
@@ -101,7 +101,7 @@ describe('source map location', () => {
101101
.get('/static/app.js.map')
102102
.reply(200, RAW_INLINE_SOURCE_MAP);
103103

104-
validateGeneratedFile(url, report => {
104+
validateMinifiedFileAtUrl(url, report => {
105105
expect(report.errors).toHaveLength(0);
106106
done();
107107
});
@@ -118,7 +118,7 @@ describe('source map location', () => {
118118
.get('/static/app.js.map')
119119
.reply(200, RAW_INLINE_SOURCE_MAP);
120120

121-
validateGeneratedFile(url, report => {
121+
validateMinifiedFileAtUrl(url, report => {
122122
expect(report.errors).toHaveLength(0);
123123
done();
124124
});
@@ -129,7 +129,7 @@ describe('source map location', () => {
129129
.get(appPath)
130130
.reply(200, 'function(){}();');
131131

132-
validateGeneratedFile(url, report => {
132+
validateMinifiedFileAtUrl(url, report => {
133133
expect(report.errors).toHaveLength(1);
134134
expect(report.errors[0].name).toBe('SourceMapNotFoundError');
135135
done();
@@ -144,7 +144,7 @@ describe('http failures', () => {
144144
.socketDelay(5001)
145145
.reply(200, '<html></html>');
146146

147-
validateGeneratedFile(url, report => {
147+
validateMinifiedFileAtUrl(url, report => {
148148
expect(report.errors).toHaveLength(1);
149149
expect(report.errors[0].name).toBe('ResourceTimeoutError');
150150
expect(report.errors[0]).toHaveProperty(
@@ -164,7 +164,7 @@ describe('http failures', () => {
164164
.get('/static/app.js.map')
165165
.socketDelay(5001)
166166
.reply(200, RAW_DEFAULT_SOURCE_MAP);
167-
validateGeneratedFile(url, report => {
167+
validateMinifiedFileAtUrl(url, report => {
168168
expect(report.errors).toHaveLength(1);
169169
expect(report.errors[0].name).toBe('ResourceTimeoutError');
170170
expect(report.errors[0]).toHaveProperty(
@@ -180,7 +180,7 @@ describe('http failures', () => {
180180
.get(appPath)
181181
.reply(401, 'Not Authenticated');
182182

183-
validateGeneratedFile(url, report => {
183+
validateMinifiedFileAtUrl(url, report => {
184184
expect(report.errors).toHaveLength(1);
185185
expect(report.errors[0].name).toBe('UnableToFetchMinifiedError');
186186
done();
@@ -198,7 +198,7 @@ describe('http failures', () => {
198198
port: 1337
199199
});
200200

201-
validateGeneratedFile(url, report => {
201+
validateMinifiedFileAtUrl(url, report => {
202202
expect(report.errors).toHaveLength(1);
203203
expect(report.errors[0].name).toBe('ConnectionRefusedError');
204204
done();
@@ -214,7 +214,7 @@ describe('http failures', () => {
214214
.get('/static/app.js.map')
215215
.reply(401, 'Not Authenticated');
216216

217-
validateGeneratedFile(url, report => {
217+
validateMinifiedFileAtUrl(url, report => {
218218
expect(report.errors).toHaveLength(1);
219219
expect(report.errors[0].name).toBe('UnableToFetchSourceMapError');
220220
done();
@@ -232,7 +232,7 @@ describe('http failures', () => {
232232
.get('/static/two.js')
233233
.reply(401, 'Not authenticated');
234234

235-
validateGeneratedFile(url, report => {
235+
validateMinifiedFileAtUrl(url, report => {
236236
// verify all mocked requests satisfied
237237
scope.done();
238238
expect(report.errors).toHaveLength(1);
@@ -252,7 +252,7 @@ describe('parsing failures', () => {
252252
.get('/static/app.js.map')
253253
.reply(200, '!@#(!*@#(*&@');
254254

255-
validateGeneratedFile(url, report => {
255+
validateMinifiedFileAtUrl(url, report => {
256256
expect(report.errors).toHaveLength(1);
257257
expect(report.errors[0].name).toBe('InvalidJSONError');
258258
expect(report.errors[0]).toHaveProperty(
@@ -272,7 +272,7 @@ describe('parsing failures', () => {
272272
.get('/static/app.js.map')
273273
.reply(200, '{"version":"3"}');
274274

275-
validateGeneratedFile(url, report => {
275+
validateMinifiedFileAtUrl(url, report => {
276276
expect(report.errors).toHaveLength(1);
277277
expect(report.errors[0].name).toBe('InvalidSourceMapFormatError');
278278
expect(report.errors[0]).toHaveProperty(
@@ -296,7 +296,7 @@ describe('content failures', () => {
296296
.get('/static/two.js')
297297
.reply(200, ' \n\n\n<!DOCTYPE html><html>lol</html>');
298298

299-
validateGeneratedFile(url, report => {
299+
validateMinifiedFileAtUrl(url, report => {
300300
scope.done();
301301
expect(report.errors).toHaveLength(1);
302302
expect(report.errors[0].name).toBe('BadContentError');
@@ -327,7 +327,7 @@ describe('mappings', () => {
327327
.get('/static/add.inlineSources.js.map')
328328
.reply(200, fs.readFileSync(mapFilePath, 'utf-8'));
329329

330-
validateGeneratedFile(url, report => {
330+
validateMinifiedFileAtUrl(url, report => {
331331
expect(report.errors).toHaveLength(0);
332332
done();
333333
});
@@ -349,7 +349,7 @@ describe('mappings', () => {
349349
.get('/static/add.fuzzLines.js.map')
350350
.reply(200, fs.readFileSync(mapFilePath, 'utf-8'));
351351

352-
validateGeneratedFile(url, report => {
352+
validateMinifiedFileAtUrl(url, report => {
353353
expect(report.errors).not.toHaveLength(0);
354354
expect(report.errors[0].name).toBe('BadTokenError');
355355
expect(report.errors[0]).toHaveProperty(
@@ -376,7 +376,7 @@ describe('mappings', () => {
376376
.get('/static/add.fuzzColumns.js.map')
377377
.reply(200, fs.readFileSync(mapFilePath, 'utf-8'));
378378

379-
validateGeneratedFile(url, report => {
379+
validateMinifiedFileAtUrl(url, report => {
380380
expect(report.warnings).not.toHaveLength(0);
381381
expect(report.warnings[0].name).toBe('BadColumnError');
382382
expect(report.warnings[0]).toHaveProperty(

server/src/lib/errors.ts

Lines changed: 13 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -169,6 +169,17 @@ class BadColumnError extends BadTokenError {
169169
}
170170
}
171171

172+
class UnknownError extends Error {
173+
resolutions: Array<string>;
174+
175+
constructor(url: string) {
176+
super();
177+
this.name = 'UnknownError';
178+
this.message = `An unknown error occurred for url: ${url}`;
179+
this.resolutions = ['Try again.'];
180+
}
181+
}
182+
172183
export {
173184
SourceMapNotFoundError,
174185
UnableToFetchError,
@@ -182,5 +193,6 @@ export {
182193
BadContentError,
183194
BadColumnError,
184195
ResourceTimeoutError,
185-
ConnectionRefusedError as SocketRefusedError
196+
ConnectionRefusedError as SocketRefusedError,
197+
UnknownError
186198
};

server/src/lib/validateGeneratedFile.ts

Lines changed: 10 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -7,34 +7,39 @@ import {
77
SourceMapNotFoundError,
88
UnableToFetchMinifiedError,
99
ResourceTimeoutError,
10-
SocketRefusedError
10+
SocketRefusedError,
11+
UnknownError
1112
} from './errors';
1213
import { MAX_TIMEOUT } from './constants';
1314
import { resolveUrl, getSourceMapLocation } from './utils';
15+
import { setTag } from '@sentry/node';
1416

1517
/**
1618
* Validates a target transpiled/minified file located at a given url
1719
* @param {string} url The target URL of the generated (transpiled) file,
1820
* e.g. https://example.com/static/app.min.js
1921
* @param {function} callback Invoked when validation is finished, passed a Report object
2022
*/
21-
export default function validateGeneratedFile(
23+
export function validateMinifiedFileAtUrl(
2224
url: string,
2325
callback: (report: Report) => void
2426
) {
2527
const report = new Report({ url });
2628

2729
request(url, { timeout: MAX_TIMEOUT }, (error, response, body) => {
2830
if (error) {
31+
setTag('outgoing_request_had_error', true);
32+
2933
if (error.message === 'ESOCKETTIMEDOUT') {
3034
report.pushError(new ResourceTimeoutError(url, MAX_TIMEOUT));
31-
return void callback(report);
3235
} else if (error.code === 'ECONNREFUSED') {
3336
report.pushError(new SocketRefusedError(url));
34-
return void callback(report);
37+
} else {
38+
report.pushError(new UnknownError(url));
3539
}
3640

37-
return void console.error(error);
41+
callback(report);
42+
return;
3843
}
3944

4045
if (response && response.statusCode !== 200) {

server/src/lib/validateSourceMap.ts

Lines changed: 6 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -20,7 +20,8 @@ import {
2020
InvalidSourceMapFormatError,
2121
InvalidJSONError,
2222
BadContentError,
23-
ResourceTimeoutError
23+
ResourceTimeoutError,
24+
UnknownError
2425
} from './errors';
2526

2627
import { MAX_TIMEOUT } from './constants';
@@ -70,9 +71,11 @@ export default function validateSourceMap(
7071
if (error) {
7172
if (error.message === 'ESOCKETTIMEDOUT') {
7273
report.pushError(new ResourceTimeoutError(sourceMapUrl, MAX_TIMEOUT));
73-
return void reportCallback(report);
74+
} else {
75+
report.pushError(new UnknownError(sourceMapUrl));
7476
}
75-
return void console.error(error);
77+
reportCallback(report);
78+
return;
7679
}
7780

7881
if (response && response.statusCode !== 200) {

0 commit comments

Comments
 (0)