stable

Service layers

The eleven with-* folders that group services in the hub source tree — a folder bracket, not a runtime seam.

Mirrors the eleven with-*/ folders in packages/hub/src/. The full opt-in catalog — every service with its subpath and with<Name>() factory — is Services.

@noy-db/hub is a minimal always-on core plus opt-in services: tree-shakeable capabilities (history, indexing, blobs, sync, …) that you enable one at a time by passing a with<Service>() factory to createNoydb(). In the source tree those services are grouped into eleven with-<name>/ folders — the service layers. This page explains what a layer folder is, and — just as important — what it is not. The developer-facing view of the same services is the Services catalog.

Layers are a folder grouping, not a runtime seam

A layer (with-<name>/) is the organizational grouping of the with-* units — the service folders, plus the two single-purpose port folders with-cargo and with-pod. It is a soft bracket today; it may later harden into a real plug-in seam, but it is not one now.

Concretely, that means there is nothing in the runtime or code at the layer level: no layer factory, no layer subpath export, no layer API, no withLayer(). A layer is purely the parent folder its service files sit in. Every capability is a per-service unit: each service keeps its own @noy-db/hub/<service> subpath export and its own with<Service>() factory registered at createNoydb(). You never import or configure a layer — only the services inside it:

import { createNoydb } from '@noy-db/hub'
import { withHistory } from '@noy-db/hub/history' // lives in with-commit/
import { withIndexing } from '@noy-db/hub/indexing' // lives in with-lookup/

const db = await createNoydb({
  user: 'me',
  historyStrategy: withHistory(),
  indexingStrategy: withIndexing(),
})
// → two services from two different layers, wired identically per-service;
//   "with-commit" and "with-lookup" never appear anywhere in application code

The eleven layers

Each layer folder groups services with a common intent (see the Services catalog for every service with its subpath, with<Name>() factory, and cost). Two layers (with-cargo, with-pod) are single-purpose ports — contract subpaths an external consumer binds — rather than service groupings; see Ports.

LayerGroups<service>/ subfolders
with-auditTime, audit & compliance — attestation, consent logging, erasure, write guards, accounting periods, data portabilityattestation, consent, forget, guards, periods, portability, sealed-record, tiers
with-cargoThe /cargo port — the multi-vault orchestration seam bound by klum-db, the control plane that manages a fleet of vaultsflat files (active.ts, adopt-partition.ts, decrypt-partition.ts, describe-extraction.ts, extract-partition.ts, strategy.ts, vault-diff.ts, walk-closure.ts) — no service subfolders
with-commitWrite & mutate — transactions, versioning/history, CRDT merge, sequencescrdt, history, numbering, sequence, tx
with-forkSnapshot & portability — checkpoints, archives, read-only framesarchive, shadow, snapshots
with-formulaDerived data — computed fields, derivations, materialized views, overlay viewscomputed, derivations, materialized-views, overlay-views
with-lookupRead & query — persisted indexes, search, aggregation, embeddingsaggregate, embeddings, indexing, search
with-partyPrincipals — who you are, what you may do, how you prove it: teams, sessions, policy, custody, the credential brokerauth-introspection, broker, custody, directory, policy, session, team
with-podThe /pod port — serialize/save a vault as the .noydb artifact (the encrypted container format used for backup and transport)flat files (backup.ts, bundle.ts, format.ts, pod-store.ts, ulid.ts) — no service subfolders
with-shapeData shape — binary attachments, links, schema introspection & updates, satellites, persisted schemasblobs, introspection, links, persisted-schemas, satellites, schema-update
with-storeStore operations — combinators over the store contract, not a store adapter itselflazy (+ flat route-store.ts, store-middleware.ts)
with-syncReplication — moving state between stores and between browser contexts: the sync engine, strategy, presence, sync transactions, tab coordinationflat files (active.ts, credentials.ts, engine.ts, period-scope.ts, presence.ts, strategy.ts, tab-coordination.ts, tab-write-relay.ts, transaction.ts) — no service subfolders

with-store is worth a specific callout since it's easy to confuse with the /to port: /to (port/to/) is the contract door — a behavior-free re-export barrel that a to-* storage package binds. with-store is a service of combinators over that contract — routeStore (multiplex by collection/size/age) and store middleware (withRetry, withCache, withCircuitBreaker, …), each mapping NoydbStore → NoydbStore. Its audience is application authors composing stores; a store author never touches it. See Ports → Imports point inward only for the door-stays-behavior-free rule this split enforces.

with-sync is the newest layer, and the reason it exists is the cleanest illustration of what a layer is for: with-party describes principals, while sync replicates state — two different concerns that had been filed under one bracket. Since 0.4.0-pre the sync engine, strategy, presence and sync transactions live in with-sync/, along with tab coordination and the tab write relay (which coordinate browser contexts of the same user, so they were never a party concern either). Nothing about how you use sync changed: the subpath is still @noy-db/hub/sync and the factory is still withSync(). One narrow import path did change — @noy-db/hub/team no longer re-exports SyncEngine, SyncTransaction or PresenceHandle; import those from @noy-db/hub/sync, which is where they ship.

Field features live in the top-level via/ folder

The field-feature families — money, i18n, lookup, classified, blob, and computed — are not a with-* service layer. Since 0.3.0-pre.11 they sit in their own top-level via/ folder (packages/hub/src/via/, renamed from the former shape/), one subfolder per feature. A field feature is declared per field through viaFields: { field: via(...) }, not opted into per collection like a service — so it earns its own preposition rather than a with-* bracket. The kernel machinery that runs the phased pipeline and the dependency graph lives in kernel/via; the developer-facing surface is the via page. This is why the with-shape row above no longer lists classified, i18n, or money — those moved into via/ when field features gained their own folder.

Next

The Services catalog is the developer-facing view of the same folders — one page per service, organized by layer, with subpath, factory, LOC cost, and opt-in example. This page is the structural mirror of the source tree; that page is where you go to actually use one.

Families → — the satellite packages these layers' ports (/to, /on, /at, /in, /by, /as) are bound by.