@gracile/engine
Advanced tools
Comparing version 0.2.2-next.0 to 0.2.2-next.1
import { type ViteDevServer } from 'vite'; | ||
import { type GracileAsyncMiddleware } from '../server/request.js'; | ||
import { type GracileHandler } from '../server/request.js'; | ||
import type { GracileConfig } from '../user-config.js'; | ||
@@ -8,4 +8,4 @@ export declare function createDevHandler({ vite, gracileConfig, }: { | ||
}): Promise<{ | ||
handler: GracileAsyncMiddleware; | ||
handler: GracileHandler; | ||
}>; | ||
//# sourceMappingURL=dev.d.ts.map |
@@ -5,3 +5,3 @@ import { logger } from '@gracile/internal-utils/logger'; | ||
import { collectRoutes } from '../routes/collect.js'; | ||
import { createGracileMiddleware, } from '../server/request.js'; | ||
import { createGracileHandler, } from '../server/request.js'; | ||
export async function createDevHandler({ vite, gracileConfig, }) { | ||
@@ -27,4 +27,4 @@ const root = vite.config.root; | ||
const serverMode = false; | ||
const gracile = createGracileMiddleware({ vite, root, serverMode, routes }); | ||
const gracile = createGracileHandler({ vite, root, serverMode, routes }); | ||
return { handler: gracile }; | ||
} |
@@ -50,3 +50,3 @@ import type { ServerRenderedTemplate } from '@lit-labs/ssr'; | ||
* */ | ||
response: ResponseInit; | ||
responseInit: ResponseInit; | ||
}) => MaybePromise<Data> | MaybePromise<void>; | ||
@@ -53,0 +53,0 @@ export type HandlerGeneric = Handler<HandlerData | HandlerDataHtml> | Partial<Record<MethodHtml, Handler<HandlerData | HandlerDataHtml>> & Record<MethodNonHtml, Handler<Response>>>; |
@@ -1,11 +0,11 @@ | ||
import { type GracileAsyncMiddleware } from '../request.js'; | ||
export declare function honoAdapter(middleware: GracileAsyncMiddleware): (context: { | ||
import type { GracileHandler } from '../request.js'; | ||
export type GracileHonoHandler = (context: { | ||
req: { | ||
raw: Request; | ||
}; | ||
res: ResponseInit; | ||
var: unknown; | ||
}) => Promise<Response>; | ||
export declare const honoAdapter: (handler: GracileHandler) => GracileHonoHandler; | ||
export declare function getClientDistPath(root: string): string; | ||
export { printAddressInfos } from '../utils.js'; | ||
//# sourceMappingURL=hono.d.ts.map |
@@ -6,23 +6,10 @@ // import { logger } from '@gracile/internal-utils/logger.build'; | ||
import { CLIENT_DIST_DIR } from '../env.js'; | ||
import {} from '../request.js'; | ||
export function honoAdapter(middleware) { | ||
return async function honoMiddleware(context) { | ||
const result = await middleware(context.req.raw, context.var); | ||
if (result instanceof Readable) { | ||
return new Response(Readable.toWeb(result), { | ||
headers: { 'content-type': 'html' }, | ||
}); | ||
// context.res.headers.set('content-type', 'html'); | ||
// return stream(c, async (stream) => { | ||
// stream.onAbort(() => { | ||
// throw new Error('Stream aborted!'); | ||
// }); | ||
// await stream.pipe(/** @type {ReadableStream} */ Readable.toWeb(result)); | ||
// }); | ||
} | ||
if (result) | ||
return result; | ||
throw new Error('Rendering was impossible in the Hono adapter!'); | ||
}; | ||
} | ||
export const honoAdapter = (handler) => async (context) => { | ||
const result = await handler(context.req.raw, context.var); | ||
if (result?.body) | ||
return new Response(Readable.toWeb(result.body), result.init); | ||
if (result?.response) | ||
return result.response; | ||
throw new Error('Rendering was impossible in the Hono adapter!'); | ||
}; | ||
export function getClientDistPath(root) { | ||
@@ -29,0 +16,0 @@ return relative(process.cwd(), fileURLToPath(new URL(CLIENT_DIST_DIR, root))); |
import type { IncomingMessage, ServerResponse } from 'http'; | ||
import { type GracileAsyncMiddleware } from '../request.js'; | ||
export declare function nodeAdapter(middleware: GracileAsyncMiddleware): (req: IncomingMessage, res: ServerResponse, locals?: unknown) => Promise<void | ServerResponse<IncomingMessage> | null>; | ||
import type { GracileHandler } from '../request.js'; | ||
export declare function nodeAdapter(handler: GracileHandler): (req: IncomingMessage, res: ServerResponse, locals?: unknown) => Promise<void | ServerResponse<IncomingMessage> | null>; | ||
export declare function getClientDistPath(root: string): string; | ||
export { printAddressInfos } from '../utils.js'; | ||
//# sourceMappingURL=node.d.ts.map |
import { fileURLToPath } from 'node:url'; | ||
import { logger } from '@gracile/internal-utils/logger.build'; | ||
import { createServerAdapter } from '@whatwg-node/server'; | ||
import { Readable, Writable } from 'stream'; | ||
import { Writable } from 'stream'; | ||
import { CLIENT_DIST_DIR } from '../env.js'; | ||
import {} from '../request.js'; | ||
// NOTE: Find a more canonical way to ponyfill the Node HTTP request to standard Request | ||
// @ts-expect-error Abusing this feature! | ||
const nodeRequestToStandardRequest = createServerAdapter((request) => request); | ||
export function nodeAdapter(middleware) { | ||
return async function nodeMiddleware(req, res, | ||
// next: (error?: unknown) => void, | ||
locals) { | ||
function standardResponseInitToNodeResponse(responseInit, res) { | ||
const headers = responseInit instanceof Response | ||
? responseInit.headers | ||
: new Headers(responseInit.headers); | ||
headers.forEach((content, header) => res.setHeader(header, content)); | ||
if (responseInit.status) | ||
res.statusCode = responseInit.status; | ||
if (responseInit.statusText) | ||
res.statusMessage = responseInit.statusText; | ||
} | ||
export function nodeAdapter(handler) { | ||
return async function nodeHandler(req, res, locals) { | ||
const request = (await Promise.resolve(nodeRequestToStandardRequest.handleNodeRequest( | ||
@@ -21,18 +28,11 @@ // HACK: Incorrect typings | ||
}; | ||
const result = await middleware(request, mergedLocals).catch((error) => | ||
// next(error), | ||
res.end(String(error))); | ||
// console.log({ result }); | ||
if (result instanceof Readable) { | ||
res.setHeader('Content-Type', 'text/html'); | ||
return result.pipe(res); | ||
const result = await handler(request, mergedLocals); | ||
if (result?.body) { | ||
standardResponseInitToNodeResponse(result.init, res); | ||
return result.body.pipe(res); | ||
} | ||
if (result instanceof Response) { | ||
if (result.status) | ||
res.statusCode = result.status; | ||
if (result.statusText) | ||
res.statusMessage = result.statusText; | ||
result.headers?.forEach((content, header) => res.setHeader(header, content)); | ||
if (result.body) { | ||
const piped = await result.body | ||
if (result?.response) { | ||
standardResponseInitToNodeResponse(result.response, res); | ||
if (result.response.body) { | ||
const piped = await result.response.body | ||
.pipeTo(Writable.toWeb(res)) | ||
@@ -39,0 +39,0 @@ .catch((e) => logger.error(String(e))); |
import { Readable } from 'node:stream'; | ||
import type { ViteDevServer } from 'vite'; | ||
import type * as R from '../routes/route.js'; | ||
/** | ||
* This is fully compatible with Express or bare Node HTTP | ||
* What it adds on top of Connect-style middleware: | ||
* 1. Async. | ||
* 2. Can return a `ServerResponse` | ||
*/ | ||
export type GracileAsyncMiddleware = (request: Request, locals?: unknown) => Promise<Response | Readable | null>; | ||
export declare function createGracileMiddleware({ vite, routes, routeImports, routeAssets, root, serverMode, }: { | ||
export type GracileHandler = (request: Request, locals?: unknown) => Promise<{ | ||
response: Response; | ||
body?: never; | ||
init?: never; | ||
} | { | ||
response?: never; | ||
body: Readable; | ||
init: ResponseInit; | ||
} | null>; | ||
export declare function createGracileHandler({ vite, routes, routeImports, routeAssets, root, serverMode, }: { | ||
vite?: ViteDevServer | undefined; | ||
@@ -18,3 +20,3 @@ routes: R.RoutesManifest; | ||
serverMode?: boolean | undefined; | ||
}): GracileAsyncMiddleware; | ||
}): GracileHandler; | ||
//# sourceMappingURL=request.d.ts.map |
@@ -9,3 +9,4 @@ import { Readable } from 'node:stream'; | ||
import { getRoute } from '../routes/match.js'; | ||
export function createGracileMiddleware({ vite, routes, routeImports, routeAssets, root, serverMode, }) { | ||
const CONTENT_TYPE_HTML = { 'Content-Type': 'text/html' }; | ||
export function createGracileHandler({ vite, routes, routeImports, routeAssets, root, serverMode, }) { | ||
async function createErrorPage(urlPath, e) { | ||
@@ -16,3 +17,4 @@ logger.error(e.message); | ||
errorPageHtml = await vite.transformIndexHtml(urlPath, errorPageHtml); | ||
return { errorPageHtml, headers: { 'Content-Type': 'text-html' } }; | ||
console.log({ errorPageHtml }); | ||
return { errorPageHtml, headers: { ...CONTENT_TYPE_HTML } }; | ||
} | ||
@@ -49,7 +51,9 @@ const middleware = async (request, locals) => { | ||
const { errorPageHtml, headers } = await createErrorPage(urlPath, new Error(message)); | ||
return new Response(errorPageHtml, { | ||
headers, | ||
status: 404, | ||
statusText: '404 not found!', | ||
}); | ||
return { | ||
response: new Response(errorPageHtml, { | ||
headers, | ||
status: 404, | ||
statusText: '404 not found!', | ||
}), | ||
}; | ||
} | ||
@@ -83,3 +87,3 @@ const routeTemplateOptions = { | ||
url: new URL(fullUrl), | ||
response: responseInit, | ||
responseInit, | ||
params: routeInfos.params, | ||
@@ -136,3 +140,5 @@ locals: providedLocals, | ||
const statusText = `This route doesn't handle the \`${method}\` method!`; | ||
return new Response(statusText, { status: 405, statusText }); | ||
return { | ||
response: new Response(statusText, { status: 405, statusText }), | ||
}; | ||
} | ||
@@ -153,23 +159,31 @@ } | ||
if (location) { | ||
return Response.redirect(location, output.status); | ||
return { response: Response.redirect(location, output.status) }; | ||
} | ||
} | ||
return output; | ||
return { response: output }; | ||
// MARK: Stream page render | ||
} | ||
// MARK: Page stream error | ||
return !output | ||
? null | ||
: output.on('error', (error) => { | ||
const errorMessage = `There was an error while rendering a template chunk on server-side.\n` + | ||
`It was omitted from the resulting HTML.`; | ||
logger.error(errorMessage); | ||
logger.error(error.message); | ||
if (vite) | ||
setTimeout(() => { | ||
vite.hot.send('gracile:ssr-error', { | ||
message: errorMessage, | ||
}); | ||
}, 500); | ||
}); | ||
if (output instanceof Readable) { | ||
responseInit.headers = { | ||
...responseInit.headers, | ||
...CONTENT_TYPE_HTML, | ||
}; | ||
return { | ||
body: output.on('error', (error) => { | ||
const errorMessage = `There was an error while rendering a template chunk on server-side.\n` + | ||
`It was omitted from the resulting HTML.`; | ||
logger.error(errorMessage); | ||
logger.error(error.message); | ||
if (vite) | ||
setTimeout(() => { | ||
vite.hot.send('gracile:ssr-error', { | ||
message: errorMessage, | ||
}); | ||
}, 500); | ||
}), | ||
init: responseInit, | ||
}; | ||
} | ||
return null; | ||
// MARK: Errors | ||
@@ -182,7 +196,9 @@ } | ||
const { errorPageHtml: ultimateErrorPage, headers } = await createErrorPage('__gracile_error', error); | ||
return new Response(String(ultimateErrorPage), { | ||
headers, | ||
status: 500, | ||
statusText: 'Gracile middleware error', | ||
}); | ||
return { | ||
response: new Response(String(ultimateErrorPage), { | ||
headers, | ||
status: 500, | ||
statusText: 'Gracile middleware error', | ||
}), | ||
}; | ||
} | ||
@@ -189,0 +205,0 @@ }; |
{ | ||
"name": "@gracile/engine", | ||
"version": "0.2.2-next.0", | ||
"version": "0.2.2-next.1", | ||
"description": "A thin, full-stack, web framework", | ||
@@ -78,3 +78,3 @@ "keywords": [ | ||
}, | ||
"gitHead": "2535f8c1a880d7265380ec00bc74d8ec2f9e2967" | ||
"gitHead": "8bcbeaa8c82b22003a1f227133a5a2f04589fe8a" | ||
} |
Sorry, the diff of this file is not supported yet
Sorry, the diff of this file is not supported yet
Sorry, the diff of this file is not supported yet
Sorry, the diff of this file is not supported yet
Sorry, the diff of this file is not supported yet
Sorry, the diff of this file is not supported yet
License Policy Violation
LicenseThis package is not allowed per your license policy. Review the package's license to ensure compliance.
Found 1 instance in 1 package
License Policy Violation
LicenseThis package is not allowed per your license policy. Review the package's license to ensure compliance.
Found 1 instance in 1 package
138957
1826