@ginimessersmith/env-cast 1.0.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.
- package/LICENSE +21 -0
- package/README.md +1 -0
- package/dist/index.d.mts +62 -0
- package/dist/index.d.ts +62 -0
- package/dist/index.js +2 -0
- package/dist/index.js.map +1 -0
- package/dist/index.mjs +2 -0
- package/dist/index.mjs.map +1 -0
- package/package.json +44 -0
package/LICENSE
ADDED
|
@@ -0,0 +1,21 @@
|
|
|
1
|
+
MIT License
|
|
2
|
+
|
|
3
|
+
Copyright (c) 2026 Gino Baptista
|
|
4
|
+
|
|
5
|
+
Permission is hereby granted, free of charge, to any person obtaining a copy
|
|
6
|
+
of this software and associated documentation files (the "Software"), to deal
|
|
7
|
+
in the Software without restriction, including without limitation the rights
|
|
8
|
+
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
|
9
|
+
copies of the Software, and to permit persons to whom the Software is
|
|
10
|
+
furnished to do so, subject to the following conditions:
|
|
11
|
+
|
|
12
|
+
The above copyright notice and this permission notice shall be included in all
|
|
13
|
+
copies or substantial portions of the Software.
|
|
14
|
+
|
|
15
|
+
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
|
16
|
+
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
|
17
|
+
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
|
18
|
+
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
|
19
|
+
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
|
20
|
+
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
|
|
21
|
+
SOFTWARE.
|
package/README.md
ADDED
|
@@ -0,0 +1 @@
|
|
|
1
|
+
# env-cast
|
package/dist/index.d.mts
ADDED
|
@@ -0,0 +1,62 @@
|
|
|
1
|
+
interface BaseSchema {
|
|
2
|
+
required?: boolean;
|
|
3
|
+
}
|
|
4
|
+
interface StringSchema extends BaseSchema {
|
|
5
|
+
type: 'string';
|
|
6
|
+
/** The default value to use if the environment variable is not set. */
|
|
7
|
+
default?: string;
|
|
8
|
+
/** The minimum allowed length of the string. Cannot be negative. */
|
|
9
|
+
minLength?: number;
|
|
10
|
+
/** The maximum allowed length of the string. Cannot be negative. */
|
|
11
|
+
maxLength?: number;
|
|
12
|
+
}
|
|
13
|
+
interface NumberSchema extends BaseSchema {
|
|
14
|
+
type: 'number';
|
|
15
|
+
/** The default value to use if the environment variable is not set. */
|
|
16
|
+
default?: number;
|
|
17
|
+
/** The minimum allowed mathematical value. */
|
|
18
|
+
min?: number;
|
|
19
|
+
/** The maximum allowed mathematical value. */
|
|
20
|
+
max?: number;
|
|
21
|
+
}
|
|
22
|
+
interface BooleanSchema extends BaseSchema {
|
|
23
|
+
type: "boolean";
|
|
24
|
+
/** The default value to use if the environment variable is not set. */
|
|
25
|
+
default?: boolean;
|
|
26
|
+
}
|
|
27
|
+
interface JsonSchema extends BaseSchema {
|
|
28
|
+
type: "json";
|
|
29
|
+
default?: unknown;
|
|
30
|
+
}
|
|
31
|
+
type SchemaItem = StringSchema | NumberSchema | BooleanSchema | JsonSchema;
|
|
32
|
+
type EnvSchema = Record<string, SchemaItem>;
|
|
33
|
+
type IsGuaranteed<T extends SchemaItem> = T["required"] extends true ? true : "default" extends keyof T ? true : false;
|
|
34
|
+
type ResolveType<T extends SchemaItem> = T extends {
|
|
35
|
+
type: "number";
|
|
36
|
+
} ? number : T extends {
|
|
37
|
+
type: "boolean";
|
|
38
|
+
} ? boolean : T extends {
|
|
39
|
+
type: "json";
|
|
40
|
+
} ? any : string;
|
|
41
|
+
type InferEnv<T extends EnvSchema> = {
|
|
42
|
+
[K in keyof T]: IsGuaranteed<T[K]> extends true ? ResolveType<T[K]> : ResolveType<T[K]> | undefined;
|
|
43
|
+
};
|
|
44
|
+
|
|
45
|
+
/**
|
|
46
|
+
* Custom error class thrown by EnvCast when a validation or configuration fails.
|
|
47
|
+
*/
|
|
48
|
+
declare class EnvCastError extends Error {
|
|
49
|
+
readonly variable: string;
|
|
50
|
+
constructor(variable: string, message: string);
|
|
51
|
+
}
|
|
52
|
+
|
|
53
|
+
/**
|
|
54
|
+
* Creates a strictly typed environment object based on the provided schema.
|
|
55
|
+
* * 🧙♂️ Crafted with precision by @ginimessersmith
|
|
56
|
+
* @param schema The validation and casting schema.
|
|
57
|
+
* @param source The source object to read variables from (defaults to process.env).
|
|
58
|
+
* @returns A strictly typed object with the parsed environment variables.
|
|
59
|
+
*/
|
|
60
|
+
declare function createEnv<T extends EnvSchema>(schema: T, source?: Record<string, string | undefined>): InferEnv<T>;
|
|
61
|
+
|
|
62
|
+
export { EnvCastError, type EnvSchema, type InferEnv, createEnv };
|
package/dist/index.d.ts
ADDED
|
@@ -0,0 +1,62 @@
|
|
|
1
|
+
interface BaseSchema {
|
|
2
|
+
required?: boolean;
|
|
3
|
+
}
|
|
4
|
+
interface StringSchema extends BaseSchema {
|
|
5
|
+
type: 'string';
|
|
6
|
+
/** The default value to use if the environment variable is not set. */
|
|
7
|
+
default?: string;
|
|
8
|
+
/** The minimum allowed length of the string. Cannot be negative. */
|
|
9
|
+
minLength?: number;
|
|
10
|
+
/** The maximum allowed length of the string. Cannot be negative. */
|
|
11
|
+
maxLength?: number;
|
|
12
|
+
}
|
|
13
|
+
interface NumberSchema extends BaseSchema {
|
|
14
|
+
type: 'number';
|
|
15
|
+
/** The default value to use if the environment variable is not set. */
|
|
16
|
+
default?: number;
|
|
17
|
+
/** The minimum allowed mathematical value. */
|
|
18
|
+
min?: number;
|
|
19
|
+
/** The maximum allowed mathematical value. */
|
|
20
|
+
max?: number;
|
|
21
|
+
}
|
|
22
|
+
interface BooleanSchema extends BaseSchema {
|
|
23
|
+
type: "boolean";
|
|
24
|
+
/** The default value to use if the environment variable is not set. */
|
|
25
|
+
default?: boolean;
|
|
26
|
+
}
|
|
27
|
+
interface JsonSchema extends BaseSchema {
|
|
28
|
+
type: "json";
|
|
29
|
+
default?: unknown;
|
|
30
|
+
}
|
|
31
|
+
type SchemaItem = StringSchema | NumberSchema | BooleanSchema | JsonSchema;
|
|
32
|
+
type EnvSchema = Record<string, SchemaItem>;
|
|
33
|
+
type IsGuaranteed<T extends SchemaItem> = T["required"] extends true ? true : "default" extends keyof T ? true : false;
|
|
34
|
+
type ResolveType<T extends SchemaItem> = T extends {
|
|
35
|
+
type: "number";
|
|
36
|
+
} ? number : T extends {
|
|
37
|
+
type: "boolean";
|
|
38
|
+
} ? boolean : T extends {
|
|
39
|
+
type: "json";
|
|
40
|
+
} ? any : string;
|
|
41
|
+
type InferEnv<T extends EnvSchema> = {
|
|
42
|
+
[K in keyof T]: IsGuaranteed<T[K]> extends true ? ResolveType<T[K]> : ResolveType<T[K]> | undefined;
|
|
43
|
+
};
|
|
44
|
+
|
|
45
|
+
/**
|
|
46
|
+
* Custom error class thrown by EnvCast when a validation or configuration fails.
|
|
47
|
+
*/
|
|
48
|
+
declare class EnvCastError extends Error {
|
|
49
|
+
readonly variable: string;
|
|
50
|
+
constructor(variable: string, message: string);
|
|
51
|
+
}
|
|
52
|
+
|
|
53
|
+
/**
|
|
54
|
+
* Creates a strictly typed environment object based on the provided schema.
|
|
55
|
+
* * 🧙♂️ Crafted with precision by @ginimessersmith
|
|
56
|
+
* @param schema The validation and casting schema.
|
|
57
|
+
* @param source The source object to read variables from (defaults to process.env).
|
|
58
|
+
* @returns A strictly typed object with the parsed environment variables.
|
|
59
|
+
*/
|
|
60
|
+
declare function createEnv<T extends EnvSchema>(schema: T, source?: Record<string, string | undefined>): InferEnv<T>;
|
|
61
|
+
|
|
62
|
+
export { EnvCastError, type EnvSchema, type InferEnv, createEnv };
|
package/dist/index.js
ADDED
|
@@ -0,0 +1,2 @@
|
|
|
1
|
+
'use strict';var i=class r extends Error{variable;constructor(t,n){let e=t==="GINIMESSERSMITH"?"[EnvCast] Easter Egg unlocked! My creator @ginimessersmith says hi. ":`[EnvCast] Error in variable '${t}': `;super(`${e}${n}`),this.name="EnvCastError",this.variable=t,Error.captureStackTrace&&Error.captureStackTrace(this,r);}};function s(r,t,n){if(n.minLength!==void 0&&n.minLength<=0)throw new i(r,"Configuration error: 'minLength' cannot be negative or zero.");if(n.maxLength!==void 0&&n.maxLength<=0)throw new i(r,"Configuration error: 'maxLength' cannot be negative or zero.");if(n.minLength!==void 0&&n.maxLength!==void 0&&n.minLength>n.maxLength)throw new i(r,"Configuration error: 'minLength' cannot be greater than 'maxLength'.");if(n.minLength!==void 0&&t.length<n.minLength)throw new i(r,`Length must be at least ${n.minLength} characters.`);if(n.maxLength!==void 0&&t.length>n.maxLength)throw new i(r,`Length must not exceed ${n.maxLength} characters.`);return t}function u(r,t,n){let e=Number(t);if(Number.isNaN(e))throw new i(r,`Must be a valid number. Received: '${t}'`);if(n.min!==void 0&&n.max!==void 0&&n.min>n.max)throw new i(r,"Configuration error: 'min' cannot be greater than 'max'.");if(n.min!==void 0&&e<n.min)throw new i(r,`Must be greater than or equal to ${n.min}.`);if(n.max!==void 0&&e>n.max)throw new i(r,`Must be less than or equal to ${n.max}.`);return e}function f(r,t){let n=t.toLowerCase().trim();if(n==="true"||n==="1")return true;if(n==="false"||n==="0")return false;throw new i(r,`Must be a boolean ('true', 'false', '1', '0'). Received: '${t}'`)}function g(r,t){try{return JSON.parse(t)}catch{throw new i(r,`Must be a valid JSON string. Received: '${t}'`)}}function w(r,t=process.env){let n={};for(let e in r){if(!Object.prototype.hasOwnProperty.call(r,e))continue;let o=r[e],a=t[e];if(a===void 0||a===""){if(o?.required)throw new i(e,"Missing required environment variable.");o?.default!==void 0&&(n[e]=o.default);continue}switch(o?.type){case "string":n[e]=s(e,a,o);break;case "number":n[e]=u(e,a,o);break;case "boolean":n[e]=f(e,a);break;case "json":n[e]=g(e,a);break;default:throw new i(e,"Unknown schema type.")}}return n}exports.EnvCastError=i;exports.createEnv=w;//# sourceMappingURL=index.js.map
|
|
2
|
+
//# sourceMappingURL=index.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"sources":["../src/errors.ts","../src/parser.ts","../src/index.ts"],"names":["EnvCastError","_EnvCastError","variable","message","prefix","parseString","key","value","schema","parseNumber","parsed","parseBoolean","normalizedValue","parseJson","createEnv","source","result","spec","rawValue"],"mappings":"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","file":"index.js","sourcesContent":["/**\r\n * Custom error class thrown by EnvCast when a validation or configuration fails.\r\n */\r\nexport class EnvCastError extends Error {\r\n public readonly variable: string;\r\n\r\n constructor(variable: string, message: string) {\r\n const prefix = variable === 'GINIMESSERSMITH'\r\n ? `[EnvCast] Easter Egg unlocked! My creator @ginimessersmith says hi. `\r\n : `[EnvCast] Error in variable '${variable}': `;\r\n\r\n super(`${prefix}${message}`);\r\n \r\n this.name = 'EnvCastError';\r\n this.variable = variable;\r\n \r\n if (Error.captureStackTrace) {\r\n Error.captureStackTrace(this, EnvCastError);\r\n }\r\n }\r\n}","import { EnvCastError } from \"./errors\";\r\nimport type {\r\n StringSchema,\r\n NumberSchema,\r\n} from \"./types\";\r\n\r\nexport function parseString(\r\n key: string,\r\n value: string,\r\n schema: StringSchema,\r\n): string {\r\n if (schema.minLength !== undefined && schema.minLength <= 0) {\r\n throw new EnvCastError(key, `Configuration error: 'minLength' cannot be negative or zero.`);\r\n }\r\n \r\n if (schema.maxLength !== undefined && schema.maxLength <= 0) {\r\n throw new EnvCastError(key, `Configuration error: 'maxLength' cannot be negative or zero.`);\r\n }\r\n\r\n if (schema.minLength !== undefined && schema.maxLength !== undefined && schema.minLength > schema.maxLength) {\r\n throw new EnvCastError(key, `Configuration error: 'minLength' cannot be greater than 'maxLength'.`);\r\n }\r\n\r\n if (schema.minLength !== undefined && value.length < schema.minLength) {\r\n throw new EnvCastError(key, `Length must be at least ${schema.minLength} characters.`);\r\n }\r\n \r\n if (schema.maxLength !== undefined && value.length > schema.maxLength) {\r\n throw new EnvCastError(key, `Length must not exceed ${schema.maxLength} characters.`);\r\n }\r\n\r\n return value;\r\n}\r\n\r\nexport function parseNumber(\r\n key: string,\r\n value: string,\r\n schema: NumberSchema,\r\n): number {\r\n const parsed = Number(value);\r\n\r\n if (Number.isNaN(parsed)) {\r\n throw new EnvCastError(key, `Must be a valid number. Received: '${value}'`);\r\n }\r\n\r\n if (schema.min !== undefined && schema.max !== undefined && schema.min > schema.max) {\r\n throw new EnvCastError(key, `Configuration error: 'min' cannot be greater than 'max'.`);\r\n }\r\n\r\n if (schema.min !== undefined && parsed < schema.min) {\r\n throw new EnvCastError(key, `Must be greater than or equal to ${schema.min}.`);\r\n }\r\n\r\n if (schema.max !== undefined && parsed > schema.max) {\r\n throw new EnvCastError(key, `Must be less than or equal to ${schema.max}.`);\r\n }\r\n\r\n return parsed;\r\n}\r\n\r\nexport function parseBoolean(key: string, value: string): boolean {\r\n const normalizedValue = value.toLowerCase().trim();\r\n\r\n if (normalizedValue === \"true\" || normalizedValue === \"1\") {\r\n return true;\r\n }\r\n\r\n if (normalizedValue === \"false\" || normalizedValue === \"0\") {\r\n return false;\r\n }\r\n\r\n throw new EnvCastError(\r\n key,\r\n `Must be a boolean ('true', 'false', '1', '0'). Received: '${value}'`,\r\n );\r\n}\r\n\r\nexport function parseJson(key: string, value: string): unknown {\r\n try {\r\n return JSON.parse(value);\r\n } catch (error) {\r\n throw new EnvCastError(\r\n key,\r\n `Must be a valid JSON string. Received: '${value}'`,\r\n );\r\n }\r\n}\r\n","import { EnvCastError } from './errors';\r\nimport { parseString, parseNumber, parseBoolean, parseJson } from './parser';\r\nimport type { EnvSchema, InferEnv } from './types';\r\nexport type { EnvSchema, InferEnv } from './types';\r\nexport { EnvCastError } from './errors';\r\n\r\n/**\r\n * Creates a strictly typed environment object based on the provided schema.\r\n * * 🧙♂️ Crafted with precision by @ginimessersmith\r\n * @param schema The validation and casting schema.\r\n * @param source The source object to read variables from (defaults to process.env).\r\n * @returns A strictly typed object with the parsed environment variables.\r\n */\r\nexport function createEnv<T extends EnvSchema>(\r\n schema: T,\r\n source: Record<string, string | undefined> = process.env\r\n): InferEnv<T> {\r\n const result: any = {};\r\n\r\n for (const key in schema) {\r\n if (!Object.prototype.hasOwnProperty.call(schema, key)) continue;\r\n\r\n const spec = schema[key];\r\n const rawValue = source[key];\r\n\r\n if (rawValue === undefined || rawValue === '') {\r\n if (spec?.required) {\r\n throw new EnvCastError(key, 'Missing required environment variable.');\r\n }\r\n \r\n if (spec?.default !== undefined) {\r\n result[key] = spec.default;\r\n }\r\n continue;\r\n }\r\n\r\n switch (spec?.type) {\r\n case 'string':\r\n result[key] = parseString(key, rawValue, spec);\r\n break;\r\n case 'number':\r\n result[key] = parseNumber(key, rawValue, spec);\r\n break;\r\n case 'boolean':\r\n result[key] = parseBoolean(key, rawValue);\r\n break;\r\n case 'json':\r\n result[key] = parseJson(key, rawValue);\r\n break;\r\n default:\r\n throw new EnvCastError(key, `Unknown schema type.`);\r\n }\r\n }\r\n\r\n return result as InferEnv<T>;\r\n}"]}
|
package/dist/index.mjs
ADDED
|
@@ -0,0 +1,2 @@
|
|
|
1
|
+
var i=class r extends Error{variable;constructor(t,n){let e=t==="GINIMESSERSMITH"?"[EnvCast] Easter Egg unlocked! My creator @ginimessersmith says hi. ":`[EnvCast] Error in variable '${t}': `;super(`${e}${n}`),this.name="EnvCastError",this.variable=t,Error.captureStackTrace&&Error.captureStackTrace(this,r);}};function s(r,t,n){if(n.minLength!==void 0&&n.minLength<=0)throw new i(r,"Configuration error: 'minLength' cannot be negative or zero.");if(n.maxLength!==void 0&&n.maxLength<=0)throw new i(r,"Configuration error: 'maxLength' cannot be negative or zero.");if(n.minLength!==void 0&&n.maxLength!==void 0&&n.minLength>n.maxLength)throw new i(r,"Configuration error: 'minLength' cannot be greater than 'maxLength'.");if(n.minLength!==void 0&&t.length<n.minLength)throw new i(r,`Length must be at least ${n.minLength} characters.`);if(n.maxLength!==void 0&&t.length>n.maxLength)throw new i(r,`Length must not exceed ${n.maxLength} characters.`);return t}function u(r,t,n){let e=Number(t);if(Number.isNaN(e))throw new i(r,`Must be a valid number. Received: '${t}'`);if(n.min!==void 0&&n.max!==void 0&&n.min>n.max)throw new i(r,"Configuration error: 'min' cannot be greater than 'max'.");if(n.min!==void 0&&e<n.min)throw new i(r,`Must be greater than or equal to ${n.min}.`);if(n.max!==void 0&&e>n.max)throw new i(r,`Must be less than or equal to ${n.max}.`);return e}function f(r,t){let n=t.toLowerCase().trim();if(n==="true"||n==="1")return true;if(n==="false"||n==="0")return false;throw new i(r,`Must be a boolean ('true', 'false', '1', '0'). Received: '${t}'`)}function g(r,t){try{return JSON.parse(t)}catch{throw new i(r,`Must be a valid JSON string. Received: '${t}'`)}}function w(r,t=process.env){let n={};for(let e in r){if(!Object.prototype.hasOwnProperty.call(r,e))continue;let o=r[e],a=t[e];if(a===void 0||a===""){if(o?.required)throw new i(e,"Missing required environment variable.");o?.default!==void 0&&(n[e]=o.default);continue}switch(o?.type){case "string":n[e]=s(e,a,o);break;case "number":n[e]=u(e,a,o);break;case "boolean":n[e]=f(e,a);break;case "json":n[e]=g(e,a);break;default:throw new i(e,"Unknown schema type.")}}return n}export{i as EnvCastError,w as createEnv};//# sourceMappingURL=index.mjs.map
|
|
2
|
+
//# sourceMappingURL=index.mjs.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"sources":["../src/errors.ts","../src/parser.ts","../src/index.ts"],"names":["EnvCastError","_EnvCastError","variable","message","prefix","parseString","key","value","schema","parseNumber","parsed","parseBoolean","normalizedValue","parseJson","createEnv","source","result","spec","rawValue"],"mappings":"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","file":"index.mjs","sourcesContent":["/**\r\n * Custom error class thrown by EnvCast when a validation or configuration fails.\r\n */\r\nexport class EnvCastError extends Error {\r\n public readonly variable: string;\r\n\r\n constructor(variable: string, message: string) {\r\n const prefix = variable === 'GINIMESSERSMITH'\r\n ? `[EnvCast] Easter Egg unlocked! My creator @ginimessersmith says hi. `\r\n : `[EnvCast] Error in variable '${variable}': `;\r\n\r\n super(`${prefix}${message}`);\r\n \r\n this.name = 'EnvCastError';\r\n this.variable = variable;\r\n \r\n if (Error.captureStackTrace) {\r\n Error.captureStackTrace(this, EnvCastError);\r\n }\r\n }\r\n}","import { EnvCastError } from \"./errors\";\r\nimport type {\r\n StringSchema,\r\n NumberSchema,\r\n} from \"./types\";\r\n\r\nexport function parseString(\r\n key: string,\r\n value: string,\r\n schema: StringSchema,\r\n): string {\r\n if (schema.minLength !== undefined && schema.minLength <= 0) {\r\n throw new EnvCastError(key, `Configuration error: 'minLength' cannot be negative or zero.`);\r\n }\r\n \r\n if (schema.maxLength !== undefined && schema.maxLength <= 0) {\r\n throw new EnvCastError(key, `Configuration error: 'maxLength' cannot be negative or zero.`);\r\n }\r\n\r\n if (schema.minLength !== undefined && schema.maxLength !== undefined && schema.minLength > schema.maxLength) {\r\n throw new EnvCastError(key, `Configuration error: 'minLength' cannot be greater than 'maxLength'.`);\r\n }\r\n\r\n if (schema.minLength !== undefined && value.length < schema.minLength) {\r\n throw new EnvCastError(key, `Length must be at least ${schema.minLength} characters.`);\r\n }\r\n \r\n if (schema.maxLength !== undefined && value.length > schema.maxLength) {\r\n throw new EnvCastError(key, `Length must not exceed ${schema.maxLength} characters.`);\r\n }\r\n\r\n return value;\r\n}\r\n\r\nexport function parseNumber(\r\n key: string,\r\n value: string,\r\n schema: NumberSchema,\r\n): number {\r\n const parsed = Number(value);\r\n\r\n if (Number.isNaN(parsed)) {\r\n throw new EnvCastError(key, `Must be a valid number. Received: '${value}'`);\r\n }\r\n\r\n if (schema.min !== undefined && schema.max !== undefined && schema.min > schema.max) {\r\n throw new EnvCastError(key, `Configuration error: 'min' cannot be greater than 'max'.`);\r\n }\r\n\r\n if (schema.min !== undefined && parsed < schema.min) {\r\n throw new EnvCastError(key, `Must be greater than or equal to ${schema.min}.`);\r\n }\r\n\r\n if (schema.max !== undefined && parsed > schema.max) {\r\n throw new EnvCastError(key, `Must be less than or equal to ${schema.max}.`);\r\n }\r\n\r\n return parsed;\r\n}\r\n\r\nexport function parseBoolean(key: string, value: string): boolean {\r\n const normalizedValue = value.toLowerCase().trim();\r\n\r\n if (normalizedValue === \"true\" || normalizedValue === \"1\") {\r\n return true;\r\n }\r\n\r\n if (normalizedValue === \"false\" || normalizedValue === \"0\") {\r\n return false;\r\n }\r\n\r\n throw new EnvCastError(\r\n key,\r\n `Must be a boolean ('true', 'false', '1', '0'). Received: '${value}'`,\r\n );\r\n}\r\n\r\nexport function parseJson(key: string, value: string): unknown {\r\n try {\r\n return JSON.parse(value);\r\n } catch (error) {\r\n throw new EnvCastError(\r\n key,\r\n `Must be a valid JSON string. Received: '${value}'`,\r\n );\r\n }\r\n}\r\n","import { EnvCastError } from './errors';\r\nimport { parseString, parseNumber, parseBoolean, parseJson } from './parser';\r\nimport type { EnvSchema, InferEnv } from './types';\r\nexport type { EnvSchema, InferEnv } from './types';\r\nexport { EnvCastError } from './errors';\r\n\r\n/**\r\n * Creates a strictly typed environment object based on the provided schema.\r\n * * 🧙♂️ Crafted with precision by @ginimessersmith\r\n * @param schema The validation and casting schema.\r\n * @param source The source object to read variables from (defaults to process.env).\r\n * @returns A strictly typed object with the parsed environment variables.\r\n */\r\nexport function createEnv<T extends EnvSchema>(\r\n schema: T,\r\n source: Record<string, string | undefined> = process.env\r\n): InferEnv<T> {\r\n const result: any = {};\r\n\r\n for (const key in schema) {\r\n if (!Object.prototype.hasOwnProperty.call(schema, key)) continue;\r\n\r\n const spec = schema[key];\r\n const rawValue = source[key];\r\n\r\n if (rawValue === undefined || rawValue === '') {\r\n if (spec?.required) {\r\n throw new EnvCastError(key, 'Missing required environment variable.');\r\n }\r\n \r\n if (spec?.default !== undefined) {\r\n result[key] = spec.default;\r\n }\r\n continue;\r\n }\r\n\r\n switch (spec?.type) {\r\n case 'string':\r\n result[key] = parseString(key, rawValue, spec);\r\n break;\r\n case 'number':\r\n result[key] = parseNumber(key, rawValue, spec);\r\n break;\r\n case 'boolean':\r\n result[key] = parseBoolean(key, rawValue);\r\n break;\r\n case 'json':\r\n result[key] = parseJson(key, rawValue);\r\n break;\r\n default:\r\n throw new EnvCastError(key, `Unknown schema type.`);\r\n }\r\n }\r\n\r\n return result as InferEnv<T>;\r\n}"]}
|
package/package.json
ADDED
|
@@ -0,0 +1,44 @@
|
|
|
1
|
+
{
|
|
2
|
+
"name": "@ginimessersmith/env-cast",
|
|
3
|
+
"version": "1.0.1",
|
|
4
|
+
"description": "Zero-dependency, strictly typed environment variable parser and validator.",
|
|
5
|
+
"main": "./dist/index.js",
|
|
6
|
+
"module": "./dist/index.mjs",
|
|
7
|
+
"types": "./dist/index.d.ts",
|
|
8
|
+
"exports": {
|
|
9
|
+
".": {
|
|
10
|
+
"import": "./dist/index.mjs",
|
|
11
|
+
"require": "./dist/index.js",
|
|
12
|
+
"types": "./dist/index.d.ts"
|
|
13
|
+
}
|
|
14
|
+
},
|
|
15
|
+
"files": [
|
|
16
|
+
"dist"
|
|
17
|
+
],
|
|
18
|
+
"engines": {
|
|
19
|
+
"node": ">=16.0.0"
|
|
20
|
+
},
|
|
21
|
+
"scripts": {
|
|
22
|
+
"build": "tsup",
|
|
23
|
+
"dev": "tsup --watch",
|
|
24
|
+
"test": "vitest run",
|
|
25
|
+
"test:watch": "vitest"
|
|
26
|
+
},
|
|
27
|
+
"keywords": [
|
|
28
|
+
"env",
|
|
29
|
+
"environment",
|
|
30
|
+
"validation",
|
|
31
|
+
"typescript",
|
|
32
|
+
"zero-dependency",
|
|
33
|
+
"typesafe"
|
|
34
|
+
],
|
|
35
|
+
"author": "ginimessersmith <hello</>ginobaptista@gmail.com> (https://github.com/ginimessersmith)",
|
|
36
|
+
"license": "MIT",
|
|
37
|
+
"devDependencies": {
|
|
38
|
+
"@changesets/cli": "^2.29.8",
|
|
39
|
+
"@types/node": "^25.2.3",
|
|
40
|
+
"tsup": "^8.5.1",
|
|
41
|
+
"typescript": "^5.9.3",
|
|
42
|
+
"vitest": "^4.0.18"
|
|
43
|
+
}
|
|
44
|
+
}
|