Repository navigation
Expand file tree
/
Copy pathapp.mts
More file actions
61 lines (54 loc) · 2.49 KB
/
Copy pathapp.mts
File metadata and controls
61 lines (54 loc) · 2.49 KB
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
/*
* Copyright 2026 1o1 Co. Ltd.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
/**
* The composition root: the process entry point, which runs at import — there
* is no exported factory. It parses and validates `../config/application.conf`
* once, then mounts, in this order, the healthcheck at the root, CORS and
* the mode router under `http.pathPrefix`, and a `404` for whatever neither
* answered; listens, answers `Expect: 100-continue` against the body limit
* (`continueWithinLimit`), and installs graceful shutdown.
*
* The `404` is answered at once, without reading the body: express's own
* waits for the body to end first, and an oversized upload that expected
* 100-continue outside the prefix is not told to send one.
*/
import { parseFile } from "@o3co/ts.hocon";
import { validate } from "@o3co/ts.hocon/zod";
import express from "express";
import { type AppConfig, AppConfigSchema } from "../config/application.schema.mjs";
import { resolveRouter } from "./app-internal.mjs";
import logger from "./logger.mjs";
import { bodyLimitBytes, continueWithinLimit } from "./router/body-limit.mjs";
import * as routers from "./router/index.mjs";
import { installGracefulShutdown } from "./shutdown.mjs";
const config: AppConfig = validate(
parseFile(new URL("../config/application.conf", import.meta.url).pathname),
AppConfigSchema,
);
// The proxy announces no framework of its own; a proxied answer carries the
// upstream's `X-Powered-By`, if any.
const app = express().disable("x-powered-by");
const server = app
.use(routers.Healthcheck.createRouter())
.use(config.http.pathPrefix, routers.Cors.createCors(config), resolveRouter(config))
.use((_req: express.Request, res: express.Response) => {
res.sendStatus(404);
})
.listen(config.http.port, config.http.hostname, () => {
logger.info(`Server ready at http://${config.http.hostname}:${config.http.port}`);
});
server.on("checkContinue", continueWithinLimit(bodyLimitBytes(config), app));
installGracefulShutdown(server, { logger });