Fetch Handler Package
Fetch Handler Package
DevOps Agent Kit — documentation written for AI agents, readable by humans.
Overview
@jay-framework/jay-fetch-handler exports a standard (Request) → Response function for BaaS platforms (Wix, Cloudflare Workers) where an HTTP server is not needed — the platform provides the HTTP layer and calls the fetch function directly.
Installation
npm install @jay-framework/jay-fetch-handler
API
import { createJayFetchHandler } from '@jay-framework/jay-fetch-handler';
const handler = createJayFetchHandler(options);
// handler: (request: Request) => Promise<Response>
Options
interface JayFetchHandlerOptions {
// Artifact source (one required)
backendDir?: string; // Path to build/v{n}/backend/ (creates FilesystemArtifactStore)
artifactStore?: ArtifactStore; // Custom store for non-filesystem backends (DL#143)
staticBaseUrl?: string; // Base URL for browser assets (default: '/')
frontendDir?: string; // When set, serves static files from this directory
// Pre-imported modules — for bundled entry.mjs (DL#143)
plugins?: PreImportedPlugin[];
actionModules?: Array<{ module: Record<string, unknown>; name: string }>;
}
| Option | Required | Description |
|---|---|---|
backendDir |
* | Path to the backend build directory. Creates a FilesystemArtifactStore internally |
artifactStore |
* | Custom ArtifactStore implementation (e.g., cloud storage). Use instead of backendDir |
staticBaseUrl |
No | URL prefix for import maps, CSS links, and client bundles. Set to your CDN URL for external hosting. Default: / |
frontendDir |
No | When provided, the handler serves static files from this directory. Omit for CDN deployments where static files are hosted elsewhere |
plugins |
No | Pre-imported plugin init modules. Bypasses filesystem discovery — use for bundled deployments |
actionModules |
No | Pre-imported action modules. Bypasses filesystem discovery — use for bundled deployments |
* One of backendDir or artifactStore is required.
Usage — Self-Hosted
import { createJayFetchHandler } from '@jay-framework/jay-fetch-handler';
const handler = createJayFetchHandler({
backendDir: './build/v1/backend',
staticBaseUrl: '/',
frontendDir: './build/v1/frontend',
});
Usage — CDN Mode
const handler = createJayFetchHandler({
backendDir: './build/v1/backend',
staticBaseUrl: 'https://static.parastorage.com/services/my-app/1.0.0/',
});
export default { fetch: handler };
The BaaS runtime calls handler(request) for each incoming HTTP request.
Usage — BaaS with Custom Artifact Store
For deployments where backend files are not on the local filesystem (e.g., stored in a cloud database), provide a custom ArtifactStore and pre-imported modules:
import { createJayFetchHandler } from '@jay-framework/jay-fetch-handler';
import { WixDataArtifactStore } from '@jay-framework/wix-baas-adapter';
import { init as wixStoresInit } from '@jay-framework/wix-stores';
import * as wixStoresModule from '@jay-framework/wix-stores';
const handler = createJayFetchHandler({
artifactStore: new WixDataArtifactStore({
collectionId: 'jay-backend-files',
cacheDir: '/tmp/jay-backend',
}),
staticBaseUrl: 'https://static.parastorage.com/services/my-app/1.0.0/',
plugins: [{ name: 'wix-stores', init: wixStoresInit }],
actionModules: [{ module: wixStoresModule, name: 'wix-stores' }],
});
export default { fetch: handler };
The ArtifactStore interface:
interface ArtifactStore {
readManifest(): Promise<RouteManifest>;
readCacheData(relativePath: string): Promise<CacheEntry>;
readPagePartsConfig(relativePath: string): Promise<any>;
loadServerElement(relativePath: string): Promise<ServerElementModule>;
loadModule(modulePath: string, local?: boolean): Promise<any>;
getAssetPath(relativePath: string): string;
getBuildDir(): string;
}
loadModule handles all module loading — server elements, page components, headless components. The local flag indicates whether the path is relative to the build directory (true) or an npm package (false). For filesystem deployments, local modules resolve from basePath and npm modules use bare import(). BaaS implementations resolve all modules from their pre-bundled registry, ignoring the local flag.
For serve-only imports (no build-time dependencies), use @jay-framework/production-server/serve.
Usage — Cloudflare Workers
import { createJayFetchHandler } from '@jay-framework/jay-fetch-handler';
const handler = createJayFetchHandler({
backendDir: './backend',
staticBaseUrl: 'https://cdn.example.com/assets/',
});
export default { fetch: handler };
Usage — Standalone with HTTP Server
import { createJayFetchHandler } from '@jay-framework/jay-fetch-handler';
import http from 'node:http';
import { Readable } from 'node:stream';
const handler = createJayFetchHandler({
backendDir: './build/v1/backend',
staticBaseUrl: '/',
frontendDir: './build/v1/frontend',
});
http
.createServer(async (req, res) => {
const url = new URL(req.url, `http://${req.headers.host}`);
const headers = new Headers();
for (const [k, v] of Object.entries(req.headers)) {
if (v) headers.set(k, Array.isArray(v) ? v.join(', ') : v);
}
const init: RequestInit = { method: req.method, headers };
if (req.method !== 'GET' && req.method !== 'HEAD') {
init.body = Readable.toWeb(req) as ReadableStream;
(init as any).duplex = 'half';
}
const request = new Request(url, init);
const response = await handler(request);
const resHeaders: Record<string, string> = {};
response.headers.forEach((v, k) => {
resHeaders[k] = v;
});
res.writeHead(response.status, resHeaders);
if (response.body) {
const reader = response.body.getReader();
while (true) {
const { done, value } = await reader.read();
if (done) break;
res.write(value);
}
}
res.end();
})
.listen(4000);
This is what jay-stack serve does internally. Use the CLI for standard deployments; use the handler directly when you need custom server logic.
Behavior
The handler processes requests in this order:
- Actions —
/_jay/actions/*routes to the action registry - Static files — if
frontendDiris set, checksfrontend/, thenfrontend/public/ - Page requests — matches against the route manifest, runs fast-phase SSR, streams HTML
Initialization (loading manifest, running init.ts, registering actions) happens lazily on the first request.
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 →