├── preview ├── .gitignore ├── bun.lockb ├── package.json └── src │ └── index.ts ├── bun.lockb ├── screenshots ├── common.png ├── fancy.png └── commontz.png ├── .prettierrc ├── src ├── presets │ ├── index.ts │ ├── commontz.ts │ ├── common.ts │ └── fancy.ts ├── types.ts ├── utils.ts └── index.ts ├── .github ├── workflows │ ├── create-release.yml │ └── publish-npm.yml └── ISSUE_TEMPLATE │ ├── 1-bug.yml │ └── 2-preset.yml ├── CONTRIBUTING.md ├── LICENSE ├── package.json ├── README.md ├── test └── logestic.test.ts ├── .gitignore ├── CHANGELOG.md ├── CODE_OF_CONDUCT.md └── tsconfig.json /preview/.gitignore: -------------------------------------------------------------------------------- 1 | *.log -------------------------------------------------------------------------------- /bun.lockb: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/cybercoder-naj/logestic/HEAD/bun.lockb -------------------------------------------------------------------------------- /preview/bun.lockb: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/cybercoder-naj/logestic/HEAD/preview/bun.lockb -------------------------------------------------------------------------------- /screenshots/common.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/cybercoder-naj/logestic/HEAD/screenshots/common.png -------------------------------------------------------------------------------- /screenshots/fancy.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/cybercoder-naj/logestic/HEAD/screenshots/fancy.png -------------------------------------------------------------------------------- /screenshots/commontz.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/cybercoder-naj/logestic/HEAD/screenshots/commontz.png -------------------------------------------------------------------------------- /.prettierrc: -------------------------------------------------------------------------------- 1 | { 2 | "semi": true, 3 | "trailingComma": "none", 4 | "singleQuote": true, 5 | "printWidth": 80, 6 | "tabWidth": 2, 7 | "useTabs": false, 8 | "bracketSpacing": true, 9 | "arrowParens": "avoid", 10 | "parser": "typescript" 11 | } -------------------------------------------------------------------------------- /src/presets/index.ts: -------------------------------------------------------------------------------- 1 | import { Preset } from '../types'; 2 | import common from './common'; 3 | import fancy from './fancy'; 4 | import commontz from './commontz'; 5 | 6 | export const getPreset = (preset: Preset) => { 7 | switch (preset) { 8 | case 'common': 9 | return common; 10 | case 'fancy': 11 | return fancy; 12 | case 'commontz': 13 | return commontz; 14 | } 15 | }; 16 | -------------------------------------------------------------------------------- /.github/workflows/create-release.yml: -------------------------------------------------------------------------------- 1 | name: Create a release 2 | 3 | on: 4 | push: 5 | tags: 6 | - 'v*' 7 | 8 | jobs: 9 | create-release: 10 | runs-on: ubuntu-latest 11 | permissions: 12 | contents: write 13 | 14 | steps: 15 | - uses: actions/checkout@v2 16 | 17 | - name: Create a release 18 | uses: ncipollo/release-action@v1 19 | with: 20 | generateReleaseNotes: true -------------------------------------------------------------------------------- /preview/package.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "@logestic/preview", 3 | "version": "0.0.1", 4 | "description": "", 5 | "main": "src/index.ts", 6 | "scripts": { 7 | "dev": "bun --watch run src/index.ts" 8 | }, 9 | "repository": { 10 | "type": "git", 11 | "url": "git+https://github.com/cybercoder-naj/logestic.git" 12 | }, 13 | "author": "Nishant Aanjaney Jalan", 14 | "license": "MIT", 15 | "bugs": { 16 | "url": "https://github.com/cybercoder-naj/logestic/issues" 17 | }, 18 | "homepage": "https://github.com/cybercoder-naj/logestic#readme", 19 | "dependencies": { 20 | "elysia": "^1.1.3", 21 | "logestic": "file:.." 22 | } 23 | } 24 | -------------------------------------------------------------------------------- /preview/src/index.ts: -------------------------------------------------------------------------------- 1 | import { Elysia } from 'elysia'; 2 | import { Logestic } from 'logestic'; 3 | 4 | const app = new Elysia() 5 | .use(Logestic.preset('fancy')) 6 | .get('/', () => 'Hello, world!') 7 | .get('/hello/:name', ({ params: { name } }) => `Hello, ${name}!`) 8 | .get('/returnBad', ({ set, logestic }) => { 9 | set.status = 402; 10 | logestic.debug("Something isn't quite right"); 11 | return 'Bad'; 12 | }) 13 | .get('/crashServer', ({ set, logestic }) => { 14 | set.status = 500; 15 | logestic.error('MAYDAY!'); 16 | return 'Server crashed'; 17 | }) 18 | .listen(3000, () => { 19 | console.log('Server is running on port 3000'); 20 | }); 21 | -------------------------------------------------------------------------------- /.github/workflows/publish-npm.yml: -------------------------------------------------------------------------------- 1 | name: Publish package to npmjs 2 | 3 | on: 4 | release: 5 | types: [published] 6 | 7 | jobs: 8 | publish: 9 | runs-on: ubuntu-latest 10 | 11 | steps: 12 | - uses: actions/checkout@v2 13 | 14 | - name: Setup Node.js 15 | uses: actions/setup-node@v1 16 | with: 17 | node-version: 20 18 | registry-url: 'https://registry.npmjs.org' 19 | 20 | - name: Setup Bun 21 | uses: oven-sh/setup-bun@v1 22 | with: 23 | bun-version: latest 24 | registry-url: 'https://registry.npmjs.org' 25 | 26 | - name: Install dependencies 27 | run: bun install --frozen-lockfile --production 28 | 29 | - name: Publish to npm 30 | run: npm publish --provenance --access public 31 | with: 32 | NODE_AUTH_TOKEN: {{ secrets.NPM_TOKEN }} -------------------------------------------------------------------------------- /src/presets/commontz.ts: -------------------------------------------------------------------------------- 1 | import { Logestic } from '..'; 2 | import chalk from 'chalk'; 3 | import { LogesticOptions } from '../types'; 4 | 5 | export default (options: LogesticOptions) => 6 | new Logestic(options).use(['time', 'method', 'path', 'status']).format({ 7 | onSuccess({ time, method, path, status }) { 8 | const grayTime = chalk.gray(`${time!!.toString()}`); 9 | const methodPath = chalk.cyan(`${method} ${path}`); 10 | let statusColor = chalk.white; 11 | 12 | if (200 <= status && status < 300) statusColor = chalk.green; 13 | if (400 <= status && status < 500) statusColor = chalk.yellow; 14 | if (500 <= status) statusColor = chalk.red; 15 | 16 | return `[${grayTime}] ${methodPath} ${statusColor(status)}`; 17 | }, 18 | onFailure({ request, error, code, datetime }) { 19 | const grayTime = chalk.gray(`${datetime.toString()}`); 20 | const msg = chalk.red( 21 | `${request.method} ${request.url} ${error.message} ${code}` 22 | ); 23 | return `[${grayTime}] ${msg}`; 24 | } 25 | }); 26 | -------------------------------------------------------------------------------- /src/presets/common.ts: -------------------------------------------------------------------------------- 1 | import { Logestic } from '..'; 2 | import chalk from 'chalk'; 3 | import { LogesticOptions } from '../types'; 4 | 5 | export default (options: LogesticOptions) => 6 | new Logestic(options).use(['time', 'method', 'path', 'status']).format({ 7 | onSuccess({ time, method, path, status }) { 8 | const grayTime = chalk.gray(`${time!!.toISOString()}`); 9 | const methodPath = chalk.cyan(`${method} ${path}`); 10 | let statusColor = chalk.white; 11 | 12 | if (200 <= status && status < 300) statusColor = chalk.green; 13 | if (400 <= status && status < 500) statusColor = chalk.yellow; 14 | if (500 <= status) statusColor = chalk.red; 15 | 16 | return `[${grayTime}] ${methodPath} ${statusColor(status)}`; 17 | }, 18 | onFailure({ request, error, code, datetime }) { 19 | const grayTime = chalk.gray(`${datetime.toISOString()}`); 20 | const msg = chalk.red( 21 | `${request.method} ${request.url} ${error.message} ${code}` 22 | ); 23 | return `[${grayTime}] ${msg}`; 24 | } 25 | }); 26 | -------------------------------------------------------------------------------- /CONTRIBUTING.md: -------------------------------------------------------------------------------- 1 | # Contributing to Logestic 2 | 3 | ## Reporting Issues 4 | 5 | 😥 Feel free to submit an issue when Logestic is not working as you expected. 6 | 7 | ## Solving Issues 8 | 9 | 1. ❗ All PRs must reference an issue. 10 | 2. 🗣 If there is an issue you want to work on, ask on the issue thread if you want to work on it. 11 | 3. 🍴 Fork this repository and create a new branch `fix-[number]/[short description]` according to the issue. 12 | 4. ✍ Fix the issue. 13 | 6. 🎆 Open a PR and wait until a collaborator merges it in. 14 | 15 | ## Adding Presets 16 | 17 | 1. 🍴 Fork this repository and create a new branch `preset-[name]` with the name of your preset. 18 | 2. ✍ Create a new file under [presets/](./src/presets/) and export an Elysia instance with your Logestic middleware. 19 | 3. ➕ Add the case clause file in [index.ts](./src/presets/index.ts) and the key type to [types](./src/types.ts). 20 | 4. 🖼 Add a preview screenshot in [screenshots](./screenshots/). 21 | 5. 🎆 Open a PR and wait until a collaborator merges it in. Attach a screenshot so we can add to the Wiki. 22 | -------------------------------------------------------------------------------- /LICENSE: -------------------------------------------------------------------------------- 1 | MIT License 2 | 3 | Copyright (c) 2024 Nishant Aanjaney Jalan 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. 22 | -------------------------------------------------------------------------------- /.github/ISSUE_TEMPLATE/1-bug.yml: -------------------------------------------------------------------------------- 1 | name: Bug Report 2 | description: File a bug/issue 3 | labels: ["bug"] 4 | body: 5 | - type: markdown 6 | attributes: 7 | value: | 8 | Thank you for using Logestic. Your contributions help make Logestic better! 9 | 10 | Use the [Wiki](https://github.com/cybercoder-naj/logestic/wiki) to view the full documentation if your issue is regarding how to use Logestic. 11 | 12 | - type: input 13 | attributes: 14 | label: What version of Logestic are you using? 15 | 16 | - type: textarea 17 | attributes: 18 | label: What is the bug and how to reproduce it? 19 | description: Add steps how to re-create this bug and describe it. 20 | validations: 21 | required: false 22 | 23 | - type: textarea 24 | attributes: 25 | label: What is the expected behaviour? 26 | description: A concise description of what you expect to happen. 27 | validations: 28 | required: false 29 | 30 | - type: textarea 31 | attributes: 32 | label: Any additional information/media? 33 | description: Use the same to provide images, code, links, etc. 34 | validations: 35 | required: false 36 | -------------------------------------------------------------------------------- /src/presets/fancy.ts: -------------------------------------------------------------------------------- 1 | import { Logestic } from '..'; 2 | import chalk from 'chalk'; 3 | import { LogesticOptions } from '../types'; 4 | 5 | const getDateTimeString = (date: Date) => { 6 | const year = date.getFullYear(); 7 | const month = date.getMonth() + 1; 8 | const day = date.getDate(); 9 | const hours = date.getHours(); 10 | const minutes = date.getMinutes(); 11 | const seconds = date.getSeconds(); 12 | return `${day}/${month}/${year} ${hours}:${minutes}:${seconds}`; 13 | }; 14 | 15 | const defaultOptions: LogesticOptions = { 16 | showLevel: true 17 | }; 18 | 19 | export default (options: LogesticOptions) => 20 | new Logestic({ 21 | ...defaultOptions, 22 | ...options 23 | }) 24 | .use(['time', 'method', 'path', 'duration']) 25 | .format({ 26 | onSuccess({ time, method, path, duration }) { 27 | const dateTime = chalk.gray(getDateTimeString(time!!)); 28 | const methodPath = chalk.cyan(`${method} ${path}`); 29 | 30 | return `${dateTime} ${methodPath} ${duration}μs`; 31 | }, 32 | onFailure({ request, datetime }) { 33 | const dateTime = getDateTimeString(datetime!!); 34 | return chalk.red(`${dateTime} ${request.method} ${request.url}`); 35 | } 36 | }); 37 | -------------------------------------------------------------------------------- /package.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "logestic", 3 | "version": "1.2.4", 4 | "author": "Nishant Aanjaney Jalan ", 5 | "description": "An advanced and customisable logging library for ElysiaJS", 6 | "keywords": [ 7 | "logging", 8 | "logger", 9 | "elysia", 10 | "elysiajs", 11 | "middleware" 12 | ], 13 | "homepage": "https://github.com/cybercoder-naj/logestic.git", 14 | "bugs": "https://github.com/cybercoder-naj/logestic/issues", 15 | "license": "MIT", 16 | "repository": { 17 | "type": "git", 18 | "url": "git+https://github.com/cybercoder-naj/logestic.git" 19 | }, 20 | "files": [ 21 | "dist" 22 | ], 23 | "main": "dist/index.js", 24 | "module": "src/index.ts", 25 | "type": "module", 26 | "scripts": { 27 | "build": "rimraf dist && bun build src/index.ts --outdir dist --target bun --minify-syntax --minify-whitespace -e elysia && tsc", 28 | "test": "bun test", 29 | "preview": "bun run --cwd preview dev", 30 | "prepublishOnly": "bun run build && { echo '/*'; cat LICENSE; echo '*/'; cat dist/index.js; } > /tmp/index.js && mv /tmp/index.js dist/index.js" 31 | }, 32 | "peerDependencies": { 33 | "typescript": "^5.0.0", 34 | "elysia": "^1.1.3" 35 | }, 36 | "devDependencies": { 37 | "@elysiajs/eden": "1.0.7", 38 | "bun-types": "latest", 39 | "elysia": "^1.1.3", 40 | "rimraf": "^5.0.5", 41 | "typescript": "^5.4.3" 42 | }, 43 | "publishConfig": { 44 | "access": "public" 45 | }, 46 | "dependencies": { 47 | "chalk": "^5.3.0" 48 | } 49 | } 50 | -------------------------------------------------------------------------------- /.github/ISSUE_TEMPLATE/2-preset.yml: -------------------------------------------------------------------------------- 1 | name: Submit a Preset 2 | description: Submit a preset 3 | labels: ["new preset"] 4 | body: 5 | - type: markdown 6 | attributes: 7 | value: | 8 | Thank you for using Logestic. Your contributions help make Logestic better! 9 | 10 | - type: checkboxes 11 | attributes: 12 | label: Have you read the Contributing Guidelines? 13 | description: Please read the Contributing Guidelines to submit a valid preset. 14 | options: 15 | - label: I have read the contributing guidelines. 16 | required: true 17 | 18 | - type: checkboxes 19 | attributes: 20 | label: Are you submitting your own work? 21 | description: Make sure you are not submitting someone else's work. 22 | options: 23 | - label: I confirm that the preset I am submitting is my work. 24 | required: true 25 | 26 | - type: input 27 | attributes: 28 | label: What is the name of the preset? 29 | description: Give your preset a unique name! 30 | 31 | - type: checkboxes 32 | attributes: 33 | label: Verify if you have done the following. 34 | options: 35 | - label: Added your preset name to `Preset` type in `src/types.ts`. 36 | required: true 37 | - label: Created a file in `src/presets` that exports an `Elysia` logger instance as default. 38 | required: true 39 | - label: Added the case clause in `src/presets/index.ts`. 40 | required: true 41 | - label: Added a preview image in `screenshots/`. 42 | required: true 43 | 44 | - type: textarea 45 | attributes: 46 | label: Paste a preview image of your preset. 47 | validations: 48 | required: false 49 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | # Logestic 2 | 3 | [![npm version](https://badge.fury.io/js/logestic.svg)](https://badge.fury.io/js/logestic) 4 | 5 | [Demo](./preview/src/index.ts) • [Documentation](https://github.com/cybercoder-naj/logestic/wiki) • [Changelog](./CHANGELOG.md) • [License](./LICENSE) 6 | 7 | An advanced and customisable logging library for [ElysiaJS](https://elysiajs.com). 8 | 9 |
10 | fancy preset 11 |
= v1.2.2 | v1.1.3 | ✅ | 35 | 36 | ## Usage 37 | 38 | There are two ways to add logging to your Elysia application. The quickest way to use this logger is using a preset. 39 | 40 | ```typescript 41 | import { Elysia } from 'elysia'; 42 | import { Logestic } from 'logestic'; 43 | 44 | const app = new Elysia() 45 | .use(Logestic.preset('common')) 46 | .get('/', () => "Hello from server") 47 | /* ... */ 48 | .listen(3000, () => { 49 | console.log("Server is running on port 3000") 50 | }); 51 | ``` 52 | 53 | These [presets](https://github.com/cybercoder-naj/logestic/wiki/Presets) available to use. 54 | 55 | ## Contributing Guidelines 56 | 57 | See [CONTRIBUTING.md](./CONTRIBUTING.md) -------------------------------------------------------------------------------- /test/logestic.test.ts: -------------------------------------------------------------------------------- 1 | import { describe, it, expect, beforeAll, beforeEach } from 'bun:test'; 2 | import { Elysia } from 'elysia'; 3 | import { Logestic } from '../src'; 4 | import { edenTreaty } from '@elysiajs/eden'; 5 | 6 | describe('Logestic', () => { 7 | describe('Custom formatting', () => { 8 | let app: Elysia; 9 | let client: any; 10 | let logs: string[] = []; 11 | 12 | beforeAll(() => { 13 | const logestic = new Logestic(msg => logs.push(msg)) 14 | .use('method') 15 | .use('path') 16 | .use('contentLength'); 17 | 18 | const logger = logestic.custom(({ method, path, contentLength }) => { 19 | return `${method} ${path} ${contentLength}`; 20 | }); 21 | 22 | app = new Elysia() 23 | .use(logger) 24 | .get('/api/:id', () => 'Hello, World!') 25 | .listen(3000); 26 | 27 | client = edenTreaty('http://127.0.0.1:3000'); 28 | }); 29 | 30 | beforeEach(() => (logs = [])); 31 | 32 | it('Custom formatting', async () => { 33 | await client.api['hi'].get(); 34 | 35 | console.log('Custom logs', logs); 36 | expect(logs.length).toBe(1); 37 | expect(logs[0]).toBe('GET /api/hi 0'); 38 | }); 39 | }); 40 | 41 | describe('Preset formatting', () => { 42 | let app: Elysia; 43 | let client: any; 44 | let logs: string[] = []; 45 | 46 | beforeAll(() => { 47 | const logger = Logestic.preset('common', msg => logs.push(msg)); 48 | 49 | app = new Elysia() 50 | .use(logger) 51 | .get('/api/:id', () => 'Hello, World!') 52 | .listen(3000); 53 | 54 | client = edenTreaty('http://127.0.0.1:3000'); 55 | }); 56 | 57 | beforeEach(() => (logs = [])); 58 | 59 | it('Preset formatting', async () => { 60 | await client.api['hi'].get(); 61 | 62 | expect(logs.length).toBe(1); 63 | expect(logs[0]).toBe(' GET /api/hi 200 0'); 64 | }); 65 | }); 66 | }); 67 | -------------------------------------------------------------------------------- /src/types.ts: -------------------------------------------------------------------------------- 1 | /** 2 | * @module types 3 | * @description This module provides types for the Logestic module. 4 | * It includes types for attributes, presets, and options. 5 | * It also includes a type for the format object. 6 | */ 7 | 8 | import { BunFile } from 'bun'; 9 | 10 | export type Attribute = { 11 | ip: string; 12 | method: string; 13 | path: string; 14 | body: any; 15 | query: Record; 16 | time: Date; 17 | contentLength: number; 18 | status: number; 19 | referer: string; 20 | userAgent: string; 21 | duration: bigint; 22 | }; 23 | 24 | export type ErrorAttribute = { 25 | request: Request; 26 | error: Error; 27 | code: any; // either string description or number 28 | datetime: Date; 29 | }; 30 | 31 | /** 32 | * `Presets` is an object that contains preset configurations for the Logestic module. 33 | */ 34 | export type Preset = 'common' | 'fancy' | 'commontz'; 35 | /** 36 | * `Callback` is an object that contains functions to format successful and failed logs. 37 | */ 38 | export type Callback = { 39 | onRequest?: (attr: Request) => string; 40 | onSuccess: (attr: Pick) => string; 41 | onFailure: (attr: ErrorAttribute) => string; 42 | }; 43 | 44 | export type LogType = 'http' | 'info' | 'warn' | 'debug' | 'error'; 45 | export type LogLevelColour = { 46 | [key in LogType]?: string; 47 | }; 48 | 49 | /** 50 | * `LogesticOptions` is an object that contains options for the Logestic module. 51 | * 52 | * @property dest - The logging destination. It cannot be Bun.stdin. Defaults to Bun.stdout. 53 | * @property showLevel - Whether to show the log level. Defaults to `false`. 54 | * @property logLevelColour - The colour of each log level. 55 | * @property httpLogging - Whether to log HTTP requests. Defaults to `true`. 56 | * @property explicitLogging - Whether to log explicit logs. Defaults to `true`. 57 | * @see LogLevelColour 58 | */ 59 | export type LogesticOptions = { 60 | dest?: BunFile; 61 | showLevel?: boolean; 62 | logLevelColour?: LogLevelColour; 63 | httpLogging?: boolean; 64 | explicitLogging?: boolean; 65 | }; 66 | -------------------------------------------------------------------------------- /.gitignore: -------------------------------------------------------------------------------- 1 | # Based on https://raw.githubusercontent.com/github/gitignore/main/Node.gitignore 2 | 3 | # Logs 4 | 5 | logs 6 | _.log 7 | npm-debug.log_ 8 | yarn-debug.log* 9 | yarn-error.log* 10 | lerna-debug.log* 11 | .pnpm-debug.log* 12 | 13 | # Caches 14 | 15 | .cache 16 | 17 | # Diagnostic reports (https://nodejs.org/api/report.html) 18 | 19 | report.[0-9]_.[0-9]_.[0-9]_.[0-9]_.json 20 | 21 | # Runtime data 22 | 23 | pids 24 | _.pid 25 | _.seed 26 | *.pid.lock 27 | 28 | # Directory for instrumented libs generated by jscoverage/JSCover 29 | 30 | lib-cov 31 | 32 | # Coverage directory used by tools like istanbul 33 | 34 | coverage 35 | *.lcov 36 | 37 | # nyc test coverage 38 | 39 | .nyc_output 40 | 41 | # Grunt intermediate storage (https://gruntjs.com/creating-plugins#storing-task-files) 42 | 43 | .grunt 44 | 45 | # Bower dependency directory (https://bower.io/) 46 | 47 | bower_components 48 | 49 | # node-waf configuration 50 | 51 | .lock-wscript 52 | 53 | # Compiled binary addons (https://nodejs.org/api/addons.html) 54 | 55 | build/Release 56 | 57 | # Dependency directories 58 | 59 | node_modules/ 60 | jspm_packages/ 61 | 62 | # Snowpack dependency directory (https://snowpack.dev/) 63 | 64 | web_modules/ 65 | 66 | # TypeScript cache 67 | 68 | *.tsbuildinfo 69 | 70 | # Optional npm cache directory 71 | 72 | .npm 73 | 74 | # Optional eslint cache 75 | 76 | .eslintcache 77 | 78 | # Optional stylelint cache 79 | 80 | .stylelintcache 81 | 82 | # Microbundle cache 83 | 84 | .rpt2_cache/ 85 | .rts2_cache_cjs/ 86 | .rts2_cache_es/ 87 | .rts2_cache_umd/ 88 | 89 | # Optional REPL history 90 | 91 | .node_repl_history 92 | 93 | # Output of 'npm pack' 94 | 95 | *.tgz 96 | 97 | # Yarn Integrity file 98 | 99 | .yarn-integrity 100 | 101 | # dotenv environment variable files 102 | 103 | .env 104 | .env.development.local 105 | .env.test.local 106 | .env.production.local 107 | .env.local 108 | 109 | # parcel-bundler cache (https://parceljs.org/) 110 | 111 | .parcel-cache 112 | 113 | # Next.js build output 114 | 115 | .next 116 | out 117 | 118 | # Nuxt.js build / generate output 119 | 120 | .nuxt 121 | dist 122 | 123 | # Gatsby files 124 | 125 | # Comment in the public line in if your project uses Gatsby and not Next.js 126 | 127 | # https://nextjs.org/blog/next-9-1#public-directory-support 128 | 129 | # public 130 | 131 | # vuepress build output 132 | 133 | .vuepress/dist 134 | 135 | # vuepress v2.x temp and cache directory 136 | 137 | .temp 138 | 139 | # Docusaurus cache and generated files 140 | 141 | .docusaurus 142 | 143 | # Serverless directories 144 | 145 | .serverless/ 146 | 147 | # FuseBox cache 148 | 149 | .fusebox/ 150 | 151 | # DynamoDB Local files 152 | 153 | .dynamodb/ 154 | 155 | # TernJS port file 156 | 157 | .tern-port 158 | 159 | # Stores VSCode versions used for testing VSCode extensions 160 | 161 | .vscode-test 162 | .vscode/ 163 | 164 | # yarn v2 165 | 166 | .yarn/cache 167 | .yarn/unplugged 168 | .yarn/build-state.yml 169 | .yarn/install-state.gz 170 | .pnp.* 171 | 172 | # IntelliJ based IDEs 173 | .idea 174 | 175 | # Finder (MacOS) folder config 176 | .DS_Store 177 | -------------------------------------------------------------------------------- /src/utils.ts: -------------------------------------------------------------------------------- 1 | /** 2 | * @module utils 3 | * @description This module provides utility functions for logging. 4 | * It includes a function to build attributes from the context and requested attributes, 5 | * and a function to colour log types. 6 | */ 7 | 8 | import { StatusMap } from 'elysia'; 9 | import { type Context } from 'elysia'; 10 | import type { Attribute, LogType, LogLevelColour } from './types'; 11 | import chalk, { ChalkInstance } from 'chalk'; 12 | 13 | /** 14 | * @param ctx Elysia context 15 | * @param reqAttrs A map of attributes to be built 16 | * @returns The built attributes 17 | */ 18 | export const buildAttrs = ( 19 | ctx: Context, 20 | reqAttrs: K[], 21 | timeStart: bigint 22 | ): Pick => { 23 | const { request, path, body, query, set } = ctx; 24 | 25 | let attrs: Partial = {}; 26 | for (const key of reqAttrs) { 27 | const k = key as K; 28 | switch (k) { 29 | case 'ip': 30 | attrs.ip = request.headers.get('x-forwarded-for') || ''; 31 | break; 32 | 33 | case 'method': 34 | attrs.method = request.method; 35 | break; 36 | 37 | case 'path': 38 | attrs.path = path; 39 | break; 40 | 41 | case 'body': 42 | attrs.body = body; 43 | break; 44 | 45 | case 'query': 46 | attrs.query = query; 47 | break; 48 | 49 | case 'time': 50 | attrs.time = new Date(); 51 | break; 52 | 53 | case 'contentLength': 54 | attrs.contentLength = Number(request.headers.get('content-length')); 55 | break; 56 | 57 | case 'status': 58 | if (!set.status) break; 59 | 60 | attrs.status = 61 | typeof set.status === 'number' ? set.status : StatusMap[set.status]; 62 | break; 63 | 64 | case 'referer': 65 | attrs.referer = request.headers.get('referer') || ''; 66 | break; 67 | 68 | case 'userAgent': 69 | attrs.userAgent = request.headers.get('user-agent') || ''; 70 | break; 71 | 72 | case 'duration': 73 | const now = process.hrtime.bigint(); 74 | attrs.duration = (now - timeStart) / 1000n; 75 | break; 76 | } 77 | } 78 | 79 | return attrs as Pick; 80 | }; 81 | 82 | /** 83 | * @param type the log type to colour 84 | * @param colourDef a map of log types to colours 85 | * @returns a string with the ANSI colour code wrapped around the log type 86 | */ 87 | export const colourLogType = ( 88 | type: LogType, 89 | colourDef: LogLevelColour 90 | ): string => { 91 | let bgColour: ChalkInstance = chalk.bgBlack; 92 | // If the log type is not in the colour definition, use the default colour 93 | switch (type) { 94 | case 'http': 95 | bgColour = 96 | (colourDef[type] && chalk.hex(colourDef[type]!!)) || chalk.bgBlue; 97 | break; 98 | 99 | case 'info': 100 | bgColour = 101 | (colourDef[type] && chalk.hex(colourDef[type]!!)) || chalk.bgGreen; 102 | break; 103 | 104 | case 'warn': 105 | bgColour = 106 | (colourDef[type] && chalk.hex(colourDef[type]!!)) || chalk.bgYellow; 107 | break; 108 | 109 | case 'debug': 110 | bgColour = 111 | (colourDef[type] && chalk.hex(colourDef[type]!!)) || chalk.bgCyan; 112 | break; 113 | 114 | case 'error': 115 | bgColour = 116 | (colourDef[type] && chalk.hex(colourDef[type]!!)) || chalk.bgRed; 117 | break; 118 | } 119 | 120 | const withSpaces = ` ${type.toUpperCase()} `; 121 | return bgColour?.(withSpaces) ?? withSpaces; 122 | }; 123 | 124 | export function removeAnsi(text: string): string { 125 | return text.replace(/\u001b\[\d*m/g, '').trimStart(); 126 | } 127 | -------------------------------------------------------------------------------- /CHANGELOG.md: -------------------------------------------------------------------------------- 1 | # CHANGELOG 2 | 3 | ## [1.2.4] - 10-10-2024 4 | ### Fixed 5 | - Prevent logging for empty messages ([#38](https://github.com/cybercoder-naj/logestic/pull/38)) 6 | 7 | ## [1.2.3] - 20-07-2024 8 | ### Fixed 9 | - Deploy minified code with a workaround that works. ([#35](https://github.com/cybercoder-naj/logestic/pull/35)) 10 | 11 | ## [1.2.2] - 20-07-2024 12 | ### Fixed 13 | - Deploy non-minified code for Elysia applications to run. ([#34](https://github.com/cybercoder-naj/logestic/pull/34)) 14 | 15 | ## [1.2.1] - 19-07-2024 16 | ### Added 17 | - GitHub Actions to automate the release workflow. ([#29](https://github.com/cybercoder-naj/logestic/pull/29)) 18 | 19 | ### Fixed 20 | - Breaking changes with Elysia v1.1.x releases. ([#32](https://github.com/cybercoder-naj/logestic/pull/32)) 21 | 22 | ## [1.2.0] - 27-05-2024 23 | ### Added 24 | - New preset `commontz`, which is similar to `common` but logs the time in server's timezone. ([#28](https://github.com/cybercoder-naj/logestic/pull/28)) 25 | 26 | ## [1.1.1] - 07-04-2024 27 | ### Fixed 28 | - `onSuccess` receiving undefined values in parameters. 29 | 30 | ## [1.1.0] - 31-03-2024 31 | ### Added 32 | - Optional `onRequest` logging formatter for hooking onto onRequest. ([#13](https://github.com/cybercoder-naj/logestic/issues/13)) 33 | 34 | ## [1.0.1] - 30-03-2024 35 | ### Added 36 | - Type-safety to onSuccess method, based on attributes passed on `use`. ([#6](https://github.com/cybercoder-naj/logestic/issues/6)) 37 | 38 | ### Fixed 39 | - Status of type `number` and not `any`. ([#5](https://github.com/cybercoder-naj/logestic/issues/5)) 40 | 41 | ## [1.0.0] - 27-03-2024 42 | - First stable release! 🎆 43 | 44 | ## [1.0.0-alpha.6] - 27-03-2024 45 | ### Fixed 46 | - Fix issues related to file logging. ([#14](https://github.com/cybercoder-naj/logestic/issues/14)) 47 | 48 | ## [1.0.0-alpha.5] - 26-03-2024 49 | ### Changed 50 | - Request duration returns time in microseconds. 51 | - `fancy` preset includes the duration on successful requests. 52 | 53 | ### Fixed 54 | - Incorrect status code when returning with `error` function ([#11](https://github.com/cybercoder-naj/logestic/issues/11)) 55 | 56 | ## [1.0.0-alpha.4] - 26-03-2024 57 | ### Added 58 | - Request duration as a logging feature ([#10](https://github.com/cybercoder-naj/logestic/issues/10)) 59 | 60 | ## [1.0.0-alpha.3] - 25-03-2024 61 | ### Changed 62 | - README file and updated the Wiki page. 63 | 64 | ### Fixed 65 | - Default configuration for `fancy` preset. 66 | 67 | ## [1.0.0-alpha.2] - 21-03-2024 68 | ### Added 69 | - Customisable log type/level colour. 70 | - Option to disable implicit and explicit logging. 71 | - `build` function to create a logger wihout any `httpLogging`. 72 | 73 | ### Changed 74 | - Passing in options will override preset options. 75 | - Type loss when using Logestic middleware. 76 | 77 | ## [1.0.0-alpha.1] - 21-03-2024 78 | *Redacted. see 1.0.0-alpha.2 for changes* 79 | 80 | ## [0.5.0] - 21-03-2024 81 | ### Added 82 | - Origin/level of the log message, 'HTTP', 'ERROR', 'WARN', 'DEBUG', 'INFO'. 83 | - `info`, `warn`, `debug`, `error` functions are added for custom logging throughout the application. 84 | 85 | ### Changed 86 | - **BREAKING CHANGE**: `Logestic` accepts an options object instead of a destination file. 87 | - **BREAKING CHANGE**: `log` is a private function. Replace all usages of `log` function with `info` function. 88 | - Presets definition returns an `Elysia` instance. 89 | 90 | ## [0.4.0] - 21-03-2024 91 | ### Added 92 | - Custom Error logging when request fails. 93 | 94 | ### Changed 95 | - **BREAKING CHANGE**: Custom logging functionality accepts an object of two functions, `onSuccess` and `onFailure`. 96 | 97 | 98 | ## [0.3.0] - 19-03-2024 99 | ### Added 100 | - New logging preset: `'fancy'` 101 | 102 | ### Changed 103 | - **BREAKING CHANGE**: renamed `custom` function to `format` 104 | 105 | This is the first version to be documented in the changelog. Previous changes are not recorded. 106 | -------------------------------------------------------------------------------- /CODE_OF_CONDUCT.md: -------------------------------------------------------------------------------- 1 | # Contributor Covenant Code of Conduct 2 | 3 | ## Our Pledge 4 | 5 | We as members, contributors, and leaders pledge to make participation in our 6 | community a harassment-free experience for everyone, regardless of age, body 7 | size, visible or invisible disability, ethnicity, sex characteristics, gender 8 | identity and expression, level of experience, education, socio-economic status, 9 | nationality, personal appearance, race, religion, or sexual identity 10 | and orientation. 11 | 12 | We pledge to act and interact in ways that contribute to an open, welcoming, 13 | diverse, inclusive, and healthy community. 14 | 15 | ## Our Standards 16 | 17 | Examples of behavior that contributes to a positive environment for our 18 | community include: 19 | 20 | * Demonstrating empathy and kindness toward other people 21 | * Being respectful of differing opinions, viewpoints, and experiences 22 | * Giving and gracefully accepting constructive feedback 23 | * Accepting responsibility and apologizing to those affected by our mistakes, 24 | and learning from the experience 25 | * Focusing on what is best not just for us as individuals, but for the 26 | overall community 27 | 28 | Examples of unacceptable behavior include: 29 | 30 | * The use of sexualized language or imagery, and sexual attention or 31 | advances of any kind 32 | * Trolling, insulting or derogatory comments, and personal or political attacks 33 | * Public or private harassment 34 | * Publishing others' private information, such as a physical or email 35 | address, without their explicit permission 36 | * Other conduct which could reasonably be considered inappropriate in a 37 | professional setting 38 | 39 | ## Enforcement Responsibilities 40 | 41 | Community leaders are responsible for clarifying and enforcing our standards of 42 | acceptable behavior and will take appropriate and fair corrective action in 43 | response to any behavior that they deem inappropriate, threatening, offensive, 44 | or harmful. 45 | 46 | Community leaders have the right and responsibility to remove, edit, or reject 47 | comments, commits, code, wiki edits, issues, and other contributions that are 48 | not aligned to this Code of Conduct, and will communicate reasons for moderation 49 | decisions when appropriate. 50 | 51 | ## Scope 52 | 53 | This Code of Conduct applies within all community spaces, and also applies when 54 | an individual is officially representing the community in public spaces. 55 | Examples of representing our community include using an official e-mail address, 56 | posting via an official social media account, or acting as an appointed 57 | representative at an online or offline event. 58 | 59 | ## Enforcement 60 | 61 | Instances of abusive, harassing, or otherwise unacceptable behavior may be 62 | reported to the community leaders responsible for enforcement at 63 | cybercoder.nishant@gmail.com. 64 | All complaints will be reviewed and investigated promptly and fairly. 65 | 66 | All community leaders are obligated to respect the privacy and security of the 67 | reporter of any incident. 68 | 69 | ## Enforcement Guidelines 70 | 71 | Community leaders will follow these Community Impact Guidelines in determining 72 | the consequences for any action they deem in violation of this Code of Conduct: 73 | 74 | ### 1. Correction 75 | 76 | **Community Impact**: Use of inappropriate language or other behavior deemed 77 | unprofessional or unwelcome in the community. 78 | 79 | **Consequence**: A private, written warning from community leaders, providing 80 | clarity around the nature of the violation and an explanation of why the 81 | behavior was inappropriate. A public apology may be requested. 82 | 83 | ### 2. Warning 84 | 85 | **Community Impact**: A violation through a single incident or series 86 | of actions. 87 | 88 | **Consequence**: A warning with consequences for continued behavior. No 89 | interaction with the people involved, including unsolicited interaction with 90 | those enforcing the Code of Conduct, for a specified period of time. This 91 | includes avoiding interactions in community spaces as well as external channels 92 | like social media. Violating these terms may lead to a temporary or 93 | permanent ban. 94 | 95 | ### 3. Temporary Ban 96 | 97 | **Community Impact**: A serious violation of community standards, including 98 | sustained inappropriate behavior. 99 | 100 | **Consequence**: A temporary ban from any sort of interaction or public 101 | communication with the community for a specified period of time. No public or 102 | private interaction with the people involved, including unsolicited interaction 103 | with those enforcing the Code of Conduct, is allowed during this period. 104 | Violating these terms may lead to a permanent ban. 105 | 106 | ### 4. Permanent Ban 107 | 108 | **Community Impact**: Demonstrating a pattern of violation of community 109 | standards, including sustained inappropriate behavior, harassment of an 110 | individual, or aggression toward or disparagement of classes of individuals. 111 | 112 | **Consequence**: A permanent ban from any sort of public interaction within 113 | the community. 114 | 115 | ## Attribution 116 | 117 | This Code of Conduct is adapted from the [Contributor Covenant][homepage], 118 | version 2.0, available at 119 | https://www.contributor-covenant.org/version/2/0/code_of_conduct.html. 120 | 121 | Community Impact Guidelines were inspired by [Mozilla's code of conduct 122 | enforcement ladder](https://github.com/mozilla/diversity). 123 | 124 | [homepage]: https://www.contributor-covenant.org 125 | 126 | For answers to common questions about this code of conduct, see the FAQ at 127 | https://www.contributor-covenant.org/faq. Translations are available at 128 | https://www.contributor-covenant.org/translations. 129 | -------------------------------------------------------------------------------- /src/index.ts: -------------------------------------------------------------------------------- 1 | /** 2 | * @module logestic 3 | * @description This module provides a class to configure and perform logging. 4 | */ 5 | 6 | import Elysia from 'elysia'; 7 | import { 8 | Attribute, 9 | Callback, 10 | LogLevelColour, 11 | LogesticOptions, 12 | Preset 13 | } from './types'; 14 | import { BunFile } from 'bun'; 15 | import c from 'chalk'; 16 | import { buildAttrs, colourLogType, removeAnsi } from './utils'; 17 | import { getPreset } from './presets'; 18 | import fs from 'node:fs'; 19 | 20 | export type { Attribute, LogesticOptions }; 21 | export const chalk = c; // Re-export chalk for custom formatting 22 | 23 | /** 24 | * Logestic class provides methods to configure and perform logging. 25 | */ 26 | export class Logestic { 27 | private requestedAttrs: K[]; 28 | private dest!: BunFile; 29 | private showLevel: boolean; 30 | private logLevelColour: LogLevelColour; 31 | private httpLogging: boolean; 32 | private explicitLogging: boolean; 33 | 34 | /** 35 | * Creates a new Logestic instance. 36 | * 37 | * @param options - The options to configure the Logestic instance. 38 | * @see LogesticOptions 39 | */ 40 | constructor(options: LogesticOptions = {}) { 41 | this.requestedAttrs = []; 42 | this.showLevel = options.showLevel || false; 43 | this.logLevelColour = options.logLevelColour || {}; 44 | this.httpLogging = options.httpLogging || true; 45 | this.explicitLogging = options.explicitLogging || true; 46 | 47 | this.setDest(options.dest || Bun.stdout); 48 | } 49 | 50 | private setDest(dest: BunFile): void { 51 | if (dest === Bun.stdin) { 52 | // Cannot log to stdin 53 | throw new Error( 54 | 'Cannot log to stdin. Please provide a writable destination.' 55 | ); 56 | } 57 | if (dest === Bun.stdout || dest === Bun.stderr) { 58 | // Use stdout or stderr 59 | this.dest = dest; 60 | return; 61 | } 62 | 63 | // Custom file destination 64 | this.createFileIfNotExists(dest) 65 | .then(file => (this.dest = file)) 66 | .catch(err => { 67 | throw err; 68 | }); 69 | } 70 | 71 | private async createFileIfNotExists(dest: BunFile): Promise { 72 | if (!(await dest.exists())) { 73 | Bun.write(dest, ''); 74 | } 75 | return dest; 76 | } 77 | 78 | /** 79 | * Requests Logestic to provide a particular attribute. 80 | * @param attrs - An attribute key or an array of attribute keys. 81 | * @returns The Logestic instance for chaining. 82 | */ 83 | use(attr: NK): Logestic; 84 | use(attrs: NK[]): Logestic; 85 | use(attrs: NK | NK[]): Logestic { 86 | if (Array.isArray(attrs)) { 87 | for (const attr of attrs) { 88 | this._use(attr); 89 | } 90 | return this as unknown as Logestic; 91 | } 92 | 93 | // Single attribute 94 | this._use(attrs); 95 | return this as unknown as Logestic; 96 | } 97 | 98 | private _use(attr: K) { 99 | this.requestedAttrs.push(attr); 100 | } 101 | 102 | /** 103 | * @param name The name of the preset to use. 104 | * @param options The options to configure the preset. Any options provided will override the preset's default options. 105 | * @returns A new Elysia instance with the logger plugged in. 106 | */ 107 | static preset(name: Preset, options: LogesticOptions = {}) { 108 | return getPreset(name)(options); 109 | } 110 | 111 | /** 112 | * Use this when you do not want any http logging. 113 | * 114 | * @returns Elysia instance with the logger plugged in. 115 | */ 116 | build(this: Logestic) { 117 | return new Elysia({ 118 | name: 'logestic' 119 | }).decorate('logestic', this); 120 | } 121 | 122 | /** 123 | * Successful requests will not log if httpLogging is disabled. 124 | * Error logs will always be logged regardless. 125 | * 126 | * @param formatAttr - The format object containing functions to format successful and failed logs. 127 | * @returns Elysia instance with the logger plugged in. 128 | */ 129 | format(this: Logestic, formatAttr: Callback) { 130 | return this.build() 131 | .state('logestic_timeStart', 0n) 132 | .onRequest(({ store, request }) => { 133 | store.logestic_timeStart = process.hrtime.bigint(); 134 | 135 | if (formatAttr.onRequest) { 136 | let msg = formatAttr.onRequest(request); 137 | if (this.showLevel) { 138 | msg = `${colourLogType('http', this.logLevelColour)} ${msg}`; 139 | } 140 | this.log(msg); 141 | } 142 | }) 143 | .onAfterResponse({ as: 'global' }, ctx => { 144 | if (!this.httpLogging) { 145 | return; 146 | } 147 | 148 | // get attributes, format and log 149 | const { 150 | store: { logestic_timeStart } 151 | } = ctx; 152 | let attrs = buildAttrs(ctx, this.requestedAttrs, logestic_timeStart); 153 | let msg = formatAttr.onSuccess(attrs); 154 | if (this.showLevel) { 155 | msg = `${colourLogType('http', this.logLevelColour)} ${msg}`; 156 | } 157 | this.log(msg); 158 | }) 159 | .onError({ as: 'global' }, ({ request, error, code }) => { 160 | let datetime = new Date(); 161 | let msg = formatAttr.onFailure({ request, error, code, datetime }); 162 | if (this.showLevel) { 163 | msg = `${colourLogType('error', this.logLevelColour)} ${msg}`; 164 | } 165 | this.log(msg); 166 | }); 167 | } 168 | 169 | private async log(msg: string): Promise { 170 | // ignore empty logs 171 | if (!msg || msg === "") return 172 | 173 | const msgNewLine = `${msg}\n`; 174 | if (!this.dest.name || !this.dest.name.length) { 175 | // This is either stdout or stderr 176 | Bun.write(this.dest, msgNewLine); 177 | return; 178 | } 179 | 180 | const sanitised = removeAnsi(msgNewLine); 181 | fs.appendFile(this.dest.name, sanitised, err => { 182 | if (err) { 183 | throw err; 184 | } 185 | }); 186 | } 187 | 188 | /** 189 | * Logs an info message to the destination. 190 | * 191 | * @param msg The message to log. 192 | */ 193 | info(msg: string): void { 194 | if (!this.explicitLogging) { 195 | return; 196 | } 197 | 198 | let _msg = msg; 199 | if (this.showLevel) { 200 | _msg = `${colourLogType('info', this.logLevelColour)} ${msg}`; 201 | } 202 | this.log(_msg); 203 | } 204 | 205 | /** 206 | * Logs a warning message to the destination. 207 | * 208 | * @param msg The message to log. 209 | */ 210 | warn(msg: string): void { 211 | if (!this.explicitLogging) { 212 | return; 213 | } 214 | 215 | let _msg = msg; 216 | if (this.showLevel) { 217 | _msg = `${colourLogType('warn', this.logLevelColour)} ${msg}`; 218 | } 219 | this.log(_msg); 220 | } 221 | 222 | /** 223 | * Logs a debug message to the destination. 224 | * 225 | * @param msg The message to log. 226 | */ 227 | debug(msg: string): void { 228 | if (!this.explicitLogging) { 229 | return; 230 | } 231 | 232 | let _msg = msg; 233 | if (this.showLevel) { 234 | _msg = `${colourLogType('debug', this.logLevelColour)} ${msg}`; 235 | } 236 | this.log(_msg); 237 | } 238 | 239 | /** 240 | * Logs an error message to the destination. 241 | * 242 | * @param msg The message to log. 243 | */ 244 | error(msg: string): void { 245 | if (!this.explicitLogging) { 246 | return; 247 | } 248 | 249 | let _msg = msg; 250 | if (this.showLevel) { 251 | _msg = `${colourLogType('error', this.logLevelColour)} ${msg}`; 252 | } 253 | this.log(_msg); 254 | } 255 | } 256 | -------------------------------------------------------------------------------- /tsconfig.json: -------------------------------------------------------------------------------- 1 | { 2 | "compilerOptions": { 3 | /* Visit https://aka.ms/tsconfig to read more about this file */ 4 | 5 | /* Projects */ 6 | // "incremental": true, /* Save .tsbuildinfo files to allow for incremental compilation of projects. */ 7 | // "composite": true, /* Enable constraints that allow a TypeScript project to be used with project references. */ 8 | // "tsBuildInfoFile": "./.tsbuildinfo", /* Specify the path to .tsbuildinfo incremental compilation file. */ 9 | // "disableSourceOfProjectReferenceRedirect": true, /* Disable preferring source files instead of declaration files when referencing composite projects. */ 10 | // "disableSolutionSearching": true, /* Opt a project out of multi-project reference checking when editing. */ 11 | // "disableReferencedProjectLoad": true, /* Reduce the number of projects loaded automatically by TypeScript. */ 12 | 13 | /* Language and Environment */ 14 | "target": "ES2021", /* Set the JavaScript language version for emitted JavaScript and include compatible library declarations. */ 15 | // "lib": [], /* Specify a set of bundled library declaration files that describe the target runtime environment. */ 16 | // "jsx": "preserve", /* Specify what JSX code is generated. */ 17 | // "experimentalDecorators": true, /* Enable experimental support for TC39 stage 2 draft decorators. */ 18 | // "emitDecoratorMetadata": true, /* Emit design-type metadata for decorated declarations in source files. */ 19 | // "jsxFactory": "", /* Specify the JSX factory function used when targeting React JSX emit, e.g. 'React.createElement' or 'h'. */ 20 | // "jsxFragmentFactory": "", /* Specify the JSX Fragment reference used for fragments when targeting React JSX emit e.g. 'React.Fragment' or 'Fragment'. */ 21 | // "jsxImportSource": "", /* Specify module specifier used to import the JSX factory functions when using 'jsx: react-jsx*'. */ 22 | // "reactNamespace": "", /* Specify the object invoked for 'createElement'. This only applies when targeting 'react' JSX emit. */ 23 | // "noLib": true, /* Disable including any library files, including the default lib.d.ts. */ 24 | // "useDefineForClassFields": true, /* Emit ECMAScript-standard-compliant class fields. */ 25 | // "moduleDetection": "auto", /* Control what method is used to detect module-format JS files. */ 26 | 27 | /* Modules */ 28 | "module": "ES2022", /* Specify what module code is generated. */ 29 | // "rootDir": "./", /* Specify the root folder within your source files. */ 30 | "moduleResolution": "node", /* Specify how TypeScript looks up a file from a given module specifier. */ 31 | // "baseUrl": "./", /* Specify the base directory to resolve non-relative module names. */ 32 | // "paths": {}, /* Specify a set of entries that re-map imports to additional lookup locations. */ 33 | // "rootDirs": [], /* Allow multiple folders to be treated as one when resolving modules. */ 34 | // "typeRoots": [], /* Specify multiple folders that act like './node_modules/@types'. */ 35 | "types": ["bun-types"], /* Specify type package names to be included without being referenced in a source file. */ 36 | // "allowUmdGlobalAccess": true, /* Allow accessing UMD globals from modules. */ 37 | // "moduleSuffixes": [], /* List of file name suffixes to search when resolving a module. */ 38 | // "resolveJsonModule": true, /* Enable importing .json files. */ 39 | // "noResolve": true, /* Disallow 'import's, 'require's or ''s from expanding the number of files TypeScript should add to a project. */ 40 | 41 | /* JavaScript Support */ 42 | // "allowJs": true, /* Allow JavaScript files to be a part of your program. Use the 'checkJS' option to get errors from these files. */ 43 | // "checkJs": true, /* Enable error reporting in type-checked JavaScript files. */ 44 | // "maxNodeModuleJsDepth": 1, /* Specify the maximum folder depth used for checking JavaScript files from 'node_modules'. Only applicable with 'allowJs'. */ 45 | 46 | /* Emit */ 47 | "declaration": true, /* Generate .d.ts files from TypeScript and JavaScript files in your project. */ 48 | // "declarationMap": true, /* Create sourcemaps for d.ts files. */ 49 | "emitDeclarationOnly": true, /* Only output d.ts files and not JavaScript files. */ 50 | // "sourceMap": true, /* Create source map files for emitted JavaScript files. */ 51 | // "outFile": "./", /* Specify a file that bundles all outputs into one JavaScript file. If 'declaration' is true, also designates a file that bundles all .d.ts output. */ 52 | "outDir": "./dist", /* Specify an output folder for all emitted files. */ 53 | // "removeComments": true, /* Disable emitting comments. */ 54 | // "noEmit": true, /* Disable emitting files from a compilation. */ 55 | // "importHelpers": true, /* Allow importing helper functions from tslib once per project, instead of including them per-file. */ 56 | // "importsNotUsedAsValues": "remove", /* Specify emit/checking behavior for imports that are only used for types. */ 57 | // "downlevelIteration": true, /* Emit more compliant, but verbose and less performant JavaScript for iteration. */ 58 | // "sourceRoot": "", /* Specify the root path for debuggers to find the reference source code. */ 59 | // "mapRoot": "", /* Specify the location where debugger should locate map files instead of generated locations. */ 60 | // "inlineSourceMap": true, /* Include sourcemap files inside the emitted JavaScript. */ 61 | // "inlineSources": true, /* Include source code in the sourcemaps inside the emitted JavaScript. */ 62 | // "emitBOM": true, /* Emit a UTF-8 Byte Order Mark (BOM) in the beginning of output files. */ 63 | // "newLine": "crlf", /* Set the newline character for emitting files. */ 64 | // "stripInternal": true, /* Disable emitting declarations that have '@internal' in their JSDoc comments. */ 65 | // "noEmitHelpers": true, /* Disable generating custom helper functions like '__extends' in compiled output. */ 66 | // "noEmitOnError": true, /* Disable emitting files if any type checking errors are reported. */ 67 | // "preserveConstEnums": true, /* Disable erasing 'const enum' declarations in generated code. */ 68 | // "declarationDir": "./", /* Specify the output directory for generated declaration files. */ 69 | // "preserveValueImports": true, /* Preserve unused imported values in the JavaScript output that would otherwise be removed. */ 70 | 71 | /* Interop Constraints */ 72 | // "isolatedModules": true, /* Ensure that each file can be safely transpiled without relying on other imports. */ 73 | // "allowSyntheticDefaultImports": true, /* Allow 'import x from y' when a module doesn't have a default export. */ 74 | "esModuleInterop": true, /* Emit additional JavaScript to ease support for importing CommonJS modules. This enables 'allowSyntheticDefaultImports' for type compatibility. */ 75 | // "preserveSymlinks": true, /* Disable resolving symlinks to their realpath. This correlates to the same flag in node. */ 76 | "forceConsistentCasingInFileNames": true, /* Ensure that casing is correct in imports. */ 77 | 78 | /* Type Checking */ 79 | "strict": true, /* Enable all strict type-checking options. */ 80 | "noImplicitAny": true, /* Enable error reporting for expressions and declarations with an implied 'any' type. */ 81 | // "strictNullChecks": true, /* When type checking, take into account 'null' and 'undefined'. */ 82 | // "strictFunctionTypes": true, /* When assigning functions, check to ensure parameters and the return values are subtype-compatible. */ 83 | // "strictBindCallApply": true, /* Check that the arguments for 'bind', 'call', and 'apply' methods match the original function. */ 84 | // "strictPropertyInitialization": true, /* Check for class properties that are declared but not set in the constructor. */ 85 | // "noImplicitThis": true, /* Enable error reporting when 'this' is given the type 'any'. */ 86 | // "useUnknownInCatchVariables": true, /* Default catch clause variables as 'unknown' instead of 'any'. */ 87 | // "alwaysStrict": true, /* Ensure 'use strict' is always emitted. */ 88 | "noUnusedLocals": false, /* Enable error reporting when local variables aren't read. */ 89 | "noUnusedParameters": false, /* Raise an error when a function parameter isn't read. */ 90 | // "exactOptionalPropertyTypes": true, /* Interpret optional property types as written, rather than adding 'undefined'. */ 91 | // "noImplicitReturns": true, /* Enable error reporting for codepaths that do not explicitly return in a function. */ 92 | // "noFallthroughCasesInSwitch": true, /* Enable error reporting for fallthrough cases in switch statements. */ 93 | // "noUncheckedIndexedAccess": true, /* Add 'undefined' to a type when accessed using an index. */ 94 | // "noImplicitOverride": true, /* Ensure overriding members in derived classes are marked with an override modifier. */ 95 | // "noPropertyAccessFromIndexSignature": true, /* Enforces using indexed accessors for keys declared using an indexed type. */ 96 | // "allowUnusedLabels": true, /* Disable error reporting for unused labels. */ 97 | // "allowUnreachableCode": true, /* Disable error reporting for unreachable code. */ 98 | 99 | /* Completeness */ 100 | // "skipDefaultLibCheck": true, /* Skip type checking .d.ts files that are included with TypeScript. */ 101 | "skipLibCheck": true /* Skip type checking all .d.ts files. */ 102 | }, 103 | "include": ["src/**/*.ts"], 104 | "exclude": ["node_modules", "dist"] 105 | } 106 | --------------------------------------------------------------------------------