@mika/undercurrent (1.0.0)
Installation
@mika:registry=npm install @mika/undercurrent@1.0.0"@mika/undercurrent": "1.0.0"About this package
Undercurrent
Undercurrent is the reference server implementation for the server side of Blackcurrant.
It helps an Express application expose selected Postgres-backed resources through the Blackcurrant sync, reconciliation, mutation, and server-manifest protocol. The app still owns authentication, domain rules, non-synced tables, and server-side Postgres migrations.
Undercurrent is not the authoritative source for the Blackcurrant protocol.
When protocol behavior is in question, use ../../blackcurrant/main.
Protocol References
Read these first when wire behavior is in question:
../../blackcurrant/main/README.md: Blackcurrant client runtime overview.../../blackcurrant/main/WIRE.md: authoritative HTTP and SSE wire contract.../../blackcurrant/main/SERVER.md: server implementation guide.../../blackcurrant/main/requirements/: client-side requirements that exercise the server-facing contract.
Undercurrent documentation should link to those files instead of duplicating Blackcurrant protocol rules.
What It Solves
Undercurrent gives apps a conventional way to:
- serve
GET /sync/<visibility>/<seq>?version=<runtime-version> - serve
POST /reconciliation/<seq>?version=<runtime-version> - generate the Blackcurrant server manifest for the current app version
- expose resource mutation routes
- write managed Postgres rows and journal entries in one transaction
- build compact sync frames from a durable journal
- reconcile complete visible object sets
- track principal visibility versions
- coordinate open sync streams with app auth routes
- export OpenAPI fragments for managed routes
Postgres remains the application database. Undercurrent only manages resources registered with it.
Sketch
import express from "express"
import postgres from "postgres"
import { Undercurrent } from "undercurrent"
const app = express()
const sql = postgres(process.env.DATABASE_URL)
const undercurrent = Undercurrent({
app,
sql,
version: "2026.05.13",
clientMigrations,
principal: async (req) => req.user ? `user:${req.user.id}` : "anonymous",
})
const users = undercurrent.resource("User", {
optimistic: true,
fields: {
fullName: "text",
phone: "text",
hasPassword: "boolean",
},
privateFields: {
passwordHash: "text",
createdFromIp: "text",
},
visible: ({ sql, principal }) => sql`
select "id"
from "Users"
where ...
`,
})
users.modify(async (object, ctx) => {
if (ctx.principal !== "superadmin1337") {
throw ctx.forbidden("I don't want you to do that.")
}
return {
...object,
fullName: object.fullName.trim(),
}
})
await undercurrent.ready()
This is a v1 design sketch. See API.md for the proposed API surface.
HTTP Paths
The summaries here are orientation only. Use
../../blackcurrant/main/WIRE.md for exact request and response contracts.
| Path | Purpose |
|---|---|
GET /sync/<visibility>/<seq>?version=<runtime-version> |
Opens the Blackcurrant SSE stream. The first data message is terminal versionRequired or accepted manifest; accepted streams then establish hello and send compact frames or reconciliation. |
POST /reconciliation/<seq>?version=<runtime-version> |
Repairs the client's complete visible object set from retained authoritative ids and returns the new frontier as streamed NDJSON. |
POST <resource-path> |
Accepts a full-object add mutation for one explicitly enabled resource create operation. |
PUT <resource-path>/<id> |
Accepts a full-object modify mutation for one explicitly enabled resource modify operation. |
DELETE <resource-path>/<id> |
Accepts a delete mutation for one explicitly enabled resource delete operation. |
Login, logout, session management, uploads, and other application-specific
endpoints belong to the host application. They can still use
undercurrent.write(...) when they need to mutate managed resources.
Documents
| Path | Purpose |
|---|---|
ARCHITECTURE.md |
V1 architecture, component responsibilities, and data flow. |
API.md |
Proposed Undercurrent application API. |
SCHEMA.md |
Postgres, resource, manifest, and serialization schema contract. |
UPGRADING-2X.md |
Initial migration guidance for Kotte/Blackcurrant 2.x-style servers. |
AGENTS.md |
Agent-specific repository instructions. |
WORKFLOW.md |
Staged change workflow for requirement-bearing work. |
VERIFICATION.md |
Local verification model, requirement domains, and proof rules. |
DECISIONS.md |
Durable project decisions. |
requirements/ |
Undercurrent requirements, once behavior is specified. |
changes/ |
Per-change staged workflow artifacts. |
test/ |
Canonical executable proof, once implementation work begins. |
Related Prior Work
../../kotte contains a production server for an earlier Blackcurrant
2.x-style sync protocol. It is useful migration context, especially for
journal-backed sync, route/model separation, Postgres notifications, and
visibility repair operations. It is not authoritative for Blackcurrant 3
behavior.
Dependencies
Dependencies
| ID | Version |
|---|---|
| express | ^5.2.1 |
| postgres | ^3.4.9 |
| yaml | ^2.9.0 |