Hoppa till innehållet

Devportalen /portal/dev

Startsideportalens ekosystem för människa och agent

Dokumentationen / Paket

@startsidan/module-sdk

PaketStartsideportalen

Kontraktet mellan skalet och modulerna, plus urvalsfunktionerna skalet använder för att komponera dem.

källa: packages/module-sdk/srcuppdaterad: 2026-10-07

Ansvar

  • Definiera ModuleManifest, UserContext och de typer modulerna fyller.
  • Göra urvalet: filtrera på roll, sortera på order, aggregera actions.
  • Äga den samlade uppgiftslistan: uppgifterFor läser alla modulers uppgifter, öppna och hanterade, med källan ifylld – vid varje anrop, utan lager.
  • Låta aggregerande moduler nå registret utan att skalet skickar det som prop.
  • Beskriva redaktionella sidor och deras innehåll som block, oberoende av källa.
  • Bära flödestyperna tills motorn lyfts till packages/flow-engine i M4.

Filer

Tabell: Sökväg, Roll
SökvägRoll
packages/module-sdk/src/types.tsModuleManifest, UserContext, Widget (med label för flyttknapparna, ADR-018), ActionItem, ModuleRoute (focus, standard, full) och RouteComponent (ADR-019, ADR-025), Genvag (ADR-025), Notification och NotificationsProvider (ADR-020), FokusItem och FokusProvider (ADR-021), IntentHandler.
packages/module-sdk/src/select.tswidgetsFor, actionsFor, uppgifterFor, navFor, genvagarFor, mergeNav, routeFor (med parametrar), matchaVag, suggestionsFor.
packages/module-sdk/src/define.tsdefineModule: typkontroll utan annotering.
packages/module-sdk/src/provide.tsprovideRegistry och currentRegistry (ADR-007).
packages/module-sdk/src/page.tsPageManifest, PageContent, ContentBlock och Inline (ADR-016).
packages/module-sdk/src/pages.tsfindPage, pageTrail, pageHref, hubsInSection, articlesUnder, resolveContent, pageProblems.
packages/module-sdk/src/flow.tsFlowDefinition, turkontraktets zod-schema, farSkapas.
packages/module-sdk/src/prompt.tsbyggSystemprompt: systemprompten ur flödesdefinitionen, inklusive blocket med redan fastställda fält (ADR-013).

API

Tabell: Namn, Signatur, Beskrivning
NamnSignaturBeskrivning
defineModule(manifest: ModuleManifest) => ModuleManifestIdentitetsfunktion som ger typkontroll på manifestet.
widgetsFor(modules, slot, ctx) => Widget[]Widgets i en slot som rollen ska se, i ordning. Widgetens roles är snävare än modulens.
actionsFor(modules, ctx) => Promise<ActionItem[]>Aggregatet bakom "Att agera på": de öppna uppgifterna. En modul som fallerar tar inte ned kortet.
uppgifterFor(modules, ctx) => Promise<Uppgift[]>Den samlade uppgiftslistan bakom Mina uppgifter och AI-assistentens verktyg: öppna i ordning, sedan hanterade, senast hanterade först. Varje uppgift får modul, kalla (modulens namn om modulen inte satt en) och lage (öppen om inget sattes).
routeFor(modules, path, ctx) => { route, module, params } | undefinedSlår upp en modulrutt, med parametrar ur mönster som /verktyg/personal/:id. En exakt väg går före ett mönster (ADR-019).
fokusFor(modules, ctx) => Promise<FokusItem[]>Fokusytornas innehåll, nyast först. Skalet visar den första som inte är stängd (ADR-021).
genvagarFor(modules, ctx) => Genvag[]Knapparna bredvid hälsningen på startsidan, rollfiltrerade och sorterade på order (ADR-025).
notificationsFor(modules, ctx) => Promise<Notification[]>Klockans notiser från alla moduler, nyast först. En modul som fallerar tar inte ned de andras (ADR-020).
matchaVag(monster: string, path: string) => Record<string, string> | undefinedMönstermatchningen bakom routeFor. ":namn" fångar ett segment.
intentsFor / matchaAvsikt(modules, ctx) => IntentHandler[] / (intents, fraga) => IntentHandler | undefinedAvsikterna rollen når, och den första vars mönster står i frågan – gemener, delsträng. AI-fältet använder dem före modellen.
provideRegistry / currentRegistry(all: ModuleManifest[]) => void / () => ModuleManifest[]Registret för aggregerande moduler (ADR-007).
findPage(modules, segments: string[]) => PageManifest | undefinedSlår upp en sida på URL-segmenten under /sidor: [sektion, ingång] eller [sektion, ingång, artikel].
pageTrail / pageHref(modules, page) => PageManifest[] / (page) => stringBrödsmulorna från ingången ned till sidan, och sidans väg.
resolveContent(page, ctx) => Promise<PageContent>Statiskt innehåll eller källa – skalet behöver inte veta vilket.
topPagesInSection(modules, section) => PageManifest[]Sektionens sidor utan parent – ingångar och inramade sidor. En webbplats meny.
pageProblems(modules) => string[]Registrets invarianter: unika slugar, artikelns parent är en ingång i samma sektion. Körs i test.
byggSystemprompt(flow, profil, faltHittills?) => stringPrompten ur flödet. faltHittills förankrar värdena så att modellen återger dem ordagrant i stället för att formulera om sig varje tur.
buildTurnSchema(flow: FlowDefinition) => ZodObjectTurkontraktet byggt ur flödet: reply, fields, complete, create.
farSkapas(flow, turCreate, varden, antalAnvandarsvar) => booleanTre villkor samtidigt: modellen har begärt det, allt obligatoriskt finns, och användaren har sett en sammanfattning.

