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.
svelte-kit-vice/web/routes/active/get-started/composition/+page.svelte

232 lines
8.7 KiB

<script lang="ts">
import CodeBlock from '../../_components/CodeBlock.svelte';
import Callout from '../../_components/Callout.svelte';
import PageNav from '../../_components/PageNav.svelte';
const dependencyDiagram = `createActiveApp()
core, always present:
Logger -> Bus
Logger -> Timers
Logger + Bus + Timers -> Orca
Prefs
services, opt-in:
core Prefs -> lang
core Prefs -> format
dom + prefs projector -> global preference attrs
storage + http + timers -> session
session -> auth / perm / connections
lang -> sium
orchestration:
session events -> App.bus -> App.orca actions -> cache / perm / connections`;
const appExample = `import { createActiveApp } from '$active-app';
import {
defineActiveLangs,
defineActiveFormat,
defineActiveDom,
defineActiveStorage,
defineEngineHttp,
defineActiveSession,
defineActiveCache
} from '$active-app/services';
import { createActivePrefsDomProjection } from '$prefs';
import { applyStandardOrca } from '$active-app/presets';
import { LogLevel, consoleTransport } from '$logger';
export const App = createActiveApp({
logger: { level: LogLevel.INFO, transports: [consoleTransport()] },
orca: { maxDepth: 24 },
prefs: {
capabilities,
environment,
intent: { language: 'es', locale: 'es-ES' }
},
services: {
dom: defineActiveDom(),
langs: defineActiveLangs({ schema, defaultLocale: 'es', fallbackChain: ['en'] }),
format: defineActiveFormat(),
storage: defineActiveStorage(),
http: defineEngineHttp({ baseUrl: '/api' }),
session: defineActiveSession({ schemas, storage, onRefresh, onRevoke }),
cache: defineActiveCache()
}
});
export const prefsProjection = createActivePrefsDomProjection({
prefs: App.prefs,
dom: App.dom
});
applyStandardOrca(App);`;
const orcaExample = `import {
applyCacheClearOnIdentityChange,
applyPermInvalidateOnIdentityChange,
applyConnectionsReauthOnIdentityChange
} from '$active-app/presets';
applyCacheClearOnIdentityChange(App);
applyPermInvalidateOnIdentityChange(App);
applyConnectionsReauthOnIdentityChange(App);`;
const prefsExample = `App.prefs.language.set('es');
App.prefs.locale.set('es-MX');
App.prefs.motion.set('reduce');
// App.prefs drives downstream services when they are declared:
// - App.langs follows App.prefs.language.get()
// - App.format follows App.prefs.locale.get()
// - prefs projection can write direction, motion, sound and haptic attrs`;
</script>
<svelte:head>
<title>Composition - Active</title>
</svelte:head>
<article class="article">
<header class="breadcrumbs">
<a href="/active">Get Started</a>
<span aria-hidden="true">/</span>
<span>Composition</span>
</header>
<h1>Composition</h1>
<p class="lead">
Active is wired through <code>$active-app</code>. The current model is a fixed runtime
core plus a typed service schema: <code>Logger</code>, <code>Bus</code>,
<code>Timers</code>, <code>Orca</code> and <code>Prefs</code> always exist; the rest of
the ecosystem is declared explicitly under <code>services</code>.
</p>
<h2>Factories</h2>
<ul>
<li>
<strong><code>createEngineXxx(options)</code></strong> - pure factory. It has no
Svelte runes and is safe for server code, tests and adapters.
</li>
<li>
<strong><code>createActiveXxx(options)</code></strong> - reactive runtime wrapper. It
lives in a <code>.svelte.ts</code> file when it owns <code>$state</code>.
</li>
<li>
<strong><code>defineActiveXxx()</code> / <code>defineEngineXxx()</code></strong> -
service-schema adapters used only by <code>$active-app/services</code>.
</li>
</ul>
<Callout variant="info" title="Core is not a service">
<p>
The App core is configured with root options on <code>createActiveApp()</code>. Do not
declare <code>logger</code>, <code>bus</code>, <code>timers</code>,
<code>orca</code> or <code>prefs</code> inside <code>services</code>.
</p>
</Callout>
<h2>Fixed core</h2>
<table>
<thead>
<tr>
<th>Member</th>
<th>Created by</th>
<th>Purpose</th>
</tr>
</thead>
<tbody>
<tr><td><code>App.logger</code></td><td><code>createEngineLogger()</code></td><td>Structured logs and transports.</td></tr>
<tr><td><code>App.bus</code></td><td><code>createSvelteEngineBus()</code></td><td>Typed application event bus.</td></tr>
<tr><td><code>App.timers</code></td><td><code>createActiveTimers()</code></td><td>Deterministic scheduler and shared clock.</td></tr>
<tr><td><code>App.orca</code></td><td><code>createEngineOrca()</code></td><td>Cross-module orchestration. It is inert until actions or presets are registered.</td></tr>
<tr><td><code>App.prefs</code></td><td><code>createActivePrefs()</code></td><td>Core preference engine. Uses root <code>prefs</code> options or neutral defaults.</td></tr>
</tbody>
</table>
<h2>Typed services</h2>
<p>
Every declared service becomes a typed lowercase property on <code>App</code>. Services can
be lazy or immediate, can request a subset of the core, and can depend on other declared
services. Undeclared services do not exist on the App type.
</p>
<table>
<thead>
<tr>
<th>Service</th>
<th>Factory</th>
<th>Important wiring</th>
</tr>
</thead>
<tbody>
<tr><td><code>lang</code></td><td><code>defineActiveLangs()</code></td><td>Always follows <code>App.prefs.language.get()</code>.</td></tr>
<tr><td><code>format</code></td><td><code>defineActiveFormat()</code></td><td>Always reads its locale source from <code>App.prefs</code> (or an explicit <code>localeSource</code> override).</td></tr>
<tr><td><code>dom</code></td><td><code>defineActiveDom()</code></td><td>Browser document adapter; inert on the server.</td></tr>
<tr><td><code>storage</code></td><td><code>defineActiveStorage()</code></td><td>Runtime storage adapter, memory-backed by default.</td></tr>
<tr><td><code>http</code></td><td><code>defineEngineHttp()</code></td><td>Engine service for API calls and request diagnostics.</td></tr>
<tr><td><code>cache</code></td><td><code>defineActiveCache()</code></td><td>Passive cache. Identity reactions belong to Orca presets.</td></tr>
<tr><td><code>sium</code></td><td><code>defineEngineSium()</code></td><td>Validation engine; consumes <code>lang</code> if declared.</td></tr>
<tr><td><code>session</code></td><td><code>defineActiveSession()</code></td><td>Publishes session events on <code>App.bus</code>.</td></tr>
<tr><td><code>auth</code></td><td><code>defineActiveAuth()</code></td><td>Client reflector for server-authoritative auth flows.</td></tr>
<tr><td><code>perm</code></td><td><code>defineActivePerm()</code></td><td>Permission reflector. Invalidation is opt-in through Orca.</td></tr>
<tr><td><code>connections</code></td><td><code>defineActiveConnections()</code></td><td>Realtime registry; reauth/close reactions are Orca presets.</td></tr>
</tbody>
</table>
<h2>Dependency graph</h2>
<CodeBlock lang="text" code={dependencyDiagram} title="Current composition map" />
<h2>App composition</h2>
<CodeBlock lang="ts" code={appExample} title="src/lib/app.ts" />
<h2>Orca reactions</h2>
<p>
Module events are public typed contracts on <code>App.bus</code>. The bus does not run
destructive behavior by itself; <code>App.orca</code> owns those cross-module reactions.
Use <code>applyStandardOrca(App)</code> for the default set, or cherry-pick individual
presets when the application needs a narrower policy.
</p>
<CodeBlock lang="ts" code={orcaExample} />
<h2>Preferences propagation</h2>
<p>
<code>App.prefs</code> is the ecosystem-wide source of user intent. Locale is no longer a
Lang-only concern: language drives translations, locale drives regional formats, and
shared preferences such as direction, motion, sound and haptic can be projected through
the explicit prefs DOM projector.
</p>
<CodeBlock lang="ts" code={prefsExample} />
<h2>Disposal</h2>
<p>
<code>App.dispose()</code> publishes the dispose-starting event, disposes constructed
services in reverse construction order, tears down the prefs storage bridge, then disposes
<code>Prefs</code>, <code>Orca</code>, <code>Bus</code>, <code>Timers</code> and finally
<code>Logger</code>. The operation is idempotent.
</p>
<CodeBlock lang="ts" code={`onDestroy(() => App.dispose());`} />
<h2>Server boundary</h2>
<p>
<code>$active-app</code> is the client composition root. Server authority stays in
<code>$svrs</code> and pure engines. Shared contracts belong in <code>$libs</code>.
</p>
<PageNav />
</article>
<style>
.breadcrumbs {
display: flex;
align-items: center;
gap: 0.4rem;
font-size: 0.8125rem;
color: var(--c-fg-subtle);
margin-bottom: 1rem;
}
.breadcrumbs a {
color: var(--c-fg-muted);
}
</style>

Powered by TurnKey Linux.