UNPKG

@t3-oss/env-core

Version:

This is the framework agnostic core package of t3-env.

84 lines (82 loc) 3.01 kB
//#region src/standard.ts function ensureSynchronous(value, message) { if (value instanceof Promise) throw new Error(message); } function parseWithDictionary(dictionary, value) { const result = {}; const issues = []; for (const key in dictionary) { const propResult = dictionary[key]["~standard"].validate(value[key]); ensureSynchronous(propResult, `Validation must be synchronous, but ${key} returned a Promise.`); if (propResult.issues) { issues.push(...propResult.issues.map((issue) => ({ ...issue, message: issue.message, path: [key, ...issue.path ?? []] }))); continue; } result[key] = propResult.value; } if (issues.length) return { issues }; return { value: result }; } //#endregion //#region src/index.ts /** * Create a new environment variable schema. */ function createEnv(opts) { const runtimeEnv = opts.runtimeEnvStrict ?? opts.runtimeEnv ?? process.env; const emptyStringAsUndefined = opts.emptyStringAsUndefined ?? false; if (emptyStringAsUndefined) { for (const [key, value] of Object.entries(runtimeEnv)) if (value === "") delete runtimeEnv[key]; } const skip = !!opts.skipValidation; if (skip) return runtimeEnv; const _client = typeof opts.client === "object" ? opts.client : {}; const _server = typeof opts.server === "object" ? opts.server : {}; const _shared = typeof opts.shared === "object" ? opts.shared : {}; const isServer = opts.isServer ?? (typeof window === "undefined" || "Deno" in window); const finalSchemaShape = isServer ? { ..._server, ..._shared, ..._client } : { ..._client, ..._shared }; const parsed = opts.createFinalSchema?.(finalSchemaShape, isServer)["~standard"].validate(runtimeEnv) ?? parseWithDictionary(finalSchemaShape, runtimeEnv); ensureSynchronous(parsed, "Validation must be synchronous"); const onValidationError = opts.onValidationError ?? ((issues) => { console.error("❌ Invalid environment variables:", issues); throw new Error("Invalid environment variables"); }); const onInvalidAccess = opts.onInvalidAccess ?? (() => { throw new Error("❌ Attempted to access a server-side environment variable on the client"); }); if (parsed.issues) return onValidationError(parsed.issues); const isServerAccess = (prop) => { if (!opts.clientPrefix) return true; return !prop.startsWith(opts.clientPrefix) && !(prop in _shared); }; const isValidServerAccess = (prop) => { return isServer || !isServerAccess(prop); }; const ignoreProp = (prop) => { return prop === "__esModule" || prop === "$$typeof"; }; const extendedObj = (opts.extends ?? []).reduce((acc, curr) => { return Object.assign(acc, curr); }, {}); const fullObj = Object.assign(extendedObj, parsed.value); const env = new Proxy(fullObj, { get(target, prop) { if (typeof prop !== "string") return void 0; if (ignoreProp(prop)) return void 0; if (!isValidServerAccess(prop)) return onInvalidAccess(prop); return Reflect.get(target, prop); } }); return env; } //#endregion export { createEnv };