typed-settings 0.1.1 → 0.2.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.
Files changed (83) hide show
  1. package/README.md +18 -9
  2. package/bin/typed-settings.mjs +5 -0
  3. package/dist/adapters/joi.cjs +1 -26
  4. package/dist/adapters/joi.d.cts +2 -1
  5. package/dist/adapters/joi.d.ts +2 -1
  6. package/dist/adapters/joi.js +1 -1
  7. package/dist/adapters/superstruct.cjs +1 -26
  8. package/dist/adapters/superstruct.js +1 -1
  9. package/dist/adapters/yup.cjs +1 -25
  10. package/dist/adapters/yup.js +1 -1
  11. package/dist/adapters/zod.cjs +3 -36
  12. package/dist/adapters/zod.d.cts +2 -0
  13. package/dist/adapters/zod.d.ts +2 -0
  14. package/dist/adapters/zod.js +1 -33
  15. package/dist/check-XVFZEVNV.js +1 -0
  16. package/dist/chunk-4EAMKDNK.js +3 -0
  17. package/dist/chunk-5D2AQWDG.js +1 -0
  18. package/dist/chunk-C6CG2D4B.js +2 -0
  19. package/dist/chunk-FQYD5ZKE.js +1 -0
  20. package/dist/chunk-NQDE3WLR.js +3 -0
  21. package/dist/chunk-RURPDXIJ.js +1 -0
  22. package/dist/cli/main.cjs +36 -2220
  23. package/dist/cli/main.js +32 -806
  24. package/dist/errors-JkkOM0u-.d.cts +25 -0
  25. package/dist/errors-JkkOM0u-.d.ts +25 -0
  26. package/dist/framework/next.cjs +5 -1153
  27. package/dist/framework/next.d.cts +5 -3
  28. package/dist/framework/next.d.ts +5 -3
  29. package/dist/framework/next.js +1 -15
  30. package/dist/framework/vite.cjs +5 -1151
  31. package/dist/framework/vite.d.cts +10 -3
  32. package/dist/framework/vite.d.ts +10 -3
  33. package/dist/framework/vite.js +1 -14
  34. package/dist/index.cjs +5 -1176
  35. package/dist/index.d.cts +46 -10
  36. package/dist/index.d.ts +46 -10
  37. package/dist/index.js +1 -6
  38. package/dist/node.cjs +6 -1236
  39. package/dist/node.d.cts +23 -9
  40. package/dist/node.d.ts +23 -9
  41. package/dist/node.js +1 -7
  42. package/dist/{types-CClP1lxq.d.ts → types-CcsYDAdO.d.cts} +27 -3
  43. package/dist/{types-CClP1lxq.d.cts → types-CcsYDAdO.d.ts} +27 -3
  44. package/dist/vault/aws.cjs +4 -217
  45. package/dist/vault/aws.d.cts +3 -1
  46. package/dist/vault/aws.d.ts +3 -1
  47. package/dist/vault/aws.js +2 -167
  48. package/dist/vault/hashicorp.cjs +4 -183
  49. package/dist/vault/hashicorp.d.cts +3 -1
  50. package/dist/vault/hashicorp.d.ts +3 -1
  51. package/dist/vault/hashicorp.js +2 -77
  52. package/dist/vault/http.cjs +4 -185
  53. package/dist/vault/http.d.cts +3 -1
  54. package/dist/vault/http.d.ts +3 -1
  55. package/dist/vault/http.js +2 -79
  56. package/package.json +10 -3
  57. package/dist/chunk-33M5GIKQ.js +0 -13
  58. package/dist/chunk-A5TCQJ7L.js +0 -65
  59. package/dist/chunk-EE6LXNJV.js +0 -34
  60. package/dist/chunk-F6DX3HXZ.js +0 -101
  61. package/dist/chunk-OVFMKC2O.js +0 -15
  62. package/dist/chunk-RCO6K3WQ.js +0 -984
  63. package/dist/chunk-RQC6OMVV.js +0 -86
  64. package/dist/chunk-UFUHHR2J.js +0 -38
  65. package/dist/chunk-VTIYOSG2.js +0 -233
  66. package/dist/errors-itGaU4Q8.d.cts +0 -17
  67. package/dist/errors-itGaU4Q8.d.ts +0 -17
  68. package/dist/formats/env.cjs +0 -103
  69. package/dist/formats/env.d.cts +0 -8
  70. package/dist/formats/env.d.ts +0 -8
  71. package/dist/formats/env.js +0 -1
  72. package/dist/formats/json.cjs +0 -15
  73. package/dist/formats/json.d.cts +0 -7
  74. package/dist/formats/json.d.ts +0 -7
  75. package/dist/formats/json.js +0 -1
  76. package/dist/formats/toml.cjs +0 -17
  77. package/dist/formats/toml.d.cts +0 -7
  78. package/dist/formats/toml.d.ts +0 -7
  79. package/dist/formats/toml.js +0 -1
  80. package/dist/formats/yaml.cjs +0 -40
  81. package/dist/formats/yaml.d.cts +0 -8
  82. package/dist/formats/yaml.d.ts +0 -8
  83. package/dist/formats/yaml.js +0 -1
