API model

Beignet APIs follow a small grammar. Once you know the grammar, new packages should feel predictable.

Naming

Use define* for static declarations that describe application-owned shape.

defineErrors(...)
definePorts(...)
defineConfig(...)

Use create* for runtime factories, adapters, servers, clients, providers, and test helpers.

createContractGroup()
createEnv(...)
createNextServer(...)
createClient(...)
createReactQuery(client)
createReactHookForm()
createNuqs()
createProvider(...)
createUseCase(...)
createUseCaseTester(...)

Definition helpers use domain language when the helper creates a reusable application primitive or runtime declaration.

defineEntity("Post")
defineEvent("PostPublished")
defineValueObject("Email")
defineJob("SendEmail")

Declaration builders use .build() when they need an explicit finalization step.

defineEntity("Post").props(postSchema).build()
defineValueObject("Email").schema(emailSchema).build()

Builders

Builders are immutable. Chained methods refine the definition and return the next builder.

const posts = createContractGroup()
  .namespace("posts")
  .prefix("/api/posts")
  .headers(writerHeadersSchema);

export const createPost = posts
  .post("/")
  .body(createPostSchema)
  .errors({ Unauthorized: errors.Unauthorized })
  .responses({ 201: postSchema });

The same shape appears in application code.

export const createPostUseCase = useCase
  .command("posts.create")
  .input(createPostSchema)
  .output(postSchema)
  .run(async ({ ctx, input }) => {
    return ctx.ports.posts.create(input);
  });

Contract-aware adapters

Contract-aware adapters accept the contract builder you already exported. You do not need to manually extract .config for normal usage.

const endpoint = client.endpoint(createPost);
const mutation = rq(createPost).mutationOptions();
const form = rhf(createPost).useForm();
const filters = nq(listPosts).query({ parsers });

This is the main transfer rule: define the contract once, then bind it to the runtime surface you need.

Normal path and escape hatches

The normal path is contract-first and builder-driven:

contract -> server route -> client endpoint -> React adapter

Properties such as .config, .schema, .metadata, .responseSchemas, and .endpoint are escape hatches for integration code, generators, tests, and advanced introspection. Application code should usually pass the contract builder directly.

App vocabulary

Beignet apps keep the same concepts in predictable folders.

features/   feature-owned contracts, routes, use cases, policies, and UI
server/     runtime wiring
ports/      app-wide dependency interfaces
infra/      concrete adapters
client/     browser/core/server client adapters
lib/        shared app helpers such as env, auth, and use-case builder

The CLI follows this vocabulary when it inspects an app, generates resources, and reports drift.