Files
netris-nestri/packages/core
Wanjohi 01542cf14a feat(session): runs wait in line for a free slot on their host
A host holds only so many runs at once, and until now every waiting run
was handed to it regardless; the ones it could not hold failed there.

The host now says on its heartbeat how many runs it holds, and is handed
only as many waiting runs as it has free. The rest wait in line: paid
runs before free-weekend runs, then first come first served. Reading a
waiting run returns its place in line, and says when a paid run that
asked later has gone ahead, so a free player is never reordered quietly.

A waiting run nobody has asked after for a minute was abandoned, and
leaves the line rather than holding up everyone behind it. A host that
does not report its slots is handed every run, as before.
2026-10-11 13:53:00 +03:00
..
2026-08-06 22:13:51 +03:00
2026-08-06 22:13:51 +03:00

packages/core

@nestri/core — the domain layer for Nestri. All business logic, database access, and serialization lives here. The API and auth workers are thin pass-through translation layers on top.

What it contains

Area Files Purpose
db db/index.ts, db/types.ts, db/test.ts Drizzle + Postgres (Database.use/transaction), ULID column helpers
users user/* Users, linked accounts, fingerprints, library
teams team/* Teams + membership with roles (team_member)
games game/* Game catalog, depot content, per-host downloads
steam steam/index.ts Steam API integration & SSH identity resolution
auth auth/subjects.ts JWT subjects shared with the auth worker
infra env.ts, context.ts, actor.ts, fn.ts, id.ts, error.ts, examples.ts Environment, Actor model, zod-typed fn() wrappers, IDs, error types, examples
migrations migrations/ Drizzle-kit SQL migrations for Postgres schema

Conventions

  • Domain namespaces (user/, team/, ...) expose typed fn() functions that validate input with a Zod schema and serialize DB rows inside the function boundary — the API routes never see raw table rows.
  • Actor model: Actor.userID, Actor.type, ... pull the current authenticated identity from AsyncLocalStorage (set by the API middleware / auth worker) without passing it through call chains.
  • Soft delete: every table has time_deleted; queries filter with isNull(table.timeDeleted).
  • IDs: ULIDs via Identifier.ascending('user') → usr_....
  • Tables are defined in *.sql.ts files (drizzle) with namespaces in index.ts.
  • Environment is read through Env.get(), init by worker bindings.

Structure

src/
├── actor.ts, env.ts, id.ts, fn.ts, error.ts, examples.ts
├── db/
├── auth/
├── user/       (user.sql.ts, linked-account.*, fingerprint.*, library.*, index.ts)
├── team/       (team.sql.ts, member.*, index.ts)
├── game/       (game.sql.ts, depot.*, download.*, index.ts)
├── steam/      (index.ts)
├── pairing-code/
├── access-token/
└── machine/

Scripts

bun run db:push   # push schema (drizzle-kit)
bun run db        # open drizzle-kit

Usage

import { Team } from '@nestri/core/team/index';
import { Database } from '@nestri/core/db/index';

const team = await Team.fromID('tem_...');