hanzio 1.2.0 → 2.1.0
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 +786 -239
- package/dist/api-wrapper/builders.d.ts +4 -3
- package/dist/api-wrapper/create-client.d.ts +1 -1
- package/dist/api-wrapper/describe.d.ts +16 -0
- package/dist/api-wrapper/endpoint.d.ts +18 -0
- package/dist/api-wrapper/errors.d.ts +39 -2
- package/dist/api-wrapper/index.d.ts +5 -0
- package/dist/api-wrapper/otel.d.ts +44 -0
- package/dist/api-wrapper/paginate.d.ts +12 -0
- package/dist/api-wrapper/redaction.d.ts +2 -0
- package/dist/api-wrapper/shared.d.ts +16 -2
- package/dist/api-wrapper/testing.d.ts +23 -0
- package/dist/api-wrapper/transport.d.ts +4 -5
- package/dist/api-wrapper/types.d.ts +103 -18
- package/dist/array/index.d.ts +50 -4
- package/dist/cache/createCache.d.ts +31 -0
- package/dist/cache/index.d.ts +19 -2
- package/dist/color/contrast.d.ts +40 -0
- package/dist/color/index.d.ts +2 -0
- package/dist/{math → color}/metricsSeriesColors.d.ts +14 -7
- package/dist/cool-console-log/index.d.ts +34 -5
- package/dist/crypto/encoding.d.ts +18 -0
- package/dist/crypto/hash.d.ts +33 -0
- package/dist/crypto/index.d.ts +4 -0
- package/dist/crypto/sealer.d.ts +25 -0
- package/dist/crypto/webhook.d.ts +20 -0
- package/dist/date/index.d.ts +46 -2
- package/dist/emitter/index.d.ts +21 -0
- package/dist/error/index.d.ts +12 -0
- package/dist/format/index.d.ts +102 -0
- package/dist/function/index.d.ts +60 -0
- package/dist/guard/index.d.ts +20 -0
- package/dist/i18n/index.d.ts +37 -0
- package/dist/index-0zvtcbzy.js +224 -0
- package/dist/index-8r2vdzjg.js +87 -0
- package/dist/index-hy7kbb99.js +157 -0
- package/dist/index-hyt6c56h.js +290 -0
- package/dist/{src/secrets/infisical.js → index-j1ybktbr.js} +500 -538
- package/dist/index-k9yx6bne.js +89 -0
- package/dist/index-kj1phgrx.js +169 -0
- package/dist/index-ktynw3vs.js +37 -0
- package/dist/index-mnkcfyx8.js +78 -0
- package/dist/{p-queue/index.js → index-pwt0dz63.js} +7 -11
- package/dist/index-rp5pqghz.js +157 -0
- package/dist/index-w882zry3.js +29 -0
- package/dist/index.d.ts +7 -7
- package/dist/jwt/index.d.ts +50 -2
- package/dist/math/index.d.ts +2 -2
- package/dist/math/linearRegressionTrend.d.ts +14 -1
- package/dist/math/scale.d.ts +8 -0
- package/dist/object/index.d.ts +19 -0
- package/dist/p-queue/index.d.ts +1 -1
- package/dist/promise/index.d.ts +97 -2
- package/dist/secrets/core.d.ts +7 -0
- package/dist/secrets/index.d.ts +3 -1
- package/dist/secrets/public-config.d.ts +7 -0
- package/dist/secrets/vite.d.ts +1 -0
- package/dist/secrets/worker.d.ts +1 -0
- package/dist/sitemap/index.d.ts +48 -6
- package/dist/src/api-wrapper/index.js +60 -1130
- package/dist/src/api-wrapper/testing.js +20 -0
- package/dist/{cool-console-log → src/cool-console-log}/index.js +80 -33
- package/dist/src/crypto/index.js +195 -0
- package/dist/src/format/index.js +211 -0
- package/dist/src/i18n/index.js +36 -0
- package/dist/src/index.js +739 -3145
- package/dist/src/jwt/index.js +138 -92
- package/dist/src/p-queue/index.js +9 -437
- package/dist/src/secrets/index.js +50 -1428
- package/dist/src/secrets/vite.js +10 -39
- package/dist/src/secrets/worker.js +14 -273
- package/dist/src/sitemap/index.js +183 -511
- package/dist/src/storage/index.js +119 -0
- package/dist/src/zod/index.js +340 -167
- package/dist/state/index.d.ts +21 -0
- package/dist/storage/index.d.ts +58 -0
- package/dist/string/index.d.ts +75 -2
- package/dist/typedswitch/index.d.ts +31 -24
- package/dist/types/index.d.ts +11 -0
- package/dist/url/index.d.ts +50 -1
- package/dist/zod/index.d.ts +32 -3
- package/dist/zod/introspect.d.ts +19 -0
- package/dist/zod/jsonToZodSchemaMapper.d.ts +3 -1
- package/dist/zod/zodMinMaxFilter.d.ts +22 -3
- package/dist/zod/zodToTypeString.d.ts +8 -3
- package/package.json +78 -7
- package/src/api-wrapper/actions-impl.ts +11 -72
- package/src/api-wrapper/builders.ts +32 -25
- package/src/api-wrapper/create-client.ts +171 -41
- package/src/api-wrapper/describe.ts +157 -0
- package/src/api-wrapper/endpoint.ts +26 -0
- package/src/api-wrapper/error-reporting.ts +7 -1
- package/src/api-wrapper/errors.ts +107 -2
- package/src/api-wrapper/headers.ts +11 -6
- package/src/api-wrapper/index.ts +5 -0
- package/src/api-wrapper/otel.ts +139 -0
- package/src/api-wrapper/paginate.ts +28 -0
- package/src/api-wrapper/redaction.ts +42 -0
- package/src/api-wrapper/shared.ts +21 -2
- package/src/api-wrapper/testing.ts +48 -0
- package/src/api-wrapper/transport.ts +41 -43
- package/src/api-wrapper/types.ts +185 -18
- package/src/array/index.ts +195 -42
- package/src/cache/createCache.ts +157 -0
- package/src/cache/index.ts +132 -147
- package/src/color/contrast.ts +163 -0
- package/src/color/index.ts +22 -0
- package/src/{math → color}/metricsSeriesColors.ts +47 -49
- package/src/cool-console-log/index.ts +128 -41
- package/src/crypto/encoding.ts +83 -0
- package/src/crypto/hash.ts +170 -0
- package/src/crypto/index.ts +26 -0
- package/src/crypto/sealer.ts +168 -0
- package/src/crypto/webhook.ts +86 -0
- package/src/date/index.ts +109 -34
- package/src/emitter/index.ts +82 -0
- package/src/error/index.ts +63 -0
- package/src/format/index.ts +389 -0
- package/src/function/index.ts +201 -0
- package/src/guard/index.ts +80 -0
- package/src/i18n/index.ts +125 -0
- package/src/index.ts +11 -7
- package/src/jwt/index.ts +199 -125
- package/src/math/index.ts +5 -10
- package/src/math/linearRegressionTrend.ts +33 -8
- package/src/math/scale.ts +17 -0
- package/src/object/index.ts +99 -0
- package/src/p-queue/index.ts +2 -0
- package/src/promise/index.ts +304 -9
- package/src/secrets/core.ts +72 -16
- package/src/secrets/index.ts +16 -4
- package/src/secrets/public-config.ts +47 -0
- package/src/secrets/vite.ts +2 -0
- package/src/secrets/worker.ts +2 -0
- package/src/sitemap/index.ts +293 -130
- package/src/state/index.ts +133 -81
- package/src/storage/index.ts +187 -0
- package/src/string/index.ts +261 -23
- package/src/typedswitch/index.ts +58 -38
- package/src/types/index.ts +14 -0
- package/src/url/index.ts +146 -1
- package/src/zod/index.ts +105 -9
- package/src/zod/introspect.ts +103 -0
- package/src/zod/jsonToZodSchemaMapper.ts +44 -21
- package/src/zod/zodMinMaxFilter.ts +37 -13
- package/src/zod/zodToTypeString.ts +184 -181
- package/dist/api-wrapper/index.js +0 -250
- package/dist/gzip/index.d.ts +0 -2
- package/dist/gzip/index.js +0 -16
- package/dist/index.js +0 -1823
- package/dist/jwt/index.js +0 -19
- package/dist/sitemap/index.js +0 -552
- package/dist/src/gzip/index.js +0 -16
- package/dist/src/secrets/loaders.js +0 -1529
- package/dist/zod/index.js +0 -210
|
@@ -0,0 +1,290 @@
|
|
|
1
|
+
import {
|
|
2
|
+
SecretLoadError2
|
|
3
|
+
} from "./index-ktynw3vs.js";
|
|
4
|
+
|
|
5
|
+
// src/secrets/environment.ts
|
|
6
|
+
function getProcessEnvironment() {
|
|
7
|
+
return typeof process === "undefined" ? undefined : process.env;
|
|
8
|
+
}
|
|
9
|
+
function resolveSecretEnvironment(option, env) {
|
|
10
|
+
const explicit = typeof option === "function" ? option() : option;
|
|
11
|
+
if (typeof explicit === "object" && explicit !== null) {
|
|
12
|
+
if (typeof explicit.slug !== "string" || !/^[a-zA-Z0-9][a-zA-Z0-9_-]*$/.test(explicit.slug)) {
|
|
13
|
+
throw new SecretLoadError2("CONFIGURATION", "Custom secret environment requires a valid slug.");
|
|
14
|
+
}
|
|
15
|
+
return explicit.slug;
|
|
16
|
+
}
|
|
17
|
+
const selected = explicit ?? env?.SECRETS_ENV;
|
|
18
|
+
if (selected !== undefined) {
|
|
19
|
+
if (selected === "production" || selected === "prod") {
|
|
20
|
+
return "prod";
|
|
21
|
+
}
|
|
22
|
+
if (selected === "development" || selected === "dev") {
|
|
23
|
+
return "dev";
|
|
24
|
+
}
|
|
25
|
+
if (selected === "staging") {
|
|
26
|
+
return "staging";
|
|
27
|
+
}
|
|
28
|
+
throw new SecretLoadError2("CONFIGURATION", "Invalid secret environment. Use dev, staging, prod, or an explicit { slug } option.");
|
|
29
|
+
}
|
|
30
|
+
if (env?.NODE_ENV === "production" || env?.NODE_ENV === "prod") {
|
|
31
|
+
return "prod";
|
|
32
|
+
}
|
|
33
|
+
if (env?.NODE_ENV === "staging") {
|
|
34
|
+
return "staging";
|
|
35
|
+
}
|
|
36
|
+
return "dev";
|
|
37
|
+
}
|
|
38
|
+
|
|
39
|
+
// src/secrets/deadline.ts
|
|
40
|
+
async function withSecretDeadline(options, operation) {
|
|
41
|
+
const timeoutMs = options.timeoutMs ?? 30000;
|
|
42
|
+
if (!Number.isFinite(timeoutMs) || timeoutMs <= 0 || timeoutMs > 2147483647) {
|
|
43
|
+
throw new SecretLoadError2("CONFIGURATION", "Secret timeoutMs must be a positive finite timer duration.");
|
|
44
|
+
}
|
|
45
|
+
const controller = new AbortController;
|
|
46
|
+
const cancel = () => controller.abort(new SecretLoadError2("ABORTED", "Secret loading was cancelled."));
|
|
47
|
+
if (options.signal?.aborted) {
|
|
48
|
+
cancel();
|
|
49
|
+
} else {
|
|
50
|
+
options.signal?.addEventListener("abort", cancel, { once: true });
|
|
51
|
+
}
|
|
52
|
+
const timer = setTimeout(() => controller.abort(new SecretLoadError2("TIMEOUT", `Secret loading timed out after ${timeoutMs}ms.`)), timeoutMs);
|
|
53
|
+
let rejectOnAbort = () => {};
|
|
54
|
+
try {
|
|
55
|
+
const aborted = new Promise((_, reject) => {
|
|
56
|
+
rejectOnAbort = () => reject(controller.signal.reason);
|
|
57
|
+
controller.signal.addEventListener("abort", rejectOnAbort, { once: true });
|
|
58
|
+
});
|
|
59
|
+
if (controller.signal.aborted) {
|
|
60
|
+
throw controller.signal.reason;
|
|
61
|
+
}
|
|
62
|
+
return await Promise.race([operation(controller.signal), aborted]);
|
|
63
|
+
} finally {
|
|
64
|
+
clearTimeout(timer);
|
|
65
|
+
options.signal?.removeEventListener("abort", cancel);
|
|
66
|
+
controller.signal.removeEventListener("abort", rejectOnAbort);
|
|
67
|
+
}
|
|
68
|
+
}
|
|
69
|
+
|
|
70
|
+
// src/secrets/core.ts
|
|
71
|
+
var registryKey = Symbol.for("hanzio.secrets.environmentWrites.v1");
|
|
72
|
+
var shared = globalThis;
|
|
73
|
+
var environmentWrites = shared[registryKey] ?? new WeakMap;
|
|
74
|
+
shared[registryKey] = environmentWrites;
|
|
75
|
+
var defaultLogger = {
|
|
76
|
+
info: (message, attrs) => console.log(`${message} environment=${attrs.environment} count=${attrs.count} source=${attrs.source} durationMs=${attrs.durationMs}`, { sources: attrs.sources }),
|
|
77
|
+
error: (message, attrs) => console.error(message, attrs)
|
|
78
|
+
};
|
|
79
|
+
function readOverrides(keys, env) {
|
|
80
|
+
if (!env) {
|
|
81
|
+
return {};
|
|
82
|
+
}
|
|
83
|
+
const writes = environmentWrites.get(env);
|
|
84
|
+
return Object.fromEntries(keys.flatMap((key) => {
|
|
85
|
+
const value = Object.hasOwn(env, key) ? env[key] : undefined;
|
|
86
|
+
if (writes?.has(key)) {
|
|
87
|
+
if (writes.get(key) === value) {
|
|
88
|
+
return [];
|
|
89
|
+
}
|
|
90
|
+
writes.delete(key);
|
|
91
|
+
}
|
|
92
|
+
return value ? [[key, value]] : [];
|
|
93
|
+
}));
|
|
94
|
+
}
|
|
95
|
+
function createSecretSet2(keys, options, environmentVariables) {
|
|
96
|
+
const keySet = [...new Set(keys)];
|
|
97
|
+
let environment;
|
|
98
|
+
let initialized = false;
|
|
99
|
+
const logger = options.logger === false ? undefined : options.logger ?? defaultLogger;
|
|
100
|
+
let cached;
|
|
101
|
+
let parsed;
|
|
102
|
+
let sources;
|
|
103
|
+
let inFlight;
|
|
104
|
+
const log = (level, message, attributes) => {
|
|
105
|
+
try {
|
|
106
|
+
logger?.[level](message, attributes);
|
|
107
|
+
} catch {}
|
|
108
|
+
};
|
|
109
|
+
const loadSnapshot = async (request, signal, environment) => {
|
|
110
|
+
const local = readOverrides(keySet, environmentVariables);
|
|
111
|
+
const missing = keySet.filter((key) => !Object.hasOwn(local, key));
|
|
112
|
+
let loaderSource = options.loader.source ?? "custom loader";
|
|
113
|
+
let loaded = {};
|
|
114
|
+
if (missing.length) {
|
|
115
|
+
try {
|
|
116
|
+
loaded = await options.loader({
|
|
117
|
+
keys: missing,
|
|
118
|
+
environment,
|
|
119
|
+
signal,
|
|
120
|
+
timeoutMs: request.timeoutMs ?? options.timeoutMs ?? 30000,
|
|
121
|
+
reportSource: (source) => {
|
|
122
|
+
loaderSource = source;
|
|
123
|
+
}
|
|
124
|
+
});
|
|
125
|
+
} catch (error) {
|
|
126
|
+
if (error instanceof SecretLoadError2) {
|
|
127
|
+
throw error;
|
|
128
|
+
}
|
|
129
|
+
throw new SecretLoadError2("LOADER", "Secret loader failed.");
|
|
130
|
+
}
|
|
131
|
+
}
|
|
132
|
+
const overrides = readOverrides(keySet, environmentVariables);
|
|
133
|
+
const next = Object.fromEntries(keySet.map((key) => {
|
|
134
|
+
if (Object.hasOwn(overrides, key)) {
|
|
135
|
+
return [key, overrides[key]];
|
|
136
|
+
}
|
|
137
|
+
if (Object.hasOwn(loaded, key)) {
|
|
138
|
+
return [key, loaded[key]];
|
|
139
|
+
}
|
|
140
|
+
return [key, undefined];
|
|
141
|
+
}));
|
|
142
|
+
const missingKeys = keySet.filter((key) => typeof next[key] !== "string" || !next[key]);
|
|
143
|
+
if (missingKeys.length) {
|
|
144
|
+
throw new SecretLoadError2("MISSING_SECRETS", `Missing secrets: ${missingKeys.join(", ")}`);
|
|
145
|
+
}
|
|
146
|
+
let nextParsed;
|
|
147
|
+
try {
|
|
148
|
+
nextParsed = options.schema ? await options.schema.parseAsync({ ...next }) : { ...next };
|
|
149
|
+
nextParsed = structuredClone(nextParsed);
|
|
150
|
+
} catch {
|
|
151
|
+
throw new SecretLoadError2("VALIDATION", "Secret schema validation failed. Check the configured schema; values are omitted.");
|
|
152
|
+
}
|
|
153
|
+
signal.throwIfAborted();
|
|
154
|
+
const nextSources = Object.fromEntries(keySet.map((key) => [
|
|
155
|
+
key,
|
|
156
|
+
Object.hasOwn(overrides, key) ? "process.env" : loaderSource
|
|
157
|
+
]));
|
|
158
|
+
if (options.writeToProcessEnv !== false && environmentVariables) {
|
|
159
|
+
let writes = environmentWrites.get(environmentVariables);
|
|
160
|
+
if (!writes) {
|
|
161
|
+
writes = new Map;
|
|
162
|
+
environmentWrites.set(environmentVariables, writes);
|
|
163
|
+
}
|
|
164
|
+
for (const key of keySet) {
|
|
165
|
+
if (Object.hasOwn(overrides, key)) {
|
|
166
|
+
continue;
|
|
167
|
+
}
|
|
168
|
+
environmentVariables[key] = next[key];
|
|
169
|
+
writes.set(key, next[key]);
|
|
170
|
+
}
|
|
171
|
+
}
|
|
172
|
+
cached = next;
|
|
173
|
+
parsed = nextParsed;
|
|
174
|
+
sources = nextSources;
|
|
175
|
+
initialized = true;
|
|
176
|
+
};
|
|
177
|
+
const load = (request = {}) => {
|
|
178
|
+
if (inFlight) {
|
|
179
|
+
return inFlight;
|
|
180
|
+
}
|
|
181
|
+
inFlight = (async () => {
|
|
182
|
+
const start = Date.now();
|
|
183
|
+
try {
|
|
184
|
+
environment ??= resolveSecretEnvironment(options.environment, environmentVariables);
|
|
185
|
+
const resolvedEnvironment = environment;
|
|
186
|
+
await withSecretDeadline({
|
|
187
|
+
timeoutMs: request.timeoutMs ?? options.timeoutMs,
|
|
188
|
+
signal: request.signal ?? options.signal
|
|
189
|
+
}, (signal) => loadSnapshot(request, signal, resolvedEnvironment));
|
|
190
|
+
const sourceCounts = new Map;
|
|
191
|
+
for (const key of keySet) {
|
|
192
|
+
const source = sources[key];
|
|
193
|
+
sourceCounts.set(source, (sourceCounts.get(source) ?? 0) + 1);
|
|
194
|
+
}
|
|
195
|
+
const counts = Object.fromEntries(sourceCounts);
|
|
196
|
+
log("info", "Loaded secrets", {
|
|
197
|
+
environment: resolvedEnvironment,
|
|
198
|
+
count: keySet.length,
|
|
199
|
+
durationMs: Date.now() - start,
|
|
200
|
+
source: Object.keys(counts).join(" + ") || "none",
|
|
201
|
+
sources: counts
|
|
202
|
+
});
|
|
203
|
+
} catch (error) {
|
|
204
|
+
const safe = error instanceof SecretLoadError2 ? error : new SecretLoadError2("LOADER", "Secret loading failed.");
|
|
205
|
+
log("error", "Secret loading failed", {
|
|
206
|
+
environment: environment ?? "unresolved",
|
|
207
|
+
count: keySet.length,
|
|
208
|
+
durationMs: Date.now() - start,
|
|
209
|
+
code: safe.code
|
|
210
|
+
});
|
|
211
|
+
throw safe;
|
|
212
|
+
}
|
|
213
|
+
})().finally(() => {
|
|
214
|
+
inFlight = undefined;
|
|
215
|
+
});
|
|
216
|
+
return inFlight;
|
|
217
|
+
};
|
|
218
|
+
const assertLoaded = () => {
|
|
219
|
+
if (!initialized) {
|
|
220
|
+
throw new SecretLoadError2("CONFIGURATION", "Secret set has not been loaded. Await load() before reading values.");
|
|
221
|
+
}
|
|
222
|
+
};
|
|
223
|
+
const secretSet = {
|
|
224
|
+
secret(key) {
|
|
225
|
+
assertLoaded();
|
|
226
|
+
if (!Object.hasOwn(cached, key)) {
|
|
227
|
+
throw new SecretLoadError2("MISSING_SECRETS", `Secret ${key} not found`);
|
|
228
|
+
}
|
|
229
|
+
return cached[key];
|
|
230
|
+
},
|
|
231
|
+
secrets() {
|
|
232
|
+
assertLoaded();
|
|
233
|
+
return { ...cached };
|
|
234
|
+
},
|
|
235
|
+
parsed() {
|
|
236
|
+
assertLoaded();
|
|
237
|
+
return structuredClone(parsed);
|
|
238
|
+
},
|
|
239
|
+
sources() {
|
|
240
|
+
assertLoaded();
|
|
241
|
+
return { ...sources };
|
|
242
|
+
},
|
|
243
|
+
async load(request) {
|
|
244
|
+
if (!initialized) {
|
|
245
|
+
await load(request);
|
|
246
|
+
}
|
|
247
|
+
return secretSet;
|
|
248
|
+
},
|
|
249
|
+
async reload(request) {
|
|
250
|
+
await load(request);
|
|
251
|
+
return secretSet;
|
|
252
|
+
}
|
|
253
|
+
};
|
|
254
|
+
return secretSet;
|
|
255
|
+
}
|
|
256
|
+
async function defineSecretSet2(keys, options, environmentVariables) {
|
|
257
|
+
return createSecretSet2(keys, options, environmentVariables).load();
|
|
258
|
+
}
|
|
259
|
+
|
|
260
|
+
// src/secrets/worker-loader.ts
|
|
261
|
+
function cloudflareWorkerEnvLoader2(workerEnv) {
|
|
262
|
+
const loader = async (ctx) => {
|
|
263
|
+
const out = Object.create(null);
|
|
264
|
+
for (const key of ctx.keys) {
|
|
265
|
+
const str = workerBindingToString(Object.hasOwn(workerEnv, key) ? workerEnv[key] : undefined);
|
|
266
|
+
if (str !== undefined) {
|
|
267
|
+
out[key] = str;
|
|
268
|
+
}
|
|
269
|
+
}
|
|
270
|
+
return out;
|
|
271
|
+
};
|
|
272
|
+
return Object.assign(loader, { source: "Cloudflare Worker bindings" });
|
|
273
|
+
}
|
|
274
|
+
function workerBindingToString(value) {
|
|
275
|
+
if (value === undefined || value === null) {
|
|
276
|
+
return;
|
|
277
|
+
}
|
|
278
|
+
if (typeof value === "string") {
|
|
279
|
+
return value === "" ? undefined : value;
|
|
280
|
+
}
|
|
281
|
+
if (typeof value === "number" || typeof value === "boolean" || typeof value === "bigint") {
|
|
282
|
+
return String(value);
|
|
283
|
+
}
|
|
284
|
+
if (typeof value === "object") {
|
|
285
|
+
return JSON.stringify(value);
|
|
286
|
+
}
|
|
287
|
+
return String(value);
|
|
288
|
+
}
|
|
289
|
+
|
|
290
|
+
export { withSecretDeadline, getProcessEnvironment, resolveSecretEnvironment, createSecretSet2, defineSecretSet2, cloudflareWorkerEnvLoader2 };
|