npm package: @otterlyspace/env
Description: > [!WARNING] > This project is in early development. The API may change significantly before reaching a stable release and has not yet been extensively tested in production environments. > Use at your own risk. Please provide feedback and report issues to
Latest version: 1.0.1

# @otterlyspace/env

> [!WARNING]
> This project is in early development. The API may change significantly before reaching a stable release and has not yet been extensively tested in production environments.
> Use at your own risk. Please provide feedback and report issues to help us improve the library!

A type-safe environment variable manager for monorepos, heavily inspired by [t3-env](https://github.com/t3-oss/t3-env), built with [Standard Schema](https://standardschema.dev/) support.

## Features

- 🛡️ **Validator Agnostic**: Works with Zod, Valibot, Arktype, or any library supporting Standard Schema.
- 📦 **Monorepo Ready**: Share environment validation across packages with `isGlobalInstance` and `useGlobalInstance`.
- 🔒 **Security**: Prevents accidental exposure of server-side variables to the client.
- 🌐 **Universal**: Supports multiple client prefixes (e.g., `VITE_`, `EXPO_`).
- 🧩 **Presets**: Extend configurations easily.

## Installation

```bash
yarn add @otterlyspace/env
# Install your preferred Standard Schema-compatible validator (e.g., zod, valibot, arktype)
yarn add zod
```

## Usage

### 1. Define your environment (Main App)

In your main application (e.g., `apps/web/src/env.ts`), create the global environment instance.

```typescript
import { createEnv } from "@otterlyspace/env";
import { z } from "zod";

export const env = createEnv({
  server: {
    DATABASE_URL: z.string().url(),
    API_SECRET: z.string().min(1),
  },
  client: {
    VITE_PUBLIC_API_URL: z.string().url(),
  },
  // Variables starting with these prefixes are allowed on the client
  clientPrefix: "VITE_", 
  runtimeEnv: process.env,
  // Registers this as the source of truth for the monorepo
  isGlobalInstance: true, 
});
```

### Advanced Options

- **`skipValidation`**: Useful for CI/Docker builds where env vars might not be present.
- **`emptyStringAsUndefined`**: Treats empty strings as `undefined`.
- **`onValidationError`**: Custom error handler.

```typescript
const env = createEnv({
  // ...
  skipValidation: !!process.env.SKIP_ENV_VALIDATION,
  emptyStringAsUndefined: true,
  onValidationError: (error) => {
    console.error("❌ Invalid environment variables:", error.message);
    throw error;
  },
});
```

### 2. Use in Internal Packages

In your internal packages (e.g., `packages/ui/src/env.ts`), reuse the global instance.

```typescript
import { createEnv } from "@otterlyspace/env";
import { z } from "zod";

export const env = createEnv({
  // Define the subset of variables this package needs for type safety
  client: {
    VITE_PUBLIC_API_URL: z.string().url(),
  },
  clientPrefix: "VITE_",
  runtimeEnv: process.env,
  // Tries to use the already validated global instance
  useGlobalInstance: true, 
});
```

### 3. Access Variables

```typescript
import { env } from "./env";

console.log(env.VITE_PUBLIC_API_URL); // Type-safe access
```

## Development

### Setup

```bash
yarn install
```

### Testing

```bash
yarn test
```

### Building

```bash
yarn build
```

## License

MIT