alepha
Version:
Easy-to-use modern TypeScript framework for building many kind of applications.
245 lines (207 loc) • 7.13 kB
Markdown
# Alepha Framework
Convention-driven TypeScript framework for type-safe full-stack applications.
## Philosophy
- **Primitives**: `$`-prefixed functions (`$action`, `$entity`, `$page`)
- **Class-Based**: Services are classes, primitives are class properties
- **Zero-Config**: Code structure IS configuration
- **End-to-End Types**: Database → API → React
## Rules
- Use `t` from Alepha for schemas (not Zod)
- Use `protected` instead of `private` for class members
- Import with file extensions: `import { User } from "./User.ts"`
- Primitives are class properties (except `$entity`, `$atom`)
- No decorators, no Express/Fastify patterns
- No manual instantiation - use dependency injection
## Project Structure
```
src/
├── api/ # Backend
│ ├── controllers/ # $action endpoints
│ ├── services/ # Business logic
│ ├── entities/ # $entity definitions
│ └── index.ts # $module
├── web/ # Frontend (React)
│ ├── components/ # React components
│ ├── atoms/ # $atom state
│ ├── AppRouter.ts # $page routes
│ └── index.ts # $module
├── main.server.ts # Server entry
├── main.browser.ts # Browser entry
└── main.css # Styles
```
## Primitives Reference
### Core (`alepha`)
| Primitive | Purpose |
|-----------|---------|
| `$inject` | Dependency injection |
| `$env` | Environment variables |
| `$hook` | Lifecycle hooks (on: "start", "stop") |
| `$atom` | Global state (module-level) |
| `$module` | Module definition |
| `$context` | Request-scoped context |
### Server (`alepha/server`)
| Primitive | Purpose |
|-----------|---------|
| `$action` | REST API endpoints (auto GET/POST) |
| `$route` | Low-level HTTP routes |
| `$client` | Type-safe HTTP client for cross-module |
### Database (`alepha/orm`)
| Primitive | Purpose |
|-----------|---------|
| `$entity` | Database table definition |
| `$repository` | Type-safe CRUD operations |
| `$sequence` | Auto-increment sequences |
### Infrastructure
| Primitive | Import | Purpose |
|-----------|--------|---------|
| `$logger` | `alepha/logger` | Structured logging |
| `$queue` | `alepha/queue` | Background jobs |
| `$scheduler` | `alepha/scheduler` | Cron tasks |
| `$cache` | `alepha/cache` | Cached computations |
| `$bucket` | `alepha/bucket` | File storage |
| `$email` | `alepha/email` | Email sending |
| `$sms` | `alepha/sms` | SMS sending |
| `$lock` | `alepha/lock` | Distributed locks |
| `$retry` | `alepha/retry` | Retry with backoff |
### Security (`alepha/security`)
| Primitive | Purpose |
|-----------|---------|
| `$issuer` | JWT token generation/validation |
| `$permission` | Permission definitions |
| `$role` | Role-based access |
| `$basicAuth` | HTTP Basic Auth |
| `$serviceAccount` | Service-to-service auth |
### React (`alepha/react/router`)
| Primitive | Purpose |
|-----------|---------|
| `$page` | Pages with SSR, loaders, code-splitting |
| `$head` | Document head management |
| `$dictionary` | i18n translations |
### Other
| Primitive | Import | Purpose |
|-----------|--------|---------|
| `$command` | `alepha/command` | CLI commands |
| `$swagger` | `alepha/server` | OpenAPI docs |
| `$proxy` | `alepha/server` | HTTP proxy |
| `$tool` | `alepha/mcp` | MCP tool definition |
| `$prompt` | `alepha/mcp` | MCP prompt definition |
| `$resource` | `alepha/mcp` | MCP resource definition |
## React Hooks
```typescript
import { useAlepha, useClient, useStore, useAction, useInject } from "alepha/react";
import { useRouter, useActive, useQueryParams } from "alepha/react/router";
import { useForm, useFormState } from "alepha/react/form";
import { useAuth } from "alepha/react/auth";
import { useHead } from "alepha/react/head";
import { useI18n } from "alepha/react/i18n";
```
| Hook | Purpose |
|------|---------|
| `useClient<T>()` | Type-safe API calls |
| `useStore(atom)` | Global state `[value, setValue]` |
| `useAction({ handler })` | Async ops with loading/error |
| `useRouter<T>()` | Type-safe navigation |
| `useActive(path)` | Check if route is active |
| `useForm({ schema, handler })` | Forms with validation |
| `useAuth()` | Authentication state |
| `useInject(Service)` | Access DI container |
## Examples
### API Endpoint
```typescript
import { t } from "alepha";
import { $action } from "alepha/server";
class UserController {
getUser = $action({
path: "/users/:id",
schema: {
params: t.object({ id: t.uuid() }),
response: t.object({ id: t.uuid(), email: t.email() }),
},
handler: async ({ params }) => this.userRepo.findById(params.id),
});
}
```
### Entity & Repository
```typescript
import { t } from "alepha";
import { $entity, $repository, db } from "alepha/orm";
export const userEntity = $entity({
name: "users",
schema: t.object({
id: db.primaryKey(),
email: t.email(),
createdAt: db.createdAt(),
}),
});
class UserService {
users = $repository(userEntity);
}
```
### Page with Loader
```tsx
import { t } from "alepha";
import { $page } from "alepha/react/router";
import { $client } from "alepha/server/links";
class AppRouter {
api = $client<UserController>();
userDetail = $page({
path: "/users/:id",
schema: { params: t.object({ id: t.uuid() }) },
loader: async ({ params }) => ({
user: await this.api.getUser({ params })
}),
component: ({ user }) => <div>{user.email}</div>,
});
}
```
### Form
```tsx
import { t } from "alepha";
import { useForm } from "alepha/react/form";
function LoginForm() {
const form = useForm({
schema: t.object({
email: t.email(),
password: t.text(),
}),
handler: async (values) => {
await api.login(values);
},
});
return (
<form {...form.props}>
<input {...form.input.email.props} />
<input {...form.input.password.props} />
<button type="submit">Login</button>
</form>
);
}
```
## Schema Types (`t`)
```typescript
import { t } from "alepha";
t.string() // Basic string
t.text() // String with maxLength, trim, lowercase options
t.email() // Email validation
t.uuid() // UUID validation
t.number() // Number
t.integer() // Integer
t.boolean() // Boolean
t.date() // Date
t.array(t.string()) // Array
t.object({ ... }) // Object
t.optional(t.string()) // Optional
t.nullable(t.string()) // Nullable
t.enum(["a", "b"]) // Enum
t.literal("value") // Literal
t.union([...]) // Union
```
## Common Mistakes
1. Using decorators → Use primitives (`$action`, not `@Get()`)
2. Using Zod → Use `t` from Alepha
3. Using Express patterns → No `app.get()`, `router.use()`
4. Using `$inject` across modules → Use `$client` instead
5. Using async constructors → Use `$hook({ on: "start" })`
6. Manual instantiation → Let DI container manage
## Source Code
Read implementation at `src/` directory. Check `.spec.ts` files for usage examples.