@fluojs/config 1.0.0-beta.4 → 1.0.0-beta.5
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.ko.md +2 -0
- package/README.md +2 -0
- package/dist/load.d.ts.map +1 -1
- package/dist/load.js +16 -6
- package/dist/module.d.ts.map +1 -1
- package/dist/module.js +4 -2
- package/dist/options.d.ts +16 -0
- package/dist/options.d.ts.map +1 -0
- package/dist/options.js +51 -0
- package/dist/reload-module.d.ts.map +1 -1
- package/dist/reload-module.js +2 -1
- package/package.json +2 -2
package/README.ko.md
CHANGED
|
@@ -91,6 +91,8 @@ class MyService {
|
|
|
91
91
|
|
|
92
92
|
`ConfigReloadManager.reload()`는 리로드 작업을 직렬화합니다. 현재 리로드가 listener 알림을 수행하는 동안 다른 리로드가 요청되면 후속 리로드는 큐에 들어가 활성 알림이 끝난 뒤 적용됩니다. 활성 알림이 실패하면 이전 snapshot을 복구하고 큐에 있던 리로드는 폐기합니다. 동일한 직렬화와 rollback 계약은 `createConfigReloader(...).reload()`에도 적용되며, watch로 시작된 알림 중 큐에 들어간 manual reload도 이 계약을 따릅니다.
|
|
93
93
|
|
|
94
|
+
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가 트리거될 수 있습니다.
|
|
95
|
+
|
|
94
96
|
## 공개 API
|
|
95
97
|
|
|
96
98
|
| 클래스/헬퍼 | 설명 |
|
package/README.md
CHANGED
|
@@ -95,6 +95,8 @@ The `schema` option accepts a synchronous [Standard Schema](https://standardsche
|
|
|
95
95
|
|
|
96
96
|
`ConfigReloadManager.reload()` serializes reload work. If another reload is requested while the current reload is notifying listeners, the follow-up reload is queued and applied after the active notification finishes; if the active notification fails, the previous snapshot is restored and the queued reload is discarded. The same serialization and rollback contract applies to `createConfigReloader(...).reload()`, including manual reloads queued during watch-triggered notifications.
|
|
97
97
|
|
|
98
|
+
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.
|
|
99
|
+
|
|
98
100
|
## Public API
|
|
99
101
|
|
|
100
102
|
| Class/Helper | Description |
|
package/dist/load.d.ts.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"load.d.ts","sourceRoot":"","sources":["../src/load.ts"],"names":[],"mappings":"
|
|
1
|
+
{"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"}
|
package/dist/load.js
CHANGED
|
@@ -1,9 +1,10 @@
|
|
|
1
1
|
import { existsSync, readFileSync, watch } from 'node:fs';
|
|
2
|
-
import { join } from 'node:path';
|
|
2
|
+
import { basename, dirname, join } from 'node:path';
|
|
3
3
|
import { FluoError } from '@fluojs/core';
|
|
4
4
|
import { parse as dotenvParse } from 'dotenv';
|
|
5
5
|
import { expand as dotenvExpand } from 'dotenv-expand';
|
|
6
6
|
import { cloneConfigDictionary } from './clone.js';
|
|
7
|
+
import { snapshotConfigLoadOptions } from './options.js';
|
|
7
8
|
const reloadFailureReasons = new WeakMap();
|
|
8
9
|
function markReloadFailure(error, reason) {
|
|
9
10
|
if (typeof error === 'object' && error !== null) {
|
|
@@ -226,12 +227,20 @@ function applyReload(normalized, state, listeners, reason) {
|
|
|
226
227
|
}
|
|
227
228
|
}
|
|
228
229
|
function startReloaderWatcher(normalized, options, state, listeners, errorListeners) {
|
|
229
|
-
if (!options.watch
|
|
230
|
+
if (!options.watch) {
|
|
230
231
|
return undefined;
|
|
231
232
|
}
|
|
232
|
-
|
|
233
|
+
const watchTarget = existsSync(normalized.envFile) ? normalized.envFile : dirname(normalized.envFile);
|
|
234
|
+
const watchedEnvFileName = basename(normalized.envFile);
|
|
235
|
+
if (!existsSync(watchTarget)) {
|
|
236
|
+
return undefined;
|
|
237
|
+
}
|
|
238
|
+
return watch(watchTarget, {
|
|
233
239
|
persistent: false
|
|
234
|
-
}, () => {
|
|
240
|
+
}, (_eventType, filename) => {
|
|
241
|
+
if (watchTarget !== normalized.envFile && filename !== null && filename.toString() !== watchedEnvFileName) {
|
|
242
|
+
return;
|
|
243
|
+
}
|
|
235
244
|
try {
|
|
236
245
|
applyReload(normalized, state, listeners, 'watch');
|
|
237
246
|
} catch (error) {
|
|
@@ -269,7 +278,8 @@ function closeReloader(state, listeners, errorListeners) {
|
|
|
269
278
|
* ```
|
|
270
279
|
*/
|
|
271
280
|
export function createConfigReloader(options) {
|
|
272
|
-
const
|
|
281
|
+
const loadOptions = snapshotConfigLoadOptions(options);
|
|
282
|
+
const normalized = normalizeLoadOptions(loadOptions);
|
|
273
283
|
const state = {
|
|
274
284
|
current: resolveConfig(normalized),
|
|
275
285
|
pendingReloadReason: undefined,
|
|
@@ -278,7 +288,7 @@ export function createConfigReloader(options) {
|
|
|
278
288
|
};
|
|
279
289
|
const listeners = new Set();
|
|
280
290
|
const errorListeners = new Set();
|
|
281
|
-
state.watcher = startReloaderWatcher(normalized,
|
|
291
|
+
state.watcher = startReloaderWatcher(normalized, loadOptions, state, listeners, errorListeners);
|
|
282
292
|
return {
|
|
283
293
|
close() {
|
|
284
294
|
closeReloader(state, listeners, errorListeners);
|
package/dist/module.d.ts.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"module.d.ts","sourceRoot":"","sources":["../src/module.ts"],"names":[],"mappings":"
|
|
1
|
+
{"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"}
|
package/dist/module.js
CHANGED
|
@@ -1,5 +1,6 @@
|
|
|
1
1
|
import { defineModuleMetadata } from '@fluojs/core/internal';
|
|
2
2
|
import { loadConfig } from './load.js';
|
|
3
|
+
import { snapshotConfigModuleOptions } from './options.js';
|
|
3
4
|
import { ConfigService, createConfigServiceFromSnapshot } from './service.js';
|
|
4
5
|
/**
|
|
5
6
|
* Module facade that wires normalized configuration into the application container.
|
|
@@ -25,13 +26,14 @@ export class ConfigModule {
|
|
|
25
26
|
* ```
|
|
26
27
|
*/
|
|
27
28
|
static forRoot(options) {
|
|
29
|
+
const loadOptions = snapshotConfigModuleOptions(options);
|
|
28
30
|
class ConfigModuleImpl extends ConfigModule {}
|
|
29
31
|
defineModuleMetadata(ConfigModuleImpl, {
|
|
30
|
-
global:
|
|
32
|
+
global: loadOptions.isGlobal ?? true,
|
|
31
33
|
exports: [ConfigService],
|
|
32
34
|
providers: [{
|
|
33
35
|
provide: ConfigService,
|
|
34
|
-
useFactory: () => createConfigServiceFromSnapshot(loadConfig(
|
|
36
|
+
useFactory: () => createConfigServiceFromSnapshot(loadConfig(loadOptions))
|
|
35
37
|
}]
|
|
36
38
|
});
|
|
37
39
|
return ConfigModuleImpl;
|
|
@@ -0,0 +1,16 @@
|
|
|
1
|
+
import type { ConfigLoadOptions, ConfigModuleOptions } from './types.js';
|
|
2
|
+
/**
|
|
3
|
+
* Creates a detached snapshot of config module registration options.
|
|
4
|
+
*
|
|
5
|
+
* @param options Caller-owned module options captured at registration time.
|
|
6
|
+
* @returns Options that cannot observe later caller mutations of config dictionaries.
|
|
7
|
+
*/
|
|
8
|
+
export declare function snapshotConfigModuleOptions(options?: ConfigModuleOptions): ConfigModuleOptions;
|
|
9
|
+
/**
|
|
10
|
+
* Creates a detached snapshot of config load and reload options.
|
|
11
|
+
*
|
|
12
|
+
* @param options Caller-owned load options captured by loaders or reload modules.
|
|
13
|
+
* @returns Options that preserve registration-time config dictionary inputs.
|
|
14
|
+
*/
|
|
15
|
+
export declare function snapshotConfigLoadOptions(options?: ConfigLoadOptions): ConfigLoadOptions;
|
|
16
|
+
//# sourceMappingURL=options.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"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"}
|
package/dist/options.js
ADDED
|
@@ -0,0 +1,51 @@
|
|
|
1
|
+
import { cloneConfigDictionary } from './clone.js';
|
|
2
|
+
function snapshotConfigDictionary(value) {
|
|
3
|
+
return value === undefined ? undefined : cloneConfigDictionary(value);
|
|
4
|
+
}
|
|
5
|
+
function snapshotProcessEnv(processEnv) {
|
|
6
|
+
if (processEnv === undefined) {
|
|
7
|
+
return undefined;
|
|
8
|
+
}
|
|
9
|
+
const snapshot = {};
|
|
10
|
+
for (const [key, value] of Object.entries(processEnv)) {
|
|
11
|
+
if (value !== undefined) {
|
|
12
|
+
snapshot[key] = value;
|
|
13
|
+
}
|
|
14
|
+
}
|
|
15
|
+
return Object.freeze(snapshot);
|
|
16
|
+
}
|
|
17
|
+
|
|
18
|
+
/**
|
|
19
|
+
* Creates a detached snapshot of config module registration options.
|
|
20
|
+
*
|
|
21
|
+
* @param options Caller-owned module options captured at registration time.
|
|
22
|
+
* @returns Options that cannot observe later caller mutations of config dictionaries.
|
|
23
|
+
*/
|
|
24
|
+
export function snapshotConfigModuleOptions(options) {
|
|
25
|
+
if (options === undefined) {
|
|
26
|
+
return {};
|
|
27
|
+
}
|
|
28
|
+
return Object.freeze({
|
|
29
|
+
...options,
|
|
30
|
+
defaults: snapshotConfigDictionary(options.defaults),
|
|
31
|
+
processEnv: snapshotProcessEnv(options.processEnv)
|
|
32
|
+
});
|
|
33
|
+
}
|
|
34
|
+
|
|
35
|
+
/**
|
|
36
|
+
* Creates a detached snapshot of config load and reload options.
|
|
37
|
+
*
|
|
38
|
+
* @param options Caller-owned load options captured by loaders or reload modules.
|
|
39
|
+
* @returns Options that preserve registration-time config dictionary inputs.
|
|
40
|
+
*/
|
|
41
|
+
export function snapshotConfigLoadOptions(options) {
|
|
42
|
+
if (options === undefined) {
|
|
43
|
+
return {};
|
|
44
|
+
}
|
|
45
|
+
return Object.freeze({
|
|
46
|
+
...options,
|
|
47
|
+
defaults: snapshotConfigDictionary(options.defaults),
|
|
48
|
+
processEnv: snapshotProcessEnv(options.processEnv),
|
|
49
|
+
runtimeOverrides: snapshotConfigDictionary(options.runtimeOverrides)
|
|
50
|
+
});
|
|
51
|
+
}
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"reload-module.d.ts","sourceRoot":"","sources":["../src/reload-module.ts"],"names":[],"mappings":"
|
|
1
|
+
{"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"}
|
package/dist/reload-module.js
CHANGED
|
@@ -8,6 +8,7 @@ import { Inject } from '@fluojs/core';
|
|
|
8
8
|
import { defineModuleMetadata } from '@fluojs/core/internal';
|
|
9
9
|
import { cloneConfigDictionary } from './clone.js';
|
|
10
10
|
import { createConfigReloader } from './load.js';
|
|
11
|
+
import { snapshotConfigLoadOptions } from './options.js';
|
|
11
12
|
import { ConfigService, replaceConfigServiceSnapshotUnchecked } from './service.js';
|
|
12
13
|
const CONFIG_RELOAD_OPTIONS = Symbol('fluo.config.reload-options');
|
|
13
14
|
|
|
@@ -110,7 +111,7 @@ class ConfigReloadManager {
|
|
|
110
111
|
export { _ConfigReloadManager as ConfigReloadManager };
|
|
111
112
|
export class ConfigReloadModule {
|
|
112
113
|
static forRoot(options) {
|
|
113
|
-
const loadOptions = options
|
|
114
|
+
const loadOptions = snapshotConfigLoadOptions(options);
|
|
114
115
|
class ConfigReloadModuleImpl extends ConfigReloadModule {}
|
|
115
116
|
defineModuleMetadata(ConfigReloadModuleImpl, {
|
|
116
117
|
exports: [CONFIG_RELOADER],
|
package/package.json
CHANGED
|
@@ -8,7 +8,7 @@
|
|
|
8
8
|
"environment",
|
|
9
9
|
"typed-config"
|
|
10
10
|
],
|
|
11
|
-
"version": "1.0.0-beta.
|
|
11
|
+
"version": "1.0.0-beta.5",
|
|
12
12
|
"private": false,
|
|
13
13
|
"license": "MIT",
|
|
14
14
|
"repository": {
|
|
@@ -38,7 +38,7 @@
|
|
|
38
38
|
"@standard-schema/spec": "^1.1.0",
|
|
39
39
|
"dotenv": "^16.0.0",
|
|
40
40
|
"dotenv-expand": "^11.0.0",
|
|
41
|
-
"@fluojs/core": "^1.0.0-beta.
|
|
41
|
+
"@fluojs/core": "^1.0.0-beta.3"
|
|
42
42
|
},
|
|
43
43
|
"devDependencies": {
|
|
44
44
|
"vitest": "^3.2.4"
|