@zucker-framework/config 1.0.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/dist/index.mjs ADDED
@@ -0,0 +1,1265 @@
1
+ var __defProp = Object.defineProperty;
2
+ var __name = (target, value) => __defProp(target, "name", { value, configurable: true });
3
+
4
+ // src/config.service.ts
5
+ import { Injectable as Injectable2, Inject, Logger as Logger2, Optional } from "@nestjs/common";
6
+ import { ValidationException } from "@zucker-framework/core";
7
+ import { EventEmitter2 } from "eventemitter2";
8
+
9
+ // src/config-scope-manager.ts
10
+ import { Injectable, Logger } from "@nestjs/common";
11
+ function _ts_decorate(decorators, target, key, desc) {
12
+ var c = arguments.length, r = c < 3 ? target : desc === null ? desc = Object.getOwnPropertyDescriptor(target, key) : desc, d;
13
+ if (typeof Reflect === "object" && typeof Reflect.decorate === "function") {
14
+ r = Reflect.decorate(decorators, target, key, desc);
15
+ } else {
16
+ for (var i = decorators.length - 1; i >= 0; i--) {
17
+ if (d = decorators[i]) {
18
+ r = (c < 3 ? d(r) : c > 3 ? d(target, key, r) : d(target, key)) || r;
19
+ }
20
+ }
21
+ }
22
+ return c > 3 && r && Object.defineProperty(target, key, r), r;
23
+ }
24
+ __name(_ts_decorate, "_ts_decorate");
25
+ var ConfigScopeManager = class _ConfigScopeManager {
26
+ static {
27
+ __name(this, "ConfigScopeManager");
28
+ }
29
+ logger = new Logger(_ConfigScopeManager.name);
30
+ scopes = /* @__PURE__ */ new Map();
31
+ /**
32
+ * Register a fully defined scope.
33
+ */
34
+ register(scope) {
35
+ this.scopes.set(scope.id, scope);
36
+ this.logger.debug(`Config scope registered: ${scope.id} (${scope.name})`);
37
+ }
38
+ /**
39
+ * Add a scope with separate property definitions — mirrors jetlinks ConfigScopeManager.addScope().
40
+ *
41
+ * Reference: jetlinks ConfigScopeManager.addScope(ConfigScope, List<ConfigPropertyDef>)
42
+ */
43
+ addScope(scopePartial, properties) {
44
+ const existing = this.scopes.get(scopePartial.id);
45
+ if (existing) {
46
+ const existingKeys = new Set(existing.properties.map((p) => p.key));
47
+ for (const prop of properties) {
48
+ if (!existingKeys.has(prop.key)) {
49
+ existing.properties.push(prop);
50
+ existingKeys.add(prop.key);
51
+ }
52
+ }
53
+ return;
54
+ }
55
+ const scope = {
56
+ id: scopePartial.id,
57
+ name: scopePartial.name,
58
+ isPublic: scopePartial.publicAccess ?? false,
59
+ publicAccess: scopePartial.publicAccess ?? false,
60
+ properties
61
+ };
62
+ this.scopes.set(scope.id, scope);
63
+ this.logger.debug(`Config scope added: ${scope.id} (${scope.name})`);
64
+ }
65
+ /**
66
+ * Apply customizers — call during module initialization.
67
+ *
68
+ * Reference: jetlinks ConfigScopeProperties.custom()
69
+ */
70
+ applyCustomizers(customizers) {
71
+ for (const customizer of customizers) {
72
+ customizer.custom(this);
73
+ }
74
+ }
75
+ get(scopeId) {
76
+ return this.scopes.get(scopeId);
77
+ }
78
+ getAll() {
79
+ return Array.from(this.scopes.values());
80
+ }
81
+ has(scopeId) {
82
+ return this.scopes.has(scopeId);
83
+ }
84
+ unregister(scopeId) {
85
+ return this.scopes.delete(scopeId);
86
+ }
87
+ /**
88
+ * Get all scopes marked as public access.
89
+ *
90
+ * Reference: jetlinks SystemConfigManagerController checks isPublicAccess()
91
+ * for unauthenticated access.
92
+ */
93
+ getPublicScopes() {
94
+ return Array.from(this.scopes.values()).filter((s) => s.publicAccess);
95
+ }
96
+ getProperties(scopeId) {
97
+ return this.scopes.get(scopeId)?.properties ?? [];
98
+ }
99
+ /**
100
+ * Validate a config value against its scope property definition.
101
+ * Returns error messages if invalid.
102
+ */
103
+ validate(scopeId, key, value) {
104
+ const scope = this.scopes.get(scopeId);
105
+ if (!scope) return [
106
+ `Unknown scope: ${scopeId}`
107
+ ];
108
+ const prop = scope.properties.find((p) => p.key === key);
109
+ if (!prop) return [
110
+ `Unknown property: ${key} in scope ${scopeId}`
111
+ ];
112
+ const errors = [];
113
+ if (prop.readonly) {
114
+ errors.push(`Property ${key} is read-only`);
115
+ }
116
+ if (value === null || value === void 0) {
117
+ return errors;
118
+ }
119
+ const actualType = typeof value;
120
+ switch (prop.type) {
121
+ case "string":
122
+ if (actualType !== "string") errors.push(`Expected string for ${key}, got ${actualType}`);
123
+ break;
124
+ case "number":
125
+ if (actualType !== "number") errors.push(`Expected number for ${key}, got ${actualType}`);
126
+ break;
127
+ case "boolean":
128
+ if (actualType !== "boolean") errors.push(`Expected boolean for ${key}, got ${actualType}`);
129
+ break;
130
+ case "json":
131
+ case "object":
132
+ if (actualType !== "object") errors.push(`Expected object for ${key}, got ${actualType}`);
133
+ break;
134
+ case "password":
135
+ case "encrypted":
136
+ if (actualType !== "string") errors.push(`Expected string for encrypted ${key}, got ${actualType}`);
137
+ break;
138
+ }
139
+ return errors;
140
+ }
141
+ };
142
+ ConfigScopeManager = _ts_decorate([
143
+ Injectable()
144
+ ], ConfigScopeManager);
145
+
146
+ // src/config.service.ts
147
+ import { DATABASE_ADAPTER } from "@zucker-framework/crud";
148
+ function _ts_decorate2(decorators, target, key, desc) {
149
+ var c = arguments.length, r = c < 3 ? target : desc === null ? desc = Object.getOwnPropertyDescriptor(target, key) : desc, d;
150
+ if (typeof Reflect === "object" && typeof Reflect.decorate === "function") {
151
+ r = Reflect.decorate(decorators, target, key, desc);
152
+ } else {
153
+ for (var i = decorators.length - 1; i >= 0; i--) {
154
+ if (d = decorators[i]) {
155
+ r = (c < 3 ? d(r) : c > 3 ? d(target, key, r) : d(target, key)) || r;
156
+ }
157
+ }
158
+ }
159
+ return c > 3 && r && Object.defineProperty(target, key, r), r;
160
+ }
161
+ __name(_ts_decorate2, "_ts_decorate");
162
+ function _ts_metadata(metadataKey, metadataValue) {
163
+ if (typeof Reflect === "object" && typeof Reflect.metadata === "function") {
164
+ return Reflect.metadata(metadataKey, metadataValue);
165
+ }
166
+ }
167
+ __name(_ts_metadata, "_ts_metadata");
168
+ function _ts_param(paramIndex, decorator) {
169
+ return function(target, key) {
170
+ decorator(target, key, paramIndex);
171
+ };
172
+ }
173
+ __name(_ts_param, "_ts_param");
174
+ var CONFIG_CHANGED_EVENT = "zucker.config-changed";
175
+ var CONFIG_CHANGED_TOPIC = "system/config/changed";
176
+ var CONFIG_ENCRYPTOR = "CONFIG_ENCRYPTOR";
177
+ var ConfigService = class _ConfigService {
178
+ static {
179
+ __name(this, "ConfigService");
180
+ }
181
+ db;
182
+ eventEmitter;
183
+ scopeManager;
184
+ encryptor;
185
+ topicEventBus;
186
+ logger = new Logger2(_ConfigService.name);
187
+ cache = /* @__PURE__ */ new Map();
188
+ static CACHE_MAX_SIZE = 1024;
189
+ constructor(db, eventEmitter, scopeManager, encryptor, topicEventBus) {
190
+ this.db = db;
191
+ this.eventEmitter = eventEmitter;
192
+ this.scopeManager = scopeManager;
193
+ this.encryptor = encryptor;
194
+ this.topicEventBus = topicEventBus;
195
+ }
196
+ /**
197
+ * 获取指定 scope 和 key 的配置值
198
+ * @param scope 配置域
199
+ * @param key 配置键
200
+ * @returns 配置值,不存在时返回 undefined
201
+ */
202
+ async get(scope, key) {
203
+ const cacheKey = `${scope}:${key}`;
204
+ if (this.cache.has(cacheKey)) {
205
+ return this.cache.get(cacheKey);
206
+ }
207
+ const record = await this.db.model("config").findUnique({
208
+ where: {
209
+ scope_key: {
210
+ scope,
211
+ key
212
+ }
213
+ }
214
+ });
215
+ if (!record) return void 0;
216
+ let value = record.value;
217
+ if (this.encryptor && this.isEncryptedProperty(scope, key)) {
218
+ try {
219
+ value = await this.encryptor.decrypt(value);
220
+ } catch (decryptError) {
221
+ this.logger.error(`Failed to decrypt config ${scope}.${key}: ${decryptError instanceof Error ? decryptError.message : String(decryptError)}`);
222
+ return void 0;
223
+ }
224
+ }
225
+ while (this.cache.size >= _ConfigService.CACHE_MAX_SIZE) {
226
+ const firstKey = this.cache.keys().next().value;
227
+ this.cache.delete(firstKey);
228
+ }
229
+ this.cache.set(cacheKey, value);
230
+ return value;
231
+ }
232
+ /**
233
+ * Get a config value with a fallback default.
234
+ * If no stored value exists, checks the scope definition default,
235
+ * then falls back to the provided default.
236
+ *
237
+ * Reference: jetlinks getProperties merges defaults from ConfigPropertyDef.
238
+ */
239
+ async getOrDefault(scope, key, defaultValue) {
240
+ const value = await this.get(scope, key);
241
+ if (value !== void 0) return value;
242
+ if (this.scopeManager?.has(scope)) {
243
+ const prop = this.scopeManager.getProperties(scope).find((p) => p.key === key);
244
+ if (prop?.defaultValue !== void 0) return prop.defaultValue;
245
+ }
246
+ return defaultValue;
247
+ }
248
+ /**
249
+ * 设置配置值(自动触发变更事件)
250
+ * @param scope 配置域
251
+ * @param key 配置键
252
+ * @param value 配置值
253
+ * @throws ValidationException 校验失败时
254
+ */
255
+ async set(scope, key, value) {
256
+ if (this.scopeManager?.has(scope)) {
257
+ const errors = this.scopeManager.validate(scope, key, value);
258
+ if (errors.length > 0) {
259
+ throw new ValidationException({
260
+ [key]: errors
261
+ }, `Config validation failed: ${errors.join(", ")}`);
262
+ }
263
+ }
264
+ const cacheKey = `${scope}:${key}`;
265
+ let oldValue = this.cache.get(cacheKey);
266
+ if (oldValue === void 0) {
267
+ const existing = await this.db.model("config").findUnique({
268
+ where: {
269
+ scope_key: {
270
+ scope,
271
+ key
272
+ }
273
+ }
274
+ });
275
+ if (existing) {
276
+ oldValue = existing.value;
277
+ }
278
+ }
279
+ let storedValue = value;
280
+ if (this.encryptor && this.isEncryptedProperty(scope, key) && typeof value === "string") {
281
+ storedValue = await this.encryptor.encrypt(value);
282
+ }
283
+ await this.db.model("config").update({
284
+ where: {
285
+ scope_key: {
286
+ scope,
287
+ key
288
+ }
289
+ },
290
+ data: {
291
+ value: storedValue
292
+ }
293
+ }).catch(async (updateError) => {
294
+ this.logger.debug(`Config key ${scope}.${key} not found, creating: ${updateError instanceof Error ? updateError.message : String(updateError)}`);
295
+ await this.db.model("config").create({
296
+ data: {
297
+ scope,
298
+ key,
299
+ value: storedValue
300
+ }
301
+ });
302
+ });
303
+ while (this.cache.size >= _ConfigService.CACHE_MAX_SIZE) {
304
+ const firstKey = this.cache.keys().next().value;
305
+ this.cache.delete(firstKey);
306
+ }
307
+ this.cache.set(cacheKey, value);
308
+ await this.recordHistory(scope, key, oldValue, value);
309
+ const payload = {
310
+ scope,
311
+ key,
312
+ oldValue,
313
+ newValue: value
314
+ };
315
+ this.eventEmitter?.emit(CONFIG_CHANGED_EVENT, payload);
316
+ if (this.topicEventBus) {
317
+ await this.topicEventBus.publish(CONFIG_CHANGED_TOPIC, payload);
318
+ }
319
+ this.logger.debug(`Config updated: ${scope}.${key}`);
320
+ }
321
+ /**
322
+ * Set multiple properties at once for a scope.
323
+ * Performs batch validation first, then persists all values and emits
324
+ * a single consolidated event — mirrors jetlinks ConfigManager.setProperties(scope, Map)
325
+ * which does repository.save + cache.evict instead of N individual updates.
326
+ */
327
+ async setProperties(scope, values) {
328
+ const entries = Object.entries(values);
329
+ if (entries.length === 0) return;
330
+ if (this.scopeManager?.has(scope)) {
331
+ const allErrors = {};
332
+ for (const [key, value] of entries) {
333
+ const errors = this.scopeManager.validate(scope, key, value);
334
+ if (errors.length > 0) {
335
+ allErrors[key] = errors;
336
+ }
337
+ }
338
+ if (Object.keys(allErrors).length > 0) {
339
+ throw new ValidationException(allErrors, `Config batch validation failed`);
340
+ }
341
+ }
342
+ const changes = [];
343
+ await this.db.$transaction(async (tx) => {
344
+ for (const [key, value] of entries) {
345
+ const cacheKey = `${scope}:${key}`;
346
+ const oldValue = this.cache.get(cacheKey);
347
+ let storedValue = value;
348
+ if (this.encryptor && this.isEncryptedProperty(scope, key) && typeof value === "string") {
349
+ storedValue = await this.encryptor.encrypt(value);
350
+ }
351
+ await tx.model("config").update({
352
+ where: {
353
+ scope_key: {
354
+ scope,
355
+ key
356
+ }
357
+ },
358
+ data: {
359
+ value: storedValue
360
+ }
361
+ }).catch(async (updateError) => {
362
+ this.logger.debug(`Config key ${scope}.${key} not found, creating: ${updateError instanceof Error ? updateError.message : String(updateError)}`);
363
+ await tx.model("config").create({
364
+ data: {
365
+ scope,
366
+ key,
367
+ value: storedValue
368
+ }
369
+ });
370
+ });
371
+ if (this.cache.size >= _ConfigService.CACHE_MAX_SIZE) {
372
+ const firstKey = this.cache.keys().next().value;
373
+ this.cache.delete(firstKey);
374
+ }
375
+ this.cache.set(cacheKey, value);
376
+ changes.push({
377
+ scope,
378
+ key,
379
+ oldValue,
380
+ newValue: value
381
+ });
382
+ }
383
+ });
384
+ for (const payload of changes) {
385
+ this.eventEmitter?.emit(CONFIG_CHANGED_EVENT, payload);
386
+ }
387
+ if (this.topicEventBus) {
388
+ for (const payload of changes) {
389
+ await this.topicEventBus.publish(CONFIG_CHANGED_TOPIC, payload);
390
+ }
391
+ }
392
+ this.logger.debug(`Config batch updated: ${scope} (${entries.length} properties)`);
393
+ }
394
+ /**
395
+ * 获取指定 scope 下的所有配置
396
+ * @param scope 配置域
397
+ * @returns 键值对集合(包含默认值)
398
+ */
399
+ async getAll(scope) {
400
+ const records = await this.db.model("config").findMany({
401
+ where: {
402
+ scope
403
+ }
404
+ });
405
+ const result = {};
406
+ if (this.scopeManager?.has(scope)) {
407
+ const props = this.scopeManager.getProperties(scope);
408
+ for (const prop of props) {
409
+ if (prop.defaultValue !== void 0) {
410
+ result[prop.key] = prop.defaultValue;
411
+ }
412
+ }
413
+ }
414
+ for (const record of records) {
415
+ let value = record.value;
416
+ if (this.encryptor && this.isEncryptedProperty(scope, record.key)) {
417
+ try {
418
+ value = await this.encryptor.decrypt(value);
419
+ } catch (decryptError) {
420
+ this.logger.error(`Failed to decrypt config ${scope}.${record.key}: ${decryptError instanceof Error ? decryptError.message : String(decryptError)}`);
421
+ continue;
422
+ }
423
+ }
424
+ result[record.key] = value;
425
+ if (this.cache.size >= _ConfigService.CACHE_MAX_SIZE) {
426
+ const firstKey = this.cache.keys().next().value;
427
+ this.cache.delete(firstKey);
428
+ }
429
+ this.cache.set(`${scope}:${record.key}`, value);
430
+ }
431
+ return result;
432
+ }
433
+ /**
434
+ * Remove a specific config property.
435
+ */
436
+ async remove(scope, key) {
437
+ const cacheKey = `${scope}:${key}`;
438
+ let oldValue = this.cache.get(cacheKey);
439
+ if (oldValue === void 0) {
440
+ const existing = await this.db.model("config").findUnique({
441
+ where: {
442
+ scope_key: {
443
+ scope,
444
+ key
445
+ }
446
+ }
447
+ });
448
+ if (existing) {
449
+ oldValue = existing.value;
450
+ }
451
+ }
452
+ await this.db.model("config").delete({
453
+ where: {
454
+ scope_key: {
455
+ scope,
456
+ key
457
+ }
458
+ }
459
+ }).catch(() => {
460
+ });
461
+ this.cache.delete(cacheKey);
462
+ const payload = {
463
+ scope,
464
+ key,
465
+ oldValue,
466
+ newValue: void 0
467
+ };
468
+ this.eventEmitter?.emit(CONFIG_CHANGED_EVENT, payload);
469
+ if (this.topicEventBus) {
470
+ await this.topicEventBus.publish(CONFIG_CHANGED_TOPIC, payload);
471
+ }
472
+ }
473
+ /**
474
+ * 监听配置变更事件
475
+ * @param callback 变更回调
476
+ * @returns 订阅句柄,调用 unsubscribe() 取消监听
477
+ */
478
+ onChange(callback) {
479
+ if (!this.eventEmitter) return {
480
+ unsubscribe: /* @__PURE__ */ __name(() => void 0, "unsubscribe")
481
+ };
482
+ const ee = this.eventEmitter;
483
+ ee.on(CONFIG_CHANGED_EVENT, callback);
484
+ return {
485
+ unsubscribe: /* @__PURE__ */ __name(() => ee.off(CONFIG_CHANGED_EVENT, callback), "unsubscribe")
486
+ };
487
+ }
488
+ /**
489
+ * 监听指定 scope.key 的配置变更,每次变更时执行回调。
490
+ *
491
+ * @param scope 配置域
492
+ * @param key 配置键(可选,不传则监听整个 scope)
493
+ * @param callback 变更回调
494
+ * @returns 取消监听函数
495
+ */
496
+ watch(scope, key, callback) {
497
+ const handler = /* @__PURE__ */ __name((payload) => {
498
+ if (payload.scope !== scope) return;
499
+ if (key && payload.key !== key) return;
500
+ callback(payload.newValue, payload.oldValue);
501
+ }, "handler");
502
+ if (!this.eventEmitter) return {
503
+ unsubscribe: /* @__PURE__ */ __name(() => void 0, "unsubscribe")
504
+ };
505
+ const ee = this.eventEmitter;
506
+ ee.on(CONFIG_CHANGED_EVENT, handler);
507
+ return {
508
+ unsubscribe: /* @__PURE__ */ __name(() => ee.off(CONFIG_CHANGED_EVENT, handler), "unsubscribe")
509
+ };
510
+ }
511
+ /**
512
+ * 清除配置缓存
513
+ * @param scope 可选的配置域,不传则清除所有缓存
514
+ */
515
+ clearCache(scope) {
516
+ if (scope) {
517
+ const prefix = `${scope}:`;
518
+ for (const key of this.cache.keys()) {
519
+ if (key.startsWith(prefix)) this.cache.delete(key);
520
+ }
521
+ } else {
522
+ this.cache.clear();
523
+ }
524
+ }
525
+ // ─── 配置版本控制 ──────────────────────────────────────────────────
526
+ /**
527
+ * 记录配置变更历史(自动版本号递增)
528
+ * 配置版本控制
529
+ */
530
+ async recordHistory(scope, key, oldValue, newValue) {
531
+ try {
532
+ await this.db.model("configHistory").create({
533
+ data: {
534
+ scope,
535
+ key,
536
+ oldValue: oldValue !== void 0 ? JSON.stringify(oldValue) : null,
537
+ newValue: JSON.stringify(newValue),
538
+ changedAt: /* @__PURE__ */ new Date()
539
+ }
540
+ });
541
+ } catch {
542
+ }
543
+ }
544
+ /**
545
+ * 查询配置变更历史
546
+ * @param scope 配置域
547
+ * @param key 配置键(可选,不传则查询该 scope 所有变更)
548
+ * @param limit 返回条数(默认 20)
549
+ */
550
+ async getHistory(scope, key, limit = 20) {
551
+ try {
552
+ const where = {
553
+ scope
554
+ };
555
+ if (key) where.key = key;
556
+ return await this.db.model("configHistory").findMany({
557
+ where,
558
+ orderBy: {
559
+ changedAt: "desc"
560
+ },
561
+ take: limit
562
+ });
563
+ } catch {
564
+ return [];
565
+ }
566
+ }
567
+ /**
568
+ * 回滚配置到指定历史版本
569
+ * @param historyId 历史记录 ID
570
+ */
571
+ async rollback(historyId) {
572
+ try {
573
+ const record = await this.db.model("configHistory").findUnique({
574
+ where: {
575
+ id: historyId
576
+ }
577
+ });
578
+ if (!record || record.oldValue === null) return;
579
+ const value = JSON.parse(record.oldValue);
580
+ await this.set(record.scope, record.key, value);
581
+ } catch (error) {
582
+ this.logger.warn(`Config rollback failed: ${error instanceof Error ? error.message : String(error)}`);
583
+ }
584
+ }
585
+ /**
586
+ * Check if a property is marked as encrypted in its scope definition.
587
+ */
588
+ isEncryptedProperty(scope, key) {
589
+ if (!this.scopeManager) return false;
590
+ const props = this.scopeManager.getProperties(scope);
591
+ const prop = props.find((p) => p.key === key);
592
+ return prop?.encrypted === true;
593
+ }
594
+ };
595
+ ConfigService = _ts_decorate2([
596
+ Injectable2(),
597
+ _ts_param(0, Inject(DATABASE_ADAPTER)),
598
+ _ts_param(1, Optional()),
599
+ _ts_param(2, Optional()),
600
+ _ts_param(3, Optional()),
601
+ _ts_param(3, Inject(CONFIG_ENCRYPTOR)),
602
+ _ts_param(4, Optional()),
603
+ _ts_param(4, Inject("TOPIC_EVENT_BUS")),
604
+ _ts_metadata("design:type", Function),
605
+ _ts_metadata("design:paramtypes", [
606
+ typeof DatabaseAdapter === "undefined" ? Object : DatabaseAdapter,
607
+ typeof EventEmitter2 === "undefined" ? Object : EventEmitter2,
608
+ typeof ConfigScopeManager === "undefined" ? Object : ConfigScopeManager,
609
+ typeof ConfigEncryptor === "undefined" ? Object : ConfigEncryptor,
610
+ typeof TopicEventBusLike === "undefined" ? Object : TopicEventBusLike
611
+ ])
612
+ ], ConfigService);
613
+
614
+ // src/config.module.ts
615
+ import { Module, Global } from "@nestjs/common";
616
+
617
+ // src/layered-config.service.ts
618
+ import { Injectable as Injectable3, Inject as Inject2, Logger as Logger3, Optional as Optional2 } from "@nestjs/common";
619
+ import { ValidationException as ValidationException2 } from "@zucker-framework/core";
620
+ import { EventEmitter2 as EventEmitter22 } from "eventemitter2";
621
+ import { DATABASE_ADAPTER as DATABASE_ADAPTER2 } from "@zucker-framework/crud";
622
+ function _ts_decorate3(decorators, target, key, desc) {
623
+ var c = arguments.length, r = c < 3 ? target : desc === null ? desc = Object.getOwnPropertyDescriptor(target, key) : desc, d;
624
+ if (typeof Reflect === "object" && typeof Reflect.decorate === "function") {
625
+ r = Reflect.decorate(decorators, target, key, desc);
626
+ } else {
627
+ for (var i = decorators.length - 1; i >= 0; i--) {
628
+ if (d = decorators[i]) {
629
+ r = (c < 3 ? d(r) : c > 3 ? d(target, key, r) : d(target, key)) || r;
630
+ }
631
+ }
632
+ }
633
+ return c > 3 && r && Object.defineProperty(target, key, r), r;
634
+ }
635
+ __name(_ts_decorate3, "_ts_decorate");
636
+ function _ts_metadata2(metadataKey, metadataValue) {
637
+ if (typeof Reflect === "object" && typeof Reflect.metadata === "function") {
638
+ return Reflect.metadata(metadataKey, metadataValue);
639
+ }
640
+ }
641
+ __name(_ts_metadata2, "_ts_metadata");
642
+ function _ts_param2(paramIndex, decorator) {
643
+ return function(target, key) {
644
+ decorator(target, key, paramIndex);
645
+ };
646
+ }
647
+ __name(_ts_param2, "_ts_param");
648
+ var CONFIG_LAYER_PRIORITY = {
649
+ system: 0,
650
+ tenant: 1,
651
+ user: 2
652
+ };
653
+ var LAYERED_CONFIG_CHANGED_EVENT = "zucker.layered-config-changed";
654
+ var LAYERED_CONFIG_CHANGED_TOPIC = "system/config/layered-changed";
655
+ var LayeredConfigService = class _LayeredConfigService {
656
+ static {
657
+ __name(this, "LayeredConfigService");
658
+ }
659
+ db;
660
+ scopeManager;
661
+ eventEmitter;
662
+ topicEventBus;
663
+ logger = new Logger3(_LayeredConfigService.name);
664
+ cache = /* @__PURE__ */ new Map();
665
+ constructor(db, scopeManager, eventEmitter, topicEventBus) {
666
+ this.db = db;
667
+ this.scopeManager = scopeManager;
668
+ this.eventEmitter = eventEmitter;
669
+ this.topicEventBus = topicEventBus;
670
+ }
671
+ /**
672
+ * Get a config value, resolving through layers (user > tenant > system > default).
673
+ */
674
+ async get(scope, key, context) {
675
+ if (context?.userId) {
676
+ const userValue = await this.getLayerValue(scope, key, "user", context.userId);
677
+ if (userValue !== void 0) return userValue;
678
+ }
679
+ if (context?.tenantId) {
680
+ const tenantValue = await this.getLayerValue(scope, key, "tenant", context.tenantId);
681
+ if (tenantValue !== void 0) return tenantValue;
682
+ }
683
+ const systemValue = await this.getLayerValue(scope, key, "system");
684
+ if (systemValue !== void 0) return systemValue;
685
+ const scopeDef = this.scopeManager.get(scope);
686
+ if (scopeDef) {
687
+ const prop = scopeDef.properties.find((p) => p.key === key);
688
+ if (prop) return prop.defaultValue;
689
+ }
690
+ return void 0;
691
+ }
692
+ /**
693
+ * Set a config value at a specific layer.
694
+ */
695
+ async set(scope, key, value, layer, ownerId) {
696
+ const errors = this.scopeManager.validate(scope, key, value);
697
+ if (errors.length > 0) {
698
+ throw new ValidationException2({
699
+ [key]: errors
700
+ }, `Config validation failed: ${errors.join(", ")}`);
701
+ }
702
+ const compositeKey = this.buildLayerKey(scope, key, layer, ownerId);
703
+ const oldValue = await this.getLayerValue(scope, key, layer, ownerId);
704
+ await this.db.model("config").update({
705
+ where: {
706
+ scope_key: {
707
+ scope: compositeKey,
708
+ key
709
+ }
710
+ },
711
+ data: {
712
+ value,
713
+ updatedAt: /* @__PURE__ */ new Date()
714
+ }
715
+ }).catch(async () => {
716
+ await this.db.model("config").create({
717
+ data: {
718
+ scope: compositeKey,
719
+ key,
720
+ value
721
+ }
722
+ });
723
+ });
724
+ const payload = {
725
+ scope,
726
+ key,
727
+ layer,
728
+ oldValue,
729
+ newValue: value
730
+ };
731
+ this.eventEmitter?.emit(LAYERED_CONFIG_CHANGED_EVENT, payload);
732
+ if (this.topicEventBus) {
733
+ await this.topicEventBus.publish(LAYERED_CONFIG_CHANGED_TOPIC, payload);
734
+ }
735
+ }
736
+ /**
737
+ * Get all values for a scope, merged across layers.
738
+ */
739
+ async getAll(scope, context) {
740
+ const result = {};
741
+ const scopeDef = this.scopeManager.get(scope);
742
+ if (scopeDef) {
743
+ for (const prop of scopeDef.properties) {
744
+ if (prop.defaultValue !== void 0) {
745
+ result[prop.key] = prop.defaultValue;
746
+ }
747
+ }
748
+ }
749
+ const systemRecords = await this.getLayerRecords(scope, "system");
750
+ for (const [k, v] of Object.entries(systemRecords)) {
751
+ result[k] = v;
752
+ }
753
+ if (context?.tenantId) {
754
+ const tenantRecords = await this.getLayerRecords(scope, "tenant", context.tenantId);
755
+ for (const [k, v] of Object.entries(tenantRecords)) {
756
+ result[k] = v;
757
+ }
758
+ }
759
+ if (context?.userId) {
760
+ const userRecords = await this.getLayerRecords(scope, "user", context.userId);
761
+ for (const [k, v] of Object.entries(userRecords)) {
762
+ result[k] = v;
763
+ }
764
+ }
765
+ return result;
766
+ }
767
+ /**
768
+ * Set multiple properties at a specific layer.
769
+ * Validates all entries first, then persists in batch.
770
+ *
771
+ * Reference: jetlinks ConfigManager.setProperties(scope, Map)
772
+ */
773
+ async setProperties(scope, values, layer, ownerId) {
774
+ const entries = Object.entries(values);
775
+ if (entries.length === 0) return;
776
+ const allErrors = {};
777
+ for (const [key, value] of entries) {
778
+ const errors = this.scopeManager.validate(scope, key, value);
779
+ if (errors.length > 0) {
780
+ allErrors[key] = errors;
781
+ }
782
+ }
783
+ if (Object.keys(allErrors).length > 0) {
784
+ throw new ValidationException2(allErrors, `Layered config batch validation failed`);
785
+ }
786
+ const changes = [];
787
+ await this.db.$transaction(async (txDb) => {
788
+ for (const [key, value] of entries) {
789
+ const compositeKey = this.buildLayerKey(scope, key, layer, ownerId);
790
+ const cacheKey = `${compositeKey}:${key}`;
791
+ const oldValue = this.cache.get(cacheKey);
792
+ await txDb.model("config").update({
793
+ where: {
794
+ scope_key: {
795
+ scope: compositeKey,
796
+ key
797
+ }
798
+ },
799
+ data: {
800
+ value,
801
+ updatedAt: /* @__PURE__ */ new Date()
802
+ }
803
+ }).catch(async () => {
804
+ await txDb.model("config").create({
805
+ data: {
806
+ scope: compositeKey,
807
+ key,
808
+ value
809
+ }
810
+ });
811
+ });
812
+ this.cache.set(cacheKey, value);
813
+ changes.push({
814
+ scope,
815
+ key,
816
+ layer,
817
+ oldValue,
818
+ newValue: value
819
+ });
820
+ }
821
+ });
822
+ for (const payload of changes) {
823
+ this.eventEmitter?.emit(LAYERED_CONFIG_CHANGED_EVENT, payload);
824
+ }
825
+ if (this.topicEventBus) {
826
+ for (const payload of changes) {
827
+ await this.topicEventBus.publish(LAYERED_CONFIG_CHANGED_TOPIC, payload);
828
+ }
829
+ }
830
+ }
831
+ /**
832
+ * Remove a config value at a specific layer.
833
+ */
834
+ async remove(scope, key, layer, ownerId) {
835
+ const compositeKey = this.buildLayerKey(scope, key, layer, ownerId);
836
+ const cacheKey = `${compositeKey}:${key}`;
837
+ const oldValue = this.cache.get(cacheKey);
838
+ await this.db.model("config").delete({
839
+ where: {
840
+ scope_key: {
841
+ scope: compositeKey,
842
+ key
843
+ }
844
+ }
845
+ }).catch(() => {
846
+ });
847
+ this.cache.delete(cacheKey);
848
+ const payload = {
849
+ scope,
850
+ key,
851
+ layer,
852
+ oldValue,
853
+ newValue: void 0
854
+ };
855
+ this.eventEmitter?.emit(LAYERED_CONFIG_CHANGED_EVENT, payload);
856
+ if (this.topicEventBus) {
857
+ await this.topicEventBus.publish(LAYERED_CONFIG_CHANGED_TOPIC, payload);
858
+ }
859
+ }
860
+ /**
861
+ * Clear the in-memory cache.
862
+ * @param scope Optional — only clear entries for this scope prefix
863
+ */
864
+ clearCache(scope) {
865
+ if (scope) {
866
+ for (const key of this.cache.keys()) {
867
+ if (key.startsWith(scope)) this.cache.delete(key);
868
+ }
869
+ } else {
870
+ this.cache.clear();
871
+ }
872
+ }
873
+ async getLayerValue(scope, key, layer, ownerId) {
874
+ const compositeKey = this.buildLayerKey(scope, key, layer, ownerId);
875
+ const cacheKey = `${compositeKey}:${key}`;
876
+ if (this.cache.has(cacheKey)) {
877
+ return this.cache.get(cacheKey);
878
+ }
879
+ const record = await this.db.model("config").findUnique({
880
+ where: {
881
+ scope_key: {
882
+ scope: compositeKey,
883
+ key
884
+ }
885
+ }
886
+ });
887
+ if (record) {
888
+ this.cache.set(cacheKey, record.value);
889
+ }
890
+ return record?.value;
891
+ }
892
+ async getLayerRecords(scope, layer, ownerId) {
893
+ const compositeScope = ownerId ? `${scope}@${layer}:${ownerId}` : `${scope}@${layer}`;
894
+ const records = await this.db.model("config").findMany({
895
+ where: {
896
+ scope: compositeScope
897
+ }
898
+ });
899
+ const result = {};
900
+ for (const record of records) {
901
+ result[record.key] = record.value;
902
+ }
903
+ return result;
904
+ }
905
+ buildLayerKey(scope, _key, layer, ownerId) {
906
+ if (ownerId) {
907
+ return `${scope}@${layer}:${ownerId}`;
908
+ }
909
+ return `${scope}@${layer}`;
910
+ }
911
+ };
912
+ LayeredConfigService = _ts_decorate3([
913
+ Injectable3(),
914
+ _ts_param2(0, Inject2(DATABASE_ADAPTER2)),
915
+ _ts_param2(2, Optional2()),
916
+ _ts_param2(3, Optional2()),
917
+ _ts_param2(3, Inject2("TOPIC_EVENT_BUS")),
918
+ _ts_metadata2("design:type", Function),
919
+ _ts_metadata2("design:paramtypes", [
920
+ typeof DatabaseAdapter === "undefined" ? Object : DatabaseAdapter,
921
+ typeof ConfigScopeManager === "undefined" ? Object : ConfigScopeManager,
922
+ typeof EventEmitter22 === "undefined" ? Object : EventEmitter22,
923
+ typeof TopicEventBusLike === "undefined" ? Object : TopicEventBusLike
924
+ ])
925
+ ], LayeredConfigService);
926
+
927
+ // src/config.module.ts
928
+ function _ts_decorate4(decorators, target, key, desc) {
929
+ var c = arguments.length, r = c < 3 ? target : desc === null ? desc = Object.getOwnPropertyDescriptor(target, key) : desc, d;
930
+ if (typeof Reflect === "object" && typeof Reflect.decorate === "function") {
931
+ r = Reflect.decorate(decorators, target, key, desc);
932
+ } else {
933
+ for (var i = decorators.length - 1; i >= 0; i--) {
934
+ if (d = decorators[i]) {
935
+ r = (c < 3 ? d(r) : c > 3 ? d(target, key, r) : d(target, key)) || r;
936
+ }
937
+ }
938
+ }
939
+ return c > 3 && r && Object.defineProperty(target, key, r), r;
940
+ }
941
+ __name(_ts_decorate4, "_ts_decorate");
942
+ var CONFIG_MODULE_OPTIONS = /* @__PURE__ */ Symbol("CONFIG_MODULE_OPTIONS");
943
+ var ZuckerConfigModule = class _ZuckerConfigModule {
944
+ static {
945
+ __name(this, "ZuckerConfigModule");
946
+ }
947
+ static forRoot(options) {
948
+ const providers = [
949
+ ConfigService,
950
+ ConfigScopeManager,
951
+ LayeredConfigService
952
+ ];
953
+ if (options?.encryptor) {
954
+ providers.push({
955
+ provide: CONFIG_ENCRYPTOR,
956
+ useValue: options.encryptor
957
+ });
958
+ }
959
+ return {
960
+ module: _ZuckerConfigModule,
961
+ global: true,
962
+ providers,
963
+ exports: [
964
+ ConfigService,
965
+ ConfigScopeManager,
966
+ LayeredConfigService
967
+ ]
968
+ };
969
+ }
970
+ static forRootAsync(options) {
971
+ const asyncProviders = this.createAsyncProviders(options);
972
+ return {
973
+ module: _ZuckerConfigModule,
974
+ global: true,
975
+ imports: options.imports ?? [],
976
+ providers: [
977
+ ...asyncProviders,
978
+ {
979
+ provide: CONFIG_ENCRYPTOR,
980
+ useFactory: /* @__PURE__ */ __name((opts) => opts.encryptor ?? null, "useFactory"),
981
+ inject: [
982
+ CONFIG_MODULE_OPTIONS
983
+ ]
984
+ },
985
+ ConfigService,
986
+ ConfigScopeManager,
987
+ LayeredConfigService
988
+ ],
989
+ exports: [
990
+ ConfigService,
991
+ ConfigScopeManager,
992
+ LayeredConfigService
993
+ ]
994
+ };
995
+ }
996
+ static createAsyncProviders(options) {
997
+ if (options.useFactory) {
998
+ return [
999
+ {
1000
+ provide: CONFIG_MODULE_OPTIONS,
1001
+ useFactory: options.useFactory,
1002
+ inject: options.inject ?? []
1003
+ }
1004
+ ];
1005
+ }
1006
+ const optionsProvider = {
1007
+ provide: CONFIG_MODULE_OPTIONS,
1008
+ useFactory: /* @__PURE__ */ __name(async (factory) => factory.createConfigOptions(), "useFactory"),
1009
+ inject: [
1010
+ options.useClass ?? options.useExisting
1011
+ ]
1012
+ };
1013
+ if (options.useClass) {
1014
+ return [
1015
+ {
1016
+ provide: options.useClass,
1017
+ useClass: options.useClass
1018
+ },
1019
+ optionsProvider
1020
+ ];
1021
+ }
1022
+ return [
1023
+ optionsProvider
1024
+ ];
1025
+ }
1026
+ };
1027
+ ZuckerConfigModule = _ts_decorate4([
1028
+ Global(),
1029
+ Module({})
1030
+ ], ZuckerConfigModule);
1031
+
1032
+ // src/config.guard.ts
1033
+ import { Injectable as Injectable4, Inject as Inject3, Logger as Logger4 } from "@nestjs/common";
1034
+ function _ts_decorate5(decorators, target, key, desc) {
1035
+ var c = arguments.length, r = c < 3 ? target : desc === null ? desc = Object.getOwnPropertyDescriptor(target, key) : desc, d;
1036
+ if (typeof Reflect === "object" && typeof Reflect.decorate === "function") {
1037
+ r = Reflect.decorate(decorators, target, key, desc);
1038
+ } else {
1039
+ for (var i = decorators.length - 1; i >= 0; i--) {
1040
+ if (d = decorators[i]) {
1041
+ r = (c < 3 ? d(r) : c > 3 ? d(target, key, r) : d(target, key)) || r;
1042
+ }
1043
+ }
1044
+ }
1045
+ return c > 3 && r && Object.defineProperty(target, key, r), r;
1046
+ }
1047
+ __name(_ts_decorate5, "_ts_decorate");
1048
+ function _ts_metadata3(metadataKey, metadataValue) {
1049
+ if (typeof Reflect === "object" && typeof Reflect.metadata === "function") {
1050
+ return Reflect.metadata(metadataKey, metadataValue);
1051
+ }
1052
+ }
1053
+ __name(_ts_metadata3, "_ts_metadata");
1054
+ function _ts_param3(paramIndex, decorator) {
1055
+ return function(target, key) {
1056
+ decorator(target, key, paramIndex);
1057
+ };
1058
+ }
1059
+ __name(_ts_param3, "_ts_param");
1060
+ var CONFIG_SCOPE_REGISTRY = "CONFIG_SCOPE_REGISTRY";
1061
+ var ConfigGuard = class _ConfigGuard {
1062
+ static {
1063
+ __name(this, "ConfigGuard");
1064
+ }
1065
+ scopeRegistry;
1066
+ logger = new Logger4(_ConfigGuard.name);
1067
+ constructor(scopeRegistry) {
1068
+ this.scopeRegistry = scopeRegistry;
1069
+ }
1070
+ canActivate(context) {
1071
+ const request = context.switchToHttp().getRequest();
1072
+ const scope = request.params?.scope ?? request.query?.scope;
1073
+ if (!scope) {
1074
+ return this.isAuthenticated(request);
1075
+ }
1076
+ const entry = this.scopeRegistry.get(scope);
1077
+ if (entry?.publicAccess) {
1078
+ this.logger.debug(`\u516C\u5F00\u8BBF\u95EE scope: ${scope}`);
1079
+ return true;
1080
+ }
1081
+ return this.isAuthenticated(request);
1082
+ }
1083
+ isAuthenticated(request) {
1084
+ return !!request.user;
1085
+ }
1086
+ };
1087
+ ConfigGuard = _ts_decorate5([
1088
+ Injectable4(),
1089
+ _ts_param3(0, Inject3(CONFIG_SCOPE_REGISTRY)),
1090
+ _ts_metadata3("design:type", Function),
1091
+ _ts_metadata3("design:paramtypes", [
1092
+ typeof Map === "undefined" ? Object : Map
1093
+ ])
1094
+ ], ConfigGuard);
1095
+
1096
+ // src/feature-flags.ts
1097
+ import { Injectable as Injectable5 } from "@nestjs/common";
1098
+ import { FeatureFlagEvaluator } from "@zucker-framework/feature-flags";
1099
+ import { FeatureFlagEvaluator as FeatureFlagEvaluator2, defaultFeatureFlagEnvKey } from "@zucker-framework/feature-flags";
1100
+ function _ts_decorate6(decorators, target, key, desc) {
1101
+ var c = arguments.length, r = c < 3 ? target : desc === null ? desc = Object.getOwnPropertyDescriptor(target, key) : desc, d;
1102
+ if (typeof Reflect === "object" && typeof Reflect.decorate === "function") {
1103
+ r = Reflect.decorate(decorators, target, key, desc);
1104
+ } else {
1105
+ for (var i = decorators.length - 1; i >= 0; i--) {
1106
+ if (d = decorators[i]) {
1107
+ r = (c < 3 ? d(r) : c > 3 ? d(target, key, r) : d(target, key)) || r;
1108
+ }
1109
+ }
1110
+ }
1111
+ return c > 3 && r && Object.defineProperty(target, key, r), r;
1112
+ }
1113
+ __name(_ts_decorate6, "_ts_decorate");
1114
+ function _ts_metadata4(metadataKey, metadataValue) {
1115
+ if (typeof Reflect === "object" && typeof Reflect.metadata === "function") {
1116
+ return Reflect.metadata(metadataKey, metadataValue);
1117
+ }
1118
+ }
1119
+ __name(_ts_metadata4, "_ts_metadata");
1120
+ var FeatureFlagService = class extends FeatureFlagEvaluator {
1121
+ static {
1122
+ __name(this, "FeatureFlagService");
1123
+ }
1124
+ constructor() {
1125
+ super((key) => process.env[key]);
1126
+ }
1127
+ };
1128
+ FeatureFlagService = _ts_decorate6([
1129
+ Injectable5(),
1130
+ _ts_metadata4("design:type", Function),
1131
+ _ts_metadata4("design:paramtypes", [])
1132
+ ], FeatureFlagService);
1133
+
1134
+ // src/config-watcher.ts
1135
+ import { Logger as Logger5 } from "@nestjs/common";
1136
+ import { watch, existsSync, statSync } from "fs";
1137
+ var ConfigFileWatcher = class _ConfigFileWatcher {
1138
+ static {
1139
+ __name(this, "ConfigFileWatcher");
1140
+ }
1141
+ logger = new Logger5(_ConfigFileWatcher.name);
1142
+ stabilityMs;
1143
+ deleteGraceMs;
1144
+ watched = /* @__PURE__ */ new Map();
1145
+ constructor(options = {}) {
1146
+ this.stabilityMs = options.stabilityMs ?? 1e3;
1147
+ this.deleteGraceMs = options.deleteGraceMs ?? 1700;
1148
+ }
1149
+ /**
1150
+ * 开始监听文件
1151
+ * @returns 取消监听函数
1152
+ */
1153
+ watch(filePath, callback) {
1154
+ if (this.watched.has(filePath)) {
1155
+ this.unwatch(filePath);
1156
+ }
1157
+ const entry = {
1158
+ path: filePath,
1159
+ callback,
1160
+ watcher: null,
1161
+ debounceTimer: null,
1162
+ deleteGraceTimer: null,
1163
+ lastModified: this.getModifiedTime(filePath)
1164
+ };
1165
+ try {
1166
+ entry.watcher = watch(filePath, (eventType) => {
1167
+ this.handleEvent(entry, eventType);
1168
+ });
1169
+ entry.watcher.on("error", (err) => {
1170
+ this.logger.warn(`Watch error on ${filePath}: ${err.message}`);
1171
+ });
1172
+ } catch {
1173
+ this.logger.warn(`Cannot watch ${filePath} \u2014 file may not exist yet`);
1174
+ }
1175
+ this.watched.set(filePath, entry);
1176
+ return () => this.unwatch(filePath);
1177
+ }
1178
+ /**
1179
+ * 停止监听指定文件
1180
+ */
1181
+ unwatch(filePath) {
1182
+ const entry = this.watched.get(filePath);
1183
+ if (!entry) return;
1184
+ entry.watcher?.close();
1185
+ if (entry.debounceTimer) clearTimeout(entry.debounceTimer);
1186
+ if (entry.deleteGraceTimer) clearTimeout(entry.deleteGraceTimer);
1187
+ this.watched.delete(filePath);
1188
+ }
1189
+ /**
1190
+ * 关闭所有监听
1191
+ */
1192
+ close() {
1193
+ for (const path of [
1194
+ ...this.watched.keys()
1195
+ ]) {
1196
+ this.unwatch(path);
1197
+ }
1198
+ }
1199
+ /**
1200
+ * 获取当前监听的文件列表
1201
+ */
1202
+ getWatchedFiles() {
1203
+ return [
1204
+ ...this.watched.keys()
1205
+ ];
1206
+ }
1207
+ handleEvent(entry, eventType) {
1208
+ if (eventType === "rename") {
1209
+ if (!existsSync(entry.path)) {
1210
+ if (entry.deleteGraceTimer) clearTimeout(entry.deleteGraceTimer);
1211
+ entry.deleteGraceTimer = setTimeout(() => {
1212
+ entry.deleteGraceTimer = null;
1213
+ if (!existsSync(entry.path)) {
1214
+ this.logger.warn(`Config file deleted: ${entry.path}`);
1215
+ }
1216
+ }, this.deleteGraceMs);
1217
+ return;
1218
+ }
1219
+ if (entry.deleteGraceTimer) {
1220
+ clearTimeout(entry.deleteGraceTimer);
1221
+ entry.deleteGraceTimer = null;
1222
+ }
1223
+ }
1224
+ if (entry.debounceTimer) clearTimeout(entry.debounceTimer);
1225
+ entry.debounceTimer = setTimeout(() => {
1226
+ entry.debounceTimer = null;
1227
+ const newModified = this.getModifiedTime(entry.path);
1228
+ if (newModified === entry.lastModified) return;
1229
+ entry.lastModified = newModified;
1230
+ this.logger.log(`Config changed: ${entry.path}`);
1231
+ try {
1232
+ entry.callback();
1233
+ } catch (err) {
1234
+ this.logger.error(`Config reload callback failed: ${err}`);
1235
+ }
1236
+ }, this.stabilityMs);
1237
+ }
1238
+ getModifiedTime(filePath) {
1239
+ try {
1240
+ return statSync(filePath).mtimeMs;
1241
+ } catch {
1242
+ return 0;
1243
+ }
1244
+ }
1245
+ };
1246
+ export {
1247
+ CONFIG_CHANGED_EVENT,
1248
+ CONFIG_CHANGED_TOPIC,
1249
+ CONFIG_ENCRYPTOR,
1250
+ CONFIG_LAYER_PRIORITY,
1251
+ CONFIG_MODULE_OPTIONS,
1252
+ CONFIG_SCOPE_REGISTRY,
1253
+ ConfigFileWatcher,
1254
+ ConfigGuard,
1255
+ ConfigScopeManager,
1256
+ ConfigService,
1257
+ DATABASE_ADAPTER,
1258
+ FeatureFlagEvaluator2 as FeatureFlagEvaluator,
1259
+ FeatureFlagService,
1260
+ LAYERED_CONFIG_CHANGED_EVENT,
1261
+ LAYERED_CONFIG_CHANGED_TOPIC,
1262
+ LayeredConfigService,
1263
+ ZuckerConfigModule,
1264
+ defaultFeatureFlagEnvKey
1265
+ };