@eighty4/dank 0.0.4-1 → 0.0.4-2

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.
package/lib_js/http.js CHANGED
@@ -1,230 +1,211 @@
1
- import { createReadStream } from 'node:fs';
2
- import { stat } from 'node:fs/promises';
3
- import { createServer, } from 'node:http';
4
- import { extname, join } from 'node:path';
5
- import { Readable } from 'node:stream';
6
- import mime from 'mime';
7
- export function startWebServer(serve, frontendFetcher, httpServices, pageRoutes) {
8
- const serverAddress = 'http://localhost:' + serve.dankPort;
9
- const handler = (req, res) => {
10
- if (!req.url || !req.method) {
11
- res.end();
12
- }
13
- else {
14
- const url = new URL(serverAddress + req.url);
15
- const headers = convertHeadersToFetch(req.headers);
16
- frontendFetcher(url, headers, res, () => onNotFound(req, url, headers, httpServices, pageRoutes, serve, res));
17
- }
18
- };
19
- createServer(serve.logHttp ? createLogWrapper(handler) : handler).listen(serve.dankPort);
20
- console.log(serve.preview ? 'preview' : 'dev', `server is live at http://127.0.0.1:${serve.dankPort}`);
1
+ import { createReadStream } from "node:fs";
2
+ import { stat } from "node:fs/promises";
3
+ import { createServer } from "node:http";
4
+ import { extname, join } from "node:path";
5
+ import { Readable } from "node:stream";
6
+ import mime from "mime";
7
+ function startWebServer(serve, frontendFetcher, httpServices, pageRoutes) {
8
+ const serverAddress = "http://localhost:" + serve.dankPort;
9
+ const handler = (req, res) => {
10
+ if (!req.url || !req.method) {
11
+ res.end();
12
+ } else {
13
+ const url = new URL(serverAddress + req.url);
14
+ const headers = convertHeadersToFetch(req.headers);
15
+ frontendFetcher(url, headers, res, () => onNotFound(req, url, headers, httpServices, pageRoutes, serve, res));
16
+ }
17
+ };
18
+ createServer(serve.logHttp ? createLogWrapper(handler) : handler).listen(serve.dankPort);
19
+ console.log(serve.preview ? "preview" : "dev", `server is live at http://127.0.0.1:${serve.dankPort}`);
21
20
  }
22
21
  async function onNotFound(req, url, headers, httpServices, pageRoutes, serve, res) {
23
- if (req.method === 'GET' && extname(url.pathname) === '') {
24
- const urlRewrite = tryUrlRewrites(url, pageRoutes, serve);
25
- if (urlRewrite) {
26
- streamFile(urlRewrite, res);
27
- return;
28
- }
29
- }
30
- const fetchResponse = await tryHttpServices(req, url, headers, httpServices);
31
- if (fetchResponse) {
32
- sendFetchResponse(res, fetchResponse);
33
- }
34
- else {
35
- res.writeHead(404);
36
- res.end();
22
+ if (req.method === "GET" && extname(url.pathname) === "") {
23
+ const urlRewrite = tryUrlRewrites(url, pageRoutes, serve);
24
+ if (urlRewrite) {
25
+ streamFile(urlRewrite, res);
26
+ return;
37
27
  }
28
+ }
29
+ const fetchResponse = await tryHttpServices(req, url, headers, httpServices);
30
+ if (fetchResponse) {
31
+ sendFetchResponse(res, fetchResponse);
32
+ } else {
33
+ res.writeHead(404);
34
+ res.end();
35
+ }
38
36
  }
39
37
  async function sendFetchResponse(res, fetchResponse) {
40
- res.writeHead(fetchResponse.status, undefined, convertHeadersFromFetch(fetchResponse.headers));
41
- if (fetchResponse.body) {
42
- Readable.fromWeb(fetchResponse.body).pipe(res);
43
- }
44
- else {
45
- res.end();
46
- }
38
+ res.writeHead(fetchResponse.status, void 0, convertHeadersFromFetch(fetchResponse.headers));
39
+ if (fetchResponse.body) {
40
+ Readable.fromWeb(fetchResponse.body).pipe(res);
41
+ } else {
42
+ res.end();
43
+ }
47
44
  }
48
45
  function tryUrlRewrites(url, pageRoutes, serve) {
49
- const urlRewrite = pageRoutes.urlRewrites.find(urlRewrite => urlRewrite.pattern.test(url.pathname));
50
- return urlRewrite
51
- ? join(serve.dirs.buildWatch, urlRewrite.url, 'index.html')
52
- : null;
46
+ const urlRewrite = pageRoutes.urlRewrites.find((urlRewrite2) => urlRewrite2.pattern.test(url.pathname));
47
+ return urlRewrite ? join(serve.dirs.buildWatch, urlRewrite.url, "index.html") : null;
53
48
  }
54
49
  async function tryHttpServices(req, url, headers, httpServices) {
55
- if (url.pathname.startsWith('/.well-known/')) {
56
- return null;
57
- }
58
- const body = await collectReqBody(req);
59
- const { running } = httpServices;
60
- for (const httpService of running) {
61
- const proxyUrl = new URL(url);
62
- proxyUrl.port = `${httpService.port}`;
63
- try {
64
- const response = await retryFetchWithTimeout(proxyUrl, {
65
- body,
66
- headers,
67
- method: req.method,
68
- redirect: 'manual',
69
- });
70
- if (response.status === 404 || response.status === 405) {
71
- continue;
72
- }
73
- else {
74
- return response;
75
- }
76
- }
77
- catch (e) {
78
- if (e === 'retrytimeout') {
79
- continue;
80
- }
81
- else {
82
- errorExit(`unexpected error http proxying to port ${httpService.port}: ${e.message}`);
83
- }
84
- }
85
- }
50
+ if (url.pathname.startsWith("/.well-known/")) {
86
51
  return null;
52
+ }
53
+ const body = await collectReqBody(req);
54
+ const { running } = httpServices;
55
+ for (const httpService of running) {
56
+ const proxyUrl = new URL(url);
57
+ proxyUrl.port = `${httpService.port}`;
58
+ try {
59
+ const response = await retryFetchWithTimeout(proxyUrl, {
60
+ body,
61
+ headers,
62
+ method: req.method,
63
+ redirect: "manual"
64
+ });
65
+ if (response.status === 404 || response.status === 405) {
66
+ continue;
67
+ } else {
68
+ return response;
69
+ }
70
+ } catch (e) {
71
+ if (e === "retrytimeout") {
72
+ continue;
73
+ } else {
74
+ errorExit(`unexpected error http proxying to port ${httpService.port}: ${e.message}`);
75
+ }
76
+ }
77
+ }
78
+ return null;
87
79
  }
88
80
  function collectReqBody(req) {
89
- let body = '';
90
- req.on('data', data => (body += data.toString()));
91
- return new Promise(res => req.on('end', () => res(body.length ? body : null)));
81
+ let body = "";
82
+ req.on("data", (data) => body += data.toString());
83
+ return new Promise((res) => req.on("end", () => res(body.length ? body : null)));
92
84
  }
93
85
  function createLogWrapper(handler) {
94
- return (req, res) => {
95
- console.log(' > ', req.method, req.url);
96
- res.on('close', () => {
97
- console.log('', res.statusCode, req.method, req.url);
98
- });
99
- handler(req, res);
100
- };
101
- }
102
- export function createBuiltDistFilesFetcher(dir, manifest) {
103
- return (url, _headers, res, notFound) => {
104
- if (manifest.pageUrls.has(url.pathname)) {
105
- streamFile(join(dir, url.pathname, 'index.html'), res);
106
- }
107
- else if (manifest.files.has(url.pathname)) {
108
- streamFile(join(dir, url.pathname), res);
109
- }
110
- else {
111
- notFound();
112
- }
113
- };
114
- }
115
- // todo replace PageRouteState with WebsiteRegistry
116
- export function createDevServeFilesFetcher(pageRoutes, serve) {
117
- const proxyAddress = 'http://127.0.0.1:' + serve.esbuildPort;
118
- return (url, _headers, res, notFound) => {
119
- if (pageRoutes.urls.includes(url.pathname)) {
120
- streamFile(join(serve.dirs.buildWatch, url.pathname, 'index.html'), res);
121
- }
122
- else {
123
- const maybePublicPath = join(serve.dirs.public, url.pathname);
124
- exists(maybePublicPath).then(fromPublic => {
125
- if (fromPublic) {
126
- streamFile(maybePublicPath, res);
127
- }
128
- else {
129
- retryFetchWithTimeout(proxyAddress + url.pathname)
130
- .then(fetchResponse => {
131
- if (fetchResponse.status === 404) {
132
- notFound();
133
- }
134
- else {
135
- res.writeHead(fetchResponse.status, convertHeadersFromFetch(fetchResponse.headers));
136
- fetchResponse
137
- .bytes()
138
- .then(data => res.end(data));
139
- }
140
- })
141
- .catch(e => {
142
- if (isFetchRetryTimeout(e)) {
143
- res.writeHead(504);
144
- }
145
- else {
146
- console.error('unknown frontend proxy fetch error:', e);
147
- res.writeHead(502);
148
- }
149
- res.end();
150
- });
151
- }
152
- });
86
+ return (req, res) => {
87
+ console.log(" > ", req.method, req.url);
88
+ res.on("close", () => {
89
+ console.log("", res.statusCode, req.method, req.url);
90
+ });
91
+ handler(req, res);
92
+ };
93
+ }
94
+ function createBuiltDistFilesFetcher(dir, manifest) {
95
+ return (url, _headers, res, notFound) => {
96
+ if (manifest.pageUrls.has(url.pathname)) {
97
+ streamFile(join(dir, url.pathname, "index.html"), res);
98
+ } else if (manifest.files.has(url.pathname)) {
99
+ streamFile(join(dir, url.pathname), res);
100
+ } else {
101
+ notFound();
102
+ }
103
+ };
104
+ }
105
+ function createDevServeFilesFetcher(pageRoutes, serve) {
106
+ const proxyAddress = "http://127.0.0.1:" + serve.esbuildPort;
107
+ return (url, _headers, res, notFound) => {
108
+ if (pageRoutes.urls.includes(url.pathname)) {
109
+ streamFile(join(serve.dirs.buildWatch, url.pathname, "index.html"), res);
110
+ } else {
111
+ const maybePublicPath = join(serve.dirs.public, url.pathname);
112
+ exists(maybePublicPath).then((fromPublic) => {
113
+ if (fromPublic) {
114
+ streamFile(maybePublicPath, res);
115
+ } else {
116
+ retryFetchWithTimeout(proxyAddress + url.pathname).then((fetchResponse) => {
117
+ if (fetchResponse.status === 404) {
118
+ notFound();
119
+ } else {
120
+ res.writeHead(fetchResponse.status, convertHeadersFromFetch(fetchResponse.headers));
121
+ fetchResponse.bytes().then((data) => res.end(data));
122
+ }
123
+ }).catch((e) => {
124
+ if (isFetchRetryTimeout(e)) {
125
+ res.writeHead(504);
126
+ } else {
127
+ console.error("unknown frontend proxy fetch error:", e);
128
+ res.writeHead(502);
129
+ }
130
+ res.end();
131
+ });
153
132
  }
154
- };
133
+ });
134
+ }
135
+ };
155
136
  }
156
137
  const PROXY_FETCH_RETRY_INTERVAL = 27;
157
- const PROXY_FETCH_RETRY_TIMEOUT = 1000;
138
+ const PROXY_FETCH_RETRY_TIMEOUT = 1e3;
158
139
  async function retryFetchWithTimeout(url, requestInit) {
159
- let timeout = Date.now() + PROXY_FETCH_RETRY_TIMEOUT;
160
- while (true) {
161
- try {
162
- return await fetch(url, requestInit);
163
- }
164
- catch (e) {
165
- if (isNodeFailedFetch(e) || isBunFailedFetch(e)) {
166
- if (timeout < Date.now()) {
167
- throw 'retrytimeout';
168
- }
169
- else {
170
- await new Promise(res => setTimeout(res, PROXY_FETCH_RETRY_INTERVAL));
171
- }
172
- }
173
- else {
174
- throw e;
175
- }
140
+ let timeout = Date.now() + PROXY_FETCH_RETRY_TIMEOUT;
141
+ while (true) {
142
+ try {
143
+ return await fetch(url, requestInit);
144
+ } catch (e) {
145
+ if (isNodeFailedFetch(e) || isBunFailedFetch(e)) {
146
+ if (timeout < Date.now()) {
147
+ throw "retrytimeout";
148
+ } else {
149
+ await new Promise((res) => setTimeout(res, PROXY_FETCH_RETRY_INTERVAL));
176
150
  }
151
+ } else {
152
+ throw e;
153
+ }
177
154
  }
155
+ }
178
156
  }
179
157
  function isFetchRetryTimeout(e) {
180
- return e === 'retrytimeout';
158
+ return e === "retrytimeout";
181
159
  }
182
160
  function isBunFailedFetch(e) {
183
- return e.code === 'ConnectionRefused';
161
+ return e.code === "ConnectionRefused";
184
162
  }
185
163
  function isNodeFailedFetch(e) {
186
- return e.message === 'fetch failed';
164
+ return e.message === "fetch failed";
187
165
  }
188
166
  async function exists(p) {
189
- try {
190
- const maybe = stat(p);
191
- return (await maybe).isFile();
192
- }
193
- catch (ignore) {
194
- return false;
195
- }
167
+ try {
168
+ const maybe = stat(p);
169
+ return (await maybe).isFile();
170
+ } catch (ignore) {
171
+ return false;
172
+ }
196
173
  }
197
174
  function streamFile(p, res) {
198
- res.setHeader('Content-Type', mime.getType(p) || 'application/octet-stream');
199
- const reading = createReadStream(p);
200
- reading.pipe(res);
201
- reading.on('error', err => {
202
- console.error(`file read ${reading.path} error ${err.message}`);
203
- res.statusCode = 500;
204
- res.end();
205
- });
175
+ res.setHeader("Content-Type", mime.getType(p) || "application/octet-stream");
176
+ const reading = createReadStream(p);
177
+ reading.pipe(res);
178
+ reading.on("error", (err) => {
179
+ console.error(`file read ${reading.path} error ${err.message}`);
180
+ res.statusCode = 500;
181
+ res.end();
182
+ });
206
183
  }
207
184
  function convertHeadersFromFetch(from) {
208
- const to = {};
209
- for (const name of from.keys()) {
210
- to[name] = from.get(name);
211
- }
212
- return to;
185
+ const to = {};
186
+ for (const name of from.keys()) {
187
+ to[name] = from.get(name);
188
+ }
189
+ return to;
213
190
  }
214
191
  function convertHeadersToFetch(from) {
215
- const to = new Headers();
216
- for (const [name, values] of Object.entries(from)) {
217
- if (Array.isArray(values)) {
218
- for (const value of values)
219
- to.append(name, value);
220
- }
221
- else if (values) {
222
- to.set(name, values);
223
- }
192
+ const to = new Headers();
193
+ for (const [name, values] of Object.entries(from)) {
194
+ if (Array.isArray(values)) {
195
+ for (const value of values)
196
+ to.append(name, value);
197
+ } else if (values) {
198
+ to.set(name, values);
224
199
  }
225
- return to;
200
+ }
201
+ return to;
226
202
  }
227
203
  function errorExit(msg) {
228
- console.log(`\u001b[31merror:\u001b[0m`, msg);
229
- process.exit(1);
230
- }
204
+ console.log(`\x1B[31merror:\x1B[0m`, msg);
205
+ process.exit(1);
206
+ }
207
+ export {
208
+ createBuiltDistFilesFetcher,
209
+ createDevServeFilesFetcher,
210
+ startWebServer
211
+ };