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/ecosystem/+page.svelte

324 lines
14 KiB

<script lang="ts">
import Callout from '../../_components/Callout.svelte';
import CodeBlock from '../../_components/CodeBlock.svelte';
import PageNav from '../../_components/PageNav.svelte';
const layerMap = `src/libs/* shared contracts, constants and pure helpers
src/svrs/* server-authoritative engines and backend adapters
src/arts/* client/runtime artifacts, active wrappers and browser ergonomics
src/web/routes documentation, test pages and app routes
$active-app client composition root: Logger, Bus, Timers, Orca, Prefs core + typed services`;
const appFlow = `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'] }),
storage: defineActiveStorage({ adapter: localAdapter, namespace: 'app' }),
http: defineEngineHttp({ baseUrl: '/api' }),
cache: defineActiveCache({ defaultPolicy: 'interactive' }),
sium: defineEngineSium({}),
session: defineActiveSession({ storage, onRefresh, onRevoke }),
auth: defineActiveAuth({ initial: data.auth }),
perm: defineActivePerm({ endpoint: '/api/perm' }),
connections: defineActiveConnections({})
}
});
const prefsProjection = createActivePrefsDomProjection({
prefs: App.prefs,
dom: App.dom
});
applyStandardOrca(App); // wires cache, perm and connections reactions through App.orca`;
const serverFlow = `const Auth = createEngineAuth({
security,
ports: { store, actors, sess, cache, logger, timer, crypto, passwordHasher, mailer }
});
const Perms = createEnginePerms({
schema,
policies,
providers,
compilers,
logger
});
const Cache = createEngineCache({
namespace: 'api',
adapter,
scopeResolver,
policies,
logger
});`;
const requestFlow = `Browser
→ ActiveAuth / ActivePerms / App.http / ActiveCache
→ SvelteKit endpoint or action
→ $svrs/auth reads Auth current and session binding
→ $svrs/perm asserts actor can perform action
→ $svrs/cache serves or fetches scoped data
→ App.http receives typed result
→ Active roots update snapshots and UI`;
const identityFlow = `signInPassword()
→ ActiveAuth obtains CSRF and posts to server
→ EngineAuth validates credential and binds session through the session port
→ Session state changes
→ Perms snapshot/cache must be invalidated for the new actor
→ Cache private scopes change actorId / permissionHash
→ Connections can reauthenticate or disconnect through the App session bridge`;
const localeFlow = `App.prefs.language.set('ar')
App.prefs.locale.set('ar-EG')
-> prefs resolves effective language and regional locale
-> App.langs follows App.prefs.language.get()
-> App.format follows App.prefs.locale.get()
-> prefs projection writes dir="rtl" and cross-modal attrs through App.dom
-> ActiveEidos owns data-theme, data-mode and data-density when UIX is mounted`;
</script>
<svelte:head>
<title>Ecosystem — Active</title>
</svelte:head>
<article class="article">
<header class="breadcrumbs">
<a href="/active">Get Started</a>
<span aria-hidden="true">/</span>
<span>Ecosystem</span>
</header>
<h1>Ecosystem</h1>
<p class="lead">
Active is not a bag of utilities. It is a runtime ecosystem: a small language of
artifacts, factories, contracts and layer boundaries that lets a SvelteKit app avoid
reinventing infrastructure for every feature.
</p>
<h2>Layer map</h2>
<p>
The first thing to understand is where a module is allowed to live. The same concept can
have shared contracts, a server authority and an active client reflector, but those are not
the same layer.
</p>
<CodeBlock code={layerMap} lang="text" />
<table>
<thead>
<tr>
<th>Layer</th>
<th>What belongs there</th>
<th>What must not happen there</th>
</tr>
</thead>
<tbody>
<tr>
<td><code>libs</code></td>
<td>Types, constants, pure algorithms, shared contracts.</td>
<td>No Svelte state, no browser APIs, no database or framework dependency.</td>
</tr>
<tr>
<td><code>svrs</code></td>
<td>Server engines, secrets, backend adapters, request security.</td>
<td>No UI state and no trust in client-provided identity or permissions.</td>
</tr>
<tr>
<td><code>arts</code></td>
<td>Public runtime artifacts, active wrappers, browser/client ergonomics.</td>
<td>No server secrets, no authoritative authorization, no password/token persistence.</td>
</tr>
<tr>
<td><code>$active-app</code></td>
<td>Client composition root with fixed core plus typed services.</td>
<td>No replacement for server engines; it wires runtime modules, not backend authority.</td>
</tr>
</tbody>
</table>
<Callout variant="warn" title="Server authority">
<p>
<code>auth</code>, <code>perm</code> and <code>cache</code> have server-level modules
because they can affect identity, access or private data coherence. Their active
counterparts are reflections for UX, not the source of truth.
</p>
</Callout>
<h2>Domains</h2>
<p>
The modules are grouped by problem, not by technical trick. This makes the dependency
direction easier to reason about.
</p>
<table>
<thead>
<tr>
<th>Domain</th>
<th>Modules</th>
<th>Responsibility</th>
</tr>
</thead>
<tbody>
<tr><td>Composition</td><td><code>$active-app</code></td><td>Single client root, fixed Logger/Bus/Timers/Orca/Prefs core, typed service schema and disposal order.</td></tr>
<tr><td>Identity</td><td><code>$auth</code>, <code>$session</code>, <code>$perm</code></td><td>Prove identity, keep session continuity, decide access.</td></tr>
<tr><td>Data</td><td><code>$http</code>, <code>$cache</code>, <code>$storage</code></td><td>Remote calls, coherent cached data, safe local persistence.</td></tr>
<tr><td>Preferences</td><td><code>$prefs</code></td><td>User intent, environment defaults and effective locale/timezone/perception values.</td></tr>
<tr><td>I18n and formats</td><td><code>$langs</code>, <code>$format</code></td><td>Text translation plus preference-driven numbers, currency, units and dates.</td></tr>
<tr><td>DOM and UI runtime</td><td><code>$adom</code>, <code>$prefs</code>, <code>$uix/eidos</code></td><td>DOM writes, global preference attrs and visual theme/mode/density.</td></tr>
<tr><td>Validation</td><td><code>$sium</code></td><td>Page-scoped schemas, issues, metadata and translated validation messages.</td></tr>
<tr><td>Infrastructure</td><td><code>$bus</code>, <code>$logger</code>, <code>$timer</code>, <code>$orca</code>, <code>$connection</code></td><td>Events, structured logs, deterministic timers, orchestration and realtime connections.</td></tr>
</tbody>
</table>
<h2>Factories</h2>
<p>
The factory naming is the backbone of the framework. If a module owns pure behavior, it has
an <code>Engine</code>. If it owns reactive state for Svelte, it has an <code>Active</code>.
If it must be authoritative on the server, the engine lives in <code>$svrs</code>.
</p>
<table>
<thead>
<tr>
<th>Factory</th>
<th>Use it when</th>
<th>Examples</th>
</tr>
</thead>
<tbody>
<tr><td><code>createEngineXxx()</code></td><td>You need deterministic, non-runes runtime logic.</td><td><code>createEngineHttp</code>, <code>createEngineTimers</code>, <code>createEngineSium</code></td></tr>
<tr><td><code>createActiveXxx()</code></td><td>You need Svelte 5 reactive state and lifecycle.</td><td><code>createActiveStorage</code>, <code>createActiveConnections</code></td></tr>
<tr><td><code>$svrs/createEngineXxx()</code></td><td>The result must be server-authoritative.</td><td><code>createEngineAuth</code>, <code>createEnginePerms</code>, <code>createEngineCache</code></td></tr>
<tr><td><code>App.logger / App.bus / App.timers / App.orca / App.prefs</code></td><td>You need the fixed App core.</td><td>Always present; configured from root options, never declared as services.</td></tr>
<tr><td><code>defineActiveXxx() / defineEngineXxx()</code></td><td>You want App to declare a service in its schema and inject core deps automatically.</td><td><code>defineEngineSium({`{}`})</code>, <code>defineActiveAuth({`{...}`})</code></td></tr>
</tbody>
</table>
<h2>App composition</h2>
<p>
<code>createActiveApp()</code> gives the browser/client side a stable surface. The fixed
core is always present: <code>Logger</code>, <code>Bus</code>, <code>Timers</code>,
<code>Orca</code> and <code>Prefs</code>. Feature modules are declared explicitly in
<code>services</code>, so pages only pay for what the app composes.
</p>
<CodeBlock code={appFlow} lang="ts" title="Client composition" />
<h2>Server composition</h2>
<p>
Server engines are explicit. They receive ports instead of importing infrastructure
directly, which keeps tests deterministic and adapters replaceable.
</p>
<CodeBlock code={serverFlow} lang="ts" title="Server composition" />
<h2>Request flow</h2>
<p>
A full request crosses several modules, but each one has one job. That separation is the
main value of the ecosystem.
</p>
<CodeBlock code={requestFlow} lang="text" />
<h2>Identity flow</h2>
<p>
Identity-sensitive work follows a stricter chain. <code>auth</code> proves identity,
<code>$session</code> keeps continuity, <code>$perm</code> decides access, and
<code>cache</code> must scope or invalidate private data.
</p>
<CodeBlock code={identityFlow} lang="text" />
<h2>Locale flow</h2>
<p>
Preferences are the ecosystem-wide source of user intent. Translation language, regional
format locale and document direction can be related, but they are not the same value.
</p>
<CodeBlock code={localeFlow} lang="text" />
<h2>Choosing a module</h2>
<table>
<thead>
<tr>
<th>If you need...</th>
<th>Use</th>
<th>Do not use</th>
</tr>
</thead>
<tbody>
<tr><td>Translate labels, messages or fallbacks.</td><td><code>$langs</code></td><td><code>$format</code> or ad-hoc dictionaries.</td></tr>
<tr><td>Format numbers, dates, currency or units.</td><td><code>$format</code></td><td><code>$langs</code>.</td></tr>
<tr><td>Persist non-secret preferences or drafts.</td><td><code>$storage</code></td><td><code>$session</code>, localStorage calls spread through pages.</td></tr>
<tr><td>Keep logged-in continuity.</td><td><code>$session</code></td><td><code>$auth</code> alone.</td></tr>
<tr><td>Prove identity or run login/recovery flows.</td><td><code>$svrs/auth</code> plus <code>$auth</code></td><td><code>perm</code> or client-only checks.</td></tr>
<tr><td>Decide if an actor can do something.</td><td><code>$svrs/perm</code> plus <code>$perm</code></td><td><code>auth</code>, roles hard-coded in UI.</td></tr>
<tr><td>Cache data with scopes and invalidation.</td><td><code>$svrs/cache</code> or <code>$cache</code></td><td><code>$storage</code> as a query cache.</td></tr>
<tr><td>Schedule retries, refreshes or timeouts.</td><td><code>timer</code></td><td>raw <code>setTimeout</code> scattered across modules.</td></tr>
<tr><td>Open realtime sockets and channels.</td><td><code>$connection</code></td><td>custom WebSocket state in components.</td></tr>
<tr><td>Validate forms and generate issues.</td><td><code>sium</code></td><td><code>perm</code> or manual string errors.</td></tr>
</tbody>
</table>
<h2>Integration rules</h2>
<ul>
<li>Every public string used for logs, events, methods, categories or protocol names belongs in constants.</li>
<li>Modules receive the shared <code>Logger</code> contract; they do not invent local logger interfaces.</li>
<li>Diagnostics are allowed as a catalog layer, but they emit through <code>Logger</code>.</li>
<li>Server engines never trust actor, permission or private scope values sent by the browser.</li>
<li>Active clients can cache for UX, but protected data and mutations must be checked server-side.</li>
<li>Auto/manual preferences behave consistently: auto follows source changes; manual stays fixed until <code>clearX()</code>.</li>
<li><code>dispose()</code> must be real, idempotent and should reject future work where the module owns resources.</li>
</ul>
<Callout variant="tip" title="Working with AI agents">
<p>
If an AI is going to modify Active, send it first to
<a href="/active/get-started/ai-agents">AI Agents</a>. That page defines the operating
rules: read order, layer boundaries, logger contract, constants, docs truthfulness and
the completion checklist.
</p>
</Callout>
<h2>Test strategy</h2>
<p>
The ecosystem needs three levels of tests. A module can be correct in isolation and still
fail when identity, permissions, cache and realtime state interact.
</p>
<table>
<thead>
<tr>
<th>Level</th>
<th>Targets</th>
<th>What it proves</th>
</tr>
</thead>
<tbody>
<tr><td>Unit</td><td><code>src/arts/*/test</code>, <code>src/libs/*/test</code>, <code>src/svrs/*/test</code></td><td>Each artifact obeys its own contract.</td></tr>
<tr><td>Integration</td><td><code>src/arts/active-app/test</code></td><td>App wiring, prefs propagation, orca presets, session bridge, disposal order.</td></tr>
<tr><td>Scenario</td><td><code>/test/ecosystem</code></td><td>A realistic app story with auth, session, perm, cache, http, sium, connection and UI state together.</td></tr>
</tbody>
</table>
<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.