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

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 +505 -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
@@ -0,0 +1,220 @@
1
+ "use strict";
2
+ var __importDefault = (this && this.__importDefault) || function (mod) {
3
+ return (mod && mod.__esModule) ? mod : { "default": mod };
4
+ };
5
+ Object.defineProperty(exports, "__esModule", { value: true });
6
+ const Server_1 = require("./Server");
7
+ const nullthrows_1 = __importDefault(require("nullthrows"));
8
+ const url_1 = __importDefault(require("url"));
9
+ // @ts-expect-error TS7016
10
+ const mime_types_1 = __importDefault(require("mime-types"));
11
+ // @ts-expect-error TS7016
12
+ const ws_1 = __importDefault(require("ws"));
13
+ const assert_1 = __importDefault(require("assert"));
14
+ const utils_1 = require("@atlaspack/utils");
15
+ const FS_CONCURRENCY = 64;
16
+ const HMR_ENDPOINT = '/__parcel_hmr';
17
+ const BROADCAST_MAX_ASSETS = 10000;
18
+ class HMRServer {
19
+ constructor(options) {
20
+ this.unresolvedError = null;
21
+ this.bundleGraph = null;
22
+ this.options = options;
23
+ }
24
+ async start() {
25
+ let server = this.options.devServer;
26
+ if (!server) {
27
+ let result = await (0, utils_1.createHTTPServer)({
28
+ https: this.options.https,
29
+ inputFS: this.options.inputFS,
30
+ outputFS: this.options.outputFS,
31
+ cacheDir: this.options.cacheDir,
32
+ listener: (req, res) => {
33
+ (0, Server_1.setHeaders)(res);
34
+ if (!this.handle(req, res)) {
35
+ res.statusCode = 404;
36
+ res.end();
37
+ }
38
+ },
39
+ });
40
+ server = result.server;
41
+ server.listen(this.options.port, this.options.host);
42
+ this.stopServer = result.stop;
43
+ }
44
+ else {
45
+ this.options.addMiddleware?.((req, res) => this.handle(req, res));
46
+ }
47
+ this.wss = new ws_1.default.Server({ server });
48
+ this.wss.on('connection', (ws) => {
49
+ if (this.unresolvedError) {
50
+ ws.send(JSON.stringify(this.unresolvedError));
51
+ }
52
+ });
53
+ this.wss.on('error', (err) => this.handleSocketError(err));
54
+ }
55
+ handle(req, res) {
56
+ let { pathname } = url_1.default.parse(req.originalUrl || req.url);
57
+ if (pathname != null && pathname.startsWith(HMR_ENDPOINT)) {
58
+ let id = pathname.slice(HMR_ENDPOINT.length + 1);
59
+ let bundleGraph = (0, nullthrows_1.default)(this.bundleGraph);
60
+ let asset = bundleGraph.getAssetById(id);
61
+ this.getHotAssetContents(asset).then((output) => {
62
+ res.setHeader('Content-Type', mime_types_1.default.contentType(asset.type));
63
+ res.end(output);
64
+ });
65
+ return true;
66
+ }
67
+ return false;
68
+ }
69
+ async stop() {
70
+ if (this.stopServer != null) {
71
+ await this.stopServer();
72
+ this.stopServer = null;
73
+ }
74
+ this.wss.close();
75
+ }
76
+ async emitError(options, diagnostics) {
77
+ let renderedDiagnostics = await Promise.all(diagnostics.map((d) => (0, utils_1.prettyDiagnostic)(d, options)));
78
+ // store the most recent error so we can notify new connections
79
+ // and so we can broadcast when the error is resolved
80
+ this.unresolvedError = {
81
+ type: 'error',
82
+ diagnostics: {
83
+ ansi: renderedDiagnostics,
84
+ html: renderedDiagnostics.map((d, i) => {
85
+ return {
86
+ message: (0, utils_1.ansiHtml)(d.message),
87
+ stack: (0, utils_1.ansiHtml)(d.stack),
88
+ frames: d.frames.map((f) => ({
89
+ location: f.location,
90
+ code: (0, utils_1.ansiHtml)(f.code),
91
+ })),
92
+ hints: d.hints.map((hint) => (0, utils_1.ansiHtml)(hint)),
93
+ documentation: diagnostics[i].documentationURL ?? '',
94
+ };
95
+ }),
96
+ },
97
+ };
98
+ this.broadcast(this.unresolvedError);
99
+ }
100
+ async emitUpdate(event) {
101
+ this.unresolvedError = null;
102
+ this.bundleGraph = event.bundleGraph;
103
+ let changedAssets = new Set(event.changedAssets.values());
104
+ if (changedAssets.size === 0)
105
+ return;
106
+ let queue = new utils_1.PromiseQueue({ maxConcurrent: FS_CONCURRENCY });
107
+ for (let asset of changedAssets) {
108
+ if (asset.type !== 'js' && asset.type !== 'css') {
109
+ // If all of the incoming dependencies of the asset actually resolve to a JS asset
110
+ // rather than the original, we can mark the runtimes as changed instead. URL runtimes
111
+ // have a cache busting query param added with HMR enabled which will trigger a reload.
112
+ let runtimes = new Set();
113
+ let incomingDeps = event.bundleGraph.getIncomingDependencies(asset);
114
+ let isOnlyReferencedByRuntimes = incomingDeps.every((dep) => {
115
+ let resolved = event.bundleGraph.getResolvedAsset(dep);
116
+ let isRuntime = resolved?.type === 'js' && resolved !== asset;
117
+ if (resolved && isRuntime) {
118
+ runtimes.add(resolved);
119
+ }
120
+ return isRuntime;
121
+ });
122
+ if (isOnlyReferencedByRuntimes) {
123
+ for (let runtime of runtimes) {
124
+ // @ts-expect-error TS2345
125
+ changedAssets.add(runtime);
126
+ }
127
+ continue;
128
+ }
129
+ }
130
+ queue.add(async () => {
131
+ let dependencies = event.bundleGraph.getDependencies(asset);
132
+ let depsByBundle = {};
133
+ for (let bundle of event.bundleGraph.getBundlesWithAsset(asset)) {
134
+ let deps = {};
135
+ for (let dep of dependencies) {
136
+ let resolved = event.bundleGraph.getResolvedAsset(dep, bundle);
137
+ if (resolved) {
138
+ deps[getSpecifier(dep)] =
139
+ event.bundleGraph.getAssetPublicId(resolved);
140
+ }
141
+ }
142
+ depsByBundle[bundle.id] = deps;
143
+ }
144
+ return {
145
+ id: event.bundleGraph.getAssetPublicId(asset),
146
+ url: this.getSourceURL(asset),
147
+ type: asset.type,
148
+ // No need to send the contents of non-JS assets to the client.
149
+ output: asset.type === 'js' ? await this.getHotAssetContents(asset) : '',
150
+ envHash: asset.env.id,
151
+ outputFormat: asset.env.outputFormat,
152
+ depsByBundle,
153
+ };
154
+ });
155
+ }
156
+ let assets = await queue.run();
157
+ if (assets.length >= BROADCAST_MAX_ASSETS) {
158
+ // Too many assets to send via an update without errors, just reload instead
159
+ this.broadcast({ type: 'reload' });
160
+ }
161
+ else {
162
+ this.broadcast({
163
+ type: 'update',
164
+ // @ts-expect-error TS2322
165
+ assets,
166
+ });
167
+ }
168
+ }
169
+ async getHotAssetContents(asset) {
170
+ let output = await asset.getCode();
171
+ let bundleGraph = (0, nullthrows_1.default)(this.bundleGraph);
172
+ if (asset.type === 'js') {
173
+ let publicId = bundleGraph.getAssetPublicId(asset);
174
+ output = `parcelHotUpdate['${publicId}'] = function (require, module, exports) {${output}}`;
175
+ }
176
+ let sourcemap = await asset.getMap();
177
+ if (sourcemap) {
178
+ let sourcemapStringified = await sourcemap.stringify({
179
+ format: 'inline',
180
+ sourceRoot: Server_1.SOURCES_ENDPOINT + '/',
181
+ fs: asset.fs,
182
+ });
183
+ (0, assert_1.default)(typeof sourcemapStringified === 'string');
184
+ output += `\n//# sourceMappingURL=${sourcemapStringified}`;
185
+ output += `\n//# sourceURL=${encodeURI(this.getSourceURL(asset))}\n`;
186
+ }
187
+ return output;
188
+ }
189
+ getSourceURL(asset) {
190
+ let origin = '';
191
+ if (!this.options.devServer) {
192
+ origin = `http://${this.options.host || 'localhost'}:${this.options.port}`;
193
+ }
194
+ return origin + HMR_ENDPOINT + '/' + asset.id;
195
+ }
196
+ handleSocketError(err) {
197
+ if (err.code === 'ECONNRESET') {
198
+ // This gets triggered on page refresh, ignore this
199
+ return;
200
+ }
201
+ this.options.logger.warn({
202
+ origin: '@atlaspack/reporter-dev-server',
203
+ message: `[${err.code}]: ${err.message}`,
204
+ stack: err.stack,
205
+ });
206
+ }
207
+ broadcast(msg) {
208
+ const json = JSON.stringify(msg);
209
+ for (let ws of this.wss.clients) {
210
+ ws.send(json);
211
+ }
212
+ }
213
+ }
214
+ exports.default = HMRServer;
215
+ function getSpecifier(dep) {
216
+ if (typeof dep.meta.placeholder === 'string') {
217
+ return dep.meta.placeholder;
218
+ }
219
+ return dep.specifier;
220
+ }
package/dist/Server.js ADDED
@@ -0,0 +1,408 @@
1
+ "use strict";
2
+ var __importDefault = (this && this.__importDefault) || function (mod) {
3
+ return (mod && mod.__esModule) ? mod : { "default": mod };
4
+ };
5
+ Object.defineProperty(exports, "__esModule", { value: true });
6
+ exports.SOURCES_ENDPOINT = void 0;
7
+ exports.setHeaders = setHeaders;
8
+ const assert_1 = __importDefault(require("assert"));
9
+ const path_1 = __importDefault(require("path"));
10
+ const url_1 = __importDefault(require("url"));
11
+ const utils_1 = require("@atlaspack/utils");
12
+ const serverErrors_1 = __importDefault(require("./serverErrors"));
13
+ const fs_1 = __importDefault(require("fs"));
14
+ const ejs_1 = __importDefault(require("ejs"));
15
+ const connect_1 = __importDefault(require("connect"));
16
+ const serve_handler_1 = __importDefault(require("serve-handler"));
17
+ const http_proxy_middleware_1 = require("http-proxy-middleware");
18
+ const url_2 = require("url");
19
+ const launch_editor_1 = __importDefault(require("launch-editor"));
20
+ const fresh_1 = __importDefault(require("fresh"));
21
+ function setHeaders(res) {
22
+ res.setHeader('Access-Control-Allow-Origin', '*');
23
+ res.setHeader('Access-Control-Allow-Methods', 'GET, HEAD, PUT, PATCH, POST, DELETE');
24
+ res.setHeader('Access-Control-Allow-Headers', 'Origin, X-Requested-With, Content-Type, Accept, Content-Type');
25
+ res.setHeader('Cache-Control', 'max-age=0, must-revalidate');
26
+ }
27
+ const SLASH_REGEX = /\//g;
28
+ exports.SOURCES_ENDPOINT = '/__parcel_source_root';
29
+ const EDITOR_ENDPOINT = '/__parcel_launch_editor';
30
+ const TEMPLATE_404 = fs_1.default.readFileSync(path_1.default.join(__dirname, '..', 'templates/404.html'), 'utf8');
31
+ const TEMPLATE_500 = fs_1.default.readFileSync(path_1.default.join(__dirname, '..', 'templates/500.html'), 'utf8');
32
+ class Server {
33
+ constructor(options) {
34
+ this.options = options;
35
+ try {
36
+ this.rootPath = new url_2.URL(options.publicUrl).pathname;
37
+ }
38
+ catch (e) {
39
+ this.rootPath = options.publicUrl;
40
+ }
41
+ this.pending = true;
42
+ this.pendingRequests = [];
43
+ this.middleware = [];
44
+ this.bundleGraph = null;
45
+ this.requestBundle = null;
46
+ this.errors = null;
47
+ }
48
+ buildStart() {
49
+ this.pending = true;
50
+ }
51
+ buildSuccess(bundleGraph, requestBundle) {
52
+ this.bundleGraph = bundleGraph;
53
+ this.requestBundle = requestBundle;
54
+ this.errors = null;
55
+ this.pending = false;
56
+ if (this.pendingRequests.length > 0) {
57
+ let pendingRequests = this.pendingRequests;
58
+ this.pendingRequests = [];
59
+ for (let [req, res] of pendingRequests) {
60
+ this.respond(req, res);
61
+ }
62
+ }
63
+ }
64
+ async buildError(options, diagnostics) {
65
+ this.pending = false;
66
+ this.errors = await Promise.all(diagnostics.map(async (d) => {
67
+ let ansiDiagnostic = await (0, utils_1.prettyDiagnostic)(d, options);
68
+ return {
69
+ message: (0, utils_1.ansiHtml)(ansiDiagnostic.message),
70
+ stack: ansiDiagnostic.stack ? (0, utils_1.ansiHtml)(ansiDiagnostic.stack) : null,
71
+ frames: ansiDiagnostic.frames.map((f) => ({
72
+ location: f.location,
73
+ code: (0, utils_1.ansiHtml)(f.code),
74
+ })),
75
+ hints: ansiDiagnostic.hints.map((hint) => (0, utils_1.ansiHtml)(hint)),
76
+ documentation: d.documentationURL ?? '',
77
+ };
78
+ }));
79
+ }
80
+ respond(req, res) {
81
+ if (this.middleware.some((handler) => handler(req, res)))
82
+ return;
83
+ let { pathname, search } = url_1.default.parse(req.originalUrl || req.url);
84
+ if (pathname == null) {
85
+ pathname = '/';
86
+ }
87
+ if (pathname.startsWith(EDITOR_ENDPOINT) && search) {
88
+ let query = new url_2.URLSearchParams(search);
89
+ let file = query.get('file');
90
+ if (file) {
91
+ // File location might start with /__parcel_source_root if it came from a source map.
92
+ if (file.startsWith(exports.SOURCES_ENDPOINT)) {
93
+ file = file.slice(exports.SOURCES_ENDPOINT.length + 1);
94
+ }
95
+ (0, launch_editor_1.default)(file);
96
+ }
97
+ res.end();
98
+ }
99
+ else if (this.errors) {
100
+ return this.send500(req, res);
101
+ }
102
+ else if (path_1.default.extname(pathname) === '') {
103
+ // If the URL doesn't start with the public path, or the URL doesn't
104
+ // have a file extension, send the main HTML bundle.
105
+ return this.sendIndex(req, res);
106
+ }
107
+ else if (pathname.startsWith(exports.SOURCES_ENDPOINT)) {
108
+ req.url = pathname.slice(exports.SOURCES_ENDPOINT.length);
109
+ return this.serve(this.options.inputFS, this.options.projectRoot, req, res, () => this.send404(req, res));
110
+ }
111
+ else if (pathname.startsWith(this.rootPath)) {
112
+ // Otherwise, serve the file from the dist folder
113
+ req.url =
114
+ this.rootPath === '/' ? pathname : pathname.slice(this.rootPath.length);
115
+ if (req.url[0] !== '/') {
116
+ req.url = '/' + req.url;
117
+ }
118
+ return this.serveBundle(req, res, () => this.sendIndex(req, res));
119
+ }
120
+ else {
121
+ return this.send404(req, res);
122
+ }
123
+ }
124
+ sendIndex(req, res) {
125
+ if (this.bundleGraph) {
126
+ // If the main asset is an HTML file, serve it
127
+ let htmlBundleFilePaths = this.bundleGraph
128
+ .getBundles()
129
+ .filter((bundle) => path_1.default.posix.extname(bundle.name) === '.html')
130
+ .map((bundle) => {
131
+ return `/${(0, utils_1.relativePath)(this.options.distDir, bundle.filePath, false)}`;
132
+ });
133
+ let indexFilePath = null;
134
+ let { pathname: reqURL } = url_1.default.parse(req.originalUrl || req.url);
135
+ if (!reqURL) {
136
+ reqURL = '/';
137
+ }
138
+ if (htmlBundleFilePaths.length === 1) {
139
+ indexFilePath = htmlBundleFilePaths[0];
140
+ }
141
+ else {
142
+ let bestMatch = null;
143
+ for (let bundle of htmlBundleFilePaths) {
144
+ let bundleDir = path_1.default.posix.dirname(bundle);
145
+ let bundleDirSubdir = bundleDir === '/' ? bundleDir : bundleDir + '/';
146
+ let withoutExtension = path_1.default.posix.basename(bundle, path_1.default.posix.extname(bundle));
147
+ let isIndex = withoutExtension === 'index';
148
+ let matchesIsIndex = null;
149
+ if (isIndex &&
150
+ (reqURL.startsWith(bundleDirSubdir) || reqURL === bundleDir)) {
151
+ // bundle is /bar/index.html and (/bar or something inside of /bar/** was requested was requested)
152
+ matchesIsIndex = true;
153
+ }
154
+ else if (reqURL == path_1.default.posix.join(bundleDir, withoutExtension)) {
155
+ // bundle is /bar/foo.html and /bar/foo was requested
156
+ matchesIsIndex = false;
157
+ }
158
+ if (matchesIsIndex != null) {
159
+ let depth = bundle.match(SLASH_REGEX)?.length ?? 0;
160
+ if (bestMatch == null ||
161
+ // This one is more specific (deeper)
162
+ bestMatch.depth < depth ||
163
+ // This one is just as deep, but the bundle name matches and not just index.html
164
+ (bestMatch.depth === depth && bestMatch.isIndex)) {
165
+ bestMatch = { bundle, depth, isIndex: matchesIsIndex };
166
+ }
167
+ }
168
+ }
169
+ indexFilePath = bestMatch?.['bundle'] ?? htmlBundleFilePaths[0];
170
+ }
171
+ if (indexFilePath) {
172
+ req.url = indexFilePath;
173
+ this.serveBundle(req, res, () => this.send404(req, res));
174
+ }
175
+ else {
176
+ this.send404(req, res);
177
+ }
178
+ }
179
+ else {
180
+ this.send404(req, res);
181
+ }
182
+ }
183
+ async serveBundle(req, res, next) {
184
+ let bundleGraph = this.bundleGraph;
185
+ if (bundleGraph) {
186
+ let { pathname } = url_1.default.parse(req.url);
187
+ if (!pathname) {
188
+ this.send500(req, res);
189
+ return;
190
+ }
191
+ let requestedPath = path_1.default.normalize(pathname.slice(1));
192
+ let bundle = bundleGraph
193
+ .getBundles()
194
+ .find((b) => path_1.default.relative(this.options.distDir, b.filePath) === requestedPath);
195
+ if (!bundle) {
196
+ this.serveDist(req, res, next);
197
+ return;
198
+ }
199
+ (0, assert_1.default)(this.requestBundle != null);
200
+ try {
201
+ await this.requestBundle(bundle);
202
+ }
203
+ catch (err) {
204
+ this.send500(req, res);
205
+ return;
206
+ }
207
+ this.serveDist(req, res, next);
208
+ }
209
+ else {
210
+ this.send404(req, res);
211
+ }
212
+ }
213
+ serveDist(req, res, next) {
214
+ return this.serve(this.options.outputFS, this.options.distDir, req, res, next);
215
+ }
216
+ async serve(fs, root, req, res, next) {
217
+ if (req.method !== 'GET' && req.method !== 'HEAD') {
218
+ // method not allowed
219
+ res.statusCode = 405;
220
+ res.setHeader('Allow', 'GET, HEAD');
221
+ res.setHeader('Content-Length', '0');
222
+ res.end();
223
+ return;
224
+ }
225
+ try {
226
+ var filePath = url_1.default.parse(req.url).pathname || '';
227
+ filePath = decodeURIComponent(filePath);
228
+ }
229
+ catch (err) {
230
+ return this.sendError(res, 400);
231
+ }
232
+ filePath = path_1.default.normalize('.' + path_1.default.sep + filePath);
233
+ // malicious path
234
+ if (filePath.includes(path_1.default.sep + '..' + path_1.default.sep)) {
235
+ return this.sendError(res, 403);
236
+ }
237
+ // join / normalize from the root dir
238
+ if (!path_1.default.isAbsolute(filePath)) {
239
+ filePath = path_1.default.normalize(path_1.default.join(root, filePath));
240
+ }
241
+ try {
242
+ var stat = await fs.stat(filePath);
243
+ }
244
+ catch (err) {
245
+ if (err.code === 'ENOENT') {
246
+ return next(req, res);
247
+ }
248
+ return this.sendError(res, 500);
249
+ }
250
+ // Fall back to next handler if not a file
251
+ if (!stat || !stat.isFile()) {
252
+ return next(req, res);
253
+ }
254
+ if ((0, fresh_1.default)(req.headers, { 'last-modified': stat.mtime.toUTCString() })) {
255
+ res.statusCode = 304;
256
+ res.end();
257
+ return;
258
+ }
259
+ return (0, serve_handler_1.default)(req, res, {
260
+ public: root,
261
+ cleanUrls: false,
262
+ }, {
263
+ // @ts-expect-error TS7006
264
+ lstat: (path) => fs.stat(path),
265
+ // @ts-expect-error TS7006
266
+ realpath: (path) => fs.realpath(path),
267
+ // @ts-expect-error TS7006
268
+ createReadStream: (path, options) => fs.createReadStream(path, options),
269
+ // @ts-expect-error TS7006
270
+ readdir: (path) => fs.readdir(path),
271
+ });
272
+ }
273
+ sendError(res, statusCode) {
274
+ res.statusCode = statusCode;
275
+ res.end();
276
+ }
277
+ send404(req, res) {
278
+ res.statusCode = 404;
279
+ res.end(TEMPLATE_404);
280
+ }
281
+ send500(req, res) {
282
+ res.setHeader('Content-Type', 'text/html; charset=utf-8');
283
+ res.writeHead(500);
284
+ if (this.errors) {
285
+ return res.end(ejs_1.default.render(TEMPLATE_500, {
286
+ errors: this.errors,
287
+ hmrOptions: this.options.hmrOptions,
288
+ }));
289
+ }
290
+ }
291
+ logAccessIfVerbose(req) {
292
+ this.options.logger.verbose({
293
+ message: `Request: ${req.headers.host}${req.originalUrl || req.url}`,
294
+ });
295
+ }
296
+ /**
297
+ * Load proxy table from package.json and apply them.
298
+ */
299
+ async applyProxyTable(app) {
300
+ // avoid skipping project root
301
+ const fileInRoot = path_1.default.join(this.options.projectRoot, 'index');
302
+ const configFilePath = await (0, utils_1.resolveConfig)(this.options.inputFS, fileInRoot, [
303
+ '.proxyrc.cts',
304
+ '.proxyrc.mts',
305
+ '.proxyrc.ts',
306
+ '.proxyrc.cjs',
307
+ '.proxyrc.mjs',
308
+ '.proxyrc.js',
309
+ '.proxyrc',
310
+ '.proxyrc.json',
311
+ ], this.options.projectRoot);
312
+ if (!configFilePath) {
313
+ return this;
314
+ }
315
+ const filename = path_1.default.basename(configFilePath);
316
+ if (filename === '.proxyrc' || filename === '.proxyrc.json') {
317
+ let conf = await (0, utils_1.readConfig)(this.options.inputFS, configFilePath);
318
+ if (!conf) {
319
+ return this;
320
+ }
321
+ let cfg = conf.config;
322
+ if (typeof cfg !== 'object') {
323
+ this.options.logger.warn({
324
+ message: "Proxy table in '.proxyrc' should be of object type. Skipping...",
325
+ });
326
+ return this;
327
+ }
328
+ for (const [context, options] of Object.entries(cfg)) {
329
+ // each key is interpreted as context, and value as middleware options
330
+ // @ts-expect-error TS2345
331
+ app.use((0, http_proxy_middleware_1.createProxyMiddleware)(context, options));
332
+ }
333
+ }
334
+ else {
335
+ let cfg = await this.options.packageManager.require(configFilePath, fileInRoot);
336
+ if (Object.prototype.toString.call(cfg) === '[object Module]') {
337
+ cfg = cfg.default;
338
+ }
339
+ if (typeof cfg !== 'function') {
340
+ this.options.logger.warn({
341
+ message: `Proxy configuration file '${filename}' should export a function. Skipping...`,
342
+ });
343
+ return this;
344
+ }
345
+ cfg(app);
346
+ }
347
+ return this;
348
+ }
349
+ async start() {
350
+ const finalHandler = (req, res) => {
351
+ this.logAccessIfVerbose(req);
352
+ // Wait for the parcelInstance to finish bundling if needed
353
+ if (this.pending) {
354
+ this.pendingRequests.push([req, res]);
355
+ }
356
+ else {
357
+ this.respond(req, res);
358
+ }
359
+ };
360
+ const app = (0, connect_1.default)();
361
+ app.use((req, res, next) => {
362
+ setHeaders(res);
363
+ next();
364
+ });
365
+ app.use((req, res, next) => {
366
+ if (req.url === '/__parcel_healthcheck') {
367
+ res.statusCode = 200;
368
+ res.write(`${Date.now()}`);
369
+ res.end();
370
+ }
371
+ else {
372
+ next();
373
+ }
374
+ });
375
+ await this.applyProxyTable(app);
376
+ app.use(finalHandler);
377
+ let { server, stop } = await (0, utils_1.createHTTPServer)({
378
+ cacheDir: this.options.cacheDir,
379
+ https: this.options.https,
380
+ inputFS: this.options.inputFS,
381
+ listener: app,
382
+ outputFS: this.options.outputFS,
383
+ host: this.options.host,
384
+ });
385
+ this.stopServer = stop;
386
+ server.listen(this.options.port, this.options.host);
387
+ // @ts-expect-error TS2322
388
+ return new Promise((resolve, reject) => {
389
+ server.once('error', (err) => {
390
+ this.options.logger.error({
391
+ // @ts-expect-error TS2345
392
+ message: (0, serverErrors_1.default)(err, this.options.port),
393
+ });
394
+ reject(err);
395
+ });
396
+ server.once('listening', () => {
397
+ // @ts-expect-error TS2345
398
+ resolve(server);
399
+ });
400
+ });
401
+ }
402
+ async stop() {
403
+ (0, assert_1.default)(this.stopServer != null);
404
+ await this.stopServer();
405
+ this.stopServer = null;
406
+ }
407
+ }
408
+ exports.default = Server;
@@ -0,0 +1,2 @@
1
+ "use strict";
2
+ Object.defineProperty(exports, "__esModule", { value: true });