htmx-router
Advanced tools
+3
-4
@@ -56,6 +56,5 @@ import { QuickHash } from "./internal/util.js"; | ||
| return null; | ||
| const headers = new Headers(); | ||
| headers.set("Content-Type", "text/css"); | ||
| headers.set("Cache-Control", "public, max-age=604800"); | ||
| return new Response(build.sheet, { headers }); | ||
| ctx.headers.set("Content-Type", "text/css"); | ||
| ctx.headers.set("Cache-Control", "public, max-age=604800"); | ||
| return new Response(build.sheet, { headers: ctx.headers }); | ||
| } |
+10
-9
| import { ServerOnlyWarning } from "./internal/util.js"; | ||
| ServerOnlyWarning("event-source"); | ||
| // global for easy reuse | ||
| const encoder = new TextEncoder(); | ||
| const headers = new Headers(); | ||
| // Chunked encoding with immediate forwarding by proxies (i.e. nginx) | ||
| headers.set("X-Accel-Buffering", "no"); | ||
| headers.set("Transfer-Encoding", "chunked"); | ||
| headers.set("Content-Type", "text/event-stream"); | ||
| // the maximum keep alive chrome shouldn't ignore | ||
| headers.set("Keep-Alive", "timeout=120"); | ||
| headers.set("Connection", "keep-alive"); | ||
| /** | ||
@@ -98,11 +108,2 @@ * Helper for Server-Sent-Events, with auto close on SIGTERM and SIGHUP messages | ||
| } | ||
| // global for easy reuse | ||
| const encoder = new TextEncoder(); | ||
| const headers = new Headers(); | ||
| // Chunked encoding with immediate forwarding by proxies (i.e. nginx) | ||
| headers.set("X-Accel-Buffering", "no"); | ||
| headers.set("Transfer-Encoding", "chunked"); | ||
| headers.set("Content-Type", "text/event-stream"); | ||
| headers.set("Keep-Alive", "timeout=120"); // the maximum keep alive chrome shouldn't ignore | ||
| headers.set("Connection", "keep-alive"); | ||
| // Auto close all SSE streams when shutdown requested | ||
@@ -109,0 +110,0 @@ // Without this graceful shutdowns will hang indefinitely |
@@ -123,6 +123,5 @@ import { ServerOnlyWarning } from "./util.js"; | ||
| return null; | ||
| const headers = new Headers(); | ||
| headers.set("Content-Type", "text/javascript"); | ||
| headers.set("Cache-Control", "public, max-age=604800"); | ||
| return new Response(script, { headers }); | ||
| ctx.headers.set("Content-Type", "text/javascript"); | ||
| ctx.headers.set("Cache-Control", "public, max-age=604800"); | ||
| return new Response(script, { headers: ctx.headers }); | ||
| } |
| import type { IncomingMessage, ServerResponse } from "http"; | ||
| import type { ViteDevServer } from "vite"; | ||
| import type { GenericContext } from "../router.js"; | ||
| import { GenericContext } from "../router.js"; | ||
| type Config = { | ||
@@ -5,0 +5,0 @@ build: Promise<any> | (() => Promise<Record<string, any>>); |
| import type { Config } from './index.js'; | ||
| import type { RouteTree } from '../../router.js'; | ||
| export declare function createRequestHandler(config: Config): (req: Request) => Promise<Response>; | ||
| export declare function createRequestHandler(config: Config): (req: Request) => Promise<{ | ||
| response: Response; | ||
| headers: { | ||
| [key: string]: string | string[]; | ||
| }; | ||
| }>; | ||
| export declare function Resolve(request: Request, tree: RouteTree, config: Config): Promise<{ | ||
@@ -5,0 +10,0 @@ response: Response; |
| import { ServerOnlyWarning } from "../util.js"; | ||
| ServerOnlyWarning("native-request"); | ||
| import { GenericContext } from "../router.js"; | ||
| import { MakeStatus } from "../../status.js"; | ||
| export function createRequestHandler(config) { | ||
| return async (req) => { | ||
| try { | ||
| const mod = typeof config.build === "function" ? await config.build() : await config.build; | ||
| let { response } = await Resolve(req, mod.tree, config); | ||
| return response; | ||
| } | ||
| catch (e) { | ||
| if (e instanceof Error) { | ||
| console.error(e.stack); | ||
| config.viteDevServer?.ssrFixStacktrace(e); | ||
| return new Response(e.message + "\n" + e.stack, { status: 500, statusText: "Internal Server Error" }); | ||
| } | ||
| else { | ||
| console.error(e); | ||
| return new Response(String(e), { status: 500, statusText: "Internal Server Error" }); | ||
| } | ||
| } | ||
| const mod = typeof config.build === "function" ? await config.build() : await config.build; | ||
| return await Resolve(req, mod.tree, config); | ||
| }; | ||
| } | ||
| export async function Resolve(request, tree, config) { | ||
| const url = new URL(request.url); | ||
| const ctx = new GenericContext(request, url, config.render); | ||
| const x = ctx.url.pathname.endsWith("/") ? ctx.url.pathname.slice(0, -1) : ctx.url.pathname; | ||
| const fragments = x.split("/").slice(1); | ||
| let response = await tree.resolve(fragments, ctx); | ||
| if (response === null) | ||
| response = new Response("No Route Found", { status: 404, statusText: "Not Found", headers: ctx.headers }); | ||
| // Override with context headers | ||
| if (response.headers !== ctx.headers) { | ||
| for (const [key, value] of ctx.headers) { | ||
| if (response.headers.has(key)) | ||
| continue; | ||
| response.headers.set(key, value); | ||
| const ctx = new GenericContext(request, new URL(request.url), config.render); | ||
| let response; | ||
| try { | ||
| const x = ctx.url.pathname.endsWith("/") ? ctx.url.pathname.slice(0, -1) : ctx.url.pathname; | ||
| const fragments = x.split("/").slice(1); | ||
| const res = await tree.resolve(fragments, ctx); | ||
| response = res === null | ||
| ? new Response("No Route Found", MakeStatus("Not Found", ctx.headers)) | ||
| : res; | ||
| // Override with context headers | ||
| if (response.headers !== ctx.headers) { | ||
| for (const [key, value] of ctx.headers) | ||
| response.headers.set(key, value); | ||
| } | ||
| } | ||
| catch (e) { | ||
| if (e instanceof Error) { | ||
| console.error(e.stack); | ||
| config.viteDevServer?.ssrFixStacktrace(e); | ||
| response = new Response(e.message + "\n" + e.stack, { status: 500, statusText: "Internal Server Error" }); | ||
| } | ||
| else { | ||
| console.error(e); | ||
| response = new Response(String(e), { status: 500, statusText: "Internal Server Error" }); | ||
| } | ||
| } | ||
| // Merge cookie changes | ||
@@ -41,0 +39,0 @@ const headers = Object.fromEntries(response.headers); |
+1
-1
| { | ||
| "name": "htmx-router", | ||
| "version": "1.0.4", | ||
| "version": "1.0.5", | ||
| "description": "A lightweight SSR framework with server+client islands", | ||
@@ -5,0 +5,0 @@ "keywords": [ |
+1
-4
@@ -67,6 +67,3 @@ declare const definitions: { | ||
| export type StatusText = typeof definitions[keyof typeof definitions]; | ||
| export declare function MakeStatus(lookup: number | StatusText): { | ||
| status: number; | ||
| statusText: StatusText; | ||
| }; | ||
| export declare function MakeStatus(lookup: number | StatusText, init?: ResponseInit | Headers): ResponseInit; | ||
| export {}; |
+17
-6
@@ -76,8 +76,10 @@ const definitions = { | ||
| } | ||
| export function MakeStatus(lookup) { | ||
| export function MakeStatus(lookup, init) { | ||
| if (init instanceof Headers) | ||
| init = { headers: init }; | ||
| if (typeof lookup === "number") | ||
| return lookupCode(lookup); | ||
| return lookupStatus(lookup); | ||
| return lookupCode(lookup, init); | ||
| return lookupStatus(lookup, init); | ||
| } | ||
| function lookupCode(status) { | ||
| function lookupCode(status, init) { | ||
| if (status < 100) | ||
@@ -87,9 +89,18 @@ throw new TypeError(`Status ${status}<100`); | ||
| throw new TypeError(`Status ${status}>599`); | ||
| return { status, statusText: lookup[status] }; | ||
| const statusText = lookup[status]; | ||
| return Status(status, statusText, init); | ||
| } | ||
| function lookupStatus(statusText) { | ||
| function lookupStatus(statusText, init) { | ||
| const status = index.get(statusText.toLowerCase()); | ||
| if (!status) | ||
| throw new TypeError(`statusText ${statusText} is not of type StatusText`); | ||
| return Status(status, statusText, init); | ||
| } | ||
| function Status(status, statusText, init) { | ||
| if (init) { | ||
| init.statusText = statusText; | ||
| init.status = status; | ||
| return init; | ||
| } | ||
| return { status, statusText }; | ||
| } |
Environment variable access
Supply chain riskPackage accesses environment variables, which may be a sign of credential stuffing or data theft.
Found 1 instance in 1 package
Filesystem access
Supply chain riskAccesses the file system, and could potentially read sensitive data.
Found 1 instance in 1 package
Long strings
Supply chain riskContains long string literals, which may be a sign of obfuscated or packed code.
Found 1 instance in 1 package
Environment variable access
Supply chain riskPackage accesses environment variables, which may be a sign of credential stuffing or data theft.
Found 1 instance in 1 package
Filesystem access
Supply chain riskAccesses the file system, and could potentially read sensitive data.
Found 1 instance in 1 package
Long strings
Supply chain riskContains long string literals, which may be a sign of obfuscated or packed code.
Found 1 instance in 1 package
81679
0.32%2358
0.43%9
12.5%