wooks 0.0.1-beta.4 → 0.0.1-beta.6
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/README.md +83 -0
- package/dist/src/composables/headers.d.ts +1 -1
- package/dist/src/composables/index.d.ts +1 -0
- package/dist/src/composables/index.d.ts.map +1 -1
- package/dist/src/composables/proxy-utils.d.ts +25 -0
- package/dist/src/composables/proxy-utils.d.ts.map +1 -0
- package/dist/src/composables/proxy.d.ts +12 -0
- package/dist/src/composables/proxy.d.ts.map +1 -0
- package/dist/src/composables/tests/proxy.spec.d.ts +2 -0
- package/dist/src/composables/tests/proxy.spec.d.ts.map +1 -0
- package/dist/src/response/core.d.ts +1 -1
- package/dist/src/response/core.d.ts.map +1 -1
- package/dist/src/response/renderer.d.ts +2 -2
- package/dist/src/response/renderer.d.ts.map +1 -1
- package/dist/src/utils/log.d.ts +5 -0
- package/dist/src/utils/log.d.ts.map +1 -0
- package/dist/wooks.cjs.prod.js +218 -54
- package/dist/wooks.d.ts +21 -4
- package/dist/wooks.esm-bundler.js +218 -55
- package/package.json +18 -15
package/dist/wooks.cjs.prod.js
CHANGED
|
@@ -10,6 +10,7 @@ var fs = require('fs');
|
|
|
10
10
|
var path = require('path');
|
|
11
11
|
var url = require('url');
|
|
12
12
|
var net = require('net');
|
|
13
|
+
var nodeFetchNative = require('node-fetch-native');
|
|
13
14
|
|
|
14
15
|
function _interopDefaultLegacy (e) { return e && typeof e === 'object' && 'default' in e ? e["default"] : e; }
|
|
15
16
|
|
|
@@ -18,8 +19,15 @@ var path__default = /*#__PURE__*/_interopDefaultLegacy(path);
|
|
|
18
19
|
|
|
19
20
|
const banner = () => `[wooks][${new Date().toISOString().replace('T', ' ').replace(/\.\d{3}z$/i, '')}] `;
|
|
20
21
|
|
|
21
|
-
function
|
|
22
|
+
function warn(text) {
|
|
23
|
+
console.warn('[33m' + banner() + text + '[0m');
|
|
24
|
+
}
|
|
25
|
+
function logError(error) {
|
|
22
26
|
console.error('[91m' + '[1m' + banner() + error + '[0m');
|
|
27
|
+
}
|
|
28
|
+
|
|
29
|
+
function panic(error) {
|
|
30
|
+
logError(error);
|
|
23
31
|
return new Error(error);
|
|
24
32
|
}
|
|
25
33
|
|
|
@@ -195,6 +203,9 @@ class BaseWooksResponseRenderer {
|
|
|
195
203
|
if (typeof response.body === 'undefined') {
|
|
196
204
|
return '';
|
|
197
205
|
}
|
|
206
|
+
if (response.body instanceof Uint8Array) {
|
|
207
|
+
return response.body;
|
|
208
|
+
}
|
|
198
209
|
if (typeof response.body === 'object') {
|
|
199
210
|
if (!response.getContentType())
|
|
200
211
|
response.setContentType(contentTypes.application.json);
|
|
@@ -232,11 +243,10 @@ function useRequest() {
|
|
|
232
243
|
return reqCache.reqId;
|
|
233
244
|
}
|
|
234
245
|
function getIp(options) {
|
|
235
|
-
|
|
236
|
-
if (options === null || options === void 0 ? void 0 : options.trustProxy) {
|
|
246
|
+
if (options?.trustProxy) {
|
|
237
247
|
if (typeof reqCache.forwardedIp !== 'string') {
|
|
238
248
|
if (typeof req.headers[xForwardedFor] === 'string' && req.headers[xForwardedFor]) {
|
|
239
|
-
reqCache.forwardedIp =
|
|
249
|
+
reqCache.forwardedIp = req.headers[xForwardedFor].split(',').shift()?.trim();
|
|
240
250
|
}
|
|
241
251
|
else {
|
|
242
252
|
return getIp();
|
|
@@ -246,16 +256,15 @@ function useRequest() {
|
|
|
246
256
|
}
|
|
247
257
|
else {
|
|
248
258
|
if (typeof reqCache.remoteIp !== 'string') {
|
|
249
|
-
reqCache.remoteIp =
|
|
259
|
+
reqCache.remoteIp = req.socket?.remoteAddress || req.connection?.remoteAddress || '';
|
|
250
260
|
}
|
|
251
261
|
return reqCache.remoteIp;
|
|
252
262
|
}
|
|
253
263
|
}
|
|
254
264
|
function getIpList() {
|
|
255
|
-
var _a, _b;
|
|
256
265
|
if (!reqCache.ipList) {
|
|
257
266
|
reqCache.ipList = {
|
|
258
|
-
remoteIp:
|
|
267
|
+
remoteIp: req.socket?.remoteAddress || req.connection?.remoteAddress || '',
|
|
259
268
|
forwarded: (req.headers[xForwardedFor] || '').split(',').map(s => s.trim()),
|
|
260
269
|
};
|
|
261
270
|
}
|
|
@@ -318,10 +327,10 @@ function useSetHeaders() {
|
|
|
318
327
|
delete cache[name];
|
|
319
328
|
}
|
|
320
329
|
function setContentType(value) {
|
|
321
|
-
setHeader('
|
|
330
|
+
setHeader('content-type', value);
|
|
322
331
|
}
|
|
323
332
|
function enableCors(origin = '*') {
|
|
324
|
-
setHeader('
|
|
333
|
+
setHeader('access-control-allow-origin', origin);
|
|
325
334
|
}
|
|
326
335
|
return {
|
|
327
336
|
setHeader,
|
|
@@ -378,13 +387,13 @@ function useAuthorization() {
|
|
|
378
387
|
authorization,
|
|
379
388
|
authType,
|
|
380
389
|
authRawCredentials,
|
|
381
|
-
isBasic: () =>
|
|
382
|
-
isBearer: () =>
|
|
390
|
+
isBasic: () => authType()?.toLocaleLowerCase() === 'basic',
|
|
391
|
+
isBearer: () => authType()?.toLocaleLowerCase() === 'bearer',
|
|
383
392
|
basicCredentials: () => {
|
|
384
393
|
if (authorization) {
|
|
385
394
|
if (typeof cache.basicCredentials === 'undefined') {
|
|
386
395
|
const type = authType();
|
|
387
|
-
if (
|
|
396
|
+
if (type?.toLocaleLowerCase() === 'basic') {
|
|
388
397
|
const creds = Buffer.from(authRawCredentials() || '', 'base64').toString('ascii');
|
|
389
398
|
const [username, password] = creds.split(':');
|
|
390
399
|
cache.basicCredentials = { username, password };
|
|
@@ -455,16 +464,16 @@ const renderPragmaNoCache = (v) => v ? 'no-cache' : '';
|
|
|
455
464
|
function useSetCacheControl() {
|
|
456
465
|
const { setHeader } = useSetHeaders();
|
|
457
466
|
const setAge = (value) => {
|
|
458
|
-
setHeader('
|
|
467
|
+
setHeader('age', renderAge(value));
|
|
459
468
|
};
|
|
460
469
|
const setExpires = (value) => {
|
|
461
|
-
setHeader('
|
|
470
|
+
setHeader('expires', renderExpires(value));
|
|
462
471
|
};
|
|
463
472
|
const setPragmaNoCache = (value = true) => {
|
|
464
|
-
setHeader('
|
|
473
|
+
setHeader('pragma', renderPragmaNoCache(value));
|
|
465
474
|
};
|
|
466
475
|
const setCacheControl = (data) => {
|
|
467
|
-
setHeader('
|
|
476
|
+
setHeader('cache-control', renderCacheControl(data));
|
|
468
477
|
};
|
|
469
478
|
return {
|
|
470
479
|
setExpires,
|
|
@@ -825,12 +834,12 @@ function useRespCookie(name) {
|
|
|
825
834
|
attrs: {},
|
|
826
835
|
};
|
|
827
836
|
Object.defineProperty(hook, 'value', {
|
|
828
|
-
get: () =>
|
|
829
|
-
set: (value) =>
|
|
837
|
+
get: () => getCookie(name)?.value,
|
|
838
|
+
set: (value) => setCookie(name, value, getCookie(name)?.attrs),
|
|
830
839
|
});
|
|
831
840
|
Object.defineProperty(hook, 'attrs', {
|
|
832
|
-
get: () =>
|
|
833
|
-
set: (attrs) =>
|
|
841
|
+
get: () => getCookie(name)?.attrs,
|
|
842
|
+
set: (attrs) => setCookie(name, getCookie(name)?.value || '', attrs),
|
|
834
843
|
});
|
|
835
844
|
return hook;
|
|
836
845
|
}
|
|
@@ -861,6 +870,135 @@ function useStatus() {
|
|
|
861
870
|
return hook;
|
|
862
871
|
}
|
|
863
872
|
|
|
873
|
+
class IterableRecords {
|
|
874
|
+
[Symbol.iterator]() {
|
|
875
|
+
return this;
|
|
876
|
+
}
|
|
877
|
+
index = 0;
|
|
878
|
+
next() {
|
|
879
|
+
return { value: undefined, done: true };
|
|
880
|
+
}
|
|
881
|
+
}
|
|
882
|
+
class CookiesIterable extends IterableRecords {
|
|
883
|
+
cookies;
|
|
884
|
+
constructor(cookiesString) {
|
|
885
|
+
super();
|
|
886
|
+
this.cookies = cookiesString.split(/,\s(?!\d{2}[\s-])/);
|
|
887
|
+
}
|
|
888
|
+
next() {
|
|
889
|
+
const str = this.cookies[this.index++];
|
|
890
|
+
const ind = str ? str.indexOf('=') : 0;
|
|
891
|
+
return this.index <= this.cookies.length ?
|
|
892
|
+
{ value: [str.slice(0, ind), str.slice(ind + 1)], done: false } :
|
|
893
|
+
{ value: undefined, done: true };
|
|
894
|
+
}
|
|
895
|
+
}
|
|
896
|
+
class HeadersIterable extends IterableRecords {
|
|
897
|
+
entries;
|
|
898
|
+
constructor(headers) {
|
|
899
|
+
super();
|
|
900
|
+
this.entries = Object.entries(headers);
|
|
901
|
+
}
|
|
902
|
+
next() {
|
|
903
|
+
return this.index < this.entries.length ?
|
|
904
|
+
{ value: this.entries[this.index++], done: false } :
|
|
905
|
+
{ value: undefined, done: true };
|
|
906
|
+
}
|
|
907
|
+
}
|
|
908
|
+
function applyProxyControls(records, controls, additionalBlockers) {
|
|
909
|
+
let result = {};
|
|
910
|
+
const { allow, block, overwrite } = controls;
|
|
911
|
+
const defaultedAllow = allow || '*';
|
|
912
|
+
if (defaultedAllow) {
|
|
913
|
+
for (const [name, value] of records) {
|
|
914
|
+
const add = block !== '*' && (defaultedAllow === '*' ||
|
|
915
|
+
(defaultedAllow.find(item => typeof item === 'string' && name.toLowerCase() === item.toLowerCase() || item instanceof RegExp && item.test(name)))) && (!block || !block.find(item => typeof item === 'string' && name.toLowerCase() === item.toLowerCase() || item instanceof RegExp && item.test(name))) && (!additionalBlockers || !additionalBlockers.includes(name));
|
|
916
|
+
if (add) {
|
|
917
|
+
result[name] = value;
|
|
918
|
+
}
|
|
919
|
+
}
|
|
920
|
+
}
|
|
921
|
+
if (overwrite) {
|
|
922
|
+
if (typeof overwrite === 'function') {
|
|
923
|
+
result = overwrite(result);
|
|
924
|
+
}
|
|
925
|
+
else {
|
|
926
|
+
result = { ...result, ...overwrite };
|
|
927
|
+
}
|
|
928
|
+
}
|
|
929
|
+
return result;
|
|
930
|
+
}
|
|
931
|
+
|
|
932
|
+
const reqHeadersToBlock = [
|
|
933
|
+
'connection',
|
|
934
|
+
'accept-encoding',
|
|
935
|
+
'content-length',
|
|
936
|
+
'upgrade-insecure-requests',
|
|
937
|
+
'cookie',
|
|
938
|
+
];
|
|
939
|
+
const resHeadersToBlock = [
|
|
940
|
+
'transfer-encoding',
|
|
941
|
+
'content-encoding',
|
|
942
|
+
'set-cookie',
|
|
943
|
+
];
|
|
944
|
+
function useProxy() {
|
|
945
|
+
const status = useStatus();
|
|
946
|
+
const { setHeader, headers: setHeadersObject } = useSetHeaders();
|
|
947
|
+
const { req } = useCurrentWooksContext().getCtx();
|
|
948
|
+
return async function proxy(target, opts) {
|
|
949
|
+
const targetUrl = new URL(target);
|
|
950
|
+
const path = targetUrl.pathname || '/';
|
|
951
|
+
const url = new URL(path, targetUrl.origin).toString() + (targetUrl.search);
|
|
952
|
+
const modifiedHeaders = { ...req.headers, host: targetUrl.hostname };
|
|
953
|
+
const headers = opts?.reqHeaders ? applyProxyControls(new HeadersIterable(modifiedHeaders), opts?.reqHeaders, reqHeadersToBlock) : {};
|
|
954
|
+
const cookies = opts?.reqCookies && req.headers.cookie ? applyProxyControls(new CookiesIterable(req.headers.cookie), opts?.reqCookies) : null;
|
|
955
|
+
if (cookies) {
|
|
956
|
+
headers.cookie = Object.entries(cookies).map(v => v.join('=')).join('; ');
|
|
957
|
+
}
|
|
958
|
+
const method = opts?.method || req.method;
|
|
959
|
+
if (opts?.debug) {
|
|
960
|
+
console.log();
|
|
961
|
+
warn(`[proxy] ${'[32m'}${req.method} ${req.url}${'[33m'} → ${'[36m'}${method} ${url}${'[33m'}`);
|
|
962
|
+
console.log('[33m' + 'headers:', JSON.stringify(headers, null, ' '), '[39m');
|
|
963
|
+
}
|
|
964
|
+
const resp = await nodeFetchNative.fetch(url, {
|
|
965
|
+
method,
|
|
966
|
+
body: ['GET', 'HEAD'].includes(method) ? undefined : req,
|
|
967
|
+
headers: headers,
|
|
968
|
+
});
|
|
969
|
+
status.value = resp.status;
|
|
970
|
+
if (opts?.debug) {
|
|
971
|
+
console.log();
|
|
972
|
+
warn(`[proxy] ${resp.status} ${'[32m'}${req.method} ${req.url}${'[33m'} → ${'[36m'}${method} ${url}${'[33m'}`);
|
|
973
|
+
console.log(`${'[33m'}response headers:${'[39m'}`);
|
|
974
|
+
}
|
|
975
|
+
const resHeaders = opts?.resHeaders ? applyProxyControls(resp.headers.entries(), opts?.resHeaders, resHeadersToBlock) : null;
|
|
976
|
+
const resCookies = opts?.resCookies ? applyProxyControls(new CookiesIterable(resp.headers.get('set-cookie') || ''), opts?.resCookies) : null;
|
|
977
|
+
if (resHeaders) {
|
|
978
|
+
for (const [name, value] of Object.entries(resHeaders)) {
|
|
979
|
+
if (name) {
|
|
980
|
+
setHeader(name, value);
|
|
981
|
+
if (opts?.debug) {
|
|
982
|
+
console.log(`\t${'[33m'}${name}=${'[32m'}${value}${'[39m'}`);
|
|
983
|
+
}
|
|
984
|
+
}
|
|
985
|
+
}
|
|
986
|
+
}
|
|
987
|
+
if (resCookies) {
|
|
988
|
+
setHeadersObject['set-cookie'] = (setHeadersObject['set-cookie'] || []);
|
|
989
|
+
for (const [name, value] of Object.entries(resCookies)) {
|
|
990
|
+
if (name) {
|
|
991
|
+
setHeadersObject['set-cookie'].push(`${name}=${value}`);
|
|
992
|
+
if (opts?.debug) {
|
|
993
|
+
console.log(`\t${'[1m'}${'[33m'}set-cookie=${'[32m'}${name}=${value}${'[0m'}`);
|
|
994
|
+
}
|
|
995
|
+
}
|
|
996
|
+
}
|
|
997
|
+
}
|
|
998
|
+
return resp;
|
|
999
|
+
};
|
|
1000
|
+
}
|
|
1001
|
+
|
|
864
1002
|
const httpStatusCodes = {
|
|
865
1003
|
[100]: 'Continue',
|
|
866
1004
|
[101]: 'Switching protocols',
|
|
@@ -1001,12 +1139,15 @@ const defaultStatus = {
|
|
|
1001
1139
|
DELETE: exports.EHttpStatusCode.Accepted,
|
|
1002
1140
|
};
|
|
1003
1141
|
const baseRenderer = new BaseWooksResponseRenderer();
|
|
1142
|
+
const FetchResponse = Response;
|
|
1004
1143
|
class BaseWooksResponse {
|
|
1144
|
+
renderer;
|
|
1005
1145
|
constructor(renderer = baseRenderer) {
|
|
1006
1146
|
this.renderer = renderer;
|
|
1007
|
-
this._status = 0;
|
|
1008
|
-
this._headers = {};
|
|
1009
1147
|
}
|
|
1148
|
+
_status = 0;
|
|
1149
|
+
_body;
|
|
1150
|
+
_headers = {};
|
|
1010
1151
|
get status() {
|
|
1011
1152
|
return this._status;
|
|
1012
1153
|
}
|
|
@@ -1028,10 +1169,10 @@ class BaseWooksResponse {
|
|
|
1028
1169
|
return this;
|
|
1029
1170
|
}
|
|
1030
1171
|
getContentType() {
|
|
1031
|
-
return this._headers['
|
|
1172
|
+
return this._headers['content-type'];
|
|
1032
1173
|
}
|
|
1033
1174
|
setContentType(value) {
|
|
1034
|
-
this._headers['
|
|
1175
|
+
this._headers['content-type'] = value;
|
|
1035
1176
|
return this;
|
|
1036
1177
|
}
|
|
1037
1178
|
enableCors(origin = '*') {
|
|
@@ -1039,15 +1180,15 @@ class BaseWooksResponse {
|
|
|
1039
1180
|
return this;
|
|
1040
1181
|
}
|
|
1041
1182
|
setCookie(name, value, attrs) {
|
|
1042
|
-
const cookies = this._headers['
|
|
1183
|
+
const cookies = this._headers['set-cookie'] = (this._headers['set-cookie'] || []);
|
|
1043
1184
|
cookies.push(renderCookie(name, { value, attrs: attrs || {} }));
|
|
1044
1185
|
return this;
|
|
1045
1186
|
}
|
|
1046
1187
|
setCacheControl(data) {
|
|
1047
|
-
this.setHeader('
|
|
1188
|
+
this.setHeader('cache-control', renderCacheControl(data));
|
|
1048
1189
|
}
|
|
1049
1190
|
setCookieRaw(rawValue) {
|
|
1050
|
-
const cookies = this._headers['
|
|
1191
|
+
const cookies = this._headers['set-cookie'] = (this._headers['set-cookie'] || []);
|
|
1051
1192
|
cookies.push(rawValue);
|
|
1052
1193
|
return this;
|
|
1053
1194
|
}
|
|
@@ -1064,17 +1205,18 @@ class BaseWooksResponse {
|
|
|
1064
1205
|
mergeHeaders() {
|
|
1065
1206
|
const { headers } = useSetHeaders();
|
|
1066
1207
|
const { cookies, removeCookie } = useSetCookies();
|
|
1067
|
-
const newCookies = (this._headers['
|
|
1208
|
+
const newCookies = (this._headers['set-cookie'] || []);
|
|
1068
1209
|
for (const cookie of newCookies) {
|
|
1069
1210
|
removeCookie(cookie.slice(0, cookie.indexOf('=')));
|
|
1070
1211
|
}
|
|
1071
1212
|
this._headers = {
|
|
1213
|
+
server: `Wooks v${"0.0.1-beta.5"}`,
|
|
1072
1214
|
...headers,
|
|
1073
1215
|
...this._headers,
|
|
1074
1216
|
};
|
|
1075
1217
|
const setCookie = [...newCookies, ...cookies()];
|
|
1076
1218
|
if (setCookie && setCookie.length) {
|
|
1077
|
-
this._headers['
|
|
1219
|
+
this._headers['set-cookie'] = setCookie;
|
|
1078
1220
|
}
|
|
1079
1221
|
return this;
|
|
1080
1222
|
}
|
|
@@ -1118,15 +1260,36 @@ class BaseWooksResponse {
|
|
|
1118
1260
|
stream.pipe(res);
|
|
1119
1261
|
}
|
|
1120
1262
|
}
|
|
1263
|
+
else if (this.body instanceof FetchResponse) {
|
|
1264
|
+
this.mergeStatus('ok');
|
|
1265
|
+
if (method === 'HEAD') {
|
|
1266
|
+
res.end();
|
|
1267
|
+
}
|
|
1268
|
+
else {
|
|
1269
|
+
void respondWithFetch(this.body.body, res);
|
|
1270
|
+
}
|
|
1271
|
+
}
|
|
1121
1272
|
else {
|
|
1122
1273
|
const renderedBody = this.renderer.render(this);
|
|
1123
1274
|
this.mergeStatus(renderedBody);
|
|
1124
1275
|
res.writeHead(this.status, {
|
|
1125
|
-
'
|
|
1276
|
+
'content-length': Buffer.byteLength(renderedBody),
|
|
1126
1277
|
...this._headers,
|
|
1127
1278
|
}).end(method !== 'HEAD' ? renderedBody : '');
|
|
1128
1279
|
}
|
|
1129
1280
|
}
|
|
1281
|
+
}
|
|
1282
|
+
async function respondWithFetch(fetchBody, res) {
|
|
1283
|
+
if (fetchBody) {
|
|
1284
|
+
try {
|
|
1285
|
+
for await (const chunk of fetchBody) {
|
|
1286
|
+
res.write(chunk);
|
|
1287
|
+
}
|
|
1288
|
+
}
|
|
1289
|
+
catch (e) {
|
|
1290
|
+
}
|
|
1291
|
+
}
|
|
1292
|
+
res.end();
|
|
1130
1293
|
}
|
|
1131
1294
|
|
|
1132
1295
|
const preStyles = 'font-family: monospace;'
|
|
@@ -1146,7 +1309,7 @@ class WooksErrorRenderer extends BaseWooksResponseRenderer {
|
|
|
1146
1309
|
`<head><title>${data.statusCode} ${httpStatusCodes[data.statusCode]}</title></head>` +
|
|
1147
1310
|
`<body><center><h1>${data.statusCode} ${httpStatusCodes[data.statusCode]}</h1></center>` +
|
|
1148
1311
|
`<center><h4>${data.message}</h1></center><hr color="#666">` +
|
|
1149
|
-
`<center style="color: #666;">
|
|
1312
|
+
`<center style="color: #666;"> Wooks v${"0.0.1-beta.5"} </center>` +
|
|
1150
1313
|
`${keys.length ? `<pre style="${preStyles}">${JSON.stringify({ ...data, statusCode: undefined, message: undefined, error: undefined }, null, ' ')}</pre>` : ''}` +
|
|
1151
1314
|
'</body></html>';
|
|
1152
1315
|
}
|
|
@@ -1167,9 +1330,8 @@ class WooksErrorRenderer extends BaseWooksResponseRenderer {
|
|
|
1167
1330
|
+ `${keys.length ? (',' + keys.map(k => `"${escapeQuotes(k)}":${JSON.stringify(data[k])}`).join(',')) : ''}}`;
|
|
1168
1331
|
}
|
|
1169
1332
|
render(response) {
|
|
1170
|
-
var _a;
|
|
1171
1333
|
const { acceptsJson, acceptsText, acceptsHtml } = useAccept();
|
|
1172
|
-
response.status =
|
|
1334
|
+
response.status = response.body?.statusCode || 500;
|
|
1173
1335
|
if (acceptsJson()) {
|
|
1174
1336
|
return this.renderJson(response);
|
|
1175
1337
|
}
|
|
@@ -1189,6 +1351,8 @@ function escapeQuotes(s) {
|
|
|
1189
1351
|
}
|
|
1190
1352
|
|
|
1191
1353
|
class WooksError extends Error {
|
|
1354
|
+
code;
|
|
1355
|
+
_body;
|
|
1192
1356
|
constructor(code = 500, _body = '') {
|
|
1193
1357
|
super(typeof _body === 'string' ? _body : _body.message);
|
|
1194
1358
|
this.code = code;
|
|
@@ -1206,6 +1370,7 @@ class WooksError extends Error {
|
|
|
1206
1370
|
error: httpStatusCodes[this.code],
|
|
1207
1371
|
};
|
|
1208
1372
|
}
|
|
1373
|
+
renderer;
|
|
1209
1374
|
attachRenderer(renderer) {
|
|
1210
1375
|
this.renderer = renderer;
|
|
1211
1376
|
}
|
|
@@ -1239,6 +1404,10 @@ function createResponseFrom(data) {
|
|
|
1239
1404
|
}
|
|
1240
1405
|
|
|
1241
1406
|
class Wooks {
|
|
1407
|
+
options;
|
|
1408
|
+
router;
|
|
1409
|
+
server;
|
|
1410
|
+
_uncoughtExceptionHandler;
|
|
1242
1411
|
constructor(options) {
|
|
1243
1412
|
this.options = options;
|
|
1244
1413
|
this.router = new router.ProstoRouter();
|
|
@@ -1251,22 +1420,20 @@ class Wooks {
|
|
|
1251
1420
|
}
|
|
1252
1421
|
listen(port, hostname, cb) {
|
|
1253
1422
|
return new Promise((resolve, reject) => {
|
|
1254
|
-
var _a;
|
|
1255
1423
|
const myCb = () => {
|
|
1256
|
-
var _a;
|
|
1257
1424
|
const fn = typeof hostname === 'function' ? hostname : cb;
|
|
1258
1425
|
process.on('uncaughtException', this._uncoughtExceptionHandler);
|
|
1259
1426
|
if (fn) {
|
|
1260
1427
|
fn();
|
|
1261
1428
|
}
|
|
1262
|
-
|
|
1429
|
+
this.server?.off('error', reject);
|
|
1263
1430
|
resolve();
|
|
1264
1431
|
};
|
|
1265
1432
|
try {
|
|
1266
1433
|
this.server = createServer({
|
|
1267
1434
|
port,
|
|
1268
1435
|
}, this.processRequest.bind(this), typeof hostname === 'string' ? hostname : '', myCb);
|
|
1269
|
-
|
|
1436
|
+
this.server?.on('error', reject);
|
|
1270
1437
|
}
|
|
1271
1438
|
catch (e) {
|
|
1272
1439
|
reject(e);
|
|
@@ -1275,8 +1442,7 @@ class Wooks {
|
|
|
1275
1442
|
}
|
|
1276
1443
|
close() {
|
|
1277
1444
|
return new Promise((resolve, reject) => {
|
|
1278
|
-
|
|
1279
|
-
(_a = this.server) === null || _a === void 0 ? void 0 : _a.close((err) => {
|
|
1445
|
+
this.server?.close((err) => {
|
|
1280
1446
|
if (err)
|
|
1281
1447
|
return reject(err);
|
|
1282
1448
|
process.off('uncaughtException', this._uncoughtExceptionHandler);
|
|
@@ -1285,11 +1451,10 @@ class Wooks {
|
|
|
1285
1451
|
});
|
|
1286
1452
|
}
|
|
1287
1453
|
processRequest(req, res) {
|
|
1288
|
-
var _a;
|
|
1289
1454
|
const found = this.router.lookup(req.method, req.url);
|
|
1290
1455
|
const ctx = {
|
|
1291
1456
|
__setHeader: {
|
|
1292
|
-
Server: 'wooks v' + "0.0.1-beta.
|
|
1457
|
+
Server: 'wooks v' + "0.0.1-beta.5",
|
|
1293
1458
|
},
|
|
1294
1459
|
};
|
|
1295
1460
|
if (found) {
|
|
@@ -1298,22 +1463,20 @@ class Wooks {
|
|
|
1298
1463
|
const { restoreCtx } = useCurrentWooksContext();
|
|
1299
1464
|
this.processHandlers(req, res, found)
|
|
1300
1465
|
.catch((e) => {
|
|
1301
|
-
var _a;
|
|
1302
1466
|
this.printError('Internal error, please report: ', e);
|
|
1303
1467
|
restoreCtx();
|
|
1304
|
-
|
|
1468
|
+
createResponseFrom(e)?.respond();
|
|
1305
1469
|
clearCurrentWooksContext();
|
|
1306
1470
|
console.error('[91m' + '[1m' + banner(), e, '[0m');
|
|
1307
1471
|
});
|
|
1308
1472
|
}
|
|
1309
1473
|
else {
|
|
1310
1474
|
setCurrentWooksContext(req, res, {}, ctx);
|
|
1311
|
-
|
|
1475
|
+
createResponseFrom(new WooksError(404))?.respond();
|
|
1312
1476
|
clearCurrentWooksContext();
|
|
1313
1477
|
}
|
|
1314
1478
|
}
|
|
1315
1479
|
async processHandlers(req, res, found) {
|
|
1316
|
-
var _a, _b;
|
|
1317
1480
|
const { restoreCtx } = useCurrentWooksContext();
|
|
1318
1481
|
for (const [i, handler] of found.route.handlers.entries()) {
|
|
1319
1482
|
const isLastHandler = found.route.handlers.length === i + 1;
|
|
@@ -1323,7 +1486,7 @@ class Wooks {
|
|
|
1323
1486
|
clearCurrentWooksContext();
|
|
1324
1487
|
const result = await promise;
|
|
1325
1488
|
restoreCtx();
|
|
1326
|
-
|
|
1489
|
+
createResponseFrom(result)?.respond();
|
|
1327
1490
|
clearCurrentWooksContext();
|
|
1328
1491
|
break;
|
|
1329
1492
|
}
|
|
@@ -1331,7 +1494,7 @@ class Wooks {
|
|
|
1331
1494
|
this.printError('Uncought route handler exception: ' + (req.url || '') + '\n', e);
|
|
1332
1495
|
if (isLastHandler) {
|
|
1333
1496
|
restoreCtx();
|
|
1334
|
-
|
|
1497
|
+
createResponseFrom(e)?.respond();
|
|
1335
1498
|
clearCurrentWooksContext();
|
|
1336
1499
|
}
|
|
1337
1500
|
}
|
|
@@ -2587,7 +2750,7 @@ async function serveFile(filePath, options = {}) {
|
|
|
2587
2750
|
return '';
|
|
2588
2751
|
}
|
|
2589
2752
|
setHeader('etag', etag);
|
|
2590
|
-
setHeader('
|
|
2753
|
+
setHeader('last-modified', lastModified.toUTCString());
|
|
2591
2754
|
if (options.cacheControl !== undefined) {
|
|
2592
2755
|
setCacheControl(options.cacheControl);
|
|
2593
2756
|
}
|
|
@@ -2604,7 +2767,7 @@ async function serveFile(filePath, options = {}) {
|
|
|
2604
2767
|
}
|
|
2605
2768
|
else if (options.index) {
|
|
2606
2769
|
if (filePath[filePath.length - 1] !== '/' && url && url[url.length - 1] !== '/') {
|
|
2607
|
-
return new BaseWooksResponse().setStatus(302).setHeader('
|
|
2770
|
+
return new BaseWooksResponse().setStatus(302).setHeader('location', url + '/');
|
|
2608
2771
|
}
|
|
2609
2772
|
restoreCtx();
|
|
2610
2773
|
return serveFile(path__default.join(filePath, options.index), {
|
|
@@ -2613,7 +2776,7 @@ async function serveFile(filePath, options = {}) {
|
|
|
2613
2776
|
});
|
|
2614
2777
|
}
|
|
2615
2778
|
removeHeader('etag');
|
|
2616
|
-
removeHeader('
|
|
2779
|
+
removeHeader('last-modified');
|
|
2617
2780
|
throw new WooksError(404);
|
|
2618
2781
|
}
|
|
2619
2782
|
let range = headers.range;
|
|
@@ -2638,13 +2801,13 @@ async function serveFile(filePath, options = {}) {
|
|
|
2638
2801
|
range = '';
|
|
2639
2802
|
}
|
|
2640
2803
|
else {
|
|
2641
|
-
setHeader('
|
|
2804
|
+
setHeader('content-range', `bytes ${start}-${end}/${fileStats.size}`);
|
|
2642
2805
|
status(206);
|
|
2643
2806
|
}
|
|
2644
2807
|
}
|
|
2645
|
-
setHeader('
|
|
2646
|
-
setHeader('
|
|
2647
|
-
setHeader('
|
|
2808
|
+
setHeader('accept-ranges', 'bytes');
|
|
2809
|
+
setHeader('content-type', getMimeType(normalizedPath) || 'application/octet-stream');
|
|
2810
|
+
setHeader('content-length', size);
|
|
2648
2811
|
if (options.headers) {
|
|
2649
2812
|
for (const header of Object.keys(options.headers)) {
|
|
2650
2813
|
setHeader(header, options.headers[header]);
|
|
@@ -2722,6 +2885,7 @@ exports.useCacheObject = useCacheObject;
|
|
|
2722
2885
|
exports.useCookies = useCookies;
|
|
2723
2886
|
exports.useCurrentWooksContext = useCurrentWooksContext;
|
|
2724
2887
|
exports.useHeaders = useHeaders;
|
|
2888
|
+
exports.useProxy = useProxy;
|
|
2725
2889
|
exports.useRequest = useRequest;
|
|
2726
2890
|
exports.useRespCookie = useRespCookie;
|
|
2727
2891
|
exports.useRespHeader = useRespHeader;
|
package/dist/wooks.d.ts
CHANGED
|
@@ -35,12 +35,12 @@ export declare class BaseWooksResponse<BodyType = unknown> {
|
|
|
35
35
|
setHeader(name: string, value: string): this;
|
|
36
36
|
getHeader(name: string): string | string[];
|
|
37
37
|
protected mergeHeaders(): this;
|
|
38
|
-
protected mergeStatus(renderedBody: string): this;
|
|
38
|
+
protected mergeStatus(renderedBody: string | Uint8Array): this;
|
|
39
39
|
respond(): void;
|
|
40
40
|
}
|
|
41
41
|
|
|
42
42
|
export declare class BaseWooksResponseRenderer<T = unknown> implements TWooksResponseRenderer<T> {
|
|
43
|
-
render(response: BaseWooksResponse<T>): string;
|
|
43
|
+
render(response: BaseWooksResponse<T>): string | Uint8Array;
|
|
44
44
|
}
|
|
45
45
|
|
|
46
46
|
export declare function clearCacheObject(name: symbol | string): void;
|
|
@@ -423,8 +423,23 @@ export declare interface TWooksHook<T = string> {
|
|
|
423
423
|
export declare interface TWooksOptions {
|
|
424
424
|
}
|
|
425
425
|
|
|
426
|
+
export declare interface TWooksProxyControls {
|
|
427
|
+
overwrite?: Record<string, string> | ((data: Record<string, string>) => Record<string, string>);
|
|
428
|
+
allow?: (string | RegExp)[] | '*';
|
|
429
|
+
block?: (string | RegExp)[] | '*';
|
|
430
|
+
}
|
|
431
|
+
|
|
432
|
+
export declare interface TWooksProxyOptions {
|
|
433
|
+
method?: string;
|
|
434
|
+
reqHeaders?: TWooksProxyControls;
|
|
435
|
+
reqCookies?: TWooksProxyControls;
|
|
436
|
+
resHeaders?: TWooksProxyControls;
|
|
437
|
+
resCookies?: TWooksProxyControls;
|
|
438
|
+
debug?: boolean;
|
|
439
|
+
}
|
|
440
|
+
|
|
426
441
|
export declare interface TWooksResponseRenderer<T = unknown> {
|
|
427
|
-
render: (response: BaseWooksResponse<T>) => string;
|
|
442
|
+
render: (response: BaseWooksResponse<T>) => string | Uint8Array;
|
|
428
443
|
}
|
|
429
444
|
|
|
430
445
|
export declare function useAccept(): {
|
|
@@ -476,6 +491,8 @@ export declare function useCurrentWooksContext(): {
|
|
|
476
491
|
|
|
477
492
|
export declare function useHeaders(): IncomingHttpHeaders;
|
|
478
493
|
|
|
494
|
+
export declare function useProxy(): (target: string, opts?: TWooksProxyOptions) => Promise<Response>;
|
|
495
|
+
|
|
479
496
|
export declare function useRequest(): {
|
|
480
497
|
rawRequest: IncomingMessage;
|
|
481
498
|
url: string | undefined;
|
|
@@ -533,7 +550,7 @@ export declare function useSetHeaders(): {
|
|
|
533
550
|
setHeader: (name: string, value: string | number) => void;
|
|
534
551
|
removeHeader: (name: string) => void;
|
|
535
552
|
setContentType: (value: string) => void;
|
|
536
|
-
headers: Record<string, string>;
|
|
553
|
+
headers: Record<string, string | string[]>;
|
|
537
554
|
enableCors: (origin?: string) => void;
|
|
538
555
|
};
|
|
539
556
|
|