appstage 0.3.1 → 0.3.5

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 (54) hide show
  1. package/dist/index.d.ts +32 -0
  2. package/package.json +3 -6
  3. package/index.ts +0 -32
  4. package/src/controllers/files.ts +0 -250
  5. package/src/controllers/redirect.ts +0 -29
  6. package/src/controllers/unhandledError.ts +0 -15
  7. package/src/controllers/unhandledRoute.ts +0 -14
  8. package/src/lib/lang/getEffectiveLocale.ts +0 -52
  9. package/src/lib/lang/getLocales.ts +0 -10
  10. package/src/lib/lang/toLanguage.ts +0 -3
  11. package/src/lib/logger/LogOptions.ts +0 -8
  12. package/src/lib/logger/ansiEscapeCodes.ts +0 -6
  13. package/src/lib/logger/levelColors.ts +0 -4
  14. package/src/lib/logger/log.ts +0 -82
  15. package/src/middleware/init.ts +0 -22
  16. package/src/middleware/lang.ts +0 -83
  17. package/src/middleware/requestEvents.ts +0 -29
  18. package/src/scripts/bin.ts +0 -40
  19. package/src/scripts/build.ts +0 -80
  20. package/src/scripts/cli.ts +0 -43
  21. package/src/scripts/const/commonBuildOptions.ts +0 -13
  22. package/src/scripts/const/entryExtensions.ts +0 -1
  23. package/src/scripts/types/BuildParams.ts +0 -22
  24. package/src/scripts/utils/buildClient.ts +0 -42
  25. package/src/scripts/utils/buildServer.ts +0 -36
  26. package/src/scripts/utils/buildServerCSS.ts +0 -40
  27. package/src/scripts/utils/createPostbuildPlugins.ts +0 -66
  28. package/src/scripts/utils/getEntries.ts +0 -22
  29. package/src/scripts/utils/getEntryPoints.ts +0 -25
  30. package/src/scripts/utils/getFirstAvailable.ts +0 -22
  31. package/src/scripts/utils/setEntriesExport.ts +0 -30
  32. package/src/scripts/utils/toImportPath.ts +0 -12
  33. package/src/types/Controller.ts +0 -4
  34. package/src/types/ErrorController.ts +0 -3
  35. package/src/types/LogEventPayload.ts +0 -12
  36. package/src/types/LogLevel.ts +0 -1
  37. package/src/types/Middleware.ts +0 -7
  38. package/src/types/MiddlewareSet.ts +0 -3
  39. package/src/types/RenderStatus.ts +0 -9
  40. package/src/types/ReqCtx.ts +0 -11
  41. package/src/types/TransformContent.ts +0 -11
  42. package/src/types/express.d.ts +0 -15
  43. package/src/types/global.d.ts +0 -19
  44. package/src/utils/createApp.ts +0 -45
  45. package/src/utils/cspNonce.ts +0 -6
  46. package/src/utils/emitLog.ts +0 -18
  47. package/src/utils/getEntries.ts +0 -22
  48. package/src/utils/getServerURL.ts +0 -38
  49. package/src/utils/getStatusMessage.ts +0 -5
  50. package/src/utils/injectNonce.ts +0 -7
  51. package/src/utils/renderStatus.ts +0 -20
  52. package/src/utils/serializeState.ts +0 -3
  53. package/src/utils/servePipeableStream.ts +0 -32
  54. package/tsconfig.json +0 -19
