primate 0.11.0 → 0.13.0
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/LICENSE +0 -2
- package/README.md +52 -99
- package/eslint.config.js +1 -0
- package/exports.js +1 -3
- package/module.json +10 -5
- package/package.json +14 -17
- package/readme/extensions/handlers/html/user.js +13 -0
- package/readme/extensions/handlers/htmx/user-index.html +4 -0
- package/readme/extensions/handlers/htmx/user.js +23 -0
- package/readme/extensions/handlers/redirect/user.js +6 -0
- package/readme/{domains → extensions/modules/domains}/fields.js +3 -4
- package/readme/{domains → extensions/modules/domains}/predicates.js +3 -3
- package/readme/{domains → extensions/modules/domains}/short-field-notation.js +3 -3
- package/readme/routing/basic.js +1 -1
- package/readme/routing/explicit-handlers.js +4 -0
- package/readme/routing/sharing-logic-across-requests.js +2 -2
- package/readme/serving-content/html.js +10 -11
- package/readme/serving-content/json.js +2 -2
- package/readme/serving-content/plain-text.js +1 -1
- package/readme/serving-content/response.js +6 -0
- package/readme/serving-content/streams.js +1 -1
- package/readme/template.md +135 -0
- package/scripts/docs.sh +7 -0
- package/src/bin.js +2 -0
- package/src/bundle.js +14 -7
- package/src/compile.js +5 -0
- package/src/config.js +73 -0
- package/src/duck.js +4 -0
- package/src/extend.spec.js +19 -27
- package/src/handlers/exports.js +5 -0
- package/src/handlers/html.js +18 -0
- package/src/handlers/http404.js +6 -4
- package/src/handlers/json.js +6 -4
- package/src/handlers/redirect.js +7 -0
- package/src/handlers/stream.js +6 -4
- package/src/handlers/text.js +6 -11
- package/src/http-statuses.js +5 -0
- package/src/index.html +8 -0
- package/src/log.js +7 -4
- package/src/mimes.js +12 -0
- package/src/register.js +5 -0
- package/src/respond.js +24 -0
- package/src/route.js +15 -28
- package/src/run.js +10 -9
- package/src/serve.js +25 -12
- package/README.template.md +0 -190
- package/bin/primate.js +0 -5
- package/readme/getting-started/generate-ssl.sh +0 -1
- package/readme/getting-started/lay-out-app.sh +0 -1
- package/readme/getting-started/site-index.html +0 -1
- package/readme/getting-started/site.js +0 -3
- package/src/conf.js +0 -30
- package/src/http-statuses.json +0 -5
- package/src/mimes.json +0 -12
- package/src/preset/stores/default.js +0 -2
- /package/readme/{serving-content → extensions/handlers/html}/user-index.html +0 -0
- /package/readme/{modules → extensions/modules}/configure.js +0 -0
- /package/readme/{modules → extensions/modules}/domains/configure.js +0 -0
- /package/readme/{getting-started/hello.js → getting-started.js} +0 -0
- /package/src/{preset/primate.conf.js → primate.config.js} +0 -0
package/scripts/docs.sh
ADDED
package/src/bin.js
ADDED
package/src/bundle.js
CHANGED
|
@@ -1,14 +1,21 @@
|
|
|
1
|
-
import {File} from "runtime-compat/
|
|
1
|
+
import {File} from "runtime-compat/fs";
|
|
2
|
+
const filter = (key, array) => array?.flatMap(m => m[key] ?? []) ?? [];
|
|
2
3
|
|
|
3
|
-
|
|
4
|
+
const makePublic = async env => {
|
|
4
5
|
const {paths} = env;
|
|
6
|
+
|
|
7
|
+
// remove public directory in case exists
|
|
8
|
+
if (await paths.public.exists) {
|
|
9
|
+
await paths.public.file.remove();
|
|
10
|
+
}
|
|
11
|
+
await paths.public.file.create();
|
|
12
|
+
|
|
5
13
|
if (await paths.static.exists) {
|
|
6
|
-
// remove public directory in case exists
|
|
7
|
-
if (await paths.public.exists) {
|
|
8
|
-
await paths.public.file.remove();
|
|
9
|
-
}
|
|
10
|
-
await paths.public.file.create();
|
|
11
14
|
// copy static files to public
|
|
12
15
|
await File.copy(paths.static, paths.public);
|
|
13
16
|
}
|
|
14
17
|
};
|
|
18
|
+
|
|
19
|
+
export default async env => await makePublic(env) &&
|
|
20
|
+
[...filter("bundle", env.modules), _ => _].reduceRight((acc, handler) =>
|
|
21
|
+
input => handler(input, acc))(env);
|
package/src/compile.js
ADDED
package/src/config.js
ADDED
|
@@ -0,0 +1,73 @@
|
|
|
1
|
+
import {File, Path} from "runtime-compat/fs";
|
|
2
|
+
import {is} from "runtime-compat/dyndef";
|
|
3
|
+
import cache from "./cache.js";
|
|
4
|
+
import extend from "./extend.js";
|
|
5
|
+
import defaults from "./primate.config.js";
|
|
6
|
+
import * as log from "./log.js";
|
|
7
|
+
import * as handlers from "./handlers/exports.js";
|
|
8
|
+
import package_json from "../package.json" assert {type: "json"};
|
|
9
|
+
|
|
10
|
+
const qualify = (root, paths) =>
|
|
11
|
+
Object.keys(paths).reduce((sofar, key) => {
|
|
12
|
+
const value = paths[key];
|
|
13
|
+
sofar[key] = typeof value === "string"
|
|
14
|
+
? new Path(root, value)
|
|
15
|
+
: qualify(`${root}/${key}`, value);
|
|
16
|
+
return sofar;
|
|
17
|
+
}, {});
|
|
18
|
+
|
|
19
|
+
const getConfig = async (root, filename) => {
|
|
20
|
+
try {
|
|
21
|
+
return extend(defaults, (await import(root.join(filename))).default);
|
|
22
|
+
} catch (error) {
|
|
23
|
+
return defaults;
|
|
24
|
+
}
|
|
25
|
+
};
|
|
26
|
+
|
|
27
|
+
const getRoot = async () => {
|
|
28
|
+
try {
|
|
29
|
+
// use module root if possible
|
|
30
|
+
return await Path.root();
|
|
31
|
+
} catch (error) {
|
|
32
|
+
// fall back to current directory
|
|
33
|
+
return Path.resolve();
|
|
34
|
+
}
|
|
35
|
+
};
|
|
36
|
+
|
|
37
|
+
const index = async env => {
|
|
38
|
+
const name = "index.html";
|
|
39
|
+
try {
|
|
40
|
+
// user-provided file
|
|
41
|
+
return await File.read(`${env.paths.static.join(name)}`);
|
|
42
|
+
} catch (error) {
|
|
43
|
+
// fallback
|
|
44
|
+
return new Path(import.meta.url).directory.join(name).file.read();
|
|
45
|
+
}
|
|
46
|
+
};
|
|
47
|
+
|
|
48
|
+
export default async (filename = "primate.config.js") => {
|
|
49
|
+
is(filename).string();
|
|
50
|
+
const root = await getRoot();
|
|
51
|
+
const config = await getConfig(root, filename);
|
|
52
|
+
|
|
53
|
+
const env = {
|
|
54
|
+
...config,
|
|
55
|
+
paths: qualify(root, config.paths),
|
|
56
|
+
root,
|
|
57
|
+
log: {...log, error: error => log.error(error, config)},
|
|
58
|
+
register: (name, handler) => {
|
|
59
|
+
env.handlers[name] = handler;
|
|
60
|
+
},
|
|
61
|
+
handlers: {...handlers},
|
|
62
|
+
render: async html => (await index(env)).replace("%body%", () => html),
|
|
63
|
+
};
|
|
64
|
+
env.log.info(`${package_json.name} \x1b[34m${package_json.version}\x1b[0m`);
|
|
65
|
+
const modules = await Promise.all(config.modules.map(module => module(env)));
|
|
66
|
+
// modules may load other modules
|
|
67
|
+
const loads = await Promise.all(modules
|
|
68
|
+
.filter(module => module.load !== undefined)
|
|
69
|
+
.map(module => module.load()(env)));
|
|
70
|
+
|
|
71
|
+
return cache("config", filename, () => ({...env,
|
|
72
|
+
modules: modules.concat(loads)}));
|
|
73
|
+
};
|
package/src/duck.js
ADDED
package/src/extend.spec.js
CHANGED
|
@@ -40,20 +40,20 @@ export default test => {
|
|
|
40
40
|
});
|
|
41
41
|
|
|
42
42
|
test.case("one property of a subobject", assert => {
|
|
43
|
-
const base = {key: {
|
|
44
|
-
const extension = {key: {
|
|
43
|
+
const base = {key: {subkey: "subvalue"}};
|
|
44
|
+
const extension = {key: {subkey: "subvalue 2"}};
|
|
45
45
|
assert(extend(base, extension)).equals(extension);
|
|
46
46
|
});
|
|
47
47
|
|
|
48
48
|
test.case("two properties of a subobject, one replaced", assert => {
|
|
49
|
-
|
|
50
|
-
|
|
51
|
-
|
|
52
|
-
|
|
53
|
-
|
|
49
|
+
const base = {key: {subkey: "subvalue", subkey2: "subvalue2"}};
|
|
50
|
+
const extension = {key: {subkey: "subvalue 2"}};
|
|
51
|
+
const extended = {key: {subkey: "subvalue 2", subkey2: "subvalue2"}};
|
|
52
|
+
assert(extend(base, extension)).equals(extended);
|
|
53
|
+
});
|
|
54
54
|
|
|
55
|
-
test.case("
|
|
56
|
-
const
|
|
55
|
+
test.case("config enhancement", assert => {
|
|
56
|
+
const base = {
|
|
57
57
|
base: "/",
|
|
58
58
|
debug: false,
|
|
59
59
|
defaults: {
|
|
@@ -61,16 +61,14 @@ export default test => {
|
|
|
61
61
|
context: "guest",
|
|
62
62
|
},
|
|
63
63
|
paths: {
|
|
64
|
-
client: "client",
|
|
65
|
-
data: {
|
|
66
|
-
domains: "domains",
|
|
67
|
-
stores: "stores",
|
|
68
|
-
},
|
|
69
64
|
public: "public",
|
|
65
|
+
static: "static",
|
|
66
|
+
routes: "routes",
|
|
67
|
+
components: "components",
|
|
70
68
|
},
|
|
71
69
|
};
|
|
72
70
|
|
|
73
|
-
const
|
|
71
|
+
const additional = {
|
|
74
72
|
debug: true,
|
|
75
73
|
environment: "testing",
|
|
76
74
|
defaults: {
|
|
@@ -78,11 +76,7 @@ export default test => {
|
|
|
78
76
|
mode: "operational",
|
|
79
77
|
},
|
|
80
78
|
paths: {
|
|
81
|
-
client: "
|
|
82
|
-
data: {
|
|
83
|
-
stores: "storage",
|
|
84
|
-
drivers: "drivers",
|
|
85
|
-
},
|
|
79
|
+
client: "client",
|
|
86
80
|
},
|
|
87
81
|
};
|
|
88
82
|
|
|
@@ -96,16 +90,14 @@ export default test => {
|
|
|
96
90
|
mode: "operational",
|
|
97
91
|
},
|
|
98
92
|
paths: {
|
|
99
|
-
client: "
|
|
100
|
-
data: {
|
|
101
|
-
domains: "domains",
|
|
102
|
-
drivers: "drivers",
|
|
103
|
-
stores: "storage",
|
|
104
|
-
},
|
|
93
|
+
client: "client",
|
|
105
94
|
public: "public",
|
|
95
|
+
static: "static",
|
|
96
|
+
routes: "routes",
|
|
97
|
+
components: "components",
|
|
106
98
|
},
|
|
107
99
|
};
|
|
108
100
|
|
|
109
|
-
assert(extend(
|
|
101
|
+
assert(extend(base, additional)).equals(extended);
|
|
110
102
|
});
|
|
111
103
|
};
|
|
@@ -0,0 +1,18 @@
|
|
|
1
|
+
const getContent = async (env, name) => {
|
|
2
|
+
try {
|
|
3
|
+
return await env.paths.components.join(`${name}.html`).file.read();
|
|
4
|
+
} catch (error) {
|
|
5
|
+
throw new Error(`cannot load component at ${name}.html`);
|
|
6
|
+
}
|
|
7
|
+
};
|
|
8
|
+
|
|
9
|
+
export default (content, {status = 200, partial = false, adhoc = false} = {}) =>
|
|
10
|
+
async (env, headers) => {
|
|
11
|
+
const html = adhoc ? content : await getContent(env, content);
|
|
12
|
+
return [
|
|
13
|
+
partial ? html : await env.render(html), {
|
|
14
|
+
status,
|
|
15
|
+
headers: {...headers, "Content-Type": "text/html"},
|
|
16
|
+
},
|
|
17
|
+
];
|
|
18
|
+
};
|
package/src/handlers/http404.js
CHANGED
package/src/handlers/json.js
CHANGED
|
@@ -1,4 +1,6 @@
|
|
|
1
|
-
export default (
|
|
2
|
-
|
|
3
|
-
|
|
4
|
-
}
|
|
1
|
+
export default (body, {status = 200} = {}) => (_, headers) => [
|
|
2
|
+
JSON.stringify(body), {
|
|
3
|
+
status,
|
|
4
|
+
headers: {...headers, "Content-Type": "application/json"},
|
|
5
|
+
},
|
|
6
|
+
];
|
package/src/handlers/stream.js
CHANGED
|
@@ -1,4 +1,6 @@
|
|
|
1
|
-
export default (
|
|
2
|
-
|
|
3
|
-
|
|
4
|
-
}
|
|
1
|
+
export default (body, {status = 200} = {}) => (_, headers) => [
|
|
2
|
+
body, {
|
|
3
|
+
status,
|
|
4
|
+
headers: {...headers, "Content-Type": "application/octet-stream"},
|
|
5
|
+
},
|
|
6
|
+
];
|
package/src/handlers/text.js
CHANGED
|
@@ -1,11 +1,6 @@
|
|
|
1
|
-
|
|
2
|
-
|
|
3
|
-
|
|
4
|
-
|
|
5
|
-
|
|
6
|
-
|
|
7
|
-
.map((string, i) => string + awaitedKeys[i])
|
|
8
|
-
.join("") + strings[strings.length + last];
|
|
9
|
-
|
|
10
|
-
return [body, {status: 200, headers: {"Content-Type": "text/plain"}}];
|
|
11
|
-
};
|
|
1
|
+
export default (body, {status = 200} = {}) => (_, headers) => [
|
|
2
|
+
body, {
|
|
3
|
+
status,
|
|
4
|
+
headers: {...headers, "Content-Type": "text/plain"},
|
|
5
|
+
},
|
|
6
|
+
];
|
package/src/index.html
ADDED
package/src/log.js
CHANGED
|
@@ -19,8 +19,11 @@ const log = new Proxy(Log, {
|
|
|
19
19
|
log.paint(colors[property] ?? reset, message).paint(reset, " ")),
|
|
20
20
|
});
|
|
21
21
|
|
|
22
|
-
export
|
|
23
|
-
|
|
24
|
-
|
|
25
|
-
|
|
22
|
+
export const info = (...args) => log.green("[info]").reset(...args).nl();
|
|
23
|
+
|
|
24
|
+
export const warn = (...args) => log.yellow("[warn]").reset(...args).nl();
|
|
25
|
+
|
|
26
|
+
export const error = (originalError, env) => {
|
|
27
|
+
log.red("[error]").reset(originalError.message).nl();
|
|
28
|
+
env.debug && console.log(originalError);
|
|
26
29
|
};
|
package/src/mimes.js
ADDED
|
@@ -0,0 +1,12 @@
|
|
|
1
|
+
export default {
|
|
2
|
+
binary: "application/octet-stream",
|
|
3
|
+
css: "text/css",
|
|
4
|
+
html: "text/html",
|
|
5
|
+
jpg: "image/jpeg",
|
|
6
|
+
js: "text/javascript",
|
|
7
|
+
json: "application/json",
|
|
8
|
+
png: "image/png",
|
|
9
|
+
svg: "image/svg+xml",
|
|
10
|
+
woff2: "font/woff2",
|
|
11
|
+
webp: "image/webp",
|
|
12
|
+
};
|
package/src/register.js
ADDED
package/src/respond.js
ADDED
|
@@ -0,0 +1,24 @@
|
|
|
1
|
+
import {Blob} from "runtime-compat/fs";
|
|
2
|
+
import {text, json, stream} from "./handlers/exports.js";
|
|
3
|
+
import {isResponse as isResponseDuck} from "./duck.js";
|
|
4
|
+
import RouteError from "./errors/Route.js";
|
|
5
|
+
|
|
6
|
+
const isText = value => {
|
|
7
|
+
if (typeof value === "string") {
|
|
8
|
+
return text(value);
|
|
9
|
+
}
|
|
10
|
+
throw new RouteError(`no handler found for ${value}`);
|
|
11
|
+
};
|
|
12
|
+
|
|
13
|
+
const isNonNullObject = value => typeof value === "object" && value !== null;
|
|
14
|
+
const isObject = value => isNonNullObject(value)
|
|
15
|
+
? json(value) : isText(value);
|
|
16
|
+
const isResponse = value => isResponseDuck(value)
|
|
17
|
+
? () => value : isObject(value);
|
|
18
|
+
const isStream = value => value instanceof ReadableStream
|
|
19
|
+
? stream(value) : isResponse(value);
|
|
20
|
+
const isBlob = value => value instanceof Blob
|
|
21
|
+
? stream(value) : isStream(value);
|
|
22
|
+
const guess = value => isBlob(value);
|
|
23
|
+
|
|
24
|
+
export default result => typeof result === "function" ? result : guess(result);
|
package/src/route.js
CHANGED
|
@@ -1,29 +1,17 @@
|
|
|
1
|
-
import {
|
|
2
|
-
import {Path, File} from "runtime-compat/filesystem";
|
|
1
|
+
import {Path} from "runtime-compat/fs";
|
|
3
2
|
import {is} from "runtime-compat/dyndef";
|
|
4
|
-
import text from "./handlers/text.js";
|
|
5
|
-
import json from "./handlers/json.js";
|
|
6
|
-
import stream from "./handlers/stream.js";
|
|
7
3
|
import RouteError from "./errors/Route.js";
|
|
8
4
|
|
|
9
|
-
const isText = value => {
|
|
10
|
-
if (typeof value === "string") {
|
|
11
|
-
return text`${value}`;
|
|
12
|
-
}
|
|
13
|
-
throw new RouteError(`no handler found for ${value}`);
|
|
14
|
-
};
|
|
15
|
-
const isObject = value => typeof value === "object" && value !== null
|
|
16
|
-
? json`${value}` : isText(value);
|
|
17
|
-
const isStream = value => value instanceof ReadableStream
|
|
18
|
-
? stream`${value}` : isObject(value);
|
|
19
|
-
const isFile = value => value instanceof File
|
|
20
|
-
? stream`${value}` : isStream(value);
|
|
21
|
-
const guess = value => isFile(value);
|
|
22
|
-
|
|
23
5
|
// insensitive-case equal
|
|
24
6
|
const ieq = (left, right) => left.toLowerCase() === right.toLowerCase();
|
|
25
|
-
|
|
26
|
-
|
|
7
|
+
// HTTP verbs
|
|
8
|
+
const verbs = [
|
|
9
|
+
// CRUD
|
|
10
|
+
"post", "get", "put", "delete",
|
|
11
|
+
// extended
|
|
12
|
+
"delete", "connect", "options", "trace", "patch",
|
|
13
|
+
];
|
|
14
|
+
export default async (definitions, handlers) => {
|
|
27
15
|
const aliases = [];
|
|
28
16
|
const routes = [];
|
|
29
17
|
const expand = path => aliases.reduce((expanded, {key, value}) =>
|
|
@@ -43,11 +31,11 @@ export default async definitions => {
|
|
|
43
31
|
ieq(route.method, method) && route.path.test(path)) ?? fallback;
|
|
44
32
|
|
|
45
33
|
const router = {
|
|
34
|
+
...Object.fromEntries(verbs.map(verb =>
|
|
35
|
+
[verb, (path, callback) => add(verb, path, callback)])),
|
|
46
36
|
map: (path, callback) => add("map", path, callback),
|
|
47
|
-
get: (path, callback) => add("get", path, callback),
|
|
48
|
-
post: (path, callback) => add("post", path, callback),
|
|
49
37
|
alias: (key, value) => aliases.push({key, value}),
|
|
50
|
-
|
|
38
|
+
route: async request => {
|
|
51
39
|
const {method} = request.original;
|
|
52
40
|
const url = new URL(`https://primatejs.com${request.pathname}`);
|
|
53
41
|
const {pathname, searchParams} = url;
|
|
@@ -58,15 +46,14 @@ export default async definitions => {
|
|
|
58
46
|
const path = pathname.split("/").filter(part => part !== "");
|
|
59
47
|
const named = verb.path?.exec(pathname)?.groups ?? {};
|
|
60
48
|
|
|
61
|
-
|
|
49
|
+
return verb.handler(await find("map", pathname)
|
|
62
50
|
.handler({...request, pathname, params, path, named}));
|
|
63
|
-
|
|
64
|
-
return typeof result === "function" ? result : guess(result);
|
|
65
51
|
},
|
|
66
52
|
};
|
|
67
53
|
if (await definitions.exists) {
|
|
68
54
|
const files = (await Path.list(definitions)).map(route => import(route));
|
|
69
|
-
await Promise.all(files.map(async route =>
|
|
55
|
+
await Promise.all(files.map(async route =>
|
|
56
|
+
(await route).default(router, handlers)));
|
|
70
57
|
}
|
|
71
58
|
return router;
|
|
72
59
|
};
|
package/src/run.js
CHANGED
|
@@ -1,13 +1,14 @@
|
|
|
1
|
-
import
|
|
2
|
-
import
|
|
1
|
+
import config from "./config.js";
|
|
2
|
+
import register from "./register.js";
|
|
3
|
+
import compile from "./compile.js";
|
|
3
4
|
import bundle from "./bundle.js";
|
|
5
|
+
import route from "./route.js";
|
|
6
|
+
import serve from "./serve.js";
|
|
4
7
|
|
|
5
|
-
|
|
6
|
-
|
|
7
|
-
|
|
8
|
-
|
|
9
|
-
const router = await route(paths.routes);
|
|
8
|
+
export default async () => {
|
|
9
|
+
const env = await config();
|
|
10
|
+
await register(env);
|
|
11
|
+
await compile(env);
|
|
10
12
|
await bundle(env);
|
|
11
|
-
|
|
12
|
-
await serve({router, ...env, modules: extract(env.modules ?? [], "serve")});
|
|
13
|
+
serve({router: await route(env.paths.routes, env.handlers), ...env});
|
|
13
14
|
};
|
package/src/serve.js
CHANGED
|
@@ -1,12 +1,16 @@
|
|
|
1
|
-
import {Path} from "runtime-compat/
|
|
1
|
+
import {Path} from "runtime-compat/fs";
|
|
2
2
|
import {serve, Response} from "runtime-compat/http";
|
|
3
|
-
import statuses from "./http-statuses.
|
|
4
|
-
import mimes from "./mimes.
|
|
3
|
+
import statuses from "./http-statuses.js";
|
|
4
|
+
import mimes from "./mimes.js";
|
|
5
5
|
import {http404} from "./handlers/http.js";
|
|
6
|
+
import {isResponse} from "./duck.js";
|
|
7
|
+
import respond from "./respond.js";
|
|
6
8
|
|
|
7
9
|
const regex = /\.([a-z1-9]*)$/u;
|
|
8
10
|
const mime = filename => mimes[filename.match(regex)[1]] ?? mimes.binary;
|
|
9
11
|
|
|
12
|
+
const filter = (key, array) => array?.flatMap(m => m[key] ?? []) ?? [];
|
|
13
|
+
|
|
10
14
|
const contents = {
|
|
11
15
|
"application/x-www-form-urlencoded": body =>
|
|
12
16
|
Object.fromEntries(body.split("&").map(part => part.split("=")
|
|
@@ -15,8 +19,7 @@ const contents = {
|
|
|
15
19
|
};
|
|
16
20
|
|
|
17
21
|
export default env => {
|
|
18
|
-
const
|
|
19
|
-
let result;
|
|
22
|
+
const _respond = async request => {
|
|
20
23
|
const csp = Object.keys(env.http.csp).reduce((policy_string, key) =>
|
|
21
24
|
`${policy_string}${key} ${env.http.csp[key]};`, "");
|
|
22
25
|
const headers = {
|
|
@@ -25,12 +28,21 @@ export default env => {
|
|
|
25
28
|
};
|
|
26
29
|
|
|
27
30
|
try {
|
|
28
|
-
|
|
31
|
+
const {router} = env;
|
|
32
|
+
const modules = filter("route", env.modules);
|
|
33
|
+
// handle is the last module to be executed
|
|
34
|
+
const handlers = [...modules, router.route].reduceRight((acc, handler) =>
|
|
35
|
+
input => handler(input, acc));
|
|
36
|
+
return await respond(await handlers(request))(env, headers);
|
|
29
37
|
} catch (error) {
|
|
30
|
-
env.error(error
|
|
31
|
-
|
|
38
|
+
env.log.error(error);
|
|
39
|
+
return http404()(env, headers);
|
|
32
40
|
}
|
|
33
|
-
|
|
41
|
+
};
|
|
42
|
+
|
|
43
|
+
const route = async request => {
|
|
44
|
+
const response = await _respond(request);
|
|
45
|
+
return isResponse(response) ? response : new Response(...response);
|
|
34
46
|
};
|
|
35
47
|
|
|
36
48
|
const resource = async file => new Response(file.readable, {
|
|
@@ -50,7 +62,7 @@ export default env => {
|
|
|
50
62
|
try {
|
|
51
63
|
return await _serve(request);
|
|
52
64
|
} catch (error) {
|
|
53
|
-
env.error(error
|
|
65
|
+
env.log.error(error);
|
|
54
66
|
return new Response(null, {status: statuses.InternalServerError});
|
|
55
67
|
}
|
|
56
68
|
};
|
|
@@ -60,7 +72,8 @@ export default env => {
|
|
|
60
72
|
return type === undefined ? body : type(body);
|
|
61
73
|
};
|
|
62
74
|
|
|
63
|
-
const {http
|
|
75
|
+
const {http} = env;
|
|
76
|
+
const modules = filter("serve", env.modules);
|
|
64
77
|
|
|
65
78
|
// handle is the last module to be executed
|
|
66
79
|
const handlers = [...modules, handle].reduceRight((acc, handler) =>
|
|
@@ -87,5 +100,5 @@ export default env => {
|
|
|
87
100
|
return handlers({original: request, pathname: pathname + search, body});
|
|
88
101
|
}, http);
|
|
89
102
|
|
|
90
|
-
env.info(`running on ${http.host}:${http.port}`);
|
|
103
|
+
env.log.info(`running on ${http.host}:${http.port}`);
|
|
91
104
|
};
|