@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,506 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Configuration System for Bueno Framework
|
|
3
|
+
*
|
|
4
|
+
* Provides a comprehensive configuration system supporting:
|
|
5
|
+
* - `bueno.config.ts` file loading
|
|
6
|
+
* - Environment variables
|
|
7
|
+
* - Schema validation
|
|
8
|
+
* - Deep merging of config sources
|
|
9
|
+
*/
|
|
10
|
+
|
|
11
|
+
// Re-export types
|
|
12
|
+
export type {
|
|
13
|
+
BuenoConfig,
|
|
14
|
+
ServerConfig,
|
|
15
|
+
DatabaseConfig,
|
|
16
|
+
CacheConfig,
|
|
17
|
+
LoggerConfig,
|
|
18
|
+
HealthConfig,
|
|
19
|
+
MetricsConfig,
|
|
20
|
+
TelemetryConfig,
|
|
21
|
+
FrontendConfig,
|
|
22
|
+
DeepPartial,
|
|
23
|
+
UserConfig,
|
|
24
|
+
UserConfigFn,
|
|
25
|
+
InferConfig,
|
|
26
|
+
} from "./types";
|
|
27
|
+
|
|
28
|
+
// Re-export merge utilities
|
|
29
|
+
export { deepMerge, mergeConfigs, isObject } from "./merge";
|
|
30
|
+
|
|
31
|
+
// Re-export environment utilities
|
|
32
|
+
export {
|
|
33
|
+
loadEnv,
|
|
34
|
+
getEnvConfig,
|
|
35
|
+
getEnvValue,
|
|
36
|
+
setEnvValue,
|
|
37
|
+
envConfigMapping,
|
|
38
|
+
type EnvConfigMapping,
|
|
39
|
+
} from "./env";
|
|
40
|
+
|
|
41
|
+
// Re-export loader utilities
|
|
42
|
+
export {
|
|
43
|
+
loadConfig,
|
|
44
|
+
loadConfigFile,
|
|
45
|
+
loadConfigFiles,
|
|
46
|
+
findConfigFile,
|
|
47
|
+
clearConfigCache,
|
|
48
|
+
getCachedConfig,
|
|
49
|
+
watchConfig,
|
|
50
|
+
validateConfigStructure,
|
|
51
|
+
getConfigPathFromArgs,
|
|
52
|
+
getConfigPathFromEnv,
|
|
53
|
+
type LoadedConfig,
|
|
54
|
+
} from "./loader";
|
|
55
|
+
|
|
56
|
+
// Re-export validation utilities
|
|
57
|
+
export {
|
|
58
|
+
validateConfig,
|
|
59
|
+
validateConfigSync,
|
|
60
|
+
validateConfigDefaults,
|
|
61
|
+
validateWithSchema,
|
|
62
|
+
assertValidConfig,
|
|
63
|
+
formatValidationErrors,
|
|
64
|
+
createConfigError,
|
|
65
|
+
createCustomValidator,
|
|
66
|
+
isStandardSchema,
|
|
67
|
+
type ConfigValidationResult,
|
|
68
|
+
type ConfigValidationError,
|
|
69
|
+
type ConfigValidationWarning,
|
|
70
|
+
} from "./validation";
|
|
71
|
+
|
|
72
|
+
import type { StandardSchema } from "../types";
|
|
73
|
+
import type {
|
|
74
|
+
BuenoConfig,
|
|
75
|
+
DeepPartial,
|
|
76
|
+
UserConfig,
|
|
77
|
+
UserConfigFn,
|
|
78
|
+
InferConfig,
|
|
79
|
+
} from "./types";
|
|
80
|
+
import { deepMerge, mergeConfigs } from "./merge";
|
|
81
|
+
import { loadEnv, getEnvConfig } from "./env";
|
|
82
|
+
import { loadConfig, findConfigFile, clearConfigCache } from "./loader";
|
|
83
|
+
import {
|
|
84
|
+
validateConfig,
|
|
85
|
+
validateConfigSync,
|
|
86
|
+
assertValidConfig,
|
|
87
|
+
type ConfigValidationResult,
|
|
88
|
+
} from "./validation";
|
|
89
|
+
|
|
90
|
+
/**
|
|
91
|
+
* Default configuration values
|
|
92
|
+
*/
|
|
93
|
+
const DEFAULT_CONFIG: BuenoConfig = {
|
|
94
|
+
server: {
|
|
95
|
+
port: 3000,
|
|
96
|
+
host: "localhost",
|
|
97
|
+
development: false,
|
|
98
|
+
},
|
|
99
|
+
database: {
|
|
100
|
+
url: undefined,
|
|
101
|
+
poolSize: 10,
|
|
102
|
+
enableMetrics: true,
|
|
103
|
+
slowQueryThreshold: 100,
|
|
104
|
+
},
|
|
105
|
+
cache: {
|
|
106
|
+
driver: "memory",
|
|
107
|
+
url: undefined,
|
|
108
|
+
ttl: 3600,
|
|
109
|
+
keyPrefix: "",
|
|
110
|
+
enableMetrics: true,
|
|
111
|
+
},
|
|
112
|
+
logger: {
|
|
113
|
+
level: "info",
|
|
114
|
+
pretty: false,
|
|
115
|
+
output: "console",
|
|
116
|
+
},
|
|
117
|
+
health: {
|
|
118
|
+
enabled: true,
|
|
119
|
+
healthPath: "/health",
|
|
120
|
+
readyPath: "/ready",
|
|
121
|
+
},
|
|
122
|
+
metrics: {
|
|
123
|
+
enabled: true,
|
|
124
|
+
collectInterval: 60000,
|
|
125
|
+
maxHistorySize: 100,
|
|
126
|
+
},
|
|
127
|
+
telemetry: {
|
|
128
|
+
enabled: false,
|
|
129
|
+
serviceName: "bueno-app",
|
|
130
|
+
endpoint: undefined,
|
|
131
|
+
sampleRate: 1.0,
|
|
132
|
+
},
|
|
133
|
+
frontend: {
|
|
134
|
+
devServer: false,
|
|
135
|
+
hmr: true,
|
|
136
|
+
port: 3001,
|
|
137
|
+
},
|
|
138
|
+
};
|
|
139
|
+
|
|
140
|
+
/**
|
|
141
|
+
* ConfigManager options
|
|
142
|
+
*/
|
|
143
|
+
export interface ConfigManagerOptions<T extends BuenoConfig = BuenoConfig> {
|
|
144
|
+
/** Custom config file path */
|
|
145
|
+
configPath?: string;
|
|
146
|
+
/** Working directory */
|
|
147
|
+
cwd?: string;
|
|
148
|
+
/** Whether to load environment variables */
|
|
149
|
+
loadEnv?: boolean;
|
|
150
|
+
/** Whether to use default config */
|
|
151
|
+
useDefaults?: boolean;
|
|
152
|
+
/** Custom schema for validation */
|
|
153
|
+
schema?: StandardSchema<T>;
|
|
154
|
+
/** Whether to validate config on load */
|
|
155
|
+
validate?: boolean;
|
|
156
|
+
/** Additional config to merge */
|
|
157
|
+
config?: DeepPartial<T>;
|
|
158
|
+
}
|
|
159
|
+
|
|
160
|
+
/**
|
|
161
|
+
* Config change callback
|
|
162
|
+
*/
|
|
163
|
+
export type ConfigChangeCallback<T extends BuenoConfig = BuenoConfig> = (
|
|
164
|
+
config: T,
|
|
165
|
+
) => void;
|
|
166
|
+
|
|
167
|
+
/**
|
|
168
|
+
* ConfigManager class
|
|
169
|
+
* Manages configuration loading, merging, validation, and access
|
|
170
|
+
*/
|
|
171
|
+
export class ConfigManager<T extends BuenoConfig = BuenoConfig> {
|
|
172
|
+
private config: T;
|
|
173
|
+
private options: ConfigManagerOptions<T>;
|
|
174
|
+
private loaded = false;
|
|
175
|
+
private filePath?: string;
|
|
176
|
+
private watchers: ConfigChangeCallback<T>[] = [];
|
|
177
|
+
private unwatch?: () => void;
|
|
178
|
+
|
|
179
|
+
constructor(options: ConfigManagerOptions<T> = {}) {
|
|
180
|
+
this.options = options;
|
|
181
|
+
this.config = (options.useDefaults !== false
|
|
182
|
+
? { ...DEFAULT_CONFIG }
|
|
183
|
+
: {}) as T;
|
|
184
|
+
|
|
185
|
+
// Apply initial config if provided
|
|
186
|
+
if (options.config) {
|
|
187
|
+
this.config = deepMerge(this.config, options.config) as T;
|
|
188
|
+
}
|
|
189
|
+
}
|
|
190
|
+
|
|
191
|
+
/**
|
|
192
|
+
* Load configuration from all sources
|
|
193
|
+
* Order: defaults → file config → env vars → CLI args → provided config
|
|
194
|
+
*/
|
|
195
|
+
async load(): Promise<T> {
|
|
196
|
+
// Load environment variables
|
|
197
|
+
if (this.options.loadEnv !== false) {
|
|
198
|
+
loadEnv();
|
|
199
|
+
}
|
|
200
|
+
|
|
201
|
+
// Load config file
|
|
202
|
+
const { config: fileConfig, filePath } = await loadConfig<T>({
|
|
203
|
+
configPath: this.options.configPath,
|
|
204
|
+
cwd: this.options.cwd,
|
|
205
|
+
});
|
|
206
|
+
|
|
207
|
+
this.filePath = filePath;
|
|
208
|
+
|
|
209
|
+
// Get environment config
|
|
210
|
+
const envConfig = getEnvConfig();
|
|
211
|
+
|
|
212
|
+
// Merge all sources
|
|
213
|
+
const merged = mergeConfigs(
|
|
214
|
+
{} as T,
|
|
215
|
+
this.options.useDefaults !== false ? DEFAULT_CONFIG : {} as T,
|
|
216
|
+
fileConfig as T,
|
|
217
|
+
envConfig as T,
|
|
218
|
+
this.options.config as T || {} as T,
|
|
219
|
+
);
|
|
220
|
+
|
|
221
|
+
this.config = merged as T;
|
|
222
|
+
|
|
223
|
+
// Validate if requested
|
|
224
|
+
if (this.options.validate !== false) {
|
|
225
|
+
await this.validate(this.options.schema);
|
|
226
|
+
}
|
|
227
|
+
|
|
228
|
+
this.loaded = true;
|
|
229
|
+
return this.config;
|
|
230
|
+
}
|
|
231
|
+
|
|
232
|
+
/**
|
|
233
|
+
* Get the entire configuration
|
|
234
|
+
*/
|
|
235
|
+
getAll(): T {
|
|
236
|
+
return { ...this.config } as T;
|
|
237
|
+
}
|
|
238
|
+
|
|
239
|
+
/**
|
|
240
|
+
* Get a configuration value using dot notation
|
|
241
|
+
* @example
|
|
242
|
+
* config.get('server.port') // 3000
|
|
243
|
+
* config.get('database.url') // 'postgresql://...'
|
|
244
|
+
*/
|
|
245
|
+
get<K extends keyof T>(key: K): T[K];
|
|
246
|
+
get<K extends string>(key: K): unknown;
|
|
247
|
+
get(key: string): unknown {
|
|
248
|
+
const parts = key.split(".");
|
|
249
|
+
let current: unknown = this.config;
|
|
250
|
+
|
|
251
|
+
for (const part of parts) {
|
|
252
|
+
if (current === null || current === undefined) {
|
|
253
|
+
return undefined;
|
|
254
|
+
}
|
|
255
|
+
if (typeof current !== "object") {
|
|
256
|
+
return undefined;
|
|
257
|
+
}
|
|
258
|
+
current = (current as Record<string, unknown>)[part];
|
|
259
|
+
}
|
|
260
|
+
|
|
261
|
+
return current;
|
|
262
|
+
}
|
|
263
|
+
|
|
264
|
+
/**
|
|
265
|
+
* Set a configuration value at runtime
|
|
266
|
+
* @example
|
|
267
|
+
* config.set('server.port', 4000)
|
|
268
|
+
*/
|
|
269
|
+
set<K extends keyof T>(key: K, value: T[K]): void;
|
|
270
|
+
set(key: string, value: unknown): void;
|
|
271
|
+
set(key: string, value: unknown): void {
|
|
272
|
+
const parts = key.split(".");
|
|
273
|
+
let current: Record<string, unknown> = this.config as Record<string, unknown>;
|
|
274
|
+
|
|
275
|
+
for (let i = 0; i < parts.length - 1; i++) {
|
|
276
|
+
const part = parts[i];
|
|
277
|
+
if (!(part in current)) {
|
|
278
|
+
current[part] = {};
|
|
279
|
+
}
|
|
280
|
+
current = current[part] as Record<string, unknown>;
|
|
281
|
+
}
|
|
282
|
+
|
|
283
|
+
current[parts[parts.length - 1]] = value;
|
|
284
|
+
|
|
285
|
+
// Notify watchers
|
|
286
|
+
this.notifyWatchers();
|
|
287
|
+
}
|
|
288
|
+
|
|
289
|
+
/**
|
|
290
|
+
* Check if a configuration key exists
|
|
291
|
+
*/
|
|
292
|
+
has(key: string): boolean {
|
|
293
|
+
return this.get(key) !== undefined;
|
|
294
|
+
}
|
|
295
|
+
|
|
296
|
+
/**
|
|
297
|
+
* Validate the current configuration
|
|
298
|
+
*/
|
|
299
|
+
async validate(schema?: StandardSchema<T>): Promise<ConfigValidationResult> {
|
|
300
|
+
const result = await validateConfig(this.config, schema);
|
|
301
|
+
|
|
302
|
+
if (!result.valid) {
|
|
303
|
+
const errors = result.errors
|
|
304
|
+
.map((e) => `${e.path ? e.path + ": " : ""}${e.message}`)
|
|
305
|
+
.join("\n");
|
|
306
|
+
throw new Error(`Configuration validation failed:\n${errors}`);
|
|
307
|
+
}
|
|
308
|
+
|
|
309
|
+
// Log warnings
|
|
310
|
+
for (const warning of result.warnings) {
|
|
311
|
+
console.warn(
|
|
312
|
+
`Config warning: ${warning.message}${warning.path ? ` (at ${warning.path})` : ""}`,
|
|
313
|
+
);
|
|
314
|
+
}
|
|
315
|
+
|
|
316
|
+
return result;
|
|
317
|
+
}
|
|
318
|
+
|
|
319
|
+
/**
|
|
320
|
+
* Validate synchronously (only default rules)
|
|
321
|
+
*/
|
|
322
|
+
validateSync(): ConfigValidationResult {
|
|
323
|
+
return validateConfigSync(this.config as unknown as DeepPartial<BuenoConfig>);
|
|
324
|
+
}
|
|
325
|
+
|
|
326
|
+
/**
|
|
327
|
+
* Watch for configuration changes
|
|
328
|
+
*/
|
|
329
|
+
watch(callback: ConfigChangeCallback<T>): () => void {
|
|
330
|
+
this.watchers.push(callback);
|
|
331
|
+
|
|
332
|
+
// Return unsubscribe function
|
|
333
|
+
return () => {
|
|
334
|
+
const index = this.watchers.indexOf(callback);
|
|
335
|
+
if (index !== -1) {
|
|
336
|
+
this.watchers.splice(index, 1);
|
|
337
|
+
}
|
|
338
|
+
};
|
|
339
|
+
}
|
|
340
|
+
|
|
341
|
+
/**
|
|
342
|
+
* Start watching the config file for changes
|
|
343
|
+
*/
|
|
344
|
+
async watchFile(): Promise<void> {
|
|
345
|
+
if (!this.filePath) {
|
|
346
|
+
this.filePath = await findConfigFile(this.options.cwd);
|
|
347
|
+
}
|
|
348
|
+
|
|
349
|
+
if (!this.filePath) {
|
|
350
|
+
return;
|
|
351
|
+
}
|
|
352
|
+
|
|
353
|
+
// Clear the cache to allow reloading
|
|
354
|
+
clearConfigCache();
|
|
355
|
+
|
|
356
|
+
// Set up polling for file changes
|
|
357
|
+
const { watchConfig } = await import("./loader");
|
|
358
|
+
this.unwatch = watchConfig(
|
|
359
|
+
this.filePath,
|
|
360
|
+
async () => {
|
|
361
|
+
await this.load();
|
|
362
|
+
},
|
|
363
|
+
{ debounce: 100 },
|
|
364
|
+
);
|
|
365
|
+
}
|
|
366
|
+
|
|
367
|
+
/**
|
|
368
|
+
* Stop watching the config file
|
|
369
|
+
*/
|
|
370
|
+
unwatchFile(): void {
|
|
371
|
+
if (this.unwatch) {
|
|
372
|
+
this.unwatch();
|
|
373
|
+
this.unwatch = undefined;
|
|
374
|
+
}
|
|
375
|
+
}
|
|
376
|
+
|
|
377
|
+
/**
|
|
378
|
+
* Check if config has been loaded
|
|
379
|
+
*/
|
|
380
|
+
isLoaded(): boolean {
|
|
381
|
+
return this.loaded;
|
|
382
|
+
}
|
|
383
|
+
|
|
384
|
+
/**
|
|
385
|
+
* Get the config file path
|
|
386
|
+
*/
|
|
387
|
+
getFilePath(): string | undefined {
|
|
388
|
+
return this.filePath;
|
|
389
|
+
}
|
|
390
|
+
|
|
391
|
+
/**
|
|
392
|
+
* Reset configuration to defaults
|
|
393
|
+
*/
|
|
394
|
+
reset(): void {
|
|
395
|
+
this.config = { ...DEFAULT_CONFIG } as T;
|
|
396
|
+
this.loaded = false;
|
|
397
|
+
this.notifyWatchers();
|
|
398
|
+
}
|
|
399
|
+
|
|
400
|
+
/**
|
|
401
|
+
* Merge additional configuration
|
|
402
|
+
*/
|
|
403
|
+
merge(config: DeepPartial<T>): void {
|
|
404
|
+
this.config = deepMerge(this.config, config) as T;
|
|
405
|
+
this.notifyWatchers();
|
|
406
|
+
}
|
|
407
|
+
|
|
408
|
+
/**
|
|
409
|
+
* Notify all watchers of a change
|
|
410
|
+
*/
|
|
411
|
+
private notifyWatchers(): void {
|
|
412
|
+
for (const watcher of this.watchers) {
|
|
413
|
+
try {
|
|
414
|
+
watcher(this.config);
|
|
415
|
+
} catch (error) {
|
|
416
|
+
console.error("Error in config watcher:", error);
|
|
417
|
+
}
|
|
418
|
+
}
|
|
419
|
+
}
|
|
420
|
+
}
|
|
421
|
+
|
|
422
|
+
/**
|
|
423
|
+
* Define configuration with type safety
|
|
424
|
+
* @example
|
|
425
|
+
* export default defineConfig({
|
|
426
|
+
* server: { port: 3000 },
|
|
427
|
+
* database: { url: process.env.DATABASE_URL },
|
|
428
|
+
* })
|
|
429
|
+
*/
|
|
430
|
+
export function defineConfig<T extends BuenoConfig = BuenoConfig>(
|
|
431
|
+
config: UserConfig<T>,
|
|
432
|
+
): UserConfig<T> {
|
|
433
|
+
return config;
|
|
434
|
+
}
|
|
435
|
+
|
|
436
|
+
/**
|
|
437
|
+
* Define configuration with a function
|
|
438
|
+
* @example
|
|
439
|
+
* export default defineConfigFn((env) => ({
|
|
440
|
+
* server: { port: env.PORT ? parseInt(env.PORT) : 3000 },
|
|
441
|
+
* }))
|
|
442
|
+
*/
|
|
443
|
+
export function defineConfigFn<T extends BuenoConfig = BuenoConfig>(
|
|
444
|
+
fn: UserConfigFn<T>,
|
|
445
|
+
): UserConfigFn<T> {
|
|
446
|
+
return fn;
|
|
447
|
+
}
|
|
448
|
+
|
|
449
|
+
/**
|
|
450
|
+
* Create a configuration manager
|
|
451
|
+
* @example
|
|
452
|
+
* const config = await createConfigManager();
|
|
453
|
+
* const port = config.get('server.port');
|
|
454
|
+
*/
|
|
455
|
+
export async function createConfigManager<
|
|
456
|
+
T extends BuenoConfig = BuenoConfig,
|
|
457
|
+
>(options?: ConfigManagerOptions<T>): Promise<ConfigManager<T>> {
|
|
458
|
+
const manager = new ConfigManager<T>(options);
|
|
459
|
+
await manager.load();
|
|
460
|
+
return manager;
|
|
461
|
+
}
|
|
462
|
+
|
|
463
|
+
/**
|
|
464
|
+
* Create a configuration manager without loading
|
|
465
|
+
* @example
|
|
466
|
+
* const config = createConfigManagerSync();
|
|
467
|
+
* // Later: await config.load();
|
|
468
|
+
*/
|
|
469
|
+
export function createConfigManagerSync<T extends BuenoConfig = BuenoConfig>(
|
|
470
|
+
options?: ConfigManagerOptions<T>,
|
|
471
|
+
): ConfigManager<T> {
|
|
472
|
+
return new ConfigManager<T>(options);
|
|
473
|
+
}
|
|
474
|
+
|
|
475
|
+
/**
|
|
476
|
+
* Load configuration and return the config object directly
|
|
477
|
+
* @example
|
|
478
|
+
* const config = await loadConfigDirect();
|
|
479
|
+
* console.log(config.server?.port);
|
|
480
|
+
*/
|
|
481
|
+
export async function loadConfigDirect<
|
|
482
|
+
T extends BuenoConfig = BuenoConfig,
|
|
483
|
+
>(options?: ConfigManagerOptions<T>): Promise<T> {
|
|
484
|
+
const manager = await createConfigManager<T>(options);
|
|
485
|
+
return manager.getAll();
|
|
486
|
+
}
|
|
487
|
+
|
|
488
|
+
// Singleton instance for convenience
|
|
489
|
+
let defaultManager: ConfigManager | undefined;
|
|
490
|
+
|
|
491
|
+
/**
|
|
492
|
+
* Get the default configuration manager
|
|
493
|
+
*/
|
|
494
|
+
export function getConfigManager(): ConfigManager {
|
|
495
|
+
if (!defaultManager) {
|
|
496
|
+
defaultManager = new ConfigManager();
|
|
497
|
+
}
|
|
498
|
+
return defaultManager;
|
|
499
|
+
}
|
|
500
|
+
|
|
501
|
+
/**
|
|
502
|
+
* Set the default configuration manager
|
|
503
|
+
*/
|
|
504
|
+
export function setConfigManager(manager: ConfigManager): void {
|
|
505
|
+
defaultManager = manager;
|
|
506
|
+
}
|