@arkstack/common 0.2.4 → 0.3.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.
package/LICENSE ADDED
@@ -0,0 +1,21 @@
1
+ MIT License
2
+
3
+ Copyright (c) 2026 Toneflix Technologies Limited
4
+
5
+ Permission is hereby granted, free of charge, to any person obtaining a copy
6
+ of this software and associated documentation files (the "Software"), to deal
7
+ in the Software without restriction, including without limitation the rights
8
+ to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
9
+ copies of the Software, and to permit persons to whom the Software is
10
+ furnished to do so, subject to the following conditions:
11
+
12
+ The above copyright notice and this permission notice shall be included in all
13
+ copies or substantial portions of the Software.
14
+
15
+ THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
16
+ IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
17
+ FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
18
+ AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
19
+ LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
20
+ OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
21
+ SOFTWARE.
package/dist/app.d.ts CHANGED
@@ -1,4 +1,4 @@
1
- import { GlobalConfig, GlobalEnv } from './system'
1
+ import { GlobalConfig, GlobalEnv } from './'
2
2
 
3
3
  declare global {
4
4
  var env: GlobalEnv
package/dist/index.d.ts CHANGED
@@ -1,5 +1,6 @@
1
1
  /// <reference path="./app.d.ts" />
2
2
  import { DotPath } from "@h3ravel/support";
3
+ import { ChalkInstance } from "chalk";
3
4
 
4
5
  //#region src/lifecycle.d.ts
5
6
  declare const bindGracefulShutdown: (shutdown: () => Promise<void> | void) => void;
@@ -21,16 +22,68 @@ declare const buildHtmlErrorResponse: ({
21
22
  //#region src/prototypes.d.ts
22
23
  declare const loadPrototypes: () => void;
23
24
  //#endregion
24
- //#region src/system.d.ts
25
+ //#region src/Logger.d.ts
26
+ declare class Console {
27
+ static log: (...args: any[]) => string | void;
28
+ static debug: (...args: any[]) => void;
29
+ static warn: (...args: any[]) => void[];
30
+ static info: (...args: any[]) => void[];
31
+ static error: (...args: any[]) => void[];
32
+ }
33
+ declare class Logger {
34
+ private static verbosity;
35
+ private static isQuiet;
36
+ private static isSilent;
37
+ static configure(options?: {
38
+ verbosity?: number;
39
+ quiet?: boolean;
40
+ silent?: boolean;
41
+ }): void;
42
+ private static shouldSuppressOutput;
43
+ static twoColumnDetail(name: string, value: string, log?: true, spacer?: string): void;
44
+ static twoColumnDetail(name: string, value: string, log?: false, spacer?: string): [string, string, string];
45
+ static describe(name: string, desc: string, width?: number, log?: true): void;
46
+ static describe(name: string, desc: string, width?: number, log?: false): [string, string, string];
47
+ static split(name: string, value: string, status?: 'success' | 'info' | 'error', exit?: boolean, preserveCol?: boolean, spacer?: string): void;
48
+ static textFormat(txt: unknown | unknown[], color: (...text: unknown[]) => string, preserveCol?: boolean): string;
49
+ static success(msg: any, exit?: boolean, preserveCol?: boolean): void;
50
+ static info(msg: any, exit?: boolean, preserveCol?: boolean): void;
51
+ static error(msg: any, exit?: boolean, preserveCol?: boolean): void;
52
+ static warn(msg: any, exit?: boolean, preserveCol?: boolean): void;
53
+ static debug<M = any>(msg: M | M[], exit?: boolean, preserveCol?: boolean): void;
54
+ static quiet(): void;
55
+ static chalker(styles: LoggerChalk[]): (input: any) => string;
56
+ static parse(config: LoggerParseSignature, joiner?: string, log?: true, sc?: LoggerChalk): void;
57
+ static parse(config: LoggerParseSignature, joiner?: string, log?: false, sc?: LoggerChalk): string;
58
+ static log: LoggerLog;
59
+ static console(): typeof Console;
60
+ }
61
+ //#endregion
62
+ //#region src/types.d.ts
63
+ type LoggerChalk = keyof ChalkInstance | ChalkInstance | (keyof ChalkInstance)[];
64
+ type LoggerParseSignature = [string, LoggerChalk][];
65
+ type DotPathValue<T, P extends string> = P extends `${infer Head}.${infer Tail}` ? Head extends keyof T ? DotPathValue<T[Head], Tail> : never : P extends keyof T ? T[P] : never;
66
+ interface LoggerLog {
67
+ (): typeof Logger;
68
+ <L extends boolean>(config: string, joiner: LoggerChalk, log?: L, sc?: LoggerChalk): L extends true ? void : string;
69
+ <L extends boolean>(config: LoggerParseSignature, joiner?: string, log?: L, sc?: LoggerChalk): L extends true ? void : string;
70
+ <L extends boolean>(config?: LoggerParseSignature, joiner?: string, log?: L, sc?: LoggerChalk): L extends true ? void : string | Logger;
71
+ }
25
72
  interface GlobalEnv {
26
- <X = string, Y = undefined>(env: string, defaultValue?: Y): Y extends undefined ? X : Y;
73
+ <X = string, Y = undefined | X>(env: string, defaultValue?: Y): Y extends undefined ? X : Y;
27
74
  }
28
- declare const env: GlobalEnv;
29
- declare const appUrl: (link?: string) => string;
30
75
  interface GlobalConfig {
31
- <X extends Record<string, any>, P extends DotPath<X> | undefined = undefined>(key?: P, defaultValue?: any): P extends string ? any : X;
76
+ <X extends Record<string, any>>(): X;
77
+ <X extends Record<string, any>, P extends DotPath<X>>(key: P): DotPathValue<X, P>;
78
+ <X extends Record<string, any>, P extends DotPath<X>, D>(key: P, defaultValue: D): DotPathValue<X, P> | D;
32
79
  }
80
+ //#endregion
81
+ //#region src/system.d.ts
82
+ declare const env: GlobalEnv;
83
+ declare const appUrl: (link?: string) => string;
33
84
  declare const config: GlobalConfig;
85
+ declare const nodeEnv: () => "prod" | "dev";
86
+ declare const outputDir: (cwd?: string) => string;
34
87
  //#endregion
35
- export { GlobalConfig, GlobalEnv, appUrl, bindGracefulShutdown, bootWithDetectedPort, buildHtmlErrorResponse, config, env, loadPrototypes };
88
+ export { DotPathValue, GlobalConfig, GlobalEnv, Logger, LoggerChalk, LoggerLog, LoggerParseSignature, appUrl, bindGracefulShutdown, bootWithDetectedPort, buildHtmlErrorResponse, config, env, loadPrototypes, nodeEnv, outputDir };
36
89
  //# sourceMappingURL=index.d.ts.map
package/dist/index.js CHANGED
@@ -3,6 +3,7 @@ import { createRequire } from "module";
3
3
  import path from "node:path";
4
4
  import { readdirSync } from "fs";
5
5
  import { detect } from "detect-port";
6
+ import chalk from "chalk";
6
7
 
7
8
  //#region src/lifecycle.ts
8
9
  const bindGracefulShutdown = (shutdown) => {
@@ -86,6 +87,30 @@ const config = (key, defaultValue) => {
86
87
  if (key) return Obj.get(config, key, defaultValue);
87
88
  return config;
88
89
  };
90
+ /**
91
+ * Gets the current Node environment (development or production).
92
+ *
93
+ * @returns
94
+ */
95
+ const nodeEnv = () => {
96
+ let envValue = env("NODE_ENV", "development");
97
+ if (envValue !== "development" && envValue !== "production") envValue = "development";
98
+ return envValue === "production" ? "prod" : "dev";
99
+ };
100
+ /**
101
+ * Gets the output directory for the application based on the current environment.
102
+ *
103
+ * @param cwd The current working directory (optional, defaults to process.cwd()).
104
+ * @returns
105
+ */
106
+ const outputDir = (cwd = process.cwd()) => {
107
+ const NODE_ENV = nodeEnv();
108
+ const output = {
109
+ dev: env("OUTPUT_DIR_DEV", ".arkstack/build"),
110
+ prod: env("OUTPUT_DIR", "dist")
111
+ };
112
+ return path.isAbsolute(output[NODE_ENV] ?? output.dev) ? output[NODE_ENV] ?? output.dev : path.join(cwd, output[NODE_ENV] ?? output.dev);
113
+ };
89
114
 
90
115
  //#endregion
91
116
  //#region src/network.ts
@@ -174,5 +199,209 @@ const loadPrototypes = () => {
174
199
  };
175
200
 
176
201
  //#endregion
177
- export { appUrl, bindGracefulShutdown, bootWithDetectedPort, buildHtmlErrorResponse, config, env, loadPrototypes };
202
+ //#region src/Logger.ts
203
+ var Console = class {
204
+ static log = (...args) => Logger.log(args.map((e) => [e, "white"]));
205
+ static debug = (...args) => Logger.debug(args, false, true);
206
+ static warn = (...args) => args.map((e) => Logger.warn(e, false, true));
207
+ static info = (...args) => args.map((e) => Logger.info(e, false, true));
208
+ static error = (...args) => args.map((e) => Logger.error(e, false), true);
209
+ };
210
+ var Logger = class Logger {
211
+ /**
212
+ * Global verbosity configuration
213
+ */
214
+ static verbosity = 0;
215
+ static isQuiet = false;
216
+ static isSilent = false;
217
+ /**
218
+ * Configure global verbosity levels
219
+ */
220
+ static configure(options = {}) {
221
+ this.verbosity = options.verbosity ?? 0;
222
+ this.isQuiet = options.quiet ?? false;
223
+ this.isSilent = options.silent ?? false;
224
+ }
225
+ /**
226
+ * Check if output should be suppressed
227
+ */
228
+ static shouldSuppressOutput(level) {
229
+ if (this.isSilent) return true;
230
+ if (this.isQuiet && (level === "info" || level === "success")) return true;
231
+ if (level === "debug" && this.verbosity < 3) return true;
232
+ return false;
233
+ }
234
+ static twoColumnDetail(name, value, log = true, spacer = ".") {
235
+ const regex = /\x1b\[\d+m/g;
236
+ const width = Math.max(process.stdout.columns, 100);
237
+ const dots = Math.max(width - name.replace(regex, "").length - value.replace(regex, "").length - 10, 0);
238
+ if (log) return console.log(name, chalk.gray(spacer.repeat(dots)), value);
239
+ else return [
240
+ name,
241
+ chalk.gray(spacer.repeat(dots)),
242
+ value
243
+ ];
244
+ }
245
+ static describe(name, desc, width = 50, log = true) {
246
+ width = Math.max(width, 30);
247
+ const dots = Math.max(width - name.replace(/\x1b\[\d+m/g, "").length, 0);
248
+ if (log) return console.log(name, " ".repeat(dots), desc);
249
+ else return [
250
+ name,
251
+ " ".repeat(dots),
252
+ desc
253
+ ];
254
+ }
255
+ /**
256
+ * Logs the message in two columns but allways passing status
257
+ *
258
+ * @param name
259
+ * @param value
260
+ * @param status
261
+ * @param exit
262
+ * @param preserveCol
263
+ */
264
+ static split(name, value, status, exit = false, preserveCol = false, spacer = ".") {
265
+ status ??= "info";
266
+ const color = {
267
+ success: chalk.bgGreen,
268
+ info: chalk.bgBlue,
269
+ error: chalk.bgRed
270
+ };
271
+ const [_name, dots, val] = this.twoColumnDetail(name, value, false, spacer);
272
+ console.log(this.textFormat(_name, color[status], preserveCol), dots, val);
273
+ if (exit) process.exit(0);
274
+ }
275
+ /**
276
+ * Wraps text with chalk
277
+ *
278
+ * @param txt
279
+ * @param color
280
+ * @param preserveCol
281
+ * @returns
282
+ */
283
+ static textFormat(txt, color, preserveCol = false) {
284
+ if (txt instanceof Error) {
285
+ const err = txt;
286
+ const code = err.code ?? err.statusCode ? ` (${err.code ?? err.statusCode})` : "";
287
+ const output = [];
288
+ if (err.message) output.push(this.textFormat(`${err.constructor.name}${code}: ${err.message}`, chalk.bgRed, preserveCol));
289
+ if (err.stack) output.push(" " + chalk.white(err.stack.replace(`${err.name}: ${err.message}`, "").trim()));
290
+ return output.join("\n");
291
+ }
292
+ if (Array.isArray(txt)) return txt.map((e) => this.textFormat(e, color, preserveCol)).join("\n");
293
+ if (typeof txt === "object") return this.textFormat(Object.values(txt), color, preserveCol);
294
+ if (typeof txt !== "string") return color(txt);
295
+ const str = String(txt);
296
+ if (preserveCol) return str;
297
+ const [first, ...rest] = str.split(":");
298
+ if (rest.length === 0) return str;
299
+ return color(` ${first} `) + rest.join(":");
300
+ }
301
+ /**
302
+ * Logs a success message
303
+ *
304
+ * @param msg
305
+ * @param exit
306
+ * @param preserveCol
307
+ */
308
+ static success(msg, exit = false, preserveCol = false) {
309
+ if (!this.shouldSuppressOutput("success")) console.log(chalk.green("✓"), this.textFormat(msg, chalk.bgGreen, preserveCol));
310
+ if (exit) process.exit(0);
311
+ }
312
+ /**
313
+ * Logs an informational message
314
+ *
315
+ * @param msg
316
+ * @param exit
317
+ * @param preserveCol
318
+ */
319
+ static info(msg, exit = false, preserveCol = false) {
320
+ if (!this.shouldSuppressOutput("info")) console.log(chalk.blue("ℹ"), this.textFormat(msg, chalk.bgBlue, preserveCol));
321
+ if (exit) process.exit(0);
322
+ }
323
+ /**
324
+ * Logs an error message
325
+ *
326
+ * @param msg
327
+ * @param exit
328
+ * @param preserveCol
329
+ */
330
+ static error(msg, exit = true, preserveCol = false) {
331
+ if (!this.shouldSuppressOutput("error")) if (msg instanceof Error) {
332
+ if (msg.message) console.error(chalk.red("✖"), this.textFormat("ERROR:" + msg.message, chalk.bgRed, preserveCol));
333
+ console.error(chalk.red(`${msg.detail ? `${msg.detail}\n` : ""}${msg.stack}`));
334
+ } else console.error(chalk.red("✖"), this.textFormat(msg, chalk.bgRed, preserveCol));
335
+ if (exit) process.exit(1);
336
+ }
337
+ /**
338
+ * Logs a warning message
339
+ *
340
+ * @param msg
341
+ * @param exit
342
+ * @param preserveCol
343
+ */
344
+ static warn(msg, exit = false, preserveCol = false) {
345
+ if (!this.shouldSuppressOutput("warn")) console.warn(chalk.yellow("⚠"), this.textFormat(msg, chalk.bgYellow, preserveCol));
346
+ if (exit) process.exit(0);
347
+ }
348
+ /**
349
+ * Logs a debug message (only shown with verbosity >= 3)
350
+ *
351
+ * @param msg
352
+ * @param exit
353
+ * @param preserveCol
354
+ */
355
+ static debug(msg, exit = false, preserveCol = false) {
356
+ if (!this.shouldSuppressOutput("debug")) if (Array.isArray(msg)) for (let i = 0; i < msg.length; i++) console.log(chalk.gray("🐛"), chalk.bgGray(i + 1), this.textFormat(msg[i], chalk.bgGray, preserveCol));
357
+ else console.log(chalk.gray("🐛"), this.textFormat(msg, chalk.bgGray, preserveCol));
358
+ if (exit) process.exit(0);
359
+ }
360
+ /**
361
+ * Terminates the process
362
+ */
363
+ static quiet() {
364
+ process.exit(0);
365
+ }
366
+ static chalker(styles) {
367
+ return (input) => styles.reduce((acc, style) => {
368
+ if (style in chalk) return (typeof style === "function" ? style : chalk[style])(acc);
369
+ return acc;
370
+ }, input);
371
+ }
372
+ static parse(config, joiner = " ", log = true, sc) {
373
+ const string = config.map(([str, opt]) => {
374
+ if (Array.isArray(opt)) opt = Logger.chalker(opt);
375
+ const output = typeof opt === "string" && typeof chalk[opt] === "function" ? chalk[opt](str) : typeof opt === "function" ? opt(str) : str;
376
+ if (!sc) return output;
377
+ return this.textFormat(output, Logger.chalker(Array.isArray(sc) ? sc : [sc]));
378
+ }).join(joiner);
379
+ if (log && !this.shouldSuppressOutput("line")) console.log(string);
380
+ else return string;
381
+ }
382
+ /**
383
+ * Ouput formater object or format the output
384
+ *
385
+ * @returns
386
+ */
387
+ static log = ((config, joiner, log = true, sc) => {
388
+ if (typeof config === "string") {
389
+ const conf = [[config, joiner]];
390
+ return this.parse(conf, "", log, sc);
391
+ } else if (Array.isArray(config)) return this.parse(config, String(joiner), log, sc);
392
+ else if (log && !this.shouldSuppressOutput("line")) return console.log(this.textFormat(config, Logger.chalker(["blue"])));
393
+ return this;
394
+ });
395
+ /**
396
+ * A simple console like output logger
397
+ *
398
+ * @returns
399
+ */
400
+ static console() {
401
+ return Console;
402
+ }
403
+ };
404
+
405
+ //#endregion
406
+ export { Logger, appUrl, bindGracefulShutdown, bootWithDetectedPort, buildHtmlErrorResponse, config, env, loadPrototypes, nodeEnv, outputDir };
178
407
  //# sourceMappingURL=index.js.map
package/dist/index.js.map CHANGED
@@ -1 +1 @@
1
- {"version":3,"file":"index.js","names":[],"sources":["../src/lifecycle.ts","../src/system.ts","../src/network.ts","../src/prototypes.ts"],"sourcesContent":["export const bindGracefulShutdown = (shutdown: () => Promise<void> | void) => {\n ['SIGINT', 'SIGTERM', 'SIGQUIT'].forEach((signal) => {\n process.on(signal, async () => {\n await shutdown()\n })\n })\n}\n","import { DotPath, Obj } from '@h3ravel/support'\n\nimport { createRequire } from 'module'\nimport path from 'node:path'\nimport { readdirSync } from 'fs'\n\nexport interface GlobalEnv {\n <X = string, Y = undefined> (\n env: string,\n defaultValue?: Y,\n ): Y extends undefined ? X : Y\n}\n\n/**\n * Read the .env file\n *\n * @param env\n * @param def\n * @returns\n */\nexport const env: GlobalEnv = <X = string, Y = undefined> (\n env: string,\n defaultValue?: Y,\n) => {\n let val: string | number | boolean | undefined | null = process.env[env] ?? ''\n\n if ([true, 'true', 'on', false, 'false', 'off'].includes(val)) {\n val = [true, 'true', 'on'].includes(val)\n }\n\n if (!isNaN(Number(val)) && typeof val !== 'boolean' && typeof val !== 'undefined' && val !== '') {\n val = Number(val)\n }\n\n if (val === '') {\n val = undefined\n }\n\n if (val === 'null') {\n val = null\n }\n\n val ??= defaultValue as typeof val\n\n return val as Y extends undefined ? X : Y\n}\n\n/**\n * Build the app url\n *\n * @param link\n * @returns\n */\nexport const appUrl = (link?: string): string => {\n const port = env('PORT') || '3000'\n const defaultUrl = `http://localhost:${port}`\n const appUrl = env('APP_URL') ?? defaultUrl\n\n try {\n const url = new URL(appUrl)\n // Append port only if APP_URL has a port or is localhost\n if (url.port || url.hostname === 'localhost') {\n url.port = port\n }\n // Remove trailing slash from base URL\n const baseUrl = url.toString().replace(/\\/$/, '')\n // Append link with proper path separator\n if (link) {\n // Ensure link starts with '/' and remove duplicate slashes\n const normalizedLink = `/${link.replace(/^\\/+/, '')}`\n\n return `${baseUrl}${normalizedLink}`\n }\n\n return baseUrl\n } catch {\n // Return default URL with link if provided\n return link ? `${defaultUrl}/${link.replace(/^\\/+/, '')}` : defaultUrl\n }\n}\n\nexport interface GlobalConfig {\n <X extends Record<string, any>, P extends DotPath<X> | undefined = undefined> (\n key?: P,\n defaultValue?: any\n ): P extends string ? any : X\n}\n\n/**\n * Gets the application configuration.\n * \n * @param key The configuration key to retrieve.\n * @param defaultValue The default value to return if the key is not found.\n * @returns The configuration value.\n */\nexport const config: GlobalConfig = <X extends Record<string, any>, P extends DotPath<X> | undefined = undefined> (\n key?: P,\n defaultValue?: any\n) => {\n const require = createRequire(import.meta.url)\n\n const files = readdirSync(path.join(process.cwd(), 'dist/config'), { withFileTypes: true })\n .filter(file => {\n if (file.name.includes('middleware') && globalThis.arkctx.runtime === 'CLI') return false\n\n return file.isFile() && (file.name.endsWith('.js') || file.name.endsWith('.ts'))\n })\n\n const config = files.reduce((configs, file) => {\n const configName = path.basename(file.name, path.extname(file.name))\n\n configs[configName] = require(path.join(file.parentPath, file.name))\n .default((globalThis as any).app())\n\n return configs\n }, {} as Record<string, any>) as X\n\n\n if (key) {\n return Obj.get(config, key, defaultValue)\n }\n\n return config\n}","import { config, env } from './system'\n\nimport { detect } from 'detect-port'\n\nexport const bootWithDetectedPort = async (\n boot: (port: number) => Promise<void>,\n preferredPort: number = 3000,\n app?: any\n) => {\n if (app && !globalThis.app)\n globalThis.app = () => app\n globalThis.env = env\n globalThis.config = config\n globalThis.arkctx = {\n runtime: 'HTTP',\n }\n const port = await detect(preferredPort)\n await boot(port)\n}\n\n\nexport const buildHtmlErrorResponse = ({\n message = 'An unexpected error occurred.',\n stack,\n title,\n code = 500,\n}: {\n message?: string;\n stack?: string;\n code?: number;\n title?: string;\n}) => {\n const titleMap: Record<number, string> = {\n 400: 'Bad Request',\n 401: 'Unauthorized',\n 403: 'Forbidden',\n 404: 'Not Found',\n 500: 'Internal Server Error',\n 502: 'Bad Gateway',\n 503: 'Service Unavailable',\n 504: 'Gateway Timeout',\n }\n\n title = titleMap[code] || title || 'Error'\n\n return `\n <html>\n <head>\n <title>${code} | ${title}</title>\n <style>\n body {\n font-family: Arial, sans-serif;\n background-color: #f8f8f8;\n color: #333;\n padding: 20px;\n }\n h1 {\n color: #e74c3c;\n }\n h3 {\n color: #3498db;\n }\n p {\n color: #555;\n }\n pre {\n background-color: #eee;\n padding: 10px;\n border-radius: 5px;\n overflow-x: auto;\n }\n </style>\n </head>\n <body>\n <h1>${code}</h1>\n <h3>${title}</h3>\n <p>${message}</p>\n ${stack ? `<h2>Stack Trace:</h2><pre>${stack}</pre>` : ''}\n </body>\n </html>\n `\n}","export const loadPrototypes = () => {\n String.prototype.titleCase = function () {\n return this.toLowerCase()\n .replace(/_/g, ' ')\n .replace(/-/g, ' ')\n .replace(/(?:^|\\s)\\w/g, function (match) {\n return match.toUpperCase()\n })\n }\n\n String.prototype.camelCase = function () {\n return this.replace(/(?:^\\w|[A-Z]|\\b\\w|\\s+)/g, function (match, index) {\n if (+match === 0) return '' // or if (/\\s+/.test(match)) for white spaces\n\n return index === 0 ? match.toLowerCase() : match.toUpperCase()\n })\n }\n\n String.prototype.pascalCase = function () {\n return this.replace(/(?:^\\w|[A-Z]|\\b\\w|\\s+)/g, function (match) {\n return match.toUpperCase()\n })\n }\n\n String.prototype.truncate = function (len: number = 20, suffix: string = '...') {\n if (this.length <= len) {\n return this.toString()\n }\n\n const truncated = this.substring(0, len)\n const lastSpaceIndex = truncated.lastIndexOf(' ')\n if (lastSpaceIndex > 0) {\n return truncated.substring(0, lastSpaceIndex) + suffix\n }\n\n return truncated + suffix\n }\n} \n"],"mappings":"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"}
1
+ {"version":3,"file":"index.js","names":[],"sources":["../src/lifecycle.ts","../src/system.ts","../src/network.ts","../src/prototypes.ts","../src/Logger.ts"],"sourcesContent":["export const bindGracefulShutdown = (shutdown: () => Promise<void> | void) => {\n ['SIGINT', 'SIGTERM', 'SIGQUIT'].forEach((signal) => {\n process.on(signal, async () => {\n await shutdown()\n })\n })\n}\n","import { DotPath, Obj } from '@h3ravel/support'\nimport { GlobalConfig, GlobalEnv } from './types'\n\nimport { createRequire } from 'module'\nimport path from 'node:path'\nimport { readdirSync } from 'fs'\n\n/**\n * Read the .env file\n *\n * @param env\n * @param def\n * @returns\n */\nexport const env: GlobalEnv = <X = string, Y = undefined | X> (\n env: string,\n defaultValue?: Y,\n) => {\n let val: string | number | boolean | undefined | null = process.env[env] ?? ''\n\n if ([true, 'true', 'on', false, 'false', 'off'].includes(val)) {\n val = [true, 'true', 'on'].includes(val)\n }\n\n if (!isNaN(Number(val)) && typeof val !== 'boolean' && typeof val !== 'undefined' && val !== '') {\n val = Number(val)\n }\n\n if (val === '') {\n val = undefined\n }\n\n if (val === 'null') {\n val = null\n }\n\n val ??= defaultValue as typeof val\n\n return val as Y extends undefined ? X : Y\n}\n\n/**\n * Build the app url\n *\n * @param link\n * @returns\n */\nexport const appUrl = (link?: string): string => {\n const port = env('PORT') || '3000'\n const defaultUrl = `http://localhost:${port}`\n const appUrl = env('APP_URL') ?? defaultUrl\n\n try {\n const url = new URL(appUrl)\n // Append port only if APP_URL has a port or is localhost\n if (url.port || url.hostname === 'localhost') {\n url.port = port\n }\n // Remove trailing slash from base URL\n const baseUrl = url.toString().replace(/\\/$/, '')\n // Append link with proper path separator\n if (link) {\n // Ensure link starts with '/' and remove duplicate slashes\n const normalizedLink = `/${link.replace(/^\\/+/, '')}`\n\n return `${baseUrl}${normalizedLink}`\n }\n\n return baseUrl\n } catch {\n // Return default URL with link if provided\n return link ? `${defaultUrl}/${link.replace(/^\\/+/, '')}` : defaultUrl\n }\n}\n\n/**\n * Gets the application configuration.\n * \n * @param key The configuration key to retrieve.\n * @param defaultValue The default value to return if the key is not found.\n * @returns The configuration value.\n */\nexport const config: GlobalConfig = <X extends Record<string, any>, P extends DotPath<X> | undefined = undefined> (\n key?: P,\n defaultValue?: any\n) => {\n const require = createRequire(import.meta.url)\n\n const files = readdirSync(path.join(process.cwd(), 'dist/config'), { withFileTypes: true })\n .filter(file => {\n if (file.name.includes('middleware') && globalThis.arkctx.runtime === 'CLI') return false\n\n return file.isFile() && (file.name.endsWith('.js') || file.name.endsWith('.ts'))\n })\n\n const config = files.reduce((configs, file) => {\n const configName = path.basename(file.name, path.extname(file.name))\n\n configs[configName] = require(path.join(file.parentPath, file.name))\n .default((globalThis as any).app())\n\n return configs\n }, {} as Record<string, any>) as X\n\n\n if (key) {\n return Obj.get(config, key, defaultValue)\n }\n\n return config\n}\n\n/**\n * Gets the current Node environment (development or production).\n * \n * @returns \n */\nexport const nodeEnv = () => {\n let envValue = env<'development' | 'production'>('NODE_ENV', 'development')\n\n if (envValue !== 'development' && envValue !== 'production') {\n envValue = 'development'\n }\n\n return envValue === 'production' ? 'prod' : 'dev'\n}\n\n/**\n * Gets the output directory for the application based on the current environment.\n * \n * @param cwd The current working directory (optional, defaults to process.cwd()).\n * @returns \n */\nexport const outputDir = (cwd = process.cwd()) => {\n const NODE_ENV = nodeEnv()\n\n const output = {\n dev: env('OUTPUT_DIR_DEV', '.arkstack/build'),\n prod: env('OUTPUT_DIR', 'dist'),\n }\n\n return path.isAbsolute(output[NODE_ENV] ?? output.dev)\n ? (output[NODE_ENV] ?? output.dev)\n : path.join(cwd, output[NODE_ENV] ?? output.dev)\n}","import { config, env } from './system'\n\nimport { detect } from 'detect-port'\n\nexport const bootWithDetectedPort = async (\n boot: (port: number) => Promise<void>,\n preferredPort: number = 3000,\n app?: any\n) => {\n if (app && !globalThis.app)\n globalThis.app = () => app\n globalThis.env = env\n globalThis.config = config\n globalThis.arkctx = {\n runtime: 'HTTP',\n }\n const port = await detect(preferredPort)\n await boot(port)\n}\n\n\nexport const buildHtmlErrorResponse = ({\n message = 'An unexpected error occurred.',\n stack,\n title,\n code = 500,\n}: {\n message?: string;\n stack?: string;\n code?: number;\n title?: string;\n}) => {\n const titleMap: Record<number, string> = {\n 400: 'Bad Request',\n 401: 'Unauthorized',\n 403: 'Forbidden',\n 404: 'Not Found',\n 500: 'Internal Server Error',\n 502: 'Bad Gateway',\n 503: 'Service Unavailable',\n 504: 'Gateway Timeout',\n }\n\n title = titleMap[code] || title || 'Error'\n\n return `\n <html>\n <head>\n <title>${code} | ${title}</title>\n <style>\n body {\n font-family: Arial, sans-serif;\n background-color: #f8f8f8;\n color: #333;\n padding: 20px;\n }\n h1 {\n color: #e74c3c;\n }\n h3 {\n color: #3498db;\n }\n p {\n color: #555;\n }\n pre {\n background-color: #eee;\n padding: 10px;\n border-radius: 5px;\n overflow-x: auto;\n }\n </style>\n </head>\n <body>\n <h1>${code}</h1>\n <h3>${title}</h3>\n <p>${message}</p>\n ${stack ? `<h2>Stack Trace:</h2><pre>${stack}</pre>` : ''}\n </body>\n </html>\n `\n}","export const loadPrototypes = () => {\n String.prototype.titleCase = function () {\n return this.toLowerCase()\n .replace(/_/g, ' ')\n .replace(/-/g, ' ')\n .replace(/(?:^|\\s)\\w/g, function (match) {\n return match.toUpperCase()\n })\n }\n\n String.prototype.camelCase = function () {\n return this.replace(/(?:^\\w|[A-Z]|\\b\\w|\\s+)/g, function (match, index) {\n if (+match === 0) return '' // or if (/\\s+/.test(match)) for white spaces\n\n return index === 0 ? match.toLowerCase() : match.toUpperCase()\n })\n }\n\n String.prototype.pascalCase = function () {\n return this.replace(/(?:^\\w|[A-Z]|\\b\\w|\\s+)/g, function (match) {\n return match.toUpperCase()\n })\n }\n\n String.prototype.truncate = function (len: number = 20, suffix: string = '...') {\n if (this.length <= len) {\n return this.toString()\n }\n\n const truncated = this.substring(0, len)\n const lastSpaceIndex = truncated.lastIndexOf(' ')\n if (lastSpaceIndex > 0) {\n return truncated.substring(0, lastSpaceIndex) + suffix\n }\n\n return truncated + suffix\n }\n} \n","import chalk, { type ChalkInstance } from 'chalk'\nimport { LoggerChalk, LoggerLog, LoggerParseSignature } from './types'\n\nclass Console {\n static log = (...args: any[]) => Logger.log(args.map(e => [e, 'white']))\n static debug = (...args: any[]) => Logger.debug(args, false, true)\n static warn = (...args: any[]) => args.map(e => Logger.warn(e, false, true))\n static info = (...args: any[]) => args.map(e => Logger.info(e, false, true))\n static error = (...args: any[]) => args.map(e => Logger.error(e, false), true)\n}\n\nexport class Logger {\n /**\n * Global verbosity configuration\n */\n private static verbosity: number = 0\n private static isQuiet: boolean = false\n private static isSilent: boolean = false\n\n /**\n * Configure global verbosity levels\n */\n static configure (options: { verbosity?: number, quiet?: boolean, silent?: boolean } = {}) {\n this.verbosity = options.verbosity ?? 0\n this.isQuiet = options.quiet ?? false\n this.isSilent = options.silent ?? false\n }\n\n /**\n * Check if output should be suppressed\n */\n private static shouldSuppressOutput (level: 'line' | 'debug' | 'info' | 'warn' | 'error' | 'success'): boolean {\n if (this.isSilent) return true\n if (this.isQuiet && (level === 'info' || level === 'success')) return true\n if (level === 'debug' && this.verbosity < 3) return true\n\n return false\n }\n /**\n * Logs the message in two columns\n * \n * @param name \n * @param value \n * @param log If set to false, array of [name, dots, value] output will be returned and not logged \n * @returns \n */\n static twoColumnDetail (name: string, value: string, log?: true, spacer?: string): void\n static twoColumnDetail (name: string, value: string, log?: false, spacer?: string): [string, string, string]\n static twoColumnDetail (name: string, value: string, log = true, spacer = '.'): [string, string, string] | void {\n // eslint-disable-next-line no-control-regex\n const regex = /\\x1b\\[\\d+m/g\n const width = Math.max(process.stdout.columns, 100)\n const dots = Math.max(width - name.replace(regex, '').length - value.replace(regex, '').length - 10, 0)\n\n if (log) return console.log(name, chalk.gray(spacer.repeat(dots)), value)\n else return [name, chalk.gray(spacer.repeat(dots)), value]\n }\n\n /**\n * Logs the message in two columns\n * \n * @param name \n * @param desc \n * @param width \n * @param log If set to false, array of [name, dots, value] output will be returned and not logged \n * @returns \n */\n static describe (name: string, desc: string, width?: number, log?: true): void\n static describe (name: string, desc: string, width?: number, log?: false): [string, string, string]\n static describe (name: string, desc: string, width = 50, log = true): [string, string, string] | void {\n width = Math.max(width, 30)\n // eslint-disable-next-line no-control-regex\n const regex = /\\x1b\\[\\d+m/g\n const dots = Math.max(width - name.replace(regex, '').length, 0)\n\n if (log) return console.log(name, ' '.repeat(dots), desc)\n else return [name, ' '.repeat(dots), desc]\n }\n\n /**\n * Logs the message in two columns but allways passing status\n * \n * @param name \n * @param value \n * @param status \n * @param exit \n * @param preserveCol \n */\n static split (name: string, value: string, status?: 'success' | 'info' | 'error', exit = false, preserveCol = false, spacer = '.') {\n status ??= 'info'\n const color = { success: chalk.bgGreen, info: chalk.bgBlue, error: chalk.bgRed }\n\n const [_name, dots, val] = this.twoColumnDetail(name, value, false, spacer)\n\n console.log(this.textFormat(_name, color[status], preserveCol), dots, val)\n\n if (exit) process.exit(0)\n }\n\n /**\n * Wraps text with chalk\n * \n * @param txt \n * @param color \n * @param preserveCol \n * @returns \n */\n static textFormat (\n txt: unknown | unknown[],\n color: (...text: unknown[]) => string,\n preserveCol = false\n ): string {\n if (txt instanceof Error) {\n const err: Error & { code?: number, statusCode?: number } = txt\n const code = err.code ?? err.statusCode ? ` (${err.code ?? err.statusCode})` : ''\n const output: string[] = []\n\n if (err.message) {\n output.push(this.textFormat(`${err.constructor.name}${code}: ${err.message}`, chalk.bgRed, preserveCol))\n }\n\n if (err.stack) {\n output.push(' ' + chalk.white(err.stack.replace(`${err.name}: ${err.message}`, '').trim()))\n }\n\n return output.join('\\n')\n }\n\n if (Array.isArray(txt)) {\n return txt.map(e => this.textFormat(e, color, preserveCol)).join('\\n')\n }\n\n if (typeof txt === 'object') {\n return this.textFormat(Object.values(txt!), color, preserveCol)\n }\n\n if (typeof txt !== 'string') {\n return color(txt)\n }\n\n const str = String(txt)\n\n if (preserveCol) return str\n\n const [first, ...rest] = str.split(':')\n if (rest.length === 0) return str\n\n return color(` ${first} `) + rest.join(':')\n }\n\n /**\n * Logs a success message\n * \n * @param msg \n * @param exit \n * @param preserveCol \n */\n static success (msg: any, exit = false, preserveCol = false) {\n if (!this.shouldSuppressOutput('success')) {\n console.log(chalk.green('✓'), this.textFormat(msg, chalk.bgGreen, preserveCol))\n }\n if (exit) process.exit(0)\n }\n\n /**\n * Logs an informational message\n * \n * @param msg \n * @param exit \n * @param preserveCol \n */\n static info (msg: any, exit = false, preserveCol = false) {\n if (!this.shouldSuppressOutput('info')) {\n console.log(chalk.blue('ℹ'), this.textFormat(msg, chalk.bgBlue, preserveCol))\n }\n if (exit) process.exit(0)\n }\n\n /**\n * Logs an error message\n * \n * @param msg \n * @param exit \n * @param preserveCol \n */\n static error (msg: any, exit = true, preserveCol = false) {\n if (!this.shouldSuppressOutput('error')) {\n if (msg instanceof Error) {\n if (msg.message) {\n console.error(chalk.red('✖'), this.textFormat('ERROR:' + msg.message, chalk.bgRed, preserveCol))\n }\n console.error(chalk.red(`${(msg as any).detail ? `${(msg as any).detail}\\n` : ''}${msg.stack}`))\n } else {\n console.error(chalk.red('✖'), this.textFormat(msg, chalk.bgRed, preserveCol))\n }\n }\n if (exit) process.exit(1)\n }\n\n /**\n * Logs a warning message\n * \n * @param msg \n * @param exit \n * @param preserveCol \n */\n static warn (msg: any, exit = false, preserveCol = false) {\n if (!this.shouldSuppressOutput('warn')) {\n console.warn(chalk.yellow('⚠'), this.textFormat(msg, chalk.bgYellow, preserveCol))\n }\n if (exit) process.exit(0)\n }\n\n /**\n * Logs a debug message (only shown with verbosity >= 3)\n * \n * @param msg \n * @param exit \n * @param preserveCol \n */\n static debug<M = any> (msg: M | M[], exit = false, preserveCol = false) {\n if (!this.shouldSuppressOutput('debug')) {\n if (Array.isArray(msg)) {\n for (let i = 0; i < msg.length; i++) {\n console.log(chalk.gray('🐛'), chalk.bgGray(i + 1), this.textFormat(msg[i], chalk.bgGray, preserveCol))\n }\n } else {\n console.log(chalk.gray('🐛'), this.textFormat(msg, chalk.bgGray, preserveCol))\n }\n }\n if (exit) process.exit(0)\n }\n\n /**\n * Terminates the process\n */\n static quiet () {\n process.exit(0)\n }\n\n static chalker (styles: LoggerChalk[]) {\n return (input: any): string =>\n styles.reduce((acc, style) => {\n if ((style as any) in chalk) {\n const fn = typeof style === 'function'\n ? style\n : chalk[style as never]\n\n return fn(acc)\n }\n\n return acc\n }, input)\n }\n\n /**\n * Parse an array formated message and logs it\n * \n * @param config \n * @param joiner \n * @param log If set to false, string output will be returned and not logged \n * @param sc color to use ue on split text if : is found \n */\n static parse (config: LoggerParseSignature, joiner?: string, log?: true, sc?: LoggerChalk): void\n static parse (config: LoggerParseSignature, joiner?: string, log?: false, sc?: LoggerChalk): string\n static parse (config: LoggerParseSignature, joiner = ' ', log = true, sc?: LoggerChalk): string | void {\n const string = config.map(([str, opt]) => {\n if (Array.isArray(opt)) {\n opt = Logger.chalker(opt) as ChalkInstance\n }\n\n const output = typeof opt === 'string' && typeof chalk[opt] === 'function'\n ? (chalk as any)[opt](str)\n : typeof opt === 'function' ? opt(str) : str\n\n if (!sc) {\n return output\n }\n\n return this.textFormat(output, Logger.chalker(Array.isArray(sc) ? sc : [sc]))\n }).join(joiner)\n\n if (log && !this.shouldSuppressOutput('line')) console.log(string)\n else return string\n }\n\n /**\n * Ouput formater object or format the output\n * \n * @returns \n */\n static log: LoggerLog = ((config, joiner, log: boolean = true, sc) => {\n if (typeof config === 'string') {\n const conf = [[config, joiner]] as [string, keyof ChalkInstance][]\n\n return this.parse(conf, '', log as false, sc)\n } else if (Array.isArray(config)) {\n return this.parse(config, String(joiner), log as false, sc)\n } else if (log && !this.shouldSuppressOutput('line')) {\n return console.log(this.textFormat(config, Logger.chalker(['blue'])))\n }\n\n return this\n }) as LoggerLog\n\n /**\n * A simple console like output logger\n * \n * @returns \n */\n static console () {\n return Console\n }\n}"],"mappings":"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"}
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@arkstack/common",
3
- "version": "0.2.4",
3
+ "version": "0.3.1",
4
4
  "type": "module",
5
5
  "description": "Common package for Arkstack providing common implementations of core Arkstack features such as routing, middleware, and database integration.",
6
6
  "homepage": "https://arkstack.toneflix.net",
@@ -30,6 +30,7 @@
30
30
  "./package.json": "./package.json"
31
31
  },
32
32
  "dependencies": {
33
+ "chalk": "^5.6.2",
33
34
  "detect-port": "^2.1.0"
34
35
  },
35
36
  "peerDependencies": {