@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 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 config followed by semantic version.
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);
@@ -1,9 +1,61 @@
1
- import { IConfigKeeper, IConfig } from '@guanghechen/config.types';
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.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@1.0.5",
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@1.0.5/packages/config#readme",
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.0",
46
- "@guanghechen/config.types": "^2.0.0",
47
- "@guanghechen/invariant": "^7.0.0",
48
- "@guanghechen/resource": "^2.0.0",
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
- "gitHead": "12990a720b31d50d217e2e17a6191256dc94eda6"
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
+ }