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.
172 lines
5.0 KiB
172 lines
5.0 KiB
/**
|
|
* `createDatingApp` — opinionated `createActiveApp` composition for the
|
|
* Nexo demo. Picks a fixed service schema so consumer components can
|
|
* type their `App` prop as `DatingApp` and get autocomplete on
|
|
* `App.lang`, `App.session`, `App.cache`, … without falling back to
|
|
* `unknown`.
|
|
*
|
|
* Contract intentionally narrower than the README's full list: `auth`,
|
|
* `perm` and `connection` need port wiring that lives outside Phase 0
|
|
* scope (auth flows go through `DatingApiClient` directly while the
|
|
* artifact-level `App.auth` waits for a Nexo-shaped HTTP port). They
|
|
* will be added by their respective phases — see
|
|
* `src/web/routes/dating/plan-implementacion.md`.
|
|
*/
|
|
|
|
import { createActiveApp, type ActiveApp } from '$active-app';
|
|
import {
|
|
defineActiveCache,
|
|
defineActiveFormat,
|
|
defineActiveFrontend,
|
|
defineActiveLang,
|
|
defineActivePrefs,
|
|
defineActiveSession,
|
|
defineActiveStorage,
|
|
defineEngineHttp,
|
|
defineEngineSium
|
|
} from '$active-app/services';
|
|
import type { PrefsCapabilities } from '$libs/prefs';
|
|
import type { DatingUser } from './types.ts';
|
|
import { createDatingApiClient, type DatingApiClient } from './api.ts';
|
|
|
|
/**
|
|
* Bootstrap lang schema. Phase 0 ships only the strings the shell
|
|
* needs; later phases register their own namespaces via
|
|
* `App.lang.extend(...)` rather than threading more keys through
|
|
* here.
|
|
*/
|
|
export const NEXO_LANG_SCHEMA = {
|
|
nexo: {
|
|
title: { es: 'Nexo', en: 'Nexo' },
|
|
tagline: {
|
|
es: 'Demo del ecosistema Active sobre un producto real.',
|
|
en: 'Active ecosystem demo running on a real product.'
|
|
},
|
|
nav: {
|
|
discover: { es: 'Descubre', en: 'Discover' },
|
|
matches: { es: 'Matches', en: 'Matches' },
|
|
profile: { es: 'Perfil', en: 'Profile' },
|
|
safety: { es: 'Seguridad', en: 'Safety' },
|
|
devtools: { es: 'Devtools', en: 'Devtools' }
|
|
},
|
|
auth: {
|
|
login: { es: 'Iniciar sesión', en: 'Sign in' },
|
|
register: { es: 'Crear cuenta', en: 'Sign up' },
|
|
logout: { es: 'Cerrar sesión', en: 'Sign out' }
|
|
}
|
|
}
|
|
} as const;
|
|
|
|
export const NEXO_PREFS_CAPABILITIES: PrefsCapabilities = {
|
|
languages: ['es', 'en'],
|
|
locales: ['es-ES', 'en-US'],
|
|
currencies: ['EUR', 'USD'],
|
|
unitSystems: ['metric', 'imperial'],
|
|
themes: ['light', 'dark', 'system'],
|
|
densities: ['compact', 'comfortable', 'spacious'],
|
|
motions: ['allow', 'reduce', 'system'],
|
|
defaults: {
|
|
language: 'es',
|
|
locale: 'es-ES',
|
|
currency: 'EUR',
|
|
timezone: 'Europe/Madrid',
|
|
unitSystem: 'metric',
|
|
theme: 'light',
|
|
density: 'comfortable',
|
|
motion: 'allow',
|
|
direction: 'ltr'
|
|
}
|
|
};
|
|
|
|
export interface CreateDatingAppOptions {
|
|
/**
|
|
* Override the Nexo API base URL. Defaults to the standalone server
|
|
* at `http://127.0.0.1:8787` (see `servers/dating/README.md`).
|
|
*/
|
|
readonly apiBase?: string;
|
|
/**
|
|
* Optional `fetch` override — typically `event.fetch` during SSR or
|
|
* a mocked transport in tests.
|
|
*/
|
|
readonly fetch?: typeof fetch;
|
|
/**
|
|
* Frontend mount target. SvelteKit pages pass the layout root here
|
|
* so theme / density / direction get applied to the right node.
|
|
*/
|
|
readonly frontendTarget?: () => HTMLElement | null;
|
|
}
|
|
|
|
/**
|
|
* Concrete `ActiveApp` shape exposed by `createDatingApp`. Components
|
|
* accept `App: DatingApp` to keep autocomplete and type-checked
|
|
* service access; using a generic `ActiveApp` here would degrade
|
|
* every service slot to `unknown`.
|
|
*/
|
|
export type DatingApp = ReturnType<typeof composeApp>;
|
|
|
|
function composeApp(options: CreateDatingAppOptions) {
|
|
return createActiveApp({
|
|
services: {
|
|
lang: defineActiveLang({
|
|
schema: NEXO_LANG_SCHEMA,
|
|
defaultLocale: 'es',
|
|
fallbackChain: ['en']
|
|
}),
|
|
prefs: defineActivePrefs({ capabilities: NEXO_PREFS_CAPABILITIES }),
|
|
storage: defineActiveStorage({ namespace: 'nexo' }),
|
|
frontend: defineActiveFrontend({
|
|
target: options.frontendTarget,
|
|
theme: 'base',
|
|
mode: 'auto',
|
|
density: 'comfortable'
|
|
}),
|
|
format: defineActiveFormat(),
|
|
cache: defineActiveCache({
|
|
defaultMemoryAdapter: { suppressProductionWarning: true }
|
|
}),
|
|
http: defineEngineHttp({
|
|
fetch: options.fetch,
|
|
timeout: 10_000,
|
|
retry: { limit: 1 }
|
|
}),
|
|
session: defineActiveSession<DatingUser>({ schemas: {} }),
|
|
sium: defineEngineSium()
|
|
}
|
|
});
|
|
}
|
|
|
|
/**
|
|
* Compose a `DatingApp` plus the Nexo HTTP client. The two are
|
|
* returned together because almost every component needs both —
|
|
* `App` for ecosystem state and `api` for typed server calls — and
|
|
* keeping the construction in one helper means the demo only has one
|
|
* canonical wiring point.
|
|
*
|
|
* Disposing the wrapper tears the App down; the API client is
|
|
* stateless and needs no lifecycle.
|
|
*/
|
|
export interface DatingAppHandle {
|
|
readonly App: DatingApp;
|
|
readonly api: DatingApiClient;
|
|
dispose(): void;
|
|
}
|
|
|
|
export function createDatingApp(options: CreateDatingAppOptions = {}): DatingAppHandle {
|
|
const App = composeApp(options);
|
|
const api = createDatingApiClient({
|
|
base: options.apiBase,
|
|
fetch: options.fetch
|
|
});
|
|
return {
|
|
App,
|
|
api,
|
|
dispose: () => App.dispose()
|
|
};
|
|
}
|
|
|
|
/**
|
|
* Marker re-export so consumers that only need the type don't pull
|
|
* the runtime in just for `ActiveApp`.
|
|
*/
|
|
export type { ActiveApp };
|