@grest-ts/config 0.0.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/LICENSE +21 -0
- package/README.md +57 -0
- package/dist/src/GGConfig.d.ts +13 -0
- package/dist/src/GGConfig.d.ts.map +1 -0
- package/dist/src/GGConfig.js +58 -0
- package/dist/src/GGConfig.js.map +1 -0
- package/dist/src/GGConfigKey.d.ts +29 -0
- package/dist/src/GGConfigKey.d.ts.map +1 -0
- package/dist/src/GGConfigKey.js +79 -0
- package/dist/src/GGConfigKey.js.map +1 -0
- package/dist/src/GGConfigLocator.d.ts +35 -0
- package/dist/src/GGConfigLocator.d.ts.map +1 -0
- package/dist/src/GGConfigLocator.js +95 -0
- package/dist/src/GGConfigLocator.js.map +1 -0
- package/dist/src/GGConfigStore.d.ts +24 -0
- package/dist/src/GGConfigStore.d.ts.map +1 -0
- package/dist/src/GGConfigStore.js +89 -0
- package/dist/src/GGConfigStore.js.map +1 -0
- package/dist/src/GG_CONFIG.d.ts +4 -0
- package/dist/src/GG_CONFIG.d.ts.map +1 -0
- package/dist/src/GG_CONFIG.js +3 -0
- package/dist/src/GG_CONFIG.js.map +1 -0
- package/dist/src/assureValidConfigPath.d.ts +12 -0
- package/dist/src/assureValidConfigPath.d.ts.map +1 -0
- package/dist/src/assureValidConfigPath.js +35 -0
- package/dist/src/assureValidConfigPath.js.map +1 -0
- package/dist/src/index-node.d.ts +12 -0
- package/dist/src/index-node.d.ts.map +1 -0
- package/dist/src/index-node.js +12 -0
- package/dist/src/index-node.js.map +1 -0
- package/dist/src/keys/GGResource.d.ts +9 -0
- package/dist/src/keys/GGResource.d.ts.map +1 -0
- package/dist/src/keys/GGResource.js +14 -0
- package/dist/src/keys/GGResource.js.map +1 -0
- package/dist/src/keys/GGSecret.d.ts +9 -0
- package/dist/src/keys/GGSecret.d.ts.map +1 -0
- package/dist/src/keys/GGSecret.js +14 -0
- package/dist/src/keys/GGSecret.js.map +1 -0
- package/dist/src/keys/GGSetting.d.ts +11 -0
- package/dist/src/keys/GGSetting.d.ts.map +1 -0
- package/dist/src/keys/GGSetting.js +20 -0
- package/dist/src/keys/GGSetting.js.map +1 -0
- package/dist/src/stores/GGConfigStoreFile.d.ts +17 -0
- package/dist/src/stores/GGConfigStoreFile.d.ts.map +1 -0
- package/dist/src/stores/GGConfigStoreFile.js +62 -0
- package/dist/src/stores/GGConfigStoreFile.js.map +1 -0
- package/dist/src/stores/GGConfigStoreLocal.d.ts +54 -0
- package/dist/src/stores/GGConfigStoreLocal.d.ts.map +1 -0
- package/dist/src/stores/GGConfigStoreLocal.js +76 -0
- package/dist/src/stores/GGConfigStoreLocal.js.map +1 -0
- package/dist/src/tsconfig.json +16 -0
- package/dist/testkit/GGConfigCommands.d.ts +18 -0
- package/dist/testkit/GGConfigCommands.d.ts.map +1 -0
- package/dist/testkit/GGConfigCommands.js +42 -0
- package/dist/testkit/GGConfigCommands.js.map +1 -0
- package/dist/testkit/GGConfigTestComponent.d.ts +9 -0
- package/dist/testkit/GGConfigTestComponent.d.ts.map +1 -0
- package/dist/testkit/GGConfigTestComponent.js +20 -0
- package/dist/testkit/GGConfigTestComponent.js.map +1 -0
- package/dist/testkit/GGConfigTestStore.d.ts +23 -0
- package/dist/testkit/GGConfigTestStore.d.ts.map +1 -0
- package/dist/testkit/GGConfigTestStore.js +85 -0
- package/dist/testkit/GGConfigTestStore.js.map +1 -0
- package/dist/testkit/GGTestSelectorConfig.d.ts +22 -0
- package/dist/testkit/GGTestSelectorConfig.d.ts.map +1 -0
- package/dist/testkit/GGTestSelectorConfig.js +57 -0
- package/dist/testkit/GGTestSelectorConfig.js.map +1 -0
- package/dist/testkit/index-testkit.d.ts +5 -0
- package/dist/testkit/index-testkit.d.ts.map +1 -0
- package/dist/testkit/index-testkit.js +5 -0
- package/dist/testkit/index-testkit.js.map +1 -0
- package/dist/tsconfig.publish.tsbuildinfo +1 -0
- package/package.json +59 -0
- package/src/GGConfig.ts +70 -0
- package/src/GGConfigKey.ts +107 -0
- package/src/GGConfigLocator.ts +112 -0
- package/src/GGConfigStore.ts +100 -0
- package/src/GG_CONFIG.ts +4 -0
- package/src/assureValidConfigPath.spec.ts +140 -0
- package/src/assureValidConfigPath.ts +34 -0
- package/src/index-node.ts +11 -0
- package/src/keys/GGResource.ts +20 -0
- package/src/keys/GGSecret.ts +20 -0
- package/src/keys/GGSetting.ts +28 -0
- package/src/stores/GGConfigStoreFile.ts +69 -0
- package/src/stores/GGConfigStoreLocal.ts +110 -0
- package/src/tsconfig.json +16 -0
package/LICENSE
ADDED
|
@@ -0,0 +1,21 @@
|
|
|
1
|
+
MIT License
|
|
2
|
+
|
|
3
|
+
Copyright (c) 2025 Grest Games OÜ
|
|
4
|
+
|
|
5
|
+
Permission is hereby granted, free of charge, to any person obtaining a copy
|
|
6
|
+
of this software and associated documentation files (the "Software"), to deal
|
|
7
|
+
in the Software without restriction, including without limitation the rights
|
|
8
|
+
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
|
9
|
+
copies of the Software, and to permit persons to whom the Software is
|
|
10
|
+
furnished to do so, subject to the following conditions:
|
|
11
|
+
|
|
12
|
+
The above copyright notice and this permission notice shall be included in all
|
|
13
|
+
copies or substantial portions of the Software.
|
|
14
|
+
|
|
15
|
+
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
|
16
|
+
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
|
17
|
+
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
|
18
|
+
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
|
19
|
+
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
|
20
|
+
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
|
|
21
|
+
SOFTWARE.
|
package/README.md
ADDED
|
@@ -0,0 +1,57 @@
|
|
|
1
|
+
# @grest-ts/config
|
|
2
|
+
|
|
3
|
+
Type-safe configuration management for Grest Framework.
|
|
4
|
+
|
|
5
|
+
## Features
|
|
6
|
+
|
|
7
|
+
- Type-safe configuration keys with validation
|
|
8
|
+
- Multiple key types (Settings, Secrets, Resources)
|
|
9
|
+
- Pluggable storage backends (file, environment, remote)
|
|
10
|
+
- Runtime configuration updates with watchers
|
|
11
|
+
- Centralized configuration definitions
|
|
12
|
+
- Config values are validated!
|
|
13
|
+
|
|
14
|
+
## Pattern
|
|
15
|
+
|
|
16
|
+
- Keys are defined statically, but values are resolved at runtime from async context
|
|
17
|
+
- Different key types (Setting, Secret, Resource) can use different storage backends (Strategy pattern)
|
|
18
|
+
- Supports watching for runtime configuration changes (Observer pattern)
|
|
19
|
+
|
|
20
|
+
## Quick usage example
|
|
21
|
+
|
|
22
|
+
```typescript
|
|
23
|
+
import {GGConfig, GGResource, GGSecret, GGSetting} from "@grest-ts/config"
|
|
24
|
+
|
|
25
|
+
// Define configuration keys
|
|
26
|
+
export const AppConfig = GGConfig.define('/app/', () => ({
|
|
27
|
+
port: new GGSetting('port', 3000, 'Server port', IsInt),
|
|
28
|
+
apiKey: new GGSecret('apiKey', '', 'External API key', IsString),
|
|
29
|
+
dbUrl: new GGResource('db/url', 'localhost:5432', 'Database URL', IsString)
|
|
30
|
+
}));
|
|
31
|
+
|
|
32
|
+
// Usage in runtime
|
|
33
|
+
const port = AppConfig.port.get();
|
|
34
|
+
const apiKey = AppConfig.apiKey.reveal();
|
|
35
|
+
const dbUrl = AppConfig.dbUrl.get(); // if value changes, you get the new value
|
|
36
|
+
|
|
37
|
+
// Watch for changes (in case you need to) - as a simple example: you need to roll a mysql user password and start a new pool without any downtime.
|
|
38
|
+
AppConfig.dbUrl.watch(() => {
|
|
39
|
+
// Do something when dbUrl changes
|
|
40
|
+
})
|
|
41
|
+
|
|
42
|
+
// Where actually values come from? You define the source in the runtime compose.
|
|
43
|
+
// in example we use a file (don't really use files, use proper services for each category!)
|
|
44
|
+
// These particular stores also watch the file for updates. Most stores should allow dynamic config updates!
|
|
45
|
+
// You can also add your own stores, groups etc rather easily.
|
|
46
|
+
new GGConfigLoader(new Map<any, any>([
|
|
47
|
+
[GGSetting, new GGConfigStoreFile("./config/settings.json", import.meta.url)],
|
|
48
|
+
[GGSecret, new GGConfigStoreFile("./config/secrets.json", import.meta.url)],
|
|
49
|
+
[GGResource, new GGConfigStoreFile("./config/resources.json", import.meta.url)]
|
|
50
|
+
]));
|
|
51
|
+
|
|
52
|
+
```
|
|
53
|
+
|
|
54
|
+
## Documentation
|
|
55
|
+
|
|
56
|
+
- [Usage](./README-usage.md) - How to define and use configuration
|
|
57
|
+
- [Extending](./README-extending.md) - How to add custom key types and stores
|
|
@@ -0,0 +1,13 @@
|
|
|
1
|
+
import { GGConfigDefinition } from "./GGConfigLocator";
|
|
2
|
+
import { GGConfigKey } from "./GGConfigKey";
|
|
3
|
+
export interface GGConfigKeyCreationContext {
|
|
4
|
+
name: string;
|
|
5
|
+
add: (key: GGConfigKey) => void;
|
|
6
|
+
}
|
|
7
|
+
export declare class GGConfig {
|
|
8
|
+
static define<T>(name: string, define: () => T): GGConfigDefinition<T>;
|
|
9
|
+
static getCreationContext(): GGConfigKeyCreationContext;
|
|
10
|
+
static toJSON(config: GGConfigDefinition<any>): Record<string, unknown>;
|
|
11
|
+
private static collectKeys;
|
|
12
|
+
}
|
|
13
|
+
//# sourceMappingURL=GGConfig.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"GGConfig.d.ts","sourceRoot":"","sources":["../../src/GGConfig.ts"],"names":[],"mappings":"AAAA,OAAO,EAAC,kBAAkB,EAAC,MAAM,mBAAmB,CAAC;AAErD,OAAO,EAAC,WAAW,EAAC,MAAM,eAAe,CAAC;AAG1C,MAAM,WAAW,0BAA0B;IACvC,IAAI,EAAE,MAAM,CAAA;IACZ,GAAG,EAAE,CAAC,GAAG,EAAE,WAAW,KAAK,IAAI,CAAC;CACnC;AAID,qBAAa,QAAQ;WAEH,MAAM,CAAC,CAAC,EAAE,IAAI,EAAE,MAAM,EAAE,MAAM,EAAE,MAAM,CAAC,GAAG,kBAAkB,CAAC,CAAC,CAAC;WAmB/D,kBAAkB,IAAI,0BAA0B;WAQhD,MAAM,CAAC,MAAM,EAAE,kBAAkB,CAAC,GAAG,CAAC,GAAG,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC;IAM9E,OAAO,CAAC,MAAM,CAAC,WAAW;CAsB7B"}
|
|
@@ -0,0 +1,58 @@
|
|
|
1
|
+
import { AsyncLocalStorage } from "node:async_hooks";
|
|
2
|
+
import { GGConfigKey } from "./GGConfigKey.js";
|
|
3
|
+
const defineContext = new AsyncLocalStorage();
|
|
4
|
+
export class GGConfig {
|
|
5
|
+
static define(name, define) {
|
|
6
|
+
const keysMap = new Map();
|
|
7
|
+
const ctx = Object.freeze({
|
|
8
|
+
name,
|
|
9
|
+
add: (key) => {
|
|
10
|
+
const cls = key.constructor;
|
|
11
|
+
if (!keysMap.has(cls)) {
|
|
12
|
+
keysMap.set(cls, []);
|
|
13
|
+
}
|
|
14
|
+
keysMap.get(cls).push(key);
|
|
15
|
+
}
|
|
16
|
+
});
|
|
17
|
+
const result = defineContext.run(ctx, define);
|
|
18
|
+
keysMap.forEach(list => Object.freeze(list));
|
|
19
|
+
result.__getKeysMap = ((cls) => keysMap);
|
|
20
|
+
Object.freeze(result);
|
|
21
|
+
return result;
|
|
22
|
+
}
|
|
23
|
+
static getCreationContext() {
|
|
24
|
+
const store = defineContext.getStore();
|
|
25
|
+
if (!store) {
|
|
26
|
+
throw new Error("No prefix defined in context");
|
|
27
|
+
}
|
|
28
|
+
return store;
|
|
29
|
+
}
|
|
30
|
+
static toJSON(config) {
|
|
31
|
+
const result = {};
|
|
32
|
+
this.collectKeys(config, result);
|
|
33
|
+
return result;
|
|
34
|
+
}
|
|
35
|
+
static collectKeys(obj, result) {
|
|
36
|
+
if (obj instanceof GGConfigKey) {
|
|
37
|
+
const storeKey = obj.getStoreKey();
|
|
38
|
+
if (!result[storeKey]) {
|
|
39
|
+
result[storeKey] = {};
|
|
40
|
+
}
|
|
41
|
+
const segments = obj.name.split('/').filter(s => s.length > 0);
|
|
42
|
+
let current = result[storeKey];
|
|
43
|
+
for (let i = 0; i < segments.length - 1; i++) {
|
|
44
|
+
if (!current[segments[i]]) {
|
|
45
|
+
current[segments[i]] = {};
|
|
46
|
+
}
|
|
47
|
+
current = current[segments[i]];
|
|
48
|
+
}
|
|
49
|
+
current[segments[segments.length - 1]] = obj.getDefault();
|
|
50
|
+
}
|
|
51
|
+
else if (obj && typeof obj === 'object') {
|
|
52
|
+
for (const value of Object.values(obj)) {
|
|
53
|
+
this.collectKeys(value, result);
|
|
54
|
+
}
|
|
55
|
+
}
|
|
56
|
+
}
|
|
57
|
+
}
|
|
58
|
+
//# sourceMappingURL=GGConfig.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"GGConfig.js","sourceRoot":"","sources":["../../src/GGConfig.ts"],"names":[],"mappings":"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"}
|
|
@@ -0,0 +1,29 @@
|
|
|
1
|
+
import { GGValidator } from "@grest-ts/schema";
|
|
2
|
+
/**
|
|
3
|
+
* Widens literal types to their base primitive type.
|
|
4
|
+
* This allows T to be inferred from the validator while defaultValue accepts compatible values.
|
|
5
|
+
* e.g., Widen<tPosInt> = number, so defaultValue can be 5000
|
|
6
|
+
*/
|
|
7
|
+
export type Widen<T> = T extends number ? number : T extends string ? string : T extends boolean ? boolean : T;
|
|
8
|
+
export type GGConfigKeyConstructor<T = unknown> = {
|
|
9
|
+
readonly NAME: string;
|
|
10
|
+
new (...args: any[]): GGConfigKey<T>;
|
|
11
|
+
};
|
|
12
|
+
export declare abstract class GGConfigKey<T = unknown> {
|
|
13
|
+
private static readonly registry;
|
|
14
|
+
static hasKey(name: string): boolean;
|
|
15
|
+
static getKey(name: string): GGConfigKey;
|
|
16
|
+
readonly root: string;
|
|
17
|
+
readonly name: string;
|
|
18
|
+
readonly description: string | undefined;
|
|
19
|
+
readonly schema: GGValidator<T> | undefined;
|
|
20
|
+
/** File location where this ConfigKey was defined (file:line:col) */
|
|
21
|
+
readonly definedAt: string | undefined;
|
|
22
|
+
constructor(name: string, schema: GGValidator<T>, description: string);
|
|
23
|
+
getDefault(): T | undefined;
|
|
24
|
+
protected getValue(): T;
|
|
25
|
+
watch(listener: (value: T) => void): () => void;
|
|
26
|
+
abstract getStoreKey(): string;
|
|
27
|
+
getStore(): import("./GGConfigStore").GGConfigStore<any>;
|
|
28
|
+
}
|
|
29
|
+
//# sourceMappingURL=GGConfigKey.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"GGConfigKey.d.ts","sourceRoot":"","sources":["../../src/GGConfigKey.ts"],"names":[],"mappings":"AAEA,OAAO,EAAC,WAAW,EAAC,MAAM,kBAAkB,CAAC;AAG7C;;;;GAIG;AACH,MAAM,MAAM,KAAK,CAAC,CAAC,IAAI,CAAC,SAAS,MAAM,GAAG,MAAM,GAAG,CAAC,SAAS,MAAM,GAAG,MAAM,GAAG,CAAC,SAAS,OAAO,GAAG,OAAO,GAAG,CAAC,CAAC;AAE/G,MAAM,MAAM,sBAAsB,CAAC,CAAC,GAAG,OAAO,IAAI;IAC9C,QAAQ,CAAC,IAAI,EAAE,MAAM,CAAC;IACtB,KAAI,GAAG,IAAI,EAAE,GAAG,EAAE,GAAG,WAAW,CAAC,CAAC,CAAC,CAAA;CACtC,CAAC;AAEF,8BAAsB,WAAW,CAAC,CAAC,GAAG,OAAO;IAEzC,OAAO,CAAC,MAAM,CAAC,QAAQ,CAAC,QAAQ,CAAkC;WAEpD,MAAM,CAAC,IAAI,EAAE,MAAM,GAAG,OAAO;WAI7B,MAAM,CAAC,IAAI,EAAE,MAAM,GAAG,WAAW;IAQ/C,SAAgB,IAAI,EAAE,MAAM,CAAC;IAC7B,SAAgB,IAAI,EAAE,MAAM,CAAC;IAC7B,SAAgB,WAAW,EAAE,MAAM,GAAG,SAAS,CAAC;IAChD,SAAgB,MAAM,EAAE,WAAW,CAAC,CAAC,CAAC,GAAG,SAAS,CAAC;IACnD,qEAAqE;IACrE,SAAgB,SAAS,EAAE,MAAM,GAAG,SAAS,CAAC;gBAElC,IAAI,EAAE,MAAM,EAAE,MAAM,EAAE,WAAW,CAAC,CAAC,CAAC,EAAE,WAAW,EAAE,MAAM;IAkB9D,UAAU,IAAI,CAAC,GAAG,SAAS;IAIlC,SAAS,CAAC,QAAQ,IAAI,CAAC;IAQhB,KAAK,CAAC,QAAQ,EAAE,CAAC,KAAK,EAAE,CAAC,KAAK,IAAI,GAAG,MAAM,IAAI;aAItC,WAAW,IAAI,MAAM;IAE9B,QAAQ;CAGlB"}
|
|
@@ -0,0 +1,79 @@
|
|
|
1
|
+
import { GGConfig } from "./GGConfig.js";
|
|
2
|
+
import { assureValidConfigPath } from "./assureValidConfigPath.js";
|
|
3
|
+
import { GG_CONFIG } from "./GG_CONFIG.js";
|
|
4
|
+
export class GGConfigKey {
|
|
5
|
+
static registry = new Map();
|
|
6
|
+
static hasKey(name) {
|
|
7
|
+
return GGConfigKey.registry.has(name);
|
|
8
|
+
}
|
|
9
|
+
static getKey(name) {
|
|
10
|
+
const result = GGConfigKey.registry.get(name);
|
|
11
|
+
if (result === undefined) {
|
|
12
|
+
throw new Error(`Config key not found: ${name}`);
|
|
13
|
+
}
|
|
14
|
+
return result;
|
|
15
|
+
}
|
|
16
|
+
root;
|
|
17
|
+
name;
|
|
18
|
+
description;
|
|
19
|
+
schema;
|
|
20
|
+
/** File location where this ConfigKey was defined (file:line:col) */
|
|
21
|
+
definedAt;
|
|
22
|
+
constructor(name, schema, description) {
|
|
23
|
+
this.definedAt = captureDefinitionLocation();
|
|
24
|
+
const ctx = GGConfig.getCreationContext();
|
|
25
|
+
ctx.add(this);
|
|
26
|
+
this.root = ctx.name;
|
|
27
|
+
this.name = this.root + name;
|
|
28
|
+
assureValidConfigPath(this.name);
|
|
29
|
+
this.description = description;
|
|
30
|
+
this.schema = schema;
|
|
31
|
+
Object.freeze(this);
|
|
32
|
+
if (GGConfigKey.registry.has(this.name)) {
|
|
33
|
+
throw new Error(`Duplicate config key: ${this.name}`);
|
|
34
|
+
}
|
|
35
|
+
GGConfigKey.registry.set(this.name, this);
|
|
36
|
+
}
|
|
37
|
+
getDefault() {
|
|
38
|
+
return undefined;
|
|
39
|
+
}
|
|
40
|
+
getValue() {
|
|
41
|
+
const store = this.getStore();
|
|
42
|
+
if (!store.started) {
|
|
43
|
+
throw new Error(`Cannot read config key "${this.name}" before the config store has been started.`);
|
|
44
|
+
}
|
|
45
|
+
return store.getValue(this);
|
|
46
|
+
}
|
|
47
|
+
watch(listener) {
|
|
48
|
+
return this.getStore().watch(this, listener);
|
|
49
|
+
}
|
|
50
|
+
getStore() {
|
|
51
|
+
return GG_CONFIG.get().getStore(this.constructor);
|
|
52
|
+
}
|
|
53
|
+
}
|
|
54
|
+
function captureDefinitionLocation() {
|
|
55
|
+
const stack = new Error().stack;
|
|
56
|
+
/* This could be one possible error we are filtering for.
|
|
57
|
+
Error
|
|
58
|
+
at captureDefinitionLocation (\GG_ROOT\packages\config\src\GGConfigKey.ts:24:19)
|
|
59
|
+
at new GGConfigKey (\GG_ROOT\packages\config\src\GGConfigKey.ts:60:26)
|
|
60
|
+
at new GGResource (\GG_ROOT\packages\config\src\keys\GGResource.ts:3:8)
|
|
61
|
+
at Object.createAwsSnsProviderConfig (\GG_ROOT\packages-libs\events\events-aws\src\AwsSnsAdapter.ts:26:19)
|
|
62
|
+
at new EventPublisherConfig (\GG_ROOT\packages-libs\events\events\src\pub\EventPublisherConfig.ts:56:52)
|
|
63
|
+
at EventPublisherResource.config (\GG_ROOT\packages-libs\events\events\src\pub\EventPublisherResource.ts:39:16)
|
|
64
|
+
at <anonymous> (\GG_ROOT\examples\checklist\checklist\ChecklistConfig.ts:26:41)
|
|
65
|
+
at AsyncLocalStorage.run (node:internal/async_local_storage/async_context_frame:63:14)
|
|
66
|
+
at GGConfig.define (\GG_ROOT\packages\config\src\GGConfig.ts:27:38)
|
|
67
|
+
at <anonymous> (\GG_ROOT\examples\checklist\checklist\ChecklistConfig.ts:8:41)
|
|
68
|
+
*/
|
|
69
|
+
const lines = stack.split('\n').reverse();
|
|
70
|
+
for (let i = 1; i < lines.length; i++) {
|
|
71
|
+
const line = lines[i];
|
|
72
|
+
// Remember that minification might change the names of things.
|
|
73
|
+
if (lines[i - 1]?.includes('at AsyncLocalStorage.run ') && line?.includes('at <anonymous>')) {
|
|
74
|
+
return line.substring(0, line.length - 1).trim().replace("at <anonymous> (", "");
|
|
75
|
+
}
|
|
76
|
+
}
|
|
77
|
+
return stack;
|
|
78
|
+
}
|
|
79
|
+
//# sourceMappingURL=GGConfigKey.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"GGConfigKey.js","sourceRoot":"","sources":["../../src/GGConfigKey.ts"],"names":[],"mappings":"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"}
|
|
@@ -0,0 +1,35 @@
|
|
|
1
|
+
import { GGConfigStore } from "./GGConfigStore";
|
|
2
|
+
import { GGConfigKey, GGConfigKeyConstructor } from "./GGConfigKey";
|
|
3
|
+
import { ConfigValues, GGConfigStoreLocal } from "./stores/GGConfigStoreLocal";
|
|
4
|
+
export type GGConfigDefinition<T> = T & {
|
|
5
|
+
__isGGConfigDefinition: never;
|
|
6
|
+
__getKeysMap: () => ReadonlyMap<GGConfigKeyConstructor, GGConfigKey[]>;
|
|
7
|
+
};
|
|
8
|
+
export declare class GGConfigLocator<T extends object> {
|
|
9
|
+
#private;
|
|
10
|
+
protected readonly localConfig: GGConfigStoreLocal<T, any>;
|
|
11
|
+
/**
|
|
12
|
+
* @param config - Config definition.
|
|
13
|
+
* @param localConfig - Optional local config values. If provided, stores will use this instead of the real values when not running in production.
|
|
14
|
+
* new GGConfigLocator(MyConfig, localConfig) is shorthand for this: new GGConfigLocator(MyConfig).add(AllKeys, new GGConfigStoreLocal(MyConfig, localConfig))
|
|
15
|
+
*/
|
|
16
|
+
constructor(config: GGConfigDefinition<T>, localConfig?: ConfigValues<T>);
|
|
17
|
+
/**
|
|
18
|
+
* Can override this if you want custom handling.
|
|
19
|
+
*/
|
|
20
|
+
onNotifyError: (error: Error) => never;
|
|
21
|
+
/**
|
|
22
|
+
* Add a config store for a key type.
|
|
23
|
+
*
|
|
24
|
+
* Note for framework development: Testkit overrides this function.
|
|
25
|
+
*/
|
|
26
|
+
add<Key extends GGConfigKey>(key: GGConfigKeyConstructor<Key> | GGConfigKeyConstructor<Key>[], store: GGConfigStore<Key>): this;
|
|
27
|
+
protected _useLocalStoreIfNeeded<Key extends GGConfigKey>(store: GGConfigStore<Key>): GGConfigStore<Key>;
|
|
28
|
+
protected _add<Key extends GGConfigKey>(key: GGConfigKeyConstructor<Key> | GGConfigKeyConstructor<Key>[], store: GGConfigStore<Key>): this;
|
|
29
|
+
getStore<Key extends GGConfigKey>(keyType: GGConfigKeyConstructor<Key>): GGConfigStore<Key>;
|
|
30
|
+
getStoreByConfigKeyName<Key extends GGConfigKey>(name: string): GGConfigStore<Key>;
|
|
31
|
+
getStores(): GGConfigStore<GGConfigKey>[];
|
|
32
|
+
start(): Promise<void>;
|
|
33
|
+
teardown(): Promise<void>;
|
|
34
|
+
}
|
|
35
|
+
//# sourceMappingURL=GGConfigLocator.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"GGConfigLocator.d.ts","sourceRoot":"","sources":["../../src/GGConfigLocator.ts"],"names":[],"mappings":"AAAA,OAAO,EAAC,aAAa,EAAC,MAAM,iBAAiB,CAAC;AAC9C,OAAO,EAAC,WAAW,EAAE,sBAAsB,EAAC,MAAM,eAAe,CAAC;AAGlE,OAAO,EAAC,YAAY,EAAE,kBAAkB,EAAC,MAAM,6BAA6B,CAAC;AAE7E,MAAM,MAAM,kBAAkB,CAAC,CAAC,IAAI,CAAC,GAAG;IACpC,sBAAsB,EAAE,KAAK,CAAC;IAC9B,YAAY,EAAE,MAAM,WAAW,CAAC,sBAAsB,EAAE,WAAW,EAAE,CAAC,CAAA;CACzE,CAAC;AAEF,qBAAa,eAAe,CAAC,CAAC,SAAS,MAAM;;IAOzC,SAAS,CAAC,QAAQ,CAAC,WAAW,EAAE,kBAAkB,CAAC,CAAC,EAAE,GAAG,CAAC,CAAY;IAEtE;;;;OAIG;gBACS,MAAM,EAAE,kBAAkB,CAAC,CAAC,CAAC,EAAE,WAAW,CAAC,EAAE,YAAY,CAAC,CAAC,CAAC;IAWxE;;OAEG;IACI,aAAa,GAAI,OAAO,KAAK,KAAG,KAAK,CAE3C;IAED;;;;OAIG;IACI,GAAG,CAAC,GAAG,SAAS,WAAW,EAAE,GAAG,EAAE,sBAAsB,CAAC,GAAG,CAAC,GAAG,sBAAsB,CAAC,GAAG,CAAC,EAAE,EAAE,KAAK,EAAE,aAAa,CAAC,GAAG,CAAC,GAAG,IAAI;IAItI,SAAS,CAAC,sBAAsB,CAAC,GAAG,SAAS,WAAW,EAAE,KAAK,EAAE,aAAa,CAAC,GAAG,CAAC,GAAG,aAAa,CAAC,GAAG,CAAC;IAQxG,SAAS,CAAC,IAAI,CAAC,GAAG,SAAS,WAAW,EAAE,GAAG,EAAE,sBAAsB,CAAC,GAAG,CAAC,GAAG,sBAAsB,CAAC,GAAG,CAAC,EAAE,EAAE,KAAK,EAAE,aAAa,CAAC,GAAG,CAAC,GAAG,IAAI;IAiBnI,QAAQ,CAAC,GAAG,SAAS,WAAW,EAAE,OAAO,EAAE,sBAAsB,CAAC,GAAG,CAAC,GAAG,aAAa,CAAC,GAAG,CAAC;IAI3F,uBAAuB,CAAC,GAAG,SAAS,WAAW,EAAE,IAAI,EAAE,MAAM,GAAG,aAAa,CAAC,GAAG,CAAC;IAQlF,SAAS,IAAI,aAAa,CAAC,WAAW,CAAC,EAAE;IAInC,KAAK,IAAI,OAAO,CAAC,IAAI,CAAC;IAetB,QAAQ,IAAI,OAAO,CAAC,IAAI,CAAC;CAGzC"}
|
|
@@ -0,0 +1,95 @@
|
|
|
1
|
+
import { GGLocator, GGLocatorServiceType } from "@grest-ts/locator";
|
|
2
|
+
import { GG_CONFIG } from "./GG_CONFIG.js";
|
|
3
|
+
import { GGConfigStoreLocal } from "./stores/GGConfigStoreLocal.js";
|
|
4
|
+
export class GGConfigLocator {
|
|
5
|
+
#isStarted = false;
|
|
6
|
+
#config;
|
|
7
|
+
#storesList = [];
|
|
8
|
+
#storesMap = new Map();
|
|
9
|
+
localConfig = undefined;
|
|
10
|
+
/**
|
|
11
|
+
* @param config - Config definition.
|
|
12
|
+
* @param localConfig - Optional local config values. If provided, stores will use this instead of the real values when not running in production.
|
|
13
|
+
* new GGConfigLocator(MyConfig, localConfig) is shorthand for this: new GGConfigLocator(MyConfig).add(AllKeys, new GGConfigStoreLocal(MyConfig, localConfig))
|
|
14
|
+
*/
|
|
15
|
+
constructor(config, localConfig) {
|
|
16
|
+
if (!config)
|
|
17
|
+
throw new Error("Config definition is required");
|
|
18
|
+
this.#config = config;
|
|
19
|
+
this.localConfig = localConfig ? new GGConfigStoreLocal(config, localConfig) : undefined;
|
|
20
|
+
GGLocator.getScope().setWithLifecycle(GG_CONFIG, this, {
|
|
21
|
+
type: GGLocatorServiceType.CONFIG,
|
|
22
|
+
start: () => this.start(),
|
|
23
|
+
teardown: () => this.teardown()
|
|
24
|
+
});
|
|
25
|
+
}
|
|
26
|
+
/**
|
|
27
|
+
* Can override this if you want custom handling.
|
|
28
|
+
*/
|
|
29
|
+
onNotifyError = (error) => {
|
|
30
|
+
throw error;
|
|
31
|
+
};
|
|
32
|
+
/**
|
|
33
|
+
* Add a config store for a key type.
|
|
34
|
+
*
|
|
35
|
+
* Note for framework development: Testkit overrides this function.
|
|
36
|
+
*/
|
|
37
|
+
add(key, store) {
|
|
38
|
+
return this._add(key, this._useLocalStoreIfNeeded(store));
|
|
39
|
+
}
|
|
40
|
+
_useLocalStoreIfNeeded(store) {
|
|
41
|
+
if (process.env.NODE_ENV === "production" || !this.localConfig) {
|
|
42
|
+
return store;
|
|
43
|
+
}
|
|
44
|
+
else {
|
|
45
|
+
return this.localConfig;
|
|
46
|
+
}
|
|
47
|
+
}
|
|
48
|
+
_add(key, store) {
|
|
49
|
+
if (this.#isStarted) {
|
|
50
|
+
throw new Error("Cannot add store after config holder is started");
|
|
51
|
+
}
|
|
52
|
+
const keyTypes = Array.isArray(key) ? key : [key];
|
|
53
|
+
const keysMap = this.#config.__getKeysMap();
|
|
54
|
+
for (const keyType of keyTypes) {
|
|
55
|
+
const keysForType = (keysMap.get(keyType) ?? []);
|
|
56
|
+
store.setKeys(keysForType);
|
|
57
|
+
this.#storesMap.set(keyType.NAME, store);
|
|
58
|
+
}
|
|
59
|
+
if (!this.#storesList.includes(store)) {
|
|
60
|
+
this.#storesList.push(store);
|
|
61
|
+
}
|
|
62
|
+
return this;
|
|
63
|
+
}
|
|
64
|
+
getStore(keyType) {
|
|
65
|
+
return this.getStoreByConfigKeyName(keyType.NAME);
|
|
66
|
+
}
|
|
67
|
+
getStoreByConfigKeyName(name) {
|
|
68
|
+
const store = this.#storesMap.get(name);
|
|
69
|
+
if (!store) {
|
|
70
|
+
throw new Error(`No store for store key: ${name ?? 'undefined'}.`);
|
|
71
|
+
}
|
|
72
|
+
return store;
|
|
73
|
+
}
|
|
74
|
+
getStores() {
|
|
75
|
+
return this.#storesList;
|
|
76
|
+
}
|
|
77
|
+
async start() {
|
|
78
|
+
if (this.#isStarted) {
|
|
79
|
+
throw new Error("Already started");
|
|
80
|
+
}
|
|
81
|
+
this.#isStarted = true;
|
|
82
|
+
this.#config.__getKeysMap().forEach((_, keyType) => {
|
|
83
|
+
if (!this.#storesMap.has(keyType.NAME)) {
|
|
84
|
+
throw new Error(`Missing stores for config key type '${keyType.NAME}'`);
|
|
85
|
+
}
|
|
86
|
+
});
|
|
87
|
+
Object.freeze(this.#storesMap);
|
|
88
|
+
Object.freeze(this.#storesList);
|
|
89
|
+
await Promise.all(this.#storesList.map((store) => store.start()));
|
|
90
|
+
}
|
|
91
|
+
async teardown() {
|
|
92
|
+
await Promise.all(this.#storesList.map(s => s.teardown()));
|
|
93
|
+
}
|
|
94
|
+
}
|
|
95
|
+
//# sourceMappingURL=GGConfigLocator.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"GGConfigLocator.js","sourceRoot":"","sources":["../../src/GGConfigLocator.ts"],"names":[],"mappings":"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"}
|
|
@@ -0,0 +1,24 @@
|
|
|
1
|
+
import { GGConfigKey } from "./GGConfigKey";
|
|
2
|
+
export type ConfigUpdateCallback = (value: any) => void | Promise<void>;
|
|
3
|
+
/**
|
|
4
|
+
* Important when extending: Use resolveValue() to resolve and validate config values.
|
|
5
|
+
*/
|
|
6
|
+
export declare abstract class GGConfigStore<Key extends GGConfigKey> {
|
|
7
|
+
#private;
|
|
8
|
+
get keys(): readonly Key[];
|
|
9
|
+
protected isStarted: boolean;
|
|
10
|
+
get started(): boolean;
|
|
11
|
+
setKeys(keys: readonly Key[]): void;
|
|
12
|
+
abstract getValue<T>(key: GGConfigKey<T>): T;
|
|
13
|
+
/**
|
|
14
|
+
* Resolves the final value for a config key: uses storeValue if present, falls back to key.getDefault(),
|
|
15
|
+
* then validates against schema. If the resolved value is undefined and the schema doesn't allow it,
|
|
16
|
+
* validation will fail — this is how missing required keys are caught.
|
|
17
|
+
*/
|
|
18
|
+
protected resolveValue<T>(key: GGConfigKey<T>, storeValue: unknown, isInitialLoad?: boolean): T;
|
|
19
|
+
start(): Promise<void>;
|
|
20
|
+
teardown(): Promise<void>;
|
|
21
|
+
watch(key: GGConfigKey, callback: ConfigUpdateCallback): () => void;
|
|
22
|
+
notify(key: GGConfigKey): Promise<void>;
|
|
23
|
+
}
|
|
24
|
+
//# sourceMappingURL=GGConfigStore.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"GGConfigStore.d.ts","sourceRoot":"","sources":["../../src/GGConfigStore.ts"],"names":[],"mappings":"AAAA,OAAO,EAAC,WAAW,EAAC,MAAM,eAAe,CAAC;AAG1C,MAAM,MAAM,oBAAoB,GAAG,CAAC,KAAK,EAAE,GAAG,KAAK,IAAI,GAAG,OAAO,CAAC,IAAI,CAAC,CAAC;AAExE;;GAEG;AACH,8BAAsB,aAAa,CAAC,GAAG,SAAS,WAAW;;IAGvD,IAAW,IAAI,IAAI,SAAS,GAAG,EAAE,CAAsB;IAGvD,SAAS,CAAC,SAAS,UAAS;IAE5B,IAAW,OAAO,IAAI,OAAO,CAE5B;IAEM,OAAO,CAAC,IAAI,EAAE,SAAS,GAAG,EAAE,GAAG,IAAI;aAO1B,QAAQ,CAAC,CAAC,EAAE,GAAG,EAAE,WAAW,CAAC,CAAC,CAAC,GAAG,CAAC;IAEnD;;;;OAIG;IACH,SAAS,CAAC,YAAY,CAAC,CAAC,EAAE,GAAG,EAAE,WAAW,CAAC,CAAC,CAAC,EAAE,UAAU,EAAE,OAAO,EAAE,aAAa,GAAE,OAAe,GAAG,CAAC;IAWzF,KAAK,IAAI,OAAO,CAAC,IAAI,CAAC;IAYtB,QAAQ,IAAI,OAAO,CAAC,IAAI,CAAC;IAK/B,KAAK,CAAC,GAAG,EAAE,WAAW,EAAE,QAAQ,EAAE,oBAAoB,GAAG,MAAM,IAAI;IAa7D,MAAM,CAAC,GAAG,EAAE,WAAW;CAwBvC"}
|
|
@@ -0,0 +1,89 @@
|
|
|
1
|
+
import { GG_CONFIG } from "./GG_CONFIG.js";
|
|
2
|
+
/**
|
|
3
|
+
* Important when extending: Use resolveValue() to resolve and validate config values.
|
|
4
|
+
*/
|
|
5
|
+
export class GGConfigStore {
|
|
6
|
+
#keys = [];
|
|
7
|
+
get keys() { return this.#keys; }
|
|
8
|
+
#watchers = new Map();
|
|
9
|
+
isStarted = false;
|
|
10
|
+
get started() {
|
|
11
|
+
return this.isStarted;
|
|
12
|
+
}
|
|
13
|
+
setKeys(keys) {
|
|
14
|
+
if (this.isStarted) {
|
|
15
|
+
throw new Error(`Cannot set keys after store is started: ${this.constructor.name}`);
|
|
16
|
+
}
|
|
17
|
+
this.#keys.push(...keys);
|
|
18
|
+
}
|
|
19
|
+
/**
|
|
20
|
+
* Resolves the final value for a config key: uses storeValue if present, falls back to key.getDefault(),
|
|
21
|
+
* then validates against schema. If the resolved value is undefined and the schema doesn't allow it,
|
|
22
|
+
* validation will fail — this is how missing required keys are caught.
|
|
23
|
+
*/
|
|
24
|
+
resolveValue(key, storeValue, isInitialLoad = false) {
|
|
25
|
+
const val = storeValue !== undefined ? storeValue : key.getDefault();
|
|
26
|
+
const check = key.schema.safeParse(val);
|
|
27
|
+
if (check.success === false) {
|
|
28
|
+
const errors = JSON.stringify(check.issues.toJSON(), null, 2).replaceAll("\n", "\n\t\t");
|
|
29
|
+
throw new Error(`Config validation failed for "${key.name}" during ${isInitialLoad ? "initial-load" : "reload"}.\n\tDefined at:\n\t\t${key.definedAt}\n\tIssues:\n\t\t${errors}`);
|
|
30
|
+
}
|
|
31
|
+
else {
|
|
32
|
+
return check.value;
|
|
33
|
+
}
|
|
34
|
+
}
|
|
35
|
+
async start() {
|
|
36
|
+
if (this.isStarted === true) {
|
|
37
|
+
throw new Error(`Config store already started: ${this.constructor.name}`);
|
|
38
|
+
}
|
|
39
|
+
this.isStarted = true;
|
|
40
|
+
Object.freeze(this.#keys);
|
|
41
|
+
this.keys.forEach(key => {
|
|
42
|
+
this.getValue(key); // Get every value so that config values are definitely initialized (or they would throw)
|
|
43
|
+
});
|
|
44
|
+
}
|
|
45
|
+
async teardown() {
|
|
46
|
+
this.#watchers.clear();
|
|
47
|
+
this.isStarted = false;
|
|
48
|
+
}
|
|
49
|
+
watch(key, callback) {
|
|
50
|
+
if (!this.#watchers.has(key)) {
|
|
51
|
+
this.#watchers.set(key, []);
|
|
52
|
+
}
|
|
53
|
+
this.#watchers.get(key).push(callback);
|
|
54
|
+
return () => {
|
|
55
|
+
const list = this.#watchers.get(key);
|
|
56
|
+
if (!list)
|
|
57
|
+
return;
|
|
58
|
+
const index = list.indexOf(callback);
|
|
59
|
+
if (index >= 0)
|
|
60
|
+
list.splice(index, 1);
|
|
61
|
+
};
|
|
62
|
+
}
|
|
63
|
+
async notify(key) {
|
|
64
|
+
if (this.#watchers.has(key)) {
|
|
65
|
+
const promises = [];
|
|
66
|
+
const newValue = this.getValue(key);
|
|
67
|
+
this.#watchers.get(key).forEach(callback => {
|
|
68
|
+
try {
|
|
69
|
+
const result = callback(newValue);
|
|
70
|
+
if (result instanceof Promise) {
|
|
71
|
+
promises.push(result);
|
|
72
|
+
}
|
|
73
|
+
}
|
|
74
|
+
catch (err) {
|
|
75
|
+
GG_CONFIG.get().onNotifyError(err);
|
|
76
|
+
}
|
|
77
|
+
});
|
|
78
|
+
if (promises.length > 0) {
|
|
79
|
+
const results = await Promise.allSettled(promises);
|
|
80
|
+
for (const result of results) {
|
|
81
|
+
if (result.status === 'rejected') {
|
|
82
|
+
GG_CONFIG.get().onNotifyError(result.reason);
|
|
83
|
+
}
|
|
84
|
+
}
|
|
85
|
+
}
|
|
86
|
+
}
|
|
87
|
+
}
|
|
88
|
+
}
|
|
89
|
+
//# sourceMappingURL=GGConfigStore.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"GGConfigStore.js","sourceRoot":"","sources":["../../src/GGConfigStore.ts"],"names":[],"mappings":"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"}
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"GG_CONFIG.d.ts","sourceRoot":"","sources":["../../src/GG_CONFIG.ts"],"names":[],"mappings":"AAAA,OAAO,EAAC,YAAY,EAAC,MAAM,mBAAmB,CAAC;AAC/C,OAAO,KAAK,EAAC,eAAe,EAAC,MAAM,mBAAmB,CAAC;AAEvD,eAAO,MAAM,SAAS,oCAAqD,CAAC"}
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"GG_CONFIG.js","sourceRoot":"","sources":["../../src/GG_CONFIG.ts"],"names":[],"mappings":"AAAA,OAAO,EAAC,YAAY,EAAC,MAAM,mBAAmB,CAAC;AAG/C,MAAM,CAAC,MAAM,SAAS,GAAG,IAAI,YAAY,CAAuB,UAAU,CAAC,CAAC"}
|
|
@@ -0,0 +1,12 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Validates config key name for compatibility with external providers.
|
|
3
|
+
* Rules:
|
|
4
|
+
* - Must start with forward slash
|
|
5
|
+
* - Only letters, numbers, underscore, forward slash allowed
|
|
6
|
+
* - Each segment (word) must start with a letter
|
|
7
|
+
* - No double slashes
|
|
8
|
+
* - Cannot end with slash
|
|
9
|
+
* - Max 2048 characters (AWS limit)
|
|
10
|
+
*/
|
|
11
|
+
export declare function assureValidConfigPath(path: string): void;
|
|
12
|
+
//# sourceMappingURL=assureValidConfigPath.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"assureValidConfigPath.d.ts","sourceRoot":"","sources":["../../src/assureValidConfigPath.ts"],"names":[],"mappings":"AAAA;;;;;;;;;GASG;AACH,wBAAgB,qBAAqB,CAAC,IAAI,EAAE,MAAM,QAuBjD"}
|
|
@@ -0,0 +1,35 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Validates config key name for compatibility with external providers.
|
|
3
|
+
* Rules:
|
|
4
|
+
* - Must start with forward slash
|
|
5
|
+
* - Only letters, numbers, underscore, forward slash allowed
|
|
6
|
+
* - Each segment (word) must start with a letter
|
|
7
|
+
* - No double slashes
|
|
8
|
+
* - Cannot end with slash
|
|
9
|
+
* - Max 2048 characters (AWS limit)
|
|
10
|
+
*/
|
|
11
|
+
export function assureValidConfigPath(path) {
|
|
12
|
+
if (path.length > 2048) {
|
|
13
|
+
throw new Error(`Config key name exceeds 2048 characters: ${path}`);
|
|
14
|
+
}
|
|
15
|
+
if (!path.startsWith('/')) {
|
|
16
|
+
throw new Error(`Config key name must start with '/': ${path}`);
|
|
17
|
+
}
|
|
18
|
+
if (path.endsWith('/')) {
|
|
19
|
+
throw new Error(`Config key name cannot end with '/': ${path}`);
|
|
20
|
+
}
|
|
21
|
+
if (path.includes('//')) {
|
|
22
|
+
throw new Error(`Config key name cannot contain '//': ${path}`);
|
|
23
|
+
}
|
|
24
|
+
if (!/^[a-zA-Z0-9_\/]+$/.test(path)) {
|
|
25
|
+
throw new Error(`Config key name contains invalid characters (allowed: a-z, A-Z, 0-9, _, /): ${path}`);
|
|
26
|
+
}
|
|
27
|
+
// Each segment must start with a letter
|
|
28
|
+
const segments = path.split('/').filter(s => s.length > 0);
|
|
29
|
+
for (const segment of segments) {
|
|
30
|
+
if (!/^[a-zA-Z]/.test(segment)) {
|
|
31
|
+
throw new Error(`Each path segment must start with a letter: ${path}`);
|
|
32
|
+
}
|
|
33
|
+
}
|
|
34
|
+
}
|
|
35
|
+
//# sourceMappingURL=assureValidConfigPath.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"assureValidConfigPath.js","sourceRoot":"","sources":["../../src/assureValidConfigPath.ts"],"names":[],"mappings":"AAAA;;;;;;;;;GASG;AACH,MAAM,UAAU,qBAAqB,CAAC,IAAY;IAC9C,IAAI,IAAI,CAAC,MAAM,GAAG,IAAI,EAAE,CAAC;QACrB,MAAM,IAAI,KAAK,CAAC,4CAA4C,IAAI,EAAE,CAAC,CAAC;IACxE,CAAC;IACD,IAAI,CAAC,IAAI,CAAC,UAAU,CAAC,GAAG,CAAC,EAAE,CAAC;QACxB,MAAM,IAAI,KAAK,CAAC,wCAAwC,IAAI,EAAE,CAAC,CAAC;IACpE,CAAC;IACD,IAAI,IAAI,CAAC,QAAQ,CAAC,GAAG,CAAC,EAAE,CAAC;QACrB,MAAM,IAAI,KAAK,CAAC,wCAAwC,IAAI,EAAE,CAAC,CAAC;IACpE,CAAC;IACD,IAAI,IAAI,CAAC,QAAQ,CAAC,IAAI,CAAC,EAAE,CAAC;QACtB,MAAM,IAAI,KAAK,CAAC,wCAAwC,IAAI,EAAE,CAAC,CAAC;IACpE,CAAC;IACD,IAAI,CAAC,mBAAmB,CAAC,IAAI,CAAC,IAAI,CAAC,EAAE,CAAC;QAClC,MAAM,IAAI,KAAK,CAAC,+EAA+E,IAAI,EAAE,CAAC,CAAC;IAC3G,CAAC;IACD,wCAAwC;IACxC,MAAM,QAAQ,GAAG,IAAI,CAAC,KAAK,CAAC,GAAG,CAAC,CAAC,MAAM,CAAC,CAAC,CAAC,EAAE,CAAC,CAAC,CAAC,MAAM,GAAG,CAAC,CAAC,CAAC;IAC3D,KAAK,MAAM,OAAO,IAAI,QAAQ,EAAE,CAAC;QAC7B,IAAI,CAAC,WAAW,CAAC,IAAI,CAAC,OAAO,CAAC,EAAE,CAAC;YAC7B,MAAM,IAAI,KAAK,CAAC,+CAA+C,IAAI,EAAE,CAAC,CAAC;QAC3E,CAAC;IACL,CAAC;AACL,CAAC"}
|
|
@@ -0,0 +1,12 @@
|
|
|
1
|
+
export * from './GGConfig';
|
|
2
|
+
export * from './GG_CONFIG';
|
|
3
|
+
export * from './GGConfigLocator';
|
|
4
|
+
export * from "./GGConfigKey";
|
|
5
|
+
export * from "./GGConfigStore";
|
|
6
|
+
export * from "./stores/GGConfigStoreFile";
|
|
7
|
+
export * from "./stores/GGConfigStoreLocal";
|
|
8
|
+
export * from "./keys/GGSetting";
|
|
9
|
+
export * from "./keys/GGSecret";
|
|
10
|
+
export * from "./keys/GGResource";
|
|
11
|
+
export { assureValidConfigPath } from "./assureValidConfigPath";
|
|
12
|
+
//# sourceMappingURL=index-node.d.ts.map
|