Render Results

Render Results

Render Results

Plugin DeveloperPlugin Developer Agent Kit — documentation written for AI agents, readable by humans.

Each rendering phase (slow, fast) returns a render result indicating success, error, or redirect.

phaseOutput — Success

Returns ViewState data and optional carry-forward data for the next phase:

import { phaseOutput } from '@jay-framework/fullstack-component';

return phaseOutput(
  { title: 'My Product', price: 29.99 }, // ViewState — sent to template
  { productId: 'abc123' }, // CarryForward — passed to next phase only
);

CarryForward is available in the next phase via props.carryForward but is not part of the ViewState.

Response Headers (fast phase only)

The third parameter accepts responseHeaders to set HTTP headers on the page response:

return phaseOutput(
  { memberName: member.name },
  {},
  { responseHeaders: { 'Cache-Control': 'no-store' } },
);

Use this when the component renders per-user data that must not be cached by CDN or browser. Can be combined with headTags in the same options object.

Cookies (fast phase only)

The fast phase receives props.cookies — a Record<string, string> parsed from the HTTP Cookie header:

.withFastRender(async (props, memberService) => {
    const token = props.cookies['session-token'];
    if (!token) return redirect3xx(302, '/login');

    const member = await memberService.validate(token);
    if (!member) return redirect3xx(302, '/login');

    return phaseOutput(
        { isLoggedIn: true, memberName: member.name },
        {},
        { responseHeaders: { 'Cache-Control': 'no-store' } },
    );
})
  • props.cookies is Record<string, string> — empty {} when no cookies
  • Not available in the slow phase (compile error) — same as props.query

Error Results

Return errors to stop rendering and show an error page:

import {
  notFound,
  badRequest,
  unauthorized,
  forbidden,
  serverError5xx,
  clientError4xx,
} from '@jay-framework/fullstack-component';

// 404
if (!product) return notFound('Product not found');

// 400
if (!input.query) return badRequest('Query is required');

// 401
if (!session) return unauthorized('Please log in');

// 403
if (!canAccess) return forbidden('Access denied');

// Custom 4xx
return clientError4xx(429, 'Rate limit exceeded');

// 5xx
return serverError5xx(500, 'Database connection failed');

Redirects

import { redirect3xx } from '@jay-framework/fullstack-component';

return redirect3xx(301, '/new-location');
return redirect3xx(302, `/products/${product.slug}`);

RenderPipeline — Composable Rendering

For complex render logic, RenderPipeline chains operations with automatic error propagation:

import { RenderPipeline } from '@jay-framework/fullstack-component';

const Pipeline = RenderPipeline.for<SlowViewState, CarryForward>();

return Pipeline.try(() => db.getProduct(props.slug))
  .map((product) => product ?? Pipeline.notFound('Product not found'))
  .map(async (product) => ({
    ...product,
    reviews: await db.getReviews(product.id),
  }))
  .toPhaseOutput((product) => ({
    viewState: { title: product.name, price: product.price },
    carryForward: { productId: product.id },
  }));

Pipeline Factory Methods

const P = RenderPipeline.for<VS, CF>();

P.ok(value); // Wrap a value
P.try(() => fetchData()); // Wrap a function (catches errors)
P.from(previousPhaseResult); // Continue from a prior phase result
P.notFound('message'); // Error pipeline
P.badRequest('message'); // Error pipeline
P.unauthorized('message'); // Error pipeline
P.forbidden('message'); // Error pipeline
P.serverError(500, 'message'); // Error pipeline
P.redirect(301, '/path'); // Redirect pipeline

Pipeline Chain Methods

pipeline
    .map(value => transform(value))           // Transform the value
    .map(async value => await asyncOp(value)) // Async transform
    .recover(error => P.ok(fallbackValue))    // Recover from errors
    .toPhaseOutput(value => ({                // Convert to PhaseOutput
        viewState: { ... },
        carryForward: { ... },
    }));

Errors short-circuit — if any step returns an error pipeline, subsequent .map() calls are skipped.


About this document

This page is part of the Jay Stack Agent Kit — documentation generated from the framework source and written primarily for AI agents. The language and structure are optimized for machine consumption — expect precise, specification-style prose rather than narrative documentation. Learn more about the Agent Kit →