@buenojs/bueno 0.8.0
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/.env.example +109 -0
- package/.github/workflows/ci.yml +31 -0
- package/LICENSE +21 -0
- package/README.md +892 -0
- package/architecture.md +652 -0
- package/bun.lock +70 -0
- package/dist/cli/index.js +3233 -0
- package/dist/index.js +9014 -0
- package/package.json +77 -0
- package/src/cache/index.ts +795 -0
- package/src/cli/ARCHITECTURE.md +837 -0
- package/src/cli/bin.ts +10 -0
- package/src/cli/commands/build.ts +425 -0
- package/src/cli/commands/dev.ts +248 -0
- package/src/cli/commands/generate.ts +541 -0
- package/src/cli/commands/help.ts +55 -0
- package/src/cli/commands/index.ts +112 -0
- package/src/cli/commands/migration.ts +355 -0
- package/src/cli/commands/new.ts +804 -0
- package/src/cli/commands/start.ts +208 -0
- package/src/cli/core/args.ts +283 -0
- package/src/cli/core/console.ts +349 -0
- package/src/cli/core/index.ts +60 -0
- package/src/cli/core/prompt.ts +424 -0
- package/src/cli/core/spinner.ts +265 -0
- package/src/cli/index.ts +135 -0
- package/src/cli/templates/deploy.ts +295 -0
- package/src/cli/templates/docker.ts +307 -0
- package/src/cli/templates/index.ts +24 -0
- package/src/cli/utils/fs.ts +428 -0
- package/src/cli/utils/index.ts +8 -0
- package/src/cli/utils/strings.ts +197 -0
- package/src/config/env.ts +408 -0
- package/src/config/index.ts +506 -0
- package/src/config/loader.ts +329 -0
- package/src/config/merge.ts +285 -0
- package/src/config/types.ts +320 -0
- package/src/config/validation.ts +441 -0
- package/src/container/forward-ref.ts +143 -0
- package/src/container/index.ts +386 -0
- package/src/context/index.ts +360 -0
- package/src/database/index.ts +1142 -0
- package/src/database/migrations/index.ts +371 -0
- package/src/database/schema/index.ts +619 -0
- package/src/frontend/api-routes.ts +640 -0
- package/src/frontend/bundler.ts +643 -0
- package/src/frontend/console-client.ts +419 -0
- package/src/frontend/console-stream.ts +587 -0
- package/src/frontend/dev-server.ts +846 -0
- package/src/frontend/file-router.ts +611 -0
- package/src/frontend/frameworks/index.ts +106 -0
- package/src/frontend/frameworks/react.ts +85 -0
- package/src/frontend/frameworks/solid.ts +104 -0
- package/src/frontend/frameworks/svelte.ts +110 -0
- package/src/frontend/frameworks/vue.ts +92 -0
- package/src/frontend/hmr-client.ts +663 -0
- package/src/frontend/hmr.ts +728 -0
- package/src/frontend/index.ts +342 -0
- package/src/frontend/islands.ts +552 -0
- package/src/frontend/isr.ts +555 -0
- package/src/frontend/layout.ts +475 -0
- package/src/frontend/ssr/react.ts +446 -0
- package/src/frontend/ssr/solid.ts +523 -0
- package/src/frontend/ssr/svelte.ts +546 -0
- package/src/frontend/ssr/vue.ts +504 -0
- package/src/frontend/ssr.ts +699 -0
- package/src/frontend/types.ts +2274 -0
- package/src/health/index.ts +604 -0
- package/src/index.ts +410 -0
- package/src/lock/index.ts +587 -0
- package/src/logger/index.ts +444 -0
- package/src/logger/transports/index.ts +969 -0
- package/src/metrics/index.ts +494 -0
- package/src/middleware/built-in.ts +360 -0
- package/src/middleware/index.ts +94 -0
- package/src/modules/filters.ts +458 -0
- package/src/modules/guards.ts +405 -0
- package/src/modules/index.ts +1256 -0
- package/src/modules/interceptors.ts +574 -0
- package/src/modules/lazy.ts +418 -0
- package/src/modules/lifecycle.ts +478 -0
- package/src/modules/metadata.ts +90 -0
- package/src/modules/pipes.ts +626 -0
- package/src/router/index.ts +339 -0
- package/src/router/linear.ts +371 -0
- package/src/router/regex.ts +292 -0
- package/src/router/tree.ts +562 -0
- package/src/rpc/index.ts +1263 -0
- package/src/security/index.ts +436 -0
- package/src/ssg/index.ts +631 -0
- package/src/storage/index.ts +456 -0
- package/src/telemetry/index.ts +1097 -0
- package/src/testing/index.ts +1586 -0
- package/src/types/index.ts +236 -0
- package/src/types/optional-deps.d.ts +219 -0
- package/src/validation/index.ts +276 -0
- package/src/websocket/index.ts +1004 -0
- package/tests/integration/cli.test.ts +1016 -0
- package/tests/integration/fullstack.test.ts +234 -0
- package/tests/unit/cache.test.ts +174 -0
- package/tests/unit/cli-commands.test.ts +892 -0
- package/tests/unit/cli.test.ts +1258 -0
- package/tests/unit/container.test.ts +279 -0
- package/tests/unit/context.test.ts +221 -0
- package/tests/unit/database.test.ts +183 -0
- package/tests/unit/linear-router.test.ts +280 -0
- package/tests/unit/lock.test.ts +336 -0
- package/tests/unit/middleware.test.ts +184 -0
- package/tests/unit/modules.test.ts +142 -0
- package/tests/unit/pubsub.test.ts +257 -0
- package/tests/unit/regex-router.test.ts +265 -0
- package/tests/unit/router.test.ts +373 -0
- package/tests/unit/rpc.test.ts +1248 -0
- package/tests/unit/security.test.ts +174 -0
- package/tests/unit/telemetry.test.ts +371 -0
- package/tests/unit/test-cache.test.ts +110 -0
- package/tests/unit/test-database.test.ts +282 -0
- package/tests/unit/tree-router.test.ts +325 -0
- package/tests/unit/validation.test.ts +794 -0
- package/tsconfig.json +27 -0
|
@@ -0,0 +1,408 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Environment variable handling for Bueno Framework
|
|
3
|
+
*/
|
|
4
|
+
|
|
5
|
+
import type { BuenoConfig, DeepPartial, EnvMapping } from "./types";
|
|
6
|
+
import { ENV_MAPPINGS } from "./types";
|
|
7
|
+
import { setNestedValue } from "./merge";
|
|
8
|
+
|
|
9
|
+
/**
|
|
10
|
+
* Environment variable source information
|
|
11
|
+
*/
|
|
12
|
+
export interface EnvSourceInfo {
|
|
13
|
+
/** Environment variable name */
|
|
14
|
+
name: string;
|
|
15
|
+
/** Value of the environment variable */
|
|
16
|
+
value: string;
|
|
17
|
+
/** File the variable was loaded from */
|
|
18
|
+
source?: string;
|
|
19
|
+
}
|
|
20
|
+
|
|
21
|
+
/**
|
|
22
|
+
* Loaded environment data
|
|
23
|
+
*/
|
|
24
|
+
export interface LoadedEnv {
|
|
25
|
+
/** Raw environment variables loaded */
|
|
26
|
+
raw: Record<string, string>;
|
|
27
|
+
/** Transformed configuration from environment */
|
|
28
|
+
config: DeepPartial<BuenoConfig>;
|
|
29
|
+
/** Source information for each variable */
|
|
30
|
+
sources: Map<string, EnvSourceInfo>;
|
|
31
|
+
}
|
|
32
|
+
|
|
33
|
+
/**
|
|
34
|
+
* Environment file priority (later files override earlier ones)
|
|
35
|
+
*/
|
|
36
|
+
const ENV_FILE_PRIORITY = [
|
|
37
|
+
".env",
|
|
38
|
+
".env.local",
|
|
39
|
+
".env.development",
|
|
40
|
+
".env.production",
|
|
41
|
+
".env.test",
|
|
42
|
+
];
|
|
43
|
+
|
|
44
|
+
/**
|
|
45
|
+
* Get the current NODE_ENV
|
|
46
|
+
*/
|
|
47
|
+
export function getNodeEnv(): string {
|
|
48
|
+
return Bun.env.NODE_ENV || "development";
|
|
49
|
+
}
|
|
50
|
+
|
|
51
|
+
/**
|
|
52
|
+
* Get environment-specific .env file name
|
|
53
|
+
*/
|
|
54
|
+
export function getEnvFileName(): string {
|
|
55
|
+
const nodeEnv = getNodeEnv();
|
|
56
|
+
switch (nodeEnv) {
|
|
57
|
+
case "production":
|
|
58
|
+
return ".env.production";
|
|
59
|
+
case "test":
|
|
60
|
+
return ".env.test";
|
|
61
|
+
default:
|
|
62
|
+
return ".env.development";
|
|
63
|
+
}
|
|
64
|
+
}
|
|
65
|
+
|
|
66
|
+
/**
|
|
67
|
+
* Check if a file exists
|
|
68
|
+
*/
|
|
69
|
+
async function fileExists(path: string): Promise<boolean> {
|
|
70
|
+
try {
|
|
71
|
+
const file = Bun.file(path);
|
|
72
|
+
return await file.exists();
|
|
73
|
+
} catch {
|
|
74
|
+
return false;
|
|
75
|
+
}
|
|
76
|
+
}
|
|
77
|
+
|
|
78
|
+
/**
|
|
79
|
+
* Parse .env file content
|
|
80
|
+
*/
|
|
81
|
+
function parseEnvContent(content: string): Record<string, string> {
|
|
82
|
+
const result: Record<string, string> = {};
|
|
83
|
+
const lines = content.split("\n");
|
|
84
|
+
|
|
85
|
+
for (const line of lines) {
|
|
86
|
+
// Skip empty lines and comments
|
|
87
|
+
const trimmed = line.trim();
|
|
88
|
+
if (!trimmed || trimmed.startsWith("#")) {
|
|
89
|
+
continue;
|
|
90
|
+
}
|
|
91
|
+
|
|
92
|
+
// Parse KEY=value or KEY="value" or KEY='value'
|
|
93
|
+
const match = trimmed.match(/^([A-Za-z_][A-Za-z0-9_]*)=(.*)$/);
|
|
94
|
+
if (!match) {
|
|
95
|
+
continue;
|
|
96
|
+
}
|
|
97
|
+
|
|
98
|
+
const [, key, rawValue] = match;
|
|
99
|
+
let value = rawValue;
|
|
100
|
+
|
|
101
|
+
// Handle quoted values
|
|
102
|
+
if (
|
|
103
|
+
(value.startsWith('"') && value.endsWith('"')) ||
|
|
104
|
+
(value.startsWith("'") && value.endsWith("'"))
|
|
105
|
+
) {
|
|
106
|
+
value = value.slice(1, -1);
|
|
107
|
+
}
|
|
108
|
+
|
|
109
|
+
result[key] = value;
|
|
110
|
+
}
|
|
111
|
+
|
|
112
|
+
return result;
|
|
113
|
+
}
|
|
114
|
+
|
|
115
|
+
/**
|
|
116
|
+
* Load environment variables from a single .env file
|
|
117
|
+
*/
|
|
118
|
+
async function loadEnvFile(
|
|
119
|
+
filePath: string,
|
|
120
|
+
): Promise<{ vars: Record<string, string>; existed: boolean }> {
|
|
121
|
+
const exists = await fileExists(filePath);
|
|
122
|
+
if (!exists) {
|
|
123
|
+
return { vars: {}, existed: false };
|
|
124
|
+
}
|
|
125
|
+
|
|
126
|
+
try {
|
|
127
|
+
const file = Bun.file(filePath);
|
|
128
|
+
const content = await file.text();
|
|
129
|
+
const vars = parseEnvContent(content);
|
|
130
|
+
return { vars, existed: true };
|
|
131
|
+
} catch (error) {
|
|
132
|
+
console.warn(`Warning: Failed to load ${filePath}:`, error);
|
|
133
|
+
return { vars: {}, existed: false };
|
|
134
|
+
}
|
|
135
|
+
}
|
|
136
|
+
|
|
137
|
+
/**
|
|
138
|
+
* Load environment variables from multiple .env files
|
|
139
|
+
* Files are loaded in priority order, with later files overriding earlier ones
|
|
140
|
+
*/
|
|
141
|
+
export async function loadEnvFiles(options?: {
|
|
142
|
+
/** Custom list of env files to load */
|
|
143
|
+
files?: string[];
|
|
144
|
+
/** Whether to also load NODE_ENV-specific file */
|
|
145
|
+
loadNodeEnv?: boolean;
|
|
146
|
+
/** Base directory for env files */
|
|
147
|
+
cwd?: string;
|
|
148
|
+
}): Promise<Record<string, string>> {
|
|
149
|
+
const cwd = options?.cwd ?? process.cwd();
|
|
150
|
+
const files = options?.files ?? [...ENV_FILE_PRIORITY];
|
|
151
|
+
|
|
152
|
+
// Add NODE_ENV-specific file if requested
|
|
153
|
+
if (options?.loadNodeEnv !== false) {
|
|
154
|
+
const envFile = getEnvFileName();
|
|
155
|
+
if (!files.includes(envFile)) {
|
|
156
|
+
files.push(envFile);
|
|
157
|
+
}
|
|
158
|
+
}
|
|
159
|
+
|
|
160
|
+
const result: Record<string, string> = {};
|
|
161
|
+
|
|
162
|
+
for (const file of files) {
|
|
163
|
+
const filePath = file.startsWith("/") ? file : `${cwd}/${file}`;
|
|
164
|
+
const { vars } = await loadEnvFile(filePath);
|
|
165
|
+
Object.assign(result, vars);
|
|
166
|
+
}
|
|
167
|
+
|
|
168
|
+
return result;
|
|
169
|
+
}
|
|
170
|
+
|
|
171
|
+
/**
|
|
172
|
+
* Get environment variable value from Bun.env
|
|
173
|
+
*/
|
|
174
|
+
export function getEnvVar(name: string): string | undefined {
|
|
175
|
+
return Bun.env[name];
|
|
176
|
+
}
|
|
177
|
+
|
|
178
|
+
/**
|
|
179
|
+
* Set environment variable in Bun.env
|
|
180
|
+
*/
|
|
181
|
+
export function setEnvVar(name: string, value: string): void {
|
|
182
|
+
Bun.env[name] = value;
|
|
183
|
+
}
|
|
184
|
+
|
|
185
|
+
/**
|
|
186
|
+
* Delete environment variable from Bun.env
|
|
187
|
+
*/
|
|
188
|
+
export function deleteEnvVar(name: string): void {
|
|
189
|
+
delete Bun.env[name];
|
|
190
|
+
}
|
|
191
|
+
|
|
192
|
+
/**
|
|
193
|
+
* Transform environment variables to configuration object
|
|
194
|
+
*/
|
|
195
|
+
export function envToConfig(
|
|
196
|
+
envVars: Record<string, string>,
|
|
197
|
+
mappings: EnvMapping[] = ENV_MAPPINGS,
|
|
198
|
+
): DeepPartial<BuenoConfig> {
|
|
199
|
+
let config: DeepPartial<BuenoConfig> = {};
|
|
200
|
+
|
|
201
|
+
for (const mapping of mappings) {
|
|
202
|
+
const value = envVars[mapping.envVar];
|
|
203
|
+
if (value === undefined || value === "") {
|
|
204
|
+
continue;
|
|
205
|
+
}
|
|
206
|
+
|
|
207
|
+
const transformedValue = mapping.transform
|
|
208
|
+
? mapping.transform(value)
|
|
209
|
+
: value;
|
|
210
|
+
|
|
211
|
+
config = setNestedValue(
|
|
212
|
+
config as Record<string, unknown>,
|
|
213
|
+
mapping.configKey,
|
|
214
|
+
transformedValue,
|
|
215
|
+
) as DeepPartial<BuenoConfig>;
|
|
216
|
+
}
|
|
217
|
+
|
|
218
|
+
return config;
|
|
219
|
+
}
|
|
220
|
+
|
|
221
|
+
/**
|
|
222
|
+
* Load environment variables and transform to configuration
|
|
223
|
+
*/
|
|
224
|
+
export async function loadEnv(options?: {
|
|
225
|
+
/** Custom list of env files to load */
|
|
226
|
+
files?: string[];
|
|
227
|
+
/** Whether to load NODE_ENV-specific file */
|
|
228
|
+
loadNodeEnv?: boolean;
|
|
229
|
+
/** Base directory for env files */
|
|
230
|
+
cwd?: string;
|
|
231
|
+
/** Whether to merge with existing Bun.env */
|
|
232
|
+
mergeWithProcess?: boolean;
|
|
233
|
+
/** Custom environment variable mappings */
|
|
234
|
+
mappings?: EnvMapping[];
|
|
235
|
+
}): Promise<LoadedEnv> {
|
|
236
|
+
// Load from .env files
|
|
237
|
+
const fileVars = await loadEnvFiles(options);
|
|
238
|
+
|
|
239
|
+
// Merge with Bun.env if requested
|
|
240
|
+
const raw: Record<string, string> =
|
|
241
|
+
options?.mergeWithProcess !== false
|
|
242
|
+
? { ...fileVars, ...Object.fromEntries(Object.entries(Bun.env).filter(([, v]) => v !== undefined) as [string, string][]) }
|
|
243
|
+
: fileVars;
|
|
244
|
+
|
|
245
|
+
// Transform to config
|
|
246
|
+
const config = envToConfig(raw, options?.mappings);
|
|
247
|
+
|
|
248
|
+
// Track sources
|
|
249
|
+
const sources = new Map<string, EnvSourceInfo>();
|
|
250
|
+
for (const [name, value] of Object.entries(raw)) {
|
|
251
|
+
sources.set(name, {
|
|
252
|
+
name,
|
|
253
|
+
value,
|
|
254
|
+
source: fileVars[name] !== undefined ? ".env file" : "process",
|
|
255
|
+
});
|
|
256
|
+
}
|
|
257
|
+
|
|
258
|
+
// Set loaded vars to Bun.env
|
|
259
|
+
for (const [key, value] of Object.entries(fileVars)) {
|
|
260
|
+
if (Bun.env[key] === undefined) {
|
|
261
|
+
Bun.env[key] = value;
|
|
262
|
+
}
|
|
263
|
+
}
|
|
264
|
+
|
|
265
|
+
return { raw, config, sources };
|
|
266
|
+
}
|
|
267
|
+
|
|
268
|
+
/**
|
|
269
|
+
* Get all environment variables related to Bueno configuration
|
|
270
|
+
*/
|
|
271
|
+
export function getBuenoEnvVars(): Record<string, string> {
|
|
272
|
+
const result: Record<string, string> = {};
|
|
273
|
+
|
|
274
|
+
for (const mapping of ENV_MAPPINGS) {
|
|
275
|
+
const value = Bun.env[mapping.envVar];
|
|
276
|
+
if (value !== undefined) {
|
|
277
|
+
result[mapping.envVar] = value;
|
|
278
|
+
}
|
|
279
|
+
}
|
|
280
|
+
|
|
281
|
+
return result;
|
|
282
|
+
}
|
|
283
|
+
|
|
284
|
+
/**
|
|
285
|
+
* Check if running in development mode
|
|
286
|
+
*/
|
|
287
|
+
export function isDevelopment(): boolean {
|
|
288
|
+
return getNodeEnv() === "development";
|
|
289
|
+
}
|
|
290
|
+
|
|
291
|
+
/**
|
|
292
|
+
* Check if running in production mode
|
|
293
|
+
*/
|
|
294
|
+
export function isProduction(): boolean {
|
|
295
|
+
return getNodeEnv() === "production";
|
|
296
|
+
}
|
|
297
|
+
|
|
298
|
+
/**
|
|
299
|
+
* Check if running in test mode
|
|
300
|
+
*/
|
|
301
|
+
export function isTest(): boolean {
|
|
302
|
+
return getNodeEnv() === "test";
|
|
303
|
+
}
|
|
304
|
+
|
|
305
|
+
/**
|
|
306
|
+
* Create a custom environment variable mapping
|
|
307
|
+
*/
|
|
308
|
+
export function createEnvMapping(
|
|
309
|
+
envVar: string,
|
|
310
|
+
configKey: string,
|
|
311
|
+
transform?: (value: string) => unknown,
|
|
312
|
+
): EnvMapping {
|
|
313
|
+
return { envVar, configKey, transform };
|
|
314
|
+
}
|
|
315
|
+
|
|
316
|
+
/**
|
|
317
|
+
* Parse a boolean environment variable
|
|
318
|
+
*/
|
|
319
|
+
export function parseEnvBoolean(value: string): boolean {
|
|
320
|
+
return value === "true" || value === "1" || value === "yes";
|
|
321
|
+
}
|
|
322
|
+
|
|
323
|
+
/**
|
|
324
|
+
* Parse a number environment variable
|
|
325
|
+
*/
|
|
326
|
+
export function parseEnvNumber(value: string): number {
|
|
327
|
+
const num = parseInt(value, 10);
|
|
328
|
+
if (isNaN(num)) {
|
|
329
|
+
throw new Error(`Invalid number: ${value}`);
|
|
330
|
+
}
|
|
331
|
+
return num;
|
|
332
|
+
}
|
|
333
|
+
|
|
334
|
+
/**
|
|
335
|
+
* Parse a JSON environment variable
|
|
336
|
+
*/
|
|
337
|
+
export function parseEnvJSON<T = unknown>(value: string): T {
|
|
338
|
+
return JSON.parse(value) as T;
|
|
339
|
+
}
|
|
340
|
+
|
|
341
|
+
/**
|
|
342
|
+
* Parse an array environment variable (comma-separated)
|
|
343
|
+
*/
|
|
344
|
+
export function parseEnvArray(value: string): string[] {
|
|
345
|
+
return value.split(",").map((v) => v.trim());
|
|
346
|
+
}
|
|
347
|
+
|
|
348
|
+
/**
|
|
349
|
+
* Environment config mapping for standard Bueno config
|
|
350
|
+
*/
|
|
351
|
+
export const envConfigMapping: EnvConfigMapping[] = [
|
|
352
|
+
{ envVar: "BUENO_PORT", configKey: "server.port", transform: parseEnvNumber },
|
|
353
|
+
{ envVar: "BUENO_HOST", configKey: "server.host" },
|
|
354
|
+
{ envVar: "BUENO_DEV", configKey: "server.development", transform: parseEnvBoolean },
|
|
355
|
+
{ envVar: "DATABASE_URL", configKey: "database.url" },
|
|
356
|
+
{ envVar: "DATABASE_POOL_SIZE", configKey: "database.poolSize", transform: parseEnvNumber },
|
|
357
|
+
{ envVar: "REDIS_URL", configKey: "cache.url" },
|
|
358
|
+
{ envVar: "CACHE_DRIVER", configKey: "cache.driver" },
|
|
359
|
+
{ envVar: "CACHE_TTL", configKey: "cache.ttl", transform: parseEnvNumber },
|
|
360
|
+
{ envVar: "LOG_LEVEL", configKey: "logger.level" },
|
|
361
|
+
{ envVar: "LOG_PRETTY", configKey: "logger.pretty", transform: parseEnvBoolean },
|
|
362
|
+
{ envVar: "HEALTH_ENABLED", configKey: "health.enabled", transform: parseEnvBoolean },
|
|
363
|
+
{ envVar: "METRICS_ENABLED", configKey: "metrics.enabled", transform: parseEnvBoolean },
|
|
364
|
+
{ envVar: "TELEMETRY_ENABLED", configKey: "telemetry.enabled", transform: parseEnvBoolean },
|
|
365
|
+
{ envVar: "TELEMETRY_SERVICE_NAME", configKey: "telemetry.serviceName" },
|
|
366
|
+
{ envVar: "TELEMETRY_ENDPOINT", configKey: "telemetry.endpoint" },
|
|
367
|
+
{ envVar: "FRONTEND_DEV_SERVER", configKey: "frontend.devServer", transform: parseEnvBoolean },
|
|
368
|
+
{ envVar: "FRONTEND_HMR", configKey: "frontend.hmr", transform: parseEnvBoolean },
|
|
369
|
+
{ envVar: "FRONTEND_PORT", configKey: "frontend.port", transform: parseEnvNumber },
|
|
370
|
+
];
|
|
371
|
+
|
|
372
|
+
/**
|
|
373
|
+
* Environment config mapping interface
|
|
374
|
+
*/
|
|
375
|
+
export interface EnvConfigMapping {
|
|
376
|
+
envVar: string;
|
|
377
|
+
configKey: string;
|
|
378
|
+
transform?: (value: string) => unknown;
|
|
379
|
+
}
|
|
380
|
+
|
|
381
|
+
/**
|
|
382
|
+
* Get a config value from environment variables using the mapping
|
|
383
|
+
*/
|
|
384
|
+
export function getEnvConfig(
|
|
385
|
+
mappings: EnvConfigMapping[] = envConfigMapping,
|
|
386
|
+
): DeepPartial<BuenoConfig> {
|
|
387
|
+
const envVars: Record<string, string> = {};
|
|
388
|
+
for (const [key, value] of Object.entries(Bun.env)) {
|
|
389
|
+
if (value !== undefined) {
|
|
390
|
+
envVars[key] = value;
|
|
391
|
+
}
|
|
392
|
+
}
|
|
393
|
+
return envToConfig(envVars, mappings);
|
|
394
|
+
}
|
|
395
|
+
|
|
396
|
+
/**
|
|
397
|
+
* Get an environment variable value
|
|
398
|
+
*/
|
|
399
|
+
export function getEnvValue(key: string, defaultValue?: string): string | undefined {
|
|
400
|
+
return Bun.env[key] ?? defaultValue;
|
|
401
|
+
}
|
|
402
|
+
|
|
403
|
+
/**
|
|
404
|
+
* Set an environment variable value
|
|
405
|
+
*/
|
|
406
|
+
export function setEnvValue(key: string, value: string): void {
|
|
407
|
+
Bun.env[key] = value;
|
|
408
|
+
}
|