@guanghechen/config 2.0.0 → 2.0.1
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 +112 -2
- package/lib/cjs/index.cjs +0 -7
- package/lib/esm/index.mjs +0 -1
- package/lib/types/index.d.ts +56 -4
- package/package.json +17 -19
package/LICENSE
ADDED
|
@@ -0,0 +1,21 @@
|
|
|
1
|
+
MIT License
|
|
2
|
+
|
|
3
|
+
Copyright (c) 2023-present guanghechen (https://github.com/guanghechen)
|
|
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
CHANGED
|
@@ -49,7 +49,9 @@
|
|
|
49
49
|
</header>
|
|
50
50
|
<br/>
|
|
51
51
|
|
|
52
|
-
Utilities for defining
|
|
52
|
+
Utilities for defining versioned configuration with integrity verification. Provides base classes
|
|
53
|
+
for managing configuration data with semantic versioning compatibility checks, MAC (Message
|
|
54
|
+
Authentication Code) validation, and resource-based persistence.
|
|
53
55
|
|
|
54
56
|
## Install
|
|
55
57
|
|
|
@@ -67,5 +69,113 @@ Utilities for defining config followed by semantic version.
|
|
|
67
69
|
|
|
68
70
|
## Usage
|
|
69
71
|
|
|
72
|
+
### Using PlainJsonConfigKeeper
|
|
73
|
+
|
|
74
|
+
For simple JSON configurations without custom serialization:
|
|
75
|
+
|
|
76
|
+
```typescript
|
|
77
|
+
import { PlainJsonConfigKeeper } from '@guanghechen/config'
|
|
78
|
+
import type { ITextResource } from '@guanghechen/types'
|
|
79
|
+
|
|
80
|
+
interface IAppConfig {
|
|
81
|
+
theme: 'light' | 'dark'
|
|
82
|
+
language: string
|
|
83
|
+
autoSave: boolean
|
|
84
|
+
}
|
|
85
|
+
|
|
86
|
+
// Create a text resource (e.g., file-based)
|
|
87
|
+
const resource: ITextResource = {
|
|
88
|
+
load: async () => { /* read from file */ },
|
|
89
|
+
save: async (content: string) => { /* write to file */ },
|
|
90
|
+
destroy: async () => { /* cleanup */ },
|
|
91
|
+
}
|
|
92
|
+
|
|
93
|
+
const keeper = new PlainJsonConfigKeeper<IAppConfig>({ resource })
|
|
94
|
+
|
|
95
|
+
// Load existing config
|
|
96
|
+
const config = await keeper.load()
|
|
97
|
+
console.log(config.theme) // 'light'
|
|
98
|
+
|
|
99
|
+
// Update and save
|
|
100
|
+
await keeper.update({ ...config, theme: 'dark' })
|
|
101
|
+
await keeper.save()
|
|
102
|
+
```
|
|
103
|
+
|
|
104
|
+
### Creating Custom ConfigKeeper
|
|
105
|
+
|
|
106
|
+
For configurations requiring custom serialization/deserialization:
|
|
107
|
+
|
|
108
|
+
```typescript
|
|
109
|
+
import { JsonConfigKeeper } from '@guanghechen/config'
|
|
110
|
+
import type { ITextResource } from '@guanghechen/types'
|
|
111
|
+
|
|
112
|
+
// Runtime instance type
|
|
113
|
+
interface IUserSettings {
|
|
114
|
+
username: string
|
|
115
|
+
createdAt: Date
|
|
116
|
+
preferences: Map<string, string>
|
|
117
|
+
}
|
|
118
|
+
|
|
119
|
+
// Serializable data type (JSON-compatible)
|
|
120
|
+
interface IUserSettingsData {
|
|
121
|
+
username: string
|
|
122
|
+
createdAt: string // ISO date string
|
|
123
|
+
preferences: Array<[string, string]>
|
|
124
|
+
}
|
|
125
|
+
|
|
126
|
+
class UserSettingsKeeper extends JsonConfigKeeper<IUserSettings, IUserSettingsData> {
|
|
127
|
+
public readonly __version__ = '1.0.0'
|
|
128
|
+
public readonly __compatible_version__ = '~1.0.0' // semver range
|
|
129
|
+
|
|
130
|
+
protected async serialize(instance: IUserSettings): Promise<IUserSettingsData> {
|
|
131
|
+
return {
|
|
132
|
+
username: instance.username,
|
|
133
|
+
createdAt: instance.createdAt.toISOString(),
|
|
134
|
+
preferences: Array.from(instance.preferences.entries()),
|
|
135
|
+
}
|
|
136
|
+
}
|
|
137
|
+
|
|
138
|
+
protected async deserialize(data: IUserSettingsData): Promise<IUserSettings> {
|
|
139
|
+
return {
|
|
140
|
+
username: data.username,
|
|
141
|
+
createdAt: new Date(data.createdAt),
|
|
142
|
+
preferences: new Map(data.preferences),
|
|
143
|
+
}
|
|
144
|
+
}
|
|
145
|
+
}
|
|
146
|
+
|
|
147
|
+
const keeper = new UserSettingsKeeper({ resource })
|
|
148
|
+
|
|
149
|
+
// Load, modify, save
|
|
150
|
+
const settings = await keeper.load()
|
|
151
|
+
settings.preferences.set('fontSize', '14px')
|
|
152
|
+
await keeper.update(settings)
|
|
153
|
+
await keeper.save()
|
|
154
|
+
```
|
|
155
|
+
|
|
156
|
+
### Version Compatibility
|
|
157
|
+
|
|
158
|
+
The config keeper enforces version compatibility using semantic versioning:
|
|
159
|
+
|
|
160
|
+
```typescript
|
|
161
|
+
class MyConfigKeeper extends JsonConfigKeeper<MyInstance, MyData> {
|
|
162
|
+
public readonly __version__ = '2.1.0'
|
|
163
|
+
public readonly __compatible_version__ = '^2.0.0' // accepts 2.x.x
|
|
164
|
+
|
|
165
|
+
// ... serialize/deserialize implementations
|
|
166
|
+
}
|
|
167
|
+
|
|
168
|
+
const keeper = new MyConfigKeeper({ resource })
|
|
169
|
+
|
|
170
|
+
// Check version compatibility manually
|
|
171
|
+
if (keeper.compatible('2.0.5')) {
|
|
172
|
+
console.log('Version is compatible')
|
|
173
|
+
}
|
|
174
|
+
```
|
|
175
|
+
|
|
176
|
+
## Reference
|
|
177
|
+
|
|
178
|
+
- [homepage][homepage]
|
|
179
|
+
|
|
70
180
|
[homepage]:
|
|
71
|
-
https://github.com/guanghechen/sora/tree/@guanghechen/config@2.0.0/packages/config#readme
|
|
181
|
+
https://github.com/guanghechen/sora/tree/@guanghechen/config@2.0.0/packages/config#readme
|
package/lib/cjs/index.cjs
CHANGED
|
@@ -4,7 +4,6 @@ var byte = require('@guanghechen/byte');
|
|
|
4
4
|
var invariant = require('@guanghechen/invariant');
|
|
5
5
|
var version = require('@guanghechen/version');
|
|
6
6
|
var node_crypto = require('node:crypto');
|
|
7
|
-
var config_types = require('@guanghechen/config.types');
|
|
8
7
|
|
|
9
8
|
function calcMac(chunks, algorithm) {
|
|
10
9
|
const hash = node_crypto.createHash(algorithm);
|
|
@@ -108,9 +107,3 @@ class PlainJsonConfigKeeper extends JsonConfigKeeper {
|
|
|
108
107
|
exports.BaseConfigKeeper = BaseConfigKeeper;
|
|
109
108
|
exports.JsonConfigKeeper = JsonConfigKeeper;
|
|
110
109
|
exports.PlainJsonConfigKeeper = PlainJsonConfigKeeper;
|
|
111
|
-
Object.keys(config_types).forEach(function (k) {
|
|
112
|
-
if (k !== 'default' && !Object.prototype.hasOwnProperty.call(exports, k)) Object.defineProperty(exports, k, {
|
|
113
|
-
enumerable: true,
|
|
114
|
-
get: function () { return config_types[k]; }
|
|
115
|
-
});
|
|
116
|
-
});
|
package/lib/esm/index.mjs
CHANGED
|
@@ -2,7 +2,6 @@ import { bytes2text, randomBytes, text2bytes } from '@guanghechen/byte';
|
|
|
2
2
|
import { invariant } from '@guanghechen/invariant';
|
|
3
3
|
import { satisfies } from '@guanghechen/version';
|
|
4
4
|
import { createHash } from 'node:crypto';
|
|
5
|
-
export * from '@guanghechen/config.types';
|
|
6
5
|
|
|
7
6
|
function calcMac(chunks, algorithm) {
|
|
8
7
|
const hash = createHash(algorithm);
|
package/lib/types/index.d.ts
CHANGED
|
@@ -1,9 +1,61 @@
|
|
|
1
|
-
import {
|
|
2
|
-
export * from '@guanghechen/config.types';
|
|
3
|
-
import { ITextResource } from '@guanghechen/resource';
|
|
1
|
+
import { ITextResource } from '@guanghechen/types';
|
|
4
2
|
|
|
5
3
|
type IHashAlgorithm = 'md5' | 'sha1' | 'sha256' | 'sha512';
|
|
6
4
|
|
|
5
|
+
interface IConfig<Data> {
|
|
6
|
+
/**
|
|
7
|
+
* Config version.
|
|
8
|
+
*/
|
|
9
|
+
__version__: string;
|
|
10
|
+
/**
|
|
11
|
+
* Mac of data.
|
|
12
|
+
*/
|
|
13
|
+
__mac__: string;
|
|
14
|
+
/**
|
|
15
|
+
* A random string.
|
|
16
|
+
*/
|
|
17
|
+
__nonce__: string | undefined;
|
|
18
|
+
/**
|
|
19
|
+
* Payload data.
|
|
20
|
+
*/
|
|
21
|
+
data: Data;
|
|
22
|
+
}
|
|
23
|
+
interface IConfigKeeper<D> {
|
|
24
|
+
readonly __version__: string;
|
|
25
|
+
readonly __compatible_version__: string;
|
|
26
|
+
/**
|
|
27
|
+
* Current holding data.
|
|
28
|
+
*/
|
|
29
|
+
readonly data: Readonly<D> | undefined;
|
|
30
|
+
/**
|
|
31
|
+
* Check if the given version is compatible.
|
|
32
|
+
* @param version
|
|
33
|
+
*/
|
|
34
|
+
compatible(version: string): boolean;
|
|
35
|
+
/**
|
|
36
|
+
* Remove the config data.
|
|
37
|
+
*/
|
|
38
|
+
destroy(): Promise<void>;
|
|
39
|
+
/**
|
|
40
|
+
* Load data from the given resource or default resource, this will update the holding data.
|
|
41
|
+
*/
|
|
42
|
+
load(resource?: ITextResource): Promise<D | never>;
|
|
43
|
+
/**
|
|
44
|
+
* Parse the data from the given config content, this won't update the holding data.
|
|
45
|
+
* @param configContent
|
|
46
|
+
*/
|
|
47
|
+
parse(configContent: string): Promise<D | never>;
|
|
48
|
+
/**
|
|
49
|
+
* Save current holding data into the given resource or default resource.
|
|
50
|
+
*/
|
|
51
|
+
save(resource?: ITextResource): Promise<void>;
|
|
52
|
+
/**
|
|
53
|
+
* Update the holding data.
|
|
54
|
+
* @param data
|
|
55
|
+
*/
|
|
56
|
+
update(data: D): Promise<void>;
|
|
57
|
+
}
|
|
58
|
+
|
|
7
59
|
interface IBaseConfigKeeperProps {
|
|
8
60
|
/**
|
|
9
61
|
* The resource which hold the config data.
|
|
@@ -54,4 +106,4 @@ declare class PlainJsonConfigKeeper<Data> extends JsonConfigKeeper<Data, Data> i
|
|
|
54
106
|
}
|
|
55
107
|
|
|
56
108
|
export { BaseConfigKeeper, JsonConfigKeeper, PlainJsonConfigKeeper };
|
|
57
|
-
export type { IBaseConfigKeeperProps, IJsonConfigKeeperProps };
|
|
109
|
+
export type { IBaseConfigKeeperProps, IConfig, IConfigKeeper, IJsonConfigKeeperProps };
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@guanghechen/config",
|
|
3
|
-
"version": "2.0.
|
|
3
|
+
"version": "2.0.1",
|
|
4
4
|
"author": {
|
|
5
5
|
"name": "guanghechen",
|
|
6
6
|
"url": "https://github.com/guanghechen/"
|
|
@@ -8,17 +8,17 @@
|
|
|
8
8
|
"description": "Utilities for defining config followed by semantic version.",
|
|
9
9
|
"repository": {
|
|
10
10
|
"type": "git",
|
|
11
|
-
"url": "https://github.com/guanghechen/sora/tree/@guanghechen/config@
|
|
11
|
+
"url": "https://github.com/guanghechen/sora/tree/@guanghechen/config@2.0.0",
|
|
12
12
|
"directory": "packages/config"
|
|
13
13
|
},
|
|
14
|
-
"homepage": "https://github.com/guanghechen/sora/tree/@guanghechen/config@
|
|
14
|
+
"homepage": "https://github.com/guanghechen/sora/tree/@guanghechen/config@2.0.0/packages/config#readme",
|
|
15
15
|
"type": "module",
|
|
16
16
|
"exports": {
|
|
17
17
|
".": {
|
|
18
|
+
"types": "./lib/types/index.d.ts",
|
|
18
19
|
"source": "./src/index.ts",
|
|
19
20
|
"import": "./lib/esm/index.mjs",
|
|
20
|
-
"require": "./lib/cjs/index.cjs"
|
|
21
|
-
"types": "./lib/types/index.d.ts"
|
|
21
|
+
"require": "./lib/cjs/index.cjs"
|
|
22
22
|
}
|
|
23
23
|
},
|
|
24
24
|
"source": "./src/index.ts",
|
|
@@ -26,13 +26,6 @@
|
|
|
26
26
|
"module": "./lib/esm/index.mjs",
|
|
27
27
|
"types": "./lib/types/index.d.ts",
|
|
28
28
|
"license": "MIT",
|
|
29
|
-
"scripts": {
|
|
30
|
-
"build": "rollup -c ../../rollup.config.mjs",
|
|
31
|
-
"clean": "rimraf lib",
|
|
32
|
-
"test": "vitest run --config ../../vitest.config.ts",
|
|
33
|
-
"test:coverage": "vitest run --config ../../vitest.config.ts --coverage",
|
|
34
|
-
"test:update": "vitest run --config ../../vitest.config.ts -u"
|
|
35
|
-
},
|
|
36
29
|
"files": [
|
|
37
30
|
"lib/",
|
|
38
31
|
"!lib/**/*.map",
|
|
@@ -42,11 +35,16 @@
|
|
|
42
35
|
"README.md"
|
|
43
36
|
],
|
|
44
37
|
"dependencies": {
|
|
45
|
-
"@guanghechen/byte": "^2.0.
|
|
46
|
-
"@guanghechen/
|
|
47
|
-
"@guanghechen/
|
|
48
|
-
"@guanghechen/
|
|
49
|
-
"@guanghechen/version": "^1.0.0"
|
|
38
|
+
"@guanghechen/byte": "^2.0.1",
|
|
39
|
+
"@guanghechen/invariant": "^7.0.1",
|
|
40
|
+
"@guanghechen/types": "^2.0.1",
|
|
41
|
+
"@guanghechen/version": "^1.0.1"
|
|
50
42
|
},
|
|
51
|
-
"
|
|
52
|
-
|
|
43
|
+
"scripts": {
|
|
44
|
+
"build": "rollup -c ../../rollup.config.mjs",
|
|
45
|
+
"clean": "rimraf lib",
|
|
46
|
+
"test": "vitest run --config ../../vitest.config.ts",
|
|
47
|
+
"test:coverage": "vitest run --config ../../vitest.config.ts --coverage",
|
|
48
|
+
"test:update": "vitest run --config ../../vitest.config.ts -u"
|
|
49
|
+
}
|
|
50
|
+
}
|