@fluojs/config
Advanced tools
| import type { ConfigLoadOptions, ConfigModuleOptions } from './types.js'; | ||
| /** | ||
| * Creates a detached snapshot of config module registration options. | ||
| * | ||
| * @param options Caller-owned module options captured at registration time. | ||
| * @returns Options that cannot observe later caller mutations of config dictionaries. | ||
| */ | ||
| export declare function snapshotConfigModuleOptions(options?: ConfigModuleOptions): ConfigModuleOptions; | ||
| /** | ||
| * Creates a detached snapshot of config load and reload options. | ||
| * | ||
| * @param options Caller-owned load options captured by loaders or reload modules. | ||
| * @returns Options that preserve registration-time config dictionary inputs. | ||
| */ | ||
| export declare function snapshotConfigLoadOptions(options?: ConfigLoadOptions): ConfigLoadOptions; | ||
| //# sourceMappingURL=options.d.ts.map |
| {"version":3,"file":"options.d.ts","sourceRoot":"","sources":["../src/options.ts"],"names":[],"mappings":"AACA,OAAO,KAAK,EAAoB,iBAAiB,EAAE,mBAAmB,EAAE,MAAM,YAAY,CAAC;AAsB3F;;;;;GAKG;AACH,wBAAgB,2BAA2B,CAAC,OAAO,CAAC,EAAE,mBAAmB,GAAG,mBAAmB,CAU9F;AAED;;;;;GAKG;AACH,wBAAgB,yBAAyB,CAAC,OAAO,CAAC,EAAE,iBAAiB,GAAG,iBAAiB,CAWxF"} |
| import { cloneConfigDictionary } from './clone.js'; | ||
| function snapshotConfigDictionary(value) { | ||
| return value === undefined ? undefined : cloneConfigDictionary(value); | ||
| } | ||
| function snapshotProcessEnv(processEnv) { | ||
| if (processEnv === undefined) { | ||
| return undefined; | ||
| } | ||
| const snapshot = {}; | ||
| for (const [key, value] of Object.entries(processEnv)) { | ||
| if (value !== undefined) { | ||
| snapshot[key] = value; | ||
| } | ||
| } | ||
| return Object.freeze(snapshot); | ||
| } | ||
| /** | ||
| * Creates a detached snapshot of config module registration options. | ||
| * | ||
| * @param options Caller-owned module options captured at registration time. | ||
| * @returns Options that cannot observe later caller mutations of config dictionaries. | ||
| */ | ||
| export function snapshotConfigModuleOptions(options) { | ||
| if (options === undefined) { | ||
| return {}; | ||
| } | ||
| return Object.freeze({ | ||
| ...options, | ||
| defaults: snapshotConfigDictionary(options.defaults), | ||
| processEnv: snapshotProcessEnv(options.processEnv) | ||
| }); | ||
| } | ||
| /** | ||
| * Creates a detached snapshot of config load and reload options. | ||
| * | ||
| * @param options Caller-owned load options captured by loaders or reload modules. | ||
| * @returns Options that preserve registration-time config dictionary inputs. | ||
| */ | ||
| export function snapshotConfigLoadOptions(options) { | ||
| if (options === undefined) { | ||
| return {}; | ||
| } | ||
| return Object.freeze({ | ||
| ...options, | ||
| defaults: snapshotConfigDictionary(options.defaults), | ||
| processEnv: snapshotProcessEnv(options.processEnv), | ||
| runtimeOverrides: snapshotConfigDictionary(options.runtimeOverrides) | ||
| }); | ||
| } |
@@ -1,1 +0,1 @@ | ||
| {"version":3,"file":"load.d.ts","sourceRoot":"","sources":["../src/load.ts"],"names":[],"mappings":"AASA,OAAO,KAAK,EACV,gBAAgB,EAChB,iBAAiB,EAEjB,cAAc,EAKf,MAAM,YAAY,CAAC;AA0XpB;;;;;;;;;;;;;;;;;;;GAmBG;AACH,wBAAgB,oBAAoB,CAAC,OAAO,EAAE,iBAAiB,GAAG,cAAc,CA8B/E;AAED;;;;;;;;GAQG;AACH,wBAAgB,UAAU,CAAC,OAAO,EAAE,iBAAiB,GAAG,gBAAgB,CAEvE"} | ||
| {"version":3,"file":"load.d.ts","sourceRoot":"","sources":["../src/load.ts"],"names":[],"mappings":"AAUA,OAAO,KAAK,EACV,gBAAgB,EAChB,iBAAiB,EAEjB,cAAc,EAKf,MAAM,YAAY,CAAC;AAqYpB;;;;;;;;;;;;;;;;;;;GAmBG;AACH,wBAAgB,oBAAoB,CAAC,OAAO,EAAE,iBAAiB,GAAG,cAAc,CA+B/E;AAED;;;;;;;;GAQG;AACH,wBAAgB,UAAU,CAAC,OAAO,EAAE,iBAAiB,GAAG,gBAAgB,CAEvE"} |
+16
-6
| import { existsSync, readFileSync, watch } from 'node:fs'; | ||
| import { join } from 'node:path'; | ||
| import { basename, dirname, join } from 'node:path'; | ||
| import { FluoError } from '@fluojs/core'; | ||
@@ -7,2 +7,3 @@ import { parse as dotenvParse } from 'dotenv'; | ||
| import { cloneConfigDictionary } from './clone.js'; | ||
| import { snapshotConfigLoadOptions } from './options.js'; | ||
| const reloadFailureReasons = new WeakMap(); | ||
@@ -230,8 +231,16 @@ function markReloadFailure(error, reason) { | ||
| function startReloaderWatcher(normalized, options, state, listeners, errorListeners) { | ||
| if (!options.watch || !existsSync(normalized.envFile)) { | ||
| if (!options.watch) { | ||
| return undefined; | ||
| } | ||
| return watch(normalized.envFile, { | ||
| const watchTarget = existsSync(normalized.envFile) ? normalized.envFile : dirname(normalized.envFile); | ||
| const watchedEnvFileName = basename(normalized.envFile); | ||
| if (!existsSync(watchTarget)) { | ||
| return undefined; | ||
| } | ||
| return watch(watchTarget, { | ||
| persistent: false | ||
| }, () => { | ||
| }, (_eventType, filename) => { | ||
| if (watchTarget !== normalized.envFile && filename !== null && filename.toString() !== watchedEnvFileName) { | ||
| return; | ||
| } | ||
| try { | ||
@@ -274,3 +283,4 @@ applyReload(normalized, state, listeners, 'watch'); | ||
| export function createConfigReloader(options) { | ||
| const normalized = normalizeLoadOptions(options); | ||
| const loadOptions = snapshotConfigLoadOptions(options); | ||
| const normalized = normalizeLoadOptions(loadOptions); | ||
| const state = { | ||
@@ -284,3 +294,3 @@ current: resolveConfig(normalized), | ||
| const errorListeners = new Set(); | ||
| state.watcher = startReloaderWatcher(normalized, options, state, listeners, errorListeners); | ||
| state.watcher = startReloaderWatcher(normalized, loadOptions, state, listeners, errorListeners); | ||
| return { | ||
@@ -287,0 +297,0 @@ close() { |
@@ -1,1 +0,1 @@ | ||
| {"version":3,"file":"module.d.ts","sourceRoot":"","sources":["../src/module.ts"],"names":[],"mappings":"AAIA,OAAO,KAAK,EAAE,mBAAmB,EAAE,MAAM,YAAY,CAAC;AAEtD;;GAEG;AACH,qBAAa,YAAY;IACvB;;;;;;;;;;;;;;;;;;OAkBG;IACH,MAAM,CAAC,OAAO,CAAC,OAAO,CAAC,EAAE,mBAAmB,GAAG,UAAU,YAAY;CAgBtE"} | ||
| {"version":3,"file":"module.d.ts","sourceRoot":"","sources":["../src/module.ts"],"names":[],"mappings":"AAKA,OAAO,KAAK,EAAE,mBAAmB,EAAE,MAAM,YAAY,CAAC;AAEtD;;GAEG;AACH,qBAAa,YAAY;IACvB;;;;;;;;;;;;;;;;;;OAkBG;IACH,MAAM,CAAC,OAAO,CAAC,OAAO,CAAC,EAAE,mBAAmB,GAAG,UAAU,YAAY;CAiBtE"} |
+4
-2
| import { defineModuleMetadata } from '@fluojs/core/internal'; | ||
| import { loadConfig } from './load.js'; | ||
| import { snapshotConfigModuleOptions } from './options.js'; | ||
| import { ConfigService, createConfigServiceFromSnapshot } from './service.js'; | ||
@@ -28,9 +29,10 @@ /** | ||
| static forRoot(options) { | ||
| const loadOptions = snapshotConfigModuleOptions(options); | ||
| class ConfigModuleImpl extends ConfigModule {} | ||
| defineModuleMetadata(ConfigModuleImpl, { | ||
| global: options?.isGlobal ?? true, | ||
| global: loadOptions.isGlobal ?? true, | ||
| exports: [ConfigService], | ||
| providers: [{ | ||
| provide: ConfigService, | ||
| useFactory: () => createConfigServiceFromSnapshot(loadConfig(options ?? {})) | ||
| useFactory: () => createConfigServiceFromSnapshot(loadConfig(loadOptions)) | ||
| }] | ||
@@ -37,0 +39,0 @@ }); |
@@ -1,1 +0,1 @@ | ||
| {"version":3,"file":"reload-module.d.ts","sourceRoot":"","sources":["../src/reload-module.ts"],"names":[],"mappings":"AAKA,OAAO,EACL,aAAa,EAEd,MAAM,cAAc,CAAC;AACtB,OAAO,KAAK,EACV,gBAAgB,EAChB,iBAAiB,EACjB,yBAAyB,EACzB,cAAc,EACd,oBAAoB,EACpB,wBAAwB,EACzB,MAAM,YAAY,CAAC;AAIpB;;GAEG;AACH,eAAO,MAAM,eAAe,eAAiC,CAAC;AAY9D;;GAEG;AACH,qBACa,mBAAoB,YAAW,cAAc;IAQtD,OAAO,CAAC,QAAQ,CAAC,MAAM;IACvB,OAAO,CAAC,QAAQ,CAAC,OAAO;IAR1B,OAAO,CAAC,QAAQ,CAA6B;IAC7C,OAAO,CAAC,eAAe,CAAuC;IAC9D,OAAO,CAAC,cAAc,CAAuC;IAC7D,OAAO,CAAC,QAAQ,CAAC,eAAe,CAAmC;IACnE,OAAO,CAAC,QAAQ,CAAC,cAAc,CAAwC;gBAGpD,MAAM,EAAE,aAAa,EACrB,OAAO,EAAE,iBAAiB;IAG7C,OAAO,IAAI,gBAAgB;IAI3B,MAAM,IAAI,gBAAgB;IAI1B,SAAS,CAAC,QAAQ,EAAE,oBAAoB,GAAG,wBAAwB;IAInE,cAAc,CAAC,QAAQ,EAAE,yBAAyB,GAAG,wBAAwB;IAI7E,KAAK,IAAI,IAAI;IAeb,sBAAsB,IAAI,IAAI;IAQ9B,eAAe,IAAI,IAAI;IAIvB,OAAO,CAAC,cAAc;CA8BvB;AAED;;GAEG;AACH,qBAAa,kBAAkB;IAC7B,MAAM,CAAC,OAAO,CAAC,OAAO,CAAC,EAAE,iBAAiB,GAAG,UAAU,kBAAkB;CAsB1E"} | ||
| {"version":3,"file":"reload-module.d.ts","sourceRoot":"","sources":["../src/reload-module.ts"],"names":[],"mappings":"AAMA,OAAO,EACL,aAAa,EAEd,MAAM,cAAc,CAAC;AACtB,OAAO,KAAK,EACV,gBAAgB,EAChB,iBAAiB,EACjB,yBAAyB,EACzB,cAAc,EACd,oBAAoB,EACpB,wBAAwB,EACzB,MAAM,YAAY,CAAC;AAIpB;;GAEG;AACH,eAAO,MAAM,eAAe,eAAiC,CAAC;AAY9D;;GAEG;AACH,qBACa,mBAAoB,YAAW,cAAc;IAQtD,OAAO,CAAC,QAAQ,CAAC,MAAM;IACvB,OAAO,CAAC,QAAQ,CAAC,OAAO;IAR1B,OAAO,CAAC,QAAQ,CAA6B;IAC7C,OAAO,CAAC,eAAe,CAAuC;IAC9D,OAAO,CAAC,cAAc,CAAuC;IAC7D,OAAO,CAAC,QAAQ,CAAC,eAAe,CAAmC;IACnE,OAAO,CAAC,QAAQ,CAAC,cAAc,CAAwC;gBAGpD,MAAM,EAAE,aAAa,EACrB,OAAO,EAAE,iBAAiB;IAG7C,OAAO,IAAI,gBAAgB;IAI3B,MAAM,IAAI,gBAAgB;IAI1B,SAAS,CAAC,QAAQ,EAAE,oBAAoB,GAAG,wBAAwB;IAInE,cAAc,CAAC,QAAQ,EAAE,yBAAyB,GAAG,wBAAwB;IAI7E,KAAK,IAAI,IAAI;IAeb,sBAAsB,IAAI,IAAI;IAQ9B,eAAe,IAAI,IAAI;IAIvB,OAAO,CAAC,cAAc;CA8BvB;AAED;;GAEG;AACH,qBAAa,kBAAkB;IAC7B,MAAM,CAAC,OAAO,CAAC,OAAO,CAAC,EAAE,iBAAiB,GAAG,UAAU,kBAAkB;CAsB1E"} |
@@ -11,2 +11,3 @@ let _initClass; | ||
| import { createConfigReloader } from './load.js'; | ||
| import { snapshotConfigLoadOptions } from './options.js'; | ||
| import { ConfigService, replaceConfigServiceSnapshotUnchecked } from './service.js'; | ||
@@ -114,3 +115,3 @@ const CONFIG_RELOAD_OPTIONS = Symbol('fluo.config.reload-options'); | ||
| static forRoot(options) { | ||
| const loadOptions = options ?? {}; | ||
| const loadOptions = snapshotConfigLoadOptions(options); | ||
| class ConfigReloadModuleImpl extends ConfigReloadModule {} | ||
@@ -117,0 +118,0 @@ defineModuleMetadata(ConfigReloadModuleImpl, { |
+2
-2
@@ -11,3 +11,3 @@ { | ||
| ], | ||
| "version": "1.0.0-beta.4", | ||
| "version": "1.0.0-beta.5", | ||
| "private": false, | ||
@@ -42,3 +42,3 @@ "license": "MIT", | ||
| "dotenv-expand": "^11.0.0", | ||
| "@fluojs/core": "^1.0.0-beta.2" | ||
| "@fluojs/core": "^1.0.0-beta.3" | ||
| }, | ||
@@ -45,0 +45,0 @@ "devDependencies": { |
+2
-0
@@ -94,2 +94,4 @@ # @fluojs/config | ||
| Module registration과 reloader 생성은 caller-owned options를 저장하기 전에 snapshot으로 분리합니다. `ConfigModule.forRoot(...)`, `ConfigReloadModule.forRoot(...)`, `createConfigReloader(...)`에 넘긴 객체를 나중에 변경해도 bootstrap, manual reload, watch reload 입력은 바뀌지 않습니다. Watch mode에서 시작 시점에 env file이 없으면 빈 file snapshot처럼 취급하고 parent directory를 watch하므로, 나중에 env file을 생성해도 reload가 트리거될 수 있습니다. | ||
| ## 공개 API | ||
@@ -96,0 +98,0 @@ |
+2
-0
@@ -98,2 +98,4 @@ # @fluojs/config | ||
| Module registration and reloader creation snapshot caller-owned options before storing them. Later mutations to objects passed to `ConfigModule.forRoot(...)`, `ConfigReloadModule.forRoot(...)`, or `createConfigReloader(...)` do not affect bootstrap, manual reloads, or watch reloads. In watch mode, a missing env file at startup is treated as an empty file snapshot while the parent directory is watched so creating the env file later can still trigger reload. | ||
| ## Public API | ||
@@ -100,0 +102,0 @@ |
55742
8.46%28
12%896
9.27%124
1.64%Updated