@@ -1,183 +1,4 @@
1
- 'use strict';
2
-
3
- // src/errors.ts
4
- function byteLengthUtf8(text) {
5
- try {
6
- const g = globalThis;
7
- if (g.TextEncoder) return new g.TextEncoder().encode(text).length;
8
- if (g.Buffer) return g.Buffer.byteLength(text, "utf8");
9
- } catch {
10
- }
11
- return text.length;
12
- }
13
- var ConfigError = class extends Error {
14
- code = "E_INVALID_CONFIG";
15
- issues;
16
- constructor(issues, code = "E_INVALID_CONFIG") {
17
- const lines = issues.map(
18
- (i) => `- ${i.path} (from ${i.from}): ${i.message}`
19
- );
20
- super(`Invalid config (${issues.length} issue${issues.length === 1 ? "" : "s"}):
21
- ${lines.join("\n")}`);
22
- this.name = "ConfigError";
23
- this.code = code;
24
- this.issues = issues;
25
- }
26
- };
27
-
28
- // src/vault/shared.ts
29
- function getFetch(fetchFn) {
30
- if (fetchFn) return fetchFn;
31
- const g = globalThis;
32
- if (g.fetch) return g.fetch.bind(globalThis);
33
- throw new ConfigError(
34
- [{ path: "<provider>", from: "vault", message: "E_NO_FETCH: global fetch unavailable" }],
35
- "E_NO_FETCH"
36
- );
37
- }
38
- function sameHost(a, b) {
39
- return new URL(a).host === new URL(b).host;
40
- }
41
- var SENSITIVE_HEADER_RE = /authorization|token|secret|api[-_]?key|cookie|auth/i;
42
- function stripSensitiveForCrossHost(headers) {
43
- const next = new Headers();
44
- headers.forEach((value, key) => {
45
- if (!SENSITIVE_HEADER_RE.test(key)) next.set(key, value);
46
- });
47
- return next;
48
- }
49
- async function fetchWithRedirectGuard(url, init, fetchFn, maxRedirects = 2) {
50
- let current = url;
51
- let headers = new Headers(init.headers);
52
- for (let i = 0; i <= maxRedirects; i++) {
53
- const res = await fetchFn(current, { ...init, headers, redirect: "manual" });
54
- const status = res.status;
55
- if (![301, 302, 303, 307, 308].includes(status)) return res;
56
- const loc = res.headers.get("location");
57
- if (!loc) return res;
58
- let next;
59
- try {
60
- next = new URL(loc, current).toString();
61
- } catch {
62
- throw new ConfigError(
63
- [{ path: current, from: "vault", message: "E_REDIRECT: invalid Location header" }],
64
- "E_REDIRECT"
65
- );
66
- }
67
- if (i === maxRedirects) {
68
- throw new ConfigError(
69
- [{ path: next, from: "vault", message: "E_REDIRECT: too many redirects" }],
70
- "E_REDIRECT"
71
- );
72
- }
73
- if (!sameHost(current, next)) headers = stripSensitiveForCrossHost(headers);
74
- current = next;
75
- }
76
- throw new ConfigError([{ path: url, from: "vault", message: "E_REDIRECT" }], "E_REDIRECT");
77
- }
78
- function normalizeSecretMap(raw, providerName, opts) {
79
- const clean = (v) => {
80
- if (v === null || v === void 0) return void 0;
81
- let s = typeof v === "string" ? v : String(v);
82
- s = s.replace(/\r?\n$/, "");
83
- return s;
84
- };
85
- const out = {};
86
- if (!raw || typeof raw !== "object" || Array.isArray(raw)) {
87
- throw new ConfigError(
88
- [{ path: "<root>", from: providerName, message: "E_SHAPE: provider returned non-object" }],
89
- "E_SHAPE"
90
- );
91
- }
92
- for (const [k, v] of Object.entries(raw)) {
93
- if (v !== null && typeof v === "object" && !Array.isArray(v)) {
94
- out[k] = v;
95
- continue;
96
- }
97
- const c = clean(v);
98
- if (c !== void 0) out[k] = c;
99
- }
100
- return out;
101
- }
102
- function statusToCode(status) {
103
- if (status === 403 || status === 401) return "E_DENIED";
104
- if (status === 404) return "E_NOT_FOUND";
105
- if (status === 429) return "E_THROTTLED";
106
- if (status >= 500) return "E_UPSTREAM";
107
- return "E_PROVIDER";
108
- }
109
-
110
- // src/vault/hashicorp.ts
111
- function tokenFromEnv(explicit) {
112
- if (explicit !== void 0) return explicit || void 0;
113
- const g = globalThis;
114
- return g.process?.env?.["VAULT_TOKEN"];
115
- }
116
- function hashicorpProvider(opts) {
117
- const mount = (opts.mount ?? "secret").replace(/^\/+|\/+$/g, "");
118
- const timeoutMs = opts.timeoutMs ?? 5e3;
119
- const maxBytes = opts.maxBytes ?? 1024 * 1024;
120
- const name = `hashicorp://${mount}/${opts.path}`;
121
- let inflight = null;
122
- async function doLoad() {
123
- const token = tokenFromEnv(opts.auth?.token);
124
- const fetchFn = getFetch(opts.fetchFn);
125
- const base = opts.url.replace(/\/+$/g, "");
126
- const p = opts.path.replace(/^\/+/, "");
127
- const qs = opts.version !== void 0 ? `?version=${encodeURIComponent(String(opts.version))}` : "";
128
- const url = `${base}/v1/${mount}/${p}${qs}`;
129
- const headers = new Headers();
130
- if (token) headers.set("X-Vault-Token", token);
131
- headers.set("Accept", "application/json");
132
- let res;
133
- try {
134
- res = await fetchWithRedirectGuard(
135
- url,
136
- { headers, signal: AbortSignal.timeout(timeoutMs) },
137
- fetchFn
138
- );
139
- } catch (e) {
140
- if (e instanceof ConfigError) throw e;
141
- const err = e;
142
- const isTimeout = /timeout|abort/i.test(err?.name + err?.message);
143
- throw new ConfigError(
144
- [{ path: p, from: name, message: `${isTimeout ? "E_TIMEOUT" : "E_CONN"}: ${err?.message ?? String(e)}` }],
145
- isTimeout ? "E_TIMEOUT" : "E_CONN"
146
- );
147
- }
148
- if (!res.ok) {
149
- const code = statusToCode(res.status);
150
- throw new ConfigError([{ path: p, from: name, message: `${code}: HTTP ${res.status}` }], code);
151
- }
152
- const text = await res.text();
153
- if (byteLengthUtf8(text) > maxBytes) {
154
- throw new ConfigError([{ path: p, from: name, message: "E_TOO_LARGE: secret >cap" }], "E_TOO_LARGE");
155
- }
156
- let json;
157
- try {
158
- json = JSON.parse(text);
159
- } catch {
160
- throw new ConfigError([{ path: p, from: name, message: "E_PARSE: invalid JSON" }], "E_PARSE");
161
- }
162
- const data = json.data;
163
- const isKv2 = !!data && typeof data === "object" && "data" in data && "metadata" in data;
164
- const inner = isKv2 ? data.data : data;
165
- if (!inner || typeof inner !== "object" || Array.isArray(inner)) {
166
- throw new ConfigError([{ path: p, from: name, message: "E_SHAPE: missing data" }], "E_SHAPE");
167
- }
168
- return normalizeSecretMap(inner, name);
169
- }
170
- return {
171
- name,
172
- load() {
173
- if (!inflight) {
174
- inflight = doLoad().finally(() => {
175
- inflight = null;
176
- });
177
- }
178
- return inflight;
179
- }
180
- };
181
- }
182
-
183
- exports.hashicorpProvider = hashicorpProvider;
1
+ 'use strict';function R(e){try{let n=globalThis;if(n.TextEncoder)return new n.TextEncoder().encode(e).length;if(n.Buffer)return n.Buffer.byteLength(e,"utf8")}catch{}return e.length}var s=class extends Error{code="E_INVALID_CONFIG";issues;static[Symbol.hasInstance](n){return typeof n=="object"&&n!==null&&n.name==="ConfigError"&&typeof n.code=="string"&&Array.isArray(n.issues)}constructor(n=[],o="E_INVALID_CONFIG"){let c=n.map(t=>`- ${t.path} (from ${t.from}): ${t.message}`);super(n.length===0?"Invalid config: unknown error (no issues attached)":`Invalid config (${n.length} issue${n.length===1?"":"s"}):
2
+ ${c.join(`
3
+ `)}`),this.name="ConfigError",this.code=o,this.issues=n;}};function A(e){return e.toLowerCase()==="__proto__"}function k(e){if(e)return e;let n=globalThis;if(n.fetch)return n.fetch.bind(globalThis);throw new s([{path:"<provider>",from:"vault",message:"E_NO_FETCH: global fetch unavailable"}],"E_NO_FETCH")}function j(e,n){try{return new URL(e).host===new URL(n).host}catch{return false}}var M=/authorization|token|secret|api[-_]?key|cookie|auth/i;function F(e,n){try{return new URL(e).protocol==="https:"&&new URL(n).protocol!=="https:"}catch{return false}}function L(e){let n=new Headers;return e.forEach((o,c)=>{M.test(c)||n.set(c,o);}),n}async function b(e,n,o,c=2){let t=e,a=new Headers(n.headers);for(let i=0;i<=c;i++){let r=await o(t,{...n,headers:a,redirect:"manual"}),u=r.status;if(![301,302,303,307,308].includes(u))return r;let m=r.headers.get("location");if(!m)return r;let f;try{f=new URL(m,t).toString();}catch{throw new s([{path:t,from:"vault",message:"E_REDIRECT: invalid Location header"}],"E_REDIRECT")}if(i===c)throw new s([{path:f,from:"vault",message:"E_REDIRECT: too many redirects"}],"E_REDIRECT");(!j(t,f)||F(t,f))&&(a=L(a)),t=f;}throw new s([{path:e,from:"vault",message:"E_REDIRECT"}],"E_REDIRECT")}function T(e,n,o){let t=i=>{if(i==null)return;let r=typeof i=="string"?i:String(i);return (r=r.replace(/\r?\n$/,"")),r},a={};if(!e||typeof e!="object"||Array.isArray(e))throw new s([{path:"<root>",from:n,message:"E_SHAPE: provider returned non-object"}],"E_SHAPE");for(let[i,r]of Object.entries(e)){if(A(i))throw new s([{path:i,from:n,message:"E_PROTO: forbidden key"}],"E_PROTO");if(r!==null&&typeof r=="object"&&!Array.isArray(r)){a[i]=r;continue}let u=t(r);u!==void 0&&(a[i]=u);}return a}function O(e){return e===403||e===401?"E_DENIED":e===404?"E_NOT_FOUND":e===429?"E_THROTTLED":e===408||e===504?"E_TIMEOUT":e>=500?"E_UPSTREAM":"E_PROVIDER"}function x(e,n){let o=AbortSignal;if(typeof o.timeout=="function")try{return o.timeout(e)}catch{return}}function E(e,n,o){if(!Number.isFinite(e)||e<=0)throw new s([{path:n,from:o,message:`E_USAGE: ${n} must be a positive finite number`}],"E_USAGE")}async function P(e,n,o,c){let t,a=new Promise((i,r)=>{t=setTimeout(()=>r(new s([{path:o,from:c,message:"E_TIMEOUT: request timed out"}],"E_TIMEOUT")),n);});e.catch(()=>{});try{return await Promise.race([e,a])}finally{t&&clearTimeout(t);}}async function I(e,n,o,c,t){let a,i=new Promise((r,u)=>{a=setTimeout(()=>u(new s([{path:n,from:o,message:"E_TIMEOUT: response body timed out"}],"E_TIMEOUT")),t);});try{let r=e.text();r.catch(()=>{});let u=await Promise.race([r,i]);if(R(u)>c)throw new s([{path:n,from:o,message:"E_TOO_LARGE"}],"E_TOO_LARGE");return u}finally{a&&clearTimeout(a);}}function N(e){return e!==void 0?e||void 0:globalThis.process?.env?.VAULT_TOKEN}function G(e){let n=(e.mount??"secret").replace(/^\/+|\/+$/g,""),o=e.timeoutMs??5e3,c=e.maxBytes??1024*1024;E(o,"timeoutMs","hashicorp"),E(c,"maxBytes","hashicorp");let t=`hashicorp://${n}/${e.path}`,a=null;async function i(){let r=N(e.auth?.token),u=k(e.fetchFn),m=e.url.replace(/\/+$/g,""),f=e.path.replace(/^\/+/,""),S=e.version!==void 0?`?version=${encodeURIComponent(String(e.version))}`:"",C=`${m}/v1/${n}/${f}${S}`,h=new Headers;r&&h.set("X-Vault-Token",r),h.has("Accept")||h.set("Accept","application/json");let d;try{d=await P(b(C,{headers:h,signal:x(o)},u),o,f,t);}catch(l){if(l instanceof s)throw l;let w=l,y=/timeout|abort/i.test(w?.name+w?.message);throw new s([{path:f,from:t,message:`${y?"E_TIMEOUT":"E_CONN"}: ${w?.message??String(l)}`}],y?"E_TIMEOUT":"E_CONN")}if(!d.ok){let l=O(d.status);throw new s([{path:f,from:t,message:`${l}: HTTP ${d.status}`}],l)}let $=await I(d,f,t,c,o),_;try{_=JSON.parse($);}catch{throw new s([{path:f,from:t,message:"E_PARSE: invalid JSON"}],"E_PARSE")}let g=_.data,p=!!g&&typeof g=="object"&&Object.hasOwn(g,"data")&&Object.hasOwn(g,"metadata")?g.data:g;if(!p||typeof p!="object"||Array.isArray(p))throw new s([{path:f,from:t,message:"E_SHAPE: missing data"}],"E_SHAPE");return T(p,t)}return {name:t,load(){return a||(a=i().finally(()=>{a=null;})),a}}}
4
+ exports.hashicorpProvider=G;
@@ -1,4 +1,4 @@
1
- import { a as SecretProvider } from '../types-CClP1lxq.cjs';
1
+ import { a as SecretProvider } from '../types-CcsYDAdO.cjs';
2
2
  import { F as FetchFn } from '../shared-CucO_XsG.cjs';
