You signed in with another tab or window. Reload to refresh your session.You signed out in another tab or window. Reload to refresh your session.You switched accounts on another tab or window. Reload to refresh your session.Dismiss alert
// app/actions.tsimport{api}from"./server";// Direct, in-process, no network overheadconstuser=awaitapi.users.get({id: 1});// Mutations work the same wayawaitapi.users.create({name: "John",email: "john@example.com"});
// server.tsimport{defineContext,createAPI}from"@deessejs/server"import{authPlugin}from"./plugins/auth"const{ t, createAPI }=defineContext({ db })constapi=createAPI({router: t.router({users: t.router({get: t.query({ ... }),create: t.mutation({ ... }),}),}),plugins: [authPlugin]})// Now available:// api.users.get({ id: 1 }) // from router// api.users.create({ ... }) // from router// api.getCurrentUser() // from authPlugin// api.login({ email, password }) // from authPlugin// api.logout() // from authPlugin
Static Generation (CLI)
For better performance, plugins can pre-generate their queries/mutations at build time:
# Generate static queries/mutations from plugins
npx deesse generate
This creates a generated folder with:
Type definitions for all plugin queries/mutations
Client SDK extensions
Route handlers
Client SDK Usage
After setting up the server, clients can use the auto-generated SDK:
// React/Next.js clientimport{createClient}from"@deessejs/api/client"constclient=createClient("http://localhost:3000/api/deesse")// Query - automatically generates cache key based on function name + argsconst{ data, error }=awaitclient.users.get({id: 1})if(data.ok){console.log(data.value)}// Mutation - automatically invalidates related cache keysconst{ data, error }=awaitclient.users.create({name: "John",email: "john@example.com"})
Or with React hooks (see #51 for automatic cache revalidation):
import{useQuery,useMutation}from"@deessejs/api/client"functionUserProfile({ id }){// Cache key automatically generated: ["users.get", { id }]// When cache is invalidated (see #52), this automatically refetchesconst{ data }=useQuery(client.users.get,{ id })return<div>{data?.value.name}</div>}functionCreateUser(){// Mutation automatically invalidates related cache keysconst{ mutate }=useMutation(client.users.create)return<buttononClick={()=>mutate({name: "John",email: "john@example.com"})}>Create</button>}
Cache key system:
Each query generates a unique cache key: ["functionName", args]
Each mutation automatically invalidates related cache keys
Problem
Currently, @deessejs/functions is a single monorepo package that contains both:
This has two problems:
Solution: Multi-package architecture
Package 1: Core (FP patterns)
Package name: @deessejs/core
Contains:
Use case: Anyone needing functional programming patterns without API concerns.
Package 2: Server (Definitions + Local)
Package name: @deessejs/server
Contains:
Use case: Server actions, lambdas, workers, any in-process function calls.
Package 3: HTTP API
Package name: @deessejs/api
Built on Hono under the hood for:
Contains:
Use case: Real APIs for external clients (web, desktop, mobile).
The Vision: Dual Mode
Define functions once in @deessejs/server:
Mode 1 - Local (Server Actions)
Mode 2 - HTTP (External API)
Next.js App Router
Next.js Pages Router
Standalone Server (Express/Fastify compatible)
Cloudflare Workers
Plugin System
Plugins can extend the API by adding new queries and mutations dynamically:
Using Plugins
Static Generation (CLI)
For better performance, plugins can pre-generate their queries/mutations at build time:
# Generate static queries/mutations from plugins npx deesse generateThis creates a generated folder with:
Client SDK Usage
After setting up the server, clients can use the auto-generated SDK:
Or with React hooks (see #51 for automatic cache revalidation):
Cache key system:
HTTP API Endpoints
The auto-generated endpoints:
Summary
Single definition, Multiple execution modes, Plugin system, Automatic cache management
Questions
Related Issues
References