Reference · Building on Notato

Docs › Reference

Building on Notato

Extend the server and board with your own storage, accounts and screens.

Building on Notato#

The server is a library as well as a command. runServe takes a ServerExtension, which is how a hosted product (Notato Cloud is one) is built on the same server instead of a copy of it: annotations, MCP, relay, webhooks and the event streams are the server's own, and the extension brings what differs.

import { runServe, type ServerExtension } from "@notato/server";

const extension: ServerExtension = {
    name: "my-deployment",
    store: () => new MyPostgresStore(url),            // notes, projects and accounts
    blobs: () => new MyObjectStore(bucket),           // screenshots
    hooks: ({ store }) => ({ beforeIngest: (note, bytes) => checkQuota(store, note, bytes) }), // throw a RequestError to refuse
    auth: ({ store }) => new MyAccounts(store),       // who is signed in: admins, members, tokens
    http: ({ backend, auth }) => ({
        routes: { private: [extraRoutes], public: [callbackRoute], isPublic: (_m, p) => p === "/callback" },
        around: (request, next) => audit(request, next),   // wraps every request once its credential is known
    }),
    mcp: () => ({ requireToken: true, maxSessions: 128 }),
    start: (runtime) => startWorkers(runtime),        // returns how to stop them
};
await runServe({ version, extension });

The extension's parts are made in stages. Later stages receive the parts already made:

PartWhat it supplies
store, blobsRecords and accounts through Store & AuthStore, and screenshots through BlobStore; the defaults are SQLite and files
configA ConfigSource wrapping the settings file
hooksChecks before backend changes, such as refusing a note or project that would exceed a limit
backendAn optional LocalBackend subclass, made with the assembled store, blobs, config and hooks
authAn AuthProvider; replacing it also takes over account creation from the built-in admin login
httpExtra routes and rules for the built-in ones, authorization, middleware, allowed origins, headers, CSP and upload limits
mcpSession limits, a guard, a token requirement, tool auditing, and how a locked credential is refused
fetchA wrapper around every request, including MCP, before the HTTP handlers
startBackground work after the server starts, returning an optional stop function run before the store closes