c12 3.3.3 → 4.0.0-beta.2
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 +63 -6
- package/dist/THIRD-PARTY-LICENSES.md +33 -0
- package/dist/_chunks/libs/ohash.d.mts +30 -0
- package/dist/_chunks/libs/ohash.mjs +182 -0
- package/dist/_chunks/libs/perfect-debounce.mjs +68 -0
- package/dist/index.d.mts +22 -5
- package/dist/index.mjs +60 -45
- package/dist/update.d.mts +2 -2
- package/dist/update.mjs +1 -12
- package/package.json +48 -37
package/README.md
CHANGED
|
@@ -12,11 +12,11 @@ c12 (pronounced as /siːtwelv/, like c-twelve) is a smart configuration loader.
|
|
|
12
12
|
|
|
13
13
|
## ✅ Features
|
|
14
14
|
|
|
15
|
-
- `.js`, `.ts`, `.mjs`, `.cjs`, `.mts`, `.cts` `.json` config loader with [unjs/jiti](https://jiti.unjs.io)
|
|
15
|
+
- `.js`, `.ts`, `.mjs`, `.cjs`, `.mts`, `.cts` `.json` config loader with customizable import or [unjs/jiti](https://jiti.unjs.io) fallback.
|
|
16
16
|
- `.jsonc`, `.json5`, `.yaml`, `.yml`, `.toml` config loader with [unjs/confbox](https://confbox.unjs.io)
|
|
17
17
|
- `.config/` directory support ([config dir proposal](https://github.com/pi0/config-dir))
|
|
18
18
|
- `.rc` config support with [unjs/rc9](https://github.com/unjs/rc9)
|
|
19
|
-
- `.env` support with
|
|
19
|
+
- `.env` support with variable interpolation and `_FILE` references resolution
|
|
20
20
|
- Multiple sources merged with [unjs/defu](https://github.com/unjs/defu)
|
|
21
21
|
- Reads config from the nearest `package.json` file
|
|
22
22
|
- [Extends configurations](https://github.com/unjs/c12#extending-configuration) from multiple local or git sources
|
|
@@ -139,6 +139,25 @@ console.log(config.config.connectionPoolMax); // "10"
|
|
|
139
139
|
console.log(config.config.databaseURL); // "<...localhost...>"
|
|
140
140
|
```
|
|
141
141
|
|
|
142
|
+
#### `expandFileReferences`
|
|
143
|
+
|
|
144
|
+
Enabled by default. Environment variables ending with `_FILE` are resolved by reading the file at the specified path and assigning its trimmed content to the base key (without the `_FILE` suffix). This is useful for container secrets (e.g. Docker, Kubernetes) where sensitive values are mounted as files. Set to `false` to disable.
|
|
145
|
+
|
|
146
|
+
```ini
|
|
147
|
+
# .env
|
|
148
|
+
DATABASE_PASSWORD_FILE="/run/secrets/db_password"
|
|
149
|
+
```
|
|
150
|
+
|
|
151
|
+
```ts
|
|
152
|
+
import { loadConfig } from "c12";
|
|
153
|
+
|
|
154
|
+
const config = await loadConfig({
|
|
155
|
+
dotenv: true,
|
|
156
|
+
});
|
|
157
|
+
|
|
158
|
+
// DATABASE_PASSWORD is now set to the contents of /run/secrets/db_password
|
|
159
|
+
```
|
|
160
|
+
|
|
142
161
|
### `packageJson`
|
|
143
162
|
|
|
144
163
|
Loads config from nearest `package.json` file. It is disabled by default.
|
|
@@ -163,13 +182,35 @@ Specify override configuration. It has the **highest** priority and is applied *
|
|
|
163
182
|
|
|
164
183
|
Exclude environment-specific and built-in keys start with `$` in the resolved config. The default is `false`.
|
|
165
184
|
|
|
166
|
-
### `
|
|
185
|
+
### `import`
|
|
167
186
|
|
|
168
|
-
Custom [unjs/jiti](https://github.com/unjs/jiti)
|
|
187
|
+
Custom import function used to load configuration files. By default, c12 uses native `import()` with [unjs/jiti](https://github.com/unjs/jiti) as fallback.
|
|
169
188
|
|
|
170
|
-
|
|
189
|
+
**Example:** Using a custom [jiti](https://github.com/unjs/jiti) instance with options:
|
|
171
190
|
|
|
172
|
-
|
|
191
|
+
```js
|
|
192
|
+
import { createJiti } from "jiti";
|
|
193
|
+
|
|
194
|
+
const jiti = createJiti(import.meta.url, {
|
|
195
|
+
/* jiti options */
|
|
196
|
+
});
|
|
197
|
+
|
|
198
|
+
const { config } = await loadConfig({
|
|
199
|
+
import: (id) => jiti.import(id),
|
|
200
|
+
});
|
|
201
|
+
```
|
|
202
|
+
|
|
203
|
+
### `resolveModule`
|
|
204
|
+
|
|
205
|
+
Custom resolver for picking which export to use from the loaded module. Default: `(mod) => mod.default || mod`.
|
|
206
|
+
|
|
207
|
+
**Example:** Using a named export:
|
|
208
|
+
|
|
209
|
+
```js
|
|
210
|
+
const { config } = await loadConfig({
|
|
211
|
+
resolveModule: (mod) => mod.myConfig,
|
|
212
|
+
});
|
|
213
|
+
```
|
|
173
214
|
|
|
174
215
|
### `giget`
|
|
175
216
|
|
|
@@ -295,6 +336,14 @@ Layers:
|
|
|
295
336
|
|
|
296
337
|
## Extending config layer from remote sources
|
|
297
338
|
|
|
339
|
+
> [!NOTE]
|
|
340
|
+
> Extending from remote sources requires the [`giget`](https://giget.unjs.io) peer dependency to be installed.
|
|
341
|
+
>
|
|
342
|
+
> ```sh
|
|
343
|
+
> # ✨ Auto-detect
|
|
344
|
+
> npx nypm install giget
|
|
345
|
+
> ```
|
|
346
|
+
|
|
298
347
|
You can also extend configuration from remote sources such as npm or github.
|
|
299
348
|
|
|
300
349
|
In the repo, there should be a `config.ts` (or `config.{name}.ts`) file to be considered as a valid config layer.
|
|
@@ -364,6 +413,14 @@ export default {
|
|
|
364
413
|
|
|
365
414
|
you can use `watchConfig` instead of `loadConfig` to load config and watch for changes, add and removals in all expected configuration paths and auto reload with new config.
|
|
366
415
|
|
|
416
|
+
> [!NOTE]
|
|
417
|
+
> Watching requires the [`chokidar`](https://github.com/paulmillr/chokidar) peer dependency to be installed.
|
|
418
|
+
>
|
|
419
|
+
> ```sh
|
|
420
|
+
> # ✨ Auto-detect
|
|
421
|
+
> npx nypm install chokidar
|
|
422
|
+
> ```
|
|
423
|
+
|
|
367
424
|
### Lifecycle hooks
|
|
368
425
|
|
|
369
426
|
- `onWatch`: This function is always called when config is updated, added, or removed before attempting to reload the config.
|
|
@@ -0,0 +1,33 @@
|
|
|
1
|
+
# Licenses of Bundled Dependencies
|
|
2
|
+
|
|
3
|
+
The published artifact additionally contains code with the following licenses:
|
|
4
|
+
MIT
|
|
5
|
+
|
|
6
|
+
# Bundled Dependencies
|
|
7
|
+
|
|
8
|
+
## ohash, perfect-debounce
|
|
9
|
+
|
|
10
|
+
License: MIT
|
|
11
|
+
Repositories: https://github.com/unjs/ohash, https://github.com/unjs/perfect-debounce
|
|
12
|
+
|
|
13
|
+
> MIT License
|
|
14
|
+
>
|
|
15
|
+
> Copyright (c) Pooya Parsa <pooya@pi0.io>
|
|
16
|
+
>
|
|
17
|
+
> Permission is hereby granted, free of charge, to any person obtaining a copy
|
|
18
|
+
> of this software and associated documentation files (the "Software"), to deal
|
|
19
|
+
> in the Software without restriction, including without limitation the rights
|
|
20
|
+
> to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
|
21
|
+
> copies of the Software, and to permit persons to whom the Software is
|
|
22
|
+
> furnished to do so, subject to the following conditions:
|
|
23
|
+
>
|
|
24
|
+
> The above copyright notice and this permission notice shall be included in all
|
|
25
|
+
> copies or substantial portions of the Software.
|
|
26
|
+
>
|
|
27
|
+
> THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
|
28
|
+
> IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
|
29
|
+
> FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
|
30
|
+
> AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
|
31
|
+
> LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
|
32
|
+
> OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
|
|
33
|
+
> SOFTWARE.
|
|
@@ -0,0 +1,30 @@
|
|
|
1
|
+
//#region node_modules/.pnpm/ohash@2.0.11/node_modules/ohash/dist/utils/index.d.mts
|
|
2
|
+
/**
|
|
3
|
+
* Calculates the difference between two objects and returns a list of differences.
|
|
4
|
+
*
|
|
5
|
+
* @param {any} obj1 - The first object to compare.
|
|
6
|
+
* @param {any} obj2 - The second object to compare.
|
|
7
|
+
* @param {HashOptions} [opts={}] - Configuration options for hashing the objects. See {@link HashOptions}.
|
|
8
|
+
* @returns {DiffEntry[]} An array with the differences between the two objects.
|
|
9
|
+
*/
|
|
10
|
+
declare function diff(obj1: any, obj2: any): DiffEntry[];
|
|
11
|
+
declare class DiffEntry {
|
|
12
|
+
key: string;
|
|
13
|
+
type: "changed" | "added" | "removed";
|
|
14
|
+
newValue: DiffHashedObject;
|
|
15
|
+
oldValue?: DiffHashedObject | undefined;
|
|
16
|
+
constructor(key: string, type: "changed" | "added" | "removed", newValue: DiffHashedObject, oldValue?: DiffHashedObject | undefined);
|
|
17
|
+
toString(): string;
|
|
18
|
+
toJSON(): string;
|
|
19
|
+
}
|
|
20
|
+
declare class DiffHashedObject {
|
|
21
|
+
key: string;
|
|
22
|
+
value: any;
|
|
23
|
+
hash?: string | undefined;
|
|
24
|
+
props?: Record<string, DiffHashedObject> | undefined;
|
|
25
|
+
constructor(key: string, value: any, hash?: string | undefined, props?: Record<string, DiffHashedObject> | undefined);
|
|
26
|
+
toString(): string;
|
|
27
|
+
toJSON(): string;
|
|
28
|
+
}
|
|
29
|
+
//#endregion
|
|
30
|
+
export { diff as t };
|
|
@@ -0,0 +1,182 @@
|
|
|
1
|
+
import "node:module";
|
|
2
|
+
import { createHash } from "node:crypto";
|
|
3
|
+
var __defProp = Object.defineProperty;
|
|
4
|
+
var __exportAll = (all, no_symbols) => {
|
|
5
|
+
let target = {};
|
|
6
|
+
for (var name in all) __defProp(target, name, {
|
|
7
|
+
get: all[name],
|
|
8
|
+
enumerable: true
|
|
9
|
+
});
|
|
10
|
+
if (!no_symbols) __defProp(target, Symbol.toStringTag, { value: "Module" });
|
|
11
|
+
return target;
|
|
12
|
+
};
|
|
13
|
+
function serialize(o) {
|
|
14
|
+
return typeof o == "string" ? `'${o}'` : new c().serialize(o);
|
|
15
|
+
}
|
|
16
|
+
const c = /* @__PURE__ */ function() {
|
|
17
|
+
class o {
|
|
18
|
+
#t = /* @__PURE__ */ new Map();
|
|
19
|
+
compare(t, r) {
|
|
20
|
+
const e = typeof t, n = typeof r;
|
|
21
|
+
return e === "string" && n === "string" ? t.localeCompare(r) : e === "number" && n === "number" ? t - r : String.prototype.localeCompare.call(this.serialize(t, true), this.serialize(r, true));
|
|
22
|
+
}
|
|
23
|
+
serialize(t, r) {
|
|
24
|
+
if (t === null) return "null";
|
|
25
|
+
switch (typeof t) {
|
|
26
|
+
case "string": return r ? t : `'${t}'`;
|
|
27
|
+
case "bigint": return `${t}n`;
|
|
28
|
+
case "object": return this.$object(t);
|
|
29
|
+
case "function": return this.$function(t);
|
|
30
|
+
}
|
|
31
|
+
return String(t);
|
|
32
|
+
}
|
|
33
|
+
serializeObject(t) {
|
|
34
|
+
const r = Object.prototype.toString.call(t);
|
|
35
|
+
if (r !== "[object Object]") return this.serializeBuiltInType(r.length < 10 ? `unknown:${r}` : r.slice(8, -1), t);
|
|
36
|
+
const e = t.constructor, n = e === Object || e === void 0 ? "" : e.name;
|
|
37
|
+
if (n !== "" && globalThis[n] === e) return this.serializeBuiltInType(n, t);
|
|
38
|
+
if (typeof t.toJSON == "function") {
|
|
39
|
+
const i = t.toJSON();
|
|
40
|
+
return n + (i !== null && typeof i == "object" ? this.$object(i) : `(${this.serialize(i)})`);
|
|
41
|
+
}
|
|
42
|
+
return this.serializeObjectEntries(n, Object.entries(t));
|
|
43
|
+
}
|
|
44
|
+
serializeBuiltInType(t, r) {
|
|
45
|
+
const e = this["$" + t];
|
|
46
|
+
if (e) return e.call(this, r);
|
|
47
|
+
if (typeof r?.entries == "function") return this.serializeObjectEntries(t, r.entries());
|
|
48
|
+
throw new Error(`Cannot serialize ${t}`);
|
|
49
|
+
}
|
|
50
|
+
serializeObjectEntries(t, r) {
|
|
51
|
+
const e = Array.from(r).sort((i, a) => this.compare(i[0], a[0]));
|
|
52
|
+
let n = `${t}{`;
|
|
53
|
+
for (let i = 0; i < e.length; i++) {
|
|
54
|
+
const [a, l] = e[i];
|
|
55
|
+
n += `${this.serialize(a, true)}:${this.serialize(l)}`, i < e.length - 1 && (n += ",");
|
|
56
|
+
}
|
|
57
|
+
return n + "}";
|
|
58
|
+
}
|
|
59
|
+
$object(t) {
|
|
60
|
+
let r = this.#t.get(t);
|
|
61
|
+
return r === void 0 && (this.#t.set(t, `#${this.#t.size}`), r = this.serializeObject(t), this.#t.set(t, r)), r;
|
|
62
|
+
}
|
|
63
|
+
$function(t) {
|
|
64
|
+
const r = Function.prototype.toString.call(t);
|
|
65
|
+
return r.slice(-15) === "[native code] }" ? `${t.name || ""}()[native]` : `${t.name}(${t.length})${r.replace(/\s*\n\s*/g, "")}`;
|
|
66
|
+
}
|
|
67
|
+
$Array(t) {
|
|
68
|
+
let r = "[";
|
|
69
|
+
for (let e = 0; e < t.length; e++) r += this.serialize(t[e]), e < t.length - 1 && (r += ",");
|
|
70
|
+
return r + "]";
|
|
71
|
+
}
|
|
72
|
+
$Date(t) {
|
|
73
|
+
try {
|
|
74
|
+
return `Date(${t.toISOString()})`;
|
|
75
|
+
} catch {
|
|
76
|
+
return "Date(null)";
|
|
77
|
+
}
|
|
78
|
+
}
|
|
79
|
+
$ArrayBuffer(t) {
|
|
80
|
+
return `ArrayBuffer[${new Uint8Array(t).join(",")}]`;
|
|
81
|
+
}
|
|
82
|
+
$Set(t) {
|
|
83
|
+
return `Set${this.$Array(Array.from(t).sort((r, e) => this.compare(r, e)))}`;
|
|
84
|
+
}
|
|
85
|
+
$Map(t) {
|
|
86
|
+
return this.serializeObjectEntries("Map", t.entries());
|
|
87
|
+
}
|
|
88
|
+
}
|
|
89
|
+
for (const s of [
|
|
90
|
+
"Error",
|
|
91
|
+
"RegExp",
|
|
92
|
+
"URL"
|
|
93
|
+
]) o.prototype["$" + s] = function(t) {
|
|
94
|
+
return `${s}(${t})`;
|
|
95
|
+
};
|
|
96
|
+
for (const s of [
|
|
97
|
+
"Int8Array",
|
|
98
|
+
"Uint8Array",
|
|
99
|
+
"Uint8ClampedArray",
|
|
100
|
+
"Int16Array",
|
|
101
|
+
"Uint16Array",
|
|
102
|
+
"Int32Array",
|
|
103
|
+
"Uint32Array",
|
|
104
|
+
"Float32Array",
|
|
105
|
+
"Float64Array"
|
|
106
|
+
]) o.prototype["$" + s] = function(t) {
|
|
107
|
+
return `${s}[${t.join(",")}]`;
|
|
108
|
+
};
|
|
109
|
+
for (const s of ["BigInt64Array", "BigUint64Array"]) o.prototype["$" + s] = function(t) {
|
|
110
|
+
return `${s}[${t.join("n,")}${t.length > 0 ? "n" : ""}]`;
|
|
111
|
+
};
|
|
112
|
+
return o;
|
|
113
|
+
}();
|
|
114
|
+
const e = globalThis.process?.getBuiltinModule?.("crypto")?.hash, r = "sha256", s = "base64url";
|
|
115
|
+
function digest(t) {
|
|
116
|
+
if (e) return e(r, t, s);
|
|
117
|
+
const o = createHash(r).update(t);
|
|
118
|
+
return globalThis.process?.versions?.webcontainer ? o.digest().toString(s) : o.digest(s);
|
|
119
|
+
}
|
|
120
|
+
var dist_exports = /* @__PURE__ */ __exportAll({ digest: () => digest });
|
|
121
|
+
var utils_exports = /* @__PURE__ */ __exportAll({ diff: () => diff });
|
|
122
|
+
function diff(obj1, obj2) {
|
|
123
|
+
return _diff(_toHashedObject(obj1), _toHashedObject(obj2));
|
|
124
|
+
}
|
|
125
|
+
function _diff(h1, h2) {
|
|
126
|
+
const diffs = [];
|
|
127
|
+
const allProps = /* @__PURE__ */ new Set([...Object.keys(h1.props || {}), ...Object.keys(h2.props || {})]);
|
|
128
|
+
if (h1.props && h2.props) for (const prop of allProps) {
|
|
129
|
+
const p1 = h1.props[prop];
|
|
130
|
+
const p2 = h2.props[prop];
|
|
131
|
+
if (p1 && p2) diffs.push(..._diff(h1.props?.[prop], h2.props?.[prop]));
|
|
132
|
+
else if (p1 || p2) diffs.push(new DiffEntry((p2 || p1).key, p1 ? "removed" : "added", p2, p1));
|
|
133
|
+
}
|
|
134
|
+
if (allProps.size === 0 && h1.hash !== h2.hash) diffs.push(new DiffEntry((h2 || h1).key, "changed", h2, h1));
|
|
135
|
+
return diffs;
|
|
136
|
+
}
|
|
137
|
+
function _toHashedObject(obj, key = "") {
|
|
138
|
+
if (obj && typeof obj !== "object") return new DiffHashedObject(key, obj, serialize(obj));
|
|
139
|
+
const props = {};
|
|
140
|
+
const hashes = [];
|
|
141
|
+
for (const _key in obj) {
|
|
142
|
+
props[_key] = _toHashedObject(obj[_key], key ? `${key}.${_key}` : _key);
|
|
143
|
+
hashes.push(props[_key].hash);
|
|
144
|
+
}
|
|
145
|
+
return new DiffHashedObject(key, obj, `{${hashes.join(":")}}`, props);
|
|
146
|
+
}
|
|
147
|
+
var DiffEntry = class {
|
|
148
|
+
constructor(key, type, newValue, oldValue) {
|
|
149
|
+
this.key = key;
|
|
150
|
+
this.type = type;
|
|
151
|
+
this.newValue = newValue;
|
|
152
|
+
this.oldValue = oldValue;
|
|
153
|
+
}
|
|
154
|
+
toString() {
|
|
155
|
+
return this.toJSON();
|
|
156
|
+
}
|
|
157
|
+
toJSON() {
|
|
158
|
+
switch (this.type) {
|
|
159
|
+
case "added": return `Added \`${this.key}\``;
|
|
160
|
+
case "removed": return `Removed \`${this.key}\``;
|
|
161
|
+
case "changed": return `Changed \`${this.key}\` from \`${this.oldValue?.toString() || "-"}\` to \`${this.newValue.toString()}\``;
|
|
162
|
+
}
|
|
163
|
+
}
|
|
164
|
+
};
|
|
165
|
+
var DiffHashedObject = class {
|
|
166
|
+
constructor(key, value, hash, props) {
|
|
167
|
+
this.key = key;
|
|
168
|
+
this.value = value;
|
|
169
|
+
this.hash = hash;
|
|
170
|
+
this.props = props;
|
|
171
|
+
}
|
|
172
|
+
toString() {
|
|
173
|
+
if (this.props) return `{${Object.keys(this.props).join(",")}}`;
|
|
174
|
+
else return JSON.stringify(this.value);
|
|
175
|
+
}
|
|
176
|
+
toJSON() {
|
|
177
|
+
const k = this.key || ".";
|
|
178
|
+
if (this.props) return `${k}({${Object.keys(this.props).join(",")}})`;
|
|
179
|
+
return `${k}(${this.value})`;
|
|
180
|
+
}
|
|
181
|
+
};
|
|
182
|
+
export { dist_exports as n, utils_exports as t };
|
|
@@ -0,0 +1,68 @@
|
|
|
1
|
+
const DEBOUNCE_DEFAULTS = { trailing: true };
|
|
2
|
+
function debounce(fn, wait = 25, options = {}) {
|
|
3
|
+
options = {
|
|
4
|
+
...DEBOUNCE_DEFAULTS,
|
|
5
|
+
...options
|
|
6
|
+
};
|
|
7
|
+
if (!Number.isFinite(wait)) throw new TypeError("Expected `wait` to be a finite number");
|
|
8
|
+
let leadingValue;
|
|
9
|
+
let timeout;
|
|
10
|
+
let resolveList = [];
|
|
11
|
+
let currentPromise;
|
|
12
|
+
let trailingArgs;
|
|
13
|
+
const applyFn = (_this, args) => {
|
|
14
|
+
currentPromise = _applyPromised(fn, _this, args);
|
|
15
|
+
currentPromise.finally(() => {
|
|
16
|
+
currentPromise = null;
|
|
17
|
+
if (options.trailing && trailingArgs && !timeout) {
|
|
18
|
+
const promise = applyFn(_this, trailingArgs);
|
|
19
|
+
trailingArgs = null;
|
|
20
|
+
return promise;
|
|
21
|
+
}
|
|
22
|
+
});
|
|
23
|
+
return currentPromise;
|
|
24
|
+
};
|
|
25
|
+
const debounced = function(...args) {
|
|
26
|
+
if (options.trailing) trailingArgs = args;
|
|
27
|
+
if (currentPromise) return currentPromise;
|
|
28
|
+
return new Promise((resolve) => {
|
|
29
|
+
const shouldCallNow = !timeout && options.leading;
|
|
30
|
+
clearTimeout(timeout);
|
|
31
|
+
timeout = setTimeout(() => {
|
|
32
|
+
timeout = null;
|
|
33
|
+
const promise = options.leading ? leadingValue : applyFn(this, args);
|
|
34
|
+
trailingArgs = null;
|
|
35
|
+
for (const _resolve of resolveList) _resolve(promise);
|
|
36
|
+
resolveList = [];
|
|
37
|
+
}, wait);
|
|
38
|
+
if (shouldCallNow) {
|
|
39
|
+
leadingValue = applyFn(this, args);
|
|
40
|
+
resolve(leadingValue);
|
|
41
|
+
} else resolveList.push(resolve);
|
|
42
|
+
});
|
|
43
|
+
};
|
|
44
|
+
const _clearTimeout = (timer) => {
|
|
45
|
+
if (timer) {
|
|
46
|
+
clearTimeout(timer);
|
|
47
|
+
timeout = null;
|
|
48
|
+
}
|
|
49
|
+
};
|
|
50
|
+
debounced.isPending = () => !!timeout;
|
|
51
|
+
debounced.cancel = () => {
|
|
52
|
+
_clearTimeout(timeout);
|
|
53
|
+
resolveList = [];
|
|
54
|
+
trailingArgs = null;
|
|
55
|
+
};
|
|
56
|
+
debounced.flush = () => {
|
|
57
|
+
_clearTimeout(timeout);
|
|
58
|
+
if (!trailingArgs || currentPromise) return;
|
|
59
|
+
const args = trailingArgs;
|
|
60
|
+
trailingArgs = null;
|
|
61
|
+
return applyFn(this, args);
|
|
62
|
+
};
|
|
63
|
+
return debounced;
|
|
64
|
+
}
|
|
65
|
+
async function _applyPromised(fn, _this, args) {
|
|
66
|
+
return await fn.apply(_this, args);
|
|
67
|
+
}
|
|
68
|
+
export { debounce as t };
|
package/dist/index.d.mts
CHANGED
|
@@ -1,7 +1,6 @@
|
|
|
1
|
-
import {
|
|
1
|
+
import { t as diff } from "./_chunks/libs/ohash.mjs";
|
|
2
2
|
import { ChokidarOptions } from "chokidar";
|
|
3
3
|
import { DownloadTemplateOptions } from "giget";
|
|
4
|
-
import { diff } from "ohash/utils";
|
|
5
4
|
|
|
6
5
|
//#region src/dotenv.d.ts
|
|
7
6
|
interface DotenvOptions {
|
|
@@ -32,6 +31,22 @@ interface DotenvOptions {
|
|
|
32
31
|
* An object describing environment variables (key, value pairs).
|
|
33
32
|
*/
|
|
34
33
|
env?: NodeJS.ProcessEnv;
|
|
34
|
+
/**
|
|
35
|
+
* Resolve `_FILE` suffixed environment variables by reading the file at the
|
|
36
|
+
* specified path and assigning its trimmed content to the base key.
|
|
37
|
+
*
|
|
38
|
+
* This is useful for container secrets (e.g. Docker, Kubernetes) where
|
|
39
|
+
* sensitive values are mounted as files.
|
|
40
|
+
*
|
|
41
|
+
* @default true
|
|
42
|
+
*
|
|
43
|
+
* @example
|
|
44
|
+
* ```env
|
|
45
|
+
* DATABASE_PASSWORD_FILE="/run/secrets/db_password"
|
|
46
|
+
* # resolves to DATABASE_PASSWORD=<contents of /run/secrets/db_password>
|
|
47
|
+
* ```
|
|
48
|
+
*/
|
|
49
|
+
expandFileReferences?: boolean;
|
|
35
50
|
}
|
|
36
51
|
type Env = typeof process.env;
|
|
37
52
|
/**
|
|
@@ -125,8 +140,10 @@ interface LoadConfigOptions<T extends UserInputConfig = UserInputConfig, MT exte
|
|
|
125
140
|
/** Context passed to config functions */
|
|
126
141
|
context?: ConfigFunctionContext;
|
|
127
142
|
resolve?: (id: string, options: LoadConfigOptions<T, MT>) => null | undefined | ResolvedConfig<T, MT> | Promise<ResolvedConfig<T, MT> | undefined | null>;
|
|
128
|
-
|
|
129
|
-
|
|
143
|
+
/** Custom import function used to load configuration files */
|
|
144
|
+
import?: (id: string) => Promise<unknown>;
|
|
145
|
+
/** Custom resolver for picking which export to use from the loaded module. Default: `(mod) => mod.default || mod` */
|
|
146
|
+
resolveModule?: (mod: any) => any;
|
|
130
147
|
giget?: false | DownloadTemplateOptions;
|
|
131
148
|
merger?: (...sources: Array<T | null | undefined>) => T;
|
|
132
149
|
extend?: false | {
|
|
@@ -167,4 +184,4 @@ interface WatchConfigOptions<T extends UserInputConfig = UserInputConfig, MT ext
|
|
|
167
184
|
}
|
|
168
185
|
declare function watchConfig<T extends UserInputConfig = UserInputConfig, MT extends ConfigLayerMeta = ConfigLayerMeta>(options: WatchConfigOptions<T, MT>): Promise<ConfigWatcher<T, MT>>;
|
|
169
186
|
//#endregion
|
|
170
|
-
export { C12InputConfig, ConfigFunctionContext, ConfigLayer, ConfigLayerMeta, ConfigSource, ConfigWatcher, DefineConfig, DotenvOptions, Env, InputConfig, LoadConfigOptions, ResolvableConfig, ResolvableConfigContext, ResolvedConfig, SUPPORTED_EXTENSIONS, SourceOptions, UserInputConfig, WatchConfigOptions, createDefineConfig, loadConfig, loadDotenv, setupDotenv, watchConfig };
|
|
187
|
+
export { C12InputConfig, ConfigFunctionContext, ConfigLayer, ConfigLayerMeta, ConfigSource, type ConfigWatcher, DefineConfig, type DotenvOptions, type Env, InputConfig, LoadConfigOptions, ResolvableConfig, ResolvableConfigContext, ResolvedConfig, SUPPORTED_EXTENSIONS, SourceOptions, UserInputConfig, type WatchConfigOptions, createDefineConfig, loadConfig, loadDotenv, setupDotenv, watchConfig };
|
package/dist/index.mjs
CHANGED
|
@@ -1,29 +1,22 @@
|
|
|
1
|
-
import {
|
|
1
|
+
import { t as debounce } from "./_chunks/libs/perfect-debounce.mjs";
|
|
2
|
+
import { existsSync, readFileSync, statSync } from "node:fs";
|
|
3
|
+
import * as nodeUtil from "node:util";
|
|
2
4
|
import { basename, dirname, extname, join, normalize, resolve } from "pathe";
|
|
3
|
-
import * as dotenv from "dotenv";
|
|
4
5
|
import { readFile, rm } from "node:fs/promises";
|
|
5
6
|
import { pathToFileURL } from "node:url";
|
|
6
7
|
import { homedir } from "node:os";
|
|
7
8
|
import { resolveModulePath } from "exsolve";
|
|
8
|
-
import { createJiti } from "jiti";
|
|
9
9
|
import * as rc9 from "rc9";
|
|
10
10
|
import { defu } from "defu";
|
|
11
11
|
import { findWorkspaceDir, readPackageJSON } from "pkg-types";
|
|
12
|
-
import { debounce } from "perfect-debounce";
|
|
13
|
-
|
|
14
|
-
//#region src/dotenv.ts
|
|
15
|
-
/**
|
|
16
|
-
* Load and interpolate environment variables into `process.env`.
|
|
17
|
-
* If you need more control (or access to the values), consider using `loadDotenv` instead
|
|
18
|
-
*
|
|
19
|
-
*/
|
|
20
12
|
async function setupDotenv(options) {
|
|
21
13
|
const targetEnvironment = options.env ?? process.env;
|
|
22
14
|
const environment = await loadDotenv({
|
|
23
15
|
cwd: options.cwd,
|
|
24
16
|
fileName: options.fileName ?? ".env",
|
|
25
17
|
env: targetEnvironment,
|
|
26
|
-
interpolate: options.interpolate ?? true
|
|
18
|
+
interpolate: options.interpolate ?? true,
|
|
19
|
+
expandFileReferences: options.expandFileReferences ?? true
|
|
27
20
|
});
|
|
28
21
|
const dotenvVars = getDotEnvVars(targetEnvironment);
|
|
29
22
|
for (const key in environment) {
|
|
@@ -32,7 +25,6 @@ async function setupDotenv(options) {
|
|
|
32
25
|
}
|
|
33
26
|
return environment;
|
|
34
27
|
}
|
|
35
|
-
/** Load environment variables into an object. */
|
|
36
28
|
async function loadDotenv(options) {
|
|
37
29
|
const environment = Object.create(null);
|
|
38
30
|
const cwd = resolve(options.cwd || ".");
|
|
@@ -43,29 +35,52 @@ async function loadDotenv(options) {
|
|
|
43
35
|
for (const file of dotenvFiles) {
|
|
44
36
|
const dotenvFile = resolve(cwd, file);
|
|
45
37
|
if (!statSync(dotenvFile, { throwIfNoEntry: false })?.isFile()) continue;
|
|
46
|
-
const parsed =
|
|
38
|
+
const parsed = await readEnvFile(dotenvFile);
|
|
47
39
|
for (const key in parsed) {
|
|
48
40
|
if (key in environment && !dotenvVars.has(key)) continue;
|
|
49
41
|
environment[key] = parsed[key];
|
|
50
42
|
dotenvVars.add(key);
|
|
51
43
|
}
|
|
52
44
|
}
|
|
45
|
+
if (options.expandFileReferences !== false) {
|
|
46
|
+
for (const key in environment) if (key.endsWith("_FILE")) {
|
|
47
|
+
const targetKey = key.slice(0, -5);
|
|
48
|
+
if (environment[targetKey] === void 0) {
|
|
49
|
+
const filePath = environment[key];
|
|
50
|
+
if (filePath && statSync(filePath, { throwIfNoEntry: false })?.isFile()) {
|
|
51
|
+
environment[targetKey] = readFileSync(filePath, "utf8").trim();
|
|
52
|
+
dotenvVars.add(targetKey);
|
|
53
|
+
}
|
|
54
|
+
}
|
|
55
|
+
}
|
|
56
|
+
}
|
|
53
57
|
if (options.interpolate) interpolate(environment);
|
|
54
58
|
return environment;
|
|
55
59
|
}
|
|
60
|
+
let _parseEnv = nodeUtil.parseEnv;
|
|
61
|
+
async function readEnvFile(path) {
|
|
62
|
+
const src = readFileSync(path, "utf8");
|
|
63
|
+
if (!_parseEnv) try {
|
|
64
|
+
const dotenv = await import("dotenv");
|
|
65
|
+
_parseEnv = (src) => dotenv.parse(src);
|
|
66
|
+
} catch {
|
|
67
|
+
throw new Error("Failed to parse .env file: `node:util.parseEnv` is not available and `dotenv` package is not installed. Please upgrade your runtime or install `dotenv` as a dependency.");
|
|
68
|
+
}
|
|
69
|
+
return _parseEnv(src);
|
|
70
|
+
}
|
|
56
71
|
function interpolate(target, source = {}, parse = (v) => v) {
|
|
57
72
|
function getValue(key) {
|
|
58
73
|
return source[key] === void 0 ? target[key] : source[key];
|
|
59
74
|
}
|
|
60
|
-
function interpolate
|
|
75
|
+
function interpolate(value, parents = []) {
|
|
61
76
|
if (typeof value !== "string") return value;
|
|
62
77
|
return parse((value.match(/(.?\${?(?:[\w:]+)?}?)/g) || []).reduce((newValue, match) => {
|
|
63
78
|
const parts = /(.?)\${?([\w:]+)?}?/g.exec(match) || [];
|
|
64
79
|
const prefix = parts[1];
|
|
65
|
-
let value
|
|
80
|
+
let value, replacePart;
|
|
66
81
|
if (prefix === "\\") {
|
|
67
82
|
replacePart = parts[0] || "";
|
|
68
|
-
value
|
|
83
|
+
value = replacePart.replace(String.raw`\$`, "$");
|
|
69
84
|
} else {
|
|
70
85
|
const key = parts[2];
|
|
71
86
|
replacePart = (parts[0] || "").slice(prefix.length);
|
|
@@ -73,22 +88,19 @@ function interpolate(target, source = {}, parse = (v) => v) {
|
|
|
73
88
|
console.warn(`Please avoid recursive environment variables ( loop: ${parents.join(" > ")} > ${key} )`);
|
|
74
89
|
return "";
|
|
75
90
|
}
|
|
76
|
-
value
|
|
77
|
-
value
|
|
91
|
+
value = getValue(key);
|
|
92
|
+
value = interpolate(value, [...parents, key]);
|
|
78
93
|
}
|
|
79
|
-
return value
|
|
94
|
+
return value === void 0 ? newValue : newValue.replace(replacePart, value);
|
|
80
95
|
}, value));
|
|
81
96
|
}
|
|
82
|
-
for (const key in target) target[key] = interpolate
|
|
97
|
+
for (const key in target) target[key] = interpolate(getValue(key));
|
|
83
98
|
}
|
|
84
99
|
function getDotEnvVars(targetEnvironment) {
|
|
85
100
|
const globalRegistry = globalThis.__c12_dotenv_vars__ ||= /* @__PURE__ */ new Map();
|
|
86
101
|
if (!globalRegistry.has(targetEnvironment)) globalRegistry.set(targetEnvironment, /* @__PURE__ */ new Set());
|
|
87
102
|
return globalRegistry.get(targetEnvironment);
|
|
88
103
|
}
|
|
89
|
-
|
|
90
|
-
//#endregion
|
|
91
|
-
//#region src/loader.ts
|
|
92
104
|
const _normalize = (p) => p?.replace(/\\/g, "/");
|
|
93
105
|
const ASYNC_LOADERS = {
|
|
94
106
|
".yaml": () => import("confbox/yaml").then((r) => r.parseYAML),
|
|
@@ -122,12 +134,6 @@ async function loadConfig(options) {
|
|
|
122
134
|
...options.extend
|
|
123
135
|
};
|
|
124
136
|
const _merger = options.merger || defu;
|
|
125
|
-
options.jiti = options.jiti || createJiti(join(options.cwd, options.configFile), {
|
|
126
|
-
interopDefault: true,
|
|
127
|
-
moduleCache: false,
|
|
128
|
-
extensions: [...SUPPORTED_EXTENSIONS],
|
|
129
|
-
...options.jitiOptions
|
|
130
|
-
});
|
|
131
137
|
const r = {
|
|
132
138
|
config: {},
|
|
133
139
|
cwd: options.cwd,
|
|
@@ -274,15 +280,17 @@ const GIGET_PREFIXES = [
|
|
|
274
280
|
const NPM_PACKAGE_RE = /^(@[\da-z~-][\d._a-z~-]*\/)?[\da-z~-][\d._a-z~-]*($|\/.*)/;
|
|
275
281
|
async function resolveConfig(source, options, sourceOptions = {}) {
|
|
276
282
|
if (options.resolve) {
|
|
277
|
-
const res
|
|
278
|
-
if (res
|
|
283
|
+
const res = await options.resolve(source, options);
|
|
284
|
+
if (res) return res;
|
|
279
285
|
}
|
|
280
286
|
const _merger = options.merger || defu;
|
|
281
287
|
const customProviderKeys = Object.keys(sourceOptions.giget?.providers || {}).map((key) => `${key}:`);
|
|
282
288
|
const gigetPrefixes = customProviderKeys.length > 0 ? [...new Set([...customProviderKeys, ...GIGET_PREFIXES])] : GIGET_PREFIXES;
|
|
283
289
|
if (options.giget !== false && gigetPrefixes.some((prefix) => source.startsWith(prefix))) {
|
|
284
|
-
const { downloadTemplate } = await import("giget")
|
|
285
|
-
|
|
290
|
+
const { downloadTemplate } = await import("giget").catch((error) => {
|
|
291
|
+
throw new Error(`Extending config from \`${source}\` requires \`giget\` peer dependency to be installed.\n\nInstall it with: \`npx nypm i giget\``, { cause: error });
|
|
292
|
+
});
|
|
293
|
+
const { digest } = await import("./_chunks/libs/ohash.mjs").then((n) => n.n);
|
|
286
294
|
const cloneName = source.replace(/\W+/g, "_").split("_").splice(0, 3).join("_") + "_" + digest(source).slice(0, 10).replace(/[-_]/g, "");
|
|
287
295
|
let cloneDir;
|
|
288
296
|
const localNodeModules = resolve(options.cwd, "node_modules");
|
|
@@ -317,7 +325,22 @@ async function resolveConfig(source, options, sourceOptions = {}) {
|
|
|
317
325
|
res._configFile = res.configFile;
|
|
318
326
|
const configFileExt = extname(res.configFile) || "";
|
|
319
327
|
if (configFileExt in ASYNC_LOADERS) res.config = (await ASYNC_LOADERS[configFileExt]())(await readFile(res.configFile, "utf8"));
|
|
320
|
-
else
|
|
328
|
+
else {
|
|
329
|
+
const _resolveModule = options.resolveModule || ((mod) => mod.default || mod);
|
|
330
|
+
if (options.import) res.config = _resolveModule(await options.import(res.configFile));
|
|
331
|
+
else res.config = await import(res.configFile).then(_resolveModule, async (error) => {
|
|
332
|
+
const { createJiti } = await import("jiti").catch(() => {
|
|
333
|
+
throw new Error(`Failed to load config file \`${res.configFile}\`: ${error?.message}. Hint install \`jiti\` for compatibility.`, { cause: error });
|
|
334
|
+
});
|
|
335
|
+
const jiti = createJiti(join(options.cwd || ".", options.configFile || "/"), {
|
|
336
|
+
interopDefault: true,
|
|
337
|
+
moduleCache: false,
|
|
338
|
+
extensions: [...SUPPORTED_EXTENSIONS]
|
|
339
|
+
});
|
|
340
|
+
options.import = (id) => jiti.import(id);
|
|
341
|
+
return _resolveModule(await options.import(res.configFile));
|
|
342
|
+
});
|
|
343
|
+
}
|
|
321
344
|
if (typeof res.config === "function") res.config = await res.config(options.context);
|
|
322
345
|
if (options.envName) {
|
|
323
346
|
const envConfig = {
|
|
@@ -343,15 +366,9 @@ function tryResolve(id, options) {
|
|
|
343
366
|
});
|
|
344
367
|
return res ? normalize(res) : void 0;
|
|
345
368
|
}
|
|
346
|
-
|
|
347
|
-
//#endregion
|
|
348
|
-
//#region src/types.ts
|
|
349
369
|
function createDefineConfig() {
|
|
350
370
|
return (input) => input;
|
|
351
371
|
}
|
|
352
|
-
|
|
353
|
-
//#endregion
|
|
354
|
-
//#region src/watch.ts
|
|
355
372
|
const eventMap = {
|
|
356
373
|
add: "created",
|
|
357
374
|
change: "updated",
|
|
@@ -372,7 +389,7 @@ async function watchConfig(options) {
|
|
|
372
389
|
options.packageJson && resolve(l.cwd, "package.json")
|
|
373
390
|
]).filter(Boolean))];
|
|
374
391
|
const watch = await import("chokidar").then((r) => r.watch || r.default || r);
|
|
375
|
-
const { diff } = await import("ohash
|
|
392
|
+
const { diff } = await import("./_chunks/libs/ohash.mjs").then((n) => n.t);
|
|
376
393
|
const _fswatcher = watch(watchingFiles, {
|
|
377
394
|
ignoreInitial: true,
|
|
378
395
|
...options.chokidarOptions
|
|
@@ -414,6 +431,4 @@ async function watchConfig(options) {
|
|
|
414
431
|
return config[prop];
|
|
415
432
|
} });
|
|
416
433
|
}
|
|
417
|
-
|
|
418
|
-
//#endregion
|
|
419
|
-
export { SUPPORTED_EXTENSIONS, createDefineConfig, loadConfig, loadDotenv, setupDotenv, watchConfig };
|
|
434
|
+
export { SUPPORTED_EXTENSIONS, createDefineConfig, loadConfig, loadDotenv, setupDotenv, watchConfig };
|
package/dist/update.d.mts
CHANGED
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
import * as
|
|
1
|
+
import * as magicast from "magicast";
|
|
2
2
|
|
|
3
3
|
//#region src/update.d.ts
|
|
4
4
|
/**
|
|
@@ -10,7 +10,7 @@ interface UpdateConfigResult {
|
|
|
10
10
|
created?: boolean;
|
|
11
11
|
}
|
|
12
12
|
type MaybePromise<T> = T | Promise<T>;
|
|
13
|
-
type MagicAstOptions = Exclude<Parameters<(typeof
|
|
13
|
+
type MagicAstOptions = Exclude<Parameters<(typeof magicast)["parseModule"]>[1], undefined>;
|
|
14
14
|
interface UpdateConfigOptions {
|
|
15
15
|
/**
|
|
16
16
|
* Current working directory
|
package/dist/update.mjs
CHANGED
|
@@ -4,13 +4,10 @@ import { mkdir, readFile, writeFile } from "node:fs/promises";
|
|
|
4
4
|
import "node:url";
|
|
5
5
|
import "node:os";
|
|
6
6
|
import { join, normalize } from "pathe";
|
|
7
|
-
import "jiti";
|
|
8
7
|
import "rc9";
|
|
9
8
|
import "defu";
|
|
10
9
|
import "pkg-types";
|
|
11
10
|
import { dirname, extname } from "node:path";
|
|
12
|
-
|
|
13
|
-
//#region src/loader.ts
|
|
14
11
|
const SUPPORTED_EXTENSIONS = Object.freeze([
|
|
15
12
|
".js",
|
|
16
13
|
".ts",
|
|
@@ -25,9 +22,6 @@ const SUPPORTED_EXTENSIONS = Object.freeze([
|
|
|
25
22
|
".yml",
|
|
26
23
|
".toml"
|
|
27
24
|
]);
|
|
28
|
-
|
|
29
|
-
//#endregion
|
|
30
|
-
//#region src/update.ts
|
|
31
25
|
const UPDATABLE_EXTS = [
|
|
32
26
|
".js",
|
|
33
27
|
".ts",
|
|
@@ -36,9 +30,6 @@ const UPDATABLE_EXTS = [
|
|
|
36
30
|
".mts",
|
|
37
31
|
".cts"
|
|
38
32
|
];
|
|
39
|
-
/**
|
|
40
|
-
* @experimental Update a config file or create a new one.
|
|
41
|
-
*/
|
|
42
33
|
async function updateConfig(opts) {
|
|
43
34
|
const { parseModule } = await import("magicast");
|
|
44
35
|
let configFile = tryResolve(`./${opts.configFile}`, opts.cwd, SUPPORTED_EXTENSIONS) || tryResolve(`./.config/${opts.configFile}`, opts.cwd, SUPPORTED_EXTENSIONS) || tryResolve(`./.config/${opts.configFile.split(".")[0]}`, opts.cwd, SUPPORTED_EXTENSIONS);
|
|
@@ -75,6 +66,4 @@ function tryResolve(path, cwd, extensions) {
|
|
|
75
66
|
});
|
|
76
67
|
return res ? normalize(res) : void 0;
|
|
77
68
|
}
|
|
78
|
-
|
|
79
|
-
//#endregion
|
|
80
|
-
export { updateConfig };
|
|
69
|
+
export { updateConfig };
|
package/package.json
CHANGED
|
@@ -1,69 +1,80 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "c12",
|
|
3
|
-
"version": "
|
|
3
|
+
"version": "4.0.0-beta.2",
|
|
4
4
|
"description": "Smart Config Loader",
|
|
5
|
-
"repository": "unjs/c12",
|
|
6
5
|
"license": "MIT",
|
|
7
|
-
"
|
|
8
|
-
"type": "module",
|
|
9
|
-
"exports": {
|
|
10
|
-
".": {
|
|
11
|
-
"types": "./dist/index.d.mts",
|
|
12
|
-
"default": "./dist/index.mjs"
|
|
13
|
-
},
|
|
14
|
-
"./update": {
|
|
15
|
-
"types": "./dist/update.d.mts",
|
|
16
|
-
"default": "./dist/update.mjs"
|
|
17
|
-
}
|
|
18
|
-
},
|
|
19
|
-
"types": "./dist/index.d.mts",
|
|
6
|
+
"repository": "unjs/c12",
|
|
20
7
|
"files": [
|
|
21
8
|
"dist"
|
|
22
9
|
],
|
|
10
|
+
"type": "module",
|
|
11
|
+
"sideEffects": false,
|
|
12
|
+
"types": "./dist/index.d.mts",
|
|
13
|
+
"exports": {
|
|
14
|
+
".": "./dist/index.mjs",
|
|
15
|
+
"./update": "./dist/update.mjs"
|
|
16
|
+
},
|
|
23
17
|
"scripts": {
|
|
24
18
|
"build": "obuild",
|
|
25
19
|
"dev": "vitest dev",
|
|
26
|
-
"lint": "
|
|
27
|
-
"lint:fix": "automd &&
|
|
28
|
-
"release": "pnpm
|
|
20
|
+
"lint": "oxlint . && oxfmt --check src test",
|
|
21
|
+
"lint:fix": "automd && oxlint . --fix && oxfmt src test",
|
|
22
|
+
"release": "pnpm test && pnpm build && changelogen --release --prerelease --publish && git push --follow-tags",
|
|
29
23
|
"test": "pnpm lint && vitest run --coverage && pnpm test:types",
|
|
30
|
-
"test:types": "
|
|
24
|
+
"test:types": "tsgo --noEmit"
|
|
31
25
|
},
|
|
32
26
|
"dependencies": {
|
|
33
|
-
"
|
|
34
|
-
"confbox": "^0.2.2",
|
|
27
|
+
"confbox": "^0.2.4",
|
|
35
28
|
"defu": "^6.1.4",
|
|
36
|
-
"dotenv": "^17.2.3",
|
|
37
29
|
"exsolve": "^1.0.8",
|
|
38
|
-
"giget": "^2.0.0",
|
|
39
|
-
"jiti": "^2.6.1",
|
|
40
|
-
"ohash": "^2.0.11",
|
|
41
30
|
"pathe": "^2.0.3",
|
|
42
|
-
"perfect-debounce": "^2.0.0",
|
|
43
31
|
"pkg-types": "^2.3.0",
|
|
44
|
-
"rc9": "^
|
|
32
|
+
"rc9": "^3.0.0"
|
|
45
33
|
},
|
|
46
34
|
"devDependencies": {
|
|
47
|
-
"@types/node": "^25.
|
|
48
|
-
"@
|
|
49
|
-
"
|
|
35
|
+
"@types/node": "^25.2.1",
|
|
36
|
+
"@typescript/native-preview": "^7.0.0-dev.20260206.1",
|
|
37
|
+
"@vitest/coverage-v8": "^4.0.18",
|
|
38
|
+
"automd": "^0.4.3",
|
|
50
39
|
"changelogen": "^0.6.2",
|
|
51
|
-
"
|
|
52
|
-
"
|
|
40
|
+
"chokidar": "^5.0.0",
|
|
41
|
+
"dotenv": "^17.2.4",
|
|
42
|
+
"eslint-config-unjs": "^0.6.2",
|
|
53
43
|
"expect-type": "^1.3.0",
|
|
54
|
-
"
|
|
55
|
-
"
|
|
56
|
-
"
|
|
44
|
+
"giget": "^3.1.2",
|
|
45
|
+
"jiti": "^2.6.1",
|
|
46
|
+
"magicast": "^0.5.2",
|
|
47
|
+
"obuild": "^0.4.27",
|
|
48
|
+
"ohash": "^2.0.11",
|
|
49
|
+
"oxfmt": "^0.28.0",
|
|
50
|
+
"oxlint": "^1.43.0",
|
|
51
|
+
"perfect-debounce": "^2.1.0",
|
|
57
52
|
"typescript": "^5.9.3",
|
|
58
|
-
"vitest": "^4.0.
|
|
53
|
+
"vitest": "^4.0.18"
|
|
59
54
|
},
|
|
60
55
|
"peerDependencies": {
|
|
56
|
+
"chokidar": "^5",
|
|
57
|
+
"dotenv": "*",
|
|
58
|
+
"giget": "*",
|
|
59
|
+
"jiti": "*",
|
|
61
60
|
"magicast": "*"
|
|
62
61
|
},
|
|
63
62
|
"peerDependenciesMeta": {
|
|
63
|
+
"dotenv": {
|
|
64
|
+
"optional": true
|
|
65
|
+
},
|
|
64
66
|
"magicast": {
|
|
65
67
|
"optional": true
|
|
68
|
+
},
|
|
69
|
+
"chokidar": {
|
|
70
|
+
"optional": true
|
|
71
|
+
},
|
|
72
|
+
"jiti": {
|
|
73
|
+
"optional": true
|
|
74
|
+
},
|
|
75
|
+
"giget": {
|
|
76
|
+
"optional": true
|
|
66
77
|
}
|
|
67
78
|
},
|
|
68
|
-
"packageManager": "pnpm@10.
|
|
79
|
+
"packageManager": "pnpm@10.28.2"
|
|
69
80
|
}
|