configre 2.1.5 → 2.1.6
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/README.md +8 -10
- package/package.json +1 -1
- package/skills/configre/SKILL.md +65 -171
package/README.md
CHANGED
|
@@ -18,11 +18,10 @@ Create `config/index.cjs` with your defaults:
|
|
|
18
18
|
module.exports = {
|
|
19
19
|
db: {
|
|
20
20
|
host: "localhost",
|
|
21
|
-
port: 5432
|
|
22
|
-
password: ""
|
|
21
|
+
port: 5432
|
|
23
22
|
},
|
|
24
23
|
api: {
|
|
25
|
-
|
|
24
|
+
url: "https://api.example.com"
|
|
26
25
|
}
|
|
27
26
|
};
|
|
28
27
|
```
|
|
@@ -73,11 +72,10 @@ The resulting configuration contains:
|
|
|
73
72
|
db: {
|
|
74
73
|
host: "db.internal",
|
|
75
74
|
port: 5432,
|
|
76
|
-
password: "",
|
|
77
75
|
ssl: true
|
|
78
76
|
},
|
|
79
77
|
api: {
|
|
80
|
-
|
|
78
|
+
url: "https://api.example.com"
|
|
81
79
|
}
|
|
82
80
|
}
|
|
83
81
|
```
|
|
@@ -110,7 +108,7 @@ config/
|
|
|
110
108
|
production.secret.cjs # Production secrets, edited locally
|
|
111
109
|
```
|
|
112
110
|
|
|
113
|
-
A secret file exports only the fields it needs to supply. Your application
|
|
111
|
+
A secret file exports only the fields it needs to supply. Your application reads them through ordinary properties such as `cfg.api.key`; there is no separate secrets API. Define sensitive fields in secret files; public configuration does not need placeholders for them.
|
|
114
112
|
|
|
115
113
|
For `--config=production`, the merge order is:
|
|
116
114
|
|
|
@@ -132,17 +130,17 @@ module.exports = {
|
|
|
132
130
|
};
|
|
133
131
|
```
|
|
134
132
|
|
|
135
|
-
For a production
|
|
133
|
+
For a production API key, create `config/production.secret.cjs`:
|
|
136
134
|
|
|
137
135
|
```javascript
|
|
138
136
|
module.exports = {
|
|
139
|
-
|
|
140
|
-
|
|
137
|
+
api: {
|
|
138
|
+
key: ""
|
|
141
139
|
}
|
|
142
140
|
};
|
|
143
141
|
```
|
|
144
142
|
|
|
145
|
-
Fill in the values in these local files. Configre generates `secrets.enc.json` and adds Git exclusions for the editable secret files when your application runs.
|
|
143
|
+
Fill in the values in these local files. The production key overrides the shared key when that profile is selected, while `api.url` still comes from the public configuration. Configre generates `secrets.enc.json` and adds Git exclusions for the editable secret files when your application runs.
|
|
146
144
|
|
|
147
145
|
### Share with a server
|
|
148
146
|
|
package/package.json
CHANGED
package/skills/configre/SKILL.md
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
---
|
|
2
2
|
name: configre
|
|
3
|
-
description: Set up
|
|
3
|
+
description: Set up or edit Configre configuration in Node.js projects, including profile overrides, encrypted secrets, safe printing, and explicit environment-variable application.
|
|
4
4
|
metadata:
|
|
5
5
|
category: configuration
|
|
6
6
|
tags: [nodejs, config, environment, settings, secrets]
|
|
@@ -8,123 +8,39 @@ metadata:
|
|
|
8
8
|
|
|
9
9
|
# Configre
|
|
10
10
|
|
|
11
|
-
|
|
11
|
+
Load public defaults, extend or overwrite them by profile, and merge optional secrets synchronously.
|
|
12
12
|
|
|
13
|
-
##
|
|
13
|
+
## Setup and loading
|
|
14
14
|
|
|
15
|
-
|
|
16
|
-
|
|
17
|
-
|
|
18
|
-
|
|
19
|
-
```bash
|
|
20
|
-
npm install configre --save
|
|
21
|
-
```
|
|
22
|
-
|
|
23
|
-
### Step 2: Create the config directory
|
|
24
|
-
|
|
25
|
-
Config files **must always use the `.cjs` extension**. This works in both CommonJS and ESM projects and allows using `module.exports`.
|
|
26
|
-
|
|
27
|
-
```
|
|
28
|
-
project/
|
|
29
|
-
├── config/
|
|
30
|
-
│ ├── index.cjs # Default settings (required)
|
|
31
|
-
│ ├── myhostname.cjs # Host-specific overrides (optional)
|
|
32
|
-
│ └── myhostname.dev.cjs # Dev override for host (optional)
|
|
33
|
-
```
|
|
34
|
-
|
|
35
|
-
### Step 3: Write the default config (`config/index.cjs`)
|
|
36
|
-
|
|
37
|
-
```javascript
|
|
38
|
-
module.exports = {
|
|
39
|
-
db: {
|
|
40
|
-
host: 'localhost',
|
|
41
|
-
port: 5432,
|
|
42
|
-
user: 'dev',
|
|
43
|
-
password: ""
|
|
44
|
-
},
|
|
45
|
-
api: {
|
|
46
|
-
key: "",
|
|
47
|
-
url: 'http://localhost:3000'
|
|
48
|
-
}
|
|
49
|
-
};
|
|
50
|
-
```
|
|
51
|
-
|
|
52
|
-
Keep credentials in `.secret.cjs` files. Public settings should contain explicit empty placeholders, not real credentials or automatic environment-variable fallbacks.
|
|
53
|
-
|
|
54
|
-
### Step 4: Write host/profile overrides
|
|
55
|
-
|
|
56
|
-
Create `config/<hostname>.cjs` with only the keys that differ — they are deep-merged over defaults:
|
|
57
|
-
|
|
58
|
-
```javascript
|
|
59
|
-
module.exports = {
|
|
60
|
-
db: {
|
|
61
|
-
user: 'prod-user'
|
|
62
|
-
}
|
|
63
|
-
};
|
|
64
|
-
```
|
|
65
|
-
|
|
66
|
-
### Step 5: Load the configuration
|
|
15
|
+
Install with `npm install configre`; requires Node.js 22.13 or later.
|
|
16
|
+
Configuration files use `.cjs` and `module.exports`, including in ESM projects.
|
|
17
|
+
The path is required. Anchor it to the module; avoid deriving it from `process.cwd()`.
|
|
67
18
|
|
|
68
19
|
```javascript
|
|
69
20
|
import Configre from "configre";
|
|
70
21
|
import { join } from "node:path";
|
|
71
22
|
|
|
72
23
|
const cfg = Configre(join(import.meta.dirname, "config"));
|
|
73
|
-
|
|
74
|
-
console.log(cfg.db.host); // from default
|
|
75
|
-
console.log(cfg.db.user); // from host override
|
|
76
24
|
```
|
|
77
25
|
|
|
78
|
-
|
|
26
|
+
Create `config/index.cjs` for defaults and `config/production.cjs` for additions or overrides.
|
|
27
|
+
Keep sensitive public placeholders as `""`; put actual values in secret files.
|
|
28
|
+
CommonJS supports `require("configre")` directly, without `.default` or `await`.
|
|
29
|
+
`Configre(path)` returns configuration; `new Configre(path)` exposes `.get()` and `.print()`.
|
|
79
30
|
|
|
80
|
-
|
|
31
|
+
## Profiles and merge behavior
|
|
81
32
|
|
|
82
|
-
|
|
33
|
+
- Select with `--config=production` anywhere in the application arguments; otherwise use `os.hostname()`.
|
|
34
|
+
- Prefer `<profile>.dev.cjs` over `<profile>.cjs` when present, independently of `NODE_ENV`.
|
|
35
|
+
- Select one public profile; dev and regular variants do not merge. Missing profiles use defaults.
|
|
36
|
+
- Objects merge recursively: preserve unspecified fields, override matching values, and add new fields.
|
|
37
|
+
- Arrays merge by index and retain trailing entries; they are not replaced wholesale.
|
|
38
|
+
- Merge order: public base → public profile → secret base → secret profile.
|
|
39
|
+
- Independently prefer `<profile>.dev.secret.cjs` over `<profile>.secret.cjs`.
|
|
83
40
|
|
|
84
|
-
|
|
85
|
-
const cfg = Configre(join(import.meta.dirname, "settings"));
|
|
86
|
-
```
|
|
87
|
-
|
|
88
|
-
## Profile resolution
|
|
89
|
-
|
|
90
|
-
Configre determines the active profile by looking for a `--config=<profile>` argument anywhere in `process.argv`, or falls back to `os.hostname()`. It then checks for overrides in this order (first match wins):
|
|
41
|
+
## Secrets
|
|
91
42
|
|
|
92
|
-
|
|
93
|
-
2. `config/<profile>.cjs` — production override
|
|
94
|
-
3. No match — uses public defaults; available secrets still apply
|
|
95
|
-
|
|
96
|
-
To force a specific profile at runtime:
|
|
97
|
-
|
|
98
|
-
```bash
|
|
99
|
-
node app.js --config=staging
|
|
100
|
-
node app.js --port=3000 --config=production --debug
|
|
101
|
-
```
|
|
102
|
-
|
|
103
|
-
Using `--config=` (instead of a positional argument) avoids conflicts with other CLI flags.
|
|
104
|
-
|
|
105
|
-
## Shared secrets
|
|
106
|
-
|
|
107
|
-
### Activation and file layout
|
|
108
|
-
|
|
109
|
-
Secret support activates when the base config or selected profile has a corresponding `.secret.cjs` file, or when an encrypted file already exists. There is no `secrets` option. Without either condition, Configre loads public settings without accessing an identity or creating secret artifacts. Configre never creates editable `.secret.cjs` modules itself; create them only when secret support is wanted.
|
|
110
|
-
|
|
111
|
-
For a config directory:
|
|
112
|
-
|
|
113
|
-
```text
|
|
114
|
-
config/
|
|
115
|
-
├── index.cjs
|
|
116
|
-
├── production.cjs
|
|
117
|
-
├── index.secret.cjs # Administrator-only base secrets
|
|
118
|
-
├── production.secret.cjs # Optional administrator-only profile secrets
|
|
119
|
-
├── production.dev.secret.cjs # Optional preferred secret profile variant
|
|
120
|
-
├── secrets.enc.json # Generated ciphertext; share through Git
|
|
121
|
-
├── recipients/*.pub # Public recipient keys; share through Git
|
|
122
|
-
└── .gitignore # Generated exclusions for editable secrets
|
|
123
|
-
```
|
|
124
|
-
|
|
125
|
-
For an individual `settings.cjs` config file, sidecars are `settings.secret.cjs`, `settings.cjs.secrets.enc.json`, and `settings.cjs.recipients/`, beside the config file. An extensionless path resolving to that file uses the same sidecars. File mode selects the base secret module, not profile secret modules.
|
|
126
|
-
|
|
127
|
-
Secret modules export a plain object containing only JSON-compatible values. For example, create `config/index.secret.cjs` with empty values for the administrator to fill privately:
|
|
43
|
+
Create `index.secret.cjs` for shared secrets and `<profile>.secret.cjs` for profile secrets:
|
|
128
44
|
|
|
129
45
|
```javascript
|
|
130
46
|
module.exports = {
|
|
@@ -133,74 +49,52 @@ module.exports = {
|
|
|
133
49
|
};
|
|
134
50
|
```
|
|
135
51
|
|
|
136
|
-
|
|
137
|
-
|
|
138
|
-
|
|
139
|
-
|
|
140
|
-
|
|
141
|
-
|
|
142
|
-
|
|
143
|
-
|
|
144
|
-
|
|
145
|
-
|
|
146
|
-
|
|
147
|
-
|
|
148
|
-
###
|
|
149
|
-
|
|
150
|
-
1.
|
|
151
|
-
2.
|
|
152
|
-
3.
|
|
153
|
-
4.
|
|
154
|
-
|
|
155
|
-
|
|
156
|
-
|
|
157
|
-
|
|
158
|
-
|
|
159
|
-
|
|
160
|
-
|
|
161
|
-
|
|
162
|
-
|
|
163
|
-
|
|
164
|
-
|
|
165
|
-
|
|
166
|
-
|
|
167
|
-
|
|
168
|
-
|
|
169
|
-
|
|
52
|
+
- Secret modules supply only the needed fields; consumers read ordinary properties such as `cfg.api.key`.
|
|
53
|
+
- Activate when the base or selected profile has a secret counterpart, or ciphertext already exists.
|
|
54
|
+
- Without either condition, load public settings without identity access or secret artifacts.
|
|
55
|
+
- Configre never creates editable secret modules. There is no `secrets` option.
|
|
56
|
+
- Export plain objects containing JSON-compatible values; empty strings remain empty.
|
|
57
|
+
- Reject functions, undefined, accessors, symbols, custom objects, cycles, sparse arrays, non-finite numbers, and keys named `__proto__`, `constructor`, or `prototype`.
|
|
58
|
+
- Once active, encrypt all local profile secrets together; merge only the base and selected profile.
|
|
59
|
+
- Every authorized identity can decrypt every profile. Profiles organize values, not access.
|
|
60
|
+
- Editable secrets are authoritative for values; `recipients/` is authoritative for additional recipients.
|
|
61
|
+
- With ciphertext and no editable secret modules, load as a consumer; deleting local modules does not clear secrets.
|
|
62
|
+
- Individual `settings.cjs` files use `settings.secret.cjs`, `settings.cjs.secrets.enc.json`, and `settings.cjs.recipients/`; file mode has no secret profiles.
|
|
63
|
+
|
|
64
|
+
### Sharing and updates
|
|
65
|
+
|
|
66
|
+
1. Local: create secret files and run; Configre generates ciphertext and Git exclusions. Push the encrypted file.
|
|
67
|
+
2. Server: pull and run; Configre automatically commits and pushes `recipients/<profile>.pub`.
|
|
68
|
+
3. Local: pull, run to incorporate the public key, and push the updated ciphertext.
|
|
69
|
+
4. Server: pull and restart. Later secret updates repeat the local run/push and server pull/restart.
|
|
70
|
+
|
|
71
|
+
Registration needs a branch matching its upstream, Git author identity, and non-interactive push access.
|
|
72
|
+
Pending authorization or failed registration returns public settings only; malformed secrets, identities, and ciphertext stop loading.
|
|
73
|
+
Use isolated fixtures for verification unless live registration is authorized: loading can fetch, commit, and push.
|
|
74
|
+
Registration preserves unrelated changes, skips hooks, rejects key-name collisions, and retries failures on later loads.
|
|
75
|
+
Never commit editable secret modules or private identities; Configre rejects already tracked secret inputs.
|
|
76
|
+
Identity files live under `~/.config/configre/`: `identity.pem` is private and `identity.pub` is public.
|
|
77
|
+
Back up editable secrets and private identities; never reset damaged identities or ciphertext as a retry.
|
|
78
|
+
To revoke access, remove the recipient key, reload locally, and publish; prevent re-registration and rotate previously shared credentials when required.
|
|
79
|
+
|
|
80
|
+
## Print without secret fields
|
|
81
|
+
|
|
82
|
+
Use `cfg.print()` with `DEBUG=Configre:*`, rather than logging the merged configuration.
|
|
83
|
+
It logs current values without mutation or automatic printing on load; public siblings remain visible.
|
|
84
|
+
Omit loaded secret-file fields recursively, including encrypted inputs; omit secret arrays entirely.
|
|
85
|
+
Classification follows secret-file fields, not names: secrets copied elsewhere are not automatically detected.
|
|
86
|
+
The method is non-enumerable; spreads and JSON still contain secrets and do not preserve the method.
|
|
87
|
+
An existing `print` field is preserved; use `new Configre(configPath).print()` in that case.
|
|
88
|
+
|
|
89
|
+
## Apply environment variables
|
|
170
90
|
|
|
171
91
|
```javascript
|
|
172
|
-
|
|
173
|
-
cfg
|
|
92
|
+
import Configre, { applyConfigEnv } from "configre";
|
|
93
|
+
const cfg = Configre(configPath);
|
|
94
|
+
applyConfigEnv(cfg.env);
|
|
174
95
|
```
|
|
175
96
|
|
|
176
|
-
|
|
177
|
-
|
|
178
|
-
|
|
179
|
-
|
|
180
|
-
- Classification is by secret-file fields, not names such as `password` or `token`. Sensitive values placed only in public settings or copied to another field are not automatically detected. Keep them in secret modules and do not treat `print()` as a general-purpose redactor.
|
|
181
|
-
- The method is non-enumerable: it does not appear in `Object.keys(cfg)`, object spreads, or JSON output. Those operations still include secret data, so do not use them as redaction. A spread or JSON round trip does not preserve the method.
|
|
182
|
-
- `new Configre(configPath).print()` is also supported and prints the instance's merged settings. `.get()` still returns plain configuration data. If a configuration already has its own `print` field, that value is preserved; use the constructor's `print()` method instead.
|
|
183
|
-
|
|
184
|
-
## Examples
|
|
185
|
-
|
|
186
|
-
**Example 1: Basic setup**
|
|
187
|
-
User says: "Add configuration management to my Node.js project"
|
|
188
|
-
Actions: install configre, create `config/index.cjs` with project defaults, import Configre and load with `Configre(join(import.meta.dirname, "config"))`
|
|
189
|
-
Result: merged config object ready to use
|
|
190
|
-
|
|
191
|
-
**Example 2: Multi-environment**
|
|
192
|
-
User says: "I need different database settings per server"
|
|
193
|
-
Actions: create `config/index.cjs` with defaults, create `config/<hostname>.cjs` per server with db overrides
|
|
194
|
-
Result: each server automatically loads its own config based on hostname
|
|
195
|
-
|
|
196
|
-
**Example 3: Custom profile via CLI**
|
|
197
|
-
User says: "I want to run my app with a staging config"
|
|
198
|
-
Actions: create `config/staging.cjs`, run app with `node app.js --config=staging`
|
|
199
|
-
Result: staging overrides are merged over defaults, without conflicting with other CLI arguments
|
|
200
|
-
|
|
201
|
-
## Key behaviors
|
|
202
|
-
|
|
203
|
-
- **Deep merge**: nested plain objects merge recursively using Configre's own implementation; arrays merge by index and retain existing trailing entries rather than being replaced wholesale
|
|
204
|
-
- **Config files must use the `.cjs` extension** (`.js` is not accepted; works in both CommonJS and ESM projects)
|
|
205
|
-
- **Required path**: always pass the config directory or file path; prefer an absolute module-relative path over a process-relative path
|
|
206
|
-
- **Function vs constructor**: `Configre(path)` returns the merged config with non-enumerable `print()` when that field is available; `new Configre(path)` returns the instance with `.get()` and `.print()`
|
|
97
|
+
Call explicitly after loading. Set only undefined `process.env` variables using `String(value)`; preserve existing values, including `""`.
|
|
98
|
+
Omitted `cfg.env` does nothing; skip null/undefined entries. Reject null, arrays, non-objects, empty keys, and object values.
|
|
99
|
+
Invalid entries throw without rolling back earlier assignments. CommonJS: `const { applyConfigEnv } = require("configre")`.
|
|
100
|
+
For encryption, identity permissions, and recovery details, consult the [advanced reference](https://github.com/clasen/Configre#advanced-reference).
|