@bintvn/lite-env 1.0.0 → 1.0.1

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/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@bintvn/lite-env",
3
- "version": "1.0.0",
3
+ "version": "1.0.1",
4
4
  "description": "TypeScript based environment variable loader.",
5
5
  "keywords": [
6
6
  "util",
@@ -21,6 +21,9 @@
21
21
  "require": "./dist/index.cjs"
22
22
  }
23
23
  },
24
+ "files": [
25
+ "dist"
26
+ ],
24
27
  "scripts": {
25
28
  "build": "tsup src/index.ts --format cjs,esm --dts --clean",
26
29
  "typecheck": "tsc --noEmit --project tsconfig.json",
package/src/helper.ts DELETED
@@ -1,137 +0,0 @@
1
- import { existsSync, readFileSync } from "fs"
2
- import { AllowedEnvKeys, EnvKind, EnvKindMap, LoadedEnv } from "./types.js"
3
-
4
- export function toString(value: string): string {
5
- return String(value)
6
- }
7
-
8
- export function toNumber(value: string): number {
9
- const parsed = Number(value)
10
- if (Number.isNaN(parsed))
11
- throw new Error('Value is not supported for number')
12
-
13
- return parsed
14
- }
15
-
16
- export function toArray(value: string): string[] {
17
- if (!value.includes(','))
18
- throw new Error('Valur is not supported for array')
19
-
20
- return value.split(',')
21
- }
22
-
23
- export function toBoolean(value: string): boolean {
24
- if (value === 'true' || value === '1')
25
- return true
26
-
27
- if (value === 'false' || value === '0')
28
- return false
29
-
30
- throw new Error('Value is not supported for boolean')
31
- }
32
-
33
- export function toObject<T>(value: string): T {
34
- try {
35
- return JSON.parse(value)
36
- } catch (error) {
37
- throw new Error('Value is not supported for object')
38
- }
39
- }
40
-
41
- export function toBuffer(value: string, encoding?: BufferEncoding): Buffer {
42
- try {
43
- return Buffer.from(value, encoding || 'base64')
44
- } catch (error) {
45
- throw new Error('Value is not supported for buffer')
46
- }
47
- }
48
-
49
- export function toDate(value: string): Date {
50
- const parsed = new Date(value)
51
- if (Number.isNaN(parsed.getTime()))
52
- throw new Error('Value is not supported for date')
53
-
54
- return parsed
55
- }
56
-
57
- function parseEnvValue<TKind extends EnvKind>(kind: TKind, value: string): EnvKindMap[TKind] {
58
- switch (kind) {
59
- case "string":
60
- return toString(value) as EnvKindMap[TKind]
61
- case "number":
62
- return toNumber(value) as EnvKindMap[TKind]
63
- case "boolean":
64
- return toBoolean(value) as EnvKindMap[TKind]
65
- case "array":
66
- return toArray(value) as EnvKindMap[TKind]
67
- case "object":
68
- return toObject(value) as EnvKindMap[TKind]
69
- case "buffer":
70
- return toBuffer(value) as EnvKindMap[TKind]
71
- case "date":
72
- return toDate(value) as EnvKindMap[TKind]
73
- default: {
74
- const exhaustiveCheck: never = kind
75
- throw new Error(`Unsupported env kind: ${exhaustiveCheck}`)
76
- }
77
- }
78
- }
79
-
80
- export function safeParse<TSchema extends AllowedEnvKeys>(allowedEnvKeys: TSchema, values: Record<string, string>) {
81
- const data: Partial<LoadedEnv<TSchema>> = {}
82
- const error: string[] = []
83
-
84
- for (const key of Object.keys(allowedEnvKeys) as Array<keyof TSchema>) {
85
- const value = values[key as string]
86
- if (value === undefined) continue
87
-
88
- try {
89
- data[key] = parseEnvValue(allowedEnvKeys[key], value)
90
- } catch (e) {
91
- if (e instanceof Error)
92
- error.push(`${String(key)}: ${e.message}`)
93
- else
94
- error.push(`${String(key)}: Unknown error occurred`)
95
- }
96
- }
97
-
98
- return {
99
- success: error.length === 0,
100
- data: data as LoadedEnv<TSchema>,
101
- error
102
- }
103
- }
104
-
105
- export function formatError(message: string[]): string {
106
- return message.join('\n')
107
- }
108
-
109
- export function parseRawEnv(rawEnv: string): Record<string, string> {
110
- const result: Record<string, string> = {}
111
- const lines = rawEnv.split(/\r?\n/)
112
-
113
- for (const line of lines) {
114
- const normalized = line.trim()
115
- if (!normalized || normalized.startsWith('#')) continue
116
-
117
- const separatorIndex = normalized.indexOf('=')
118
- if (separatorIndex <= 0) continue
119
-
120
- const key = normalized.slice(0, separatorIndex).trim()
121
- const value = normalized.slice(separatorIndex + 1).trim()
122
- if (!key) continue
123
-
124
- result[key] = value
125
- }
126
-
127
- return result
128
- }
129
-
130
- export function readEnvFile(filePath: string): false | Record<string, string> {
131
- if (!existsSync(filePath)) return false
132
- return parseRawEnv(readFileSync(filePath, 'utf-8'))
133
- }
134
-
135
- export function getUnknownEnvKeys(source: Record<string, string>, allowedEnvKeys: Set<string>): string[] {
136
- return Object.keys(source).filter((key) => !allowedEnvKeys.has(key))
137
- }
package/src/index.ts DELETED
@@ -1,76 +0,0 @@
1
- import path from 'path'
2
- import { existsSync } from 'fs'
3
- import { formatError, getUnknownEnvKeys, readEnvFile, safeParse } from './helper.js'
4
- import { AllowedEnvKeys, LoadedEnv } from "./types.js";
5
-
6
- export type { AllowedEnvKeys, EnvKind, EnvKindMap, LoadedEnv } from "./types.js"
7
-
8
- declare global {
9
- var liteEnv: unknown
10
- }
11
-
12
- export function loadEnv<TSchema extends AllowedEnvKeys = {}>(
13
- allowedEnvKeys: TSchema = {} as TSchema,
14
- bypassUnknownEnvKeys: boolean = true,
15
- NODE_ENV?: string
16
- ): LoadedEnv<TSchema> {
17
- if (globalThis.liteEnv)
18
- return globalThis.liteEnv as LoadedEnv<TSchema>
19
-
20
- if (NODE_ENV) {
21
- process.env.NODE_ENV = NODE_ENV
22
- } else {
23
- if (!process.env.NODE_ENV) {
24
- process.env.NODE_ENV = 'production'
25
- }
26
-
27
- NODE_ENV = process.env.NODE_ENV
28
- }
29
-
30
- const defaultEnvPath = path.join(process.cwd(), '.env')
31
- const nodeEnvPath = path.join(process.cwd(), `.env.${NODE_ENV}`)
32
-
33
- if (!existsSync(defaultEnvPath))
34
- throw new Error('Default Environment file not found')
35
-
36
- if (!existsSync(nodeEnvPath))
37
- throw new Error(`Environment file not found: .env.${NODE_ENV}`)
38
-
39
- const defaultEnvSource = readEnvFile(defaultEnvPath)
40
- const nodeEnvSource = readEnvFile(nodeEnvPath)
41
-
42
- const mergedEnv: Record<string, string> = {}
43
-
44
- if (defaultEnvSource)
45
- Object.assign(mergedEnv, defaultEnvSource)
46
- if (nodeEnvSource)
47
- Object.assign(mergedEnv, nodeEnvSource)
48
-
49
- if (!bypassUnknownEnvKeys) {
50
- const unknownKeys = [...new Set([...getUnknownEnvKeys(mergedEnv, new Set(Object.keys(allowedEnvKeys)))])]
51
-
52
- if (unknownKeys.length > 0)
53
- throw new Error(`Unknown environment variables in env files: ${unknownKeys.join(', ')}`)
54
- } else {
55
- process.env = {
56
- ...process.env,
57
- ...mergedEnv
58
- }
59
- }
60
-
61
- const parsedEnv = safeParse(allowedEnvKeys, mergedEnv)
62
-
63
- if (!parsedEnv.success)
64
- throw new Error(`Environment validation failed: ${formatError(parsedEnv.error)}`)
65
-
66
- globalThis.liteEnv = parsedEnv.data
67
-
68
- process.env = {
69
- ...process.env,
70
- ...parsedEnv.data
71
- }
72
-
73
- console.log('Loaded env file', `${defaultEnvPath}, ${nodeEnvPath}`)
74
-
75
- return parsedEnv.data as LoadedEnv<TSchema>
76
- }
package/src/types.ts DELETED
@@ -1,21 +0,0 @@
1
- export type ENV = {
2
- NODE_ENV: string
3
- }
4
-
5
- export type EnvKindMap = {
6
- string: string
7
- number: number
8
- boolean: boolean
9
- array: string[]
10
- object: unknown
11
- buffer: Buffer
12
- date: Date
13
- }
14
-
15
- export type EnvKind = keyof EnvKindMap
16
-
17
- export type AllowedEnvKeys = Record<string, EnvKind>
18
-
19
- export type LoadedEnv<TSchema extends AllowedEnvKeys> = {
20
- [K in keyof TSchema]: EnvKindMap[TSchema[K]]
21
- }
package/tsconfig.json DELETED
@@ -1,26 +0,0 @@
1
- {
2
- "compilerOptions": {
3
- "ignoreDeprecations": "6.0",
4
- "rootDir": "src",
5
- "outDir": "dist",
6
- "tsBuildInfoFile": "./dist/.tsbuildinfo",
7
- "types": [
8
- "node"
9
- ],
10
- "noImplicitAny": true,
11
- "module": "NodeNext",
12
- "moduleResolution": "NodeNext",
13
- "paths": {
14
- "@/*": [
15
- "./src/*"
16
- ]
17
- }
18
- },
19
- "include": [
20
- "src/**/*"
21
- ],
22
- "exclude": [
23
- "node_modules",
24
- "dist"
25
- ]
26
- }
package/tsup.config.ts DELETED
@@ -1,10 +0,0 @@
1
- import { defineConfig } from 'tsup'
2
-
3
- export default defineConfig({
4
- entry: ['src'],
5
- format: ['cjs', 'esm'],
6
- dts: true,
7
- splitting: false,
8
- sourcemap: true,
9
- clean: true
10
- })