# Bun

Using KeyEnv with Bun applications.

Source: https://keyenv.dev/docs/sdks/bun/

Load KeyEnv secrets in your Bun applications using the CLI or the Node.js SDK.

## Using the CLI (Recommended)

The simplest way to use KeyEnv with Bun is via the CLI's `run` command.

### Install the CLI

```bash
curl -fsSL https://keyenv.dev/install.sh | bash
```

### Configure package.json

```json
{
  "scripts": {
    "dev": "keyenv run -p YOUR_PROJECT_ID -e development -- bun run src/index.ts",
    "start": "keyenv run -p YOUR_PROJECT_ID -e production -- bun run src/index.ts"
  }
}
```

### Run with Secrets

```bash
# Set your token
export KEYENV_TOKEN=your-service-token

# Run with secrets injected
bun run dev
```

## Using the Node.js SDK

Bun is Node.js-compatible, so you can use the official KeyEnv Node.js SDK.

### Install

```bash
bun add @keyenv/node
```

### Basic Usage

```typescript
import { KeyEnv } from '@keyenv/node';

const client = new KeyEnv({
  token: process.env.KEYENV_TOKEN!,
});

// Load secrets into process.env
await client.loadEnv('your-project-id', 'production');

console.log(process.env.DATABASE_URL);
```

### Full Example

```typescript
// src/index.ts
import { KeyEnv } from '@keyenv/node';

const client = new KeyEnv({
  token: process.env.KEYENV_TOKEN!,
});

// Load secrets before starting server
await client.loadEnv(process.env.KEYENV_PROJECT!, 'production');

const server = Bun.serve({
  port: process.env.PORT || 3000,
  fetch(req) {
    return new Response('OK');
  },
});

console.log(`Server running at http://localhost:${server.port}`);
```

## Using Bun's Built-in fetch

You can also call the KeyEnv API directly:

```typescript
const KEYENV_TOKEN = process.env.KEYENV_TOKEN;
const PROJECT_ID = 'your-project-id';
const ENVIRONMENT = 'production';

async function loadSecrets() {
  const response = await fetch(
    `https://api.keyenv.dev/api/v1/projects/${PROJECT_ID}/environments/${ENVIRONMENT}/secrets/export`,
    {
      headers: {
        'Authorization': `Bearer ${KEYENV_TOKEN}`,
      },
    }
  );

  if (!response.ok) {
    throw new Error(`Failed to fetch secrets: ${response.status}`);
  }

  const { data: secrets } = await response.json();

  for (const secret of secrets) {
    process.env[secret.key] = secret.value;
  }

  console.log(`Loaded ${secrets.length} secrets`);
}

await loadSecrets();
```

## Elysia Framework

For Elysia applications:

```typescript
import { Elysia } from 'elysia';
import { KeyEnv } from '@keyenv/node';

const client = new KeyEnv({
  token: process.env.KEYENV_TOKEN!,
});

// Load secrets before creating app
await client.loadEnv(process.env.KEYENV_PROJECT!, 'production');

const app = new Elysia()
  .get('/', () => 'Hello World')
  .get('/config', () => ({
    apiUrl: process.env.API_URL,
  }))
  .listen(3000);

console.log(`Elysia running at http://${app.server?.hostname}:${app.server?.port}`);
```

## Hono Framework

For Hono applications running on Bun:

```typescript
import { Hono } from 'hono';
import { KeyEnv } from '@keyenv/node';

const client = new KeyEnv({
  token: process.env.KEYENV_TOKEN!,
});

await client.loadEnv(process.env.KEYENV_PROJECT!, 'production');

const app = new Hono();

app.get('/', (c) => c.text('Hello World'));

export default {
  port: process.env.PORT || 3000,
  fetch: app.fetch,
};
```

## Scripts and One-off Commands

For scripts that need secrets:

```typescript
// scripts/migrate.ts
import { KeyEnv } from '@keyenv/node';

const client = new KeyEnv({
  token: process.env.KEYENV_TOKEN!,
});

// Load production secrets for migration
await client.loadEnv(process.env.KEYENV_PROJECT!, 'production');

// Now run your migration
const databaseUrl = process.env.DATABASE_URL;
console.log('Running migrations...');
// ... migration code
```

Run with:

```bash
KEYENV_TOKEN=xxx KEYENV_PROJECT=xxx bun run scripts/migrate.ts
```

Or using the CLI:

```bash
keyenv run -p PROJECT -e production -- bun run scripts/migrate.ts
```

## Testing

Load test secrets in your test setup:

```typescript
// test/setup.ts
import { KeyEnv } from '@keyenv/node';
import { beforeAll } from 'bun:test';

beforeAll(async () => {
  const client = new KeyEnv({
    token: process.env.KEYENV_TOKEN!,
  });

  await client.loadEnv(process.env.KEYENV_PROJECT!, 'test');
});
```

Configure in `bunfig.toml`:

```toml
[test]
preload = ["./test/setup.ts"]
```

## Best Practices

1. **Load secrets once at startup** - Don't fetch on every request:
   ```typescript
   // Good - load once
   await client.loadEnv(projectId, 'production');
   const server = Bun.serve({ ... });

   // Bad - fetching on every request
   app.get('/', async () => {
     await client.loadEnv(projectId, 'production'); // Don't do this!
   });
   ```

2. **Use environment-specific configs**:
   ```typescript
   const env = process.env.NODE_ENV || 'development';
   await client.loadEnv(projectId, env);
   ```

3. **Handle errors at startup**:
   ```typescript
   try {
     await client.loadEnv(projectId, 'production');
   } catch (error) {
     console.error('Failed to load secrets:', error);
     process.exit(1);
   }
   ```

4. **Use caching in serverless** - Enable cache TTL for warm function reuse:
   ```typescript
   const client = new KeyEnv({
     token: process.env.KEYENV_TOKEN!,
     cacheTtl: 300, // 5 minutes
   });
   ```
