Service layers
Mirrors the eleven
with-*/folders inpackages/hub/src/. The full opt-in catalog — every service with its subpath andwith<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.
| Layer | Groups | <service>/ subfolders |
|---|---|---|
with-audit | Time, audit & compliance — attestation, consent logging, erasure, write guards, accounting periods, data portability | attestation, consent, forget, guards, periods, portability, sealed-record, tiers |
with-cargo | The /cargo port — the multi-vault orchestration seam bound by klum-db, the control plane that manages a fleet of vaults | flat 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-commit | Write & mutate — transactions, versioning/history, CRDT merge, sequences | crdt, history, numbering, sequence, tx |
with-fork | Snapshot & portability — checkpoints, archives, read-only frames | archive, shadow, snapshots |
with-formula | Derived data — computed fields, derivations, materialized views, overlay views | computed, derivations, materialized-views, overlay-views |
with-lookup | Read & query — persisted indexes, search, aggregation, embeddings | aggregate, embeddings, indexing, search |
with-party | Principals — who you are, what you may do, how you prove it: teams, sessions, policy, custody, the credential broker | auth-introspection, broker, custody, directory, policy, session, team |
with-pod | The /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-shape | Data shape — binary attachments, links, schema introspection & updates, satellites, persisted schemas | blobs, introspection, links, persisted-schemas, satellites, schema-update |
with-store | Store operations — combinators over the store contract, not a store adapter itself | lazy (+ flat route-store.ts, store-middleware.ts) |
with-sync | Replication — moving state between stores and between browser contexts: the sync engine, strategy, presence, sync transactions, tab coordination | flat 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.