You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
dev 1f8015f2fe
Bloque L4 — active-app: defineActivePrefs + consumer wiring
5 months ago
..
active-app Bloque L4 — active-app: defineActivePrefs + consumer wiring 5 months ago
adom Bloque A — sweep stale aliases and `App.<Capitalized>` references 5 months ago
auth Bloque A — sweep stale aliases and `App.<Capitalized>` references 5 months ago
bus Bloque A — sweep stale aliases and `App.<Capitalized>` references 5 months ago
cache Bloque A — sweep stale aliases and `App.<Capitalized>` references 5 months ago
connection Bloque F1+F2 — connection backoff random + reauth singleflight 5 months ago
format Bloque L1 — prefs foundation: capability libs + Source<T> port 5 months ago
frontend Bloque L1 — prefs foundation: capability libs + Source<T> port 5 months ago
http Bloque H6 — http per-attempt observability 5 months ago
lang Bloque J1+J2+J3 — P3 polish: lang Set, frontend validators, sium CodeError 5 months ago
logger Bloque H1+H2 — logger onInternalError + clock/idFactory injection 5 months ago
orca Bloque A — sweep stale aliases and `App.<Capitalized>` references 5 months ago
perm Bloque A — sweep stale aliases and `App.<Capitalized>` references 5 months ago
prefs Bloque L3 — arts/prefs adapters: browser-env + server-env + storage bridge 5 months ago
session Bloque I5 — session broadcastChannel: false explicit opt-out 5 months ago
sium Bloque J1+J2+J3 — P3 polish: lang Set, frontend validators, sium CodeError 5 months ago
storage Bloque F3+F4 — format Rates clock injection + storage dynamicEntry guard 5 months ago
timer Bloque H3 — official createFakeTimerClock() exported from \$timer 5 months ago
README.md Bloque A — sweep stale aliases and `App.<Capitalized>` references 5 months ago

README.md

arts — runtime artifacts

src/arts/ contains the runtime building blocks of the application. Each artifact is independent, has its own README, and follows two consistent naming conventions:

  • Engine* — public methods over private state (or no state at all). Pure factory; the locale, logger or any volatile input is passed as argument on every call. When an artifact has a true server-authoritative counterpart (perm, cach), the engine lives under src/svrs/.
  • Active* — an Engine* that exposes public reactive state. Lives in a .svelte.ts file because it owns $state. Imports must target the file directly, not the barrel, to keep the rest of the artifact runes-free.

ActiveEngine Contract

Root active artifacts implement the shared ActiveEngine<TSnapshot, TError> contract from $libs/active:

interface ActiveEngine<TSnapshot, TError> {
	readonly loading: boolean;
	readonly lastError: TError | null;
	readonly disposed: boolean;

	snapshot(): TSnapshot;
	clearError(): void;
	onChange(listener: (snapshot: TSnapshot) => void): () => void;
	dispose(): void;
}

Conventions:

  • Use direct getters (Auth.current, Cache.loading, Perms.lastError), not a module-specific .state object.
  • Use loading, never pending, for in-flight work.
  • Use onChange() for snapshot subscriptions. Lower-level clients may expose their own event buses, but active roots keep this name.
  • dispose() is idempotent, clears owned listeners/entries/resources, and subsequent public operations throw the artifact's XxxDisposedError.
  • Root active artifacts that create entries (ActiveCache.entry(), ActiveConnections.connection(), etc.) own those entries and dispose them when the root is disposed.

Logger And Diagnostics Contract

Every artifact that emits runtime information follows the same two-layer contract:

import type { DiagnosticEvent, Diagnostics, Logger } from '$libs/logger';
  • Public options use logger?: Logger. Do not create artifact-local logger interfaces or narrowed aliases for individual modules.
  • The root logger implementation is EngineLogger from $logger; it extends the shared Logger contract from $libs/logger.
  • Artifact code defines <Artifact>Diagnostics with create<Artifact>Diagnostics(logger?) and emits catalogued events for internal diagnostics.
  • Diagnostic event names live in the artifact consts.ts as *_DIAGNOSTIC_EVENTS. Messages live in errors.ts or consts.ts, never as inline strings in runtime logic.
  • Diagnostics<TEvent> always exposes { logger, emit(event) }. The logger property is the common Logger, so modules that need an ad-hoc info or error still have the full logger without inventing a second interface.
  • Level routing is controlled by the logger/transports via the existing per-level enablement map, not by module-specific severity systems.

Typical shape:

export const HTTP_DIAGNOSTIC_EVENTS = {
	REQUEST: 'http.request',
	NETWORK_ERROR: 'http.network_error'
} as const;

export function createHttpDiagnostics(logger?: Logger): HttpDiagnostics {
	return createCatalogDiagnostics({
		logger,
		defaultCategory: LOGGER_CATEGORY,
		catalog: HTTP_DIAGNOSTIC_LOGS
	});
}

