libs/shared/ is the domain-agnostic floor of the platform: the @oshun/*
infrastructure packages that every product (V1–V9), every capability domain, and
every BFF imports rather than re-implements. The tree holds 49 distinct
@oshun/* packages (50 package.json manifests, one of which is the
generated libs/shared/types/dist/ copy of @oshun/types) — @oshun/logging,
@oshun/errors, @oshun/database, @oshun/event-bus, @oshun/identity,
@oshun/crypto, and the rest. What makes them shared is a property the build
enforces and a grep can verify: nothing under libs/shared/ imports a
domain. A search for @oshun/domain-*, memory-iris, evidence-sophia, or
any libs/oshun/ path across the tree returns no production hits. These
packages carry no Oshun-specific knowledge of rituals, lessons, or evidence
packs; you could lift @oshun/event-bus into an unrelated product and it would
still work. That absence of domain knowledge is exactly what makes them safe for
every domain to depend on without creating a cycle.
Each package is a real workspace package wired into tsconfig.base.json with a
path mapping that points at live source —
"@oshun/crypto": ["libs/shared/crypto/src/index.ts"]
(tsconfig.base.json:1406),
"@oshun/event-bus": ["libs/shared/event-bus/src/index.ts"] (:1496), and so
on for all nineteen packages this page covers — so an importer type-checks
against the actual implementation, not a stale dist. This page maps the
foundation by layer: types/errors/config at the bottom, observability and data
above them, eventing and the HTTP/gateway tier, and the security/identity
packages that thread through every request. It is one slab of the stack
described in the platform overview; the database and cache
internals are taken further in Persistence & Data, and
the unified identity model in Auth & Identity.
What ships, honestly#
The shared tree is the most code-complete surface in the repository because the
dependency on it is load-bearing, not aspirational. The packages in scope here
are implemented over real backends, not scaffolds: @oshun/logging is Pino
(libs/shared/logging/src/logger.ts:7,146), @oshun/metrics is prom-client
(libs/shared/metrics/src/registry.ts:7), @oshun/tracing is OpenTelemetry
with an OTLP exporter (libs/shared/tracing/src/tracer.ts:16-31),
@oshun/database opens a real pg Pool
(libs/shared/database/src/postgres-client.ts:7,40), @oshun/event-bus runs on
Redis pub/sub, and @oshun/crypto delegates every primitive to the audited
@noble/* libraries (libs/shared/crypto/src/index.ts:30-49). Most packages
ship a Vitest suite next to their source (*.spec.ts / *.test.ts); the lone
exception is @oshun/errors, which has no test suite today.
Two honesty notes, in the spirit of the repository's no-stub culture and the docs center's implemented / spec-only / provider-gated convention:
@oshun/content-securityis a plan-and-validate layer, not the media executor. Its watermarking and provenance modules are real, deterministic builders and validators — they emit typed embedding commands, C2PA/SynthID plans, and run genuine provenance-graph integrity checks — but the package is versioned0.1.0and the actual pixel/audio embedding runs downstream of the command it produces (libs/shared/content-security/src/watermarking.ts,provenance.ts). It is labeled as such below rather than implied to stamp bytes itself.- The "zero dependency" claim is strongest at the bottom.
@oshun/typeshas no external dependencies at all; most packages depend only on a backend driver. Two privacy packages —@oshun/data-residencyand@oshun/deletion-fanout— additionally import the@oshun/contractsrule tables (libs/shared/data-residency/src/dsr-routing.ts:1). They remain domain-agnostic (a residency zone is not a domain), but they are not zero-dependency the way@oshun/typesis.
Foundation: types, errors, config#
These three packages sit at the very bottom; everything above imports them and they import almost nothing.
@oshun/types is the "ZERO external dependencies" types package
(libs/shared/types/src/index.ts:6). Its load-bearing exports are a
branded-ID pattern —
type ID<T extends string = string> = string & { readonly __brand: T }
(base.ts:21) specialized into UserID, ProjectID, AssetID, SessionID,
CorrelationID, and friends — and a Result union,
type Result<T, E = Error> = Success<T> | Failure<E> (base.ts:112), so a
function can return failure as data rather than throwing. Branding means a raw
string will not type-check where a UserID is required, which catches an
entire class of "passed the project id where the user id goes" bugs at compile
time. The package also carries the base entity mixins (BaseEntity,
SoftDeletable, Versioned, Auditable) and a creative/ sub-barrel
(Script, Character, Storyboard) imported via @oshun/types/creative.
@oshun/errors standardizes failure. Every error descends from OshunError
(libs/shared/errors/src/base.ts:57), which extends the native Error with a
machine-readable code, an HTTP statusCode, structured details, a
timestamp, an isOperational flag (expected/recoverable vs. programmer bug),
and an expose flag that decides whether details reach the client —
defaulting true for 4xx and false for 5xx, so a server fault never leaks
internals. On top of the base sit a full HTTP ladder (BadRequestError …
GatewayTimeoutError, http.ts:17-214) and the domain classes that map to it:
ValidationError, AuthenticationError, TokenExpiredError,
AuthorizationError, ResourceNotFoundError, DuplicateError,
VersionConflictError, RateLimitError, ExternalServiceError,
DatabaseError (domain.ts). Error codes are grouped into closed sets —
AUTH_ERRORS, AUTHZ_ERRORS, RESOURCE_ERRORS, EXTERNAL_ERRORS (codes.ts)
— and utilities like wrapError, isOperationalError, and
createSafeErrorResponse (utils.ts) give every service one consistent way to
wrap, classify, and serialize a failure. AppError is exported as a
Lilith-compatibility alias for the same base class.
import {
ValidationError,
wrapError,
createSafeErrorResponse,
} from '@oshun/errors';
throw new ValidationError('Invalid email format', {
fields: { email: ['Invalid format'] },
});
// later, at the boundary: createSafeErrorResponse(err) → { code, message, statusCode, details? }
// 5xx details are withheld; 4xx details are exposed.
@oshun/config turns environment variables into validated, typed config via
Zod. schemas.ts defines a schema per concern (serverConfigSchema,
databaseConfigSchema, redisConfigSchema, storageConfigSchema,
authConfigSchema, loggingConfigSchema, tracingConfigSchema,
aiConfigSchema, rateLimitConfigSchema), and loader.ts exposes typed
loaders (loadServiceConfig, loadDatabaseConfig, loadRedisConfig,
loadAuthConfig) plus env helpers (getEnvNumber, getEnvBool,
isProduction). A misconfigured service fails loudly at boot — a bad PORT or
a missing DATABASE_URL is a parse error, not a NaN surfacing three hops
later. The package also ships experiment guardrails
(experiment-guardrails.ts, for V1 §28.7): a schema-validated model where each
feature-flag experiment carries guardrail metrics with a closed comparison op
set (lte | lt | gte | gt | between), and evaluateGuardrails decides whether
a ramp must auto-hold.
Observability: logging, metrics, tracing, health#
The four observability packages are emitted at every hop of the request trace in the overview; they share the philosophy of real backends with sane defaults.
@oshun/logging wraps Pino (logger.ts:7) with structured, leveled logging
and — importantly — PII redaction on by default. DEFAULT_REDACT_PATHS
(logger.ts:105) strips password, token, secret, apiKey,
authorization, cookie, creditCard, ssn, and their nested forms before a
line is written, so a careless logger.info('login', { body }) cannot spill
credentials. It ships five transports (console, file, http,
elasticsearch, tcp under transports/), sampling strategies for high-volume
paths (sampling/), and request-logger middleware for Express/Fastify/Koa
(middleware/). Child loggers carry context (logger.child({ requestId })) so
a correlation id rides every line of a request.
@oshun/metrics is Prometheus via prom-client. OshunMetricsRegistry
wraps the registry; createHistogram/createCounter/createGauge and the
global convenience functions emit metrics, and server.ts exposes the
/metrics scrape endpoint. Crucially it ships standard metric-name
vocabularies — HTTP_METRICS, DB_METRICS, CACHE_METRICS, AI_METRICS,
QUEUE_METRICS (types.ts) — plus HISTOGRAM_BUCKETS and
SUMMARY_PERCENTILES presets, so two services do not name the same latency
histogram differently and break a dashboard.
@oshun/tracing is OpenTelemetry: a NodeTracerProvider, the OTLP HTTP
exporter, and an AsyncLocalStorageContextManager (tracer.ts:16-31) that
propagates span context across await boundaries without manual threading.
withSpan('name', async (span) => …) is the ergonomic entry point;
propagation.ts and TRACE_CONTEXT_HEADERS handle W3C traceparent/baggage
and B3 propagation across service hops, with Hono middleware and an X-Ray
adapter alongside.
@oshun/health standardizes the healthy | degraded | unhealthy status
model. HealthManager aggregates registered checks; ProbeManager
(probes.ts) emits the Kubernetes liveness/readiness/startup probe handlers;
and DependencyAggregator with createDatabaseCheck/createRedisCheck
(dependencies.ts) rolls a service's downstream dependencies into one report.
The distinction between degraded and unhealthy matters: a service that lost
a cache but can still serve from the database reports degraded, and the
orchestrator keeps it in rotation instead of killing it.
Data: database and cache#
These two are summarized here and taken further in Persistence & Data.
@oshun/database is the unified data-access surface. postgres-client.ts
opens a real pooled pg Pool (:7,40) with DEFAULT_POSTGRES_CONFIG;
redis-client.ts covers Redis; transaction.ts exposes the
TransactionIsolationLevel ladder; query-builder.ts provides typed
WhereCondition/OrderByClause/PaginationOptions builders; and health.ts,
metrics.ts, migration.ts, and connection-string.ts round out pooling,
observability, and migration. It also retains a legacy-pool.ts /
legacy-migrations.ts compatibility surface for older callers.
@oshun/cache is more than a Redis wrapper — it is a small reliability
toolkit. Beyond CacheClient and the with-cache.ts getOrFetch read-through
helper, it ships an OshunCircuitBreaker (circuit-breaker.ts:39, with a
CircuitOpenError) so a flapping cache fails fast instead of piling up
timeouts, and an OshunLockManager distributed lock (distributed-lock.ts:193)
built on atomic SET NX PX with Lua-scripted release/extend that only acts if
the caller still owns the lock (:104,143) and a clock-drift safety margin
(:82). A LockExpiredError is raised if a held lock lapses
mid-critical-section, and an auto-renew timer can extend a lock under a long
job. pubsub.ts, invalidation.ts, memory-cache.ts, and key-builder.ts
(with the TTL / DOMAIN_TTL presets) complete the package.
Eventing: the cross-domain event bus#
@oshun/event-bus is how domains talk without importing each other. It is a
Redis pub/sub bus with a typed envelope (event-bus/src/types.ts:24):
interface EventEnvelope<T = unknown> {
id: string;
type: string; // e.g. 'isis.asset.generated'
source: DomainScope; // owning domain
targets?: DomainScope[]; // empty = broadcast
correlationId?: string; // request trace
causationId?: string; // parent event
payload: T;
timestamp: number;
version: string; // schema version
metadata?: Record<string, unknown>;
}
The source/targets use a closed DomainScope union —
yemaya | lilith | isis | sophia | hathor | bellona | aphrodite | asase | oshun
(types.ts:10-19), the monorepo-wide engine domains, with oshun reserved for
shared infrastructure. Handlers receive an EventContext with explicit
lifecycle control — ack(), nack(delay?), deadLetter(reason), reply(),
and publish() (types.ts:58) — so at-least-once delivery is the caller's
choice, not an accident. RetryConfig supports exponential | linear | fixed
backoff (types.ts:90-101) and DeadLetterConfig bounds retention and entry
count. A versioned topic registry (topic-registry.ts) pins each topic to
an owner domain and payload name — EventTypes.ISIS_ASSET_GENERATED is owned by
isis (topic-registry.ts:189), OshunV1EventTopics enumerates the
job-lifecycle topics — and a registry-enforcement mode rejects an unregistered
topic at publish time rather than letting a typo become a silent dead channel.
outbound-delivery.ts adds Ed25519-signed webhook delivery
(signOutboundEvent/ verifyOutboundSignature, with computed backoff) for
events that leave the platform, and webhook-simulator.ts lets a consumer test
its endpoint offline.
HTTP and gateway: http-client and gateway#
@oshun/http-client is the resilient outbound HTTP surface, and its most
security-load-bearing module is the SSRF / egress guard
(http-client/src/ssrf-guard.ts). It is deliberately two-phase to defeat
DNS-rebinding (time-of-check vs. time-of-use): assertUrlAllowed checks scheme,
port, host shape, and bare-IP literals before DNS, and
assertResolvedAddressAllowed re-checks the resolved address after DNS but
before the socket connects (ssrf-guard.ts:9-14). The default policy refuses
non-http(s) schemes, private/loopback/link-local/multicast IPs (with
classifyIpv4/classifyIpv6 covering 10/8, 127/8, 169.254/16,
172.16–31, 192.168/16, CGNAT 100.64/10, IPv6 fe80::/10, fc00::/7,
::1, and IPv4-mapped forms), embedded credentials, and ports outside an
allow-list of 80/443. Cloud metadata endpoints — 169.254.169.254 (AWS
IMDS) and metadata.google.internal — are in the always-blocked list
(:72-78). Callers configure an explicit allowedHosts list for trusted
webhook targets. Around that, the client layers retries (retry.ts), a circuit
breaker (circuit-breaker.ts), interceptors, timeouts, idempotency keys
(idempotency.ts), tenant-context propagation (tenant-context.ts), and
tracing; createResilientHttpClient wires the resilient defaults in one call.
@oshun/traefik-config generates the edge configuration rather than running
a gateway itself. It models services and routes through fluent builders
(ServiceBuilder, RouteBuilder, GatewayConfigBuilder, config.ts), carries
per-domain service/route tables (YEMAYA_SERVICES, ISIS_ROUTES,
SOPHIA_SERVICES, LILITH_ROUTES, SHARED_ROUTES … domains.ts), and emits
Traefik static and dynamic configuration via generateStaticConfig/
generateDynamicConfig/generateTraefikConfigs (traefik.ts), with a cli.ts
to render the files. This is the source of truth for which upstream a public
route reaches; the runtime backend-for-frontend tier that sits behind it is
documented in BFF & Gateway.
Security and identity#
These packages thread through every layer — the BFF authenticates with them, the domain libs authorize with them, the data layer enforces residency with them. This section is the substrate-level view; the unified session/consent/RBAC model is in Auth & Identity.
@oshun/identity is the JWT and authorization core. JwtService
(identity/src/jwt.ts:41) mints access/refresh/API-key/service tokens with
iss/aud/exp/nbf set, and verifyToken checks expiry, not-before,
issuer, and audience explicitly (:222-255) rather than trusting the library
default. Authorization is a concrete RBAC model: an eight-rung UserRole
hierarchy
(guest → user → creator → pro → team → enterprise → admin → super-admin,
types.ts:10-31), a PERMISSIONS table of namespaced grants
(projects:create, assets:read, generate:image, worlds:publish,
knowledge:ingest, admin:users …, types.ts:219), and ROLE_PERMISSIONS
mapping each role to its permission set. hasRole, hasPermissions,
hasAnyPermission, and getPermissionsForRole (middleware.ts) are the
checks; authenticate returns a 403 when a required permission is missing. It
also ships mTLS identity (mtls.ts — parsePeerCertificate,
verifyForwardedClientCert) for service-to-service trust and node:http
helpers.
@oshun/auth-primitives is the lower-level credential toolbox @oshun/auth
composes: JWT sign/verify with a JWKS model, API keys, OAuth client and token
revocation, password hashing/validation with a configurable policy, sessions
with device info, refresh-token rotation, tenant isolation, token audit, and
TOTP plus backup codes for MFA (auth-primitives/src/totp.ts,
password.ts, oauth-revoke.ts, session.ts). @oshun/auth assembles
these into an AuthService (auth/src/service.ts) handling registration,
login, and refresh — including an AccountLockoutManager (lockout.ts) — over
injected repository ports (IUserRepository, ITokenRepository,
IAuditRepository). The logic is real; persistence is the caller's to bind,
which is what keeps the package domain-agnostic.
@oshun/crypto is the single cryptographic surface, by design: "the only
entrypoint internal Oshun code should use" with "zero in-house crypto"
(crypto/src/index.ts:5-17). Every primitive delegates to the audited
@noble/* libraries — sha256/sha512/keccak256/blake3, secp256k1
sign/verify/recover (with Ethereum-address recovery), ed25519, AES-GCM,
ChaCha20-Poly1305, HMAC, the KDF family hkdf/pbkdf2/scrypt/argon2id,
ECDH over secp256k1 and x25519, and randomBytes. The single-import discipline
means a security audit greps one surface instead of chasing per-domain
re-derivations. It also ships pluggable keystore/ (local, AWS KMS, GCP KMS,
Azure Key Vault) and secrets/ (local, AWS/GCP/Azure secrets managers) backends
behind common interfaces.
@oshun/data-residency decides whether a proposed cross-zone data transfer
is allowed. ResidencyEnforcementService (enforcer.ts:144) is an
intentionally I/O-light, stateless evaluator: it reads the
OSHUN_DATA_RESIDENCY_RULES table from @oshun/contracts (zones
eu | uk | us | ca | latam | apac | global,
libs/contracts/src/common/data-residency-rules.ts:86), evaluates a transfer
against the rule plus any acknowledged mechanism (SCC, IDTA, DPF, explicit
consent), and emits a canonical audit event through an injected publisher.
enforce() throws ResidencyEnforcementError when outcome.block is true;
evaluate() returns the outcome for callers that want to branch. Storage
routing (which shard, which pool) lives upstream — the enforcer only renders the
verdict. It also ships DSR routing, home-zone resolution from a claim,
traffic-shaping, and the residency request headers.
@oshun/deletion-fanout is the shared account-deletion core, scope:shared
so any domain can run its own deletion consumer against the bus rather than
routing everything through the BFF (deletion-fanout/src/index.ts). It defines
the per-service DeletionServiceEraser port over a closed set of erasable
scopes (memory_scope, voice_profile, avatar_pack, generated_artifact,
personalization_vector, conversation_history, deletion-fanout.ts:23), and
— critically — produces an Ed25519-signed DeletionAttestation per service.
canonicaliseDeletionAttestation builds unambiguous bytes prefixed
oshun.deletion.attestation.v1 (:81-96), the signer signs them with
@noble/curves/ed25519, and verifyDeletionAttestation re-derives the
canonical bytes and checks the signature. The fan-out is fail-closed: an
overall complete is only reported when every service attests, so a
partially-completed erasure cannot masquerade as a finished
right-to-be-forgotten request. An event-driven orchestrator, a Redis transport,
the domain consumer registration, an env-resolved signer, and a runner
composition root complete the package.
@oshun/content-security models content provenance and forensic
watermarking. As flagged above it is a plan-and-validate layer (v0.1.0):
watermarking.ts emits typed WatermarkEmbeddingCommands and robustness test
suites for video/audio/image/document; provenance.ts builds C2PA
content-credential plans and SynthID watermark plans and tracks a provenance
chain. The genuinely computational piece is validateProvenanceChainIntegrity
(provenance.ts), which verifies a provenance graph by checking for missing
node references, orphan nodes, cycles (detectCycle), and a recomputed
integrityDigest over the canonicalized chain — a real graph-integrity
validator, not a stubbed true. The byte-level embedding the commands describe
is performed by an executor outside this package.
How the foundation connects to everything else#
The shared tree is the bottom of the dependency direction the build enforces, and the connections out of it are deliberate:
- Up into domain orchestration —
libs/oshun/composes these packages into product behavior: a domain service logs through@oshun/logging, persists through@oshun/database, emits and consumes through@oshun/event-bus, and authorizes through@oshun/identity. See Domain Orchestration. - Sideways into contracts — most shared packages depend on nothing
domain-shaped, but
@oshun/data-residencyand@oshun/deletion-fanoutimport the@oshun/contractsrule/zone tables, the one allowed reach from infrastructure into the shared vocabulary. See Contracts. - Down into persistence —
@oshun/databaseand@oshun/cacheare the only packages that hold real connections to Postgres/Redis; the residency and deletion machinery layered on top is the subject of Persistence & Data. - Through every request —
@oshun/identity/@oshun/authat the front,@oshun/http-client's SSRF guard on every outbound call, the observability trio on every hop, and@oshun/cryptowherever a signature or hash is needed.
The nineteen packages above are the layered core. The remaining libs/shared/
packages — @oshun/storage, @oshun/queue, @oshun/websocket,
@oshun/rate-limit, @oshun/service-discovery,
@oshun/ai/@oshun/ai-advanced, @oshun/ml, @oshun/ocr, @oshun/encoding,
@oshun/audit-platform, and others — extend the same floor with the same
discipline: real backends, injected boundaries, no domain knowledge, one
canonical home. Because they are written once and imported everywhere, a change
to how the platform logs, traces, authorizes, or signs is a single edit every
product inherits at once — which is the entire point of having a shared
foundation rather than nine of them.
Related#
- The Shared Platform — the platform framing and layered model this page fills in.
- Domain Orchestration —
libs/oshun, the service layer that composes these packages into product capability. - Contracts — the Zod vocabulary the privacy packages read and every boundary validates against.
- BFF & Gateway — the runtime tier behind the gateway config
@oshun/traefik-configgenerates. - Persistence & Data —
@oshun/database/@oshun/cacheand the residency, migration, and deletion machinery in depth. - Auth & Identity — the unified identity, session,
consent, and authorization model
@oshun/identity/@oshun/authunderpin.