N2 — codex audit blockers #1, #8: route migration + arts/cache layer fix

Closes the remaining items from segunda_auditoria-codex.md the user
explicitly called out as still pending after N1.

Layer fix (audit blocker #8):
`createEngineCache`, `EngineCache`, `EngineCacheOptions`, the cache
diagnostics catalog and the disposed-engine error infrastructure move
from `svrs/cache/*` into `libs/cache/*` (renamed `engine-*` to
distinguish from the existing pure-runtime files). Nothing in those
files is server-specific — only `Logger` integration and a dispose
guard, both universal. `arts/cache` now imports from `$libs/cache`
directly; `svrs/cache/index.ts` becomes a transparent re-export of
the same names so historical `$svrs/cache` consumers keep working.
The arts → svrs layer inversion the audit flagged is now
structurally impossible for the cache module.

Route migration (audit blocker #1):
The `/test/{aapp,cach,conn,perm,http}` pages are migrated from the
pre-`createActiveApp({ services })` API surface to the current
service-schema shape:
- `App.createSiumEngine()` → `defineEngineSium()` in services + `App.sium`.
- `App.createActiveSession(...)` → `defineActiveSession(...)` + `App.session`.
- `App.createActivePerms(...)` → `defineActivePerm(...)` + `App.perm`.
- `App.createActiveConnections<...>()` → `defineActiveConnections(...)` + `App.connections`.
- Top-level option blocks (`lang: {...}`, `http: {...}`, `cache: {...}`,
  `frontend: {...}`, `storage: {...}`, `permissions: {...}`,
  `connections: {...}`) now wrap their factories under `services: {...}`.
- `App.setLocale` / `App.getLocale` migrate to `App.lang.*`.
- `density: 'normal'` → `'comfortable'` (post-L1 vocabulary).
- Each page's `+page.ts` prerender opt-out is removed; they now build
  statically and are reachable from the test index.

`/test/ecosystem` is the one outlier: its 1387-line scenario harness
threads through Auth + Session + Perms + Cache + Connections in ways
that need API-port stubbing (AuthClientHttpPort, an EcosystemConnections
generic shape that no longer exists, etc.). The factory wiring is
already migrated in the file (services schema, App.sium / App.auth /
App.session / App.perm / App.connections / cache scope locale via a
synced `currentLocale` cell), but the consumer code still uses
`App.format` / `App.dom` / `App.createActiveConnections<...>()`
shapes that don't typecheck against the new schema. Re-excluded from
typecheck + prerender with a follow-up note; the page still loads in
dev. Migration of the remaining call sites is its own commit.

Suite: 1695 / 1695 passing. check / build / bundle / aliases all green.

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
master
dev 5 months ago
parent ca01324f67
commit 843c7087e7

@ -1,5 +1,5 @@
import { CACHE_EVENT_ALL, type CacheClock, type CacheEvent } from '$libs/cache';
import { createEngineCache } from '$svrs/cache';
import { createEngineCache } from '$libs/cache';
import {
CACHE_ACTIVE_DIAGNOSTIC_EVENTS,
CACHE_METHOD_CLEAR,
@ -13,7 +13,7 @@ import {
CACHE_METHOD_SET,
CACHE_METHOD_STATS
} from './consts.ts';
import { disposedCacheMessage } from '$svrs/cache';
import { disposedCacheMessage } from '$libs/cache';
import { createActiveCacheEntry } from './active-cache-entry.svelte.ts';
import { normalizeActiveCacheError } from './active-cache-helpers.ts';
import { createActiveCacheDiagnostics, emitActiveCacheDiagnostic } from './diagnostics.ts';

@ -25,7 +25,7 @@ export {
CACHE_METHOD_SET,
CACHE_METHOD_STATS,
CACHE_MODULE
} from '$svrs/cache';
} from '$libs/cache';
export const CACHE_ACTIVE_STATUS_IDLE = 'idle';
export const CACHE_ACTIVE_STATUS_LOADING = 'loading';

@ -1,8 +1,8 @@
import { CodeError } from '$libs/errs';
import { CACHE_ERR_ACTIVE_ENTRY_DISPOSED } from '$libs/cache';
import { CACHE_MODULE } from '$svrs/cache';
import { CACHE_MODULE } from '$libs/cache';
export { CACHE_ERROR_MSG_DISPOSED_SUFFIX, CacheDisposedError, isCacheDisposedError } from '$svrs/cache';
export { CACHE_ERROR_MSG_DISPOSED_SUFFIX, CacheDisposedError, isCacheDisposedError } from '$libs/cache';
export const CACHE_ERROR_MSG_ACTIVE_ENTRY_DISPOSED =
`[${CACHE_MODULE}] ActiveCacheEntry used after dispose().`;

@ -53,7 +53,7 @@ export {
isCacheActiveEntryDisposedError,
isCacheDisposedError
} from './errors.ts';
export { disposedCacheMessage } from '$svrs/cache';
export { disposedCacheMessage } from '$libs/cache';
export type {
ActiveCacheDiagnosticEvent,
ActiveCacheDiagnosticMeta,
@ -145,7 +145,7 @@ export {
stableHash,
stableStringify,
storageCacheAdapter
} from '$svrs/cache';
} from '$libs/cache';
export type {
CacheAdapter,
@ -187,4 +187,4 @@ export type {
SetOptions,
StorageCacheAdapterOptions,
StorageLike
} from '$svrs/cache';
} from '$libs/cache';

@ -1,9 +1,9 @@
import type { CACHE_ACTIVE_ENTRY_EVENTS, CACHE_ACTIVE_STATUSES } from './consts.ts';
import type { CacheClock, CacheEvent, CacheKey, QueryOptions, SetOptions } from '$libs/cache';
import type { EngineCache, EngineCacheOptions } from '$svrs/cache';
import type { EngineCache, EngineCacheOptions } from '$libs/cache';
import type { ActiveChangeListener, ActiveEngine } from '$libs/active';
export type { EngineCache, EngineCacheOptions } from '$svrs/cache';
export type { EngineCache, EngineCacheOptions } from '$libs/cache';
export type ActiveCacheEntryStatus = (typeof CACHE_ACTIVE_STATUSES)[number];

@ -10,10 +10,10 @@ import {
CACHE_EVENT_ADAPTER_ERROR,
CACHE_EVENT_REFRESH_ERROR,
CACHE_EVENT_STALE_IF_ERROR,
type CacheEvent,
type CacheEventType
} from '$libs/cache';
import { CACHE_LOG_MESSAGE_BY_EVENT, CACHE_MODULE } from './consts.ts';
CACHE_MODULE
} from './consts.ts';
import type { CacheEvent, CacheEventType } from './types.ts';
import { CACHE_LOG_MESSAGE_BY_EVENT } from './engine-consts.ts';
export type CacheDiagnosticEvent = DiagnosticEvent<CacheEventType, CacheEvent>;
export type CacheDiagnostics = Diagnostics<CacheDiagnosticEvent>;

@ -1,4 +1,5 @@
import { createCacheRuntime, memoryCacheAdapter } from '$libs/cache';
import { createCacheRuntime } from './engine.ts';
import { memoryCacheAdapter } from './adapters/memory.ts';
import {
CACHE_METHOD_CLEAR,
CACHE_METHOD_EXPLAIN,
@ -9,11 +10,11 @@ import {
CACHE_METHOD_QUERY,
CACHE_METHOD_SET,
CACHE_METHOD_STATS
} from './consts.ts';
} from './engine-consts.ts';
import { createCacheDiagnostics, emitCacheDiagnostic } from './diagnostics.ts';
import { CacheDisposedError } from './errors.ts';
import { disposedCacheMessage } from './helpers.ts';
import type { EngineCache, EngineCacheOptions } from './types.ts';
import { CacheDisposedError } from './engine-errors.ts';
import { disposedCacheMessage } from './engine-helpers.ts';
import type { EngineCache, EngineCacheOptions } from './engine-types.ts';
export function createEngineCache(options: EngineCacheOptions = {}): EngineCache {
const diagnostics = createCacheDiagnostics(options.logger);

@ -13,15 +13,9 @@ import {
CACHE_EVENT_SET,
CACHE_EVENT_SINGLEFLIGHT_JOIN,
CACHE_EVENT_STALE_HIT,
CACHE_EVENT_STALE_IF_ERROR,
CACHE_MODULE,
type CacheEventType
} from '$libs/cache';
// `CACHE_MODULE` is owned by `libs/cache` (the pure layer needs it for
// diagnostics) and re-exported from this server consts module so
// existing `$svrs/cache` consumers keep their import paths.
export { CACHE_MODULE };
CACHE_EVENT_STALE_IF_ERROR
} from './consts.ts';
import type { CacheEventType } from './types.ts';
export const CACHE_LOG_MESSAGE_HIT = 'cache hit';
export const CACHE_LOG_MESSAGE_MISS = 'cache miss';

@ -1,5 +1,5 @@
import { CodeError } from '$libs/errs';
import { CACHE_ERR_DISPOSED } from '$libs/cache';
import { CACHE_ERR_DISPOSED } from './errors.ts';
export const CACHE_ERROR_MSG_DISPOSED_SUFFIX = '() called on a disposed cache engine';

@ -1,4 +1,4 @@
import { CACHE_ERROR_MSG_DISPOSED_SUFFIX } from './errors.ts';
import { CACHE_ERROR_MSG_DISPOSED_SUFFIX } from './engine-errors.ts';
export function disposedCacheMessage(method: string): string {
return `${method}${CACHE_ERROR_MSG_DISPOSED_SUFFIX}`;

@ -2,9 +2,9 @@ import type {
CacheAdapter,
CacheEventHandler,
CacheRuntime,
CacheRuntimeConfig,
MemoryCacheAdapterOptions
} from '$libs/cache';
CacheRuntimeConfig
} from './types.ts';
import type { MemoryCacheAdapterOptions } from './adapters/memory.ts';
import type { Logger } from '$libs/logger';
export interface EngineCacheOptions extends Omit<CacheRuntimeConfig, 'adapter' | 'onEvent'> {

@ -68,3 +68,48 @@ export type {
export type { MemoryCacheAdapter, MemoryCacheAdapterOptions } from './adapters/memory.ts';
export type { StorageCacheAdapterOptions, StorageLike } from './adapters/storage.ts';
// ── Engine surface (formerly in `svrs/cache`) ──────────────────────────
//
// The engine factory is the runtime wrapper consumed by both `arts/cache`
// (reactive) and `svrs/cache` (server compositions). It lives here in the
// pure layer because nothing about it is server-specific — only `Logger`
// integration and a dispose guard. Closes the codex audit blocker #8
// (arts → svrs layer inversion).
export { createEngineCache } from './engine-cache.ts';
export {
CACHE_METHOD_CLEAR,
CACHE_METHOD_EXPLAIN,
CACHE_METHOD_GET,
CACHE_METHOD_INVALIDATE,
CACHE_METHOD_MUTATE,
CACHE_METHOD_ON,
CACHE_METHOD_QUERY,
CACHE_METHOD_SET,
CACHE_METHOD_STATS,
CACHE_LOG_MESSAGE_BY_EVENT,
CACHE_LOG_MESSAGE_HIT,
CACHE_LOG_MESSAGE_MISS,
CACHE_LOG_MESSAGE_STALE_HIT,
CACHE_LOG_MESSAGE_REFRESH_START,
CACHE_LOG_MESSAGE_REFRESH_SUCCESS,
CACHE_LOG_MESSAGE_REFRESH_ERROR,
CACHE_LOG_MESSAGE_STALE_IF_ERROR,
CACHE_LOG_MESSAGE_INVALIDATE,
CACHE_LOG_MESSAGE_SCHEMA_MISMATCH,
CACHE_LOG_MESSAGE_SCOPE_ERROR,
CACHE_LOG_MESSAGE_SINGLEFLIGHT_JOIN,
CACHE_LOG_MESSAGE_EVICTION,
CACHE_LOG_MESSAGE_ADAPTER_ERROR,
CACHE_LOG_MESSAGE_SET,
CACHE_LOG_MESSAGE_DELETE
} from './engine-consts.ts';
export {
CACHE_ERROR_MSG_DISPOSED_SUFFIX,
CacheDisposedError,
isCacheDisposedError
} from './engine-errors.ts';
export { disposedCacheMessage } from './engine-helpers.ts';
export { createCacheDiagnostics, emitCacheDiagnostic } from './diagnostics.ts';
export type { EngineCache, EngineCacheOptions } from './engine-types.ts';
export type { CacheDiagnosticEvent, CacheDiagnostics } from './diagnostics.ts';

@ -1,155 +1,10 @@
export { createEngineCache } from './engine-cache.ts';
export { createCacheDiagnostics, emitCacheDiagnostic } from './diagnostics.ts';
export { CACHE_ERR_DISPOSED } from '$libs/cache';
export {
CACHE_LOG_MESSAGE_ADAPTER_ERROR,
CACHE_LOG_MESSAGE_BY_EVENT,
CACHE_LOG_MESSAGE_DELETE,
CACHE_LOG_MESSAGE_EVICTION,
CACHE_LOG_MESSAGE_HIT,
CACHE_LOG_MESSAGE_INVALIDATE,
CACHE_LOG_MESSAGE_MISS,
CACHE_LOG_MESSAGE_REFRESH_ERROR,
CACHE_LOG_MESSAGE_REFRESH_START,
CACHE_LOG_MESSAGE_REFRESH_SUCCESS,
CACHE_LOG_MESSAGE_SCHEMA_MISMATCH,
CACHE_LOG_MESSAGE_SCOPE_ERROR,
CACHE_LOG_MESSAGE_SET,
CACHE_LOG_MESSAGE_SINGLEFLIGHT_JOIN,
CACHE_LOG_MESSAGE_STALE_HIT,
CACHE_LOG_MESSAGE_STALE_IF_ERROR,
CACHE_METHOD_CLEAR,
CACHE_METHOD_EXPLAIN,
CACHE_METHOD_GET,
CACHE_METHOD_INVALIDATE,
CACHE_METHOD_MUTATE,
CACHE_METHOD_ON,
CACHE_METHOD_QUERY,
CACHE_METHOD_SET,
CACHE_METHOD_STATS,
CACHE_MODULE
} from './consts.ts';
export {
CACHE_ERROR_MSG_DISPOSED_SUFFIX,
CacheDisposedError,
isCacheDisposedError
} from './errors.ts';
export { disposedCacheMessage } from './helpers.ts';
export type { EngineCache, EngineCacheOptions } from './types.ts';
export type { CacheDiagnosticEvent, CacheDiagnostics } from './diagnostics.ts';
export {
CACHE_ADAPTER_MEMORY,
CACHE_ADAPTER_STORAGE,
CACHE_DECISION_ACTION_DELETE_AND_FETCH,
CACHE_DECISION_ACTION_FETCH,
CACHE_DECISION_ACTION_SERVE,
CACHE_DECISION_ACTION_SERVE_AND_REFRESH,
CACHE_DECISION_ACTION_SKIP_CACHE,
CACHE_DECISION_REASON_BYPASS_CACHE,
CACHE_DECISION_REASON_CACHE_MISS,
CACHE_DECISION_REASON_EXPIRED,
CACHE_DECISION_REASON_FRESH,
CACHE_DECISION_REASON_NO_STORE,
CACHE_DECISION_REASON_PREFIX_EPOCH_CHANGED,
CACHE_DECISION_REASON_SCHEMA_VERSION_MISMATCH,
CACHE_DECISION_REASON_SCOPE_MISMATCH,
CACHE_DECISION_REASON_STALE_WINDOW_VALID,
CACHE_DECISION_REASON_TAG_EPOCH_CHANGED,
CACHE_ENVELOPE_STATE_DEGRADED,
CACHE_ENVELOPE_STATE_EXPIRED,
CACHE_ENVELOPE_STATE_FRESH,
CACHE_ENVELOPE_STATE_INVALIDATED,
CACHE_ENVELOPE_STATE_STALE,
CACHE_EVENT_ADAPTER_ERROR,
CACHE_EVENT_ALL,
CACHE_EVENT_DELETE,
CACHE_EVENT_EVICTION,
CACHE_EVENT_HIT,
CACHE_EVENT_INVALIDATE,
CACHE_EVENT_MISS,
CACHE_EVENT_REFRESH_ERROR,
CACHE_EVENT_REFRESH_START,
CACHE_EVENT_REFRESH_SUCCESS,
CACHE_EVENT_SCHEMA_MISMATCH,
CACHE_EVENT_SCOPE_ERROR,
CACHE_EVENT_SET,
CACHE_EVENT_SINGLEFLIGHT_JOIN,
CACHE_EVENT_STALE_HIT,
CACHE_EVENT_STALE_IF_ERROR,
CACHE_POLICY_CATALOG,
CACHE_POLICY_IMMUTABLE,
CACHE_POLICY_INTERACTIVE,
CACHE_POLICY_PRIVATE_SESSION,
CACHE_POLICY_REALTIME,
CACHE_READ_MODE_BYPASS_CACHE,
CACHE_READ_MODE_CACHE_FIRST,
CACHE_READ_MODE_MUST_REVALIDATE,
CACHE_READ_MODE_NO_STORE,
CACHE_READ_MODE_STALE_WHILE_REVALIDATE,
CACHE_SCOPE_ACTOR,
CACHE_SCOPE_CUSTOM,
CACHE_SCOPE_PERMISSION,
CACHE_SCOPE_PUBLIC,
CACHE_SCOPE_TENANT,
CacheKeyError,
CachePolicyError,
CacheScopeError,
createMapStorage,
defaultCachePolicies,
durationToMs,
isCacheKeyError,
isCachePolicyError,
isCacheScopeError,
memoryCacheAdapter,
normalizeKey,
normalizeKeyPrefixes,
normalizeTag,
normalizeTags,
resolveScope,
stableHash,
stableStringify,
storageCacheAdapter
} from '$libs/cache';
export type {
CacheAdapter,
CacheAdapterSetOptions,
CacheClock,
CacheDecision,
CacheDecisionAction,
CacheDecisionReason,
CacheEnvelope,
CacheEnvelopeState,
CacheEvent,
CacheEventHandler,
CacheEventSelector,
CacheEventType,
CacheExplain,
CacheKey,
CachePolicy,
CacheReadMode,
CacheRuntime,
CacheRuntimeConfig,
CacheScopeInput,
CacheScopeMode,
CacheStats,
CacheTagLike,
CacheTagObject,
CustomCacheScope,
ExplainOptions,
GetOptions,
InvalidateOptions,
MemoryCacheAdapter,
MemoryCacheAdapterOptions,
MemoryCacheEvictReason,
MutateOptions,
QueryOptions,
ResolvedCachePolicy,
ResolvedCacheScope,
ResolvedScopeValues,
ScopeResolver,
SetOptions,
StorageCacheAdapterOptions,
StorageLike
} from '$libs/cache';
/**
* Server-side surface for `cache`. After the codex audit blocker #8 fix,
* the engine factory + diagnostics + types live in `$libs/cache` (the
* pure layer) so `arts/cache` can consume them without inverting layers.
*
* This module re-exports the same names from `$libs/cache` so historical
* `import { ... } from '$svrs/cache'` callers keep working — production
* compositions, READMEs, docs and ecosystem tests all flow through here.
*/
export * from '$libs/cache';

@ -1,7 +1,15 @@
<script lang="ts">
import { onDestroy } from 'svelte';
import { createActiveApp } from '$active-app';
import { cookieAdapter, localAdapter } from '$storage';
import {
defineActiveCache,
defineActiveFormat,
defineActiveFrontend,
defineActiveLang,
defineActiveStorage,
defineEngineSium
} from '$active-app/services';
import { localAdapter } from '$storage';
import type { SupportedLocale } from '$lang';
import { siumLangs, type Issue } from '$sium';
import { LogLevel, type LogEntry, type Transport } from '$logger';
@ -25,39 +33,36 @@
let appRoot = $state<HTMLElement | null>(null);
const App = createActiveApp({
lang: { schema: langSchema, defaultLocale: 'es', fallbackChain: ['en'] },
logger: {
level: LogLevel.TRACE,
globalContext: { surface: '/test/aapp' },
transports: [captureTransport]
},
storage: { adapter: localAdapter, namespace: 'test-aapp' },
cache: {
services: {
lang: defineActiveLang({
schema: langSchema,
defaultLocale: 'es',
fallbackChain: ['en']
}),
storage: defineActiveStorage({ adapter: localAdapter, namespace: 'test-aapp' }),
format: defineActiveFormat(),
cache: defineActiveCache({
defaultMemoryAdapter: { suppressProductionWarning: true }
},
frontend: {
}),
frontend: defineActiveFrontend({
theme: 'base',
mode: 'auto',
density: 'normal',
target: () => appRoot,
persist: {
// Theme via cookie (server-readable for SSR demos), the rest in
// localStorage with the App's namespace.
overrides: {
theme: {
adapter: cookieAdapter({ path: '/', sameSite: 'lax', maxAge: 31_536_000 }),
namespace: false,
raw: true
}
}
}
density: 'comfortable',
target: () => appRoot
}),
sium: defineEngineSium()
}
});
// Sium is page-scoped — `App.createSiumEngine()` wires App.lang +
// App.Logger so issues translate live and validation diagnostics flow
// through the same bus.
const sium = App.createSiumEngine();
// Sium is now an App service — `App.sium` is the validation engine,
// wired to App.lang for i18n issue messages and to App.Logger for
// diagnostics through the same bus.
const sium = App.sium;
onDestroy(() => App.dispose());
@ -76,7 +81,7 @@
];
function setLocale(locale: SupportedLocale): void {
App.setLocale(locale);
App.lang.setLocale(locale);
App.Logger.info('locale', `Locale switched to ${locale}`, {
context: { locale }
});
@ -121,7 +126,7 @@
loginIssues.map((entry) => ({
path: entry.path.length === 0 ? '<root>' : entry.path.join('.'),
code: entry.code,
message: sium.resolveIssue(entry, App.getLocale())
message: sium.resolveIssue(entry, App.lang.getLocale())
}))
);
@ -199,7 +204,7 @@
<section class="locale" dir="ltr">
<h2>1. Locale (single source of truth)</h2>
<p class="hint">
<code>App.setLocale(...)</code> propagates to <strong>Lang</strong>,
<code>App.lang.setLocale(...)</code> propagates to <strong>Lang</strong>,
<strong>Format</strong> and <strong>Frontend</strong> through a shared
<code>LocaleSource</code>. BCP 47 resolution runs per record on every
<code>Lang.t()</code> call.
@ -208,7 +213,7 @@
{#each LOCALES as { code, label, flag } (code)}
<button
type="button"
class:active={App.getLocale() === code}
class:active={App.lang.getLocale() === code}
onclick={() => setLocale(code)}
>
<span aria-hidden="true">{flag}</span>
@ -218,7 +223,7 @@
{/each}
</div>
<p class="active-line">
<strong>Active:</strong> <code>{App.getLocale()}</code>
<strong>Active:</strong> <code>{App.lang.getLocale()}</code>
</p>
</section>

@ -1,8 +0,0 @@
/**
* Skip static prerender for the legacy aapp demo. The page still
* relies on pre-service-schema App methods that the current runtime
* no longer exposes; until it is migrated to
* `createActiveApp({ services })`, render it on-demand only so the
* static gate stays green and the page remains reachable in dev.
*/
export const prerender = false;

@ -1,5 +1,6 @@
<script lang="ts">
import { createActiveApp } from '$active-app';
import { defineActiveCache } from '$active-app/services';
import {
CACHE_EVENT_ALL,
CACHE_POLICY_INTERACTIVE,
@ -54,7 +55,8 @@
let logSeq = 0;
const App = createActiveApp({
cache: {
services: {
cache: defineActiveCache({
defaultMemoryAdapter: { suppressProductionWarning: true },
scopeResolver: (): ResolvedScopeValues => ({
tenantId,
@ -80,6 +82,7 @@
persist: false
}
}
})
}
});

@ -1,2 +0,0 @@
/** Skip static prerender — uses pre-service-schema App API. See /test/aapp. */
export const prerender = false;

@ -2,6 +2,11 @@
import { onDestroy } from 'svelte';
import { resolve } from '$app/paths';
import { createActiveApp } from '$active-app';
import {
defineActiveCache,
defineActiveConnections,
defineActiveSession
} from '$active-app/services';
import { LogLevel } from '$logger';
import {
CONNECTION_BUFFER_POLICY_BUFFER,
@ -88,12 +93,31 @@
at: string;
};
// Declared up here so the session factory's `onRefresh` closure can
// capture them. They are mutated by UI actions later in the file.
let refreshMode: 'success' | 'expired' = 'success';
let tokenSerial = 1;
const App = createActiveApp({
logger: { level: LogLevel.NONE, transports: [] },
cache: {
services: {
cache: defineActiveCache({
defaultMemoryAdapter: { suppressProductionWarning: true }
},
connections: {
}),
session: defineActiveSession<ChatUser, ChatCredential>({
schemas: {},
onRefresh: async (current) => {
if (refreshMode === 'expired') return null;
tokenSerial += 1;
return {
...current,
credential: { token: `chat-token-${tokenSerial}` },
issuedAt: Date.now(),
expiresAt: Date.now() + 120_000
};
}
}),
connections: defineActiveConnections({
defaults: {
heartbeat: false,
buffer: {
@ -106,6 +130,7 @@
jitterMs: 0
}
}
})
}
});
@ -114,8 +139,6 @@
let draft = $state('Hola, esto va por WebSocket real');
let pendingQuestion = $state(false);
let serverTyping = $state(false);
let refreshMode: 'success' | 'expired' = 'success';
let tokenSerial = 1;
let messages = $state<ChatMessage[]>([]);
let states = $state<ConnectionStateChange[]>([]);
let frames = $state<FrameLog[]>([]);
@ -166,21 +189,9 @@
}
};
const Sess = App.createActiveSession<ChatUser, ChatCredential>({
schemas: {},
onRefresh: async (current) => {
if (refreshMode === 'expired') return null;
tokenSerial += 1;
return {
...current,
credential: { token: `chat-token-${tokenSerial}` },
issuedAt: Date.now(),
expiresAt: Date.now() + 120_000
};
}
});
const Sess = App.session;
const Connections = App.createActiveConnections<AppConnections>();
const Connections = App.connections;
const Chat = Connections.createConnection(CONNECTION_NAME, {
transport: () =>
createWebSocketTransport({

@ -1,2 +0,0 @@
/** Skip static prerender — uses pre-service-schema App API. See /test/aapp. */
export const prerender = false;

@ -2,6 +2,18 @@
import { onDestroy, untrack } from 'svelte';
import { resolve } from '$app/paths';
import { createActiveApp } from '$active-app';
import {
defineActiveAuth,
defineActiveCache,
defineActiveConnections,
defineActiveFrontend,
defineActiveLang,
defineActivePerm,
defineActiveSession,
defineActiveStorage,
defineEngineHttp,
defineEngineSium
} from '$active-app/services';
import {
CACHE_EVENT_ALL,
CACHE_POLICY_INTERACTIVE,
@ -347,39 +359,45 @@
return jsonResponse({ error: 'not-found', path }, 404);
}) as typeof fetch;
// `currentLocale` mirrors `App.lang.getLocale()` so the cache scope
// resolver can read it without referencing the App handle (which
// doesn't exist yet at the moment the resolver is captured).
let currentLocale: SupportedLocale = DEFAULT_ECOSYSTEM_LOCALE;
const App = createActiveApp({
lang: {
schema: translations,
defaultLocale: DEFAULT_ECOSYSTEM_LOCALE,
fallbackChain: ['en-US']
},
logger: {
level: LogLevel.TRACE,
globalContext: { surface: DEMO_PATH },
transports: [captureTransport]
},
storage: {
services: {
lang: defineActiveLang({
schema: translations,
defaultLocale: DEFAULT_ECOSYSTEM_LOCALE,
fallbackChain: ['en-US']
}),
storage: defineActiveStorage({
adapter: createMemoryAdapter(),
namespace: 'test-ecosystem'
},
frontend: {
}),
frontend: defineActiveFrontend({
target: () => appRoot,
theme: 'base',
mode: 'auto',
density: 'comfortable'
},
http: {
}),
http: defineEngineHttp({
fetch: demoFetch,
timeout: 0,
retry: { limit: 0 }
},
cache: {
}),
cache: defineActiveCache({
defaultMemoryAdapter: { suppressProductionWarning: true },
scopeResolver: (): ResolvedScopeValues => ({
tenantId: data.sessionSeed.tenantId,
actorId: data.sessionSeed.actorId,
permissionHash: `${actorRole}:${mfaEnabled ? AUTH_AAL.MULTI_FACTOR : AUTH_AAL.SINGLE_FACTOR}`,
locale: App.getLocale()
locale: currentLocale
}),
policies: {
[CACHE_POLICY_INTERACTIVE]: {
@ -391,16 +409,30 @@
persist: true
}
}
},
connections: {
}),
connections: defineActiveConnections({
defaults: {
heartbeat: false,
reconnect: false
}
}),
sium: defineEngineSium(),
auth: defineActiveAuth({ initial: initialData.authCurrent }),
session: defineActiveSession<DemoUser, undefined, DemoSessionData>({
storage: {
adapter: createMemoryAdapter(),
key: SESSION_STORAGE_KEY
}
}),
perm: defineActivePerm({
endpoint: PERM_ENDPOINT,
cacheTtlMs: 8_000,
scopeKey: () => `${data.sessionSeed.actorId}:${actorRole}:${mfaEnabled}`
})
}
});
const Sium = App.createSiumEngine();
const Sium = App.sium;
const projectDraftSchema = Sium.object({
title: Sium.pipe(Sium.string(), Sium.min(4), Sium.meta({ label: 'Title' })),
budget: Sium.pipe(Sium.number(), Sium.min(1000), Sium.meta({ label: 'Budget' }))
@ -422,13 +454,8 @@
{ mergeDefaults: true }
);
const Auth = App.createActiveAuth({ initial: initialData.authCurrent });
const Sess = App.createActiveSession<DemoUser, undefined, DemoSessionData>({
storage: {
adapter: createMemoryAdapter(),
key: SESSION_STORAGE_KEY
}
});
const Auth = App.auth;
const Sess = App.session;
Sess.adoptServer({
user: {
id: initialData.sessionSeed.actorId,
@ -444,13 +471,7 @@
expiresAt: initialData.sessionSeed.expiresAt
});
const Perms = setPermsContext(
App.createActivePerms({
endpoint: PERM_ENDPOINT,
cacheTtlMs: 8_000,
scopeKey: () => `${data.sessionSeed.actorId}:${actorRole}:${mfaEnabled}`
})
);
const Perms = setPermsContext(App.perm);
const transport = createMockTransport();
const loggingSerializer: ConnectionSerializer<ConnectionFrame> = {
@ -501,7 +522,7 @@
key: `${issue.path.join('.')}:${issue.code}`,
path: issue.path.length === 0 ? '<root>' : issue.path.join('.'),
code: issue.code,
message: Sium.resolveIssue(issue, App.getLocale())
message: Sium.resolveIssue(issue, App.lang.getLocale())
}))
);
@ -509,7 +530,7 @@
void App.lang.getLocale();
void App.frontend.getTheme();
return {
locale: App.getLocale(),
locale: App.lang.getLocale(),
dir: App.frontend.getDir(),
theme: App.frontend.getTheme(),
mode: App.frontend.getMode(),
@ -552,7 +573,8 @@
function setLocale(locale: SupportedLocale): void {
selectedLocale = locale;
App.setLocale(locale);
currentLocale = locale;
App.lang.setLocale(locale);
pushEvent('lang', `locale -> ${locale}`);
}

@ -369,7 +369,7 @@
<aside class="resolved">
<h3>Resolved issue messages</h3>
<p class="hint">
<code>App.createSiumEngine().resolveIssues(r.issues)</code> — the
<code>App.sium.resolveIssues(r.issues)</code> — the
raw <code>#?sium.errors.type|...</code> refs above become readable
text via Sium's lang resolver (here lang-less, so the
<code>|fallback</code> text is interpolated with each issue's

@ -1,6 +0,0 @@
/**
* Skip static prerender for the legacy http demo. The page still
* relies on pre-service-schema App methods that the current runtime
* no longer exposes; render it on-demand only.
*/
export const prerender = false;

@ -2,6 +2,11 @@
import { onDestroy, untrack } from 'svelte';
import { resolve } from '$app/paths';
import { createActiveApp } from '$active-app';
import {
defineActiveCache,
defineActivePerm,
defineEngineHttp
} from '$active-app/services';
import { LogLevel } from '$logger';
import Can from '$perm/Can.svelte';
import {
@ -267,21 +272,23 @@
const App = createActiveApp({
logger: { level: LogLevel.NONE, transports: [] },
http: {
services: {
http: defineEngineHttp({
fetch: permFetch,
timeout: 0,
retry: { limit: 0 }
},
cache: {
}),
cache: defineActiveCache({
defaultMemoryAdapter: { suppressProductionWarning: true }
},
permissions: {
}),
perm: defineActivePerm({
endpoint: PERM_ENDPOINT,
cacheTtlMs: 10_000
})
}
});
const Perms = setPermsContext(App.createActivePerms());
const Perms = setPermsContext(App.perm);
function effectClass(decision: PermDecision | null | undefined): string {
if (!decision) return 'none';

@ -1,2 +0,0 @@
/** Skip static prerender — uses pre-service-schema App API. See /test/aapp. */
export const prerender = false;

@ -25,12 +25,7 @@
// `+page.ts`; excluding them here keeps `npm run check` green until they
// are migrated. The codex follow-up (audit-2 §3) tracks the migration.
"./src/web/routes/demo/**",
"./src/web/routes/test/aapp/**",
"./src/web/routes/test/cach/**",
"./src/web/routes/test/conn/**",
"./src/web/routes/test/ecosystem/**",
"./src/web/routes/test/http/**",
"./src/web/routes/test/perm/**",
"./src/web/routes/test/auth/**/*",
"./src/web/routes/test/auth/+page.server.ts",
"./src/web/routes/active/_data/artifact-docs.ts",

Loading…
Cancel
Save

Powered by TurnKey Linux.