@stacksjs/env 0.58.47
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/README.md +71 -0
- package/package.json +54 -0
- package/src/index.js +2190 -0
- package/src/index.ts +76 -0
- package/src/types.ts +54 -0
package/src/index.ts
ADDED
|
@@ -0,0 +1,76 @@
|
|
|
1
|
+
import p from 'node:process'
|
|
2
|
+
import fs from 'fs-extra'
|
|
3
|
+
import { projectPath } from '@stacksjs/path'
|
|
4
|
+
import { ValidationBoolean, ValidationEnum, ValidationNumber } from '@stacksjs/validation'
|
|
5
|
+
import type { EnvKey } from '../../../env'
|
|
6
|
+
import type { Env } from './types'
|
|
7
|
+
|
|
8
|
+
interface EnumObject {
|
|
9
|
+
[key: string]: string[]
|
|
10
|
+
}
|
|
11
|
+
|
|
12
|
+
export const enums: EnumObject = {
|
|
13
|
+
APP_ENV: ['local', 'dev', 'development', 'staging', 'prod', 'production'],
|
|
14
|
+
DB_CONNECTION: ['mysql', 'sqlite', 'postgres', 'planetscale'],
|
|
15
|
+
MAIL_MAILER: ['smtp', 'mailgun', 'ses', 'postmark', 'sendmail', 'log'],
|
|
16
|
+
SEARCH_ENGINE_DRIVER: ['meilisearch', 'algolia', 'typesense'],
|
|
17
|
+
FRONTEND_APP_ENV: ['development', 'staging', 'production'],
|
|
18
|
+
}
|
|
19
|
+
|
|
20
|
+
const handler = {
|
|
21
|
+
get: (target: Env, key: EnvKey) => {
|
|
22
|
+
const value = target[key] as any
|
|
23
|
+
|
|
24
|
+
// if value is a string but only contains numbers, and the key is not AWS_ACCOUNT_ID, return it as a number
|
|
25
|
+
if (typeof value === 'string' && /^\d+$/.test(value) && key !== 'AWS_ACCOUNT_ID')
|
|
26
|
+
return Number(value)
|
|
27
|
+
|
|
28
|
+
// if value is a string but only contains boolean values, return it as a boolean
|
|
29
|
+
if (typeof value === 'string' && /^(true|false)$/.test(value))
|
|
30
|
+
return value === 'true'
|
|
31
|
+
|
|
32
|
+
// at some point, let's see if we can remove the need for below
|
|
33
|
+
if (value instanceof ValidationEnum)
|
|
34
|
+
return target[key] as string
|
|
35
|
+
|
|
36
|
+
if (value instanceof ValidationBoolean)
|
|
37
|
+
return !!target[key]
|
|
38
|
+
|
|
39
|
+
if (value instanceof ValidationNumber)
|
|
40
|
+
return Number(target[key])
|
|
41
|
+
|
|
42
|
+
return value as string
|
|
43
|
+
},
|
|
44
|
+
}
|
|
45
|
+
|
|
46
|
+
export function process() {
|
|
47
|
+
return typeof Bun !== 'undefined'
|
|
48
|
+
? Bun.env
|
|
49
|
+
: p.env as unknown as Env
|
|
50
|
+
}
|
|
51
|
+
|
|
52
|
+
export const env: Env = new Proxy(process(), handler)
|
|
53
|
+
|
|
54
|
+
export function writeEnv(key: EnvKey, value: string, options?: { path: string }) {
|
|
55
|
+
const envPath = options?.path || projectPath('.env')
|
|
56
|
+
const env = fs.readFileSync(envPath, 'utf-8')
|
|
57
|
+
|
|
58
|
+
// Split the file into lines
|
|
59
|
+
const lines = env.split('\n')
|
|
60
|
+
|
|
61
|
+
// Find the line with the variable we want to update
|
|
62
|
+
const index = lines.findIndex(line => line.startsWith(`${key}=`))
|
|
63
|
+
|
|
64
|
+
// If the variable exists, update it
|
|
65
|
+
if (index !== -1)
|
|
66
|
+
lines[index] = `${key}=${value}`
|
|
67
|
+
|
|
68
|
+
// Otherwise, add a new line
|
|
69
|
+
else
|
|
70
|
+
lines.push(`${key}=${value}`)
|
|
71
|
+
|
|
72
|
+
// Join the lines back into a string and write it to the .env file
|
|
73
|
+
fs.writeFileSync(envPath, lines.join('\n'))
|
|
74
|
+
}
|
|
75
|
+
|
|
76
|
+
export * from './types'
|
package/src/types.ts
ADDED
|
@@ -0,0 +1,54 @@
|
|
|
1
|
+
import type { Infer, VineBoolean, VineEnum, VineNumber, VineString } from '@stacksjs/validation'
|
|
2
|
+
import { validator } from '@stacksjs/validation'
|
|
3
|
+
import env from '../../../../../config/env'
|
|
4
|
+
import type { EnvKey } from '../../../env'
|
|
5
|
+
|
|
6
|
+
// import type { Validate } from '@stacksjs/validation'
|
|
7
|
+
|
|
8
|
+
// we need to get this just into right format so we can infer the type
|
|
9
|
+
type EnvValue = string | boolean | number | readonly string[]
|
|
10
|
+
type EnvType = typeof env
|
|
11
|
+
type EnvKeys = keyof EnvType
|
|
12
|
+
type EnvMap = { [K in EnvKeys]: EnvType[K] extends string ? VineString :
|
|
13
|
+
EnvType[K] extends number ? VineNumber :
|
|
14
|
+
EnvType[K] extends boolean ? VineBoolean :
|
|
15
|
+
EnvType[K] extends readonly string[] ? VineEnum<string[]> : unknown }
|
|
16
|
+
|
|
17
|
+
type ValidatorType = VineString | VineNumber | VineBoolean | VineEnum<string[]>
|
|
18
|
+
|
|
19
|
+
const envStructure = Object.entries(env).reduce((acc, [key, value]) => {
|
|
20
|
+
let validatorType: ValidatorType
|
|
21
|
+
switch (typeof value) {
|
|
22
|
+
case 'string':
|
|
23
|
+
validatorType = validator.string()
|
|
24
|
+
break
|
|
25
|
+
case 'number':
|
|
26
|
+
validatorType = validator.number()
|
|
27
|
+
break
|
|
28
|
+
case 'boolean':
|
|
29
|
+
validatorType = validator.boolean()
|
|
30
|
+
break
|
|
31
|
+
default:
|
|
32
|
+
if (Array.isArray(value)) {
|
|
33
|
+
validatorType = validator.enum(value as string[])
|
|
34
|
+
break
|
|
35
|
+
}
|
|
36
|
+
throw new Error(`Invalid env value for ${key}`)
|
|
37
|
+
}
|
|
38
|
+
const envKey = key as EnvKeys
|
|
39
|
+
|
|
40
|
+
acc[envKey] = validatorType as any
|
|
41
|
+
return acc
|
|
42
|
+
}, {} as EnvMap)
|
|
43
|
+
|
|
44
|
+
export const envSchema = validator.object(envStructure)
|
|
45
|
+
export type Env = Infer<typeof envSchema>
|
|
46
|
+
|
|
47
|
+
export type EnvOptions = Env
|
|
48
|
+
export type EnvConfig = Partial<Record<EnvKey, EnvValue>>
|
|
49
|
+
|
|
50
|
+
export interface FrontendEnv {
|
|
51
|
+
FRONTEND_APP_ENV: 'local' | 'development' | 'staging' | 'production'
|
|
52
|
+
FRONTEND_APP_URL: string
|
|
53
|
+
}
|
|
54
|
+
export type FrontendEnvKeys = keyof FrontendEnv
|