appstage 0.2.1

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 (63) hide show
  1. package/LICENSE +21 -0
  2. package/README.md +0 -0
  3. package/dist/bin/build.js +532 -0
  4. package/dist/bin/startDev.js +545 -0
  5. package/dist/bin/startProd.js +545 -0
  6. package/dist/index.cjs +671 -0
  7. package/dist/index.d.ts +1162 -0
  8. package/dist/index.mjs +622 -0
  9. package/index.ts +32 -0
  10. package/package.json +39 -0
  11. package/src/controllers/dir.ts +119 -0
  12. package/src/controllers/unhandledError.ts +15 -0
  13. package/src/controllers/unhandledRoute.ts +14 -0
  14. package/src/lib/lang/getEffectiveLocale.ts +52 -0
  15. package/src/lib/lang/getLocales.ts +10 -0
  16. package/src/lib/lang/toLanguage.ts +3 -0
  17. package/src/lib/logger/LogOptions.ts +8 -0
  18. package/src/lib/logger/ansiEscapeCodes.ts +6 -0
  19. package/src/lib/logger/levelColors.ts +4 -0
  20. package/src/lib/logger/log.ts +82 -0
  21. package/src/middleware/init.ts +22 -0
  22. package/src/middleware/lang.ts +83 -0
  23. package/src/middleware/requestEvents.ts +29 -0
  24. package/src/scripts/bin/build.ts +5 -0
  25. package/src/scripts/bin/startDev.ts +5 -0
  26. package/src/scripts/bin/startProd.ts +5 -0
  27. package/src/scripts/build.ts +45 -0
  28. package/src/scripts/cli.ts +46 -0
  29. package/src/scripts/const/commonBuildOptions.ts +13 -0
  30. package/src/scripts/const/entryExtensions.ts +1 -0
  31. package/src/scripts/start.ts +18 -0
  32. package/src/scripts/types/BuildParams.ts +9 -0
  33. package/src/scripts/utils/buildClient.ts +41 -0
  34. package/src/scripts/utils/buildServer.ts +35 -0
  35. package/src/scripts/utils/buildServerCSS.ts +38 -0
  36. package/src/scripts/utils/createPostbuildPlugins.ts +66 -0
  37. package/src/scripts/utils/getEntries.ts +22 -0
  38. package/src/scripts/utils/getEntryPoints.ts +25 -0
  39. package/src/scripts/utils/getFirstAvailable.ts +22 -0
  40. package/src/scripts/utils/populateEntries.ts +28 -0
  41. package/src/scripts/utils/toImportPath.ts +12 -0
  42. package/src/types/Controller.ts +4 -0
  43. package/src/types/ErrorController.ts +3 -0
  44. package/src/types/LogEventPayload.ts +12 -0
  45. package/src/types/LogLevel.ts +1 -0
  46. package/src/types/Middleware.ts +7 -0
  47. package/src/types/MiddlewareSet.ts +3 -0
  48. package/src/types/RenderStatus.ts +9 -0
  49. package/src/types/ReqCtx.ts +11 -0
  50. package/src/types/TransformContent.ts +11 -0
  51. package/src/types/express.d.ts +15 -0
  52. package/src/types/global.d.ts +17 -0
  53. package/src/utils/createApp.ts +44 -0
  54. package/src/utils/cspNonce.ts +6 -0
  55. package/src/utils/emitLog.ts +18 -0
  56. package/src/utils/getEntries.ts +22 -0
  57. package/src/utils/getStatusMessage.ts +5 -0
  58. package/src/utils/injectNonce.ts +7 -0
  59. package/src/utils/renderStatus.ts +20 -0
  60. package/src/utils/resolveFilePath.ts +78 -0
  61. package/src/utils/serializeState.ts +3 -0
  62. package/src/utils/servePipeableStream.ts +32 -0
  63. package/tsconfig.json +18 -0
