# @worktif/runtime

[![npm version](https://img.shields.io/npm/v/@worktif/runtime.svg)](https://www.npmjs.com/package/@worktif/runtime)
![Node Support](https://img.shields.io/badge/node-%3E%3D18.0.0-43853d)
![TypeScript](https://img.shields.io/badge/TypeScript-5.8.3-3178c6)
![License](https://img.shields.io/badge/license-Elastic--2.0-blue.svg)

---

<svg focusable="false" aria-hidden="true" viewBox="0 0 582.21 122.69" id="Layer_2" xmlns="http://www.w3.org/2000/svg"><g id="Layer_1-2" data-name="Layer_1"><path d="M99.46,120.87c-8.69,0-16.46.15-24.2-.15-1.33-.05-2.95-1.82-3.81-3.19-7.68-12.26-15.31-24.56-22.72-36.98-1.67-2.81-3.49-3.87-6.75-3.72-6.26.28-12.55.08-19.32.08v43.67H.16v-63.56c9.11,0,17.73,0,26.36,0,9.49,0,18.98.11,28.47.02,11.06-.1,17.99-6.72,18.49-17.44.55-11.99-4.63-18.92-16.17-19.64-11.38-.71-22.83-.15-34.73-.15v27.05H0V.37C1.54.24,2.82.05,4.09.05c17.82-.01,35.64-.15,53.45.07,9.61.12,18.67,2.23,26.79,8.03,16.98,12.11,18.2,50.99-5.9,62.26-2.7,1.26-5.39,2.55-8.22,3.89,9.61,15.3,19.19,30.55,29.24,46.56Z" style="fill: rgb(229, 218, 218);"></path><path d="M276.2,120.88c-4.97,0-9.82.35-14.57-.18-1.87-.21-3.98-2.05-5.21-3.72-13.12-17.79-26.08-35.69-39.97-54.77v58.37h-17.64V31.93c5.44,0,10.56-.19,15.65.14,1.26.08,2.66,1.69,3.55,2.92,12.08,16.7,24.08,33.46,36.12,50.2,1.11,1.54,2.3,3.03,4.59,4.25v-57.23h17.47v88.67Z" style="fill: rgb(229, 218, 218);"></path><path d="M576.41,69.01v14.75h-37.86v22.14h43.65v15.69h-61.71V33.27h60.66v15.38h-42.65v20.37h37.9Z" style="fill: rgb(229, 218, 218);"></path><path d="M108.48,32.18h17.46c0,4.71.01,9.15,0,13.6-.04,12.64-.1,25.28-.11,37.92,0,1.99.09,3.99.29,5.97.66,6.45,2.73,12.23,9.35,14.68,7.66,2.83,15.48,3,22.38-1.97,5.52-3.98,6.24-10.42,6.31-16.62.18-15.97.06-31.93.06-47.9,0-1.79,0-3.57,0-5.64h17.66c0,9.34.02,18.45,0,27.55-.02,9.31-.02,18.63-.13,27.94-.25,21.48-11.73,33.88-33.2,34.92-6.33.31-13.01-.62-19.1-2.42-12.33-3.66-20.16-12.6-20.72-25.33-.91-20.72-.24-41.51-.24-62.7Z" style="fill: rgb(229, 218, 218);"></path><path d="M287.59,32.19h70.26v15.36h-26.2v73.01h-17.94V48.06h-26.11v-15.88Z" style="fill: rgb(229, 218, 218);"></path><path d="M369.37,120.55V32.29h17.3v88.27h-17.3Z" style="fill: rgb(229, 218, 218);"></path><path d="M468.36,32.44c6.39,0,12.56,0,19.15,0,6.77,29.23,13.55,58.47,20.39,88-5.78,0-10.97,0-16.69,0-4.63-22.25-9.27-44.53-13.9-66.81-.17-.01-.33-.02-.5-.03-4.93,22.2-9.86,44.4-14.83,66.77-5.49,0-10.81,0-16.62,0-4.94-22.13-9.9-44.35-14.86-66.57-.2-.03-.39-.06-.59-.1-4.64,22.19-9.27,44.37-13.93,66.68-5.66,0-10.96,0-16.69,0,6.94-29.32,13.84-58.44,20.8-87.83,6.24,0,12.61,0,19.13,0,4.75,21.66,9.48,43.21,14.2,64.75.18.03.36.05.54.08,4.78-21.53,9.55-43.06,14.41-64.94Z" style="fill: rgb(255, 87, 34);"></path></g></svg>

**Runtime Web** is a unified serverless framework for building full-stack TypeScript applications on AWS. Define microservices with type-safe dependency injection, write Lambda handlers with auto-injected services, build React frontends, and deploy everything with a single command.

```typescript
// One entry point. Three execution contexts. Zero configuration.
runtime({
  app: ({ router }) => <App router={router} />,
  router: runtimeRouter({ router: routes }),
  config: { serviceName: 'my-app', stage: 'dev' },
  register: {
    users: {
      ties: [UsersTies],
      lambdas: [createUserHandler, getUserHandler, updateUserHandler]
    }
  }
});
```

---

## Why Runtime?

| Traditional Approach | With Runtime |
|---------------------|--------------|
| Separate repos for frontend, backend, infra | Single unified codebase |
| Manual DI wiring in each Lambda | Type-safe auto-injection via `event.ties` |
| Write CloudFormation/Terraform manually | CDK constructs auto-provision everything |
| Different tooling for dev/build/deploy | One CLI: `runtime dev`, `runtime deploy` |
| Context switching between environments | `runtime()` auto-detects execution context |

---

## Key Features

- **Unified Codebase** – Frontend (React), Backend (Lambda), Infrastructure (CDK) in one project
- **Type-Safe Lambda DI** – Access services via `event.ties.serviceName` with full TypeScript support
- **Declarative Microservices** – Define services with `ties` (DI config) + `lambdas` (endpoints)
- **Context-Aware Execution** – Single `runtime()` entry point works in Browser, Lambda, and CDK
- **Zero-Config AWS Deployment** – CDK constructs create API Gateway, Lambda, S3, CloudFront, DynamoDB
- **Built-in Dev Server** – Local development with HMR and Lambda emulation
- **React SSR Support** – Optional server-side rendering with streaming and S3 caching
- **SEO Management** – DynamoDB-backed metadata with automatic head tag updates

---

## Table of Contents

- [Installation](#installation)
- [Quick Start](#quick-start)
- [Core Concepts](#core-concepts)
- [CLI Reference](#cli-reference)
- [CDK Infrastructure](#cdk-infrastructure)
- [React Integration](#react-integration)
- [SEO Management](#seo-management)
- [Package Exports](#package-exports)
- [Configuration](#configuration)
- [Migration Guide](#migration-guide)
- [Documentation](#documentation)
- [Contributing](#contributing)
- [License](#license)

---

## Installation

### New Projects (Recommended)

```bash
npx @worktif/runtime init
```

This creates a complete project with:
- Application structure (React frontend + Lambda handlers)
- AWS CDK infrastructure
- Development server configuration
- TypeScript configuration
- All dependencies installed

### Existing Projects

```bash
npm install @worktif/runtime
# or
yarn add @worktif/runtime
```

**Prerequisites:**
- Node.js ≥ 18
- AWS Account with CLI configured
- AWS CDK CLI: `npm install -g aws-cdk`

---

## Quick Start

### 1. Initialize Project

```bash
mkdir my-app && cd my-app
npx @worktif/runtime init
```

### 2. Define a Microservice

```typescript
// src/services/users.service.ts
export class UsersService {
  async getUser(id: string) {
    return { id, name: 'John Doe', email: 'john@example.com' };
  }
  
  async createUser(data: { email: string; name: string }) {
    return { id: crypto.randomUUID(), ...data };
  }
}
```

```typescript
// src/ties/users.ties.ts
import { UsersService } from '../services/users.service';

export class UsersTies {
  static register = {
    userService: {
      instance: UsersService,
      dependencies: []
    }
  };
}
```

```typescript
// src/handlers/users.handlers.ts
import { LambdaDefinition } from '@worktif/runtime';
import { UsersService } from '../services/users.service';

type UserTies = { userService: UsersService };

export const getUserHandler: LambdaDefinition<UserTies> = {
  id: 'get',
  ties: { userService: UsersService },
  handler: async (event, context) => {
    const user = await event.ties.userService.getUser(event.pathParameters.id);
    return {
      statusCode: 200,
      body: JSON.stringify(user)
    };
  },
  http: {
    method: 'GET',
    path: '/api/users/{id}',
    auth: 'jwt'
  }
};
```

### 3. Register in runtime()

```typescript
// src/index.tsx
import { runtime, runtimeRouter } from '@worktif/runtime';
import { UsersTies } from './ties/users.ties';
import { getUserHandler, createUserHandler } from './handlers/users.handlers';
import { routes } from './routes';
import App from './App';

runtime({
  app: ({ router }) => <App router={router} />,
  router: runtimeRouter({ router: routes }),
  config: {
    serviceName: process.env.PURE_ENV_STACK_NAME || 'my-app',
    stage: (process.env.PURE_ENV_STAGE as 'dev' | 'staging' | 'prod') || 'dev'
  },
  register: {
    users: {
      ties: [UsersTies],
      lambdas: [getUserHandler, createUserHandler]
    }
  }
});
```

### 4. Start Development

```bash
npx runtime dev
```

App runs at `http://localhost:3000` with HMR.

### 5. Deploy to AWS

```bash
npx runtime deploy --stage dev
```

Your full-stack application is now live on AWS!

---

## Core Concepts

### The runtime() Function

The `runtime()` function is the single entry point that automatically detects execution context:

| Context | Detection | Behavior |
|---------|-----------|----------|
| **Browser** | `window` exists | Hydrates React app, sets up client-side routing |
| **Lambda** | `AWS_LAMBDA_FUNCTION_NAME` env | Executes handler with DI injection |
| **CDK** | CDK synthesis context | Provides infrastructure definitions |

```typescript
runtime({
  // React application factory (Browser + Lambda SSR)
  app: ({ router }) => <App router={router} />,
  
  // Router configuration
  router: runtimeRouter({ router: routes }),
  
  // Service configuration
  config: {
    serviceName: 'my-app',
    stage: 'dev'
  },
  
  // Microservice registry (Lambda)
  register: {
    users: { ties: [UsersTies], lambdas: [...] },
    payments: { ties: [PaymentsTies], lambdas: [...] }
  }
});
```

### Microservice Architecture

Runtime organizes backend logic into **microservices** – logical groupings of related Lambda functions sharing a DI container:

```typescript
register: {
  // Microservice name
  users: {
    // DI configuration classes
    ties: [UsersTies, AuthTies],
    
    // Lambda endpoints
    lambdas: [
      createUserHandler,
      getUserHandler,
      updateUserHandler,
      deleteUserHandler
    ]
  },
  
  payments: {
    ties: [PaymentsTies, BillingTies],
    lambdas: [chargeHandler, refundHandler, webhookHandler]
  }
}
```

**Architecture:**
- Each microservice gets isolated DI container
- Lambda functions within a microservice share dependencies
- Microservices are deployed as separate Lambda functions
- API Gateway routes are auto-generated from `http` definitions

### Type-Safe Dependency Injection

Runtime provides compile-time type safety for Lambda dependencies:

```typescript
// Define ties type
type PaymentTies = {
  paymentService: PaymentsService;
  billingService: BillingService;
  configService: ConfigService;
};

// Handler with typed event.ties
export const chargeHandler: LambdaDefinition<PaymentTies> = {
  ties: {
    paymentService: PaymentsService,
    billingService: BillingService,
    configService: ConfigService
  },
  handler: async (event, context) => {
    // Full IntelliSense and type checking!
    const config = event.ties.configService.getPaymentConfig();
    const result = await event.ties.paymentService.charge({
      amount: event.body.amount,
      currency: config.defaultCurrency
    });
    await event.ties.billingService.recordTransaction(result);
    
    return { statusCode: 200, body: JSON.stringify(result) };
  }
};
```

**Benefits:**
- `event.ties.serviceName` is fully typed
- Compile-time errors for missing/wrong dependencies
- IDE autocomplete for all injected services
- No magic strings or runtime reflection

### Lambda Handlers

Lambda handlers are defined declaratively with `LambdaDefinition`:

```typescript
import { LambdaDefinition } from '@worktif/runtime';
import type { APIGatewayProxyEvent, APIGatewayProxyResult } from 'aws-lambda';

type MyTies = { userService: UsersService };

export const myHandler: LambdaDefinition<MyTies> = {
  // Unique ID within microservice (optional, auto-generated from function name)
  id: 'create',
  
  // Dependencies to inject (object format for type safety)
  ties: { userService: UsersService },
  
  // Handler function with typed event.ties
  handler: async (event, context): Promise<APIGatewayProxyResult> => {
    const user = await event.ties.userService.createUser(JSON.parse(event.body));
    return {
      statusCode: 201,
      headers: { 'Content-Type': 'application/json' },
      body: JSON.stringify(user)
    };
  },
  
  // HTTP integration (optional - creates API Gateway route)
  http: {
    method: 'POST',
    path: '/api/users',
    auth: 'jwt',      // 'none' | 'jwt' | 'iam' | 'cognito'
    cors: true
  },
  
  // Lambda-specific config overrides (optional)
  config: {
    memorySize: 1024,    // MB (128-10240)
    timeout: 30,         // seconds (1-900)
    environment: {
      CUSTOM_VAR: 'value'
    }
  }
};
```

### Ties Classes

Ties classes configure dependency injection for a microservice:

```typescript
import { UsersService } from '../services/users.service';
import { AuthService } from '../services/auth.service';
import { ConfigService } from '../services/config.service';

export class UsersTies {
  // Object-based registration (recommended)
  static register = {
    // Property name becomes the key in event.ties
    userService: {
      instance: UsersService,
      dependencies: []  // Other service keys this depends on
    },
    authService: {
      instance: AuthService,
      dependencies: ['configService']  // Depends on configService
    },
    configService: {
      instance: ConfigService,
      dependencies: []
    }
  };
}
```

**Dependency Resolution:**
- Services are instantiated in dependency order
- Circular dependencies are detected and reported
- Singleton scope by default (one instance per microservice)

---

## CLI Reference

### Development

```bash
# Start dev server with HMR
npx runtime dev

# Custom port
npx runtime dev --port 8080

# Disable HMR
npx runtime dev --no-hmr
```

### Building

```bash
# Build all targets (frontend, Lambda, CDK)
npx runtime build

# Build specific target
npx runtime build --target react
npx runtime build --target lambda
npx runtime build --target cdk
```

### Deployment

```bash
# Deploy to stage
npx runtime deploy --stage dev
npx runtime deploy --stage staging
npx runtime deploy --stage prod

# Deploy specific stack
npx runtime deploy --stage dev --stack MyApp-Infra-dev
```

### Resource Management

```bash
# List CloudFormation stacks
npx runtime stacks list
npx runtime stacks list --outputs
npx runtime stacks list --stage dev

# Destroy stacks
npx runtime destroy --stage dev
npx runtime destroy --stage dev --dry-run  # Preview
npx runtime destroy --stage dev --backup   # With backup

# Clear CDN cache
npx runtime cache-clear --stage dev
```

### SEO Management

```bash
# Initialize SEO configuration
npx runtime seo init

# Sync metadata to DynamoDB
npx runtime seo sync --stage dev

# Update specific route
npx runtime seo update --route /about --stage dev
```

### Diagnostics

```bash
# Environment checks
npx runtime doctor

# System information
npx runtime info
```

---

## CDK Infrastructure

Runtime provides CDK constructs for automatic AWS infrastructure provisioning.

### Basic Usage

```typescript
// cdk/bin/app.ts
import * as cdk from 'aws-cdk-lib';
import { RuntimeStack } from '@worktif/runtime/infra';

const app = new cdk.App();

new RuntimeStack(app, 'MyApp-Dev', {
  stage: 'dev',
  serviceName: 'my-app',
  env: {
    account: process.env.CDK_DEFAULT_ACCOUNT,
    region: 'us-east-1'
  }
});

app.synth();
```

### Two-Stack Architecture

Runtime uses a two-stack architecture for reliable deployments:

| Stack | Resources | Purpose |
|-------|-----------|---------|
| **Infra Stack** | S3, DynamoDB, CloudFront | Long-lived infrastructure |
| **Runtime Stack** | Lambda, API Gateway, Lambda Layers | Application runtime |

This ensures Lambda functions receive correct environment variables on first deployment.

### Stack Options

```typescript
new RuntimeStack(app, 'MyApp-Prod', {
  // Required
  stage: 'prod',
  serviceName: 'my-app',
  
  // Optional
  enableSeo: true,              // Enable DynamoDB SEO table
  lambdaMemorySize: 1024,       // Default Lambda memory (MB)
  lambdaTimeout: 30,            // Default Lambda timeout (seconds)
  
  // CloudFront
  domainName: 'app.example.com',
  certificateArn: 'arn:aws:acm:...',
  
  // Environment
  env: {
    account: '123456789012',
    region: 'us-east-1'
  }
});
```

### Provisioned Resources

- **API Gateway** – HTTP API with Lambda integrations
- **Lambda Functions** – One per handler definition
- **Lambda Layer** – Shared dependencies (node_modules)
- **S3 Buckets** – Static assets, SSR cache
- **CloudFront** – CDN distribution with edge caching
- **DynamoDB** – SEO metadata (optional)

---

## React Integration

Runtime extends React Router with built-in async data loading, SEO management, and SSR support through `RuntimeRouter` and `runtimeAsync`.

### Route Definition with Async Data Loading

Routes use `runtimeAsync` – an array of data retriever functions that execute in parallel during route loading:

```typescript
// src/routes.tsx
import * as React from 'react';
import { Outlet } from 'react-router';
import { RuntimeHeadManager, RuntimeRoute } from '@worktif/runtime';

import HomePage from './pages/HomePage';
import ProductPage from './pages/ProductPage';
import AboutPage from './pages/AboutPage';

// Data retriever functions for async loading
const homeDataRetriever = async ({ params, request, searchParams }) => {
  const featured = await fetchFeaturedProducts();
  return { featured };
};

const productRetriever = async ({ params }) => {
  const product = await fetchProduct(params.id);
  return { product };
};

const reviewsRetriever = async ({ params }) => {
  const reviews = await fetchReviews(params.id);
  return { reviews };
};

export const routes: RuntimeRoute[] = [
  {
    path: '/',
    id: 'root',
    // Root layout with SEO head manager
    Component: () => (
      <>
        <RuntimeHeadManager />
        <Outlet />
      </>
    ),
    children: [
      {
        path: '/',
        id: 'home',
        Component: HomePage,
        runtimeAsync: [homeDataRetriever],  // Single retriever
      },
      {
        path: '/products/:id',
        id: 'product',
        Component: ProductPage,
        runtimeAsync: [productRetriever, reviewsRetriever],  // Multiple retrievers (parallel)
      },
      {
        path: '/about',
        id: 'about',
        Component: AboutPage,
        // No runtimeAsync – static route, SEO still works
      },
    ],
  },
];
```

**Key Concepts:**
- `runtimeAsync` replaces React Router's `loader` – Runtime generates loaders automatically
- Multiple retrievers execute in parallel via `Promise.allSettled`
- Failed retrievers don't block route rendering (graceful degradation)
- SEO metadata is loaded automatically for all routes

### Router Initialization

Use `runtimeRouter()` to create a `RuntimeRouter` instance that transforms routes:

```typescript
// src/index.tsx
import { runtime, runtimeRouter } from '@worktif/runtime';
import { routes } from './routes';
import App from './App';

runtime({
  app: ({ router }) => <App router={router} />,
  router: runtimeRouter({
    router: routes,
    defaults: {
      // Default properties applied to all routes
      errorElement: <ErrorBoundary />,
    },
  }),
  config: {
    serviceName: 'my-app',
    stage: 'dev',
  },
});
```

### App Component with RuntimeRouterProvider

Use `RuntimeRouterProvider` instead of React Router's `RouterProvider`:

```typescript
// src/App.tsx
import * as React from 'react';
import { RuntimeRouterProvider } from '@worktif/runtime';

interface AppProps {
  router: any;
}

const App: React.FC<AppProps> = ({ router }) => {
  return (
    <div className="app">
      <RuntimeRouterProvider router={router} />
    </div>
  );
};

export default App;
```

### Accessing Loaded Data

Use `useRuntimeData` hook to access data from `runtimeAsync` retrievers:

```typescript
// src/pages/ProductPage.tsx
import { useRuntimeData } from '@worktif/runtime';

interface ProductData {
  product: { id: string; name: string; price: number };
  reviews: Array<{ id: string; rating: number; text: string }>;
}

function ProductPage() {
  // Type-safe access to loaded data
  const { product, reviews } = useRuntimeData<ProductData>();

  return (
    <div>
      <h1>{product.name}</h1>
      <p>Price: ${product.price}</p>
      <h2>Reviews ({reviews.length})</h2>
      {reviews.map(review => (
        <div key={review.id}>
          <span>Rating: {review.rating}/5</span>
          <p>{review.text}</p>
        </div>
      ))}
    </div>
  );
}
```

### Data Retriever Context

Each retriever receives a context object with route information:

```typescript
type DataRetrieverContext = {
  params: Params<string>;      // Route parameters (e.g., { id: '123' })
  request: Request;            // Full HTTP request object
  searchParams: URLSearchParams; // Query string parameters
};

// Example: Using all context properties
const searchRetriever = async ({ params, request, searchParams }) => {
  const query = searchParams.get('q') || '';
  const page = parseInt(searchParams.get('page') || '1');
  const category = params.category;
  
  const results = await searchProducts({ query, page, category });
  return { results, query, page };
};
```

### Server-Side Rendering

SSR is automatic when Lambda handles page requests:

1. Lambda receives request
2. `RuntimeRouter` matches route and executes `runtimeAsync` retrievers
3. `renderToPipeableStream()` generates HTML with loaded data
4. HTML cached in S3 with ETag
5. CloudFront serves cached response

**SSR Caching:**
- First request: Lambda renders, stores in S3
- Subsequent requests: S3 cache hit (fast)
- Cache invalidation: On deploy or manual

### HTML Template

Customize the HTML shell via `public/index.html`:

```html
<!DOCTYPE html>
<html lang="en">
  <head>
    <meta charset="utf-8" />
    <meta name="viewport" content="width=device-width, initial-scale=1" />
    <link rel="icon" href="{{STATIC_URL}}/favicon.ico" />
    <link rel="stylesheet" href="{{STATIC_URL}}/styles/main.css" />
    <title>My Application</title>
  </head>
  <body>
    <div id="root-runtime"></div>
  </body>
</html>
```

`{{STATIC_URL}}` is replaced with CloudFront CDN URL at runtime.

---

## SEO Management

Runtime provides DynamoDB-backed SEO metadata management.

### Setup

```bash
# Initialize SEO files
npx runtime seo init

# Creates:
# .seo/default.seo.json    - Framework defaults
# .seo/about.seo.json      - Route-specific (per route)
```

### Default Configuration

```json
{
  "route": "[seo-defaults]",
  "title": "My Application",
  "description": "Application description",
  "keywords": ["keyword1", "keyword2"],
  "ogTitle": "My Application",
  "ogDescription": "Social media description",
  "ogImage": "/og-image.png",
  "twitterCard": "summary_large_image",
  "robots": "index, follow"
}
```

### RuntimeHeadManager

Add to your layout for automatic head tag updates:

```typescript
import { RuntimeHeadManager } from '@worktif/runtime';
import { Outlet } from 'react-router';

const Layout = () => (
  <>
    <RuntimeHeadManager />
    <Header />
    <Outlet />
    <Footer />
  </>
);
```

### useRuntimeSeoMeta Hook

Access SEO data in components:

```typescript
import { useRuntimeSeoMeta } from '@worktif/runtime';

function MyComponent() {
  const seo = useRuntimeSeoMeta();
  return <h1>{seo?.title}</h1>;
}
```

### Sync to DynamoDB

```bash
npx runtime seo sync --stage dev
```

---

## Package Exports

| Export | Path | Description |
|--------|------|-------------|
| Main | `@worktif/runtime` | Core framework, React components, hooks |
| Infra | `@worktif/runtime/infra` | CDK constructs (RuntimeStack) |
| Lambda | `@worktif/runtime/lambda` | Pre-built Lambda handler bundle |
| CLI | `@worktif/runtime/cli.js` | Command-line interface |
| Bin | `@worktif/runtime/bin` | Build utilities |

```typescript
// Main library
import { runtime, runtimeRouter, ErrorBoundary, RuntimeHeadManager } from '@worktif/runtime';
import type { LambdaDefinition, MicroserviceDefinition } from '@worktif/runtime';

// CDK constructs
import { RuntimeStack, RuntimeInfraStack } from '@worktif/runtime/infra';
```

---

## Configuration

### Environment Variables

| Variable | Description | Context |
|----------|-------------|---------|
| `PURE_ENV_STACK_NAME` | Service name for AWS resources | Lambda |
| `PURE_ENV_STAGE` | Deployment stage (dev/staging/prod) | Lambda |
| `LAMBDA_ID` | Lambda identifier (auto-set by CDK) | Lambda |
| `AWS_REGION` | AWS region | Lambda |

### runtime.config.ts

```typescript
// runtime.config.ts
export default {
  projectName: 'my-app',
  defaultStage: 'dev',
  aws: {
    region: 'us-east-1'
  }
};
```

---

## Migration Guide

### DynamoDB Table Migration

If upgrading from a previous version with SEO enabled:

```bash
# Dry run first
npx runtime migrate:seo --dry-run

# Execute migration
npx runtime migrate:seo
```

See [DynamoDB Migration Guide](docs/deployment/dynamodb-table-migration.md) for details.

### Array to Object Ties Migration

**Before (deprecated):**
```typescript
const handler: LambdaDefinition = {
  ties: [UsersService, PaymentsService],
  handler: (deps) => async (event, context) => {
    // deps accessed via hash keys
  }
};
```

**After (recommended):**
```typescript
type MyTies = { userService: UsersService; paymentService: PaymentsService };

const handler: LambdaDefinition<MyTies> = {
  ties: { userService: UsersService, paymentService: PaymentsService },
  handler: async (event, context) => {
    // event.ties.userService - fully typed!
  }
};
```

---

## Documentation

### Getting Started
- [Installation Guide](docs/getting-started/installation.md)
- [Quick Start Tutorial](docs/getting-started/quick-start.md)
- [First Deployment](docs/getting-started/first-deployment.md)

### Core Concepts
- [Architecture Overview](docs/architecture/overview.md)
- [Lambda Layer Architecture](docs/architecture/lambda-layer.md)
- [Code Organization](docs/architecture/code-organization.md)
- [Request Flow](docs/architecture/request-flow.md)

### CLI & Development
- [CLI Commands](docs/cli/commands.md)
- [Local Development](docs/development/local-setup.md)
- [HMR & Live Reload](docs/development/hmr-live-reload.md)
- [Build System](docs/development/build-system.md)

### CDK & Deployment
- [CDK Usage Guide](docs/cdk/usage.md)
- [CDK Customization](docs/cdk/customization.md)
- [Deployment Overview](docs/deployment/overview.md)
- [Troubleshooting](docs/deployment/troubleshooting.md)

### Integration
- [React Setup](docs/integration/react-setup.md)
- [Router Integration](docs/integration/router-integration.md)
- [HTML Templates](docs/integration/html-template-customization.md)
- [SEO Management](docs/examples/seo-metadata-management.md)

### Reference
- [API Reference](docs/reference/api.md)
- [Configuration Reference](docs/reference/configuration.md)
- [Environment Variables](docs/reference/environment-variables.md)

**Full Documentation:** [docs/README.md](docs/README.md)

---

## Contributing

We welcome contributions! Please follow these steps:

1. Fork the repository
2. Create a feature branch
3. Make your changes with tests
4. Submit a pull request

See [CONTRIBUTING.md](CONTRIBUTING.md) for detailed guidelines.

**Security:** Report vulnerabilities privately to [raman@worktif.com](mailto:raman@worktif.com)

---

## License

This project is licensed under the [Elastic License 2.0](https://raw.githubusercontent.com/elastic/elasticsearch/v7.16.3/licenses/ELASTIC-LICENSE-2.0.txt).

- [LICENSE](LICENSE) – Full license text
- [NOTICE](NOTICE) – Attribution and relicensing details
- [CHANGELOG.md](CHANGELOG.md) – Version history

---

## Support

**Maintainer:** Raman Marozau – [raman@worktif.com](mailto:raman@worktif.com)

**Get Help:**
- [Documentation](docs/README.md)
- [GitHub Issues](https://github.com/worktif/runtime/issues)
- [Email Support](mailto:raman@worktif.com) (use "[runtime]" in subject)

---

**Ready to start?** Run `npx @worktif/runtime init` and build your first unified serverless application!
