Jay Stack
Jay Stack
Written for AI agents. See Log Methodology Note below for details.
Jay Stack is the name of the full stack framework for Jay. Like anything else in Jay, it is first designed to enable a design tool to create designs with collaboration with a developer building features.
The requirements for the Jay Stack
- Integrated with a design tool, such that
- A design tool can create new pages
- A design tool can add functionality with pre-made contracts to a page
- A design tool can use a project defined functionality with project defined contract on a page
- A design tool can use pre-made components or project defined components on a page
- Support page routing, including
- page url
- page url with parameters
- page url with optional and catch all parameters
- support different error pages
- support rendering model for website, including
- url / param loading for pages with params
- slowly changing data support and pre-rendering
- routing hook to redirect and choose pre-rendered page
- fast changing data support and rendering
- async data rendering
- client hydration and rendering
- support an application model, pre-made functionalities that can be installed at the design tool, including
- pre-made page functionality
- application global context for setting
- application pre-made components to be added to pages
- application navigation, how to navigate from one application page to another
The Key concepts of Jay Stack are
- Pages - similar to any other meta framework, a page is a definition file that generates one or more website pages
- Page Component - the Jay Component of the page. A Page can have more then one Page Component (due to applications).
- Application - an entity to be installed at the design tool. An application consists of Designed Pages, Page Components, General application context and settings and Application Components.
- Jay Components - including the Jay component and Jay element.
- Backend code
- Frontend code
File-system layout
/src
/pages
/page.jay-html -- index page on route /
/products
/[slug]/page.jay-html -- product page on route /products/[slug], where slug is a parameter
/[[lang]]/shop -- optional parameter
/[...slugs]/page.jay-html -- catch all route
/[[...slugs]]/page.jay-html -- optional catch all route
/components
/node_modules
/app-1 -- application functionality, including pages and components
/manifest.json -- file describing the content of the application
/page-1
/page.ts -- the page component
rendering process
The Jay rendering process has 3 steps - of which all are optional.
- slowly changing data rendering (similar to SSG in other frameworks)
- fast changing data rendering (similar to SSR in other frameworks)
- client rendering
This section presents the flow and ideas for the rendering process. Next we will explore different APIs to package those ideas.
Slowly changing Data Rendering
The slowly changing data rendering is used to load param values for pages with url parameters, as well as loading system parameter values (languages). The rendering continues by loading data for each set of params and pre-rendering the page.
- Given a route to a
jay-htmlfile, the file is loaded. - Call the url loading API to load all dynamic
paramvalues - set ofparamsandsystem params.params- defined by the application, likeslug.system params- defined by Jay, but loaded by the application, likelang.
- For each set of
(params, system params)load theserver view stateandserver props.- The
server view stateis used for pre-rendering the jay-html. - The
server propsare used for fast rendering.
- The
- The
server view stateis mapped to child componentsprops, which are used to call the child components slowly data loading. The child components return alsoserver view stateandserver props. - The
server view stateis used to pre-render thejay-htmlintopre-rendered-jay-html.- The
pre-rendered-jay-htmlis thejay-htmlwith theserver view statevalues replaced, as well as compiled to server JS to renderHTMLgiven the rest of theview stateat the fast changing data rendering. - There can be more then one
jay-htmls pre-rendered - one for the page, and additional ones for the child components.
- The
The App APIs
declare async function urlLoading(settings: AppSettings): Promise<Params & SystemParams>;
declare async function slowlyChangingDataLoader(
params: Params & SystemParams,
settings: AppSettings,
): Promise<ServerViewState, ServerProps>;
declare async function rerenderRoute(params: Params);
fast Changing Data Rendering
The fast changing data rendering starts with a pre-rendered jay-html, or the original jay-html is no pre-rendering was done.
Given the application server props, it loads the view state to render the final html to be sent to the browser,
as well as client props to be sent to the client component as part of the html content.
- Given a route to
jay-htmlfile and extractingparametersfrom theHTTP Request, load thepre-rendered jay-htmlor, if not present, the originaljay-html.- If
pre-rendered jay-htmlis found, thepropsare theServerPropsas defined in the slowly changing phase. - If not found, the original
jay-htmlis used, thepropsare the extractedparamsfrom the url &SystemParams.
- If
- load the fast changing data and return
- The data for rendering -
view stateandclient props - redirect
- error
- other HTTP statuses
- The data for rendering -
- load child components fast changing data, again returning
view stateandclient props. - render the final
htmlwith theclient propsas part of the content- The server can render the
jay-htmlasHTML - The server embeds in the
HTMLthe client scripts for the applications included - The server embeds in the
HTMLtheclient props
- The server can render the
The App APIs
declare async function fastChangingDataLoader(
props: ServerProps,
settings: AppSettings,
): RouteResult;
declare type RouteResult =
| Render<ViewState, ClientProps>
| NotFound
| TemporaryRedirect
| PermanentRedirect
| Error
| HTTPStatus;
Client Rendering
The client rendering starts with a loaded HTML file importing the client library of the application.
- Links in the
HTMLpage header load the applications components of the page.- Alternatively, we can delay the application components loading to an actual interaction.
- A script in the
HTMLpage reads theclient propsof each application - The script initializes each application component with the
client props - The page is now interactive using Jay logic
App Settings
The AppSettings member of all the app APIs above is a structure enabling the configuration of an application from
the design tool. It is required as a design tool does not have access to configure environment variables or secrets,
while configuration of NPM imported packages is always a challenge. The AppSettings are to put order in this space.
It is a server environment only entity, which includes an abstraction of configurations and secrets.
declare interface AppSettings {
getConfig(key: string): string;
getSecret(key: string): string;
}
Data Flow
This section describes how different sources of data flow to the different stages of page rendering.
The inputs are:
params- from the url params of all applications installed on the page, as defined by each applicationurlLoader.systemParams- params that applications can load with theurlLoaderstage, that are known and shared, likelangpageSettings- an application config for this pageappSettings- an application config for the whole application, including both config and secrets- the slowly changing data stage is running on build time / startup time / data change time,
accepting all the above sources (1..4), and produces
server carry forwardand a partialview statefor early rendering of slowly changing data. Any value rendered at this stage is considered constant by later stages. - the fast changing data stage is running on page serving as part of server side rendering,
accepts the
params,systemParams,pageSettings,appSettingsand theserver carry forwardand produces theclient carry forwardand a partialview stateto complete the html rendering of the page. - the client rendering accepts only the
params,systemParamsandclient carry forwardand produces the same partialview stateas the fast changing stage for interactive rendering
Component API
We extend the component API to support slowly and fact changing data, to support the flows above.
We explore 3 different API alternatives, on the store product page case, in
- 34 - 1 - jay stack - separate loaders API option.md
- 34 - 2 - jay stack - hooks style API option.md
- 34 - 3 - jay stack - name convention based API option.md
It looks like the first option is the best because as it is the simplest, and if we need server context to pass to client context (not final), this option works best.
Context discussion
Do we really need server context as a separate API? maybe we only need an application to be able to provide client context?
In server environment, a server urlLoader, renderSlowlyChanging and renderFastChanging can just import
a module who loads the app settings and acts as the context for all server functions.
The renderFastChanging function can pass information to the page makeJayComponent who can
provide a jay context to any child components.
Still, for server operations, it makes sense to have a singleton object that holds connections to network, configured API clients, etc. How does an application declares such a server component?
Maybe, instead of server context as in provideServerContext, we need instead a mechanism
for an application imported from NPM library or from the project code to initialize, such that
the initialization result is actually the server context provided to all server hooks?
one such mechanism is the default initialization of code running as part of a module import. Such global code can use an API to load settings and secrets, initialize a global server state of the application. However, such an option does not, by default, support settings reload during development (which can be mitigated using a dedicated API).
However, context is still needed for passing data from parent component to child components, or from the page component to child components. JayStack may introduce a way for an application to provide context to child components of the application.
Consider a store application, with a related products component that can be placed on any page. The store application can have a page main component which only provides a store context, including the current product on a product page. The related products component can then use that context to show contextual related products.
This leads to the result that we need both client and server contexts, which are responsible to pass information
from parent to child components. The urlLoader, renderSlowlyChanging and renderFastChanging are responsible for
passing information from server to client.
proposed full stack component API
type UrlParams = Array<Record<string, string>>;
type LoadParams<ServerContexts> = (contexts: ServerContexts) => Promise<UrlParams>;
interface PartialRender<ViewState extends object, CarryForward> {
render: Partial<ViewState>;
carryForward: CarryForward;
}
type RenderSlowly<
ServerContexts,
PropsT extends object,
SlowlyViewState extends object,
SlowlyCarryForward,
> = (contexts: ServerContexts, props: PropsT) => PartialRender<SlowlyViewState, SlowlyCarryForward>;
type RenderFast<
ServerContexts,
PropsT extends object,
SlowlyCarryForward,
FastViewState extends object,
FastCarryForward,
> = (contexts: ServerContexts, props: PropsT) => PartialRender<FastViewState, FastCarryForward>;
type PartialSubtract<T, P extends Partial<T>> = Omit<T, keyof P>;
interface ComponentDeclaration<
PropsT extends object,
ViewState extends object,
SlowlyViewState extends Partial<ViewState>,
FastViewState extends PartialSubtract<ViewState, SlowlyViewState>,
Refs extends object,
SlowlyCarryForward extends object,
FastCarryForward extends object,
JayElementT extends JayElement<ViewState, Refs>,
ServerContexts extends Array<any>,
ClientContexts extends Array<any>,
CompCore extends JayComponentCore<PropsT, ViewState>,
> {
elementPreRender: PreRenderElement<ViewState, Refs, JayElementT>;
loadParams?: LoadParams<ServerContexts>;
renderSlowlyChanging?: RenderSlowly<ServerContexts, PropsT, SlowlyViewState, SlowlyCarryForward>;
renderFastChanging?: RenderFast<
ServerContexts,
PropsT & SlowlyCarryForward,
SlowlyCarryForward,
FastViewState,
FastCarryForward
>;
comp: ComponentConstructor<
PropsT & FastCarryForward,
Refs,
FastViewState,
ClientContexts,
CompCore
>;
}
declare function makeJayStackComponent<
PropsT extends object,
ViewState extends object,
SlowlyViewState extends Partial<ViewState>,
FastViewState extends PartialSubtract<ViewState, SlowlyViewState>,
Refs extends object,
SlowlyCarryForward extends object,
FastCarryForward extends object,
JayElementT extends JayElement<ViewState, Refs>,
ServerContexts extends Array<any>,
ClientContexts extends Array<any>,
CompCore extends JayComponentCore<PropsT, ViewState>,
>(
compDeclaration: ComponentDeclaration<
PropsT,
ViewState,
SlowlyViewState,
FastViewState,
Refs,
SlowlyCarryForward,
FastCarryForward,
JayElementT,
ServerContexts,
ClientContexts,
CompCore
>,
serverContextMarkers: ContextMarkers<ServerContexts>,
clientContextMarkers: ContextMarkers<ClientContexts>,
): (props: PropsT) => ConcreteJayComponent<PropsT, ViewState, Refs, CompCore, JayElementT>;
The above makeJayStackComponent is compiled into makeJayComponent for the client application,
and in server environment is used to run loadParams, renderSlowlyChanging and renderFastChanging if present.
and for server context
declare function provideServerContext<ContextType>(
marker: ContextMarker<ContextType>,
context: ContextType,
);
Update
Trying to implement the above failed, as the type inference was too complex and failed to infer the DynamicViewState
for the component constructor. As a result, we result to another option, using a builder pattern
34 - 4 - jay stack - using builder.md
This option seems to be working.
Log Methodology Note
Note: These design logs are written primarily for AI agents as part of the Design Log methodology and made accessible here for human readers. The language and structure are optimized for machine consumption — expect precise, specification-style prose rather than narrative documentation.