@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/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