Stone.js: your app exists in every runtime, until you run it

작성자

카테고리:

← 피드로
DEV Community · Mr. Stone · 2026-07-23 개발(SW)
Cover image for Stone.js: your app exists in every runtime, until you run it

Mr. Stone

The rewrite tax

Count the versions of your last real-world app. There is the Express or Nest version for the server. The handler you extracted and mangled for Lambda. The API routes you re-declared when the frontend moved to Next. And now someone is asking for an MCP server so agents can use it.

Same domain logic. Four incarnations. Every framework you picked made you pay this tax, because every framework has a home runtime and your code belongs to it.

Stone.js starts from the opposite premise: an application is not an object, it is an act. Application = Domain x Context. You write the domain once; the context (server, function, browser, agent) applies itself to your domain at runtime, not the other way around.

Show me

A domain is just classes or functions. No base class, no framework import in your business logic:

import { Service } from '@stone-js/core'
import { IncomingHttpEvent } from '@stone-js/http-core'
import { Get, Post, EventHandler } from '@stone-js/router'

@Service({ alias: 'tasks' })
export class TaskService {
  private readonly items: Task[] = []

  list (): Task[] { return this.items }
  add (title: string): Task { /* ... */ }
}

@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()
  }
}

Enter fullscreen mode Exit fullscreen mode

Where does it run? That is not the domain’s problem. It is declared once, at the edge of the app:

@NodeHttp()       // a Node HTTP server
@AwsLambdaHttp() // an API Gateway handler
@Routing()
@StoneApp({ name: 'tasks' })
export class Application {}

Enter fullscreen mode Exit fullscreen mode

Each decorator is an adapter: it captures the platform’s raw event (an IncomingMessage, a Lambda payload), normalizes it into one IncomingEvent, and turns your response back into whatever the platform expects. Your controller never learns which one ran. stone run collapses the superposition into the target you deploy.

Adapters today: Node HTTP, AWS Lambda, Azure Functions, GCP Cloud Functions, Tencent SCF, Alibaba FC, edge/fetch runtimes, browser, CLI, WebSockets. One domain, any of them.

Allergic to decorators? Same parity, no decorators

Every single feature exists in two first-class forms, decorators or plain functions. Not a fallback, a parity contract:

import { defineEventHandler, defineRoutes } from '@stone-js/router'

const TaskController = ({ tasks }) => ({
  list: (event) => tasks.list()
})

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

Enter fullscreen mode Exit fullscreen mode

The decorators are TC39 2023-11 stage 3 (Symbol.metadata), not experimentalDecorators, and there is no reflect-metadata anywhere. ESM only.

The part nobody else does: agent-native

Your app can expose itself to AI agents. In development, stone mcp starts an MCP server that lets your coding agent introspect the app it is working on (routes, services, blueprint, framework knowledge). And the same adapter mechanism that serves HTTP can serve your domain to agents as tools. The fourth rewrite is the one you skip.

Is it real?

Numbers you can verify, not adjectives:

  • 40+ packages under @stone-js/* (MIT), a micro-kernel that depends on exactly 3 of them
  • 99% test coverage, enforced per package; public quality gate on SonarCloud
  • Zero known dependency vulnerabilities
  • 118 documentation pages, a generated API reference, 14 starters
  • The docs site is itself a Stone.js app (SSG mode), dogfooding included

What beta means here

The API is settled enough that I document both paradigms for everything, and unstable enough that your feedback can still bend it. That is exactly the window where trying a framework is the most fun.

I am looking for a dozen pilots: developers, architects, QA. Build something small, break it, tell me everything that hurts. You get direct access to me and founding-tester credit.

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

Happy Entanglement. 😎

원문에서 계속 ↗

코멘트

답글 남기기

이메일 주소는 공개되지 않습니다. 필수 필드는 *로 표시됩니다