@wgtechlabs/config-engine 0.1.0-staging.d0d9e7f
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 +306 -0
- package/dist/cache.d.ts +36 -0
- package/dist/cache.d.ts.map +1 -0
- package/dist/chunk-gs6j6hrj.js +35 -0
- package/dist/chunk-gs6j6hrj.js.map +10 -0
- package/dist/dot-prop.d.ts +35 -0
- package/dist/dot-prop.d.ts.map +1 -0
- package/dist/encryption.d.ts +31 -0
- package/dist/encryption.d.ts.map +1 -0
- package/dist/index.d.ts +124 -0
- package/dist/index.d.ts.map +1 -0
- package/dist/index.js +967 -0
- package/dist/index.js.map +17 -0
- package/dist/migrations.d.ts +22 -0
- package/dist/migrations.d.ts.map +1 -0
- package/dist/platform.d.ts +23 -0
- package/dist/platform.d.ts.map +1 -0
- package/dist/runtime.d.ts +15 -0
- package/dist/runtime.d.ts.map +1 -0
- package/dist/store.d.ts +48 -0
- package/dist/store.d.ts.map +1 -0
- package/dist/types.d.ts +139 -0
- package/dist/types.d.ts.map +1 -0
- package/dist/validation.d.ts +28 -0
- package/dist/validation.d.ts.map +1 -0
- package/dist/validation.js +10 -0
- package/dist/validation.js.map +9 -0
- package/package.json +82 -0
package/LICENSE
ADDED
|
@@ -0,0 +1,21 @@
|
|
|
1
|
+
MIT License
|
|
2
|
+
|
|
3
|
+
Copyright (c) 2026 Waren Gonzaga, WG Technology Labs
|
|
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,306 @@
|
|
|
1
|
+
# @wgtechlabs/config-engine
|
|
2
|
+
|
|
3
|
+