3
3
  import '@standard-schema/spec';
4
4
 
@@ -6,6 +6,8 @@ import '@standard-schema/spec';
6
6
  * HashiCorp Vault provider (KVv1 + KVv2): reads one secret path into a flat map.
7
7
  * Token comes from `auth.token` or `VAULT_TOKEN`; KVv2 envelopes unwrap only
8
8
  * when a `metadata` sibling is present. Fail-closed on 403.
9
+ *
10
+ * @module
9
11
  */
10
12
 
11
13
  /** Options for {@link hashicorpProvider}. */
@@ -1,4 +1,4 @@
1
- import { a as SecretProvider } from '../types-CClP1lxq.js';
1
+ import { a as SecretProvider } from '../types-CcsYDAdO.js';
2
2
  import { F as FetchFn } from '../shared-CucO_XsG.js';
3
3
  import '@standard-schema/spec';
4
4
 
@@ -6,6 +6,8 @@ import '@standard-schema/spec';
6
6
  * HashiCorp Vault provider (KVv1 + KVv2): reads one secret path into a flat map.
7
7
  * Token comes from `auth.token` or `VAULT_TOKEN`; KVv2 envelopes unwrap only
8
8
  * when a `metadata` sibling is present. Fail-closed on 403.
9
+ *
10
+ * @module
9
11
  */