@@ -1,29 +0,0 @@
1
- import type { Middleware } from "../types/Middleware.ts";
2
- import { emitLog } from "../utils/emitLog.ts";
3
- import { getStatusMessage } from "../utils/getStatusMessage.ts";
4
-
5
- /**
6
- * Adds event handlers, like logging, to essential request phases.
7
- */
8
- export const requestEvents: Middleware = () => (req, res, next) => {
9
- let finished = false;
10
-
11
- res.on("finish", () => {
12
- finished = true;
13
-
14
- emitLog(req.app, getStatusMessage("Finished", res.statusCode), {
15
- req,
16
- res,
17
- });
18
- });
19
-
20
- res.on("close", () => {
21
- if (!finished)
22
- emitLog(req.app, getStatusMessage("Closed", res.statusCode), {
23
- req,
24
- res,
25
- });
26
- });
27
-
28
- next();
29
- };
@@ -1,40 +0,0 @@
1
- #!/usr/bin/env node
2
- import { hasKey, isKey } from "args-json";
3
- import { cli } from "./cli.ts";
4
-
5
- const availableScriptNames = new Set(["build", "dev", "prod"]);
6
-
7
- const nodeEnvMap: Record<string, string> = {
8
- dev: "development",
9
- prod: "production",
10
- };
11
-
12
- async function run() {
13
- let [scriptName, ...args] = process.argv.slice(2);
14
-
15
- if (!availableScriptNames.has(scriptName)) {
16
- console.error("Provide a script name: 'build', 'dev', or 'prod'");
17
- return;
18
- }
19
-
20
- if (scriptName === "build") return await cli(args);
21
-
22
- let nodeEnv = nodeEnvMap[scriptName];
23
-
24
- if (nodeEnv !== undefined) process.env.NODE_ENV = nodeEnv;
25
-
26
- if (args.length !== 0 && args[0] && !isKey(args[0])) {
27
- process.env.SERVER_URL = args[0];
28
- args.shift();
29
- }
30
-
31
- if (!hasKey("--client-dir")) args.push("--client-dir", "src/public/-");
32
-
33
- await cli(
34
- nodeEnv === "development"
35
- ? ["--clean", "--start", "--watch", ...args]
36
- : ["--clean", "--start", "--silent", ...args],
37
- );
38
- }
39
-
40
- await run();
@@ -1,80 +0,0 @@
1
- import { type ChildProcess, spawn } from "node:child_process";
2
- import { access } from "node:fs/promises";
3
- import { formatDuration } from "dateshape";
4
- import type { BuildParams } from "./types/BuildParams.ts";
5
- import { buildClient } from "./utils/buildClient.ts";
6
- import { buildServer } from "./utils/buildServer.ts";
7
- import { buildServerCSS } from "./utils/buildServerCSS.ts";
8
- import { createPostbuildPlugins } from "./utils/createPostbuildPlugins.ts";
9
-
10
- const envFileNames: Record<string, string[]> = {
11
- development: [".env.development", ".env.dev"],
12
- production: [".env.production", ".env.prod"],
13
- };
14
-
15
- async function getEnvFiles() {
16
- let { NODE_ENV } = process.env;
17
- let names = [".env"];
18
-
19
- if (NODE_ENV !== undefined && NODE_ENV in envFileNames)
20
- names.push(...envFileNames[NODE_ENV]);
21
-
22
- for (let i = names.length - 1; i >= 0; i--) {
23
- try {
24
- await access(names[i]);
25
- } catch {
26
- names.splice(i, 1);
27
- }
28
- }
29
-
30
- return names;
31
- }
32
-
33
- export async function build(params: BuildParams) {
34
- let startTime = Date.now();
35
- let log = params.silent ? () => {} : console.log;
36
-
37
- log("Build started");
38
-
39
- let serverProcess: ChildProcess | null = null;
40
- let inited = false;
41
-
42
- let nodeArgs = [`${params.serverDir}/server/index.js`];
43
- let envFiles: string[] | null = null;
44
-
45
- if (params.useEnvFiles !== false) {
46
- envFiles = await getEnvFiles();
47
- nodeArgs.unshift(...envFiles.map((file) => `--env-file=${file}`));
48
- }
49
-
50
- function handleServerRebuild() {
51
- if (serverProcess) {
52
- serverProcess.kill();
53
- serverProcess = null;
54
- }
55
-
56
- if (!inited) {
57
- log(`Build completed +${formatDuration(Date.now() - startTime)}`);
58
-
59
- if (envFiles) {
60
- for (let envFile of envFiles) log(`Using ${envFile}`);
61
- }
62
-
63
- inited = true;
64
- }
65
-
66
- if (params.start)
67
- serverProcess = spawn("node", nodeArgs, { stdio: "inherit" });
68
- }
69
-
70
- let { serverPlugins, serverCSSPlugins } = createPostbuildPlugins(
71
- params,
72
- handleServerRebuild,
73
- );
74
-
75
- await Promise.all([
76
- buildServer(params, serverPlugins),
77
- buildServerCSS(params, serverCSSPlugins),
78
- buildClient(params),
79
- ]);
80
- }
@@ -1,43 +0,0 @@
1
- import { rm } from "node:fs/promises";
2
- import { Args } from "args-json";
3
- import { build } from "./build.ts";
4
- import type { BuildParams } from "./types/BuildParams.ts";
5
-
6
- async function clean({ serverDir, clientDir }: BuildParams) {
7
- let dirs = [`${serverDir}/server`, `${serverDir}/server-css`, clientDir];
8
-
9
- return Promise.all(
10
- dirs.map((dir) => rm(dir, { recursive: true, force: true })),
11
- );
12
- }
13
-
14
- export async function cli(input: string[] = []) {
15
- let args = new Args(input);
16
-
17
- let clientDir = args.getValue("--client-dir");
18
- let serverDir = args.getValue("--server-dir", "dist");
19
-
20
- if (!clientDir) throw new Error("Public assets directory is undefined");
21
-
22
- let params: BuildParams = {
23
- serverDir,
24
- clientDir,
25
- silent: args.hasKey("--silent"),
26
- watch: args.hasKey("--watch"),
27
- watchServer: args.hasKey("--watch-server"),
28
- watchClient: args.hasKey("--watch-client"),
29
- start: args.hasKey("--start"),
30
- useEnvFiles: !args.isExplicitlyOff("--use-env-files"),
31
- };
32
-
33
- if (args.hasKey("--no-auto-entries")) params.entriesPath = null;
34
-
35
- if (args.hasKey("--clean-only")) {
36
- await clean(params);
37
- return;
38
- }
39
-
40
- if (args.hasKey("--clean")) await clean(params);
41
-
42
- await build(params);
43
- }
@@ -1,13 +0,0 @@
1
- import type { BuildOptions } from "esbuild";
2
-
3
- export const commonBuildOptions: Partial<BuildOptions> = {
4
- format: "cjs",
5
- jsx: "automatic",
6
- jsxDev: process.env.NODE_ENV === "development",
7
- loader: {
8
- ".png": "dataurl",
9
- ".svg": "dataurl",
10
- ".html": "text",
11
- ".txt": "text",
12
- },
13
- };
@@ -1 +0,0 @@
1
- export const entryExtensions = ["js", "jsx", "ts", "tsx"];
@@ -1,22 +0,0 @@
1
- export type BuildParams = {
2
- serverDir: string;
3
- clientDir: string;
4
- silent?: boolean;
5
- watch?: boolean;
6
- watchClient?: boolean;
7
- watchServer?: boolean;
8
- start?: boolean;
9
- /**
10
- * A file path that the automatically picked entry exports will be
11
- * written to.
12
- *
13
- * Set it to `null` to skip the automatic picking of entry exports.
14
- *
15
- * @default "src/server/entries.ts"
16
- */
17
- entriesPath?: string | null;
18
- /**
19
- * @default true
20
- */
21
- useEnvFiles?: boolean;
22
- };
@@ -1,42 +0,0 @@
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
- const entryClientPaths = ["ui/index", "client/index", "index", "src/index"];
7
-
8
- /**
9
- * Builds the client-side code.
10
- */
11
- export async function buildClient(
12
- { clientDir, watch, watchClient }: BuildParams,
13
- plugins?: Plugin[],
14
- ) {
15
- let clientEntries = await getEntryPoints(entryClientPaths);
16
-
17
- let buildOptions: BuildOptions = {
18
- ...commonBuildOptions,
19
- entryPoints: clientEntries.map(({ path, name }) => ({
20
- in: path,
21
- out: `${name}/index`,
22
- })),
23
- bundle: true,
24
- splitting: true,
25
- format: "esm",
26
- outdir: clientDir,
27
- minify: process.env.NODE_ENV !== "development",
28
- plugins,
29
- };
30
-
31
- if (watch || watchClient) {
32
- let ctx = await esbuild.context(buildOptions);
33
-
34
- await ctx.watch();
35
-
36
- return async () => {
37
- await ctx.dispose();
38
- };
39
- }
40
-
41
- await esbuild.build(buildOptions);
42
- }
@@ -1,36 +0,0 @@
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 { setEntriesExport } from "./setEntriesExport.ts";
5
-
6
- const appServerEntryPoints = ["src/server/index.ts"];
7
-
8
- export async function buildServer(params: BuildParams, plugins?: Plugin[]) {
9
- let { serverDir, watch, watchServer } = params;
10
-
11
- await setEntriesExport(params);
12
-
13
- let buildOptions: BuildOptions = {
14
- ...commonBuildOptions,
15
- entryPoints: appServerEntryPoints,
16
- bundle: true,
17
- splitting: true,
18
- outdir: `${serverDir}/server`,
19
- platform: "node",
20
- format: "esm",
21
- packages: "external",
22
- plugins,
23
- };
24
-
25
- if (watch || watchServer) {
26
- let ctx = await esbuild.context(buildOptions);
27
-
28
- await ctx.watch();
29
-
30
- return async () => {
31
- await ctx.dispose();
32
- };
33
- }
34
-
35
- await esbuild.build(buildOptions);
36
- }
@@ -1,40 +0,0 @@
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
- const entryServerPaths = ["server", "server/index"];
7
-
8
- export async function buildServerCSS(
9
- { serverDir, watch, watchServer }: BuildParams,
10
- plugins?: Plugin[],
11
- ) {
12
- let serverEntries = await getEntryPoints(entryServerPaths);
13
-
14
- let buildOptions: BuildOptions = {
15
- ...commonBuildOptions,
16
- entryPoints: serverEntries.map(({ name, path }) => ({
17
- in: path,
18
- out: name,
19
- })),
20
- bundle: true,
21
- splitting: false,
22
- outdir: `${serverDir}/server-css`,
23
- platform: "node",
24
- format: "esm",
25
- packages: "external",
26
- plugins,
27
- };
28
-
29
- if (watch || watchServer) {
30
- let ctx = await esbuild.context(buildOptions);
31
-
32
- await ctx.watch();
33
-
34
- return async () => {
35
- await ctx.dispose();
36
- };
37
- }
38
-
39
- await esbuild.build(buildOptions);
40
- }
@@ -1,66 +0,0 @@
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
- { serverDir, clientDir }: BuildParams,
7
- onServerRebuild: (() => void) | (() => Promise<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 = `${serverDir}/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(clientDir, { recursive: true });
42
-
43
- await Promise.all(
44
- files.map(async (name) => {
45
- let dir = `${clientDir}/${name.slice(0, -4)}`;
46
-
47
- await mkdir(dir, { recursive: true });
48
- await rename(
49
- `${serverDir}/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
- }
@@ -1,22 +0,0 @@
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
- }
@@ -1,25 +0,0 @@
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
- }
@@ -1,22 +0,0 @@
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
- }
@@ -1,30 +0,0 @@
1
- import { writeFile } from "node:fs/promises";
2
- import type { BuildParams } from "../types/BuildParams.ts";
3
- import { getEntryPoints } from "./getEntryPoints.ts";
4
- import { toImportPath } from "./toImportPath.ts";
5
-
6
- export async function setEntriesExport({ entriesPath }: BuildParams) {
7
- if (entriesPath === null) return;
8
-
9
- let serverEntries = await getEntryPoints(["server", "server/index"]);
10
- let content = "";
11
-
12
- if (serverEntries.length === 0) content = "export const entries = [];";
13
- else {
14
- content = "export const entries = (\n await Promise.all([";
15
-
16
- for (let i = 0; i < serverEntries.length; i++)
17
- content += `\n import("${toImportPath(serverEntries[i].path, "src/server")}"),`;
18
-
19
- content += "\n ])\n).map(({ server }) => server);";
20
- }
21
-
22
- await writeFile(
23
- entriesPath ?? "src/server/entries.ts",
24
- `// Populated automatically during the build phase by picking
25
- // all server exports from "src/entries/<entry_name>/server(/index)?.(js|ts)".
26
- // Ignore this file if a custom set of entry exports is required.
27
- ${content}
28
- `,
29
- );
30
- }
@@ -1,12 +0,0 @@
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
- }
@@ -1,4 +0,0 @@
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;
@@ -1,3 +0,0 @@
1
- import type { ErrorRequestHandler } from "express";
2
-
3
- export type ErrorController<T = void> = (params: T) => ErrorRequestHandler;
@@ -1,12 +0,0 @@
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
- };
@@ -1 +0,0 @@
1
- export type LogLevel = "error" | "debug" | "info" | "warn";
@@ -1,7 +0,0 @@
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;
@@ -1,3 +0,0 @@
1
- import type { RequestHandler } from "express";
2
-
3
- export type MiddlewareSet<T = void> = (params: T) => RequestHandler[];
@@ -1,9 +0,0 @@
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>;
@@ -1,11 +0,0 @@
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
- };
@@ -1,11 +0,0 @@
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>;
@@ -1,15 +0,0 @@
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
- }
@@ -1,19 +0,0 @@
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
- }
18
-
19
- declare module "*.css";