Magazin

Wochenupdate: Routing, reaktive UI, Logs und Promptvertrauen

Vier gemergte Änderungen zeigen neue APIs für Web Components, Lit, PHP-Logging und Promptquellen. Nur Phore Log liegt in dieser Auswahl als bestätigtes Release 3.0.0 vor.

Zuerst die Versionsgrenze: TrunkJS Router und Prolit sind auf main gemergt, ebenso die Vertrauenslogik des Phore AI Harness. Für diese drei Änderungen ist in den geprüften Quellen kein Paket-Release bestätigt. Phore Log wurde nach master gemergt und als v3.0.0 veröffentlicht. Die Beispiele zu den drei nur als Repository-Stand bestätigten Bausteinen beschreiben daher nicht automatisch eine installierbare Registry-Version.

TrunkJS Router: Route, Outlet und sichtbarer Parameter

@trunkjs/router ist ein Frontend-Router für Web Components. Ein Router ordnet Browserpfade Komponenten zu und verwaltet Navigation und Verlauf einer Single-Page-Anwendung.

import {
  Router,
  route,
  setDefaultRouter,
  withRouter,
  type RouteChange,
} from '@trunkjs/router';

@route({ name: 'user', path: '/users/:id' })
class UserPage extends withRouter(HTMLElement) {
  override onRouteChange({ route }: RouteChange) {
    this.textContent = `User ${route.params['id']}`;
  }
}

customElements.define('app-user-page', UserPage);

const router = new Router([UserPage]);
setDefaultRouter(router);
document.body.innerHTML =
  '<router-content></router-content><a href="/users/7">User 7</a>';
router.start();
if (!router.current) {
  router.replace({ name: 'user', params: { id: 42 } });
}

Beim Einstieg zeigt das Outlet User 42; der Link wechselt per SPA-Navigation zu User 7. withRouter verbindet die Komponente mit Routenänderungen, <router-content> ist der Ausgabeplatz. Tiefe Links muss der Server auf die Anwendungsschale zurückführen. Navigation Guards, verschachtelte Routenvererbung, Scroll-Management und ein eigener Server-Fallback gehören nicht zum Router.

Prolit: reaktiven Scope in Lit einsetzen

Prolit ist ein reaktives Scope- und Template-System im TrunkJS-Monorepo. prolit(scope, fallback?) bindet einen Scope an einen Lit-Child-Part, also eine dynamische Stelle in einem Lit-Template.

const scope = scopeDefine({
  name: 'Ada',
  $fn: { rename: () => { scope.name = 'Ada Lovelace'; } },
  $tpl: prolit_html`
    <p></p>
    <button @click="$fn.rename()">Rename</button>
  `,
});

class UserCard extends LitElement {
  protected override render() {
    return html`${prolit(scope)}`;
  }
}

Für asynchrone Arbeit ergänzt scopeResource abbrechbare Lesevorgänge, bei denen der neueste Versuch gewinnt. scopeAction bündelt Pending- und Fehlerzustand und verhindert parallele Aufrufe. Diese APIs sind auf main dokumentiert; ein Paket-Release ist in den geprüften Quellen nicht bestätigt.

Phore Log 3.0.0: Vorgeschichte erst beim Fehler ausgeben

phore/log ist eine PSR-3-kompatible PHP-Loggingbibliothek. Version 3.0.0 ergänzt hierarchische Scopes, Kontext, semantische Konsolentypen und einen Fehlerpuffer.

$trace = Phore\Log\PhoreLogger::bufferedConsole(capacity: 50);
$trace->debug('Candidate A score {score}', ['score' => 0.71]);
$trace->step('Select best candidate');
$trace->error('Model resolution failed');

Der Puffer bleibt zunächst still. Erst bei einem Fehler gibt er die letzten Datensätze in Reihenfolge aus. Scopes erlauben zusätzlich zentral gesteuerte Detailstufen:

$log->setScopeLevel('user', Phore\Log\LogLevelEnum::DEBUG);
$log->scope('user')->scope('repository')->debug('Load current user');

Version 3 setzt PHP 8.5 oder neuer voraus. Das ist vor dem Update ein Kompatibilitätstest, keine Fußnote.

AI Harness: Drei verschiedene Vertrauensgrenzen

Phore AI Harness ist eine PHP-Bibliothek zum Aufbau von Modellaufrufen. Die gemergte Änderung unterscheidet drei Wege:

  1. Content-Prompt-Typen: TextPrompt, FilePrompt, ImagePrompt, AudioPrompt und StructPrompt behandeln ihren Inhalt standardmäßig als externe, unvertrauenswürdige Daten (allowInstructions: false).
  2. Stringkurzformen der globalen Funktionen: Ein direktes phore_ai_text('...') oder ein String in einer Prompt-Liste gilt als ausdrückliche Arbeitsanweisung des Anwendungscodes und wird intern als TextPrompt(..., allowInstructions: true) normalisiert. new TextPrompt($externalText) behält dagegen den sicheren Default false.
  3. PromptFile: Dieser Typ lädt eine Datei, die selbst den Prompt definiert. Der eigene Markdown-Body und über extends geerbte Prompt-Bodies sind Anweisungen. Dateien unter references bleiben standardmäßig unvertrauenswürdige Quelldaten und werden nur mit allow_instructions: true zur Instruktionsquelle.

PromptFile ist damit nicht dasselbe wie FilePrompt: PromptFile definiert den Prompt aus einer Datei; FilePrompt hängt eine Datei als Material an einen bestehenden Prompt.

$mail = FilePrompt::fromFile(
    __DIR__ . '/customer-email.txt',
    alias: 'customerMail',
    instructions: 'Extrahiere nur Termin und Bestellnummer.',
); // Dateiinhalt bleibt externe/untrusted data

$rules = FilePrompt::fromFile(
    __DIR__ . '/approved-rules.md',
    alias: 'approvedRules',
    allowInstructions: true,
); // Inhalt ist ausdrücklich instruction-enabled

Das separate Argument instructions stammt aus dem Anwendungscode und sagt, wie die Quelle verwendet werden soll. allowInstructions entscheidet dagegen, ob Anweisungen im Inhalt befolgt werden dürfen.

Für dateibasierte Prompts sieht die Grenze so aus:

extends:
  - path: base.prompt.md       # Prompt-Body: Anweisung
references:
  - path: ../external-data.md  # standardmäßig unvertraute Daten
  - path: ../approved-rules.md
    allow_instructions: true   # bewusst als Anweisung freigegeben

Das ist kein vollständiger Schutz gegen Prompt Injection. Es macht aber sichtbar, ob Inhalt als Daten oder als Anweisung gedacht ist. Für die AI-Harness-Änderung ist in den geprüften Quellen kein Release bestätigt.

Quellen

Quellenstand: 20. September 2026.