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/src/uix/contracts.ts

254 lines
8.2 KiB

import { UIX_REQUIRED_SERVICES } from './active-uix/services';
import type { ActiveApp } from '$active-app';
import type { ActiveClipboard } from '$clipboard';
import type { ActiveDom } from '$adom';
import type { EngineBus } from '$bus';
import type { ActiveEidos } from './eidos/active-eidos.svelte';
import type { ActiveFormat } from '$format';
import type { ActiveLangs } from '$langs';
import type { EngineLogger } from '$logger';
import type { ActivePrefs } from '$prefs';
import type { ActiveTimers } from '$timer';
import type { EngineSemantic } from './sema';
import type { EngineMotion } from '$motion';
import type { EngineScene } from '$scene';
import type { EngineSound } from '$sound';
import type { Morfo } from './morfo';
import type { SomaRuntime } from './soma/runtime.svelte';
import type { ActiveUix } from './active-uix/types';
import type { UixRequiredService } from './active-uix/services';
export interface ActiveUixServiceContract {
readonly langs: ActiveLangs;
readonly format: ActiveFormat | undefined;
readonly dom: ActiveDom;
readonly motion: EngineMotion;
readonly scene: EngineScene | undefined;
readonly sound: EngineSound;
readonly clipboard: ActiveClipboard;
readonly events: EngineSemantic | undefined;
readonly logger: EngineLogger;
readonly bus: EngineBus;
readonly timers: ActiveTimers;
readonly prefs: ActivePrefs;
readonly portal: string | HTMLElement | undefined;
readonly app: ActiveApp | undefined;
readonly ownsApp: boolean;
announce(message: string, priority?: 'polite' | 'assertive', timeout?: number): void;
dispose(): void;
}
export interface SomaRuntimeContract {
// Widened on purpose: this table pins the SHAPE of the runtime surface
// across every morfo, not one component's names — the one boundary where
// `SomaRuntime<Morfo>` is the honest instantiation.
part: SomaRuntime<Morfo>['part'];
partProps: SomaRuntime<Morfo>['partProps'];
keydown: SomaRuntime<Morfo>['keydown'];
trigger: SomaRuntime<Morfo>['trigger'];
}
export interface EventsServiceContract {
emit: EngineSemantic['emit'];
dispose: EngineSemantic['dispose'];
}
export interface ActiveEidosRuntimeContract {
readonly dom: ActiveDom;
readonly langs: ActiveLangs;
readonly format: ActiveFormat | undefined;
readonly prefs: ActivePrefs;
getThemeId(): string;
renderStaticCss(): string;
apply(): void;
dispose(): void;
}
export interface UixLayerContractTable {
readonly activeUix: {
readonly standaloneCreates: readonly string[];
readonly attachRequires: readonly UixRequiredService[];
readonly publicSurface: readonly (keyof ActiveUixServiceContract)[];
readonly forbiddenPublicSurface: readonly string[];
};
readonly prefsDomProjection: {
readonly role: 'cross-modal-prefs-projection';
readonly implementation: '$prefs.createActivePrefsDomProjection';
readonly requires: readonly ['prefs', 'dom'];
readonly ownsAttrs: readonly ['dir', 'lang', 'data-motion', 'data-sound', 'data-haptic'];
readonly forbiddenAttrs: readonly ['data-theme', 'data-mode', 'data-density'];
readonly createsServices: readonly [];
};
readonly morfo: {
readonly role: 'declarative-contract';
readonly owns: readonly string[];
readonly createsServices: readonly [];
readonly translationNamespacePrefix: 'components';
};
readonly somaRuntime: {
readonly role: 'morfo-interpreter';
readonly requires: readonly ['dom'];
readonly optional: readonly ['eventEngine', 'translate'];
readonly publicSurface: readonly (keyof SomaRuntimeContract)[];
readonly forbiddenPublicSurface: readonly string[];
readonly createsServices: readonly [];
};
readonly events: {
readonly role: 'perceptual-dispatch';
readonly publicServiceName: 'events';
readonly morfoPayloadName: 'semantic';
readonly requiresOneOfForVisualProjection: readonly ['dom', 'projector'];
/**
* What `defineEngineSemantic()` takes from the app schema. Both degrade to
* `undefined`: without `dom` there is no visual projection, and without
* `sound` the sound channel owns a private engine — which is why `sound`
* is listed here at all: it is how the row below keeps its
* `singleContextPerDocument` promise in attach mode.
*/
readonly serviceDependencies: readonly ['dom', 'sound'];
readonly createsServices: readonly [];
};
/**
* The Web Audio runtime (`$sound`). Requires nothing: both dependencies are
* optional ports and both degrade — without `dom` a context suspended by the
* autoplay policy resumes on the next `prime()` instead of on the next
* gesture; without `timers` the earcon's completion falls back to
* `setTimeout`. Without an `AudioContext` at all it is silently inert, which
* is why it can be created unconditionally.
*
* `singleContextPerDocument` is the invariant the art exists for: browsers
* cap concurrent contexts and the unlock gesture is per-context, so every
* consumer takes THIS engine (sema via `soundEngine`, everyone else via
* `uix.sound.context`) instead of opening its own.
*/
readonly sound: {
readonly role: 'web-audio-runtime';
readonly publicServiceName: 'sound';
readonly optional: readonly ['dom', 'timers'];
readonly degradation: 'silent';
readonly singleContextPerDocument: true;
readonly createsServices: readonly [];
};
readonly activeEidos: {
readonly role: 'visual-runtime';
readonly publicRuntime: 'ActiveEidos';
readonly forbiddenRuntime: 'EngineEidos';
readonly requiresForDomApply: readonly ['dom'];
readonly constructionOptionalServices: readonly ['langs', 'format', 'prefs'];
readonly requiredAccessors: readonly ['langs', 'prefs'];
readonly optionalAccessors: readonly ['format'];
readonly createsServices: readonly [];
};
}
export const UIX_LAYER_CONTRACTS = {
activeUix: {
standaloneCreates: [
'logger',
'bus',
'timers',
'prefs',
'langs',
'dom',
'clipboard',
'format',
'events',
'sound'
],
attachRequires: UIX_REQUIRED_SERVICES,
publicSurface: [
'langs',
'format',
'dom',
'motion',
'scene',
'sound',
'clipboard',
'events',
'logger',
'bus',
'timers',
'prefs',
'portal',
'app',
'ownsApp',
'announce',
'dispose'
],
forbiddenPublicSurface: [
'lang',
'semantic',
'frontend',
'soma',
'eidos',
'somaPortalTo',
'settings',
'presentation'
]
},
prefsDomProjection: {
role: 'cross-modal-prefs-projection',
implementation: '$prefs.createActivePrefsDomProjection',
requires: ['prefs', 'dom'],
ownsAttrs: ['dir', 'lang', 'data-motion', 'data-sound', 'data-haptic'],
forbiddenAttrs: ['data-theme', 'data-mode', 'data-density'],
createsServices: []
},
morfo: {
role: 'declarative-contract',
owns: ['parts', 'states', 'props', 'events', 'translations'],
createsServices: [],
translationNamespacePrefix: 'components'
},
somaRuntime: {
role: 'morfo-interpreter',
requires: ['dom'],
optional: ['eventEngine', 'translate'],
publicSurface: ['part', 'partProps', 'keydown', 'trigger'],
forbiddenPublicSurface: ['registerPart', 'createAttrs', 'registerContract'],
createsServices: []
},
events: {
role: 'perceptual-dispatch',
publicServiceName: 'events',
morfoPayloadName: 'semantic',
requiresOneOfForVisualProjection: ['dom', 'projector'],
serviceDependencies: ['dom', 'sound'],
createsServices: []
},
sound: {
role: 'web-audio-runtime',
publicServiceName: 'sound',
optional: ['dom', 'timers'],
degradation: 'silent',
singleContextPerDocument: true,
createsServices: []
},
activeEidos: {
role: 'visual-runtime',
publicRuntime: 'ActiveEidos',
forbiddenRuntime: 'EngineEidos',
requiresForDomApply: ['dom'],
constructionOptionalServices: ['langs', 'format', 'prefs'],
requiredAccessors: ['langs', 'prefs'],
optionalAccessors: ['format'],
createsServices: []
}
} as const satisfies UixLayerContractTable;
export type UixLayerContracts = typeof UIX_LAYER_CONTRACTS;
type Extends<T, U> = [T] extends [U] ? true : false;
export const UIX_TYPE_CONTRACTS = {
activeUix: true,
somaRuntime: true,
events: true,
activeEidos: true
} satisfies {
activeUix: Extends<ActiveUix, ActiveUixServiceContract>;
somaRuntime: Extends<SomaRuntime<Morfo>, SomaRuntimeContract>;
events: Extends<EngineSemantic, EventsServiceContract>;
activeEidos: Extends<ActiveEidos, ActiveEidosRuntimeContract>;
};

Powered by TurnKey Linux.