@arkstack/common 0.1.30 → 0.2.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/dist/index.d.ts CHANGED
@@ -1,9 +1,11 @@
1
1
  /// <reference path="./app.d.ts" />
2
+ import { DotPath } from "@h3ravel/support";
3
+
2
4
  //#region src/lifecycle.d.ts
3
5
  declare const bindGracefulShutdown: (shutdown: () => Promise<void> | void) => void;
4
6
  //#endregion
5
7
  //#region src/network.d.ts
6
- declare const bootWithDetectedPort: (boot: (port: number) => Promise<void>, preferredPort?: number) => Promise<void>;
8
+ declare const bootWithDetectedPort: (boot: (port: number) => Promise<void>, preferredPort?: number, app?: any) => Promise<void>;
7
9
  declare const buildHtmlErrorResponse: ({
8
10
  message,
9
11
  stack,
@@ -19,5 +21,10 @@ declare const buildHtmlErrorResponse: ({
19
21
  //#region src/prototypes.d.ts
20
22
  declare const loadPrototypes: () => void;
21
23
  //#endregion
22
- export { bindGracefulShutdown, bootWithDetectedPort, buildHtmlErrorResponse, loadPrototypes };
24
+ //#region src/system.d.ts
25
+ declare const env: <X = string, Y = undefined>(env: string, defaultValue?: Y) => Y extends undefined ? X : Y;
26
+ declare const appUrl: (link?: string) => string;
27
+ declare const config: <X extends Record<string, any>, P extends DotPath<X> | undefined = undefined>(key?: P, defaultValue?: any) => P extends string ? any : X;
28
+ //#endregion
29
+ export { appUrl, bindGracefulShutdown, bootWithDetectedPort, buildHtmlErrorResponse, config, env, loadPrototypes };
23
30
  //# sourceMappingURL=index.d.ts.map
package/dist/index.js CHANGED
@@ -1,4 +1,8 @@
1
1
  import { detect } from "detect-port";
2
+ import { Obj } from "@h3ravel/support";
3
+ import { createRequire } from "module";
4
+ import path from "node:path";
5
+ import { readdirSync } from "fs";
2
6
 
3
7
  //#region src/lifecycle.ts
4
8
  const bindGracefulShutdown = (shutdown) => {
@@ -15,7 +19,9 @@ const bindGracefulShutdown = (shutdown) => {
15
19
 
16
20
  //#endregion
17
21
  //#region src/network.ts
18
- const bootWithDetectedPort = async (boot, preferredPort = 3e3) => {
22
+ const bootWithDetectedPort = async (boot, preferredPort = 3e3, app) => {
23
+ if (app && globalThis.app) globalThis.app = () => app;
24
+ globalThis.arkctx = { runtime: "HTTP" };
19
25
  await boot(await detect(preferredPort));
20
26
  };
21
27
  const buildHtmlErrorResponse = ({ message = "An unexpected error occurred.", stack, title, code = 500 }) => {
@@ -96,5 +102,75 @@ const loadPrototypes = () => {
96
102
  };
97
103
 
98
104
  //#endregion
99
- export { bindGracefulShutdown, bootWithDetectedPort, buildHtmlErrorResponse, loadPrototypes };
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
+ //#endregion
175
+ export { appUrl, bindGracefulShutdown, bootWithDetectedPort, buildHtmlErrorResponse, config, env, loadPrototypes };
100
176
  //# sourceMappingURL=index.js.map
package/dist/index.js.map CHANGED
@@ -1 +1 @@
1
- {"version":3,"file":"index.js","names":[],"sources":["../src/lifecycle.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 { detect } from 'detect-port'\n\nexport const bootWithDetectedPort = async (\n boot: (port: number) => Promise<void>,\n preferredPort: number = 3000,\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":";;;AAAA,MAAa,wBAAwB,aAAyC;AAC5E;EAAC;EAAU;EAAW;EAAU,CAAC,SAAS,WAAW;AACnD,UAAQ,GAAG,QAAQ,YAAY;AAC7B,SAAM,UAAU;IAChB;GACF;;;;;ACHJ,MAAa,uBAAuB,OAClC,MACA,gBAAwB,QACrB;AAEH,OAAM,KADO,MAAM,OAAO,cAAc,CACxB;;AAIlB,MAAa,0BAA0B,EACrC,UAAU,iCACV,OACA,OACA,OAAO,UAMH;AAYJ,SAXyC;EACvC,KAAK;EACL,KAAK;EACL,KAAK;EACL,KAAK;EACL,KAAK;EACL,KAAK;EACL,KAAK;EACL,KAAK;EACN,CAEgB,SAAS,SAAS;AAEnC,QAAO;;;iBAGQ,KAAK,KAAK,MAAM;;;;;;;;;;;;;;;;;;;;;;;;;;cA0BnB,KAAK;cACL,MAAM;aACP,QAAQ;UACX,QAAQ,6BAA6B,MAAM,UAAU,GAAG;;;;;;;;ACnElE,MAAa,uBAAuB;AAChC,QAAO,UAAU,YAAY,WAAY;AACrC,SAAO,KAAK,aAAa,CACpB,QAAQ,MAAM,IAAI,CAClB,QAAQ,MAAM,IAAI,CAClB,QAAQ,eAAe,SAAU,OAAO;AACrC,UAAO,MAAM,aAAa;IAC5B;;AAGV,QAAO,UAAU,YAAY,WAAY;AACrC,SAAO,KAAK,QAAQ,2BAA2B,SAAU,OAAO,OAAO;AACnE,OAAI,CAAC,UAAU,EAAG,QAAO;AAEzB,UAAO,UAAU,IAAI,MAAM,aAAa,GAAG,MAAM,aAAa;IAChE;;AAGN,QAAO,UAAU,aAAa,WAAY;AACtC,SAAO,KAAK,QAAQ,2BAA2B,SAAU,OAAO;AAC5D,UAAO,MAAM,aAAa;IAC5B;;AAGN,QAAO,UAAU,WAAW,SAAU,MAAc,IAAI,SAAiB,OAAO;AAC5E,MAAI,KAAK,UAAU,IACf,QAAO,KAAK,UAAU;EAG1B,MAAM,YAAY,KAAK,UAAU,GAAG,IAAI;EACxC,MAAM,iBAAiB,UAAU,YAAY,IAAI;AACjD,MAAI,iBAAiB,EACjB,QAAO,UAAU,UAAU,GAAG,eAAe,GAAG;AAGpD,SAAO,YAAY"}
1
+ {"version":3,"file":"index.js","names":[],"sources":["../src/lifecycle.ts","../src/network.ts","../src/prototypes.ts","../src/system.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 { 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.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 { DotPath, Obj } from '@h3ravel/support'\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 = <X = string, Y = undefined> (\n env: string,\n defaultValue?: Y,\n): Y extends undefined ? X : Y => {\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 = <X extends Record<string, any>, P extends DotPath<X> | undefined = undefined> (\n key?: P,\n defaultValue?: any\n): P extends string ? any : X => {\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}"],"mappings":"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"}
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@arkstack/common",
3
- "version": "0.1.30",
3
+ "version": "0.2.0",
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",
@@ -32,6 +32,9 @@
32
32
  "dependencies": {
33
33
  "detect-port": "^2.1.0"
34
34
  },
35
+ "peerDependencies": {
36
+ "@h3ravel/support": "^0.15.11"
37
+ },
35
38
  "scripts": {
36
39
  "build": "tsdown --config-loader unconfig",
37
40
  "version:patch": "pnpm version patch"