|
|
4
|
+
<!-- Created with GitHub Repo Banner by Waren Gonzaga: https://ghrb.waren.build -->
|
|
5
|
+
|
|
6
|
+
> Configs should be easy.
|
|
7
|
+
|
|
8
|
+
Fast, Bun-first configuration SDK for AI agent frameworks, CLI apps, and applications — backed by SQLite with in-memory caching, Zod validation, and optional encryption.
|
|
9
|
+
|
|
10
|
+
## Use Cases
|
|
11
|
+
|
|
12
|
+
- **AI agent frameworks** — persistent agent settings, model preferences, API key management, and runtime configuration
|
|
13
|
+
- **CLI applications** — user preferences, saved credentials, and tool configuration that persists across sessions
|
|
14
|
+
- **Desktop & server apps** — application settings with schema validation, safe migrations, and multi-process access
|
|
15
|
+
|
|
16
|
+
## Features
|
|
17
|
+
|
|
18
|
+
- **SQLite-backed** — ACID transactions, WAL mode, multi-process safe
|
|
19
|
+
- **In-memory cache** — zero disk I/O on reads, configurable write-behind flush
|
|
20
|
+
- **Zod validation** — built-in schema validation with pluggable validator interface
|
|
21
|
+
- **Dot-notation access** — `config.get("ui.sidebar.width")` just works
|
|
22
|
+
- **Async migrations** — version-based with full transaction rollback on failure
|
|
23
|
+
- **Optional encryption** — AES-256-GCM via [`@wgtechlabs/secrets-engine`](https://github.com/wgtechlabs/secrets-engine) or bring your own
|
|
24
|
+
- **Change events** — watch specific keys or the entire store
|
|
25
|
+
- **Bun-first, Node.js compatible** — uses `bun:sqlite` natively, `better-sqlite3` on Node.js
|
|
26
|
+
|
|
27
|
+
## Install
|
|
28
|
+
|
|
29
|
+
```bash
|
|
30
|
+
bun add @wgtechlabs/config-engine
|
|
31
|
+
```
|
|
32
|
+
|
|
33
|
+
For Node.js, also install the SQLite driver:
|
|
34
|
+
|
|
35
|
+
```bash
|
|
36
|
+
npm install @wgtechlabs/config-engine better-sqlite3
|
|
37
|
+
```
|
|
38
|
+
|
|
39
|
+
## Quick Start
|
|
40
|
+
|
|
41
|
+
```typescript
|
|
42
|
+
import { ConfigEngine } from "@wgtechlabs/config-engine";
|
|
43
|
+
|
|
44
|
+
const config = await ConfigEngine.open({
|
|
45
|
+
projectName: "my-app",
|
|
46
|
+
defaults: {
|
|
47
|
+
theme: "dark",
|
|
48
|
+
fontSize: 14,
|
|
49
|
+
sidebar: { width: 300, visible: true },
|
|
50
|
+
},
|
|
51
|
+
});
|
|
52
|
+
|
|
53
|
+
// Read (zero disk I/O — reads from in-memory cache)
|
|
54
|
+
config.get("theme"); // "dark"
|
|
55
|
+
config.get("sidebar.width"); // 300 (dot-notation)
|
|
56
|
+
|
|
57
|
+
// Write
|
|
58
|
+
config.set("fontSize", 16);
|
|
59
|
+
config.set({ theme: "light", fontSize: 12 });
|
|
60
|
+
config.set("sidebar.visible", false);
|
|
61
|
+
|
|
62
|
+
// Check & delete
|
|
63
|
+
config.has("theme"); // true
|
|
64
|
+
config.delete("theme");
|
|
65
|
+
|
|
66
|
+
// Iterate
|
|
67
|
+
for (const [key, value] of config) {
|
|
68
|
+
console.log(key, value);
|
|
69
|
+
}
|
|
70
|
+
|
|
71
|
+
// Close when done
|
|
72
|
+
config.close();
|
|
73
|
+
```
|
|
74
|
+
|
|
75
|
+
## Validation with Zod
|
|
76
|
+
|
|
77
|
+
```typescript
|
|
78
|
+
import { ConfigEngine } from "@wgtechlabs/config-engine";
|
|
79
|
+
import { z } from "zod";
|
|
80
|
+
|
|
81
|
+
const config = await ConfigEngine.open({
|
|
82
|
+
projectName: "my-app",
|
|
83
|
+
defaults: { theme: "dark", fontSize: 14 },
|
|
84
|
+
schema: z.object({
|
|
85
|
+
theme: z.enum(["light", "dark"]),
|
|
86
|
+
fontSize: z.number().min(8).max(72),
|
|
87
|
+
}),
|
|
88
|
+
});
|
|
89
|
+
|
|
90
|
+
config.set("fontSize", 16); // OK
|
|
91
|
+
config.set("fontSize", 200); // Throws ValidationError
|
|
92
|
+
```
|
|
93
|
+
|
|
94
|
+
### Custom Validator (Pluggable)
|
|
95
|
+
|
|
96
|
+
Bring your own validation library (Valibot, AJV, etc.):
|
|
97
|
+
|
|
98
|
+
```typescript
|
|
99
|
+
import { ConfigEngine, type Validator } from "@wgtechlabs/config-engine";
|
|
100
|
+
|
|
101
|
+
const myValidator: Validator<MyConfig> = {
|
|
102
|
+
validate(data) {
|
|
103
|
+
// Your validation logic
|
|
104
|
+
if (isValid(data)) {
|
|
105
|
+
return { success: true, data: data as MyConfig };
|
|
106
|
+
}
|
|
107
|
+
return { success: false, errors: ["Validation failed"] };
|
|
108
|
+
},
|
|
109
|
+
};
|
|
110
|
+
|
|
111
|
+
const config = await ConfigEngine.open({
|
|
112
|
+
projectName: "my-app",
|
|
113
|
+
validator: myValidator,
|
|
114
|
+
});
|
|
115
|
+
```
|
|
116
|
+
|
|
117
|
+
## Migrations
|
|
118
|
+
|
|
119
|
+
Robust, async-capable migration system with full SQLite transaction rollback:
|
|
120
|
+
|
|
121
|
+
```typescript
|
|
122
|
+
const config = await ConfigEngine.open({
|
|
123
|
+
projectName: "my-app",
|
|
124
|
+
projectVersion: "3.0.0",
|
|
125
|
+
migrations: [
|
|
126
|
+
{
|
|
127
|
+
version: "2.0.0",
|
|
128
|
+
up(ctx) {
|
|
129
|
+
// Rename a key
|
|
130
|
+
const old = ctx.get("oldSetting");
|
|
131
|
+
if (old !== undefined) {
|
|
132
|
+
ctx.set("newSetting", old);
|
|
133
|
+
ctx.delete("oldSetting");
|
|
134
|
+
}
|
|
135
|
+
},
|
|
136
|
+
},
|
|
137
|
+
{
|
|
138
|
+
version: "3.0.0",
|
|
139
|
+
async up(ctx) {
|
|
140
|
+
// Async migrations supported natively
|
|
141
|
+
const data = ctx.get<string>("rawData");
|
|
142
|
+
if (data) {
|
|
143
|
+
ctx.set("processedData", data.toUpperCase());
|
|
144
|
+
ctx.delete("rawData");
|
|
145
|
+
}
|
|
146
|
+
},
|
|
147
|
+
},
|
|
148
|
+
],
|
|
149
|
+
beforeEachMigration({ fromVersion, toVersion }) {
|
|
150
|
+
console.log(`Migrating ${fromVersion} → ${toVersion}`);
|
|
151
|
+
},
|
|
152
|
+
});
|
|
153
|
+
```
|
|
154
|
+
|
|
155
|
+
If any migration throws, **all changes are rolled back** automatically.
|
|
156
|
+
|
|
157
|
+
## Encryption
|
|
158
|
+
|
|
159
|
+
Optional encryption using [`@wgtechlabs/secrets-engine`](https://github.com/wgtechlabs/secrets-engine) for machine-bound key management:
|
|
160
|
+
|
|
161
|
+
```bash
|
|
162
|
+
bun add @wgtechlabs/secrets-engine
|
|
163
|
+
```
|
|
164
|
+
|
|
165
|
+
```typescript
|
|
166
|
+
const config = await ConfigEngine.open({
|
|
167
|
+
projectName: "my-app",
|
|
168
|
+
encryptionKey: "my-app.config.key", // Key name in secrets-engine
|
|
169
|
+
});
|
|
170
|
+
|
|
171
|
+
// All values are AES-256-GCM encrypted at rest
|
|
172
|
+
config.set("apiToken", "sk-secret-value");
|
|
173
|
+
```
|
|
174
|
+
|
|
175
|
+
Or bring your own encryptor:
|
|
176
|
+
|
|
177
|
+
```typescript
|
|
178
|
+
import { ConfigEngine, type Encryptor } from "@wgtechlabs/config-engine";
|
|
179
|
+
|
|
180
|
+
const myEncryptor: Encryptor = {
|
|
181
|
+
async encrypt(plaintext) { /* ... */ },
|
|
182
|
+
async decrypt(ciphertext) { /* ... */ },
|
|
183
|
+
};
|
|
184
|
+
|
|
185
|
+
const config = await ConfigEngine.open({
|
|
186
|
+
projectName: "my-app",
|
|
187
|
+
encryptionKey: myEncryptor,
|
|
188
|
+
});
|
|
189
|
+
```
|
|
190
|
+
|
|
191
|
+
## Change Events
|
|
192
|
+
|
|
193
|
+
```typescript
|
|
194
|
+
// Watch a specific key
|
|
195
|
+
const unsubscribe = config.onDidChange("theme", (newValue, oldValue) => {
|
|
196
|
+
console.log(`Theme changed: ${oldValue} → ${newValue}`);
|
|
197
|
+
});
|
|
198
|
+
|
|
199
|
+
// Watch any change
|
|
200
|
+
config.onDidAnyChange((newStore, oldStore) => {
|
|
201
|
+
console.log("Config updated");
|
|
202
|
+
});
|
|
203
|
+
|
|
204
|
+
// Stop watching
|
|
205
|
+
unsubscribe();
|
|
206
|
+
```
|
|
207
|
+
|
|
208
|
+
## Flush Strategies
|
|
209
|
+
|
|
210
|
+
Control when writes hit disk:
|
|
211
|
+
|
|
212
|
+
```typescript
|
|
213
|
+
// Immediate — sync write on every .set() (safest)
|
|
214
|
+
const config = await ConfigEngine.open({
|
|
215
|
+
projectName: "my-app",
|
|
216
|
+
flushStrategy: "immediate",
|
|
217
|
+
});
|
|
218
|
+
|
|
219
|
+
// Batched — debounced microtask flush (default, best perf)
|
|
220
|
+
const config = await ConfigEngine.open({
|
|
221
|
+
projectName: "my-app",
|
|
222
|
+
flushStrategy: "batched",
|
|
223
|
+
});
|
|
224
|
+
|
|
225
|
+
// Manual — you control when to flush
|
|
226
|
+
const config = await ConfigEngine.open({
|
|
227
|
+
projectName: "my-app",
|
|
228
|
+
flushStrategy: "manual",
|
|
229
|
+
});
|
|
230
|
+
config.set("key", "value");
|
|
231
|
+
await config.flush(); // Explicit flush
|
|
232
|
+
```
|
|
233
|
+
|
|
234
|
+
## Where Config is Stored
|
|
235
|
+
|
|
236
|
+
SQLite database files are stored in platform-appropriate directories:
|
|
237
|
+
|
|
238
|
+
| OS | Default Path |
|
|
239
|
+
|---|---|
|
|
240
|
+
| macOS | `~/Library/Preferences/<projectName>/config.db` |
|
|
241
|
+
| Windows | `%APPDATA%/<projectName>/config.db` |
|
|
242
|
+
| Linux | `~/.config/<projectName>/config.db` |
|
|
243
|
+
|
|
244
|
+
Override with `cwd`:
|
|
245
|
+
|
|
246
|
+
```typescript
|
|
247
|
+
const config = await ConfigEngine.open({
|
|
248
|
+
projectName: "my-app",
|
|
249
|
+
cwd: "/custom/path", // → /custom/path/config.db
|
|
250
|
+
});
|
|
251
|
+
```
|
|
252
|
+
|
|
253
|
+
## API Reference
|
|
254
|
+
|
|
255
|
+
### `ConfigEngine.open(options)`
|
|
256
|
+
|
|
257
|
+
Async factory method. Returns `Promise<ConfigEngine<T>>`.
|
|
258
|
+
|
|
259
|
+
#### Options
|
|
260
|
+
|
|
261
|
+
| Option | Type | Default | Description |
|
|
262
|
+
|---|---|---|---|
|
|
263
|
+
| `projectName` | `string` | **required** | App identifier for path resolution |
|
|
264
|
+
| `projectVersion` | `string` | — | Required when `migrations` is set |
|
|
265
|
+
| `cwd` | `string` | OS config dir | Override config directory |
|
|
266
|
+
| `configName` | `string` | `"config"` | Database file name (without `.db`) |
|
|
267
|
+
| `defaults` | `Partial<T>` | — | Default values, merged on first open |
|
|
268
|
+
| `schema` | `ZodSchema<T>` | — | Zod schema for validation |
|
|
269
|
+
| `validator` | `Validator<T>` | — | Custom validator (overrides `schema`) |
|
|
270
|
+
| `encryptionKey` | `string \| Encryptor` | — | Encryption key name or custom encryptor |
|
|
271
|
+
| `migrations` | `MigrationDefinition[]` | — | Ordered migration definitions |
|
|
272
|
+
| `beforeEachMigration` | `Function` | — | Hook before each migration |
|
|
273
|
+
| `afterEachMigration` | `Function` | — | Hook after each migration |
|
|
274
|
+
| `flushStrategy` | `FlushStrategy` | `"batched"` | Write-behind strategy |
|
|
275
|
+
| `accessPropertiesByDotNotation` | `boolean` | `true` | Enable dot-notation access |
|
|
276
|
+
| `watch` | `boolean` | `false` | Watch for external changes |
|
|
277
|
+
| `clearInvalidConfig` | `boolean` | `false` | Clear store on validation/decrypt failure |
|
|
278
|
+
|
|
279
|
+
### Instance Methods
|
|
280
|
+
|
|
281
|
+
| Method | Description |
|
|
282
|
+
|---|---|
|
|
283
|
+
| `.get(key, defaultValue?)` | Get a value (dot-notation supported) |
|
|
284
|
+
| `.set(key, value)` | Set a single value |
|
|
285
|
+
| `.set(object)` | Set multiple values |
|
|
286
|
+
| `.has(key)` | Check if a key exists |
|
|
287
|
+
| `.delete(key)` | Remove a key |
|
|
288
|
+
| `.clear()` | Clear all values, restore defaults |
|
|
289
|
+
| `.reset(...keys)` | Reset specific keys to defaults |
|
|
290
|
+
| `.onDidChange(key, cb)` | Watch a key, returns unsubscribe |
|
|
291
|
+
| `.onDidAnyChange(cb)` | Watch all changes, returns unsubscribe |
|
|
292
|
+
| `.flush()` | Flush pending writes (async) |
|
|
293
|
+
| `.flushSync()` | Flush pending writes (sync) |
|
|
294
|
+
| `.close()` | Close the engine |
|
|
295
|
+
|
|
296
|
+
### Instance Properties
|
|
297
|
+
|
|
298
|
+
| Property | Type | Description |
|
|
299
|
+
|---|---|---|
|
|
300
|
+
| `.store` | `T` | Get/set the entire config object |
|
|
301
|
+
| `.size` | `number` | Number of top-level entries |
|
|
302
|
+
| `.path` | `string` | Absolute path to the database file |
|
|
303
|
+
|
|
304
|
+
## License
|
|
305
|
+
|
|
306
|
+
MIT © [WGTech Labs](https://github.com/wgtechlabs)
|
package/dist/cache.d.ts
ADDED
|
@@ -0,0 +1,36 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* @module cache
|
|
3
|
+
* In-memory cache with configurable write-behind strategy.
|
|
4
|
+
* All `.get()` calls hit the Map (zero disk I/O). Writes are
|
|
5
|
+
* flushed to the SQLite store based on the configured strategy.
|
|
6
|
+
*/
|
|
7
|
+
import type { ConfigStore } from "./store.js";
|
|
8
|
+
import type { FlushStrategy } from "./types.js";
|
|
9
|
+
export declare class ConfigCache<T extends Record<string, unknown>> {
|
|
10
|
+
#private;
|
|
11
|
+
constructor(store: ConfigStore, strategy?: FlushStrategy);
|
|
12
|
+
/** Load all data from the store into memory. */
|
|
13
|
+
load(initial?: Record<string, unknown>): void;
|
|
14
|
+
get(key: string): unknown;
|
|
15
|
+
has(key: string): boolean;
|
|
16
|
+
get size(): number;
|
|
17
|
+
/** Return a shallow copy of the entire store as a plain object. */
|
|
18
|
+
getAll(): T;
|
|
19
|
+
entries(): IterableIterator<[string, unknown]>;
|
|
20
|
+
set(key: string, value: unknown): void;
|
|
21
|
+
setMany(entries: Array<[string, unknown]>): void;
|
|
22
|
+
delete(key: string): boolean;
|
|
23
|
+
clear(): void;
|
|
24
|
+
/** Replace the entire in-memory store and schedule a full flush. */
|
|
25
|
+
replaceAll(data: T): void;
|
|
26
|
+
/** Synchronously flush all pending changes to SQLite. */
|
|
27
|
+
flushSync(): void;
|
|
28
|
+
/**
|
|
29
|
+
* Wait for any pending batched flush to complete.
|
|
30
|
+
* Returns immediately if no flush is pending.
|
|
31
|
+
*/
|
|
32
|
+
flush(): Promise<void>;
|
|
33
|
+
/** Reload from disk, discarding uncommitted changes. */
|
|
34
|
+
reload(): void;
|
|
35
|
+
}
|
|
36
|
+
//# sourceMappingURL=cache.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"cache.d.ts","sourceRoot":"","sources":["../src/cache.ts"],"names":[],"mappings":"AAAA;;;;;GAKG;AAEH,OAAO,KAAK,EAAE,WAAW,EAAE,MAAM,YAAY,CAAC;AAC9C,OAAO,KAAK,EAAE,aAAa,EAAE,MAAM,YAAY,CAAC;AAEhD,qBAAa,WAAW,CAAC,CAAC,SAAS,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC;;gBAS7C,KAAK,EAAE,WAAW,EAAE,QAAQ,GAAE,aAAyB;IAKnE,gDAAgD;IAChD,IAAI,CAAC,OAAO,CAAC,EAAE,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,GAAG,IAAI;IAe7C,GAAG,CAAC,GAAG,EAAE,MAAM,GAAG,OAAO;IAIzB,GAAG,CAAC,GAAG,EAAE,MAAM,GAAG,OAAO;IAIzB,IAAI,IAAI,IAAI,MAAM,CAEjB;IAED,mEAAmE;IACnE,MAAM,IAAI,CAAC;IAQX,OAAO,IAAI,gBAAgB,CAAC,CAAC,MAAM,EAAE,OAAO,CAAC,CAAC;IAQ9C,GAAG,CAAC,GAAG,EAAE,MAAM,EAAE,KAAK,EAAE,OAAO,GAAG,IAAI;IAOtC,OAAO,CAAC,OAAO,EAAE,KAAK,CAAC,CAAC,MAAM,EAAE,OAAO,CAAC,CAAC,GAAG,IAAI;IAShD,MAAM,CAAC,GAAG,EAAE,MAAM,GAAG,OAAO;IAU5B,KAAK,IAAI,IAAI;IAUb,oEAAoE;IACpE,UAAU,CAAC,IAAI,EAAE,CAAC,GAAG,IAAI;IAyCzB,yDAAyD;IACzD,SAAS,IAAI,IAAI;IAyBjB;;;OAGG;IACG,KAAK,IAAI,OAAO,CAAC,IAAI,CAAC;IAQ5B,wDAAwD;IACxD,MAAM,IAAI,IAAI;CAKd"}
|
|
@@ -0,0 +1,35 @@
|
|
|
1
|
+
import { createRequire } from "node:module";
|
|
2
|
+
var __require = /* @__PURE__ */ createRequire(import.meta.url);
|
|
3
|
+
|
|
4
|
+
// src/validation.ts
|
|
5
|
+
function createZodValidator(schema) {
|
|
6
|
+
return {
|
|
7
|
+
validate(data) {
|
|
8
|
+
const result = schema.safeParse(data);
|
|
9
|
+
if (result.success) {
|
|
10
|
+
return { success: true, data: result.data };
|
|
11
|
+
}
|
|
12
|
+
return {
|
|
13
|
+
success: false,
|
|
14
|
+
errors: formatZodErrors(result.error)
|
|
15
|
+
};
|
|
16
|
+
}
|
|
17
|
+
};
|
|
18
|
+
}
|
|
19
|
+
function formatZodErrors(error) {
|
|
20
|
+
return error.issues.map((issue) => {
|
|
21
|
+
const path = issue.path.length > 0 ? `\`${issue.path.join(".")}\` ` : "";
|
|
22
|
+
return `${path}${issue.message}`;
|
|
23
|
+
});
|
|
24
|
+
}
|
|
25
|
+
function resolveValidator(options) {
|
|
26
|
+
if (options.validator)
|
|
27
|
+
return options.validator;
|
|
28
|
+
if (options.schema)
|
|
29
|
+
return createZodValidator(options.schema);
|
|
30
|
+
return;
|
|
31
|
+
}
|
|
32
|
+
|
|
33
|
+
export { __require, createZodValidator, resolveValidator };
|
|
34
|
+
|
|
35
|
+
//# debugId=7925FF196403AB3864756E2164756E21
|
|
@@ -0,0 +1,10 @@
|
|
|
1
|
+
{
|
|
2
|
+
"version": 3,
|
|
3
|
+
"sources": ["../src/validation.ts"],
|
|
4
|
+
"sourcesContent": [
|
|
5
|
+
"/**\n * @module validation\n * Pluggable validation system with built-in Zod adapter.\n */\n\nimport { type ZodSchema, type ZodError } from \"zod\";\nimport type { ValidationResult, Validator } from \"./types.js\";\n\n/**\n * Create a `Validator<T>` backed by a Zod schema.\n *\n * ```ts\n * import { z } from \"zod\";\n * import { createZodValidator } from \"@wgtechlabs/config-engine/validators/zod\";\n *\n * const validator = createZodValidator(z.object({\n * theme: z.enum([\"light\", \"dark\"]),\n * fontSize: z.number().min(8).max(72),\n * }));\n * ```\n */\nexport function createZodValidator<T>(schema: ZodSchema<T>): Validator<T> {\n\treturn {\n\t\tvalidate(data: unknown): ValidationResult<T> {\n\t\t\tconst result = schema.safeParse(data);\n\t\t\tif (result.success) {\n\t\t\t\treturn { success: true, data: result.data };\n\t\t\t}\n\t\t\treturn {\n\t\t\t\tsuccess: false,\n\t\t\t\terrors: formatZodErrors(result.error),\n\t\t\t};\n\t\t},\n\t};\n}\n\n/**\n * Format Zod errors into human-readable strings.\n */\nfunction formatZodErrors(error: ZodError): string[] {\n\treturn error.issues.map((issue) => {\n\t\tconst path = issue.path.length > 0 ? `\\`${issue.path.join(\".\")}\\` ` : \"\";\n\t\treturn `${path}${issue.message}`;\n\t});\n}\n\n/**\n * Build a validator from the options — resolves `schema` vs `validator`.\n */\nexport function resolveValidator<T>(options: {\n\tschema?: ZodSchema<T>;\n\tvalidator?: Validator<T>;\n}): Validator<T> | undefined {\n\t// Explicit validator takes precedence\n\tif (options.validator) return options.validator;\n\t// Fall back to Zod schema\n\tif (options.schema) return createZodValidator(options.schema);\n\treturn undefined;\n}\n"
|
|
6
|
+
],
|
|
7
|
+
"mappings": ";;;;AAqBO,SAAS,kBAAqB,CAAC,QAAoC;AAAA,EACzE,OAAO;AAAA,IACN,QAAQ,CAAC,MAAoC;AAAA,MAC5C,MAAM,SAAS,OAAO,UAAU,IAAI;AAAA,MACpC,IAAI,OAAO,SAAS;AAAA,QACnB,OAAO,EAAE,SAAS,MAAM,MAAM,OAAO,KAAK;AAAA,MAC3C;AAAA,MACA,OAAO;AAAA,QACN,SAAS;AAAA,QACT,QAAQ,gBAAgB,OAAO,KAAK;AAAA,MACrC;AAAA;AAAA,EAEF;AAAA;AAMD,SAAS,eAAe,CAAC,OAA2B;AAAA,EACnD,OAAO,MAAM,OAAO,IAAI,CAAC,UAAU;AAAA,IAClC,MAAM,OAAO,MAAM,KAAK,SAAS,IAAI,KAAK,MAAM,KAAK,KAAK,GAAG,SAAS;AAAA,IACtE,OAAO,GAAG,OAAO,MAAM;AAAA,GACvB;AAAA;AAMK,SAAS,gBAAmB,CAAC,SAGP;AAAA,EAE5B,IAAI,QAAQ;AAAA,IAAW,OAAO,QAAQ;AAAA,EAEtC,IAAI,QAAQ;AAAA,IAAQ,OAAO,mBAAmB,QAAQ,MAAM;AAAA,EAC5D;AAAA;",
|
|
8
|
+
"debugId": "7925FF196403AB3864756E2164756E21",
|
|
9
|
+
"names": []
|
|
10
|
+
}
|
|
@@ -0,0 +1,35 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* @module dot-prop
|
|
3
|
+
* Lightweight dot-notation property access utilities.
|
|
4
|
+
* Zero dependencies — replaces the `dot-prop` npm package.
|
|
5
|
+
*/
|
|
6
|
+
/**
|
|
7
|
+
* Get a nested value using dot-notation path.
|
|
8
|
+
*
|
|
9
|
+
* ```ts
|
|
10
|
+
* getByPath({ a: { b: { c: 42 } } }, "a.b.c") // 42
|
|
11
|
+
* getByPath({ a: { b: 1 } }, "a.x") // undefined
|
|
12
|
+
* ```
|
|
13
|
+
*/
|
|
14
|
+
export declare function getByPath(obj: unknown, path: string): unknown;
|
|
15
|
+
/**
|
|
16
|
+
* Set a nested value using dot-notation path. Creates intermediate
|
|
17
|
+
* objects as needed. Returns a new object (shallow copies along the path).
|
|
18
|
+
*
|
|
19
|
+
* ```ts
|
|
20
|
+
* setByPath({}, "a.b.c", 42) // { a: { b: { c: 42 } } }
|
|
21
|
+
* setByPath({ a: { x: 1 } }, "a.b", 2) // { a: { x: 1, b: 2 } }
|
|
22
|
+
* ```
|
|
23
|
+
*/
|
|
24
|
+
export declare function setByPath<T extends Record<string, unknown>>(obj: T, path: string, value: unknown): T;
|
|
25
|
+
/**
|
|
26
|
+
* Check if a nested path exists.
|
|
27
|
+
*/
|
|
28
|
+
export declare function hasByPath(obj: unknown, path: string): boolean;
|
|
29
|
+
/**
|
|
30
|
+
* Delete a nested property using dot-notation path.
|
|
31
|
+
* Returns a new object (shallow copies along the path).
|
|
32
|
+
* Returns the original object if the path doesn't exist.
|
|
33
|
+
*/
|
|
34
|
+
export declare function deleteByPath<T extends Record<string, unknown>>(obj: T, path: string): T;
|
|
35
|
+
//# sourceMappingURL=dot-prop.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"dot-prop.d.ts","sourceRoot":"","sources":["../src/dot-prop.ts"],"names":[],"mappings":"AAAA;;;;GAIG;AAEH;;;;;;;GAOG;AACH,wBAAgB,SAAS,CAAC,GAAG,EAAE,OAAO,EAAE,IAAI,EAAE,MAAM,GAAG,OAAO,CAY7D;AAED;;;;;;;;GAQG;AACH,wBAAgB,SAAS,CAAC,CAAC,SAAS,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,EAC1D,GAAG,EAAE,CAAC,EACN,IAAI,EAAE,MAAM,EACZ,KAAK,EAAE,OAAO,GACZ,CAAC,CAsBH;AAED;;GAEG;AACH,wBAAgB,SAAS,CAAC,GAAG,EAAE,OAAO,EAAE,IAAI,EAAE,MAAM,GAAG,OAAO,CAc7D;AAED;;;;GAIG;AACH,wBAAgB,YAAY,CAAC,CAAC,SAAS,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,EAC7D,GAAG,EAAE,CAAC,EACN,IAAI,EAAE,MAAM,GACV,CAAC,CAqBH"}
|
|
@@ -0,0 +1,31 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* @module encryption
|
|
3
|
+
* Optional encryption integration via `@wgtechlabs/secrets-engine`.
|
|
4
|
+
* Also supports custom `Encryptor` implementations.
|
|
5
|
+
*/
|
|
6
|
+
import type { Encryptor } from "./types.js";
|
|
7
|
+
/**
|
|
8
|
+
* Encryption adapter that uses `@wgtechlabs/secrets-engine`.
|
|
9
|
+
*
|
|
10
|
+
* The encryption key is stored securely in secrets-engine (machine-bound,
|
|
11
|
+
* AES-256-GCM). This adapter retrieves the key on init and uses it to
|
|
12
|
+
* encrypt/decrypt config values via Node's `crypto` module.
|
|
13
|
+
*/
|
|
14
|
+
export declare class SecretsEngineEncryptor implements Encryptor {
|
|
15
|
+
#private;
|
|
16
|
+
constructor(keyName: string);
|
|
17
|
+
/** Initialize the encryptor — must be called before encrypt/decrypt. */
|
|
18
|
+
init(): Promise<void>;
|
|
19
|
+
encrypt(plaintext: string): Promise<string>;
|
|
20
|
+
decrypt(ciphertext: string): Promise<string>;
|
|
21
|
+
/** Close the underlying secrets-engine instance. */
|
|
22
|
+
close(): Promise<void>;
|
|
23
|
+
}
|
|
24
|
+
/**
|
|
25
|
+
* Resolve the encryptor from options.
|
|
26
|
+
* - If a string key name is provided, create a `SecretsEngineEncryptor`.
|
|
27
|
+
* - If an `Encryptor` object is provided, use it directly.
|
|
28
|
+
* - If undefined, return undefined (no encryption).
|
|
29
|
+
*/
|
|
30
|
+
export declare function resolveEncryptor(encryptionKey?: string | Encryptor): Promise<Encryptor | undefined>;
|
|
31
|
+
//# sourceMappingURL=encryption.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"encryption.d.ts","sourceRoot":"","sources":["../src/encryption.ts"],"names":[],"mappings":"AAAA;;;;GAIG;AAEH,OAAO,KAAK,EAAE,SAAS,EAAE,MAAM,YAAY,CAAC;AAE5C;;;;;;GAMG;AACH,qBAAa,sBAAuB,YAAW,SAAS;;gBAM3C,OAAO,EAAE,MAAM;IAI3B,wEAAwE;IAClE,IAAI,IAAI,OAAO,CAAC,IAAI,CAAC;IAsCrB,OAAO,CAAC,SAAS,EAAE,MAAM,GAAG,OAAO,CAAC,MAAM,CAAC;IAiB3C,OAAO,CAAC,UAAU,EAAE,MAAM,GAAG,OAAO,CAAC,MAAM,CAAC;IAkBlD,oDAAoD;IAC9C,KAAK,IAAI,OAAO,CAAC,IAAI,CAAC;CAM5B;AAsCD;;;;;GAKG;AACH,wBAAsB,gBAAgB,CACrC,aAAa,CAAC,EAAE,MAAM,GAAG,SAAS,GAChC,OAAO,CAAC,SAAS,GAAG,SAAS,CAAC,CAWhC"}
|
package/dist/index.d.ts
ADDED
|
@@ -0,0 +1,124 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* @module config-engine
|
|
3
|
+
* Fast, Bun-first configuration engine with SQLite-backed storage.
|
|
4
|
+
*
|
|
5
|
+
* @example
|
|
6
|
+
* ```ts
|
|
7
|
+
* import { ConfigEngine } from "@wgtechlabs/config-engine";
|
|
8
|
+
* import { z } from "zod";
|
|
9
|
+
*
|
|
10
|
+
* const config = await ConfigEngine.open({
|
|
11
|
+
* projectName: "my-app",
|
|
12
|
+
* defaults: { theme: "dark", fontSize: 14 },
|
|
13
|
+
* schema: z.object({
|
|
14
|
+
* theme: z.enum(["light", "dark"]),
|
|
15
|
+
* fontSize: z.number().min(8).max(72),
|
|
16
|
+
* }),
|
|
17
|
+
* });
|
|
18
|
+
*
|
|
19
|
+
* config.get("theme"); // "dark"
|
|
20
|
+
* config.set("fontSize", 16);
|
|
21
|
+
* config.set({ theme: "light", fontSize: 12 });
|
|
22
|
+
*
|
|
23
|
+
* config.close();
|
|
24
|
+
* ```
|
|
25
|
+
*/
|
|
26
|
+
import type { AnyChangeCallback, ChangeCallback, ConfigEngineOptions, Unsubscribe } from "./types.js";
|
|
27
|
+
export type { ConfigEngineOptions, Validator, ValidationResult, ValidationSuccess, ValidationFailure, Encryptor, MigrationDefinition, MigrationContext, MigrationHookContext, FlushStrategy as FlushStrategyType, ChangeCallback, AnyChangeCallback, Unsubscribe, } from "./types.js";
|
|
28
|
+
export { createZodValidator, resolveValidator } from "./validation.js";
|
|
29
|
+
export { resolveConfigDir, resolveConfigPath } from "./platform.js";
|
|
30
|
+
export type { FlushStrategy } from "./types.js";
|
|
31
|
+
export declare class ConfigEngineError extends Error {
|
|
32
|
+
name: string;
|
|
33
|
+
}
|
|
34
|
+
export declare class ValidationError extends ConfigEngineError {
|
|
35
|
+
name: string;
|
|
36
|
+
errors: string[];
|
|
37
|
+
constructor(errors: string[]);
|
|
38
|
+
}
|
|
39
|
+
export declare class ConfigEngine<T extends Record<string, unknown>> {
|
|
40
|
+
#private;
|
|
41
|
+
/**
|
|
42
|
+
* Private constructor — use `ConfigEngine.open()` instead.
|
|
43
|
+
*/
|
|
44
|
+
private constructor();
|
|
45
|
+
/**
|
|
46
|
+
* Async factory — the only way to create a `ConfigEngine` instance.
|
|
47
|
+
* Handles encryption init, migration, and initial validation.
|
|
48
|
+
*/
|
|
49
|
+
static open<T extends Record<string, unknown>>(options: ConfigEngineOptions<T>): Promise<ConfigEngine<T>>;
|
|
50
|
+
/**
|
|
51
|
+
* Get a config value by key. Supports dot-notation by default.
|
|
52
|
+
* @param key - The configuration key.
|
|
53
|
+
* @param defaultValue - Fallback value if the key doesn't exist.
|
|
54
|
+
*/
|
|
55
|
+
get<K extends string & keyof T>(key: K): T[K] | undefined;
|
|
56
|
+
get<K extends string & keyof T>(key: K, defaultValue: T[K]): T[K];
|
|
57
|
+
get<V = unknown>(key: string, defaultValue?: V): V | undefined;
|
|
58
|
+
/**
|
|
59
|
+
* Check whether a key exists in the config.
|
|
60
|
+
*/
|
|
61
|
+
has(key: string): boolean;
|
|
62
|
+
/**
|
|
63
|
+
* Get the entire config store as a typed object (shallow copy).
|
|
64
|
+
*/
|
|
65
|
+
get store(): T;
|
|
66
|
+
/**
|
|
67
|
+
* Replace the entire config store.
|
|
68
|
+
*/
|
|
69
|
+
set store(value: T);
|
|
70
|
+
/**
|
|
71
|
+
* Number of top-level config entries.
|
|
72
|
+
*/
|
|
73
|
+
get size(): number;
|
|
74
|
+
/**
|
|
75
|
+
* Absolute path to the SQLite database file.
|
|
76
|
+
*/
|
|
77
|
+
get path(): string;
|
|
78
|
+
/**
|
|
79
|
+
* Set a config value. Supports two signatures:
|
|
80
|
+
* - `set(key, value)` — set a single key
|
|
81
|
+
* - `set(object)` — set multiple keys at once
|
|
82
|
+
*/
|
|
83
|
+
set<K extends string & keyof T>(key: K, value: T[K]): void;
|
|
84
|
+
set(key: string, value: unknown): void;
|
|
85
|
+
set(object: Partial<T>): void;
|
|
86
|
+
/**
|
|
87
|
+
* Delete a config key.
|
|
88
|
+
*/
|
|
89
|
+
delete(key: string): void;
|
|
90
|
+
/**
|
|
91
|
+
* Delete all config entries and restore defaults.
|
|
92
|
+
*/
|
|
93
|
+
clear(): void;
|
|
94
|
+
/**
|
|
95
|
+
* Reset specific keys to their default values.
|
|
96
|
+
*/
|
|
97
|
+
reset(...keys: (string & keyof T)[]): void;
|
|
98
|
+
/**
|
|
99
|
+
* Watch a specific key for changes.
|
|
100
|
+
* @returns An unsubscribe function.
|
|
101
|
+
*/
|
|
102
|
+
onDidChange<K extends string & keyof T>(key: K, callback: ChangeCallback<T[K]>): Unsubscribe;
|
|
103
|
+
/**
|
|
104
|
+
* Watch the entire store for any change.
|
|
105
|
+
* @returns An unsubscribe function.
|
|
106
|
+
*/
|
|
107
|
+
onDidAnyChange(callback: AnyChangeCallback<T>): Unsubscribe;
|
|
108
|
+
/**
|
|
109
|
+
* Flush any pending writes to disk.
|
|
110
|
+
* Required when using `flushStrategy: "manual"`.
|
|
111
|
+
*/
|
|
112
|
+
flush(): Promise<void>;
|
|
113
|
+
/**
|
|
114
|
+
* Synchronously flush any pending writes to disk.
|
|
115
|
+
*/
|
|
116
|
+
flushSync(): void;
|
|
117
|
+
/**
|
|
118
|
+
* Close the config engine. Flushes pending writes and releases
|
|
119
|
+
* the database connection. The instance cannot be used after closing.
|
|
120
|
+
*/
|
|
121
|
+
close(): void;
|
|
122
|
+
[Symbol.iterator](): IterableIterator<[string, unknown]>;
|
|
123
|
+
}
|
|
124
|
+
//# sourceMappingURL=index.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":"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"}
|