This gives every module the same path to Sentry, Loki, Datadog, console, test-capture transports or any future sink: inject one Logger, emit typed diagnostic events, let logr route.

Error Contract

Errors follow the same rule: strings are centralized, and public programmer errors are typed.

  • Error messages and error names live in errors.ts or consts.ts.
  • Runtime code must not throw inline string/template errors outside tests or vendored code.
  • Public programmer errors use artifact-specific classes and guards: SessionDisposedError, ConnInvalidNameError, UnitsUnknownUnitError, etc.
  • Expected runtime failures should be returned as tagged data/results when the artifact already has such a contract (http, conn, perm, cach).
  • Validation failures are data (SiumValidationError.issues) and diagnostics are emitted separately when a logger is injected.

Map

Artifact Layer(s) Purpose Depends on
lang EngineLang, ActiveLang, ActiveMonoLang i18n: type-safe translations, BCP 47 resolution, plurals, refs, JSON round-trip —
logr EngineLogger Structured logger: levels, transports, filters, vitals, dispose —
timr EngineTimers, ActiveTimers Deterministic timer scheduler: clock injection, one-shots, intervals, cancellation, snapshots, backoff $libs/timers, $logger (optional)
fmts EngineFormat, ActiveFormat Localized formatting: numbers, currency, units, dates $logger (currency)
adom ActiveDom Reactive DOM service: viewport, breakpoints, attribute writes, scroll lock $libs/dom, $reactive
fend ActiveFrontend Frontend preferences: theme, mode, dir, density, applied via DOM attrs $adom
sium EngineSium Validation contracts: schemas, issues, introspection, Standard Schema interop $lang (optional), $logger (optional), $libs/days, $libs/color
stor EngineStorage, ActiveStorage Reactive sync key/value: pluggable adapters, version+migrate, TTL, validation, intra-tab + cross-tab sync, reactive keys $sium (Standard Schema interop, optional)
http EngineHttp HTTP client: tagged HttpResult, Standard Schema validation, retry, timeouts, hooks, SvelteKit event.fetch integration $libs/http, $libs/standard-schema (type-only), $logger
sess EngineSession, ActiveSession Session lifecycle: adopt/revoke/refresh, auto-refresh, 401-rescue hook, SvelteKit SSR via adoptServer + cookie reader $storage, $timer, $http, $logger (optional)
conn EngineConnections, ActiveConnections Realtime connection registry: transports, reconnect, heartbeat, request/reply, channels, session bridge $timer, $logger (optional), $session bridge (optional)
auth ActiveAuth (EngineAuth in $svrs/auth) Authentication: password flows, CSRF, current session reflector, devices, logout, server-authoritative auth handlers $libs/auth, $http, $cache, $svrs/auth
perm ActivePerms (EnginePerms in $svrs/perm) Authorization: policy runtime adapter, HTTP client/handlers, cache snapshot, <Can /> guard $libs/perm, $libs/svrs, $http, $logger (optional)
cach ActiveCache (EngineCache in $svrs/cache) Data cache: deterministic keys, policies, scopes, stale/revalidate, tags, memory/storage adapters $libs/cache, $storage (adapter), $logger (optional)
aapp ActiveApp App composition: wires Logger + Lang + Format + Frontend + Dom + Storage + Http + Timers + Cache; factories for Sess, Conn, Auth, Perm, Sium every artifact above

Composition

Most apps consume the artifacts through aapp:

import { createActiveApp } from '$active-app';

const App = createActiveApp({
	lang: { schema, defaultLocale: 'es', fallbackChain: ['en'] },
	logger: { level: LogLevel.INFO, transports: [consoleTransport()] },
	frontend: { theme: 'base' }
});

App.lang.t('common.ok');
App.format.currency.format(99.5);
App.setLocale('es-MX'); // propagates to Lang, Format, Frontend

Every member of App is always present. When the caller does not configure lang/logger/formats, App provides a structurally identical adapter (mono lang, console logger, default-locale formats). Call sites stay uniform: App.lang.t(...) and App.format.currency.format(...) work whether or not i18n was configured.

Sium, Session, Connections, Auth and Perms are exposed as factories because they are feature/page-scoped: App injects shared services, but construction is explicit at the call site.

const App = createActiveApp({
	services: {
		sium: defineEngineSium({}),
		connections: defineActiveConnections({}),
		auth: defineActiveAuth({ initial: data.auth }),
		perm: defineActivePerm({ endpoint: '/perm' })
	}
});

applyStandardOrca(App);

See aapp/README.md for the full composition contract.

Cross-artifact dependencies

                 lang      logr
                   \      / |  \
                    \    /  |   \
                    fmts   http  timr
                      \      |    /|\
