@arkstack/common 0.2.0 → 0.2.2
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/dist/app.d.ts +4 -0
- package/dist/index.d.ts +9 -3
- package/dist/index.js +74 -72
- package/dist/index.js.map +1 -1
- package/package.json +1 -1
package/dist/app.d.ts
CHANGED
package/dist/index.d.ts
CHANGED
|
@@ -22,9 +22,15 @@ declare const buildHtmlErrorResponse: ({
|
|
|
22
22
|
declare const loadPrototypes: () => void;
|
|
23
23
|
//#endregion
|
|
24
24
|
//#region src/system.d.ts
|
|
25
|
-
|
|
25
|
+
interface GlobalEnv {
|
|
26
|
+
<X = string, Y = undefined>(env: string, defaultValue?: Y): Y extends undefined ? X : Y;
|
|
27
|
+
}
|
|
28
|
+
declare const env: GlobalEnv;
|
|
26
29
|
declare const appUrl: (link?: string) => string;
|
|
27
|
-
|
|
30
|
+
interface GlobalConfig {
|
|
31
|
+
<X extends Record<string, any>, P extends DotPath<X> | undefined = undefined>(key?: P, defaultValue?: any): P extends string ? any : X;
|
|
32
|
+
}
|
|
33
|
+
declare const config: GlobalConfig;
|
|
28
34
|
//#endregion
|
|
29
|
-
export { appUrl, bindGracefulShutdown, bootWithDetectedPort, buildHtmlErrorResponse, config, env, loadPrototypes };
|
|
35
|
+
export { GlobalConfig, GlobalEnv, appUrl, bindGracefulShutdown, bootWithDetectedPort, buildHtmlErrorResponse, config, env, loadPrototypes };
|
|
30
36
|
//# sourceMappingURL=index.d.ts.map
|
package/dist/index.js
CHANGED
|
@@ -1,8 +1,8 @@
|
|
|
1
|
-
import { detect } from "detect-port";
|
|
2
1
|
import { Obj } from "@h3ravel/support";
|
|
3
2
|
import { createRequire } from "module";
|
|
4
3
|
import path from "node:path";
|
|
5
4
|
import { readdirSync } from "fs";
|
|
5
|
+
import { detect } from "detect-port";
|
|
6
6
|
|
|
7
7
|
//#region src/lifecycle.ts
|
|
8
8
|
const bindGracefulShutdown = (shutdown) => {
|
|
@@ -17,10 +17,82 @@ const bindGracefulShutdown = (shutdown) => {
|
|
|
17
17
|
});
|
|
18
18
|
};
|
|
19
19
|
|
|
20
|
+
//#endregion
|
|
21
|
+
//#region src/system.ts
|
|
22
|
+
/**
|
|
23
|
+
* Read the .env file
|
|
24
|
+
*
|
|
25
|
+
* @param env
|
|
26
|
+
* @param def
|
|
27
|
+
* @returns
|
|
28
|
+
*/
|
|
29
|
+
const env = (env, defaultValue) => {
|
|
30
|
+
let val = process.env[env] ?? "";
|
|
31
|
+
if ([
|
|
32
|
+
true,
|
|
33
|
+
"true",
|
|
34
|
+
"on",
|
|
35
|
+
false,
|
|
36
|
+
"false",
|
|
37
|
+
"off"
|
|
38
|
+
].includes(val)) val = [
|
|
39
|
+
true,
|
|
40
|
+
"true",
|
|
41
|
+
"on"
|
|
42
|
+
].includes(val);
|
|
43
|
+
if (!isNaN(Number(val)) && typeof val !== "boolean" && typeof val !== "undefined" && val !== "") val = Number(val);
|
|
44
|
+
if (val === "") val = void 0;
|
|
45
|
+
if (val === "null") val = null;
|
|
46
|
+
val ??= defaultValue;
|
|
47
|
+
return val;
|
|
48
|
+
};
|
|
49
|
+
/**
|
|
50
|
+
* Build the app url
|
|
51
|
+
*
|
|
52
|
+
* @param link
|
|
53
|
+
* @returns
|
|
54
|
+
*/
|
|
55
|
+
const appUrl = (link) => {
|
|
56
|
+
const port = env("PORT") || "3000";
|
|
57
|
+
const defaultUrl = `http://localhost:${port}`;
|
|
58
|
+
const appUrl = env("APP_URL") ?? defaultUrl;
|
|
59
|
+
try {
|
|
60
|
+
const url = new URL(appUrl);
|
|
61
|
+
if (url.port || url.hostname === "localhost") url.port = port;
|
|
62
|
+
const baseUrl = url.toString().replace(/\/$/, "");
|
|
63
|
+
if (link) return `${baseUrl}${`/${link.replace(/^\/+/, "")}`}`;
|
|
64
|
+
return baseUrl;
|
|
65
|
+
} catch {
|
|
66
|
+
return link ? `${defaultUrl}/${link.replace(/^\/+/, "")}` : defaultUrl;
|
|
67
|
+
}
|
|
68
|
+
};
|
|
69
|
+
/**
|
|
70
|
+
* Gets the application configuration.
|
|
71
|
+
*
|
|
72
|
+
* @param key The configuration key to retrieve.
|
|
73
|
+
* @param defaultValue The default value to return if the key is not found.
|
|
74
|
+
* @returns The configuration value.
|
|
75
|
+
*/
|
|
76
|
+
const config = (key, defaultValue) => {
|
|
77
|
+
const require = createRequire(import.meta.url);
|
|
78
|
+
const config = readdirSync(path.join(process.cwd(), "dist/config"), { withFileTypes: true }).filter((file) => {
|
|
79
|
+
if (file.name.includes("middleware") && globalThis.arkctx.runtime === "CLI") return false;
|
|
80
|
+
return file.isFile() && (file.name.endsWith(".js") || file.name.endsWith(".ts"));
|
|
81
|
+
}).reduce((configs, file) => {
|
|
82
|
+
const configName = path.basename(file.name, path.extname(file.name));
|
|
83
|
+
configs[configName] = require(path.join(file.parentPath, file.name)).default(globalThis.app());
|
|
84
|
+
return configs;
|
|
85
|
+
}, {});
|
|
86
|
+
if (key) return Obj.get(config, key, defaultValue);
|
|
87
|
+
return config;
|
|
88
|
+
};
|
|
89
|
+
|
|
20
90
|
//#endregion
|
|
21
91
|
//#region src/network.ts
|
|
22
92
|
const bootWithDetectedPort = async (boot, preferredPort = 3e3, app) => {
|
|
23
|
-
if (app && globalThis.app) globalThis.app = () => app;
|
|
93
|
+
if (app && !globalThis.app) globalThis.app = () => app;
|
|
94
|
+
globalThis.env = env;
|
|
95
|
+
globalThis.config = config;
|
|
24
96
|
globalThis.arkctx = { runtime: "HTTP" };
|
|
25
97
|
await boot(await detect(preferredPort));
|
|
26
98
|
};
|
|
@@ -101,76 +173,6 @@ const loadPrototypes = () => {
|
|
|
101
173
|
};
|
|
102
174
|
};
|
|
103
175
|
|
|
104
|
-
//#endregion
|
|
105
|
-
//#region src/system.ts
|
|
106
|
-
/**
|
|
107
|
-
* Read the .env file
|
|
108
|
-
*
|
|
109
|
-
* @param env
|
|
110
|
-
* @param def
|
|
111
|
-
* @returns
|
|
112
|
-
*/
|
|
113
|
-
const env = (env, defaultValue) => {
|
|
114
|
-
let val = process.env[env] ?? "";
|
|
115
|
-
if ([
|
|
116
|
-
true,
|
|
117
|
-
"true",
|
|
118
|
-
"on",
|
|
119
|
-
false,
|
|
120
|
-
"false",
|
|
121
|
-
"off"
|
|
122
|
-
].includes(val)) val = [
|
|
123
|
-
true,
|
|
124
|
-
"true",
|
|
125
|
-
"on"
|
|
126
|
-
].includes(val);
|
|
127
|
-
if (!isNaN(Number(val)) && typeof val !== "boolean" && typeof val !== "undefined" && val !== "") val = Number(val);
|
|
128
|
-
if (val === "") val = void 0;
|
|
129
|
-
if (val === "null") val = null;
|
|
130
|
-
val ??= defaultValue;
|
|
131
|
-
return val;
|
|
132
|
-
};
|
|
133
|
-
/**
|
|
134
|
-
* Build the app url
|
|
135
|
-
*
|
|
136
|
-
* @param link
|
|
137
|
-
* @returns
|
|
138
|
-
*/
|
|
139
|
-
const appUrl = (link) => {
|
|
140
|
-
const port = env("PORT") || "3000";
|
|
141
|
-
const defaultUrl = `http://localhost:${port}`;
|
|
142
|
-
const appUrl = env("APP_URL") ?? defaultUrl;
|
|
143
|
-
try {
|
|
144
|
-
const url = new URL(appUrl);
|
|
145
|
-
if (url.port || url.hostname === "localhost") url.port = port;
|
|
146
|
-
const baseUrl = url.toString().replace(/\/$/, "");
|
|
147
|
-
if (link) return `${baseUrl}${`/${link.replace(/^\/+/, "")}`}`;
|
|
148
|
-
return baseUrl;
|
|
149
|
-
} catch {
|
|
150
|
-
return link ? `${defaultUrl}/${link.replace(/^\/+/, "")}` : defaultUrl;
|
|
151
|
-
}
|
|
152
|
-
};
|
|
153
|
-
/**
|
|
154
|
-
* Gets the application configuration.
|
|
155
|
-
*
|
|
156
|
-
* @param key The configuration key to retrieve.
|
|
157
|
-
* @param defaultValue The default value to return if the key is not found.
|
|
158
|
-
* @returns The configuration value.
|
|
159
|
-
*/
|
|
160
|
-
const config = (key, defaultValue) => {
|
|
161
|
-
const require = createRequire(import.meta.url);
|
|
162
|
-
const config = readdirSync(path.join(process.cwd(), "dist/config"), { withFileTypes: true }).filter((file) => {
|
|
163
|
-
if (file.name.includes("middleware") && globalThis.arkctx.runtime === "CLI") return false;
|
|
164
|
-
return file.isFile() && (file.name.endsWith(".js") || file.name.endsWith(".ts"));
|
|
165
|
-
}).reduce((configs, file) => {
|
|
166
|
-
const configName = path.basename(file.name, path.extname(file.name));
|
|
167
|
-
configs[configName] = require(path.join(file.parentPath, file.name)).default(globalThis.app());
|
|
168
|
-
return configs;
|
|
169
|
-
}, {});
|
|
170
|
-
if (key) return Obj.get(config, key, defaultValue);
|
|
171
|
-
return config;
|
|
172
|
-
};
|
|
173
|
-
|
|
174
176
|
//#endregion
|
|
175
177
|
export { appUrl, bindGracefulShutdown, bootWithDetectedPort, buildHtmlErrorResponse, config, env, loadPrototypes };
|
|
176
178
|
//# sourceMappingURL=index.js.map
|
package/dist/index.js.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"index.js","names":[],"sources":["../src/lifecycle.ts","../src/
|
|
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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"}
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@arkstack/common",
|
|
3
|
-
"version": "0.2.
|
|
3
|
+
"version": "0.2.2",
|
|
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",
|