@@ -0,0 +1,35 @@
1
+ import esbuild, { type BuildOptions, type Plugin } from "esbuild";
2
+ import { commonBuildOptions } from "../const/commonBuildOptions.ts";
3
+ import type { BuildParams } from "../types/BuildParams.ts";
4
+ import { populateEntries } from "./populateEntries.ts";
5
+
6
+ export async function buildServer(
7
+ { targetDir, watch, watchServer }: BuildParams,
8
+ plugins?: Plugin[],
9
+ ) {
10
+ await populateEntries();
11
+
12
+ let buildOptions: BuildOptions = {
13
+ ...commonBuildOptions,
14
+ entryPoints: ["src/server/index.ts"],
15
+ bundle: true,
16
+ splitting: true,
17
+ outdir: `${targetDir}/server`,
18
+ platform: "node",
19
+ format: "esm",
20
+ packages: "external",
21
+ plugins,
22
+ };
23
+
24
+ if (watch || watchServer) {
25
+ let ctx = await esbuild.context(buildOptions);
26
+
27
+ await ctx.watch();
28
+
29
+ return async () => {
30
+ await ctx.dispose();
31
+ };
32
+ }
33
+
34
+ await esbuild.build(buildOptions);
35
+ }
@@ -0,0 +1,38 @@
1
+ import esbuild, { type BuildOptions, type Plugin } from "esbuild";
2
+ import { commonBuildOptions } from "../const/commonBuildOptions.ts";
3
+ import type { BuildParams } from "../types/BuildParams.ts";
4
+ import { getEntryPoints } from "./getEntryPoints.ts";
5
+
6
+ export async function buildServerCSS(
7
+ { targetDir, watch, watchServer }: BuildParams,
8
+ plugins?: Plugin[],
9
+ ) {
10
+ let serverEntries = await getEntryPoints(["server", "server/index"]);
11
+
12
+ let buildOptions: BuildOptions = {
13
+ ...commonBuildOptions,
14
+ entryPoints: serverEntries.map(({ name, path }) => ({
15
+ in: path,
16
+ out: name,
17
+ })),
18
+ bundle: true,
19
+ splitting: false,
20
+ outdir: `${targetDir}/server-css`,
21
+ platform: "node",
22
+ format: "esm",
23
+ packages: "external",
24
+ plugins,
25
+ };
26
+
27
+ if (watch || watchServer) {
28
+ let ctx = await esbuild.context(buildOptions);
29
+
30
+ await ctx.watch();
31
+
32
+ return async () => {
33
+ await ctx.dispose();
34
+ };
35
+ }
36
+
37
+ await esbuild.build(buildOptions);
38
+ }
@@ -0,0 +1,66 @@
1
+ import { mkdir, readdir, rename, rm } from "node:fs/promises";
2
+ import type { Plugin } from "esbuild";
3
+ import type { BuildParams } from "../types/BuildParams.ts";
4
+
5
+ export function createPostbuildPlugins(
6
+ { targetDir, publicAssetsDir }: BuildParams,
7
+ onServerRebuild: () => void,
8
+ ) {
9
+ let serverPlugins: Plugin[] = [
10
+ {
11
+ name: "skip-css",
12
+ setup(build) {
13
+ /** @see https://github.com/evanw/esbuild/issues/599#issuecomment-745118158 */
14
+ build.onLoad({ filter: /\.css$/ }, () => ({ contents: "" }));
15
+ },
16
+ },
17
+ {
18
+ name: "postbuild-server",
19
+ setup(build) {
20
+ build.onEnd(() => {
21
+ onServerRebuild();
22
+ });
23
+ },
24
+ },
25
+ ];
26
+
27
+ let serverCSSPlugins: Plugin[] = [
28
+ {
29
+ name: "postbuild-server-css",
30
+ setup(build) {
31
+ build.onEnd(async () => {
32
+ let dir = `${targetDir}/server-css`;
33
+
34
+ try {
35
+ let files = (await readdir(dir)).filter((name) =>
36
+ name.endsWith(".css"),
37
+ );
38
+
39
+ if (files.length === 0) return;
40
+
41
+ await mkdir(`${publicAssetsDir}/-`, { recursive: true });
42
+
43
+ await Promise.all(
44
+ files.map(async (name) => {
45
+ let dir = `${publicAssetsDir}/-/${name.slice(0, -4)}`;
46
+
47
+ await mkdir(dir, { recursive: true });
48
+ await rename(
49
+ `${targetDir}/server-css/${name}`,
50
+ `${dir}/index.css`,
51
+ );
52
+ }),
53
+ );
54
+
55
+ await rm(dir, { recursive: true, force: true });
56
+ } catch {}
57
+ });
58
+ },
59
+ },
60
+ ];
61
+
62
+ return {
63
+ serverPlugins,
64
+ serverCSSPlugins,
65
+ };
66
+ }
@@ -0,0 +1,22 @@
1
+ import { lstat, readdir } from "node:fs/promises";
2
+ import { join } from "node:path";
3
+
4
+ export async function getEntries() {
5
+ let cwd = process.cwd();
6
+
7
+ try {
8
+ let list = await readdir(join(cwd, "src/entries"));
9
+
10
+ let dirs = await Promise.all(
11
+ list.map(async (name) => {
12
+ let itemStat = await lstat(join(cwd, "src/entries", name));
13
+
14
+ return itemStat.isDirectory() ? name : undefined;
15
+ }),
16
+ );
17
+
18
+ return dirs.filter((dir) => dir !== undefined);
19
+ } catch {
20
+ return [];
21
+ }
22
+ }
@@ -0,0 +1,25 @@
1
+ import { getEntries } from "./getEntries.ts";
2
+ import { getFirstAvailable } from "./getFirstAvailable.ts";
3
+
4
+ type EntryPoint = {
5
+ name: string;
6
+ path: string;
7
+ };
8
+
9
+ export async function getEntryPoints(
10
+ path: string | string[],
11
+ ): Promise<EntryPoint[]> {
12
+ let entries = await getEntries();
13
+
14
+ return (
15
+ await Promise.all(
16
+ entries.map(async (name) => {
17
+ let resolvedPath = await getFirstAvailable(`src/entries/${name}`, path);
18
+
19
+ return resolvedPath === undefined
20
+ ? undefined
21
+ : { name, path: resolvedPath };
22
+ }),
23
+ )
24
+ ).filter((item) => item !== undefined);
25
+ }
@@ -0,0 +1,22 @@
1
+ import { access } from "node:fs/promises";
2
+ import { join } from "node:path";
3
+ import { entryExtensions } from "../const/entryExtensions.ts";
4
+
5
+ export async function getFirstAvailable(
6
+ dirPath: string,
7
+ path: string | string[],
8
+ ) {
9
+ let paths = Array.isArray(path) ? path : [path];
10
+
11
+ for (let filePath of paths) {
12
+ for (let ext of entryExtensions) {
13
+ let path = join(process.cwd(), dirPath, `${filePath}.${ext}`);
14
+
15
+ try {
16
+ await access(path);
17
+
18
+ return path;
19
+ } catch {}
20
+ }
21
+ }
22
+ }
@@ -0,0 +1,28 @@
1
+ import { writeFile } from "node:fs/promises";
2
+ import { getEntryPoints } from "./getEntryPoints.ts";
3
+ import { toImportPath } from "./toImportPath.ts";
4
+
5
+ export async function populateEntries() {
6
+ let serverEntries = await getEntryPoints(["server", "server/index"]);
7
+ let content = "";
8
+
9
+ if (serverEntries.length === 0) content = "export const entries = [];";
10
+ else {
11
+ content = "export const entries = (\n await Promise.all([";
12
+
13
+ for (let i = 0; i < serverEntries.length; i++) {
14
+ content += `\n // ${serverEntries[i].name}
15
+ import("${toImportPath(serverEntries[i].path, "src/server")}"),`;
16
+ }
17
+
18
+ content += "\n ])\n).map(({ server }) => server);";
19
+ }
20
+
21
+ await writeFile(
22
+ "src/server/entries.ts",
23
+ `// Populated automatically during the build phase by picking
24
+ // all server exports from 'src/entries/<entry_name>/server(/index)?.(js|ts)'
25
+ ${content}
26
+ `,
27
+ );
28
+ }
@@ -0,0 +1,12 @@
1
+ import { join, posix, relative, sep } from "node:path";
2
+
3
+ export function toImportPath(relativePath: string, referencePath = ".") {
4
+ let cwd = process.cwd();
5
+ let importPath = posix.join(
6
+ ...relative(join(cwd, referencePath), relativePath).split(sep),
7
+ );
8
+
9
+ if (importPath && !/^\.+\//.test(importPath)) importPath = `./${importPath}`;
10
+
11
+ return importPath;
12
+ }
@@ -0,0 +1,4 @@
1
+ import type { RequestHandler } from "express";
2
+
3
+ /** Defines a final request handler sending a response */
4
+ export type Controller<T = void> = (params: T) => RequestHandler;
@@ -0,0 +1,3 @@
1
+ import type { ErrorRequestHandler } from "express";
2
+
3
+ export type ErrorController<T = void> = (params: T) => ErrorRequestHandler;
@@ -0,0 +1,12 @@
1
+ import type { Request, Response } from "express";
2
+ import type { LogLevel } from "./LogLevel.ts";
3
+
4
+ export type LogEventPayload = {
5
+ timestamp?: number;
6
+ level?: LogLevel;
7
+ message?: string | Error;
8
+ status?: number;
9
+ req?: Request;
10
+ res?: Response;
11
+ data?: unknown;
12
+ };
@@ -0,0 +1 @@
1
+ export type LogLevel = "error" | "debug" | "info" | "warn";
@@ -0,0 +1,7 @@
1
+ import type { RequestHandler } from "express";
2
+
3
+ /**
4
+ * Defines an intermediate request handler performing manipulations
5
+ * with request data without sending a response
6
+ */
7
+ export type Middleware<T = void> = (params: T) => RequestHandler;
@@ -0,0 +1,3 @@
1
+ import type { RequestHandler } from "express";
2
+
3
+ export type MiddlewareSet<T = void> = (params: T) => RequestHandler[];
@@ -0,0 +1,9 @@
1
+ import type { Request, Response } from "express";
2
+
3
+ type SendParam = Parameters<Response["send"]>[0];
4
+
5
+ export type RenderStatus = (
6
+ req: Request,
7
+ res: Response,
8
+ payload?: unknown,
9
+ ) => Promise<SendParam>;
@@ -0,0 +1,11 @@
1
+ /** Session request data collected on the server via `req.ctx` */
2
+ export type ReqCtx = {
3
+ /** Request ID */
4
+ id?: string;
5
+ /** CSP nonce */
6
+ nonce?: string;
7
+ /** When the request started to be handled */
8
+ startTime?: number;
9
+ /** User locale */
10
+ lang?: string;
11
+ };
@@ -0,0 +1,11 @@
1
+ import type { Request, Response } from "express";
2
+
3
+ export type TransformContent = (
4
+ req: Request,
5
+ res: Response,
6
+ params: {
7
+ content: string;
8
+ path?: string;
9
+ name?: string;
10
+ },
11
+ ) => string | Promise<string>;
@@ -0,0 +1,15 @@
1
+ import EventEmitter from "node:events";
2
+ import type { RenderStatus } from "../types/RenderStatus.ts";
3
+ import type { ReqCtx } from "./ReqCtx.ts";
4
+
5
+ declare global {
6
+ namespace Express {
7
+ interface Request {
8
+ ctx: ReqCtx;
9
+ }
10
+ interface Application {
11
+ events?: EventEmitter;
12
+ renderStatus?: RenderStatus;
13
+ }
14
+ }
15
+ }
@@ -0,0 +1,17 @@
1
+ declare module "*.svg" {
2
+ let content: string;
3
+
4
+ export default content;
5
+ }
6
+
7
+ declare module "*.txt" {
8
+ let content: string;
9
+
10
+ export default content;
11
+ }
12
+
13
+ declare module "*.html" {
14
+ let content: string;
15
+
16
+ export default content;
17
+ }
@@ -0,0 +1,44 @@
1
+ import EventEmitter from "node:events";
2
+ import express from "express";
3
+ import { log } from "../lib/logger/log.ts";
4
+ import { init } from "../middleware/init.ts";
5
+ import { requestEvents } from "../middleware/requestEvents.ts";
6
+ import type { LogEventPayload } from "../types/LogEventPayload.ts";
7
+ import { emitLog } from "./emitLog.ts";
8
+ import { renderStatus } from "./renderStatus.ts";
9
+
10
+ export function createApp(callback?: () => void | Promise<void>) {
11
+ let app = express();
12
+
13
+ if (!app.events) app.events = new EventEmitter();
14
+
15
+ let host = process.env.APP_HOST || "localhost";
16
+ let port = Number(process.env.APP_PORT) || 80;
17
+
18
+ let listen = () => {
19
+ app.listen(port, host, () => {
20
+ let location = `http://${host}:${port}/`;
21
+ let env = `NODE_ENV=${process.env.NODE_ENV}`;
22
+
23
+ emitLog(app, `Server running at ${location} (${env})`);
24
+ });
25
+ };
26
+
27
+ if (process.env.NODE_ENV === "development")
28
+ app.events?.on("log", ({ message, ...payload }: LogEventPayload) => {
29
+ log(message, payload);
30
+ });
31
+
32
+ if (!app.renderStatus) app.renderStatus = renderStatus;
33
+
34
+ app.disable("x-powered-by");
35
+ app.use(init());
36
+ app.use(requestEvents());
37
+
38
+ let callbackResult = typeof callback === "function" ? callback() : null;
39
+
40
+ if (callbackResult instanceof Promise) callbackResult.then(listen);
41
+ else listen();
42
+
43
+ return app;
44
+ }
@@ -0,0 +1,6 @@
1
+ import type { IncomingMessage } from "node:http";
2
+ import type { Request } from "express";
3
+
4
+ export const cspNonce = (req: IncomingMessage) => {
5
+ return `'nonce-${(req as Request).ctx?.nonce}'`;
6
+ };
@@ -0,0 +1,18 @@
1
+ import type { Application } from "express";
2
+ import type { LogEventPayload } from "../types/LogEventPayload.ts";
3
+
4
+ export function emitLog(
5
+ app: Application,
6
+ message?: LogEventPayload["message"] | LogEventPayload,
7
+ payload?: LogEventPayload,
8
+ ) {
9
+ let normalizedPayload: LogEventPayload = {
10
+ timestamp: Date.now(),
11
+ ...payload,
12
+ ...(typeof message === "string" || message instanceof Error
13
+ ? { message }
14
+ : message),
15
+ };
16
+
17
+ return app.events?.emit("log", normalizedPayload);
18
+ }
@@ -0,0 +1,22 @@
1
+ import { lstat, readdir } from "node:fs/promises";
2
+ import { join } from "node:path";
3
+
4
+ export async function getEntries() {
5
+ let cwd = process.cwd();
6
+
7
+ try {
8
+ let list = await readdir(join(cwd, "src/entries"));
9
+
10
+ let dirs = await Promise.all(
11
+ list.map(async (name) => {
12
+ let itemStat = await lstat(join(cwd, "src/entries", name));
13
+
14
+ return itemStat.isDirectory() ? name : undefined;
15
+ }),
16
+ );
17
+
18
+ return dirs.filter((dir) => dir !== undefined);
19
+ } catch {
20
+ return [];
21
+ }
22
+ }
@@ -0,0 +1,5 @@
1
+ import { STATUS_CODES } from "node:http";
2
+
3
+ export function getStatusMessage(prefix: string, statusCode: number) {
4
+ return `${prefix} - [${statusCode}] ${STATUS_CODES[statusCode]}`;
5
+ }
@@ -0,0 +1,7 @@
1
+ import type { TransformContent } from "../types/TransformContent.ts";
2
+
3
+ export const injectNonce: TransformContent = (req, _res, { content }) => {
4
+ let { nonce } = req.ctx;
5
+
6
+ return nonce ? content.replace(/\{\{nonce\}\}/g, nonce) : content;
7
+ };
@@ -0,0 +1,20 @@
1
+ import { STATUS_CODES } from "node:http";
2
+ import type { RenderStatus } from "../types/RenderStatus.ts";
3
+
4
+ export const renderStatus: RenderStatus = async (req, res) => {
5
+ let { id, nonce } = req.ctx;
6
+ let statusText = `${res.statusCode} ${STATUS_CODES[res.statusCode]}`;
7
+ let date = `${new Date().toISOString().replace(/T/, " ").replace(/Z$/, "")} UTC`;
8
+
9
+ return (
10
+ "<!DOCTYPE html>" +
11
+ '<html><head><meta charset="utf-8"/>' +
12
+ '<meta name="viewport" content="width=device-width"/>' +
13
+ `<title>${statusText}</title>` +
14
+ `<style${nonce ? ` nonce="${nonce}"` : ""}>` +
15
+ "body{text-align:center;}</style></head>" +
16
+ `<body><h1>${statusText}</h1><hr/><p>` +
17
+ (id ? `<code>ID: ${id}</code><br/>` : "") +
18
+ `<code>${date}</code></p></body></html>`
19
+ );
20
+ };
@@ -0,0 +1,78 @@
1
+ import { access } from "node:fs/promises";
2
+ import { join } from "node:path";
3
+ import { toLanguage } from "../lib/lang/toLanguage.ts";
4
+
5
+ export type ResolveFilePathParams = {
6
+ name: string;
7
+ dir?: string;
8
+ lang?: string;
9
+ supportedLocales?: string[];
10
+ /** Allowed file extensions. */
11
+ ext?: string | string[];
12
+ /**
13
+ * Whether an index file should be checked if the resolved file name
14
+ * doesn't correspond to an existing file.
15
+ *
16
+ * @defaultValue `true`
17
+ */
18
+ index?: boolean;
19
+ };
20
+
21
+ export async function resolveFilePath({
22
+ name,
23
+ dir = ".",
24
+ lang,
25
+ supportedLocales = [],
26
+ ext,
27
+ index,
28
+ }: ResolveFilePathParams) {
29
+ let cwd = process.cwd();
30
+
31
+ let localeSet = new Set(supportedLocales);
32
+ let langSet = new Set(supportedLocales.map(toLanguage));
33
+
34
+ let availableNames = [
35
+ name,
36
+ ...[...localeSet, ...langSet].map((item) => `${name}.${item}`),
37
+ ];
38
+
39
+ let preferredLangNames: string[] | undefined;
40
+
41
+ if (
42
+ lang &&
43
+ (!supportedLocales.length || localeSet.has(lang) || langSet.has(lang))
44
+ )
45
+ preferredLangNames = [`${name}.${lang}`, `${name}.${toLanguage(lang)}`];
46
+
47
+ let names = new Set(
48
+ preferredLangNames
49
+ ? [...preferredLangNames, ...availableNames]
50
+ : availableNames,
51
+ );
52
+
53
+ let exts = Array.isArray(ext) ? ext : [ext];
54
+
55
+ for (let item of names) {
56
+ for (let itemExt of exts) {
57
+ let path = join(cwd, dir, `${item}${itemExt ? `.${itemExt}` : ""}`);
58
+
59
+ try {
60
+ await access(path);
61
+ return path;
62
+ } catch {}
63
+ }
64
+ }
65
+
66
+ if (index) {
67
+ for (let item of names) {
68
+ for (let itemExt of exts) {
69
+ let path = join(cwd, dir, item, `index${itemExt ? `.${itemExt}` : ""}`);
70
+
71
+ try {
72
+ await access(path);
73
+ return path;
74
+ } catch {}
75
+ }
76
+ }
77
+ }
78
+ }
@@ -0,0 +1,3 @@
1
+ export function serializeState(state: unknown) {
2
+ return JSON.stringify(state).replace(/</g, "\\x3c");
3
+ }
@@ -0,0 +1,32 @@
1
+ import type { Request, Response } from "express";
2
+ import { emitLog } from "./emitLog.ts";
3
+ import { getStatusMessage } from "./getStatusMessage.ts";
4
+
5
+ type PipeableStream = {
6
+ pipe: <Writable extends NodeJS.WritableStream>(
7
+ destination: Writable,
8
+ ) => Writable;
9
+ };
10
+
11
+ export function servePipeableStream(req: Request, res: Response) {
12
+ return async ({ pipe }: PipeableStream, error?: unknown) => {
13
+ let statusCode = error ? 500 : 200;
14
+
15
+ emitLog(req.app, getStatusMessage("Stream", statusCode), {
16
+ level: error ? "error" : undefined,
17
+ req,
18
+ res,
19
+ data: error,
20
+ });
21
+
22
+ res.status(statusCode);
23
+
24
+ if (statusCode >= 400) {
25
+ res.send(await req.app.renderStatus?.(req, res));
26
+ return;
27
+ }
28
+
29
+ res.set("Content-Type", "text/html");
30
+ pipe(res);
31
+ };
32
+ }
package/tsconfig.json ADDED
@@ -0,0 +1,18 @@
1
+ {
2
+ "include": ["./index.ts", "./src"],
3
+ "compilerOptions": {
4
+ "declaration": true,
5
+ "emitDeclarationOnly": true,
6
+ "outDir": "dist",
7
+ "lib": ["ESNext"],
8
+ "target": "ESNext",
9
+ "module": "nodenext",
10
+ "moduleResolution": "nodenext",
11
+ "allowImportingTsExtensions": true,
12
+ "resolveJsonModule": true,
13
+ "allowSyntheticDefaultImports": true,
14
+ "strict": true,
15
+ "noUnusedLocals": true,
16
+ "noUnusedParameters": true
17
+ }
18
+ }