nuxt-safe-runtime-config
Version:
Validate Nuxt runtime config with Standard Schema at build time
51 lines (50 loc) • 2.19 kB
JavaScript
export const runtimeValidationContextKey = Symbol.for("nuxt-safe-runtime-config.validation-context");
function isRuntimeConfig(value) {
return !!value && typeof value === "object" && !Array.isArray(value);
}
export function mergeTransformedRuntimeConfig(current, transformed) {
if (!isRuntimeConfig(current) || !isRuntimeConfig(transformed))
return transformed;
const merged = { ...current };
for (const [key, value] of Object.entries(transformed))
merged[key] = mergeTransformedRuntimeConfig(current[key], value);
return merged;
}
const validationStoreKey = Symbol.for("nuxt-safe-runtime-config.validation-store");
const existingValidationStore = Reflect.get(globalThis, validationStoreKey);
const validationStore = existingValidationStore ?? { states: /* @__PURE__ */ new WeakMap() };
if (!existingValidationStore)
Reflect.set(globalThis, validationStoreKey, validationStore);
export function getRuntimeValidationState(config) {
return validationStore.states.get(config);
}
export function setRuntimeValidationState(config, state) {
validationStore.states.set(config, state);
}
export function applyValidatedRuntimeConfig(config, value) {
if (!isRuntimeConfig(value))
throw new TypeError("Runtime config schema output must be an object");
for (const [key, transformedValue] of Object.entries(value)) {
if (Object.hasOwn(config, key))
Reflect.set(config, key, mergeTransformedRuntimeConfig(config[key], transformedValue));
}
setRuntimeValidationState(config, { status: "valid", value });
}
export function useValidatedRuntimeConfig(config) {
const state = getRuntimeValidationState(config);
if (!state || state.status === "invalid")
return config;
if (state.status === "valid")
return state.value;
if (state.status === "failed")
throw state.error;
throw new Error("Runtime config validation is still pending");
}
export async function waitForRuntimeConfigValidation(config) {
const state = getRuntimeValidationState(config);
if (state?.status === "pending")
await state.ready;
const settledState = getRuntimeValidationState(config);
if (settledState?.status === "failed")
throw settledState.error;
}