ecosy
Documentation

ecosy

Packages for building an application, two frameworks built on them, and forks carrying fixes upstream has not released. Each one stands alone.

yarn add @ecosy/core
app/api/users/[id]/route.ts
import { Route, NotFound } from "@ecosy/next";

export const GET = Route({ users: Users })
  .get(async (ctx) => {
    const user = await ctx.users.byId(ctx.params.id);
    if (!user) throw new NotFound("No such user");
    return user;
  });

What it is

Seventeen packages, each solving one problem and installable on its own. Most carry no dependencies at all; the ones that do depend on another package here, and say so on their own page. Nothing pulls in a framework you did not ask for.

One idea runs through all of it

A function returns a class, not an instance. Configuration is a chain, and the chain has no terminal — a half-configured chain and a finished token are the same thing, so it drops straight into an injector.

export const Vendor = Pack(EsmAdapter)
  .mount("/services/vendor")
  .fetch(HttpFetcher)
  .cache(DiskCache(".cache"));

// Vendor is a class. Nothing to call, nothing to await.
export const { GET } = Route({ vendor: Vendor }).get(async (ctx) => {
  return ctx.vendor.resolve(ctx.params.path);
});

Ports, not imports

Cacher, Fetcher, Searcher, Hook and Coordinator are structural interfaces with two or three methods. An application that already owns a cache or an HTTP client satisfies them without importing anything from here — which is what keeps the packages free of each other.