adom ─── fend          \     |   / | conn
   \      \             \    |  /  |  \
    \      \             \   | /  auth perm
     ──────────────── aapp ─ stor ─ cach
                       :
                      sium
  • lang and logr are the dependency-free roots (zero-dep libraries).
  • fmts consumes logr only inside currency (rate fetcher diagnostics).
  • sium accepts lang and logr via injection; without them it falls back to local message interpolation.
  • timr is the deterministic scheduler consumed by sess and conn.
  • http accepts logr via injection (auto-wired through aapp) and keeps shared HTTP literals/types in $libs/http.
  • sess consumes stor for persistence, timr for auto-refresh, and http for 401-rescue integration.
  • conn consumes timr for reconnect/heartbeat/ack timeouts and accepts the App session bridge when composed through aapp.
  • auth splits cleanly: $svrs/auth owns identity proof, CSRF and server handlers; $auth owns the active client reflector. It feeds sess, perm and cach through ports rather than owning their state.
  • perm splits cleanly: $svrs/perm owns the authoritative engine/HTTP handlers, while $perm owns the active UI reflector and <Can />.
  • cach splits cleanly: $svrs/cache owns the imperative engine, while $cache owns the active Svelte wrapper and can consume stor through its storage adapter.
  • adom depends only on the pure helpers in libs/dom and on libs/reactive.
  • fend depends on adom for DOM attribute writes.
  • aapp composes always-present roots and exposes factories for scoped artifacts (sium, sess, conn, auth, perm).

Shared types

Module Type Used by
$locale LocaleSource fmts.localeSource, fend.localeSource, aapp wiring
$lang SupportedLocale (LangBase | ${LangBase}-${string}) lang, consumers that want type-safe locales

Aliases

// svelte.config.js
alias: {
    $active-app:     'src/arts/aapp',
    $adom:     'src/arts/adom',
    $auth:     'src/arts/auth',
    $cache:     'src/arts/cach',
    $connection:     'src/arts/conn',
    $frontend:     'src/arts/fend',
    $format:     'src/arts/fmts',
    $http:     'src/arts/http',
    $lang:     'src/arts/lang',
    $logger:     'src/arts/logr',
    $perm:     'src/arts/perm',
    $session:     'src/arts/sess',
    $sium:     'src/arts/sium',
    $storage:     'src/arts/stor',
    $svrs:     'src/svrs',
    $timer:     'src/arts/timr',
    $libs:     'src/libs',
    $locale:   'src/libs/locale',
    $reactive: 'src/libs/reactive'
}

Bundle policy

Every artifact is designed to tree-shake cleanly:

  • package.json declares "sideEffects": ["**/*.css", "**/*.svelte"], so any .ts / .svelte.ts module that the bundler does not statically reach is dropped from the production bundle.
  • All barrels use named re-exports (export { a, b } from './x') instead of export *. This lets the bundler prove which symbols are reached from a given import and drop the rest of the source module.
  • .svelte.ts files defer module-level state (viewport.svelte.ts, body-scroll-lock.svelte.ts) so importing the barrel does not allocate Svelte runes runtime for unused features.
  • External adapters ($logger/adapters/*) and dev helpers ($active-app/testing, $sium/_examples/) live outside the main barrel. A consumer that does not reference them never pays for them.

A consumer that builds createActiveApp({ lang: { schema } }) and only calls App.lang.t(...) should land roughly in the 40–50 KB minified range. A consumer that wires every artifact (Sium + Storage cookies + Frontend preferences + Web Vitals) lands in the ~120 KB range. The difference is the per-feature surface, paid only when reached.

Test pages

Each artifact ships an interactive page under src/web/routes/test/<artifact>:

  • /test/aapp — full composition end-to-end
  • /test/ecosystem — total integration demo: auth, sess, perm, cach, http, stor, sium, fmts, fend, adom, timr, conn, lang and logr in one app flow
  • /test/lang — i18n with reactive locale switching, plurals, BCP 47
  • /test/logr — log levels, transports, vitals, Sentry integration
  • /test/fmts — numbers / currency / units / dates with shared locale
  • /test/fend — theme, mode, dir, density applied to a target
  • /test/adom — viewport, breakpoints, scroll lock, roving focus
  • /test/sium — login / signup / profile schemas with translated issues
  • /test/stor — adapters (memory / local / session / cookie), envelope versioning + migrate, raw mode, TTL, mergeDefaults, cross-tab sync
  • /test/http — GET/POST with Sium validation, retry + Retry-After, timeout, cancellation, lifecycle hooks, tagged HttpResult
  • /test/sess — session lifecycle: adopt/revoke/refresh with generation guard + dedup, auto-refresh, tagged RevokeResult, permission checks, event stream
  • /test/timr — scheduler snapshots, intervals, cancellation and deterministic clocks
  • /test/conn — websocket chat and connection/channel lifecycle
  • /test/auth — server-authoritative auth surface: password flow, CSRF, devices, routes and security events
  • /test/perm — authorization checks, <Can />, HTTP handlers and client cache
  • /test/cach — cache policies, scopes, tags and active entries

Index at /test.

Powered by TurnKey Linux.