logixlysia 2.0.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/CHANGELOG.md ADDED
@@ -0,0 +1,29 @@
1
+ # Changelog
2
+
3
+ ## [2.0.0](https://github.com/PunGrumpy/logixlysia/compare/v1.0.0...v2.0.0) (2023-11-19)
4
+
5
+
6
+ ### Features
7
+
8
+ * **ci/cd:** separate deploy workflows from ci workflows ([e0344ae](https://github.com/PunGrumpy/logixlysia/commit/e0344ae32f711d140b1c914164e8eb7a57181558))
9
+
10
+ ## 1.0.0 (2023-11-18)
11
+
12
+
13
+ ### Features
14
+
15
+ * add example for test ([8f0f1ee](https://github.com/PunGrumpy/logixlysia/commit/8f0f1ee01de5e5c639687bf0971f0347c3516ed0))
16
+ * add log on start ([f1adeb9](https://github.com/PunGrumpy/logixlysia/commit/f1adeb9c620b42a2639ea6f01fa3e0ebd583ee8f))
17
+ * add logger format and enhance logging functionality ([c0887e8](https://github.com/PunGrumpy/logixlysia/commit/c0887e8eed6142a476d2fd7eb343ef6933e26d31))
18
+ * add new style on logging ([f1d9583](https://github.com/PunGrumpy/logixlysia/commit/f1d95832eacd6528c23454b914c61e09b4c1b83a))
19
+ * **ci:** add google automated workflows ([526e069](https://github.com/PunGrumpy/logixlysia/commit/526e0695029b0235a268445fd1c72b267c030c13))
20
+ * setting environment ([6f5e553](https://github.com/PunGrumpy/logixlysia/commit/6f5e553744999c70de1d8fb1b42a5eb7b75d8798))
21
+
22
+
23
+ ### Bug Fixes
24
+
25
+ * change name ([ee0c164](https://github.com/PunGrumpy/logixlysia/commit/ee0c1645be16a582c4df03874fdf0712e27a9e6a))
26
+ * change to use chalk instead piccolors ([b2fe4f5](https://github.com/PunGrumpy/logixlysia/commit/b2fe4f5a8dce51731e1729b9b0f2c7a15d280978))
27
+ * **types:** add types ([38e1f63](https://github.com/PunGrumpy/logixlysia/commit/38e1f63b4b92f4829772d638d45d7bad8182dbdc))
28
+ * update jsdocs and add new banner ([226c7eb](https://github.com/PunGrumpy/logixlysia/commit/226c7ebac504f661e58a9581c54e1937dfbea4a8))
29
+ * **utils:** update jsdocs ([8cab996](https://github.com/PunGrumpy/logixlysia/commit/8cab996e757d997d3a05183e85d4bfe684fdb11d))
package/LICENSE ADDED
@@ -0,0 +1,21 @@
1
+ MIT License
2
+
3
+ Copyright (c) 2023 PunGrumpy
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/README.md ADDED
@@ -0,0 +1,28 @@
1
+ <div align="center">
2
+ <h1><code>🦊</code> Logixlysia</h1>
3
+ <strong>Logixlysia is a logging library for ElysiaJS</strong>
4
+ <img src="./.github/images/screenshot.png" alt="Screenshot of Logixlysia" width="100%" height="auto" />
5
+ </div>
6
+
7
+ ## `📩` Installation
8
+
9
+ ```bash
10
+ bun add logixlysia
11
+ ```
12
+
13
+ ## `📝` Usage
14
+
15
+ ```ts
16
+ import { Elysia } from 'elysia'
17
+ import { logger } from 'logixlysia'
18
+
19
+ const app = new Elysia({
20
+ name: 'Logixlysia Example'
21
+ }).use(logger())
22
+
23
+ app.listen(3000)
24
+ ```
25
+
26
+ ## `📄` License
27
+
28
+ Licensed under the [MIT License](LICENSE).
@@ -0,0 +1,21 @@
1
+ /* eslint-disable @typescript-eslint/no-var-requires */
2
+ const { existsSync } = require('fs')
3
+ const { join } = require('path')
4
+
5
+ const isBun = existsSync(join(process.cwd(), 'bun.lockb'))
6
+ const isYarn = existsSync(join(process.cwd(), 'yarn.lock'))
7
+ const isPnpm = existsSync(join(process.cwd(), 'pnpm-lock.yaml'))
8
+
9
+ const packageManager = isBun ? 'bun' : isYarn ? 'yarn' : isPnpm ? 'pnpm' : 'npm'
10
+
11
+ const options = {
12
+ '**/*.(ts|tsx)': () => `${packageManager} tsc --noEmit`,
13
+ '**/*.(ts|tsx|js)': filenames => [
14
+ `${packageManager} eslint --fix ${filenames.join(' ')}`,
15
+ `${packageManager} prettier --write ${filenames.join(' ')}`
16
+ ],
17
+ '**/*.(md|json)': filenames =>
18
+ `${packageManager} prettier --write ${filenames.join(' ')}`
19
+ }
20
+
21
+ module.exports = options
package/package.json ADDED
@@ -0,0 +1,85 @@
1
+ {
2
+ "name": "logixlysia",
3
+ "version": "2.0.0",
4
+ "description": "🦊 Logixlysia is a logger for Elysia",
5
+ "type": "module",
6
+ "module": "src/index.ts",
7
+ "main": "src/index.ts",
8
+ "author": "PunGrumpy",
9
+ "publisher": "PunGrumpy",
10
+ "maintainers": [
11
+ "PunGrumpy"
12
+ ],
13
+ "publishConfig": {
14
+ "access": "public"
15
+ },
16
+ "license": "MIT",
17
+ "scripts": {
18
+ "test": "echo \"Error: no test specified\" && exit 1",
19
+ "dev": "bun run --watch example/basic.ts",
20
+ "prepare": "husky install",
21
+ "lint": "eslint . --ext .ts",
22
+ "lint:fix": "eslint . --ext .ts --fix",
23
+ "lint:staged": "lint-staged",
24
+ "prettier": "prettier --write ."
25
+ },
26
+ "os": [
27
+ "darwin",
28
+ "linux",
29
+ "win32"
30
+ ],
31
+ "badges": [
32
+ {
33
+ "name": "npm",
34
+ "url": "https://img.shields.io/npm/v/logixlysia.svg",
35
+ "description": "npm version",
36
+ "href": "https://www.npmjs.com/package/logixlysia"
37
+ },
38
+ {
39
+ "name": "npm",
40
+ "url": "https://img.shields.io/npm/dt/logixlysia.svg",
41
+ "description": "npm downloads",
42
+ "href": "https://www.npmjs.com/package/logixlysia"
43
+ },
44
+ {
45
+ "name": "GitHub issues",
46
+ "url": "https://img.shields.io/github/issues/PunGrumpy/logixlysia.svg",
47
+ "description": "GitHub issues",
48
+ "href": "https://github.com/PunGrumpy/logixlysia/issues"
49
+ }
50
+ ],
51
+ "repository": {
52
+ "type": "git",
53
+ "url": "git+https://github.com/PunGrumpy/logixlysia.git"
54
+ },
55
+ "bugs": {
56
+ "url": "https://github.com/PunGrumpy/logixlysia/issues"
57
+ },
58
+ "homepage": "https://github.com/PunGrumpy/logixlysia#readme",
59
+ "keywords": [
60
+ "web",
61
+ "logging",
62
+ "logger",
63
+ "elysia",
64
+ "elysiajs",
65
+ "logixlysia",
66
+ "middleware",
67
+ "middleware"
68
+ ],
69
+ "dependencies": {
70
+ "@typescript-eslint/eslint-plugin": "^6.9.1",
71
+ "@typescript-eslint/parser": "^6.9.1",
72
+ "chalk": "^5.3.0",
73
+ "elysia": "^0.7.21",
74
+ "eslint": "^8.53.0"
75
+ },
76
+ "devDependencies": {
77
+ "bun-types": "^1.0.8",
78
+ "husky": "^8.0.3",
79
+ "lint-staged": "^15.0.2",
80
+ "prettier": "^3.0.3"
81
+ },
82
+ "peerDependencies": {
83
+ "typescript": "^5.0.0"
84
+ }
85
+ }
@@ -0,0 +1,11 @@
1
+ const options = {
2
+ arrowParens: 'avoid',
3
+ singleQuote: true,
4
+ bracketSpacing: true,
5
+ endOfLine: 'lf',
6
+ semi: false,
7
+ tabWidth: 2,
8
+ trailingComma: 'none'
9
+ }
10
+
11
+ module.exports = options
package/src/index.ts ADDED
@@ -0,0 +1,48 @@
1
+ import Elysia from 'elysia'
2
+ import { createLogger } from './logger'
3
+ import startString from './utils/start'
4
+ import { Server } from 'bun'
5
+
6
+ /**
7
+ * Creates a logger.
8
+ *
9
+ * @export {Function} The logger.
10
+ * @module logger
11
+ * @category Logger
12
+ * @subcategory Functions
13
+ *
14
+ * @name Logixlysia
15
+ * @description Logixlysia is a logger plugin for ElysiaJS.
16
+ * @author PunGrumpy
17
+ * @license MIT
18
+ *
19
+ * @returns {Elysia} The logger.
20
+ */
21
+ export const logger = (): Elysia => {
22
+ const log = createLogger()
23
+
24
+ const elysia = new Elysia({
25
+ name: 'Logixlysia'
26
+ })
27
+ .onStart(ctx => {
28
+ startString(ctx.app.server as Server)
29
+ })
30
+ .onRequest(ctx => {
31
+ ctx.store = { beforeTime: process.hrtime.bigint() } as {
32
+ beforeTime: bigint
33
+ }
34
+ })
35
+ .onBeforeHandle(ctx => {
36
+ ctx.store = { beforeTime: process.hrtime.bigint() } as {
37
+ beforeTime: bigint
38
+ }
39
+ })
40
+ .onAfterHandle(({ request, store }) => {
41
+ log.info(request, {}, store as { beforeTime: bigint })
42
+ })
43
+ .onError(({ request, error, store }) => {
44
+ log.error(request, error, store as { beforeTime: bigint })
45
+ })
46
+
47
+ return elysia
48
+ }
package/src/logger.ts ADDED
@@ -0,0 +1,57 @@
1
+ import chalk from 'chalk'
2
+ import durationString from './utils/duration'
3
+ import methodString from './utils/method'
4
+ import logString from './utils/log'
5
+ import pathString from './utils/path'
6
+ import statusString from './utils/status'
7
+ import { RequestInfo } from './types/RequestInfo'
8
+ import { LogData, LogLevel, Logger } from './types/Logger'
9
+ import { StoreData } from './types/StoreData'
10
+
11
+ /**
12
+ * Logs a message to the console.
13
+ *
14
+ * @param {LogLevel} level The log level.
15
+ * @param {RequestInfo} request The request information.
16
+ * @param {LogData} data The log data.
17
+ * @param {StoreData} store The store data.
18
+ *
19
+ * @returns {void} The log message.
20
+ */
21
+ function log(
22
+ level: LogLevel,
23
+ request: RequestInfo,
24
+ data: LogData,
25
+ store: StoreData
26
+ ): void {
27
+ const logStr: string[] = []
28
+ const nowStr = chalk.bgYellow(
29
+ chalk.black(
30
+ new Date().toISOString().replace('T', ' ').replace('Z', '').slice(0, -4)
31
+ )
32
+ )
33
+ const levelStr = logString(level)
34
+ const durationStr = durationString(store.beforeTime)
35
+ const methodStr = methodString(request.method)
36
+ const pathnameStr = pathString(request)
37
+ const statusStr = statusString(data.status || 200)
38
+ const messageStr = data.message || ''
39
+
40
+ logStr.push(
41
+ `🦊 ${nowStr} ${levelStr} ${durationStr} ${methodStr} ${pathnameStr} ${statusStr} ${messageStr}`
42
+ )
43
+
44
+ console.log(logStr.join(' '))
45
+ }
46
+
47
+ /**
48
+ * Creates a formatted logger.
49
+ *
50
+ * @returns {Logger} The formatted logger.
51
+ */
52
+ export const createLogger = (): Logger => ({
53
+ info: (request, data, store) => log(LogLevel.INFO, request, data, store),
54
+ warning: (request, data, store) =>
55
+ log(LogLevel.WARNING, request, data, store),
56
+ error: (request, data, store) => log(LogLevel.ERROR, request, data, store)
57
+ })
@@ -0,0 +1,12 @@
1
+ /**
2
+ * The color map interface.
3
+ *
4
+ * @interface ColorMap
5
+ *
6
+ * @property {string} key The color function.
7
+ */
8
+ interface ColorMap {
9
+ [key: string]: (str: string) => string
10
+ }
11
+
12
+ export { ColorMap }
@@ -0,0 +1,47 @@
1
+ import { RequestInfo } from './RequestInfo'
2
+ import { StoreData } from './StoreData'
3
+
4
+ /**
5
+ * The log level.
6
+ *
7
+ * @enum {string}
8
+ *
9
+ * @property {string} INFO - The info log level.
10
+ * @property {string} WARNING - The warning log level.
11
+ * @property {string} ERROR - The error log level.
12
+ */
13
+ enum LogLevel {
14
+ INFO = 'INFO',
15
+ WARNING = 'WARNING',
16
+ ERROR = 'ERROR'
17
+ }
18
+
19
+ /**
20
+ * The log data interface.
21
+ *
22
+ * @interface LogData
23
+ *
24
+ * @property {number} status The status code.
25
+ * @property {string} message The message.
26
+ */
27
+ interface LogData {
28
+ status?: number
29
+ message?: string
30
+ }
31
+
32
+ /**
33
+ * The logger interface.
34
+ *
35
+ * @interface Logger
36
+ *
37
+ * @property {Function} info Logs an info message.
38
+ * @property {Function} warning Logs a warning message.
39
+ * @property {Function} error Logs an error message.
40
+ */
41
+ interface Logger {
42
+ info(request: RequestInfo, data: LogData, store: StoreData): void
43
+ warning(request: RequestInfo, data: LogData, store: StoreData): void
44
+ error(request: RequestInfo, data: LogData, store: StoreData): void
45
+ }
46
+
47
+ export { LogLevel, LogData, Logger }
@@ -0,0 +1,16 @@
1
+ /**
2
+ * The request info.
3
+ *
4
+ * @interface RequestInfo
5
+ *
6
+ * @property {Object} headers The request headers.
7
+ * @property {string} method The request method.
8
+ * @property {string} url The request URL.
9
+ */
10
+ interface RequestInfo {
11
+ headers: { get: (key: string) => any }
12
+ method: string
13
+ url: string
14
+ }
15
+
16
+ export { RequestInfo }
@@ -0,0 +1,16 @@
1
+ /**
2
+ * The server information.
3
+ *
4
+ * @interface Server
5
+ *
6
+ * @property {string} hostname The server hostname.
7
+ * @property {number} port The server port.
8
+ * @property {string} protocol The server protocol.
9
+ */
10
+ interface Server {
11
+ hostname?: string
12
+ port?: number
13
+ protocol?: string
14
+ }
15
+
16
+ export { Server }
@@ -0,0 +1,12 @@
1
+ /**
2
+ * The store data interface.
3
+ *
4
+ * @interface StoreData
5
+ *
6
+ * @property {bigint} beforeTime The time before the request.
7
+ */
8
+ interface StoreData {
9
+ beforeTime: bigint
10
+ }
11
+
12
+ export { StoreData }
@@ -0,0 +1,38 @@
1
+ import chalk from 'chalk'
2
+
3
+ /**
4
+ * Converts the time difference between the start of the request and the end of the request to a formatted string.
5
+ *
6
+ * @param {bigint} beforeTime The timestamp taken before the request.
7
+ *
8
+ * @returns {string} A formatted duration string with a time unit.
9
+ */
10
+ function durationString(beforeTime: bigint): string {
11
+ const now = process.hrtime.bigint()
12
+ const timeDifference = now - beforeTime
13
+ const nanoseconds = Number(timeDifference)
14
+
15
+ const durationInMicroseconds = (nanoseconds / 1e3).toFixed(0)
16
+ const durationInMilliseconds = (nanoseconds / 1e6).toFixed(0)
17
+
18
+ let timeMessage: string = ''
19
+
20
+ if (nanoseconds >= 1e9) {
21
+ const seconds = (nanoseconds / 1e9).toFixed(2)
22
+ timeMessage = `${seconds}s`
23
+ } else if (nanoseconds >= 1e6) {
24
+ timeMessage = `${durationInMilliseconds}ms`
25
+ } else if (nanoseconds >= 1e3) {
26
+ timeMessage = `${durationInMicroseconds}µs`
27
+ } else {
28
+ timeMessage = `${nanoseconds}ns`
29
+ }
30
+
31
+ if (timeMessage) {
32
+ timeMessage = chalk.gray(timeMessage).padStart(8).padEnd(16)
33
+ }
34
+
35
+ return timeMessage
36
+ }
37
+
38
+ export default durationString
@@ -0,0 +1,27 @@
1
+ import chalk from 'chalk'
2
+ import { ColorMap } from '~/types/ColorMap'
3
+
4
+ /**
5
+ * Converts a log level to a colored string representation.
6
+ *
7
+ * @param {string} log The log level (e.g., 'INFO', 'WARNING').
8
+ *
9
+ * @returns {string} A colored string representing the log level.
10
+ */
11
+ function logString(log: string): string {
12
+ const colorMap: ColorMap = {
13
+ INFO: chalk.bgGreen,
14
+ WARNING: chalk.bgYellow,
15
+ ERROR: chalk.bgRed
16
+ }
17
+
18
+ const colorFunction = colorMap[log]
19
+
20
+ if (colorFunction) {
21
+ return colorFunction(chalk.black(log.padEnd(7)))
22
+ }
23
+
24
+ return log
25
+ }
26
+
27
+ export default logString
@@ -0,0 +1,31 @@
1
+ import chalk from 'chalk'
2
+ import { ColorMap } from '~/types/ColorMap'
3
+
4
+ /**
5
+ * Converts an HTTP request method to a colored string representation.
6
+ *
7
+ * @param {string} method The HTTP request method (e.g., 'GET', 'POST').
8
+ *
9
+ * @returns {string} A colored string representing the method.
10
+ */
11
+ function methodString(method: string): string {
12
+ const colorMap: ColorMap = {
13
+ GET: chalk.white,
14
+ POST: chalk.yellow,
15
+ PUT: chalk.blue,
16
+ DELETE: chalk.red,
17
+ PATCH: chalk.green,
18
+ OPTIONS: chalk.cyan,
19
+ HEAD: chalk.magenta
20
+ }
21
+
22
+ const colorFunction = colorMap[method]
23
+
24
+ if (colorFunction) {
25
+ return colorFunction(method.padEnd(7))
26
+ }
27
+
28
+ return method
29
+ }
30
+
31
+ export default methodString
@@ -0,0 +1,15 @@
1
+ import { RequestInfo } from '~/types/RequestInfo'
2
+
3
+ /**
4
+ * Returns the path string.
5
+ *
6
+ * @param {RequestInfo} path The request information.
7
+ *
8
+ * @returns {string} The path string.
9
+ */
10
+ function pathString(path: RequestInfo): string {
11
+ const url = new URL(path?.url).pathname
12
+ return url
13
+ }
14
+
15
+ export default pathString
@@ -0,0 +1,45 @@
1
+ import { Server } from '~/types/Server'
2
+
3
+ /**
4
+ * Creates a box text.
5
+ *
6
+ * @param {string} text The text.
7
+ * @param {number} width The box width.
8
+ *
9
+ * @returns {string} The box text.
10
+ */
11
+ function createBoxText(text: string, width: number): string {
12
+ const padding = ' '.repeat((width - text.length) / 2)
13
+ return `${padding}${text}${padding}`
14
+ }
15
+
16
+ /**
17
+ * Starts the server string.
18
+ *
19
+ * @param {Server} config The server configuration.
20
+ *
21
+ * @returns {void} The server string.
22
+ */
23
+ function startString(config: Server): void {
24
+ const { hostname, port, protocol } = config
25
+ const ELYSIA_VERSION = import.meta.require('elysia/package.json').version
26
+ const title = `Elysia v${ELYSIA_VERSION}`
27
+ const message = `🦊 Elysia is running at ${protocol}://${hostname}:${port}`
28
+ const messageWidth = message.length
29
+ const boxWidth = Math.max(title.length, messageWidth) + 4
30
+ const border = '─'.repeat(boxWidth)
31
+
32
+ process.stdout.write('\x1Bc')
33
+
34
+ console.log(`
35
+ ┌${border}┐
36
+ │${createBoxText('', boxWidth)} │
37
+ │${createBoxText(title, boxWidth)} │
38
+ │${createBoxText('', boxWidth)} │
39
+ │${createBoxText(message, boxWidth)}│
40
+ │${createBoxText('', boxWidth)} │
41
+ └${border}┘
42
+ `)
43
+ }
44
+
45
+ export default startString
@@ -0,0 +1,27 @@
1
+ import chalk from 'chalk'
2
+
3
+ /**
4
+ * Returns the status string.
5
+ *
6
+ * @param {number} status The status code.
7
+ *
8
+ * @returns {string} The status string.
9
+ */
10
+ function statusString(status: number): string {
11
+ if (status >= 500) {
12
+ return chalk.red(status.toString())
13
+ }
14
+ if (status >= 400) {
15
+ return chalk.yellow(status.toString())
16
+ }
17
+ if (status >= 300) {
18
+ return chalk.cyan(status.toString())
19
+ }
20
+ if (status >= 200) {
21
+ return chalk.green(status.toString())
22
+ }
23
+
24
+ return status.toString()
25
+ }
26
+
27
+ export default statusString
package/tsconfig.json ADDED
@@ -0,0 +1,28 @@
1
+ {
2
+ "$schema": "https://json.schemastore.org/tsconfig",
3
+ "compilerOptions": {
4
+ "noUncheckedIndexedAccess": true,
5
+ "strict": true,
6
+ "allowImportingTsExtensions": true,
7
+ "module": "ESNext",
8
+ "moduleResolution": "Bundler",
9
+ "paths": {
10
+ "~/*": ["./src/*"]
11
+ },
12
+ "resolveJsonModule": true,
13
+ "types": ["bun-types"],
14
+ "downlevelIteration": true,
15
+ "noEmit": true,
16
+ "allowJs": true,
17
+ "allowSyntheticDefaultImports": true,
18
+ "forceConsistentCasingInFileNames": true,
19
+ "jsx": "react",
20
+ "jsxFactory": "ElysiaJSX",
21
+ "jsxFragmentFactory": "ElysiaJSX.Fragment",
22
+ "lib": ["ESNext"],
23
+ "moduleDetection": "force",
24
+ "target": "ESNext",
25
+ "composite": true,
26
+ "skipLibCheck": true
27
+ }
28
+ }