10
12
 
11
13
  /** Options for {@link hashicorpProvider}. */
@@ -1,77 +1,2 @@
1
- import { getFetch, fetchWithRedirectGuard, statusToCode, normalizeSecretMap } from '../chunk-RQC6OMVV.js';
2
- import { ConfigError, byteLengthUtf8 } from '../chunk-EE6LXNJV.js';
3
-
4
- // src/vault/hashicorp.ts
5
- function tokenFromEnv(explicit) {
6
- if (explicit !== void 0) return explicit || void 0;
7
- const g = globalThis;
8
- return g.process?.env?.["VAULT_TOKEN"];
9
- }
10
- function hashicorpProvider(opts) {
11
- const mount = (opts.mount ?? "secret").replace(/^\/+|\/+$/g, "");
12
- const timeoutMs = opts.timeoutMs ?? 5e3;
13
- const maxBytes = opts.maxBytes ?? 1024 * 1024;
14
- const name = `hashicorp://${mount}/${opts.path}`;
15
- let inflight = null;
16
- async function doLoad() {
17
- const token = tokenFromEnv(opts.auth?.token);
18
- const fetchFn = getFetch(opts.fetchFn);
19
- const base = opts.url.replace(/\/+$/g, "");
20
- const p = opts.path.replace(/^\/+/, "");
21
- const qs = opts.version !== void 0 ? `?version=${encodeURIComponent(String(opts.version))}` : "";
22
- const url = `${base}/v1/${mount}/${p}${qs}`;
23
- const headers = new Headers();
24
- if (token) headers.set("X-Vault-Token", token);
25
- headers.set("Accept", "application/json");
26
- let res;
27
- try {
28
- res = await fetchWithRedirectGuard(
29
- url,
30
- { headers, signal: AbortSignal.timeout(timeoutMs) },
31
- fetchFn
32
- );
33
- } catch (e) {
34
- if (e instanceof ConfigError) throw e;
35
- const err = e;
36
- const isTimeout = /timeout|abort/i.test(err?.name + err?.message);
37
- throw new ConfigError(
38
- [{ path: p, from: name, message: `${isTimeout ? "E_TIMEOUT" : "E_CONN"}: ${err?.message ?? String(e)}` }],
39
- isTimeout ? "E_TIMEOUT" : "E_CONN"
40
- );
41
- }
42
- if (!res.ok) {
43
- const code = statusToCode(res.status);
44
- throw new ConfigError([{ path: p, from: name, message: `${code}: HTTP ${res.status}` }], code);
45
- }
46
- const text = await res.text();
47
- if (byteLengthUtf8(text) > maxBytes) {
48
- throw new ConfigError([{ path: p, from: name, message: "E_TOO_LARGE: secret >cap" }], "E_TOO_LARGE");
49
- }
50
- let json;
51
- try {
52
- json = JSON.parse(text);
53
- } catch {
54
- throw new ConfigError([{ path: p, from: name, message: "E_PARSE: invalid JSON" }], "E_PARSE");
55
- }
56
- const data = json.data;
57
- const isKv2 = !!data && typeof data === "object" && "data" in data && "metadata" in data;
58
- const inner = isKv2 ? data.data : data;
59
- if (!inner || typeof inner !== "object" || Array.isArray(inner)) {
60
- throw new ConfigError([{ path: p, from: name, message: "E_SHAPE: missing data" }], "E_SHAPE");
61
- }
62
- return normalizeSecretMap(inner, name);
63
- }
64
- return {
65
- name,
66
- load() {
67
- if (!inflight) {
68
- inflight = doLoad().finally(() => {
69
- inflight = null;
70
- });
71
- }
72
- return inflight;
73
- }
74
- };
75
- }
76
-
77
- export { hashicorpProvider };
1
+ import {f,a,h,b,e,d as d$1,i,c}from'../chunk-5D2AQWDG.js';import {d}from'../chunk-NQDE3WLR.js';function R(e){return e!==void 0?e||void 0:globalThis.process?.env?.VAULT_TOKEN}function x(e$1){let d$2=(e$1.mount??"secret").replace(/^\/+|\/+$/g,""),i$1=e$1.timeoutMs??5e3,p=e$1.maxBytes??1024*1024;f(i$1,"timeoutMs","hashicorp"),f(p,"maxBytes","hashicorp");let t=`hashicorp://${d$2}/${e$1.path}`,c$1=null;async function P(){let g=R(e$1.auth?.token),S=a(e$1.fetchFn),k=e$1.url.replace(/\/+$/g,""),n=e$1.path.replace(/^\/+/,""),b$1=e$1.version!==void 0?`?version=${encodeURIComponent(String(e$1.version))}`:"",A=`${k}/v1/${d$2}/${n}${b$1}`,u=new Headers;g&&u.set("X-Vault-Token",g),u.has("Accept")||u.set("Accept","application/json");let a$1;try{a$1=await h(b(A,{headers:u,signal:e(i$1)},S),i$1,n,t);}catch(r){if(r instanceof d)throw r;let h=r,w=/timeout|abort/i.test(h?.name+h?.message);throw new d([{path:n,from:t,message:`${w?"E_TIMEOUT":"E_CONN"}: ${h?.message??String(r)}`}],w?"E_TIMEOUT":"E_CONN")}if(!a$1.ok){let r=d$1(a$1.status);throw new d([{path:n,from:t,message:`${r}: HTTP ${a$1.status}`}],r)}let _=await i(a$1,n,t,p,i$1),l;try{l=JSON.parse(_);}catch{throw new d([{path:n,from:t,message:"E_PARSE: invalid JSON"}],"E_PARSE")}let s=l.data,m=!!s&&typeof s=="object"&&Object.hasOwn(s,"data")&&Object.hasOwn(s,"metadata")?s.data:s;if(!m||typeof m!="object"||Array.isArray(m))throw new d([{path:n,from:t,message:"E_SHAPE: missing data"}],"E_SHAPE");return c(m,t)}return {name:t,load(){return c$1||(c$1=P().finally(()=>{c$1=null;})),c$1}}}
2
+ export{x as hashicorpProvider};
@@ -1,185 +1,4 @@
1
- 'use strict';
2
-
3
- // src/errors.ts
4
- function byteLengthUtf8(text) {
5
- try {
6
- const g = globalThis;
7
- if (g.TextEncoder) return new g.TextEncoder().encode(text).length;
8
- if (g.Buffer) return g.Buffer.byteLength(text, "utf8");
9
- } catch {
10
- }
11
- return text.length;
12
- }
13
- var ConfigError = class extends Error {
14
- code = "E_INVALID_CONFIG";
15
- issues;
16
- constructor(issues, code = "E_INVALID_CONFIG") {
17
- const lines = issues.map(
18
- (i) => `- ${i.path} (from ${i.from}): ${i.message}`
19
- );
20
- super(`Invalid config (${issues.length} issue${issues.length === 1 ? "" : "s"}):
21
- ${lines.join("\n")}`);
22
- this.name = "ConfigError";
23
- this.code = code;
24
- this.issues = issues;
25
- }
26
- };
27
-
28
- // src/vault/shared.ts
29
- function getFetch(fetchFn) {
30
- if (fetchFn) return fetchFn;
31
- const g = globalThis;
32
- if (g.fetch) return g.fetch.bind(globalThis);
33
- throw new ConfigError(
34
- [{ path: "<provider>", from: "vault", message: "E_NO_FETCH: global fetch unavailable" }],
35
- "E_NO_FETCH"
36
- );
37
- }
38
- function sameHost(a, b) {
39
- return new URL(a).host === new URL(b).host;
40
- }
41
- var SENSITIVE_HEADER_RE = /authorization|token|secret|api[-_]?key|cookie|auth/i;
42
- function stripSensitiveForCrossHost(headers) {
43
- const next = new Headers();
44
- headers.forEach((value, key) => {
45
- if (!SENSITIVE_HEADER_RE.test(key)) next.set(key, value);
46
- });
47
- return next;
48
- }
49
- async function fetchWithRedirectGuard(url, init, fetchFn, maxRedirects = 2) {
50
- let current = url;
51
- let headers = new Headers(init.headers);
52
- for (let i = 0; i <= maxRedirects; i++) {
53
- const res = await fetchFn(current, { ...init, headers, redirect: "manual" });
54
- const status = res.status;
55
- if (![301, 302, 303, 307, 308].includes(status)) return res;
56
- const loc = res.headers.get("location");
57
- if (!loc) return res;
58
- let next;
59
- try {
60
- next = new URL(loc, current).toString();
61
- } catch {
62
- throw new ConfigError(
63
- [{ path: current, from: "vault", message: "E_REDIRECT: invalid Location header" }],
64
- "E_REDIRECT"
65
- );
66
- }
67
- if (i === maxRedirects) {
68
- throw new ConfigError(
69
- [{ path: next, from: "vault", message: "E_REDIRECT: too many redirects" }],
70
- "E_REDIRECT"
71
- );
72
- }
73
- if (!sameHost(current, next)) headers = stripSensitiveForCrossHost(headers);
74
- current = next;
75
- }
76
- throw new ConfigError([{ path: url, from: "vault", message: "E_REDIRECT" }], "E_REDIRECT");
77
- }
78
- function normalizeSecretMap(raw, providerName, opts) {
79
- const clean = (v) => {
80
- if (v === null || v === void 0) return void 0;
81
- let s = typeof v === "string" ? v : String(v);
82
- s = s.replace(/\r?\n$/, "");
83
- return s;
84
- };
85
- const out = {};
86
- if (!raw || typeof raw !== "object" || Array.isArray(raw)) {
87
- throw new ConfigError(
88
- [{ path: "<root>", from: providerName, message: "E_SHAPE: provider returned non-object" }],
89
- "E_SHAPE"
90
- );
91
- }
92
- for (const [k, v] of Object.entries(raw)) {
93
- if (v !== null && typeof v === "object" && !Array.isArray(v)) {
94
- out[k] = v;
95
- continue;
96
- }
97
- const c = clean(v);
98
- if (c !== void 0) out[k] = c;
99
- }
100
- return out;
101
- }
102
- function statusToCode(status) {
103
- if (status === 403 || status === 401) return "E_DENIED";
104
- if (status === 404) return "E_NOT_FOUND";
105
- if (status === 429) return "E_THROTTLED";
106
- if (status >= 500) return "E_UPSTREAM";
107
- return "E_PROVIDER";
108
- }
109
-
110
- // src/vault/http.ts
111
- function getAtPath(obj, path) {
112
- if (!path) return obj;
113
- let cur = obj;
114
- for (const seg of path.split(".")) {
115
- if (cur && typeof cur === "object" && seg in cur) cur = cur[seg];
116
- else return void 0;
117
- }
118
- return cur;
119
- }
120
- function httpProvider(opts) {
121
- const timeoutMs = opts.timeoutMs ?? 5e3;
122
- const maxBytes = opts.maxBytes ?? 1024 * 1024;
123
- const jsonPath = opts.jsonPath ?? "data";
124
- const name = `http://${opts.url}`;
125
- let inflight = null;
126
- async function doLoad() {
127
- const fetchFn = getFetch(opts.fetchFn);
128
- const headers = new Headers();
129
- for (const [k, v] of Object.entries(opts.headers ?? {})) {
130
- if (v !== void 0) headers.set(k, v);
131
- }
132
- headers.set("Accept", "application/json");
133
- let res;
134
- try {
135
- res = await fetchWithRedirectGuard(
136
- opts.url,
137
- { headers, signal: AbortSignal.timeout(timeoutMs) },
138
- fetchFn
139
- );
140
- } catch (e) {
141
- if (e instanceof ConfigError) throw e;
142
- const err = e;
143
- const isTimeout = /timeout|abort/i.test(err?.name + err?.message);
144
- throw new ConfigError(
145
- [{ path: opts.url, from: name, message: `${isTimeout ? "E_TIMEOUT" : "E_CONN"}: ${err?.message ?? String(e)}` }],
146
- isTimeout ? "E_TIMEOUT" : "E_CONN"
147
- );
148
- }
149
- if (!res.ok) {
150
- const code = statusToCode(res.status);
151
- throw new ConfigError([{ path: opts.url, from: name, message: `${code}: HTTP ${res.status}` }], code);
152
- }
153
- const text = await res.text();
154
- if (byteLengthUtf8(text) > maxBytes) {
155
- throw new ConfigError([{ path: opts.url, from: name, message: "E_TOO_LARGE" }], "E_TOO_LARGE");
156
- }
157
- let json;
158
- try {
159
- json = JSON.parse(text);
160
- } catch {
161
- throw new ConfigError([{ path: opts.url, from: name, message: "E_PARSE: invalid JSON" }], "E_PARSE");
162
- }
163
- let inner = getAtPath(json, jsonPath);
164
- if (inner && typeof inner === "object" && !Array.isArray(inner) && "data" in inner && "metadata" in inner) {
165
- inner = inner.data;
166
- }
167
- if (!inner || typeof inner !== "object" || Array.isArray(inner)) {
168
- throw new ConfigError([{ path: jsonPath, from: name, message: "E_SHAPE: missing data" }], "E_SHAPE");
169
- }
170
- return normalizeSecretMap(inner, name);
171
- }
172
- return {
173
- name,
174
- load() {
175
- if (!inflight) {
176
- inflight = doLoad().finally(() => {
177
- inflight = null;
178
- });
179
- }
180
- return inflight;
181
- }
182
- };
183
- }
184
-
185
- exports.httpProvider = httpProvider;
1
+ 'use strict';function E(t){try{let e=globalThis;if(e.TextEncoder)return new e.TextEncoder().encode(t).length;if(e.Buffer)return e.Buffer.byteLength(t,"utf8")}catch{}return t.length}var a=class extends Error{code="E_INVALID_CONFIG";issues;static[Symbol.hasInstance](e){return typeof e=="object"&&e!==null&&e.name==="ConfigError"&&typeof e.code=="string"&&Array.isArray(e.issues)}constructor(e=[],n="E_INVALID_CONFIG"){let c=e.map(r=>`- ${r.path} (from ${r.from}): ${r.message}`);super(e.length===0?"Invalid config: unknown error (no issues attached)":`Invalid config (${e.length} issue${e.length===1?"":"s"}):
2
+ ${c.join(`
3
+ `)}`),this.name="ConfigError",this.code=n,this.issues=e;}};function y(t){return t.toLowerCase()==="__proto__"}function _(t){if(t)return t;let e=globalThis;if(e.fetch)return e.fetch.bind(globalThis);throw new a([{path:"<provider>",from:"vault",message:"E_NO_FETCH: global fetch unavailable"}],"E_NO_FETCH")}function I(t,e){try{return new URL(t).host===new URL(e).host}catch{return false}}var S=/authorization|token|secret|api[-_]?key|cookie|auth/i;function C(t,e){try{return new URL(t).protocol==="https:"&&new URL(e).protocol!=="https:"}catch{return false}}function j(t){let e=new Headers;return t.forEach((n,c)=>{S.test(c)||e.set(c,n);}),e}async function R(t,e,n,c=2){let r=t,o=new Headers(e.headers);for(let s=0;s<=c;s++){let i=await n(r,{...e,headers:o,redirect:"manual"}),f=i.status;if(![301,302,303,307,308].includes(f))return i;let d=i.headers.get("location");if(!d)return i;let u;try{u=new URL(d,r).toString();}catch{throw new a([{path:r,from:"vault",message:"E_REDIRECT: invalid Location header"}],"E_REDIRECT")}if(s===c)throw new a([{path:u,from:"vault",message:"E_REDIRECT: too many redirects"}],"E_REDIRECT");(!I(r,u)||C(r,u))&&(o=j(o)),r=u;}throw new a([{path:t,from:"vault",message:"E_REDIRECT"}],"E_REDIRECT")}function A(t,e,n){let r=s=>{if(s==null)return;let i=typeof s=="string"?s:String(s);return (i=i.replace(/\r?\n$/,"")),i},o={};if(!t||typeof t!="object"||Array.isArray(t))throw new a([{path:"<root>",from:e,message:"E_SHAPE: provider returned non-object"}],"E_SHAPE");for(let[s,i]of Object.entries(t)){if(y(s))throw new a([{path:s,from:e,message:"E_PROTO: forbidden key"}],"E_PROTO");if(i!==null&&typeof i=="object"&&!Array.isArray(i)){o[s]=i;continue}let f=r(i);f!==void 0&&(o[s]=f);}return o}function k(t){return t===403||t===401?"E_DENIED":t===404?"E_NOT_FOUND":t===429?"E_THROTTLED":t===408||t===504?"E_TIMEOUT":t>=500?"E_UPSTREAM":"E_PROVIDER"}function b(t,e){let n=AbortSignal;if(typeof n.timeout=="function")try{return n.timeout(t)}catch{return}}function h(t,e,n){if(!Number.isFinite(t)||t<=0)throw new a([{path:e,from:n,message:`E_USAGE: ${e} must be a positive finite number`}],"E_USAGE")}function O(t){try{let e=new URL(t);e.username="",e.password="";for(let n of [...e.searchParams.keys()])/token|secret|auth|password|credential|api[-_]?key|pwd|passphrase/i.test(n)&&e.searchParams.delete(n);return e.hash="",e.toString()}catch{return t}}async function T(t,e,n,c){let r,o=new Promise((s,i)=>{r=setTimeout(()=>i(new a([{path:n,from:c,message:"E_TIMEOUT: request timed out"}],"E_TIMEOUT")),e);});t.catch(()=>{});try{return await Promise.race([t,o])}finally{r&&clearTimeout(r);}}async function P(t,e,n,c,r){let o,s=new Promise((i,f)=>{o=setTimeout(()=>f(new a([{path:e,from:n,message:"E_TIMEOUT: response body timed out"}],"E_TIMEOUT")),r);});try{let i=t.text();i.catch(()=>{});let f=await Promise.race([i,s]);if(E(f)>c)throw new a([{path:e,from:n,message:"E_TOO_LARGE"}],"E_TOO_LARGE");return f}finally{o&&clearTimeout(o);}}function $(t,e){if(!e)return t;let n=t;for(let c of e.split("."))if(n&&typeof n=="object"&&Object.hasOwn(n,c))n=n[c];else return;return n}function v(t){let e=t.timeoutMs??5e3,n=t.maxBytes??1024*1024;h(e,"timeoutMs","http"),h(n,"maxBytes","http");let c=t.jsonPath??"data",r=O(t.url),o=`http://${r}`,s=null;async function i(){let f=_(t.fetchFn),d=new Headers;for(let[g,m]of Object.entries(t.headers??{}))m!==void 0&&d.set(g,m);d.has("Accept")||d.set("Accept","application/json");let u;try{u=await T(R(t.url,{headers:d,signal:b(e)},f),e,r,o);}catch(g){if(g instanceof a)throw g;let m=g,w=/timeout|abort/i.test(m?.name+m?.message);throw new a([{path:r,from:o,message:`${w?"E_TIMEOUT":"E_CONN"}: ${m?.message??String(g)}`}],w?"E_TIMEOUT":"E_CONN")}if(!u.ok){let g=k(u.status);throw new a([{path:r,from:o,message:`${g}: HTTP ${u.status}`}],g)}let x=await P(u,r,o,n,e),p;try{p=JSON.parse(x);}catch{throw new a([{path:r,from:o,message:"E_PARSE: invalid JSON"}],"E_PARSE")}let l=$(p,c);if(l&&typeof l=="object"&&!Array.isArray(l)&&Object.hasOwn(l,"data")&&Object.hasOwn(l,"metadata")&&(l=l.data),!l||typeof l!="object"||Array.isArray(l))throw new a([{path:c,from:o,message:"E_SHAPE: missing data"}],"E_SHAPE");return A(l,o)}return {name:o,load(){return s||(s=i().finally(()=>{s=null;})),s}}}
4
+ exports.httpProvider=v;
@@ -1,10 +1,12 @@
1
- import { F as Flat, a as SecretProvider } from '../types-CClP1lxq.cjs';
1
+ import { F as Flat, a as SecretProvider } from '../types-CcsYDAdO.cjs';
2
2
  import { F as FetchFn } from '../shared-CucO_XsG.cjs';