Kontrakt

Kontraktet ska hållas tunt. Ett nytt fält gör det tyngre för alla moduler och ska bäras av minst två innan det blir permanent.

Rollfiltreringens tre nivåer – den snävaste vinner

roles på modulen        gäller allt modulen bidrar med
roles på widgeten      snävare än modulens
roles på nav-posten    snävare än modulens

PageManifest och innehållsblocken (page.ts)

interface PageManifest {
  slug: string;            // unik i registret, blir ctx.page
  section: string;         // sektions-id ur skalets "Sidor"
  parent?: string;         // ingångens slug – bara för en artikel
  layout: "hub" | "article";
  title: string; lede?: string; kicker?: string;
  quickLinks?: QuickLink[];          // bara ingång
  article?: ArticleMeta;             // bara artikel
  ai?: { suggestions?: (ctx) => Suggestion[] };
  content?: PageContent | ((ctx) => Promise<PageContent>);
}

type ContentBlock =
  | { type: "heading"; level: 2 | 3 | 4; text: string }
  | { type: "paragraph"; inlines: Inline[] }
  | { type: "list"; ordered: boolean; items: Inline[][] }
  | { type: "image"; src: string; alt: string; caption?: string };
// Aldrig HTML: en adapter översätter källan till block (ADR-016).

  | { type: "details"; summary: string; chip?: { label; tone }; blocks: ContentBlock[] }   // ADR-022

PageManifest.slots?: { main?: Widget[]; side?: Widget[] }   // bara ingång: modulens egna kort
PageContent.cards?: { title: string; blocks: ContentBlock[] }[]   // fler redaktionella kort
QuickLink.cta?: string                                       // knapptext på snabbvägskortet

interface PageLink { title: string; href: string; external: boolean; children?: PageLink[] }
// layout "embed" + embed: { src } = en extern sida i ram (ADR-017). https, ingen parent.
// children = en hopfälld nivå; så blir en webbkarta en länklista, inte en sidtyp.

Beroenden och beslut

Kvarstår

  • IntentHandler matchas med enkla mönster (matchaAvsikt) av AI-fältet; LLM-matchning av avsikter finns inte.
  • Sidor rollfiltreras inte – de är gemensamma enligt ADR-003. Behövs det, är det ett nytt fält och en ny ADR.
  • Flödestyperna ligger här i väntan på M4. ADR-005 skrivs när motorn lyfts.