irgen ships two primary entry points: app(...) for backend and frontend(...). Each DSL maps to its own DomainIR, allowing you to describe system intent independently of implementation details.

Core Concepts

To keep the architecture modular, irgen distinguishes between the data layer and the interaction layer:

Operation: The atom of the backend contract. It defines a specific API call (path, method, payload) regardless of how the UI uses it.

Action: The representation of intent in the UI. It binds a component to an operation, handling state, loading, and optimistic updates.

1import { app } from "irgen";
2
3app("DemoApp", (a) => {
4  a.entity("User", (e) => {
5    e.model({ id: "string", email: "string" });
6    e.create();
7    e.list();
8  });
9});

Common Frontend DSL

Frontend DSL declares pages and components. Components can be plain or bound to operations; policies decide final rendering modes.

1import { frontend } from "irgen";
2
3frontend("DemoFE", (f) => {
4  f.page("Home", { path: "/" }, (p) => {
5    p.component("Hero");
6  });
7  f.component("Hero", (c) => {
8    c.content = "Hello from irgen";
9  });
10});

Operation-Oriented DSL

The new frontend DSL supports an Operation-Oriented architecture with specialized constructs for connecting to any API.

Flexible Definitions

You can now define entities either directly in the options object or using standalone function calls within the callback.

1import { frontend, datasource } from "irgen";
2
3frontend("AdminApp", {
4  datasources: [{ id: "api", baseUrl: "/api" }]
5}, (app) => {
6  // Standalone function call
7  datasource("legacy", { baseUrl: "https://old.api.com" });
8
9  app.page("Dashboard", ...);
10});

Operation-Oriented UI

Use datasource, operation, and resource to model your data layer.

1app.datasource("main", { baseUrl: "/api", authStrategyId: "bearer" });
2
3app.operation("publish", {
4  datasourceId: "main",
5  method: "POST",
6  path: "/posts/:id/publish"
7});
8
9app.resource("posts", {
10  datasourceId: "main",
11  listOpId: "list-posts"
12});

Universal Actions

Actions provide a unified way to handle clicks and other events.

1// Invoke an operation
2c.onClick = {
3  kind: "invoke",
4  operationId: "signup",
5  args: { email: "user@example.com" },
6  confirmMessage: "Are you sure?"
7};
8
9// Simple navigation
10c.onClick = {
11  kind: "navigate",
12  to: "/dashboard"
13};

Macro System

Use macros to expand complex page patterns with ease.

1// Using the micro-frontend macro helper
2p.macro("TablePage", {
3  title: "User Management",
4  operationId: "list-users",
5  columns: ["name", "email"]
6});
7
8// Or using a component directly
9p.component("Login", (c) => {
10  c.macro = "AuthPage";
11});

Operation-Backed Forms

Forms can now bind directly to operations for submission and loading.

1c.form({
2  fields: ["name", "email"],
3  submit: {
4    operationId: "create-user",
5    successMessage: "User created!"
6  },
7  load: {
8    operationId: "get-user",
9    args: { id: "user-1" }
10  }
11});