3
3
  import '@standard-schema/spec';
4
4
 
5
5
  /**
6
6
  * Generic HTTP secret provider: GETs a JSON endpoint and reads a dot-path
7
7
  * (`jsonPath`, default `'data'`) into a flat map. Auth rides in `headers`.
8
+ *
9
+ * @module
8
10
  */
9
11
 
10
12
  /** Options for {@link httpProvider}. */
@@ -1,10 +1,12 @@
1
- import { F as Flat, a as SecretProvider } from '../types-CClP1lxq.js';
1
+ import { F as Flat, a as SecretProvider } from '../types-CcsYDAdO.js';
2
2
  import { F as FetchFn } from '../shared-CucO_XsG.js';
3
3
  import '@standard-schema/spec';
4
4
 
5
5
  /**
6
6
  * Generic HTTP secret provider: GETs a JSON endpoint and reads a dot-path
7
7
  * (`jsonPath`, default `'data'`) into a flat map. Auth rides in `headers`.
8
+ *
9
+ * @module
8
10
  */
9
11
 
10
12
  /** Options for {@link httpProvider}. */
@@ -1,79 +1,2 @@
1
- import { getFetch, fetchWithRedirectGuard, statusToCode, normalizeSecretMap } from '../chunk-RQC6OMVV.js';
2
- import { ConfigError, byteLengthUtf8 } from '../chunk-EE6LXNJV.js';
3
-
4
- // src/vault/http.ts
5
- function getAtPath(obj, path) {
6
- if (!path) return obj;
7
- let cur = obj;
8
- for (const seg of path.split(".")) {
9
- if (cur && typeof cur === "object" && seg in cur) cur = cur[seg];
10
- else return void 0;
11
- }
12
- return cur;
13
- }
14
- function httpProvider(opts) {
15
- const timeoutMs = opts.timeoutMs ?? 5e3;
16
- const maxBytes = opts.maxBytes ?? 1024 * 1024;
17
- const jsonPath = opts.jsonPath ?? "data";
18
- const name = `http://${opts.url}`;
19
- let inflight = null;
20
- async function doLoad() {
21
- const fetchFn = getFetch(opts.fetchFn);
22
- const headers = new Headers();
23
- for (const [k, v] of Object.entries(opts.headers ?? {})) {
24
- if (v !== void 0) headers.set(k, v);
25
- }
26
- headers.set("Accept", "application/json");
27
- let res;
28
- try {
29
- res = await fetchWithRedirectGuard(
30
- opts.url,
31
- { headers, signal: AbortSignal.timeout(timeoutMs) },
32
- fetchFn
33
- );
34
- } catch (e) {
35
- if (e instanceof ConfigError) throw e;
36
- const err = e;
37
- const isTimeout = /timeout|abort/i.test(err?.name + err?.message);
38
- throw new ConfigError(
39
- [{ path: opts.url, from: name, message: `${isTimeout ? "E_TIMEOUT" : "E_CONN"}: ${err?.message ?? String(e)}` }],
40
- isTimeout ? "E_TIMEOUT" : "E_CONN"
41
- );
42
- }
43
- if (!res.ok) {
44
- const code = statusToCode(res.status);
45
- throw new ConfigError([{ path: opts.url, from: name, message: `${code}: HTTP ${res.status}` }], code);
46
- }
47
- const text = await res.text();
48
- if (byteLengthUtf8(text) > maxBytes) {
49
- throw new ConfigError([{ path: opts.url, from: name, message: "E_TOO_LARGE" }], "E_TOO_LARGE");
50
- }
51
- let json;
52
- try {
53
- json = JSON.parse(text);
54
- } catch {
55
- throw new ConfigError([{ path: opts.url, from: name, message: "E_PARSE: invalid JSON" }], "E_PARSE");
56
- }
57
- let inner = getAtPath(json, jsonPath);
58
- if (inner && typeof inner === "object" && !Array.isArray(inner) && "data" in inner && "metadata" in inner) {
59
- inner = inner.data;
60
- }
61
- if (!inner || typeof inner !== "object" || Array.isArray(inner)) {
62
- throw new ConfigError([{ path: jsonPath, from: name, message: "E_SHAPE: missing data" }], "E_SHAPE");
63
- }
64
- return normalizeSecretMap(inner, name);
65
- }
66
- return {
67
- name,
68
- load() {
69
- if (!inflight) {
70
- inflight = doLoad().finally(() => {
71
- inflight = null;
72
- });
73
- }
74
- return inflight;
75
- }
76
- };
77
- }
78
-
79
- export { httpProvider };
1
+ import {f,g,a,h,b,e,d as d$1,i,c}from'../chunk-5D2AQWDG.js';import {d}from'../chunk-NQDE3WLR.js';function k(e,s){if(!s)return e;let n=e;for(let u of s.split("."))if(n&&typeof n=="object"&&Object.hasOwn(n,u))n=n[u];else return;return n}function _(e$1){let s=e$1.timeoutMs??5e3,n=e$1.maxBytes??1024*1024;f(s,"timeoutMs","http"),f(n,"maxBytes","http");let u=e$1.jsonPath??"data",a$1=g(e$1.url),o=`http://${a$1}`,m=null;async function b$1(){let A=a(e$1.fetchFn),h$1=new Headers;for(let[r,i]of Object.entries(e$1.headers??{}))i!==void 0&&h$1.set(r,i);h$1.has("Accept")||h$1.set("Accept","application/json");let f;try{f=await h(b(e$1.url,{headers:h$1,signal:e(s)},A),s,a$1,o);}catch(r){if(r instanceof d)throw r;let i=r,p=/timeout|abort/i.test(i?.name+i?.message);throw new d([{path:a$1,from:o,message:`${p?"E_TIMEOUT":"E_CONN"}: ${i?.message??String(r)}`}],p?"E_TIMEOUT":"E_CONN")}if(!f.ok){let r=d$1(f.status);throw new d([{path:a$1,from:o,message:`${r}: HTTP ${f.status}`}],r)}let S=await i(f,a$1,o,n,s),d$2;try{d$2=JSON.parse(S);}catch{throw new d([{path:a$1,from:o,message:"E_PARSE: invalid JSON"}],"E_PARSE")}let t=k(d$2,u);if(t&&typeof t=="object"&&!Array.isArray(t)&&Object.hasOwn(t,"data")&&Object.hasOwn(t,"metadata")&&(t=t.data),!t||typeof t!="object"||Array.isArray(t))throw new d([{path:u,from:o,message:"E_SHAPE: missing data"}],"E_SHAPE");return c(t,o)}return {name:o,load(){return m||(m=b$1().finally(()=>{m=null;})),m}}}
2
+ export{_ as httpProvider};
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "typed-settings",
3
- "version": "0.1.1",
3
+ "version": "0.2.1",
4
4
  "description": "One-call typed config for TS: env + .env + yaml/toml/json + secrets-dir + vault -> frozen object. Standard Schema + legacy bridges.",
