Install the G1 public beta
pliego-router and pliego-runtime 0.4.0-beta.1 are public on crates.io and G1 is complete. Pin both exact versions with the same version as the CLI and every other PliegoRS crate.
[dependencies]
pliego-router = "=0.4.0-beta.1"
pliego-runtime = "=0.4.0-beta.1"Keep transport and framework ownership explicit
The portable router seals route grammar, parameters, group and layout scopes, middleware capabilities, error-boundary identity, collisions, and a deterministic graph digest. The runtime owns connection and request admission, deadlines, cancellation, cleanup, response commitment, byte accounting, diagnostics, receipts, and bounded completion signals.
- Hyper
- The single HTTP/1.1 and HTTP/2 parser and protocol framing owner
- Axum / Tower
- HTTP service composition and explicit interoperability
- Tokio
- Socket execution, timers, cancellation wakeups, and task scheduling
- PliegoRS
- Bounded connection policy, sealed application semantics, failure rules, cleanup, and evidence
Bound the network before application code
TransportLimits caps active TCP connections, the absolute HTTP/1 head deadline, read and write inactivity, HTTP/2 peer streams, flow-control windows, and per-stream send buffers. RequestLimits applies header and body budgets to both protocol versions. Every policy has a deterministic digest.
use pliego_runtime::{NativeRuntimeBuilder, TransportLimits};
let transport = TransportLimits {
max_connections: 512,
http2_max_concurrent_streams: 64,
..TransportLimits::default()
};
let runtime = NativeRuntimeBuilder::new(graph, "edge-a")?
.transport_limits(transport)?
.build()?;- Overload
- Excess connections close before parsing; excess requests receive a bounded 503
- Slow peers
- Absolute head and read/write inactivity deadlines release sockets deterministically
- Body formats
- PLG-RUN-110 rejects conflicting framing with 400. The published G1 generic path rejects encoded or multipart bodies; current main adds G2 action-only decoded and part budgets.
- Shutdown
- New work stops, request scopes cancel, connections drain, and remaining tasks abort only after the deadline
Choose one explicit SSR mode
Complete renders one bounded response before commitment. Ordered streams sibling factories under backpressure. Boundary starts a bounded set of futures concurrently, emits a stable inert data-pliego-boundary template anchor, and delivers useful resolved HTML in declaration order without a JavaScript patch runtime.
use pliego_dom::{IntoView, el};
use pliego_runtime::{
AsyncBoundary, BoundaryDocument, BoundaryRenderOptions,
render_boundary_document,
};
let document = BoundaryDocument::new("Account");
let boundaries = [
AsyncBoundary::map("heading", async { "Account" }, |title| {
el("h1").child(title).into_view()
})?,
];
let response = render_boundary_document(
&document,
boundaries,
BoundaryRenderOptions::default(),
)?;Bind the document to its route-owned layout
A sealed match exposes the complete group/layout scope chain separately from the layout-only chain. LayoutDocument requires one LayoutLayer for every matched layout and composes them root to leaf. Typed before, after, and wrap operations transform one private child frame, so application code cannot omit or duplicate it. No HTML string is parsed or replaced.
use pliego_dom::{IntoView, el};
use pliego_runtime::{
DocumentHead, LayoutDocument, LayoutLayer,
render_layout_document,
};
let shell = LayoutLayer::new("guide-layout")?
.before(el("nav").child("Guide"))
.wrap(el("div").class("guide-shell"))
.head(DocumentHead::new().stylesheet("/assets/guide.css"));
let document = LayoutDocument::new(
context.route(),
el("main").child("Reference").into_view(),
)
.layout(shell)?
.title("Reference");
let response = render_layout_document(
&document,
CompleteRenderOptions::default(),
)?;- Ownership
- Missing, duplicate, or foreign layouts fail before response commitment
- Child frame
- Typed operations preserve exactly one private child by construction
- Head
- Inner and page scalar fields win; assets retain stable order and exact duplicates emit once
- Streams
- LayoutStreamDocument validates one internal slot and shares one shell-plus-content byte budget
- Receipt
- renderMode layout records both routeScopes and routeLayouts
Attach operator-owned OpenTelemetry
The runtime emits no request telemetry until the operator configures global OpenTelemetry providers and calls open_telemetry. PliegoRS installs no exporter, endpoint, credential, or collector. Enabled SERVER spans remain open through the last response-body frame, and three standard HTTP metrics cover duration, active requests, and response size.
use pliego_runtime::{
HttpScheme, OpenTelemetryConfig, RemoteTracePolicy,
};
let telemetry = OpenTelemetryConfig::new(HttpScheme::Https)
.known_method("PROPFIND")?
.remote_trace_policy(RemoteTracePolicy::AcceptW3c);
let runtime = NativeRuntimeBuilder::new(graph, "production-a")?
.open_telemetry(telemetry)
.build()?;- Default
- No instrumentation and no accepted remote parent
- Scheme
- Explicit trusted Http or Https operator value
- Metrics
- Request duration, active requests, and response body size
- Cardinality
- Known method set, sealed route template, finite framework error codes
- Receipt
- Exporter-independent coarse duration bucket
Independently of OpenTelemetry, every terminal request emits one pliegors::request tracing event with a sealed route ID, outcome, status, response bytes, coarse duration bucket, render mode, and bounded diagnostic code. It excludes request values and leaves subscriber, storage, retention, and alert policy to the operator.
Bound the work and preserve committed semantics
Boundary identities are validated and unique before commitment. Defaults allow 32 declarations, four in flight, and five seconds per future; hard ceilings are 256, 32, and 60 seconds. Shell, anchors, and resolved views share one output budget, while every view retains depth and node limits.
A timeout, application failure, panic, or output exhaustion after commitment terminates the body and records failure; it cannot rewrite the status or emit a second page. PLG-REN-210 discards application error text at the boundary instead of admitting it into public diagnostics.