@atlaspack/reporter-dev-server 2.14.5-canary.49 → 2.14.5-canary.490

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 (39) hide show
  1. package/CHANGELOG.md +496 -0
  2. package/dist/HMRServer.js +220 -0
  3. package/dist/Server.js +408 -0
  4. package/dist/ServerDataProvider.js +2 -0
  5. package/dist/ServerReporter.js +135 -0
  6. package/dist/StaticServerDataProvider.js +51 -0
  7. package/dist/serverErrors.js +16 -0
  8. package/dist/types.js +2 -0
  9. package/lib/HMRServer.js +270 -0
  10. package/lib/Server.js +466 -0
  11. package/lib/ServerDataProvider.js +1 -0
  12. package/lib/ServerReporter.js +137 -17455
  13. package/lib/StaticServerDataProvider.js +58 -0
  14. package/lib/launch-editor.d.js +1 -0
  15. package/lib/serverErrors.js +20 -0
  16. package/lib/types/HMRServer.d.ts +54 -0
  17. package/lib/types/Server.d.ts +45 -0
  18. package/lib/types/ServerDataProvider.d.ts +33 -0
  19. package/lib/types/ServerReporter.d.ts +3 -0
  20. package/lib/types/StaticServerDataProvider.d.ts +23 -0
  21. package/lib/types/serverErrors.d.ts +4 -0
  22. package/lib/types/types.d.ts +34 -0
  23. package/lib/types.js +1 -0
  24. package/package.json +19 -11
  25. package/src/{HMRServer.js → HMRServer.ts} +61 -35
  26. package/src/{Server.js → Server.ts} +52 -38
  27. package/src/ServerDataProvider.ts +34 -0
  28. package/src/{ServerReporter.js → ServerReporter.ts} +3 -5
  29. package/src/StaticServerDataProvider.ts +72 -0
  30. package/src/launch-editor.d.ts +4 -0
  31. package/src/{serverErrors.js → serverErrors.ts} +6 -5
  32. package/src/types.ts +46 -0
  33. package/{src/templates → templates}/404.html +1 -1
  34. package/{src/templates → templates}/500.html +1 -1
  35. package/test/StaticServerDataProvider.test.ts +131 -0
  36. package/tsconfig.json +18 -0
  37. package/tsconfig.tsbuildinfo +1 -0
  38. package/lib/ServerReporter.js.map +0 -1
  39. package/src/types.js.flow +0 -56