5
5
  "type": "module",
6
6
  "main": "./dist/index.cjs",
@@ -74,6 +74,7 @@
74
74
  },
75
75
  "scripts": {
76
76
  "build": "tsup",
77
+ "prepack": "npm run build",
77
78
  "test": "vitest run",
78
79
  "test:watch": "vitest",
79
80
  "typecheck": "tsc --noEmit",
@@ -89,6 +90,14 @@
89
90
  "standard-schema"
90
91
  ],
91
92
  "license": "MIT",
93
+ "repository": {
94
+ "type": "git",
95
+ "url": "https://github.com/prosubodh/typed-settings"
96
+ },
97
+ "homepage": "https://github.com/prosubodh/typed-settings#readme",
98
+ "bugs": {
99
+ "url": "https://github.com/prosubodh/typed-settings/issues"
100
+ },
92
101
  "engines": {
93
102
  "node": ">=20"
94
103
  },
@@ -118,12 +127,10 @@
118
127
  "@types/node": "^26.6.4",
119
128
  "@vitest/coverage-v8": "^3.2.7",
120
129
  "arktype": "^2.1.0",
121
- "smol-toml": "^1.3.1",
122
130
  "tsup": "^8.3.5",
123
131
  "typescript": "^5.6.3",
124
132
  "valibot": "^1.0.0",
125
133
  "vitest": "^3.0.0",
126
- "yaml": "^2.6.1",
127
134
  "zod": "^3.24.0 || ^4.0.0"
128
135
  }
129
136
  }