Stone.jsDocs
Paradigm

Start here

Why Stone.js

Most frameworks make you choose a runtime first: a server framework, an edge framework, a frontend framework. You wire your logic to that choice, and the day the runtime changes, you rewrite. Stone.js inverts the order. You write the domain. The context comes to it.

#The claim

An application is not an artefact you build for one place. It is an act: a domain, meeting a context, resolving into a response. Stone.js is the context. You keep the part that is yours, the what, and defer the part that is the platform's, the where, until the last responsible moment: run time.

Application = Domain × Context → Resolution
The Continuum Architecture

Two words carry this whole site, so let us pin them down before going further, in the plainest terms, with an everyday example.

#The same domain, everywhere

Keep an eye on this handler; it comes back a lot. Written once, it serves an HTTP API on Node; the exact same class ships to a Lambda, to a Cloudflare Worker, or becomes a tool an AI agent can call. Nothing below the domain leaks into it.

declarativeimperative
import { Service } from '@stone-js/core'

interface Task { id: string, title: string, done: boolean }

// A service, injected by its alias. Pure domain: no HTTP, no platform.
@Service({ alias: 'tasks' })
export class TaskService {
  private readonly items = new Map<string, Task>()

  list (done?: boolean): Task[] {
    const all = [...this.items.values()]
    return done === undefined ? all : all.filter((t) => t.done === done)
  }

  add (title: string): Task {
    const task: Task = { id: crypto.randomUUID(), title, done: false }
    this.items.set(task.id, task)
    return task
  }
}
import { defineService } from '@stone-js/core'

// A factory service, bound to the alias 'tasks'.
const TaskService = () => {
  const items = new Map()
  return {
    list: (done) => [...items.values()].filter((t) => done === undefined || t.done === done),
    add: (title) => {
      const task = { id: crypto.randomUUID(), title, done: false }
      items.set(task.id, task)
      return task
    }
  }
}

export const services = [defineService(TaskService, { alias: 'tasks' }, true)]
import { IncomingHttpEvent } from '@stone-js/http-core'
import { Get, Post, EventHandler } from '@stone-js/router'

@EventHandler('/tasks')
export class TaskController {
  private readonly tasks: TaskService
  constructor ({ tasks }: { tasks: TaskService }) { this.tasks = tasks }

  @Get('/')
  list (event: IncomingHttpEvent): Task[] {
    return this.tasks.list(event.get<boolean>('done'))
  }

  @Post('/')
  create (event: IncomingHttpEvent): Task {
    return this.tasks.add(event.get<string>('title', 'Untitled'))
  }
}
import { defineEventHandler, defineRoutes } from '@stone-js/router'

// A factory handler: the container hands it the resolved 'tasks' service.
const TaskController = ({ tasks }) => ({
  list: (event) => tasks.list(event.get('done')),
  create: (event) => tasks.add(event.get('title', 'Untitled'))
})

export const routes = defineRoutes([
  [defineEventHandler(TaskController, 'list'),   { path: '/tasks', method: 'GET' }],
  [defineEventHandler(TaskController, 'create'), { path: '/tasks', method: 'POST' }]
])

Two ways to write it, declarative and imperative, at strict parity. Pick one with the switch in the header; every example on the site follows your choice.

#Where this goes next

Foundations is the architecture itself, the part that holds no matter where the code runs. Contexts follows a single domain as it collapses into backend, frontend, edge and agents. Build turns those ideas into real applications, one recipe at a time. Frontier is where the framework goes next.


Stone.js

Your app exists in every runtime. Until you run it.

An open-source project by Stone Foundation
Created by Mr. Stone (Evens Pierre)