Skip to content

Commit

Permalink
fix: Everything (#184)
Browse files Browse the repository at this point in the history
  • Loading branch information
lforst authored Jan 29, 2025
1 parent 864b67a commit 1fdafab
Show file tree
Hide file tree
Showing 6 changed files with 68 additions and 44 deletions.
28 changes: 15 additions & 13 deletions client/src/views/Home.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -7,13 +7,13 @@ const VALIDATE_URL = import.meta.env.REACT_APP_VALIDATE_URL;
const TARGET_URL_PLACEHOLDER = 'http://code.jquery.com/jquery-1.9.1.min.js';

interface ExampleProps {
name: string,
url: string,
version: string,
onClick: React.MouseEventHandler<HTMLAnchorElement>,
name: string;
url: string;
version: string;
onClick: React.MouseEventHandler<HTMLAnchorElement>;
}

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

const navigate = useNavigate();

const handleSubmit = useCallback(() => {
const url = encodeURIComponent(targetUrl || TARGET_URL_PLACEHOLDER);
const url = targetUrl || TARGET_URL_PLACEHOLDER;

setIsLoading(true);

// Encode the url again to match whats saved on the server
fetch(`${VALIDATE_URL}?url=${encodeURIComponent(url)}`, {
method: 'POST'
}).then(response => {
Expand All @@ -74,10 +73,13 @@ export default function Home() {
return (
<div>
<div className="row">
<form action="/validate" onSubmit={(event: React.FormEvent) => {
event.preventDefault();
handleSubmit();
}}>
<form
action="/validate"
onSubmit={(event: React.FormEvent) => {
event.preventDefault();
handleSubmit();
}}
>
<div className="col-md-10 form-group">
<input
type="text"
Expand All @@ -101,7 +103,7 @@ export default function Home() {
<Example
key={index}
{...example}
onClick={(event) => {
onClick={event => {
event.preventDefault();

setTargetUrl(example.url);
Expand Down
6 changes: 4 additions & 2 deletions server/src/index.ts
Original file line number Diff line number Diff line change
Expand Up @@ -10,7 +10,7 @@ Sentry.init({
import path from 'path';
import { Request, Response } from 'express';
import { Storage } from '@google-cloud/storage';
import _validateGeneratedFile from './lib/validateGeneratedFile';
import { validateMinifiedFileAtUrl } from './lib/validateGeneratedFile';

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

Sentry.setTag('sourcemap_url', url);

_validateGeneratedFile(url, report => {
validateMinifiedFileAtUrl(url, report => {
const bucket = storage.bucket(config.STORAGE_BUCKET);

// object names can't contain most symbols, so encode as a URI component
Expand All @@ -66,10 +66,12 @@ export function validateGeneratedFile(req: Request, res: Response) {
contentType: 'text/plain; charset=utf-8'
}
});

stream.on('error', async err => {
res.status(500).send(err.message);
Sentry.captureException(err);
});

stream.on('finish', async () => {
res.status(200).send(encodeURIComponent(objectName));
});
Expand Down
40 changes: 20 additions & 20 deletions server/src/lib/__tests__/validateGeneratedFile.spec.ts
Original file line number Diff line number Diff line change
Expand Up @@ -3,7 +3,7 @@ import fs from 'fs';
import path from 'path';
import nock from 'nock';

import validateGeneratedFile from '../validateGeneratedFile';
import { validateMinifiedFileAtUrl } from '../validateGeneratedFile';

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

validateGeneratedFile(url, report => {
validateMinifiedFileAtUrl(url, report => {
// verify all mocked requests satisfied
scope.done();

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

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

validateGeneratedFile(url, report => {
validateMinifiedFileAtUrl(url, report => {
expect(report.errors).toHaveLength(0);
done();
});
Expand All @@ -85,7 +85,7 @@ describe('source map location', () => {
nock(HOST)
.get('/static/app.js.map')
.reply(200, RAW_INLINE_SOURCE_MAP);
validateGeneratedFile(url, report => {
validateMinifiedFileAtUrl(url, report => {
expect(report.errors).toHaveLength(0);
done();
});
Expand All @@ -101,7 +101,7 @@ describe('source map location', () => {
.get('/static/app.js.map')
.reply(200, RAW_INLINE_SOURCE_MAP);

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

validateGeneratedFile(url, report => {
validateMinifiedFileAtUrl(url, report => {
expect(report.errors).toHaveLength(0);
done();
});
Expand All @@ -129,7 +129,7 @@ describe('source map location', () => {
.get(appPath)
.reply(200, 'function(){}();');

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

validateGeneratedFile(url, report => {
validateMinifiedFileAtUrl(url, report => {
expect(report.errors).toHaveLength(1);
expect(report.errors[0].name).toBe('ResourceTimeoutError');
expect(report.errors[0]).toHaveProperty(
Expand All @@ -164,7 +164,7 @@ describe('http failures', () => {
.get('/static/app.js.map')
.socketDelay(5001)
.reply(200, RAW_DEFAULT_SOURCE_MAP);
validateGeneratedFile(url, report => {
validateMinifiedFileAtUrl(url, report => {
expect(report.errors).toHaveLength(1);
expect(report.errors[0].name).toBe('ResourceTimeoutError');
expect(report.errors[0]).toHaveProperty(
Expand All @@ -180,7 +180,7 @@ describe('http failures', () => {
.get(appPath)
.reply(401, 'Not Authenticated');

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

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

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

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

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

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

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

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

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

validateGeneratedFile(url, report => {
validateMinifiedFileAtUrl(url, report => {
expect(report.warnings).not.toHaveLength(0);
expect(report.warnings[0].name).toBe('BadColumnError');
expect(report.warnings[0]).toHaveProperty(
Expand Down
14 changes: 13 additions & 1 deletion server/src/lib/errors.ts
Original file line number Diff line number Diff line change
Expand Up @@ -169,6 +169,17 @@ class BadColumnError extends BadTokenError {
}
}

class UnknownError extends Error {
resolutions: Array<string>;

constructor(url: string) {
super();
this.name = 'UnknownError';
this.message = `An unknown error occurred for url: ${url}`;
this.resolutions = ['Try again.'];
}
}

export {
SourceMapNotFoundError,
UnableToFetchError,
Expand All @@ -182,5 +193,6 @@ export {
BadContentError,
BadColumnError,
ResourceTimeoutError,
ConnectionRefusedError as SocketRefusedError
ConnectionRefusedError as SocketRefusedError,
UnknownError
};
15 changes: 10 additions & 5 deletions server/src/lib/validateGeneratedFile.ts
Original file line number Diff line number Diff line change
Expand Up @@ -7,34 +7,39 @@ import {
SourceMapNotFoundError,
UnableToFetchMinifiedError,
ResourceTimeoutError,
SocketRefusedError
SocketRefusedError,
UnknownError
} from './errors';
import { MAX_TIMEOUT } from './constants';
import { resolveUrl, getSourceMapLocation } from './utils';
import { setTag } from '@sentry/node';

/**
* Validates a target transpiled/minified file located at a given url
* @param {string} url The target URL of the generated (transpiled) file,
* e.g. https://example.com/static/app.min.js
* @param {function} callback Invoked when validation is finished, passed a Report object
*/
export default function validateGeneratedFile(
export function validateMinifiedFileAtUrl(
url: string,
callback: (report: Report) => void
) {
const report = new Report({ url });

request(url, { timeout: MAX_TIMEOUT }, (error, response, body) => {
if (error) {
setTag('outgoing_request_had_error', true);

if (error.message === 'ESOCKETTIMEDOUT') {
report.pushError(new ResourceTimeoutError(url, MAX_TIMEOUT));
return void callback(report);
} else if (error.code === 'ECONNREFUSED') {
report.pushError(new SocketRefusedError(url));
return void callback(report);
} else {
report.pushError(new UnknownError(url));
}

return void console.error(error);
callback(report);
return;
}

if (response && response.statusCode !== 200) {
Expand Down
9 changes: 6 additions & 3 deletions server/src/lib/validateSourceMap.ts
Original file line number Diff line number Diff line change
Expand Up @@ -20,7 +20,8 @@ import {
InvalidSourceMapFormatError,
InvalidJSONError,
BadContentError,
ResourceTimeoutError
ResourceTimeoutError,
UnknownError
} from './errors';

import { MAX_TIMEOUT } from './constants';
Expand Down Expand Up @@ -70,9 +71,11 @@ export default function validateSourceMap(
if (error) {
if (error.message === 'ESOCKETTIMEDOUT') {
report.pushError(new ResourceTimeoutError(sourceMapUrl, MAX_TIMEOUT));
return void reportCallback(report);
} else {
report.pushError(new UnknownError(sourceMapUrl));
}
return void console.error(error);
reportCallback(report);
return;
}

if (response && response.statusCode !== 200) {
Expand Down

0 comments on commit 1fdafab

Please sign in to comment.