kuwan-expresspack-core 0.1.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/README.md ADDED
@@ -0,0 +1,21 @@
1
+ # core (kuwan core)
2
+
3
+ Stripped down version, no auth module, just pure express api + utilities
4
+
5
+ ## Environment Variables
6
+
7
+ - `NODE_ENV`: Set to `production` to disable type generation for config files.
8
+ - `EXPRESSPACK_EVENT_EMITTER_DEBUG`: Set to `true` to enable debug logging for the event emitter.
9
+ - `APP_LOG_LEVEL`: Set the log level for the application. Default: `3`.
10
+
11
+ Log levels:
12
+ ```
13
+ 0: Fatal and Error
14
+ 1: Warnings
15
+ 2: Normal logs
16
+ 3: Informational logs, success, fail, ready, start, ...
17
+ 4: Debug logs
18
+ 5: Trace logs
19
+ -999: Silent
20
+ +999: Verbose logs
21
+ ```
@@ -0,0 +1,40 @@
1
+ #!/usr/bin/env node
2
+ import { defineCommand, runMain } from "citty";
3
+ import path from "node:path";
4
+ import dayjs from 'dayjs';
5
+ import utc from "dayjs/plugin/utc.js";
6
+ dayjs.extend(utc);
7
+
8
+ const main = defineCommand({
9
+ meta: {
10
+ name: "expresspack",
11
+ version: "1.0.0"
12
+ },
13
+ subCommands: {
14
+ auth: () => defineCommand({
15
+ async run({ rawArgs }) {
16
+ console.log("Running auth command with args:", rawArgs);
17
+ const originalArgv = process.argv;
18
+ rawArgs.push(...[
19
+ '--output',
20
+ path.join(
21
+ 'src', 'db', 'auth_migrations',
22
+ dayjs().utc().format('YYYY-MM-DDTHH-mm-ss.SSS') + '.sql'
23
+ ),
24
+ ])
25
+ process.argv = ['node', 'better-auth',
26
+ ...rawArgs];
27
+
28
+ try {
29
+ // Import and execute better-auth CLI directly
30
+ await import('@better-auth/cli');
31
+ } finally {
32
+ // Restore original argv
33
+ process.argv = originalArgv;
34
+ }
35
+ }
36
+ })
37
+ }
38
+ });
39
+
40
+ runMain(main);
@@ -0,0 +1,9 @@
1
+ #!/usr/bin/env node
2
+ import { defineCommand, runMain } from 'citty';
3
+ import r, { dirname, resolve } from 'path';
4
+ import { fileURLToPath } from 'url';
5
+ import d from 'dayjs';
6
+ import l from 'dayjs/plugin/utc.js';
7
+ import { execa } from 'execa';
8
+
9
+ d.extend(l);var u=defineCommand({meta:{name:"expresspack-api",version:"1.0.0"},subCommands:{"db-pull":()=>defineCommand({async run({rawArgs:o}){console.log("Running db-pull command with args:",o);let i=fileURLToPath(import.meta.url),m=dirname(i),e=resolve(m,r.join("..","..","node_modules",".bin","drizzle-kit"));await execa({stdout:["pipe","inherit"]})`${e} pull ${o.join(" ")}`;}})}});runMain(u);
@@ -0,0 +1,5 @@
1
+ import Bun, { BuildConfig } from 'bun';
2
+
3
+ declare function bunBuild(options?: BuildConfig): Promise<Bun.BuildOutput>;
4
+
5
+ export { bunBuild };
@@ -0,0 +1,49 @@
1
+ import Bun from 'bun';
2
+ import { join } from 'path';
3
+
4
+ // src/build-tools/bun-build.ts
5
+ var DEFAULT_BUILD_OPTIONS = {
6
+ minify: process.env.NODE_ENV === "production",
7
+ entrypoints: ["./src/app.ts"],
8
+ outdir: "./dist",
9
+ format: "esm",
10
+ target: "node",
11
+ splitting: true,
12
+ naming: {
13
+ entry: "[dir]/[name].[ext]",
14
+ chunk: "chunks/[name]-[hash].[ext]",
15
+ asset: "assets/[name]-[hash].[ext]"
16
+ }
17
+ };
18
+ async function bunBuild(options) {
19
+ const buildOptions = {
20
+ ...DEFAULT_BUILD_OPTIONS,
21
+ ...options
22
+ };
23
+ const packageJson = {
24
+ name: "server-prod",
25
+ version: "0.0.0",
26
+ type: "module",
27
+ private: true,
28
+ dependencies: {}
29
+ };
30
+ const outDir = buildOptions.outdir;
31
+ if (!outDir) {
32
+ throw new Error("`outdir` must be specified in the build options.");
33
+ }
34
+ try {
35
+ const result = await Bun.build(buildOptions);
36
+ await Bun.write(
37
+ join(outDir, "package.json"),
38
+ JSON.stringify(packageJson, null, 2)
39
+ );
40
+ return Promise.resolve(result);
41
+ } catch (e) {
42
+ const error = e;
43
+ return Promise.reject(error);
44
+ }
45
+ }
46
+
47
+ export { bunBuild };
48
+ //# sourceMappingURL=index.mjs.map
49
+ //# sourceMappingURL=index.mjs.map
@@ -0,0 +1 @@
1
+ {"version":3,"sources":["../../src/build-tools/bun-build.ts"],"names":[],"mappings":";;;;AAGA,IAAM,qBAAA,GAAqC;AAAA,EACvC,MAAA,EAAQ,OAAA,CAAQ,GAAA,CAAI,QAAA,KAAa,YAAA;AAAA,EACjC,WAAA,EAAa,CAAC,cAAc,CAAA;AAAA,EAC5B,MAAA,EAAQ,QAAA;AAAA,EACR,MAAA,EAAQ,KAAA;AAAA,EACR,MAAA,EAAQ,MAAA;AAAA,EACR,SAAA,EAAW,IAAA;AAAA,EACX,MAAA,EAAQ;AAAA,IACN,KAAA,EAAO,oBAAA;AAAA,IACP,KAAA,EAAO,4BAAA;AAAA,IACP,KAAA,EAAO;AAAA;AAEb,CAAA;AAEA,eAAsB,SAAS,OAAA,EAAuB;AAClD,EAAA,MAAM,YAAA,GAA4B;AAAA,IAC9B,GAAG,qBAAA;AAAA,IACH,GAAG;AAAA,GACP;AAGA,EAAA,MAAM,WAAA,GAAc;AAAA,IAChB,IAAA,EAAM,aAAA;AAAA,IACN,OAAA,EAAS,OAAA;AAAA,IACT,IAAA,EAAM,QAAA;AAAA,IACN,OAAA,EAAS,IAAA;AAAA,IACT,cAAc;AAAC,GACnB;AAEA,EAAA,MAAM,SAAS,YAAA,CAAa,MAAA;AAC5B,EAAA,IAAI,CAAC,MAAA,EAAQ;AACT,IAAA,MAAM,IAAI,MAAM,kDAAkD,CAAA;AAAA,EACtE;AAEA,EAAA,IAAI;AACA,IAAA,MAAM,MAAA,GAAS,MAAM,GAAA,CAAI,KAAA,CAAM,YAAY,CAAA;AAC3C,IAAA,MAAM,GAAA,CAAI,KAAA;AAAA,MACN,IAAA,CAAK,QAAQ,cAAc,CAAA;AAAA,MAC3B,IAAA,CAAK,SAAA,CAAU,WAAA,EAAa,IAAA,EAAM,CAAC;AAAA,KACvC;AACA,IAAA,OAAO,OAAA,CAAQ,QAAQ,MAAM,CAAA;AAAA,EACjC,SAAS,CAAA,EAAG;AAER,IAAA,MAAM,KAAA,GAAQ,CAAA;AACd,IAAA,OAAO,OAAA,CAAQ,OAAO,KAAK,CAAA;AAAA,EAI/B;AACJ","file":"index.mjs","sourcesContent":["import Bun, { type BuildConfig } from 'bun';\nimport { join } from 'node:path';\n\nconst DEFAULT_BUILD_OPTIONS: BuildConfig = {\n minify: process.env.NODE_ENV === 'production',\n entrypoints: ['./src/app.ts'],\n outdir: './dist',\n format: \"esm\",\n target: \"node\",\n splitting: true,\n naming: {\n entry: '[dir]/[name].[ext]',\n chunk: 'chunks/[name]-[hash].[ext]',\n asset: 'assets/[name]-[hash].[ext]',\n },\n}\n\nexport async function bunBuild(options?: BuildConfig) {\n const buildOptions: BuildConfig = {\n ...DEFAULT_BUILD_OPTIONS,\n ...options,\n };\n\n // Uses fixed value for now to set `type` to \"module\" just to run it through Node runtime using ESM\n const packageJson = {\n name: \"server-prod\",\n version: \"0.0.0\",\n type: \"module\",\n private: true,\n dependencies: {}\n };\n\n const outDir = buildOptions.outdir;\n if (!outDir) {\n throw new Error(\"`outdir` must be specified in the build options.\");\n }\n \n try { \n const result = await Bun.build(buildOptions);\n await Bun.write(\n join(outDir, 'package.json'), \n JSON.stringify(packageJson, null, 2)\n ); \n return Promise.resolve(result);\n } catch (e) {\n // TypeScript does not allow annotations on the catch clause\n const error = e as AggregateError;\n return Promise.reject(error);\n // console.error(\"Build Failed\");\n // console.error(error);\n // console.error(JSON.stringify(error, null, 2));\n }\n}"]}
@@ -0,0 +1,10 @@
1
+ // src/config.ts
2
+ var config = {};
3
+ var config_default = config;
4
+ function getAppConfig(key) {
5
+ return config[key];
6
+ }
7
+
8
+ export { config_default, getAppConfig };
9
+ //# sourceMappingURL=chunk-6PQFCZAJ.mjs.map
10
+ //# sourceMappingURL=chunk-6PQFCZAJ.mjs.map
@@ -0,0 +1 @@
1
+ {"version":3,"sources":["../src/config.ts"],"names":[],"mappings":";AAAA,IAAM,SAAkC,EAAC;AAEzC,IAAO,cAAA,GAAQ;AAGR,SAAS,aAA4C,GAAA,EAA0B;AACpF,EAAA,OAAO,OAAO,GAAG,CAAA;AACnB","file":"chunk-6PQFCZAJ.mjs","sourcesContent":["const config: Record<string, unknown> = {};\n\nexport default config;\n\nexport function getAppConfig<K>(key: string): K;\nexport function getAppConfig<K extends keyof typeof config>(key: K): typeof config[K] {\n return config[key];\n}"]}
@@ -0,0 +1,26 @@
1
+ import Emittery from 'emittery';
2
+ import { env } from 'process';
3
+
4
+ // src/services/event/index.ts
5
+ function isDebugEnabled() {
6
+ return env.EXPRESSPACK_EVENT_EMITTER_DEBUG === "true" || env.EXPRESSPACK_EVENT_EMITTER_DEBUG === "1" || (typeof env.EXPRESSPACK_EVENT_EMITTER_DEBUG === "boolean" ? env.EXPRESSPACK_EVENT_EMITTER_DEBUG === true : false);
7
+ }
8
+ var emitter = new Emittery({
9
+ debug: {
10
+ name: "expresspack-emitter",
11
+ enabled: isDebugEnabled()
12
+ }
13
+ });
14
+ function createEmitter() {
15
+ return new Emittery({
16
+ debug: {
17
+ name: "c-emitter",
18
+ enabled: isDebugEnabled()
19
+ }
20
+ });
21
+ }
22
+ var event_default = emitter;
23
+
24
+ export { createEmitter, emitter, event_default };
25
+ //# sourceMappingURL=chunk-7UHB7O5G.mjs.map
26
+ //# sourceMappingURL=chunk-7UHB7O5G.mjs.map
@@ -0,0 +1 @@
1
+ {"version":3,"sources":["../src/services/event/index.ts"],"names":[],"mappings":";;;;AASA,SAAS,cAAA,GAA0B;AAC/B,EAAA,OAAO,GAAA,CAAI,+BAAA,KAAoC,MAAA,IACxC,GAAA,CAAI,+BAAA,KAAoC,GAAA,KAEtC,OAAO,GAAA,CAAI,+BAAA,KAAoC,SAAA,GAChD,GAAA,CAAI,+BAAA,KAAoC,IAAA,GAAO,KAAA,CAAA;AAE3D;AAKA,IAAM,OAAA,GAAU,IAAI,QAAA,CAAwB;AAAA,EACxC,KAAA,EAAO;AAAA,IACH,IAAA,EAAM,qBAAA;AAAA,IACN,SAAS,cAAA;AAAe;AAEhC,CAAC;AAKM,SAAS,aAAA,GAAsE;AAClF,EAAA,OAAO,IAAI,QAAA,CAAY;AAAA,IACnB,KAAA,EAAO;AAAA,MACH,IAAA,EAAM,WAAA;AAAA,MACN,SAAS,cAAA;AAAe;AAC5B,GACH,CAAA;AACL;AAGA,IAAO,aAAA,GAAQ","file":"chunk-7UHB7O5G.mjs","sourcesContent":["import Emittery from 'emittery';\nimport { env } from 'node:process'\n/**\n * Base event map that users can extend in their applications\n */\nexport interface EmitterEvents {\n [key: string]: any;\n}\n\nfunction isDebugEnabled(): boolean {\n return env.EXPRESSPACK_EVENT_EMITTER_DEBUG === 'true' \n || env.EXPRESSPACK_EVENT_EMITTER_DEBUG === '1' \n || (\n (typeof env.EXPRESSPACK_EVENT_EMITTER_DEBUG === 'boolean') ? \n env.EXPRESSPACK_EVENT_EMITTER_DEBUG === true : false\n );\n}\n\n/**\n * Default emitter instance for convenient access\n */\nconst emitter = new Emittery<EmitterEvents>({\n debug: {\n name: 'expresspack-emitter',\n enabled: isDebugEnabled()\n }\n});\n\n/**\n * Create a new emitter instance (for testing or isolated use)\n */\nexport function createEmitter<T extends EmitterEvents = EmitterEvents>(): Emittery<T> {\n return new Emittery<T>({\n debug: {\n name: 'c-emitter',\n enabled: isDebugEnabled()\n }\n });\n}\n\nexport { emitter };\nexport default emitter;"]}
@@ -0,0 +1,84 @@
1
+ // src/error.ts
2
+ var CUSTOM_ERROR_SYMBOL = Symbol("expresspackCustomError");
3
+ var CustomError = class _CustomError extends Error {
4
+ status;
5
+ code;
6
+ statusCode;
7
+ data;
8
+ isOperational;
9
+ [CUSTOM_ERROR_SYMBOL] = true;
10
+ constructor({
11
+ message = "An error occurred",
12
+ code = "INTERNAL_SERVER_ERROR",
13
+ statusCode = 500,
14
+ data = null,
15
+ isOperational = true,
16
+ sanitizeData = true
17
+ } = {}) {
18
+ super(message);
19
+ this.name = "CustomError";
20
+ this.status = statusCode;
21
+ this.code = code;
22
+ this.statusCode = statusCode;
23
+ this.isOperational = isOperational;
24
+ this.data = sanitizeData ? this.sanitizeDataForJSON(data) : data;
25
+ if (Error.captureStackTrace) {
26
+ Error.captureStackTrace(this, this.constructor);
27
+ }
28
+ Object.setPrototypeOf(this, _CustomError.prototype);
29
+ }
30
+ static isCustomError(error) {
31
+ return error !== null && typeof error === "object" && CUSTOM_ERROR_SYMBOL in error && error[CUSTOM_ERROR_SYMBOL] === true;
32
+ }
33
+ toJSON() {
34
+ return {
35
+ message: this.message,
36
+ code: this.code,
37
+ statusCode: this.statusCode,
38
+ data: this.data,
39
+ isOperational: this.isOperational
40
+ };
41
+ }
42
+ isOperationalError() {
43
+ return this.isOperational;
44
+ }
45
+ /**
46
+ * Sanitizes data for JSON serialization by handling circular references,
47
+ * functions, symbols, and other non-serializable values
48
+ */
49
+ sanitizeDataForJSON(data) {
50
+ try {
51
+ JSON.stringify(data);
52
+ return data;
53
+ } catch {
54
+ const seen = /* @__PURE__ */ new WeakSet();
55
+ const sanitize = (value) => {
56
+ if (value === null || typeof value !== "object") {
57
+ if (typeof value === "function" || typeof value === "symbol" || value === void 0) {
58
+ return null;
59
+ }
60
+ return value;
61
+ }
62
+ if (seen.has(value)) {
63
+ return "[Circular Reference]";
64
+ }
65
+ seen.add(value);
66
+ if (Array.isArray(value)) {
67
+ return value.map(sanitize);
68
+ }
69
+ const sanitized = {};
70
+ for (const [key, val] of Object.entries(value)) {
71
+ if (typeof key === "string") {
72
+ sanitized[key] = sanitize(val);
73
+ }
74
+ }
75
+ return sanitized;
76
+ };
77
+ return sanitize(data);
78
+ }
79
+ }
80
+ };
81
+
82
+ export { CUSTOM_ERROR_SYMBOL, CustomError };
83
+ //# sourceMappingURL=chunk-T5HNSPY3.mjs.map
84
+ //# sourceMappingURL=chunk-T5HNSPY3.mjs.map
@@ -0,0 +1 @@
1
+ {"version":3,"sources":["../src/error.ts"],"names":[],"mappings":"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","file":"chunk-T5HNSPY3.mjs","sourcesContent":["const CUSTOM_ERROR_SYMBOL = Symbol('expresspackCustomError');\n\nexport class CustomError extends Error {\n\n status: number;\n code: string;\n statusCode: number;\n data: any;\n isOperational: boolean;\n\n readonly [CUSTOM_ERROR_SYMBOL] = true;\n \n constructor({\n message = 'An error occurred',\n code = 'INTERNAL_SERVER_ERROR',\n statusCode = 500,\n data = null,\n isOperational = true,\n sanitizeData = true,\n }: {\n message?: string;\n code?: string;\n statusCode?: number;\n data?: unknown;\n isOperational?: boolean;\n sanitizeData?: boolean;\n } = {}) {\n super(message);\n this.name = 'CustomError';\n this.status = statusCode;\n this.code = code;\n this.statusCode = statusCode;\n this.isOperational = isOperational;\n\n this.data = sanitizeData ? this.sanitizeDataForJSON(data) : data;\n\n // Capture stack trace and remove the constructor chain\n if (Error.captureStackTrace) {\n Error.captureStackTrace(this, this.constructor as any);\n }\n\n Object.setPrototypeOf(this, CustomError.prototype);\n }\n\n static isCustomError(error: any): error is CustomError {\n return (\n error !== null &&\n typeof error === 'object' &&\n CUSTOM_ERROR_SYMBOL in error &&\n (error as any)[CUSTOM_ERROR_SYMBOL] === true\n );\n }\n\n public toJSON() {\n return {\n message: this.message,\n code: this.code,\n statusCode: this.statusCode,\n data: this.data,\n isOperational: this.isOperational,\n };\n }\n\n isOperationalError(): boolean {\n return this.isOperational;\n }\n\n /**\n * Sanitizes data for JSON serialization by handling circular references,\n * functions, symbols, and other non-serializable values\n */\n private sanitizeDataForJSON(data: unknown): unknown {\n try {\n // Quick check if data is already JSON-serializable\n JSON.stringify(data);\n return data;\n } catch {\n const seen = new WeakSet();\n\n const sanitize = (value: unknown): unknown => {\n // Handle primitives and null\n if (value === null || typeof value !== 'object') {\n // Remove functions, symbols, and undefined\n if (typeof value === 'function' || typeof value === 'symbol' || value === undefined) {\n return null;\n }\n return value;\n }\n\n // Handle circular references\n if (seen.has(value as object)) {\n return '[Circular Reference]';\n }\n seen.add(value as object);\n\n // Handle arrays\n if (Array.isArray(value)) {\n return value.map(sanitize);\n }\n\n // Handle objects\n const sanitized: Record<string, unknown> = {};\n for (const [key, val] of Object.entries(value)) {\n // Skip symbol keys and non-enumerable properties\n if (typeof key === 'string') {\n sanitized[key] = sanitize(val);\n }\n }\n return sanitized;\n };\n\n return sanitize(data);\n }\n }\n}\n\n// Exported the symbol just in-case it needs to be used elsewhere\nexport {\n CUSTOM_ERROR_SYMBOL\n}"]}
@@ -0,0 +1,5 @@
1
+ declare const config: Record<string, unknown>;
2
+
3
+ declare function getAppConfig<K>(key: string): K;
4
+
5
+ export { config as default, getAppConfig };
@@ -0,0 +1,3 @@
1
+ export { config_default as default, getAppConfig } from './chunk-6PQFCZAJ.mjs';
2
+ //# sourceMappingURL=config.mjs.map
3
+ //# sourceMappingURL=config.mjs.map
@@ -0,0 +1 @@
1
+ {"version":3,"sources":[],"names":[],"mappings":"","file":"config.mjs"}
@@ -0,0 +1,33 @@
1
+ declare const CUSTOM_ERROR_SYMBOL: unique symbol;
2
+ declare class CustomError extends Error {
3
+ status: number;
4
+ code: string;
5
+ statusCode: number;
6
+ data: any;
7
+ isOperational: boolean;
8
+ readonly [CUSTOM_ERROR_SYMBOL] = true;
9
+ constructor({ message, code, statusCode, data, isOperational, sanitizeData, }?: {
10
+ message?: string;
11
+ code?: string;
12
+ statusCode?: number;
13
+ data?: unknown;
14
+ isOperational?: boolean;
15
+ sanitizeData?: boolean;
16
+ });
17
+ static isCustomError(error: any): error is CustomError;
18
+ toJSON(): {
19
+ message: string;
20
+ code: string;
21
+ statusCode: number;
22
+ data: any;
23
+ isOperational: boolean;
24
+ };
25
+ isOperationalError(): boolean;
26
+ /**
27
+ * Sanitizes data for JSON serialization by handling circular references,
28
+ * functions, symbols, and other non-serializable values
29
+ */
30
+ private sanitizeDataForJSON;
31
+ }
32
+
33
+ export { CUSTOM_ERROR_SYMBOL, CustomError };
package/dist/error.mjs ADDED
@@ -0,0 +1,3 @@
1
+ export { CUSTOM_ERROR_SYMBOL, CustomError } from './chunk-T5HNSPY3.mjs';
2
+ //# sourceMappingURL=error.mjs.map
3
+ //# sourceMappingURL=error.mjs.map
@@ -0,0 +1 @@
1
+ {"version":3,"sources":[],"names":[],"mappings":"","file":"error.mjs"}
@@ -0,0 +1,69 @@
1
+ import { Express, Router } from 'express';
2
+ import { Server } from 'node:http';
3
+
4
+ declare function gracefulHTTPStart(app: Express, port: number, onStart?: () => Promise<void>): Server;
5
+
6
+ declare function gracefulShutdown(server: Server, onShutdown: () => Promise<void>): void;
7
+
8
+ type AppContext = {
9
+ app: Express;
10
+ };
11
+ type KernelExports = ((context: AppContext) => void) | Promise<void>;
12
+ /**
13
+ * This is mostly a plain Express middleware definition.
14
+ *
15
+ * We just called it "**kernel**" to avoid mixing routers
16
+ * and main app middlewares.
17
+ */
18
+ declare function defineKernel(def: KernelExports): KernelExports;
19
+
20
+ interface AppBootstrapContext extends Record<string, any> {
21
+ app: Express;
22
+ }
23
+ interface LoadKernelOptions {
24
+ /**
25
+ * Loads the main kernel (Express middlewares) of your application.
26
+ *
27
+ */
28
+ kernel: () => Promise<any>;
29
+ /**
30
+ * Loads the event listeners for the application.
31
+ *
32
+ * @example
33
+ * ```
34
+ * listener: () => import('./app/listeners/index')
35
+ * ```
36
+ */
37
+ listener?: () => Promise<any>;
38
+ /**
39
+ * Optional boot function to run after kernel (middlewares) and listeners are set up (Loaded last).
40
+ * This can be used for any additional initialization logic your application requires.
41
+ * That are not Express middlewares.
42
+ *
43
+ * For example, initializing services, setting up database connections, etc.
44
+ *
45
+ */
46
+ appBootstrap?: (context: AppBootstrapContext) => Promise<void>;
47
+ }
48
+ declare function loadKernel({ app }: {
49
+ app: any;
50
+ }, { kernel, listener, appBootstrap, }: LoadKernelOptions): Promise<void>;
51
+
52
+ declare function createRouter(): Router;
53
+
54
+ /**
55
+ * Utility to define a router middleware using a callback.
56
+ * @param fn Callback to register routes on the router
57
+ * @returns Express Router instance
58
+ */
59
+ declare function defineRouterMiddleware(fn: (router: Router) => void): Router;
60
+
61
+ /**
62
+ * Load all configurations from the config directory
63
+ *
64
+ * We don't pass context here because we are not using it.
65
+ * since this is config loading is done before the app is created.
66
+ */
67
+ declare function configLoader(root: string): Promise<void>;
68
+
69
+ export { configLoader, createRouter, defineKernel, defineRouterMiddleware, gracefulHTTPStart, gracefulShutdown, loadKernel };
package/dist/index.mjs ADDED
@@ -0,0 +1,269 @@
1
+ import { event_default } from './chunk-7UHB7O5G.mjs';
2
+ import { config_default } from './chunk-6PQFCZAJ.mjs';
3
+ import consola2 from 'consola';
4
+ import { Router } from 'express';
5
+ import path, { relative, join } from 'path';
6
+ import { glob } from 'tinyglobby';
7
+ import fs, { existsSync } from 'fs';
8
+ import process2 from 'process';
9
+
10
+ var logLevel = process.env.EXPRESSPACK_LOG_LEVEL;
11
+ var logger = consola2.create({
12
+ level: Number.isNaN(Number(logLevel)) ? 3 : Number(logLevel)
13
+ });
14
+ var logger_default = logger;
15
+
16
+ // src/graceful-start.ts
17
+ function gracefulHTTPStart(app, port, onStart) {
18
+ const server = app.listen(port, async () => {
19
+ if (onStart) {
20
+ logger_default.debug("Executing onStart hook...");
21
+ await onStart().catch((err) => {
22
+ logger_default.error("Error during onStart hook:", err);
23
+ });
24
+ }
25
+ logger_default.box({
26
+ message: `Server is running at http://localhost:${port}`,
27
+ style: { borderColor: "cyan" },
28
+ level: "info"
29
+ });
30
+ event_default.emit("app:mounted");
31
+ });
32
+ return server;
33
+ }
34
+
35
+ // src/graceful-shutdown.ts
36
+ function gracefulShutdown(server, onShutdown) {
37
+ process.on("SIGINT", async () => {
38
+ logger_default.info("Received SIGINT. Shutting down gracefully...");
39
+ await new Promise((resolve) => {
40
+ server.close(async (err) => {
41
+ if (err instanceof Error) {
42
+ logger_default.error("Error shutting down server:", err);
43
+ return resolve();
44
+ }
45
+ if (onShutdown) {
46
+ await onShutdown().catch((err2) => {
47
+ logger_default.error("Error during shutdown hook:", err2);
48
+ });
49
+ }
50
+ logger_default.info("Server has been shut down.");
51
+ return resolve();
52
+ });
53
+ });
54
+ process.exit(0);
55
+ });
56
+ }
57
+
58
+ // src/define-kernel.ts
59
+ function defineKernel(def) {
60
+ return def;
61
+ }
62
+
63
+ // src/load-kernel.ts
64
+ async function loadKernel({ app }, {
65
+ kernel,
66
+ listener,
67
+ appBootstrap
68
+ }) {
69
+ logger_default.debug("Loading kernel...");
70
+ try {
71
+ const fn = await kernel();
72
+ const setup = fn?.default || fn;
73
+ await setup({ app });
74
+ } catch (error) {
75
+ logger_default.error("Error loading kernel:", error);
76
+ throw error;
77
+ }
78
+ if (listener && typeof listener === "function") {
79
+ try {
80
+ const listenerFn = await listener();
81
+ const setupListener = listenerFn?.default || listenerFn;
82
+ if (setupListener === void 0 || typeof setupListener !== "function") {
83
+ logger_default.warn("No listener setup function found");
84
+ } else {
85
+ await setupListener();
86
+ }
87
+ } catch (error) {
88
+ logger_default.error("Error loading listener:", error);
89
+ throw error;
90
+ }
91
+ }
92
+ if (appBootstrap && typeof appBootstrap === "function") {
93
+ try {
94
+ await appBootstrap({ app });
95
+ } catch (error) {
96
+ logger_default.error("Error during boot process:", error);
97
+ throw error;
98
+ }
99
+ }
100
+ logger_default.debug("Kernel loaded.");
101
+ }
102
+ function createRouter() {
103
+ const router = Router();
104
+ return router;
105
+ }
106
+
107
+ // src/define-router-middleware.ts
108
+ function defineRouterMiddleware(fn) {
109
+ const router = createRouter();
110
+ fn(router);
111
+ return router;
112
+ }
113
+ function resolveAppPaths(root) {
114
+ const rc = join(root, "expresspack.config");
115
+ const app = join(root, "app");
116
+ const config = join(root, "config");
117
+ const appConfigFile = join(config, "app");
118
+ const bodyParserConfig = join(config, "body-parser");
119
+ const controllers = join(app, "controllers");
120
+ const services = join(app, "services");
121
+ const errors = join(app, "errors");
122
+ const middlewareFilePath = join(app, "middlewares");
123
+ const routesFilePath = join(app, "routes");
124
+ return {
125
+ rc,
126
+ root,
127
+ app,
128
+ middlewareFilePath,
129
+ routesFilePath,
130
+ config: {
131
+ base: config,
132
+ bodyParserFile: bodyParserConfig,
133
+ appConfigFile
134
+ },
135
+ controllers: {
136
+ base: controllers
137
+ },
138
+ services: {
139
+ base: services
140
+ },
141
+ errors: {
142
+ base: errors
143
+ }
144
+ };
145
+ }
146
+ var getFileCandidate = (filePath) => {
147
+ const extensions = ["ts", "mts", "js", "mjs", "cjs", "cts"];
148
+ for (const ext of extensions) {
149
+ const file = `${filePath}.${ext}`;
150
+ if (existsSync(file)) {
151
+ return file;
152
+ }
153
+ }
154
+ return null;
155
+ };
156
+ var checkDir = (filePath) => {
157
+ if (existsSync(filePath)) {
158
+ return filePath;
159
+ }
160
+ return null;
161
+ };
162
+ function logPath(path2) {
163
+ if (!path2) return "";
164
+ const sep = path.sep;
165
+ if (path2.endsWith(sep)) return path2;
166
+ return path2 + sep;
167
+ }
168
+
169
+ // package.json
170
+ var package_default = {
171
+ name: "kuwan-expresspack-core"};
172
+ function generateConfigTypeDefinitions(root, configFiles) {
173
+ const typeEntries = configFiles.map(
174
+ (c) => `${c.topic}: typeof import('${c.configPath}').default;`
175
+ );
176
+ const typeFile = `
177
+ declare module 'kuwan-expresspack-core/config' {
178
+ const config: AppConfig;
179
+ export default config;
180
+ export function getAppConfig<K extends keyof AppConfig>(key: K): AppConfig[K];
181
+
182
+ export interface AppConfig {
183
+ ${typeEntries.join("\n")}
184
+ }
185
+ }
186
+ `.trim();
187
+ const packageName = package_default.name;
188
+ const cwd = process2.cwd();
189
+ const user_space_node_modules_path = path.resolve(cwd, "node_modules");
190
+ const generatedTypesDir = path.join(user_space_node_modules_path, packageName, ".types");
191
+ consola2.debug({
192
+ cwd,
193
+ user_space_node_modules_path,
194
+ generatedTypesDir
195
+ });
196
+ if (!fs.existsSync(generatedTypesDir)) {
197
+ fs.mkdirSync(generatedTypesDir, { recursive: false });
198
+ consola2.debug("Created directory:", generatedTypesDir);
199
+ }
200
+ fs.writeFileSync(path.join(generatedTypesDir, "config.d.ts"), typeFile);
201
+ consola2.debug("Generated types at:", path.join(generatedTypesDir, "config.d.ts"));
202
+ }
203
+
204
+ // src/config-loader.ts
205
+ var GLOB_PATTERN = "*.{js,ts,mjs,cjs,mts,cts}";
206
+ var IGNORED_PATTERNS = [
207
+ /* Ignore definitions and source-maps */
208
+ "!*.d.{ts,mts,mjs,cts}",
209
+ "!*.map"
210
+ ];
211
+ async function getConfigTopics(configDir) {
212
+ const configFiles = await glob([
213
+ GLOB_PATTERN,
214
+ ...IGNORED_PATTERNS
215
+ ], {
216
+ cwd: configDir
217
+ });
218
+ const topics = /* @__PURE__ */ new Set();
219
+ configFiles.forEach((file) => {
220
+ const topic = file.replace(/\.(js|ts|mjs|cjs|mts|cts)$/, "");
221
+ topics.add(topic);
222
+ });
223
+ return Array.from(topics);
224
+ }
225
+ async function configLoader(root) {
226
+ const { config: configPath } = resolveAppPaths(root);
227
+ const configDir = configPath.base;
228
+ logger_default.debug("Loading all configurations from: " + logPath(relative(root, configPath.base)));
229
+ const dir = checkDir(configDir);
230
+ if (!dir) {
231
+ logger_default.debug("No config directory found. Looked for:", configDir);
232
+ return;
233
+ }
234
+ const topics = await getConfigTopics(configDir);
235
+ logger_default.debug(`Found ${topics.length} config files: %s`, `
236
+ ${topics.join("\n ")}`);
237
+ const configFiles = /* @__PURE__ */ new Set();
238
+ for (const topic of topics) {
239
+ const configPath2 = getFileCandidate(join(configDir, topic));
240
+ if (!configPath2) {
241
+ logger_default.warn(`No config file found for topic: ${topic}`);
242
+ continue;
243
+ }
244
+ try {
245
+ const configModule = await import(configPath2);
246
+ let configValue = configModule.default || configModule;
247
+ if (typeof configValue === "function") {
248
+ configValue = await configValue();
249
+ }
250
+ const topicCamelCase = topic.replace(/[-_](\w)/g, (_, c) => c ? c.toUpperCase() : "");
251
+ config_default[topicCamelCase] = configValue;
252
+ const fileName = configPath2.split("/").pop();
253
+ logger_default.debug(`Loaded config: ${topicCamelCase} from ${fileName}`);
254
+ if (process.env.NODE_ENV !== "production") {
255
+ configFiles.add({ topic: topicCamelCase, configPath: configPath2 });
256
+ }
257
+ } catch (error) {
258
+ logger_default.error(`Failed to load config ${topic}:`, error);
259
+ }
260
+ }
261
+ if (process.env.NODE_ENV !== "production") {
262
+ logger_default.debug("Generating type definitions for config files...");
263
+ generateConfigTypeDefinitions(root, Array.from(configFiles));
264
+ }
265
+ }
266
+
267
+ export { configLoader, createRouter, defineKernel, defineRouterMiddleware, gracefulHTTPStart, gracefulShutdown, loadKernel };
268
+ //# sourceMappingURL=index.mjs.map
269
+ //# sourceMappingURL=index.mjs.map
@@ -0,0 +1 @@
1
+ {"version":3,"sources":["../src/logger.ts","../src/graceful-start.ts","../src/graceful-shutdown.ts","../src/define-kernel.ts","../src/load-kernel.ts","../src/router-factory.ts","../src/define-router-middleware.ts","../src/lib/resolve-path.ts","../src/lib/utils.ts","../package.json","../src/lib/config-typegen.ts","../src/config-loader.ts"],"names":["consola","err","path","node_path","process","relative","configPath","join"],"mappings":"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","file":"index.mjs","sourcesContent":["import consola from 'consola';\nconst logLevel = process.env.EXPRESSPACK_LOG_LEVEL;\n/**\n * This is the internal logger\n */\nconst logger = consola.create({\n level: Number.isNaN(Number(logLevel)) ? 3 : Number(logLevel),\n})\n\nexport default logger;","import type { Express } from 'express';\nimport logger from './logger'\nimport type { Server } from 'node:http'; \nimport emitter from './services/event';\n\nexport function gracefulHTTPStart(app: Express, port: number, onStart?: () => Promise<void>): Server {\n const server = app.listen(port, async () => {\n\n if (onStart) {\n logger.debug('Executing onStart hook...');\n await onStart().catch(err => {\n logger.error('Error during onStart hook:', err);\n }); \n } \n logger.box({\n message: `Server is running at http://localhost:${port}`,\n style: { borderColor: 'cyan' },\n level: 'info'\n }) \n\n emitter.emit('app:mounted');\n\n });\n\n return server;\n}","import type { Server } from 'node:http';\nimport logger from './logger';\n\nexport function gracefulShutdown(server: Server, onShutdown: () => Promise<void>): void {\n process.on('SIGINT', async () => {\n logger.info('Received SIGINT. Shutting down gracefully...');\n await new Promise<void>((resolve) => {\n server.close(async (err?: Error) => {\n if (err instanceof Error) {\n logger.error('Error shutting down server:', err);\n return resolve();\n }\n if (onShutdown) {\n await onShutdown().catch(err => {\n logger.error('Error during shutdown hook:', err);\n });\n }\n logger.info('Server has been shut down.');\n return resolve();\n });\n });\n process.exit(0);\n });\n // (app as any).down = () => {\n // return new Promise<void>((resolve) => {\n // server.close((err?: Error) => {\n // if (err instanceof Error) {\n // console.error('Error shutting down server:', err);\n // return resolve();\n // }\n // console.info('Server has been shut down.');\n // if (hooks.onShutdown) {\n // hooks.onShutdown().catch(err => {\n // console.error('Error during onShutdown hook:', err);\n // });\n // }\n // return resolve();\n // });\n // });\n // };\n}","import type { Express } from 'express';\n\nexport type AppContext = {\n app: Express\n};\n\nexport type KernelExports = ((context: AppContext) => void) | Promise<void>;\n\n/**\n * This is mostly a plain Express middleware definition.\n * \n * We just called it \"**kernel**\" to avoid mixing routers \n * and main app middlewares.\n */\nexport function defineKernel(def: KernelExports) {\n return def;\n}","import type { Express } from 'express';\nimport logger from \"./logger\";\n\nexport interface AppBootstrapContext extends Record<string, any> {\n app: Express;\n}\n\nexport interface LoadKernelOptions {\n /**\n * Loads the main kernel (Express middlewares) of your application.\n * \n */\n kernel: () => Promise<any>;\n /**\n * Loads the event listeners for the application.\n * \n * @example\n * ```\n * listener: () => import('./app/listeners/index')\n * ```\n */\n listener?: () => Promise<any>;\n /**\n * Optional boot function to run after kernel (middlewares) and listeners are set up (Loaded last).\n * This can be used for any additional initialization logic your application requires.\n * That are not Express middlewares. \n * \n * For example, initializing services, setting up database connections, etc.\n * \n */\n appBootstrap?: (context: AppBootstrapContext) => Promise<void>;\n}\n\nexport async function loadKernel({ app }, { \n kernel,\n listener,\n appBootstrap,\n }: LoadKernelOptions): Promise<void> {\n logger.debug('Loading kernel...');\n\n // This is mainly the middleware loading\n try {\n const fn = await kernel();\n const setup = fn?.default || fn;\n await setup({ app });\n } catch (error) {\n logger.error('Error loading kernel:', error);\n throw error;\n }\n\n // Load listeners as part of the kernel\n if (listener && typeof listener === 'function') {\n try {\n const listenerFn = await listener();\n const setupListener = listenerFn?.default || listenerFn;\n if (setupListener === undefined || typeof setupListener !== 'function') {\n logger.warn('No listener setup function found');\n }else {\n await setupListener();\n }\n } catch (error) {\n logger.error('Error loading listener:', error);\n throw error;\n }\n }\n\n // Run the boot function if provided\n if (appBootstrap && typeof appBootstrap === 'function') {\n try {\n await appBootstrap({ app });\n } catch (error) {\n logger.error('Error during boot process:', error);\n throw error;\n }\n }\n \n logger.debug('Kernel loaded.');\n}","\nimport { Router } from \"express\";\n\nexport function createRouter(): Router {\n const router: Router = Router();\n\n return router;\n}","import { createRouter } from './router-factory';\nimport type { Router } from 'express';\n\n/**\n * Utility to define a router middleware using a callback.\n * @param fn Callback to register routes on the router\n * @returns Express Router instance\n */\nexport function defineRouterMiddleware(fn: (router: Router) => void): Router {\n const router = createRouter();\n fn(router);\n return router;\n}","import { existsSync } from 'node:fs'\nimport { join, relative } from 'node:path'\n\nexport function resolveAppPaths(root: string) {\n const rc = join(root, 'expresspack.config');\n const app = join(root, 'app')\n\n const config = join(root, 'config') \n const appConfigFile = join(config, 'app');\n const bodyParserConfig = join(config, 'body-parser');\n\n // Subdirectories of `app` directory\n const controllers = join(app, 'controllers')\n const services = join(app, 'services')\n const errors = join(app, 'errors')\n\n // Main application directory \n const middlewareFilePath = join(app, 'middlewares')\n const routesFilePath = join(app, 'routes')\n\n return {\n rc,\n root,\n app,\n middlewareFilePath,\n routesFilePath,\n\n config: {\n base: config,\n bodyParserFile: bodyParserConfig,\n appConfigFile,\n },\n\n controllers: {\n base: controllers,\n },\n \n services: {\n base: services,\n },\n\n errors: {\n base: errors,\n }\n }\n}\n\n/**\n * `await import(file)` cant find the file without extension.\n * Also, when bundled, the file extension will become `.js` or `.mjs` and not `.ts`.\n */\nexport const getFileCandidate = (filePath: string) => {\n // Priority order: .ts -> .mts -> .js -> .mjs -> .cjs -> .cts\n const extensions = ['ts', 'mts', 'js', 'mjs', 'cjs', 'cts']\n \n for (const ext of extensions) {\n const file = `${filePath}.${ext}`;\n if (existsSync(file)) {\n return file\n }\n }\n \n return null\n}\n\nexport const checkDir = (filePath: string) => { \n if (existsSync(filePath)) {\n return filePath\n } \n return null\n}\n\nexport const getRelativeFilePath = (filePath: string, root: string) => {\n if (!filePath.startsWith(root)) {\n throw new Error(`File path ${filePath} does not start with root ${root}`);\n }\n // Do not strip the file extension if its a file.\n \n return relative(root, filePath);\n}","import node_path from 'node:path';\n\nexport function logPath(path: string): string {\n if (!path) return '';\n const sep = node_path.sep;\n if (path.endsWith(sep)) return path;\n return path + sep;\n}\n","{\n \"name\": \"kuwan-expresspack-core\",\n \"version\": \"0.1.0\",\n \"description\": \"\",\n \"type\": \"module\",\n \"main\": \"./dist/index.mjs\",\n \"module\": \"./dist/index.mjs\",\n \"bin\": {\n \"expresspack-api\": \"./dist/bin/expresspack-api.mjs\"\n },\n \"files\": [\n \"bin\",\n \"LICENSE\",\n \"README.md\",\n \"codemods/rules\",\n \"dist\"\n ],\n \"types\": \"./dist/index.d.ts\",\n \"exports\": {\n \".\": {\n \"types\": \"./dist/index.d.ts\",\n \"import\": \"./dist/index.mjs\"\n },\n \"./build-tools\": {\n \"types\": \"./dist/build-tools/index.d.ts\",\n \"import\": \"./dist/build-tools/index.mjs\"\n },\n \"./config\": {\n \"types\": \"./dist/config.d.ts\",\n \"import\": \"./dist/config.mjs\"\n },\n \"./error\": {\n \"types\": \"./dist/error.d.ts\",\n \"import\": \"./dist/error.mjs\"\n },\n \"./middlewares/*\": {\n \"types\": \"./dist/middlewares/*/index.d.ts\",\n \"import\": \"./dist/middlewares/*/index.mjs\"\n },\n \"./middlewares/body-parser\": {\n \"types\": \"./dist/middlewares/body-parser/index.d.ts\",\n \"import\": \"./dist/middlewares/body-parser/index.mjs\"\n },\n \"./middlewares/error-handler\": {\n \"types\": \"./dist/middlewares/error-handler/index.d.ts\",\n \"import\": \"./dist/middlewares/error-handler/index.mjs\"\n },\n \"./services/*\": {\n \"types\": \"./dist/services/*/index.d.ts\",\n \"import\": \"./dist/services/*/index.d.mjs\"\n },\n \"./services/event\": {\n \"types\": \"./dist/services/event/index.d.ts\",\n \"import\": \"./dist/services/event/index.mjs\"\n }\n },\n \"scripts\": {\n \"test\": \"echo \\\"Error: no test specified\\\" && exit 1\",\n \"dev\": \"tsup --watch\",\n \"build\": \"rimraf ./dist -v && tsup-node\",\n \"release\": \"echo \\\"Please read RELEASING.md for instructions.\\\" && exit 1\"\n },\n \"dependencies\": {\n \"citty\": \"^0.1.6\",\n \"consola\": \"^3.4.2\",\n \"dayjs\": \"^1.11.13\",\n \"drizzle-kit\": \"^0.31.4\",\n \"drizzle-orm\": \"^0.44.4\",\n \"emittery\": \"^1.2.0\",\n \"execa\": \"^9.6.0\",\n \"express\": \"^5.1.0\"\n },\n \"keywords\": [],\n \"author\": {\n \"name\": \"Mark Terence Tiglao\",\n \"email\": \"github@markterence.me\"\n },\n \"license\": \"MIT\",\n \"packageManager\": \"pnpm@10.13.1+sha512.37ebf1a5c7a30d5fabe0c5df44ee8da4c965ca0c5af3dbab28c3a1681b70a256218d05c81c9c0dcf767ef6b8551eb5b960042b9ed4300c59242336377e01cfad\",\n \"devDependencies\": {\n \"@types/bun\": \"^1.2.19\",\n \"@types/express\": \"^5.0.3\",\n \"@types/node\": \"^24.0.15\",\n \"rimraf\": \"^6.0.1\",\n \"tsup\": \"^8.5.0\",\n \"tsx\": \"^4.20.3\",\n \"typescript\": \"^5.8.3\",\n \"vitest\": \"^3.2.4\"\n },\n \"peerDependencies\": {\n \"@types/express\": \"^5.0.3\",\n \"express\": \"^5.1.0\",\n \"typescript\": \"^5.8.3\"\n },\n \"sideEffects\": false\n}\n","import path from 'node:path';\nimport process from 'node:process';\nimport fs from 'node:fs';\nimport packageJson from '../../package.json';\nimport consola from 'consola';\n\nexport default function generateConfigTypeDefinitions(root, configFiles: { topic: string, configPath: string }[]) {\n\n const typeEntries = configFiles.map(\n c => `${c.topic}: typeof import('${c.configPath}').default;`\n );\n\n const typeFile = `\ndeclare module 'kuwan-expresspack-core/config' {\n const config: AppConfig;\n export default config;\n export function getAppConfig<K extends keyof AppConfig>(key: K): AppConfig[K];\n\n export interface AppConfig {\n ${typeEntries.join('\\n')}\n }\n}\n`.trim();\n\n const packageName = packageJson.name;\n\n // TODO: This needs fixing and guaranteeing that the path is correct.\n const cwd = process.cwd();\n const user_space_node_modules_path = path.resolve(cwd, 'node_modules');\n const generatedTypesDir = path.join(user_space_node_modules_path, packageName, '.types'); \n\n consola.debug({\n cwd,\n user_space_node_modules_path,\n generatedTypesDir,\n })\n \n if (!fs.existsSync(generatedTypesDir)) {\n fs.mkdirSync(generatedTypesDir, { recursive: false });\n consola.debug('Created directory:', generatedTypesDir);\n }\n\n fs.writeFileSync(path.join(generatedTypesDir, 'config.d.ts'), typeFile);\n consola.debug('Generated types at:', path.join(generatedTypesDir, 'config.d.ts'));\n}","import logger from './logger';\nimport { join, relative } from 'node:path'\nimport { glob } from 'tinyglobby';\nimport { checkDir, getFileCandidate, resolveAppPaths } from './lib/resolve-path';\nimport { logPath } from './lib/utils';\nimport config from './config';\nimport generateConfigTypeDefinitions from './lib/config-typegen';\n \n\nconst GLOB_PATTERN = '*.{js,ts,mjs,cjs,mts,cts}';\nconst IGNORED_PATTERNS = [\n /* Ignore definitions and source-maps */\n '!*.d.{ts,mts,mjs,cts}', '!*.map', \n];\n/**\n * Get all unique config topics from the config directory\n * \n * Example: `config/<topic>.{js,ts,mjs,cjs,mts,cts}`\n */\nasync function getConfigTopics(configDir: string): Promise<string[]> {\n const configFiles = await glob([\n GLOB_PATTERN,\n ...IGNORED_PATTERNS\n ], {\n cwd: configDir,\n })\n\n // Extract unique topics (filenames without extensions)\n const topics = new Set<string>()\n \n configFiles\n .forEach(file => {\n const topic = file.replace(/\\.(js|ts|mjs|cjs|mts|cts)$/, '')\n topics.add(topic)\n })\n \n return Array.from(topics);\n}\n\n/**\n * Load all configurations from the config directory\n * \n * We don't pass context here because we are not using it.\n * since this is config loading is done before the app is created.\n */\nexport async function configLoader(root: string): Promise<void> { \n const { config: configPath } = resolveAppPaths(root);\n const configDir = configPath.base;\n\n logger.debug('Loading all configurations from: '+ logPath(relative(root, configPath.base)));\n\n const dir = checkDir(configDir);\n if (!dir) {\n logger.debug('No config directory found. Looked for:', configDir);\n return;\n }\n\n const topics = await getConfigTopics(configDir);\n logger.debug(`Found ${topics.length} config files: %s`, `\\n ${topics.join('\\n ')}`);\n\n const configFiles = new Set<{ topic: string, configPath: string }>();\n\n for (const topic of topics) {\n const configPath = getFileCandidate(join(configDir, topic));\n \n if (!configPath) {\n logger.warn(`No config file found for topic: ${topic}`);\n continue;\n }\n \n try {\n const configModule = await import(configPath);\n let configValue = configModule.default || configModule\n \n // Handle factory functions\n if (typeof configValue === 'function') {\n configValue = await configValue()\n } \n // globalConfigMap.set(topic, configValue)\n const topicCamelCase = topic.replace(/[-_](\\w)/g, (_, c) => c ? c.toUpperCase() : ''); \n config[topicCamelCase] = configValue\n \n const fileName = configPath.split('/').pop()\n logger.debug(`Loaded config: ${topicCamelCase} from ${fileName}`)\n \n // For type generation, no need to generate types in production\n if (process.env.NODE_ENV !== 'production') {\n configFiles.add({ topic: topicCamelCase, configPath });\n }\n\n // Config signature validator (not implemented for now)\n // verifyConfigSignature(configModule.default || configModule, topicCamelCase, configPath);\n\n } catch (error) {\n logger.error(`Failed to load config ${topic}:`, error)\n }\n\n }\n\n if(process.env.NODE_ENV !== 'production') {\n // Generate type definitions for the config\n logger.debug('Generating type definitions for config files...');\n // logger.info('config: ' + configPath);\n generateConfigTypeDefinitions(root, Array.from(configFiles));\n }\n}\n"]}
@@ -0,0 +1,13 @@
1
+ import express, { Handler } from 'express';
2
+
3
+ type JSONOptions = Parameters<typeof express.json>[0];
4
+ type URLEncodedOptions = Parameters<typeof express.urlencoded>[0];
5
+ type BodyParserConfig = {
6
+ json?: JSONOptions;
7
+ urlencoded?: URLEncodedOptions;
8
+ };
9
+ declare function defineConfig(config: BodyParserConfig): BodyParserConfig;
10
+ declare function jsonBodyParser(options?: JSONOptions): Handler;
11
+ declare function urlencodedBodyParser(options?: URLEncodedOptions): Handler;
12
+
13
+ export { type BodyParserConfig, type JSONOptions, type URLEncodedOptions, defineConfig, jsonBodyParser, urlencodedBodyParser };
@@ -0,0 +1,24 @@
1
+ import { getAppConfig } from '../../chunk-6PQFCZAJ.mjs';
2
+ import express from 'express';
3
+
4
+ function defineConfig(config) {
5
+ return config;
6
+ }
7
+ function jsonBodyParser(options) {
8
+ const config = getAppConfig("bodyParser");
9
+ if (config && config?.json) {
10
+ return express.json(config?.json);
11
+ }
12
+ return express.json(options);
13
+ }
14
+ function urlencodedBodyParser(options) {
15
+ const config = getAppConfig("bodyParser");
16
+ if (config && config?.urlencoded) {
17
+ return express.urlencoded(config?.urlencoded);
18
+ }
19
+ return express.urlencoded(options);
20
+ }
21
+
22
+ export { defineConfig, jsonBodyParser, urlencodedBodyParser };
23
+ //# sourceMappingURL=index.mjs.map
24
+ //# sourceMappingURL=index.mjs.map
@@ -0,0 +1 @@
1
+ {"version":3,"sources":["../../../src/middlewares/body-parser/index.ts"],"names":[],"mappings":";;;AAUO,SAAS,aAAa,MAAA,EAA0B;AACnD,EAAA,OAAO,MAAA;AACX;AAEO,SAAS,eAAe,OAAA,EAAgC;AAC3D,EAAA,MAAM,MAAA,GAAS,aAAa,YAAY,CAAA;AACxC,EAAA,IAAI,MAAA,IAAU,QAAQ,IAAA,EAAM;AACxB,IAAA,OAAO,OAAA,CAAQ,IAAA,CAAK,MAAA,EAAQ,IAAI,CAAA;AAAA,EACpC;AACA,EAAA,OAAO,OAAA,CAAQ,KAAK,OAAO,CAAA;AAC/B;AAEO,SAAS,qBAAqB,OAAA,EAAsC;AACvE,EAAA,MAAM,MAAA,GAAS,aAAa,YAAY,CAAA;AACxC,EAAA,IAAI,MAAA,IAAU,QAAQ,UAAA,EAAY;AAC9B,IAAA,OAAO,OAAA,CAAQ,UAAA,CAAW,MAAA,EAAQ,UAAU,CAAA;AAAA,EAChD;AACA,EAAA,OAAO,OAAA,CAAQ,WAAW,OAAO,CAAA;AACrC","file":"index.mjs","sourcesContent":["import express, { type Handler } from 'express'\nimport { getAppConfig } from '../../config'\n\nexport type JSONOptions = Parameters<typeof express.json>[0]\nexport type URLEncodedOptions = Parameters<typeof express.urlencoded>[0]\nexport type BodyParserConfig = {\n json?: JSONOptions\n urlencoded?: URLEncodedOptions\n}\n\nexport function defineConfig(config: BodyParserConfig) {\n return config\n}\n\nexport function jsonBodyParser(options?: JSONOptions): Handler {\n const config = getAppConfig('bodyParser') as BodyParserConfig\n if (config && config?.json) {\n return express.json(config?.json)\n }\n return express.json(options)\n}\n\nexport function urlencodedBodyParser(options?: URLEncodedOptions): Handler {\n const config = getAppConfig('bodyParser') as BodyParserConfig\n if (config && config?.urlencoded) {\n return express.urlencoded(config?.urlencoded)\n }\n return express.urlencoded(options)\n}\n"]}
@@ -0,0 +1,5 @@
1
+ import { ErrorRequestHandler } from 'express';
2
+
3
+ declare function errorHandler(): ErrorRequestHandler;
4
+
5
+ export { errorHandler };
@@ -0,0 +1,14 @@
1
+ import { CustomError } from '../../chunk-T5HNSPY3.mjs';
2
+
3
+ // src/middlewares/error-handler/index.ts
4
+ function errorHandler() {
5
+ return (err, req, res, next) => {
6
+ if (CustomError.isCustomError(err)) {
7
+ return res.status(err.statusCode).json(err.toJSON());
8
+ }
9
+ };
10
+ }
11
+
12
+ export { errorHandler };
13
+ //# sourceMappingURL=index.mjs.map
14
+ //# sourceMappingURL=index.mjs.map
@@ -0,0 +1 @@
1
+ {"version":3,"sources":["../../../src/middlewares/error-handler/index.ts"],"names":[],"mappings":";;;AAGO,SAAS,YAAA,GAAoC;AAChD,EAAA,OAAO,CAAC,GAAA,EAAK,GAAA,EAAK,GAAA,EAAK,IAAA,KAAS;AAC5B,IAAA,IAAG,WAAA,CAAY,aAAA,CAAc,GAAG,CAAA,EAAG;AAC/B,MAAA,OAAO,GAAA,CACF,OAAO,GAAA,CAAI,UAAU,EACrB,IAAA,CAAK,GAAA,CAAI,QAAQ,CAAA;AAAA,IAC1B;AAAA,EACJ,CAAA;AACJ","file":"index.mjs","sourcesContent":["import { CustomError } from \"../../error\";\nimport type { ErrorRequestHandler } from 'express';\n\nexport function errorHandler(): ErrorRequestHandler {\n return (err, req, res, next) => {\n if(CustomError.isCustomError(err)) {\n return res\n .status(err.statusCode)\n .json(err.toJSON());\n }\n }\n}"]}
@@ -0,0 +1,19 @@
1
+ import * as Emittery from 'emittery';
2
+ import Emittery__default from 'emittery';
3
+
4
+ /**
5
+ * Base event map that users can extend in their applications
6
+ */
7
+ interface EmitterEvents {
8
+ [key: string]: any;
9
+ }
10
+ /**
11
+ * Default emitter instance for convenient access
12
+ */
13
+ declare const emitter: Emittery__default<EmitterEvents, EmitterEvents & Emittery.OmnipresentEventData, string>;
14
+ /**
15
+ * Create a new emitter instance (for testing or isolated use)
16
+ */
17
+ declare function createEmitter<T extends EmitterEvents = EmitterEvents>(): Emittery__default<T>;
18
+
19
+ export { type EmitterEvents, createEmitter, emitter as default, emitter };
@@ -0,0 +1,3 @@
1
+ export { createEmitter, event_default as default, emitter } from '../../chunk-7UHB7O5G.mjs';
2
+ //# sourceMappingURL=index.mjs.map
3
+ //# sourceMappingURL=index.mjs.map
@@ -0,0 +1 @@
1
+ {"version":3,"sources":[],"names":[],"mappings":"","file":"index.mjs"}
@@ -0,0 +1,6 @@
1
+ import { ConsolaInstance } from 'consola';
2
+
3
+ declare const println: ConsolaInstance;
4
+ declare function useConsoleLogger(name: string): ConsolaInstance;
5
+
6
+ export { println, useConsoleLogger };
@@ -0,0 +1,15 @@
1
+ import consola from 'consola';
2
+ import { env } from 'process';
3
+
4
+ // src/services/logger/index.ts
5
+ var logLevel = env.APP_LOG_LEVEL;
6
+ var println = consola.create({
7
+ level: Number.isNaN(Number(logLevel)) ? 3 : Number(logLevel)
8
+ });
9
+ function useConsoleLogger(name) {
10
+ return println.withTag(name);
11
+ }
12
+
13
+ export { println, useConsoleLogger };
14
+ //# sourceMappingURL=index.mjs.map
15
+ //# sourceMappingURL=index.mjs.map
@@ -0,0 +1 @@
1
+ {"version":3,"sources":["../../../src/services/logger/index.ts"],"names":[],"mappings":";;;;AAEA,IAAM,WAAW,GAAA,CAAI,aAAA;AAEd,IAAM,OAAA,GAAU,QAAQ,MAAA,CAAO;AAAA,EAClC,KAAA,EAAO,OAAO,KAAA,CAAM,MAAA,CAAO,QAAQ,CAAC,CAAA,GAAI,CAAA,GAAI,MAAA,CAAO,QAAQ;AAC/D,CAAC;AAEM,SAAS,iBAAiB,IAAA,EAA+B;AAC5D,EAAA,OAAO,OAAA,CAAQ,QAAQ,IAAI,CAAA;AAC/B","file":"index.mjs","sourcesContent":["import consola, { type ConsolaInstance } from 'consola';\nimport { env } from 'node:process';\nconst logLevel = env.APP_LOG_LEVEL;\n\nexport const println = consola.create({\n level: Number.isNaN(Number(logLevel)) ? 3 : Number(logLevel) \n})\n\nexport function useConsoleLogger(name: string): ConsolaInstance {\n return println.withTag(name);\n}"]}
package/package.json ADDED
@@ -0,0 +1,95 @@
1
+ {
2
+ "name": "kuwan-expresspack-core",
3
+ "version": "0.1.0",
4
+ "description": "",
5
+ "type": "module",
6
+ "main": "./dist/index.mjs",
7
+ "module": "./dist/index.mjs",
8
+ "bin": {
9
+ "expresspack-api": "./dist/bin/expresspack-api.mjs"
10
+ },
11
+ "files": [
12
+ "bin",
13
+ "LICENSE",
14
+ "README.md",
15
+ "codemods/rules",
16
+ "dist"
17
+ ],
18
+ "types": "./dist/index.d.ts",
19
+ "exports": {
20
+ ".": {
21
+ "types": "./dist/index.d.ts",
22
+ "import": "./dist/index.mjs"
23
+ },
24
+ "./build-tools": {
25
+ "types": "./dist/build-tools/index.d.ts",
26
+ "import": "./dist/build-tools/index.mjs"
27
+ },
28
+ "./config": {
29
+ "types": "./dist/config.d.ts",
30
+ "import": "./dist/config.mjs"
31
+ },
32
+ "./error": {
33
+ "types": "./dist/error.d.ts",
34
+ "import": "./dist/error.mjs"
35
+ },
36
+ "./middlewares/*": {
37
+ "types": "./dist/middlewares/*/index.d.ts",
38
+ "import": "./dist/middlewares/*/index.mjs"
39
+ },
40
+ "./middlewares/body-parser": {
41
+ "types": "./dist/middlewares/body-parser/index.d.ts",
42
+ "import": "./dist/middlewares/body-parser/index.mjs"
43
+ },
44
+ "./middlewares/error-handler": {
45
+ "types": "./dist/middlewares/error-handler/index.d.ts",
46
+ "import": "./dist/middlewares/error-handler/index.mjs"
47
+ },
48
+ "./services/*": {
49
+ "types": "./dist/services/*/index.d.ts",
50
+ "import": "./dist/services/*/index.d.mjs"
51
+ },
52
+ "./services/event": {
53
+ "types": "./dist/services/event/index.d.ts",
54
+ "import": "./dist/services/event/index.mjs"
55
+ }
56
+ },
57
+ "dependencies": {
58
+ "citty": "^0.1.6",
59
+ "consola": "^3.4.2",
60
+ "dayjs": "^1.11.13",
61
+ "drizzle-kit": "^0.31.4",
62
+ "drizzle-orm": "^0.44.4",
63
+ "emittery": "^1.2.0",
64
+ "execa": "^9.6.0",
65
+ "express": "^5.1.0"
66
+ },
67
+ "keywords": [],
68
+ "author": {
69
+ "name": "Mark Terence Tiglao",
70
+ "email": "github@markterence.me"
71
+ },
72
+ "license": "MIT",
73
+ "devDependencies": {
74
+ "@types/bun": "^1.2.19",
75
+ "@types/express": "^5.0.3",
76
+ "@types/node": "^24.0.15",
77
+ "rimraf": "^6.0.1",
78
+ "tsup": "^8.5.0",
79
+ "tsx": "^4.20.3",
80
+ "typescript": "^5.8.3",
81
+ "vitest": "^3.2.4"
82
+ },
83
+ "peerDependencies": {
84
+ "@types/express": "^5.0.3",
85
+ "express": "^5.1.0",
86
+ "typescript": "^5.8.3"
87
+ },
88
+ "sideEffects": false,
89
+ "scripts": {
90
+ "test": "echo \"Error: no test specified\" && exit 1",
91
+ "dev": "tsup --watch",
92
+ "build": "rimraf ./dist -v && tsup-node",
93
+ "release": "echo \"Please read RELEASING.md for instructions.\" && exit 1"
94
+ }
95
+ }