# Freestyle SDK

Learn more at [docs.freestyle.sh](https://docs.freestyle.sh)

## Installation

```bash
npm install freestyle
```

## CLI Usage

The Freestyle SDK includes a command-line interface for managing your Freestyle resources.

### Setup

Set the environment variable with your API key:

```bash
export FREESTYLE_API_KEY="your-api-key"
```

Or create a `.env` file in your project directory:

```
FREESTYLE_API_KEY=your-api-key
```

### Commands

#### Virtual Machines

```bash
# Create a new VM
freestyle vm create --name my-vm

# Create a VM from a snapshot (for debugging)
freestyle vm create --snapshot <snapshot-id>

# Create a VM with domain
freestyle vm create --domain myapp.example.com --port 3000

# Create VM and SSH into it (auto-deletes on exit)
freestyle vm create --ssh

# Create VM from snapshot and SSH into it
freestyle vm create --snapshot <snapshot-id> --ssh

# List all VMs
freestyle vm list

# SSH into a VM
freestyle vm ssh <vmId>

# SSH into a VM and delete it on exit
freestyle vm ssh <vmId> --delete-on-exit

# Execute a command on a VM
freestyle vm exec <vmId> "ls -la"

# Delete a VM
freestyle vm delete <vmId>
```

#### Serverless Deployments

```bash
# Deploy from inline code
freestyle deploy --code "export default () => 'Hello World'"

# Deploy from a file
freestyle deploy --file ./my-function.js

# Deploy from a Git repository
freestyle deploy --repo <repoId>

# Deploy a prebuilt directory
freestyle deploy --dir ./dist

# Deploy a directory and run server-side build auto-detection
freestyle deploy --dir . --build

# Deploy a directory with explicit build settings
freestyle deploy --dir . --build --build-command "npm run build" --build-out-dir dist

# Add environment variables
freestyle deploy --code "..." --env API_KEY=secret --env DEBUG=true
```

#### Serverless Runs

```bash
# Execute a one-off function from inline code
freestyle run --code "console.log('Hello!')"

# Execute from a file
freestyle run --file ./script.js
```

#### Utilities

```bash
# Get help for any command
freestyle --help
freestyle vm --help
```

## SDK Usage

```ts
import { freestyle, VmSpec } from "freestyle";
import { VmNodeJs } from "@freestyle-sh/with-nodejs";

// Create and store code with git.
const { repoId } = await freestyle.git.repos.create({
  source: {
    url: "https://github.com/freestyle-sh/freestyle-base-nextjs-shadcn",
  },
});

// Create a new branch from the default branch
const repo = freestyle.git.repos.ref({ repoId });
const { name, sha } = await repo.branches.create({
  name: "feature/something",
});

// Create commits with files (text and binary)
const { commit } = await repo.commits.create({
  message: "Add new feature",
  branch: "feature/something",
  files: [
    { path: "README.md", content: "# My Project" },
    { path: "logo.png", content: base64Image, encoding: "base64" }
  ],
  author: { name: "John Doe", email: "john@example.com" }
});

// Develop code with VMs. Add language runtimes via `with` — install the
// matching `@freestyle-sh/with-*` package and pass a builder instance.
const { vm } = await freestyle.vms.create({
  spec: new VmSpec().with("node", new VmNodeJs()),
  gitRepos: [{ repo: repoId, path: "/repo" }],
});

await vm.fs.writeTextFile("/repo/api/hello.js", "...");
await vm.exec("ls /repo");
await vm.node.runCode({ code: "console.log('hello')" });

// Deploy your code to the internet.
const { deploymentId } = await freestyle.serverless.deployments.create({
  repo: repoId,
});

// Verify a custom domain and point it at your deployment.
const { record } = await freestyle.domains.verifications.create({
  domain: "example.com",
});

console.log(record);

await freestyle.domains.verifications.complete({
  domain: "example.com",
});

await freestyle.domains.mappings.create({
  domain: "example.com",
  deploymentId: deploymentId,
});

// test your app with lightweight JS workers
for (let i = 0; i < 10; i++) {
  freestyle.serverless.runs.create({
    code: `export default () => {
        fetch("https://example.com/api/hello")
          .then(res => res.json()) 
        })
        `,
  });
}

// Restrict outbound requests and attach headers for matching domains.
await freestyle.serverless.runs.create({
  code: `export default async () => {
    const res = await fetch("https://api.freestyle.sh/some-path");
    return await res.text();
  }`,
  egress: {
    allow: {
      domains: {
        "api.freestyle.sh": [
          {
            transform: [
              {
                headers: {
                  "X-Freestyle-Admin-Key": "abc",
                  "X-Freestyle-User-Id": "123",
                },
              },
            ],
          },
        ],
        "*": [],
      },
    },
  },
});

// The same egress config shape is supported for deployments.
await freestyle.serverless.deployments.create({
  code: "export default () => new Response('ok')",
  egress: {
    allow: {
      domains: {
        "api.freestyle.sh": [
          {
            transform: [
              {
                headers: {
                  "X-Freestyle-Admin-Key": "abc",
                  "X-Freestyle-User-Id": "123",
                },
              },
            ],
          },
        ],
        "*": [],
      },
    },
  },
});
```
