Class VariableRegistry<EnvReg, Var>

Registry for managing variable definitions across multiple environments.

The VariableRegistry provides a fluent API for defining variables and their resolution methods for different environments. It ensures type safety by preventing duplicate variable names and validating environment references.

const varReg = envReg.createVariableRegistry()
.addVar("DATABASE_URL", (v) => v
.for("local", "from-env")
.for("workflows", "from-github-secrets"))
.addVar("IS_WORKFLOW", (v) => v
.for("local", "hardcoded", "false")
.for("workflows", "hardcoded", "true"))
.addVar("DOCUMENT_BUCKET", (v) => v
.dynamicFor("local", "documentBucket"))

Type Parameters

Methods

  • Adds a new variable definition to the registry.

    This method ensures type safety by preventing duplicate variable names and validating that the variable is defined for valid environments.

    Type Parameters

    • Name extends string

      The name of the variable (must be uppercase)

    • DR extends DefinedResolution<
          EnvReg,
          GetEnvName<EnvReg>,
          DefinedResolutionType<EnvReg, GetEnvName<EnvReg>>,
      >

      The defined resolution type for this variable

    Parameters

    • name: RemoveLiteral<Name, Var["name"]>

      The unique name for this variable (must be uppercase)

    • f: (b: Variable<EnvReg, Name, never>) => Variable<EnvReg, Name, DR>

      Function that configures the variable with its environment definitions

    Returns VariableRegistry<EnvReg, Var | Variable<EnvReg, Name, DR>>

    A new VariableRegistry with the added variable

    const varReg = varReg
    .addVar("DATABASE_URL", (v) => v
    .for("local", "from-env")
    .for("workflows", "from-github-secrets"))
    .addVar("IS_WORKFLOW", (v) => v
    .for("local", "hardcoded", "false")
    .for("workflows", "hardcoded", "true"))
    .addVar("DOCUMENT_BUCKET", (v) => v
    .dynamicFor("local", "documentBucket"))
  • Merges this variable registry with another one.

    This method ensures type safety by preventing conflicts between variable names from both registries.

    Type Parameters

    • Name extends string

      The name of variables in the other registry

    • Var2 extends Variable<
          EnvReg,
          Name,
          DefinedResolution<
              EnvReg,
              GetEnvName<EnvReg>,
              DefinedResolutionType<EnvReg, GetEnvName<EnvReg>>,
          >,
      >

      The variable types from the other registry

    Parameters

    Returns VariableRegistry<EnvReg, Var | Var2>

    A new VariableRegistry with variables from both registries

    const openAIVarReg = envReg.createVariableRegistry()
    .addVar("OPENAI_API_KEY", (v) => v
    .for("workflows", "from-aws-secrets")
    .for("local", "from-env"))

    const globalVarReg = envReg.createVariableRegistry()
    .mergeWith(openAIVarReg)
    .addVar("DATABASE_URL", (v) => v
    .for("workflows", "from-github-secrets")
    .for("local", "from-env"))
  • Internal

    Creates a resolver for a specific environment.

    The resolver provides type-safe access to variable values for the specified environment. It automatically handles dynamic data requirements based on the variable definitions.

    Type Parameters

    • EnvName extends string

      The environment name to create a resolver for

    • DynamicData extends undefined | { [key in string]: string }

      The dynamic data type (inferred automatically)

    Parameters

    • envName: EnvName

      The name of the environment to create a resolver for

    • envData: Infer<GetEnv<EnvReg, EnvName>["resolutions"][number]["envDataType"]>

      The environment data for the target environment

    • ...args: OptionalIf<
          KeepIf<
              DynamicData,
              Extends<GetDynamicData<EnvReg, EnvName, Var>, DynamicData>,
          >,
          Extends<undefined, DynamicData>,
      >

      Dynamic data (optional, required only if variables use dynamic resolution)

    Returns Resolver<EnvReg, EnvName, Var>

    A Resolver instance for the specified environment

    const resolver = varReg.createResolver(
    "local",
    { env: { DATABASE_URL: "test" } },
    { documentBucket: "my document bucket name" }
    )

    // Get values
    const isWorkflow = resolver.get("IS_WORKFLOW") // "false"
    const dbUrl = resolver.get("DATABASE_URL") // "test"
    const bucket = resolver.get("DOCUMENT_BUCKET") // "my document bucket name"
  • Creates a resolver with dynamic environment selection at runtime.

    This method solves the TypeScript limitation where conditional resolver creation breaks type inference. Instead of creating resolvers conditionally, you provide all possible environment configurations upfront and select the environment at runtime.

    The resolver only allows access to variables that are defined in ALL possible environments to maintain type safety.

    Type Parameters

    • Defs extends {
          [EnvName in string]?: [
              Infer<GetEnv<EnvReg, EnvName>["resolutions"][number]["envDataType"]>,
              ...args: OptionalIf<
                  GetDynamicData<EnvReg, EnvName, Var>,
                  Extends<undefined, GetDynamicData<EnvReg, EnvName, Var>>,
              >[],
          ]
      }

      The environment definitions object type

    Parameters

    • definitions: Defs

      Object mapping environment names to their data configurations

    • fn: () => keyof Defs

      Function that returns the environment name to use at runtime

    Returns Resolver<EnvReg, EnvName, Var>

    A Resolver instance for the dynamically selected environment

    // Instead of this (which breaks type inference):
    // const resolver = condition ?
    // varReg.createResolver("env1", data1) :
    // varReg.createResolver("env2", data2)

    // Use this (maintains type safety):
    const resolver = varReg.createDynamicResolver({
    env1: [{ env: { DATABASE_URL: "dev" } }],
    env2: [{ env: { DATABASE_URL: "prod" } }]
    }, () => process.env.NODE_ENV === "production" ? "env2" : "env1")

    // Only variables defined in both environments are accessible
    const dbUrl = resolver.get("DATABASE_URL") // Type-safe access

    // With dynamic data:
    const resolver = varReg.createDynamicResolver({
    local: [{ env: {} }, { bucket: "dev-bucket" }],
    prod: [{ env: {} }, { bucket: "prod-bucket" }]
    }, () => process.env.NODE_ENV === "production" ? "prod" : "local")
  • Lists all variables that use a specific resolution tag in a given environment.

    This method filters variables based on their environment-specific resolution definitions and returns the names of variables that use the specified tag in their user-defined resolutions.

    Type Parameters

    • EnvName extends string

      The environment name to filter variables for

    • Tag extends string

      The resolution tag to filter by

    Parameters

    • envName: EnvName

      The name of the environment to check

    • tag: Tag

      The resolution tag to look for

    Returns Uppercase<string>[]

    An array of variable names that use the specified tag in the given environment

    // Get all variables that use "from-env" resolution in local environment
    const envVars = varReg.listVariables("local", "from-env")
    // ["DATABASE_URL", "API_KEY", ...]