Tighten code comments + README (todo §2); trim verbose §2 headers, drop stale planned/next-item markers, correct README status
This commit is contained in:
@@ -1,8 +1,7 @@
|
||||
// Dashboard view model (todo §1): the app-shell "People" list that replaces the placeholder
|
||||
// index. Pure — turns a request URL into the data the building-block partials render, wiring
|
||||
// the §1 helpers end-to-end: parseListQuery → filter/sort/paginate the mock dataset →
|
||||
// composeNav. The dataset stands in for upstream data until plugins/§4 land; everything below
|
||||
// is real, so the filter form, sortable headers and pager round-trip through the URL (zero-JS).
|
||||
// Dashboard view model (todo §1): the home "/" app-shell "People" list. Pure — turns a request
|
||||
// URL into the data the building-block partials render, wiring the §1 helpers end-to-end:
|
||||
// parseListQuery → filter/sort/paginate a mock dataset → composeNav. Mock data stands in for
|
||||
// upstream until §4; the filter form, sortable headers and pager all round-trip the URL (zero-JS).
|
||||
|
||||
import { DEFAULT_MENU, type MenuConfig } from "./menu-config.ts";
|
||||
import { composeNav, type NavNode, type NavOverride } from "./nav.ts";
|
||||
|
||||
@@ -1,9 +1,8 @@
|
||||
// Plugin discovery (todo §2): scan plugins/, import each folder's plugin.ts default export,
|
||||
// validate it, assemble the loaded Plugin[]. The imperative shell over the pure rules in
|
||||
// plugin.ts (isValidPluginId, checkApiVersion, findConflicts). Fails loud: every per-plugin
|
||||
// problem and every error-level conflict is collected and thrown as one boot-stopping Error;
|
||||
// warn-level diagnostics (older-minor apiVersion, shared permission token) are logged, load
|
||||
// continues. The folder name is the id; mount/router wiring is the next §2 item.
|
||||
// validate it, assemble the loaded Plugin[]. The imperative shell over plugin.ts's pure rules
|
||||
// (isValidPluginId, checkApiVersion, findConflicts). Fails loud: every per-plugin problem and
|
||||
// error-level conflict is collected into one boot-stopping Error; warn-level diagnostics
|
||||
// (older-minor apiVersion, shared permission token) log and load continues. Folder name = id.
|
||||
|
||||
import { existsSync, readdirSync } from "node:fs";
|
||||
import { dirname, join } from "node:path";
|
||||
|
||||
@@ -12,7 +12,7 @@ import type { NavOverride } from "./nav.ts";
|
||||
export type Theme = "auto" | "dark" | "light";
|
||||
|
||||
export interface Branding {
|
||||
logo?: string; // optional logo asset path/URL (rendered in the shell — next §2 branding item)
|
||||
logo?: string; // optional logo asset path/URL, rendered in the sidebar brand
|
||||
name: string; // app name shown in the sidebar brand
|
||||
sub?: string; // optional brand subtitle
|
||||
theme?: Theme; // default color theme for the theme-switch
|
||||
|
||||
@@ -1,12 +1,9 @@
|
||||
// The plugin contract (todo §2) — the product's main API surface. This module is the
|
||||
// authoritative, machine-readable shape; `docs/plugin-contract.md` is the prose reference.
|
||||
// It only declares types + pure rules; the §2 discovery/router wire them to the filesystem
|
||||
// and HTTP. Philosophy: a powerful, predictable, overload-friendly API that fails loud at
|
||||
// boot/discovery rather than sandboxing at runtime.
|
||||
// The plugin contract (todo §2) — the product's main API surface: the machine-readable types +
|
||||
// pure rules; `docs/plugin-contract.md` is the prose reference, discovery/router wire it to FS+HTTP.
|
||||
// Powerful, predictable, fails loud at boot/discovery rather than sandboxing at runtime.
|
||||
//
|
||||
// A plugin's identity comes from its folder under plugins/: the folder name is the `id`
|
||||
// (validated by isValidPluginId) and the mount path is `/<id>`. Neither is written in the
|
||||
// manifest — the host derives them at discovery, so they can't drift or be claimed twice.
|
||||
// A plugin's identity is its folder under plugins/: folder name = `id` (isValidPluginId), mount =
|
||||
// `/<id>`. Neither is in the manifest — the host derives them, so they can't drift or be claimed twice.
|
||||
|
||||
import type { RequestContext } from "./context.ts";
|
||||
import type { NavNode } from "./nav.ts";
|
||||
@@ -106,11 +103,9 @@ export interface VersionCheck {
|
||||
message: string;
|
||||
}
|
||||
|
||||
// The versioning rule (provider/consumer semver): the host provides a contract version, the
|
||||
// plugin pins the one it targets. Different major → refuse (breaking either way). Same major,
|
||||
// plugin minor > host → refuse (needs a newer host). Same major, plugin minor < host → warn
|
||||
// (additive, still runs — nudge to update). Equal major/minor (patch ignored) → ok. Malformed →
|
||||
// refuse. Discovery maps refuse→throw, warn→log.
|
||||
// Provider/consumer semver check (full table in docs/plugin-contract.md): same major+minor → ok,
|
||||
// plugin minor < host → warn, else (newer minor, major mismatch, malformed) → refuse. Patch is
|
||||
// ignored. Discovery maps refuse→throw, warn→log.
|
||||
export function checkApiVersion(pluginVersion: unknown, hostVersion: string = HOST_API_VERSION): VersionCheck {
|
||||
const plugin = parseSemver(pluginVersion);
|
||||
const host = parseSemver(hostVersion);
|
||||
|
||||
@@ -1,9 +1,7 @@
|
||||
// Router (todo §2): the pure core that maps an incoming method + pathname to a discovered
|
||||
// plugin route. I/O-free — app.ts is the imperative shell that builds the context, runs the
|
||||
// gate, calls the handler, and turns its RouteResult into an HTTP response. A route is mounted
|
||||
// at `/<id>` + its path (fullPath, shared with conflict detection); `:name` segments become
|
||||
// path params. Specificity: a literal segment beats a `:param`, so /users/new wins over
|
||||
// /users/:id regardless of declaration order.
|
||||
// Router (todo §2): pure core mapping method + pathname → a discovered plugin route. I/O-free;
|
||||
// app.ts is the shell (build context, gate, call handler, render RouteResult). A route mounts at
|
||||
// `/<id>` + its path (fullPath, shared with conflict detection); `:name` segments → path params.
|
||||
// Specificity: a literal segment beats a `:param` (/users/new wins /users/:id), order-independent.
|
||||
|
||||
import { fullPath, type Plugin, type Route } from "./plugin.ts";
|
||||
|
||||
|
||||
Reference in New Issue
Block a user