logixlysia 3.3.0 → 3.3.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/.gitmodules ADDED
@@ -0,0 +1,3 @@
1
+ [submodule ".trunk/configs"]
2
+ path = .trunk/configs
3
+ url = git@github.com:PunGrumpy/.trunk.git
@@ -0,0 +1,26 @@
1
+ ---
2
+ version: 0.1
3
+ cli:
4
+ version: 1.22.1
5
+ plugins:
6
+ sources:
7
+ - id: trunk
8
+ ref: v1.5.0
9
+ uri: https://github.com/trunk-io/plugins
10
+ runtimes:
11
+ enabled:
12
+ - node@22.2.0
13
+ lint:
14
+ enabled:
15
+ - oxipng@9.1.1
16
+ - shfmt@3.6.0
17
+ - eslint@9.3.0
18
+ - actionlint@1.7.0
19
+ - git-diff-check
20
+ - markdownlint@0.40.0
21
+ - prettier@3.2.5
22
+ - trufflehog@3.76.3
23
+ - yamllint@1.35.1
24
+ actions:
25
+ enabled:
26
+ - npm-check
package/CHANGELOG.md CHANGED
@@ -1,5 +1,19 @@
1
1
  # Changelog
2
2
 
3
+ ## [3.3.2](https://github.com/PunGrumpy/logixlysia/compare/v3.3.1...v3.3.2) (2024-06-06)
4
+
5
+
6
+ ### Bug Fixes
7
+
8
+ * **npm-ignore:** accidentally ignore `tsconfig.json` ([85997f7](https://github.com/PunGrumpy/logixlysia/commit/85997f7dd8bb22b4811a7555e0a56e0cfb3ee269))
9
+
10
+ ## [3.3.1](https://github.com/PunGrumpy/logixlysia/compare/v3.3.0...v3.3.1) (2024-06-01)
11
+
12
+
13
+ ### Bug Fixes
14
+
15
+ * **deps:** move `ESLint` and related packages to dev dependencies ([98de50c](https://github.com/PunGrumpy/logixlysia/commit/98de50c6c3bffc5939963ebd04563204c7c70793)), closes [#46](https://github.com/PunGrumpy/logixlysia/issues/46)
16
+
3
17
  ## [3.3.0](https://github.com/PunGrumpy/logixlysia/compare/v3.2.0...v3.3.0) (2024-05-22)
4
18
 
5
19
 
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "logixlysia",
3
- "version": "3.3.0",
3
+ "version": "3.3.2",
4
4
  "description": "🦊 Logixlysia is a logger for Elysia",
5
5
  "type": "module",
6
6
  "module": "src/index.ts",
@@ -23,7 +23,9 @@
23
23
  "dev": "bun run --watch example/basic.ts",
24
24
  "prepare": "husky",
25
25
  "lint:staged": "lint-staged",
26
- "prettier": "prettier --write ."
26
+ "prettier": "prettier --write --config .trunk/configs/.prettierrc.yaml .",
27
+ "trunk:check": "trunk check",
28
+ "trunk:fmt": "trunk fmt"
27
29
  },
28
30
  "os": [
29
31
  "darwin",
@@ -68,23 +70,24 @@
68
70
  "middleware"
69
71
  ],
70
72
  "dependencies": {
71
- "@eslint/js": "^9.3.0",
72
- "@typescript-eslint/eslint-plugin": "^7.10.0",
73
- "@typescript-eslint/parser": "^7.10.0",
74
73
  "chalk": "^5.3.0",
75
- "elysia": "^1.0.21",
76
- "eslint": "9.x",
77
- "eslint-plugin-simple-import-sort": "^12.1.0",
78
- "typescript-eslint": "^7.10.0"
74
+ "elysia": "^1.0.21"
79
75
  },
80
76
  "devDependencies": {
81
77
  "@elysiajs/eden": "^1.0.13",
78
+ "@eslint/js": "^9.3.0",
79
+ "@trunkio/launcher": "^1.3.1",
80
+ "@typescript-eslint/eslint-plugin": "^7.10.0",
81
+ "@typescript-eslint/parser": "^7.10.0",
82
82
  "bun-types": "^1.1.9",
83
83
  "commitizen": "^4.3.0",
84
84
  "cz-conventional-changelog": "^3.3.0",
85
+ "eslint": "9.x",
86
+ "eslint-plugin-simple-import-sort": "^12.1.0",
85
87
  "husky": "^9.0.11",
86
88
  "lint-staged": "^15.2.4",
87
- "prettier": "^3.2.5"
89
+ "prettier": "^3.2.5",
90
+ "typescript-eslint": "^7.10.0"
88
91
  },
89
92
  "peerDependencies": {
90
93
  "typescript": "^5.0.0"
package/src/index.ts CHANGED
@@ -1,13 +1,13 @@
1
1
  import { Server } from 'bun'
2
2
  import Elysia from 'elysia'
3
3
 
4
- import { createLogger } from './logger'
5
- import { handleHttpError } from './logger/handle'
4
+ import { createLogger } from './logger/createLogger'
5
+ import { handleHttpError } from './logger/handleHttpError'
6
6
  import { HttpError, Options } from './types'
7
7
  import startServer from './utils/start'
8
8
 
9
9
  /**
10
- * Creates a logger.
10
+ * Creates a logger plugin for ElysiaJS.
11
11
  *
12
12
  * @export
13
13
  * @module logger
@@ -19,7 +19,9 @@ import startServer from './utils/start'
19
19
  * @author PunGrumpy
20
20
  * @license MIT
21
21
  *
22
- * @returns {Elysia} The logger.
22
+ * @param {Options} [options] Configuration options for the logger.
23
+ *
24
+ * @returns {Elysia} The logger plugin for ElysiaJS.
23
25
  */
24
26
  export default function logixlysia(options?: Options): Elysia {
25
27
  const log = createLogger(options)
@@ -1,56 +1,23 @@
1
1
  import chalk from 'chalk'
2
2
 
3
- import {
4
- LogData,
5
- Logger,
6
- LogLevel,
7
- Options,
8
- RequestInfo,
9
- StoreData
10
- } from '~/types'
3
+ import { LogData, LogLevel, Options, RequestInfo, StoreData } from '~/types'
11
4
  import durationString from '~/utils/duration'
12
5
  import logString from '~/utils/log'
13
6
  import methodString from '~/utils/method'
14
7
  import pathString from '~/utils/path'
15
8
  import statusString from '~/utils/status'
16
9
 
17
- import { filterLog } from './filter'
18
-
19
- /**
20
- * Logs a message.
21
- *
22
- * @param {LogLevel} level The log level.
23
- * @param {RequestInfo} request The request.
24
- * @param {LogData} data The log data.
25
- * @param {StoreData} store The store data.
26
- * @param {Options} options The options.
27
- */
28
- function log(
29
- level: LogLevel,
30
- request: RequestInfo,
31
- data: LogData,
32
- store: StoreData,
33
- options?: Options
34
- ): void {
35
- if (!filterLog(level, data.status || 200, request.method, options)) {
36
- return
37
- }
38
-
39
- const logMessage = buildLogMessage(level, request, data, store, options)
40
- console.log(logMessage)
41
- }
42
-
43
10
  /**
44
11
  * Builds a log message.
45
12
  *
46
13
  * @param {LogLevel} level The log level.
47
- * @param {RequestInfo} request The request.
14
+ * @param {RequestInfo} request The request information.
48
15
  * @param {LogData} data The log data.
49
16
  * @param {StoreData} store The store data.
50
- * @param {Options} options The options.
51
- * @returns {string} The log message.
17
+ * @param {Options} options The logger options.
18
+ * @returns {string} The formatted log message.
52
19
  */
53
- function buildLogMessage(
20
+ export function buildLogMessage(
54
21
  level: LogLevel,
55
22
  request: RequestInfo,
56
23
  data: LogData,
@@ -84,19 +51,3 @@ function buildLogMessage(
84
51
 
85
52
  return logMessage
86
53
  }
87
-
88
- /**
89
- * Creates a logger.
90
- *
91
- * @param {Options} options The options.
92
- * @returns {Logger} The logger.
93
- */
94
- function createLogger(options?: Options): Logger {
95
- return {
96
- log: (level, request, data, store) =>
97
- log(level, request, data, store, options),
98
- customLogFormat: options?.config?.customLogFormat
99
- }
100
- }
101
-
102
- export { buildLogMessage, createLogger, log }
@@ -0,0 +1,49 @@
1
+ import {
2
+ LogData,
3
+ Logger,
4
+ LogLevel,
5
+ Options,
6
+ RequestInfo,
7
+ StoreData
8
+ } from '~/types'
9
+
10
+ import { buildLogMessage } from './buildLogMessage'
11
+ import { filterLog } from './filter'
12
+
13
+ /**
14
+ * Logs a message to the console.
15
+ *
16
+ * @param {LogLevel} level The log level.
17
+ * @param {RequestInfo} request The request information.
18
+ * @param {LogData} data The log data.
19
+ * @param {StoreData} store The store data.
20
+ * @param {Options} options The logger options.
21
+ */
22
+ async function log(
23
+ level: LogLevel,
24
+ request: RequestInfo,
25
+ data: LogData,
26
+ store: StoreData,
27
+ options?: Options
28
+ ): Promise<void> {
29
+ if (!filterLog(level, data.status || 200, request.method, options)) {
30
+ return
31
+ }
32
+
33
+ const logMessage = buildLogMessage(level, request, data, store, options)
34
+ console.log(logMessage)
35
+ }
36
+
37
+ /**
38
+ * Creates a logger instance.
39
+ *
40
+ * @param {Options} options The logger options.
41
+ * @returns {Logger} The logger instance.
42
+ */
43
+ export function createLogger(options?: Options): Logger {
44
+ return {
45
+ log: async (level, request, data, store) =>
46
+ log(level, request, data, store, options),
47
+ customLogFormat: options?.config?.customLogFormat
48
+ }
49
+ }
@@ -1,21 +1,21 @@
1
1
  import { HttpError, Options, RequestInfo, StoreData } from '~/types'
2
2
 
3
- import { buildLogMessage } from '.'
3
+ import { buildLogMessage } from './buildLogMessage'
4
4
 
5
5
  /**
6
- * Handles an HTTP error.
6
+ * Handles an HTTP error and logs it.
7
7
  *
8
- * @param {RequestInfo} request The request.
8
+ * @param {RequestInfo} request The request information.
9
9
  * @param {HttpError} error The HTTP error.
10
10
  * @param {StoreData} store The store data.
11
- * @param {Options} options The options.
11
+ * @param {Options} options The logger options.
12
12
  */
13
- function handleHttpError(
13
+ export async function handleHttpError(
14
14
  request: RequestInfo,
15
15
  error: HttpError,
16
16
  store: StoreData,
17
17
  options?: Options
18
- ): void {
18
+ ): Promise<void> {
19
19
  const statusCode = error.status || 500
20
20
  const logMessage = buildLogMessage(
21
21
  'ERROR',
@@ -26,5 +26,3 @@ function handleHttpError(
26
26
  )
27
27
  console.error(logMessage)
28
28
  }
29
-
30
- export { handleHttpError }
@@ -9,17 +9,18 @@ import chalk from 'chalk'
9
9
  * @returns {string} A formatted duration string including the time unit.
10
10
  */
11
11
  function durationString(beforeTime: bigint): string {
12
- const nanoseconds = Number(process.hrtime.bigint() - beforeTime)
12
+ const currentTime = process.hrtime.bigint()
13
+ const nanoseconds = Number(currentTime - beforeTime)
13
14
 
14
15
  const timeUnits = [
15
- { unit: 's', threshold: 1e9 },
16
- { unit: 'ms', threshold: 1e6 },
17
- { unit: 'µs', threshold: 1e3 }
16
+ { unit: 's', threshold: 1e9, decimalPlaces: 2 },
17
+ { unit: 'ms', threshold: 1e6, decimalPlaces: 0 },
18
+ { unit: 'µs', threshold: 1e3, decimalPlaces: 0 }
18
19
  ]
19
20
 
20
- for (const { unit, threshold } of timeUnits) {
21
+ for (const { unit, threshold, decimalPlaces } of timeUnits) {
21
22
  if (nanoseconds >= threshold) {
22
- const value = (nanoseconds / threshold).toFixed(threshold === 1e9 ? 2 : 0)
23
+ const value = (nanoseconds / threshold).toFixed(decimalPlaces)
23
24
  return formatTime(value, unit)
24
25
  }
25
26
  }
package/src/utils/path.ts CHANGED
@@ -11,7 +11,7 @@ import { RequestInfo } from '~/types'
11
11
  function pathString(requestInfo: RequestInfo): string | undefined {
12
12
  try {
13
13
  return new URL(requestInfo.url).pathname
14
- } catch (error) {
14
+ } catch {
15
15
  return undefined
16
16
  }
17
17
  }
@@ -9,9 +9,9 @@ import { Server } from '~/types'
9
9
  * @returns {string} The box text.
10
10
  */
11
11
  function createBoxText(text: string, width: number): string {
12
- const paddingLength = Math.max(0, (width - text.length + 1) / 2)
12
+ const paddingLength = Math.max(0, (width - text.length) / 2)
13
13
  const padding = ' '.repeat(paddingLength)
14
- return `${padding}${text}${padding}`.slice(0, width)
14
+ return `${padding}${text}${padding}`.padEnd(width)
15
15
  }
16
16
 
17
17
  /**
@@ -26,8 +26,7 @@ function startServer(config: Server): void {
26
26
  const ELYSIA_VERSION = import.meta.require('elysia/package.json').version
27
27
  const title = `Elysia v${ELYSIA_VERSION}`
28
28
  const message = `🦊 Elysia is running at ${protocol}://${hostname}:${port}`
29
- const messageWidth = message.length
30
- const boxWidth = Math.max(title.length, messageWidth) + 4
29
+ const boxWidth = Math.max(title.length, message.length) + 4
31
30
  const border = '─'.repeat(boxWidth)
32
31
 
33
32
  console.log(`
package/.gitguardian.yml DELETED
@@ -1,16 +0,0 @@
1
- # Required, otherwise ggshield considers the file to use the deprecated v1 format
2
- version: 2
3
-
4
- # Set to true if the desired exit code for the CLI is always 0, otherwise the
5
- # exit code will be 1 if incidents are found.
6
- exit-zero: false
7
-
8
- verbose: false
9
-
10
- instance: https://dashboard.gitguardian.com
11
-
12
- # Maximum commits to scan in a hook.
13
- max-commits-for-hook: 50
14
-
15
- # Accept self-signed certificates for the API.
16
- allow-self-signed: false
package/.prettierignore DELETED
@@ -1,2 +0,0 @@
1
- CHANGELOG.md
2
- node_modules/
package/.prettierrc DELETED
@@ -1,9 +0,0 @@
1
- {
2
- "arrowParens": "avoid",
3
- "singleQuote": true,
4
- "bracketSpacing": true,
5
- "endOfLine": "lf",
6
- "semi": false,
7
- "tabWidth": 2,
8
- "trailingComma": "none"
9
- }
package/eslint.config.js DELETED
@@ -1,25 +0,0 @@
1
- import pluginJs from '@eslint/js'
2
- import eslintPlugin from '@typescript-eslint/eslint-plugin'
3
- import eslintPluginSimpleImportSort from 'eslint-plugin-simple-import-sort'
4
- import globals from 'globals'
5
- import tseslint from 'typescript-eslint'
6
-
7
- export default [
8
- pluginJs.configs.recommended,
9
- ...tseslint.configs.recommended,
10
- {
11
- languageOptions: {
12
- globals: globals.browser
13
- },
14
- plugins: {
15
- '@typescript-eslint': eslintPlugin,
16
- 'simple-import-sort': eslintPluginSimpleImportSort
17
- },
18
- rules: {
19
- 'no-undef': 'off',
20
- '@typescript-eslint/no-explicit-any': 'off',
21
- 'simple-import-sort/imports': 'error',
22
- 'simple-import-sort/exports': 'error'
23
- }
24
- }
25
- ]
@@ -1,62 +0,0 @@
1
- import { describe, expect, it } from 'bun:test'
2
-
3
- import { filterLog } from '~/logger/filter'
4
- import { LogLevel, Options } from '~/types'
5
-
6
- describe('filterLog', () => {
7
- const logLevel: LogLevel = 'info'
8
- const status = 200
9
- const method = 'GET'
10
-
11
- it('should return true if no filter is provided', () => {
12
- expect(filterLog(logLevel, status, method)).toBe(true)
13
- })
14
-
15
- it('should filter by log level (single value)', () => {
16
- const options: Options = { config: { logFilter: { level: 'error' } } }
17
- expect(filterLog(logLevel, status, method, options)).toBe(false)
18
- })
19
-
20
- it('should filter by log level (array)', () => {
21
- const options: Options = {
22
- config: { logFilter: { level: ['error', 'info'] } }
23
- }
24
- expect(filterLog(logLevel, status, method, options)).toBe(true)
25
- })
26
-
27
- it('should filter by status (single value)', () => {
28
- const options: Options = { config: { logFilter: { status: 404 } } }
29
- expect(filterLog(logLevel, status, method, options)).toBe(false)
30
- })
31
-
32
- it('should filter by status (array)', () => {
33
- const options: Options = { config: { logFilter: { status: [200, 404] } } }
34
- expect(filterLog(logLevel, status, method, options)).toBe(true)
35
- })
36
-
37
- it('should filter by method (single value)', () => {
38
- const options: Options = { config: { logFilter: { method: 'POST' } } }
39
- expect(filterLog(logLevel, status, method, options)).toBe(false)
40
- })
41
-
42
- it('should filter by method (array)', () => {
43
- const options: Options = {
44
- config: { logFilter: { method: ['GET', 'POST'] } }
45
- }
46
- expect(filterLog(logLevel, status, method, options)).toBe(true)
47
- })
48
-
49
- it('should return false if any filter condition is not met', () => {
50
- const options: Options = {
51
- config: { logFilter: { level: 'info', status: 404, method: 'POST' } }
52
- }
53
- expect(filterLog(logLevel, status, method, options)).toBe(false)
54
- })
55
-
56
- it('should return true if all filter conditions are met', () => {
57
- const options: Options = {
58
- config: { logFilter: { level: 'info', status: 200, method: 'GET' } }
59
- }
60
- expect(filterLog(logLevel, status, method, options)).toBe(true)
61
- })
62
- })
@@ -1,223 +0,0 @@
1
- import { edenTreaty } from '@elysiajs/eden'
2
- import { beforeAll, beforeEach, describe, expect, it } from 'bun:test'
3
- import { Elysia } from 'elysia'
4
-
5
- import logixlysia from '../src'
6
-
7
- describe('Logixlysia with IP logging enabled', () => {
8
- let server: Elysia
9
- let app: ReturnType<typeof edenTreaty> | any
10
- let logs: string[] = []
11
-
12
- beforeAll(() => {
13
- server = new Elysia()
14
- .use(
15
- logixlysia({
16
- config: {
17
- ip: true,
18
- customLogFormat:
19
- '🦊 {now} {duration} {level} {method} {pathname} {status} {message} {ip}'
20
- }
21
- })
22
- )
23
- .get('/', () => {
24
- return '🦊 Logixlysia Getting'
25
- })
26
- .post('logixlysia', () => '🦊 Logixlysia Posting')
27
- .listen(3000)
28
-
29
- app = edenTreaty<typeof server>('http://127.0.0.1:3000')
30
- })
31
-
32
- beforeEach(() => {
33
- logs = []
34
- })
35
-
36
- it("Logs incoming IP address for GET '/' requests when X-Forwarded-For header is present", async () => {
37
- const requestCount = 5
38
-
39
- for (let i = 0; i < requestCount; i++) {
40
- await app.get('/', {
41
- headers: { 'X-Forwarded-For': '192.168.1.1' }
42
- })
43
- }
44
-
45
- logs.forEach(log => {
46
- expect(log).toMatch(
47
- /^🦊 .+ INFO .+ .+ GET \/ .+ IP: \d{1,3}\.\d{1,3}\.\d{1,3}\.\d{1,3}$/
48
- )
49
- })
50
- })
51
-
52
- it("Logs 'null' for GET '/' requests when X-Forwarded-For header is not present", async () => {
53
- logs.forEach(log => {
54
- expect(log).toMatch(/^🦊 .+ INFO .+ .+ GET \/ .+ IP: null$/)
55
- })
56
- })
57
- })
58
-
59
- describe('Logixlysia with IP logging disabled', () => {
60
- let server: Elysia
61
- let app: ReturnType<typeof edenTreaty> | any
62
- let logs: string[] = []
63
-
64
- beforeAll(() => {
65
- server = new Elysia()
66
- .use(
67
- logixlysia({
68
- config: {
69
- ip: false,
70
- customLogFormat:
71
- '🦊 {now} {duration} {level} {method} {pathname} {status} {message} {ip}'
72
- }
73
- })
74
- )
75
- .get('/', () => '🦊 Logixlysia Getting')
76
- .post('logixlysia', () => '🦊 Logixlysia Posting')
77
- .listen(3000)
78
-
79
- app = edenTreaty<typeof server>('http://127.0.0.1:3000')
80
- })
81
-
82
- beforeEach(() => {
83
- logs = []
84
- })
85
-
86
- it("Responds correctly to GET '/' requests", async () => {
87
- const requestCount = 5
88
-
89
- for (let i = 0; i < requestCount; i++) {
90
- logs.push((await app.get('/')).data)
91
- }
92
-
93
- logs.forEach(log => {
94
- expect(log).toBe('🦊 Logixlysia Getting')
95
- })
96
- })
97
-
98
- it("Responds correctly to POST '/logixlysia' requests", async () => {
99
- const requestCount = 5
100
-
101
- for (let i = 0; i < requestCount; i++) {
102
- const postResponse = await app.logixlysia.post({})
103
- logs.push(
104
- postResponse.status === 200 ? postResponse.data : postResponse.error
105
- )
106
- }
107
-
108
- logs.forEach(log => {
109
- expect(log).toBe('🦊 Logixlysia Posting')
110
- })
111
- })
112
-
113
- it('Throws an error when attempting to post to an undefined route', async () => {
114
- const response = await app.undefinedRoute.post({})
115
- const error = response.error
116
-
117
- expect(response.status).toBe(404)
118
- expect(error).toBeInstanceOf(Error)
119
- })
120
- })
121
-
122
- describe('Logixlysia with log filtering enabled', () => {
123
- let server: Elysia
124
- let app: ReturnType<typeof edenTreaty> | any
125
- let logs: string[] = []
126
-
127
- beforeAll(() => {
128
- server = new Elysia()
129
- .use(
130
- logixlysia({
131
- config: {
132
- logFilter: {
133
- level: 'INFO',
134
- status: [200, 404],
135
- method: 'GET'
136
- }
137
- }
138
- })
139
- )
140
- .get('/', () => '🦊 Logixlysia Getting')
141
- .post('logixlysia', () => '🦊 Logixlysia Posting')
142
- .listen(3000)
143
-
144
- app = edenTreaty<typeof server>('http://127.0.0.1:3000')
145
- })
146
-
147
- beforeEach(() => {
148
- logs = []
149
- })
150
-
151
- it("Logs 'GET' requests with status 200 or 404 when log filtering criteria are met", async () => {
152
- const requestCount = 5
153
-
154
- for (let i = 0; i < requestCount; i++) {
155
- logs.push((await app.get('/')).data)
156
- }
157
-
158
- expect(logs.length).toBe(requestCount)
159
- logs.forEach(log => {
160
- expect(log).toMatch('🦊 Logixlysia Getting')
161
- })
162
- })
163
-
164
- it("Doesn't log 'POST' requests when log filtering criteria are not met", async () => {
165
- const requestCount = 5
166
-
167
- for (let i = 0; i < requestCount; i++) {
168
- await app.post('/logixlysia', {})
169
- }
170
-
171
- expect(logs.length).toBe(0)
172
- })
173
-
174
- const otherMethods = ['PUT', 'DELETE', 'PATCH', 'HEAD'] // OPTIONS is failed (IDK why)
175
- otherMethods.forEach(async method => {
176
- it(`Logs '${method}' requests with status 200 or 404 when log filtering criteria are met`, async () => {
177
- const requestCount = 5
178
-
179
- for (let i = 0; i < requestCount; i++) {
180
- logs.push((await app[method.toLowerCase()]('/')).data)
181
- }
182
-
183
- expect(logs.length).toBe(requestCount)
184
- })
185
- })
186
- })
187
-
188
- describe('Logixlysia with log filtering disabled', () => {
189
- let server: Elysia
190
- let app: ReturnType<typeof edenTreaty> | any
191
- let logs: string[] = []
192
-
193
- beforeAll(() => {
194
- server = new Elysia()
195
- .use(
196
- logixlysia({
197
- config: {
198
- logFilter: null
199
- }
200
- })
201
- )
202
- .get('/', () => '🦊 Logixlysia Getting')
203
- .post('logixlysia', () => '🦊 Logixlysia Posting')
204
- .listen(3000)
205
-
206
- app = edenTreaty<typeof server>('http://127.0.0.1:3000')
207
- })
208
-
209
- beforeEach(() => {
210
- logs = []
211
- })
212
-
213
- it('Logs all requests when log filtering is disabled', async () => {
214
- const requestCount = 5
215
-
216
- for (let i = 0; i < requestCount; i++) {
217
- logs.push((await app.get('/')).data)
218
- logs.push((await app.post('/logixlysia', {})).data)
219
- }
220
-
221
- expect(logs.length).toBe(requestCount * 2)
222
- })
223
- })
@@ -1,25 +0,0 @@
1
- import { describe, expect, it } from 'bun:test'
2
-
3
- import { ColorMap } from '~/types'
4
-
5
- describe('Color Mapping Interface', () => {
6
- it('Defines an object with string keys mapping to functions', () => {
7
- const colorMap: ColorMap = {
8
- red: (str: string) => `Red: ${str}`,
9
- green: (str: string) => `Green: ${str}`,
10
- blue: (str: string) => `Blue: ${str}`
11
- }
12
-
13
- expect(colorMap).toEqual(
14
- expect.objectContaining({
15
- red: expect.any(Function),
16
- green: expect.any(Function),
17
- blue: expect.any(Function)
18
- })
19
- )
20
-
21
- Object.keys(colorMap).forEach(key => {
22
- expect(typeof colorMap[key]).toBe('function')
23
- })
24
- })
25
- })
@@ -1,16 +0,0 @@
1
- import { describe, expect, it } from 'bun:test'
2
-
3
- import { HttpError } from '~/types'
4
-
5
- describe('HttpError', () => {
6
- it('Should create an instance with correct status and message', () => {
7
- const status = 404
8
- const message = 'Not Found'
9
- const error = new HttpError(status, message)
10
-
11
- expect(error).toBeInstanceOf(Error)
12
- expect(error).toBeInstanceOf(HttpError)
13
- expect(error.status).toBe(status)
14
- expect(error.message).toBe(message)
15
- })
16
- })
@@ -1,91 +0,0 @@
1
- import { beforeEach, describe, expect, it, jest } from 'bun:test'
2
-
3
- import { LogData, RequestInfo, StoreData } from '~/types'
4
-
5
- interface Logger {
6
- info(request: RequestInfo, data: LogData, store: StoreData): void
7
- warning(request: RequestInfo, data: LogData, store: StoreData): void
8
- error(request: RequestInfo, data: LogData, store: StoreData): void
9
- }
10
-
11
- describe('Logger interface', () => {
12
- let logger: Logger
13
-
14
- beforeEach(() => {
15
- logger = {
16
- info: jest.fn(),
17
- warning: jest.fn(),
18
- error: jest.fn()
19
- }
20
- })
21
-
22
- it('Defines the Logger interface correctly', () => {
23
- expect(logger).toEqual(
24
- expect.objectContaining({
25
- info: expect.any(Function),
26
- warning: expect.any(Function),
27
- error: expect.any(Function)
28
- })
29
- )
30
- })
31
-
32
- it('Calls the info log function with the correct arguments', () => {
33
- const request: RequestInfo = {
34
- url: '/info',
35
- method: 'GET',
36
- headers: {
37
- get: function () {
38
- throw new Error('Function not implemented.')
39
- }
40
- }
41
- }
42
- const data: LogData = { status: 200, message: 'Info log message' }
43
- const store: StoreData = {
44
- beforeTime: 0n
45
- }
46
-
47
- logger.info(request, data, store)
48
-
49
- expect(logger.info).toHaveBeenCalledWith(request, data, store)
50
- })
51
-
52
- it('Calls the warning log function with the correct arguments', () => {
53
- const request: RequestInfo = {
54
- url: '/warning',
55
- method: 'POST',
56
- headers: {
57
- get: function () {
58
- throw new Error('Function not implemented.')
59
- }
60
- }
61
- }
62
- const data: LogData = { status: 404, message: 'Warning log message' }
63
- const store: StoreData = {
64
- beforeTime: 0n
65
- }
66
-
67
- logger.warning(request, data, store)
68
-
69
- expect(logger.warning).toHaveBeenCalledWith(request, data, store)
70
- })
71
-
72
- it('Calls the error log function with the correct arguments', () => {
73
- const request: RequestInfo = {
74
- url: '/error',
75
- method: 'DELETE',
76
- headers: {
77
- get: function () {
78
- throw new Error('Function not implemented.')
79
- }
80
- }
81
- }
82
- const data: LogData = { status: 500, message: 'Error log message' }
83
- const store: StoreData = {
84
- beforeTime: 0n
85
- }
86
-
87
- logger.error(request, data, store)
88
-
89
- expect(logger.error).toHaveBeenCalledWith(request, data, store)
90
- })
91
- })
@@ -1,23 +0,0 @@
1
- import { describe, expect, it } from 'bun:test'
2
-
3
- import { RequestInfo } from '~/types'
4
-
5
- describe('Request Infomation interface', () => {
6
- it('Defines the RequestInfo interface correctly', () => {
7
- const headers = { get: () => 'value' }
8
- const method = 'GET'
9
- const url = 'https://example.com/api'
10
-
11
- const request: RequestInfo = { headers, method, url }
12
-
13
- expect(request).toEqual(
14
- expect.objectContaining({
15
- headers: expect.objectContaining({
16
- get: expect.any(Function)
17
- }),
18
- method: expect.any(String),
19
- url: expect.any(String)
20
- })
21
- )
22
- })
23
- })
@@ -1,27 +0,0 @@
1
- import { describe, expect, it } from 'bun:test'
2
-
3
- import { Server } from '~/types'
4
-
5
- describe('Server interface', () => {
6
- it('Defines the Server interface correctly', () => {
7
- const server: Server = {
8
- hostname: 'example.com',
9
- port: 8080,
10
- protocol: 'https'
11
- }
12
-
13
- expect(server).toEqual(
14
- expect.objectContaining({
15
- hostname: expect.any(String),
16
- port: expect.any(Number),
17
- protocol: expect.any(String)
18
- })
19
- )
20
- })
21
-
22
- it('Allows optional properties in the Server interface', () => {
23
- const serverWithoutOptionalProps: Server = {}
24
-
25
- expect(serverWithoutOptionalProps).toEqual(expect.objectContaining({}))
26
- })
27
- })
@@ -1,17 +0,0 @@
1
- import { describe, expect, it } from 'bun:test'
2
-
3
- import { StoreData } from '~/types'
4
-
5
- describe('Store Data interface', () => {
6
- it('Defines the StoreData interface correctly', () => {
7
- const beforeTime: bigint = BigInt(1633393533526) // Example bigint value
8
-
9
- const storeData: StoreData = { beforeTime }
10
-
11
- expect(storeData).toEqual(
12
- expect.objectContaining({
13
- beforeTime: expect.any(BigInt)
14
- })
15
- )
16
- })
17
- })
@@ -1,37 +0,0 @@
1
- import { describe, expect, it } from 'bun:test'
2
-
3
- import durationString from '~/utils/duration'
4
-
5
- describe('Duration String', () => {
6
- const testCases = [
7
- [
8
- 'Generates a string representing the duration in Seconds (s) unit',
9
- 1e9,
10
- 's'
11
- ],
12
- [
13
- 'Generates a string representing the duration in Milliseconds (ms) unit',
14
- 1e6,
15
- 'ms'
16
- ],
17
- [
18
- 'Generates a string representing the duration in Microseconds (µs) unit',
19
- 1e3,
20
- 'µs'
21
- ]
22
- // [
23
- // 'Generates a string representing the duration in Nanoseconds (ns) unit',
24
- // 1,
25
- // 'ns'
26
- // ]
27
- ]
28
-
29
- for (const [description, nanoseconds, unit] of testCases) {
30
- it(`${description}`, () => {
31
- const beforeTime = process.hrtime.bigint() - BigInt(String(nanoseconds))
32
- const result = durationString(beforeTime)
33
-
34
- expect(result).toMatch(String(unit))
35
- })
36
- }
37
- })
@@ -1,26 +0,0 @@
1
- import { describe, expect, it } from 'bun:test'
2
- import chalk from 'chalk'
3
-
4
- import logString from '~/utils/log'
5
-
6
- describe('Log String', () => {
7
- it('Produces a green background string for INFO log level', () => {
8
- const result = logString('INFO')
9
- expect(result).toBe(chalk.bgGreen.black('INFO '))
10
- })
11
-
12
- it('Produces a yellow background string for WARNING log leve', () => {
13
- const result = logString('WARNING')
14
- expect(result).toBe(chalk.bgYellow.black('WARNING'))
15
- })
16
-
17
- it('Produces a red background string for ERROR log level', () => {
18
- const result = logString('ERROR')
19
- expect(result).toBe(chalk.bgRed.black('ERROR '))
20
- })
21
-
22
- it('Returns the unmodified input string for unrecognized log levels', () => {
23
- const result = logString('DEBUG') // Assuming 'DEBUG' is not in the colorMap
24
- expect(result).toBe('DEBUG') // No coloring, returns the original string
25
- })
26
- })
@@ -1,21 +0,0 @@
1
- import { describe, expect, it } from 'bun:test'
2
- import chalk from 'chalk'
3
-
4
- import methodString from '~/utils/method'
5
-
6
- describe('Method String', () => {
7
- it('Displays a colored string for the GET method', () => {
8
- const result = methodString('GET')
9
- expect(result).toBe(chalk.green('GET '))
10
- })
11
-
12
- it('Displays a colored string for the POST method', () => {
13
- const result = methodString('POST')
14
- expect(result).toBe(chalk.yellow('POST '))
15
- })
16
-
17
- it('Outputs the original method string if it is not recognized', () => {
18
- const result = methodString('INVALID_METHOD')
19
- expect(result).toBe('INVALID_METHOD') // No coloring, returns the original string
20
- })
21
- })
@@ -1,36 +0,0 @@
1
- import { describe, expect, it } from 'bun:test'
2
-
3
- import { RequestInfo } from '~/types'
4
- import pathString from '~/utils/path'
5
-
6
- describe('Path String', () => {
7
- it('Extracts the pathname from a valid URL', () => {
8
- const testPath: RequestInfo = {
9
- url: 'https://www.example.com/path/to/resource',
10
- headers: new Map(),
11
- method: 'GET'
12
- }
13
- const result = pathString(testPath)
14
- expect(result).toBe('/path/to/resource')
15
- })
16
-
17
- it('Handles malformed URL gracefully', () => {
18
- const testPath: RequestInfo = {
19
- url: 'invalid url',
20
- headers: new Map(),
21
- method: 'GET'
22
- }
23
- const result = pathString(testPath)
24
- expect(result).toBeUndefined()
25
- })
26
-
27
- it('Returns undefined if the URL is missing', () => {
28
- const testPath: RequestInfo = {
29
- url: '',
30
- headers: new Map(),
31
- method: 'GET'
32
- }
33
- const result = pathString(testPath)
34
- expect(result).toBeUndefined()
35
- })
36
- })
@@ -1,38 +0,0 @@
1
- import { afterEach, beforeEach, describe, expect, it, jest } from 'bun:test'
2
-
3
- import { Server } from '~/types'
4
- import startServer from '~/utils/start'
5
-
6
- describe('Start String', () => {
7
- let originalConsoleLog: typeof console.log
8
- let mockConsoleLog: jest.Mock
9
-
10
- beforeEach(() => {
11
- originalConsoleLog = console.log
12
- mockConsoleLog = jest.fn()
13
- console.log = mockConsoleLog
14
- })
15
-
16
- afterEach(() => {
17
- console.log = originalConsoleLog
18
- })
19
-
20
- it('Correctly logs the expected message upon server start', () => {
21
- const config: Server = {
22
- hostname: 'localhost',
23
- port: 3000,
24
- protocol: 'http'
25
- }
26
-
27
- startServer(config)
28
-
29
- const expectedMessage = `🦊 Elysia is running at http://localhost:3000`
30
-
31
- // Extract the arguments passed to console.log during the function call
32
- const logMessage = mockConsoleLog.mock.calls
33
- .map(args => args.join(' '))
34
- .join(' ')
35
-
36
- expect(logMessage).toMatch(expectedMessage)
37
- })
38
- })
@@ -1,31 +0,0 @@
1
- import { describe, expect, it } from 'bun:test'
2
- import chalk from 'chalk'
3
-
4
- import statusString from '~/utils/status'
5
-
6
- describe('Status String', () => {
7
- it('Presents the status string in green for a 200 status code', () => {
8
- const result = statusString(200)
9
- expect(result).toBe(chalk.green('200'))
10
- })
11
-
12
- it('Presents the status string in cyan for a 301 status code', () => {
13
- const result = statusString(301)
14
- expect(result).toBe(chalk.cyan('301'))
15
- })
16
-
17
- it('Presents the status string in yellow for a 404 status code', () => {
18
- const result = statusString(404)
19
- expect(result).toBe(chalk.yellow('404'))
20
- })
21
-
22
- it('Presents the status string in red for a 500 status code', () => {
23
- const result = statusString(500)
24
- expect(result).toBe(chalk.red('500'))
25
- })
26
-
27
- it('Presents the status string in white for a 100 status code', () => {
28
- const result = statusString(100)
29
- expect(result).toBe(chalk.white('100'))
30
- })
31
- })