package/lib/Server.js ADDED
@@ -0,0 +1,466 @@
1
+ "use strict";
2
+
3
+ Object.defineProperty(exports, "__esModule", {
4
+ value: true
5
+ });
6
+ exports.default = exports.SOURCES_ENDPOINT = void 0;
7
+ exports.setHeaders = setHeaders;
8
+ function _assert() {
9
+ const data = _interopRequireDefault(require("assert"));
10
+ _assert = function () {
11
+ return data;
12
+ };
13
+ return data;
14
+ }
15
+ function _path() {
16
+ const data = _interopRequireDefault(require("path"));
17
+ _path = function () {
18
+ return data;
19
+ };
20
+ return data;
21
+ }
22
+ function _url() {
23
+ const data = _interopRequireWildcard(require("url"));
24
+ _url = function () {
25
+ return data;
26
+ };
27
+ return data;
28
+ }
29
+ function _utils() {
30
+ const data = require("@atlaspack/utils");
31
+ _utils = function () {
32
+ return data;
33
+ };
34
+ return data;
35
+ }
36
+ var _serverErrors = _interopRequireDefault(require("./serverErrors"));
37
+ function _fs() {
38
+ const data = _interopRequireDefault(require("fs"));
39
+ _fs = function () {
40
+ return data;
41
+ };
42
+ return data;
43
+ }
44
+ function _ejs() {
45
+ const data = _interopRequireDefault(require("ejs"));
46
+ _ejs = function () {
47
+ return data;
48
+ };
49
+ return data;
50
+ }
51
+ function _connect() {
52
+ const data = _interopRequireDefault(require("connect"));
53
+ _connect = function () {
54
+ return data;
55
+ };
56
+ return data;
57
+ }
58
+ function _serveHandler() {
59
+ const data = _interopRequireDefault(require("serve-handler"));
60
+ _serveHandler = function () {
61
+ return data;
62
+ };
63
+ return data;
64
+ }
65
+ function _httpProxyMiddleware() {
66
+ const data = require("http-proxy-middleware");
67
+ _httpProxyMiddleware = function () {
68
+ return data;
69
+ };
70
+ return data;
71
+ }
72
+ function _launchEditor() {
73
+ const data = _interopRequireDefault(require("launch-editor"));
74
+ _launchEditor = function () {
75
+ return data;
76
+ };
77
+ return data;
78
+ }
79
+ function _fresh() {
80
+ const data = _interopRequireDefault(require("fresh"));
81
+ _fresh = function () {
82
+ return data;
83
+ };
84
+ return data;
85
+ }
86
+ function _interopRequireWildcard(e, t) { if ("function" == typeof WeakMap) var r = new WeakMap(), n = new WeakMap(); return (_interopRequireWildcard = function (e, t) { if (!t && e && e.__esModule) return e; var o, i, f = { __proto__: null, default: e }; if (null === e || "object" != typeof e && "function" != typeof e) return f; if (o = t ? n : r) { if (o.has(e)) return o.get(e); o.set(e, f); } for (const t in e) "default" !== t && {}.hasOwnProperty.call(e, t) && ((i = (o = Object.defineProperty) && Object.getOwnPropertyDescriptor(e, t)) && (i.get || i.set) ? o(f, t, i) : f[t] = e[t]); return f; })(e, t); }
87
+ function _interopRequireDefault(e) { return e && e.__esModule ? e : { default: e }; }
88
+ // @ts-expect-error TS2307
89
+
90
+ function setHeaders(res) {
91
+ res.setHeader('Access-Control-Allow-Origin', '*');
92
+ res.setHeader('Access-Control-Allow-Methods', 'GET, HEAD, PUT, PATCH, POST, DELETE');
93
+ res.setHeader('Access-Control-Allow-Headers', 'Origin, X-Requested-With, Content-Type, Accept, Content-Type');
94
+ res.setHeader('Cache-Control', 'max-age=0, must-revalidate');
95
+ }
96
+ const SLASH_REGEX = /\//g;
97
+ const SOURCES_ENDPOINT = exports.SOURCES_ENDPOINT = '/__parcel_source_root';
98
+ const EDITOR_ENDPOINT = '/__parcel_launch_editor';
99
+ const TEMPLATE_404 = _fs().default.readFileSync(_path().default.join(__dirname, '..', 'templates/404.html'), 'utf8');
100
+ const TEMPLATE_500 = _fs().default.readFileSync(_path().default.join(__dirname, '..', 'templates/500.html'), 'utf8');
101
+ class Server {
102
+ constructor(options) {
103
+ this.options = options;
104
+ try {
105
+ this.rootPath = new (_url().URL)(options.publicUrl).pathname;
106
+ } catch (e) {
107
+ this.rootPath = options.publicUrl;
108
+ }
109
+ this.pending = true;
110
+ this.pendingRequests = [];
111
+ this.middleware = [];
112
+ this.bundleGraph = null;
113
+ this.requestBundle = null;
114
+ this.errors = null;
115
+ }
116
+ buildStart() {
117
+ this.pending = true;
118
+ }
119
+ buildSuccess(bundleGraph, requestBundle) {
120
+ this.bundleGraph = bundleGraph;
121
+ this.requestBundle = requestBundle;
122
+ this.errors = null;
123
+ this.pending = false;
124
+ if (this.pendingRequests.length > 0) {
125
+ let pendingRequests = this.pendingRequests;
126
+ this.pendingRequests = [];
127
+ for (let [req, res] of pendingRequests) {
128
+ this.respond(req, res);
129
+ }
130
+ }
131
+ }
132
+ async buildError(options, diagnostics) {
133
+ this.pending = false;
134
+ this.errors = await Promise.all(diagnostics.map(async d => {
135
+ let ansiDiagnostic = await (0, _utils().prettyDiagnostic)(d, options);
136
+ return {
137
+ message: (0, _utils().ansiHtml)(ansiDiagnostic.message),
138
+ stack: ansiDiagnostic.stack ? (0, _utils().ansiHtml)(ansiDiagnostic.stack) : null,
139
+ frames: ansiDiagnostic.frames.map(f => ({
140
+ location: f.location,
141
+ code: (0, _utils().ansiHtml)(f.code)
142
+ })),
143
+ hints: ansiDiagnostic.hints.map(hint => (0, _utils().ansiHtml)(hint)),
144
+ documentation: d.documentationURL ?? ''
145
+ };
146
+ }));
147
+ }
148
+ respond(req, res) {
149
+ if (this.middleware.some(handler => handler(req, res))) return;
150
+ let {
151
+ pathname,
152
+ search
153
+ } = _url().default.parse(req.originalUrl || req.url);
154
+ if (pathname == null) {
155
+ pathname = '/';
156
+ }
157
+ if (pathname.startsWith(EDITOR_ENDPOINT) && search) {
158
+ let query = new (_url().URLSearchParams)(search);
159
+ let file = query.get('file');
160
+ if (file) {
161
+ // File location might start with /__parcel_source_root if it came from a source map.
162
+ if (file.startsWith(SOURCES_ENDPOINT)) {
163
+ file = file.slice(SOURCES_ENDPOINT.length + 1);
164
+ }
165
+ (0, _launchEditor().default)(file);
166
+ }
167
+ res.end();
168
+ } else if (this.errors) {
169
+ return this.send500(req, res);
170
+ } else if (_path().default.extname(pathname) === '') {
171
+ // If the URL doesn't start with the public path, or the URL doesn't
172
+ // have a file extension, send the main HTML bundle.
173
+ return this.sendIndex(req, res);
174
+ } else if (pathname.startsWith(SOURCES_ENDPOINT)) {
175
+ req.url = pathname.slice(SOURCES_ENDPOINT.length);
176
+ return this.serve(this.options.inputFS, this.options.projectRoot, req, res, () => this.send404(req, res));
177
+ } else if (pathname.startsWith(this.rootPath)) {
178
+ // Otherwise, serve the file from the dist folder
179
+ req.url = this.rootPath === '/' ? pathname : pathname.slice(this.rootPath.length);
180
+ if (req.url[0] !== '/') {
181
+ req.url = '/' + req.url;
182
+ }
183
+ return this.serveBundle(req, res, () => this.sendIndex(req, res));
184
+ } else {
185
+ return this.send404(req, res);
186
+ }
187
+ }
188
+ sendIndex(req, res) {
189
+ if (this.bundleGraph) {
190
+ // If the main asset is an HTML file, serve it
191
+ let htmlBundleFilePaths = this.bundleGraph.getBundles().filter(bundle => _path().default.posix.extname(bundle.name) === '.html').map(bundle => {
192
+ return `/${(0, _utils().relativePath)(this.options.distDir, bundle.filePath, false)}`;
193
+ });
194
+ let indexFilePath = null;
195
+ let {
196
+ pathname: reqURL
197
+ } = _url().default.parse(req.originalUrl || req.url);
198
+ if (!reqURL) {
199
+ reqURL = '/';
200
+ }
201
+ if (htmlBundleFilePaths.length === 1) {
202
+ indexFilePath = htmlBundleFilePaths[0];
203
+ } else {
204
+ var _bestMatch;
205
+ let bestMatch = null;
206
+ for (let bundle of htmlBundleFilePaths) {
207
+ let bundleDir = _path().default.posix.dirname(bundle);
208
+ let bundleDirSubdir = bundleDir === '/' ? bundleDir : bundleDir + '/';
209
+ let withoutExtension = _path().default.posix.basename(bundle, _path().default.posix.extname(bundle));
210
+ let isIndex = withoutExtension === 'index';
211
+ let matchesIsIndex = null;
212
+ if (isIndex && (reqURL.startsWith(bundleDirSubdir) || reqURL === bundleDir)) {
213
+ // bundle is /bar/index.html and (/bar or something inside of /bar/** was requested was requested)
214
+ matchesIsIndex = true;
215
+ } else if (reqURL == _path().default.posix.join(bundleDir, withoutExtension)) {
216
+ // bundle is /bar/foo.html and /bar/foo was requested
217
+ matchesIsIndex = false;
218
+ }
219
+ if (matchesIsIndex != null) {
220
+ var _bundle$match;
221
+ let depth = ((_bundle$match = bundle.match(SLASH_REGEX)) === null || _bundle$match === void 0 ? void 0 : _bundle$match.length) ?? 0;
222
+ if (bestMatch == null ||
223
+ // This one is more specific (deeper)
224
+ bestMatch.depth < depth ||
225
+ // This one is just as deep, but the bundle name matches and not just index.html
226
+ bestMatch.depth === depth && bestMatch.isIndex) {
227
+ bestMatch = {
228
+ bundle,
229
+ depth,
230
+ isIndex: matchesIsIndex
231
+ };
232
+ }
233
+ }
234
+ }
235
+ indexFilePath = ((_bestMatch = bestMatch) === null || _bestMatch === void 0 ? void 0 : _bestMatch['bundle']) ?? htmlBundleFilePaths[0];
236
+ }
237
+ if (indexFilePath) {
238
+ req.url = indexFilePath;
239
+ this.serveBundle(req, res, () => this.send404(req, res));
240
+ } else {
241
+ this.send404(req, res);
242
+ }
243
+ } else {
244
+ this.send404(req, res);
245
+ }
246
+ }
247
+ async serveBundle(req, res, next) {
248
+ let bundleGraph = this.bundleGraph;
249
+ if (bundleGraph) {
250
+ let {
251
+ pathname
252
+ } = _url().default.parse(req.url);
253
+ if (!pathname) {
254
+ this.send500(req, res);
255
+ return;
256
+ }
257
+ let requestedPath = _path().default.normalize(pathname.slice(1));
258
+ let bundle = bundleGraph.getBundles().find(b => _path().default.relative(this.options.distDir, b.filePath) === requestedPath);
259
+ if (!bundle) {
260
+ this.serveDist(req, res, next);
261
+ return;
262
+ }
263
+ (0, _assert().default)(this.requestBundle != null);
264
+ try {
265
+ await this.requestBundle(bundle);
266
+ } catch (err) {
267
+ this.send500(req, res);
268
+ return;
269
+ }
270
+ this.serveDist(req, res, next);
271
+ } else {
272
+ this.send404(req, res);
273
+ }
274
+ }
275
+ serveDist(req, res, next) {
276
+ return this.serve(this.options.outputFS, this.options.distDir, req, res, next);
277
+ }
278
+ async serve(fs, root, req, res, next) {
279
+ if (req.method !== 'GET' && req.method !== 'HEAD') {
280
+ // method not allowed
281
+ res.statusCode = 405;
282
+ res.setHeader('Allow', 'GET, HEAD');
283
+ res.setHeader('Content-Length', '0');
284
+ res.end();
285
+ return;
286
+ }
287
+ try {
288
+ var filePath = _url().default.parse(req.url).pathname || '';
289
+ filePath = decodeURIComponent(filePath);
290
+ } catch (err) {
291
+ return this.sendError(res, 400);
292
+ }
293
+ filePath = _path().default.normalize('.' + _path().default.sep + filePath);
294
+
295
+ // malicious path
296
+ if (filePath.includes(_path().default.sep + '..' + _path().default.sep)) {
297
+ return this.sendError(res, 403);
298
+ }
299
+
300
+ // join / normalize from the root dir
301
+ if (!_path().default.isAbsolute(filePath)) {
302
+ filePath = _path().default.normalize(_path().default.join(root, filePath));
303
+ }
304
+ try {
305
+ var stat = await fs.stat(filePath);
306
+ } catch (err) {
307
+ if (err.code === 'ENOENT') {
308
+ return next(req, res);
309
+ }
310
+ return this.sendError(res, 500);
311
+ }
312
+
313
+ // Fall back to next handler if not a file
314
+ if (!stat || !stat.isFile()) {
315
+ return next(req, res);
316
+ }
317
+ if ((0, _fresh().default)(req.headers, {
318
+ 'last-modified': stat.mtime.toUTCString()
319
+ })) {
320
+ res.statusCode = 304;
321
+ res.end();
322
+ return;
323
+ }
324
+ return (0, _serveHandler().default)(req, res, {
325
+ public: root,
326
+ cleanUrls: false
327
+ }, {
328
+ // @ts-expect-error TS7006
329
+ lstat: path => fs.stat(path),
330
+ // @ts-expect-error TS7006
331
+ realpath: path => fs.realpath(path),
332
+ // @ts-expect-error TS7006
333
+ createReadStream: (path, options) => fs.createReadStream(path, options),
334
+ // @ts-expect-error TS7006
335
+ readdir: path => fs.readdir(path)
336
+ });
337
+ }
338
+ sendError(res, statusCode) {
339
+ res.statusCode = statusCode;
340
+ res.end();
341
+ }
342
+ send404(req, res) {
343
+ res.statusCode = 404;
344
+ res.end(TEMPLATE_404);
345
+ }
346
+ send500(req, res) {
347
+ res.setHeader('Content-Type', 'text/html; charset=utf-8');
348
+ res.writeHead(500);
349
+ if (this.errors) {
350
+ return res.end(_ejs().default.render(TEMPLATE_500, {
351
+ errors: this.errors,
352
+ hmrOptions: this.options.hmrOptions
353
+ }));
354
+ }
355
+ }
356
+ logAccessIfVerbose(req) {
357
+ this.options.logger.verbose({
358
+ message: `Request: ${req.headers.host}${req.originalUrl || req.url}`
359
+ });
360
+ }
361
+
362
+ /**
363
+ * Load proxy table from package.json and apply them.
364
+ */
365
+ async applyProxyTable(app) {
366
+ // avoid skipping project root
367
+ const fileInRoot = _path().default.join(this.options.projectRoot, 'index');
368
+ const configFilePath = await (0, _utils().resolveConfig)(this.options.inputFS, fileInRoot, ['.proxyrc.cts', '.proxyrc.mts', '.proxyrc.ts', '.proxyrc.cjs', '.proxyrc.mjs', '.proxyrc.js', '.proxyrc', '.proxyrc.json'], this.options.projectRoot);
369
+ if (!configFilePath) {
370
+ return this;
371
+ }
372
+ const filename = _path().default.basename(configFilePath);
373
+ if (filename === '.proxyrc' || filename === '.proxyrc.json') {
374
+ let conf = await (0, _utils().readConfig)(this.options.inputFS, configFilePath);
375
+ if (!conf) {
376
+ return this;
377
+ }
378
+ let cfg = conf.config;
379
+ if (typeof cfg !== 'object') {
380
+ this.options.logger.warn({
381
+ message: "Proxy table in '.proxyrc' should be of object type. Skipping..."
382
+ });
383
+ return this;
384
+ }
385
+ for (const [context, options] of Object.entries(cfg)) {
386
+ // each key is interpreted as context, and value as middleware options
387
+ // @ts-expect-error TS2345
388
+ app.use((0, _httpProxyMiddleware().createProxyMiddleware)(context, options));
389
+ }
390
+ } else {
391
+ let cfg = await this.options.packageManager.require(configFilePath, fileInRoot);
392
+ if (Object.prototype.toString.call(cfg) === '[object Module]') {
393
+ cfg = cfg.default;
394
+ }
395
+ if (typeof cfg !== 'function') {
396
+ this.options.logger.warn({
397
+ message: `Proxy configuration file '${filename}' should export a function. Skipping...`
398
+ });
399
+ return this;
400
+ }
401
+ cfg(app);
402
+ }
403
+ return this;
404
+ }
405
+ async start() {
406
+ const finalHandler = (req, res) => {
407
+ this.logAccessIfVerbose(req);
408
+
409
+ // Wait for the parcelInstance to finish bundling if needed
410
+ if (this.pending) {
411
+ this.pendingRequests.push([req, res]);
412
+ } else {
413
+ this.respond(req, res);
414
+ }
415
+ };
416
+ const app = (0, _connect().default)();
417
+ app.use((req, res, next) => {
418
+ setHeaders(res);
419
+ next();
420
+ });
421
+ app.use((req, res, next) => {
422
+ if (req.url === '/__parcel_healthcheck') {
423
+ res.statusCode = 200;
424
+ res.write(`${Date.now()}`);
425
+ res.end();
426
+ } else {
427
+ next();
428
+ }
429
+ });
430
+ await this.applyProxyTable(app);
431
+ app.use(finalHandler);
432
+ let {
433
+ server,
434
+ stop
435
+ } = await (0, _utils().createHTTPServer)({
436
+ cacheDir: this.options.cacheDir,
437
+ https: this.options.https,
438
+ inputFS: this.options.inputFS,
439
+ listener: app,
440
+ outputFS: this.options.outputFS,
441
+ host: this.options.host
442
+ });
443
+ this.stopServer = stop;
444
+ server.listen(this.options.port, this.options.host);
445
+ // @ts-expect-error TS2322
446
+ return new Promise((resolve, reject) => {
447
+ server.once('error', err => {
448
+ this.options.logger.error({
449
+ // @ts-expect-error TS2345
450
+ message: (0, _serverErrors.default)(err, this.options.port)
451
+ });
452
+ reject(err);
453
+ });
454
+ server.once('listening', () => {
455
+ // @ts-expect-error TS2345
456
+ resolve(server);
457
+ });
458
+ });
459
+ }
460
+ async stop() {
461
+ (0, _assert().default)(this.stopServer != null);
462
+ await this.stopServer();
463
+ this.stopServer = null;
464
+ }
465
+ }
466
+ exports.default = Server;
@@ -0,0 +1 @@
1
+ "use strict";