Huge News!Announcing our $40M Series B led by Abstract Ventures.Learn More
Socket
Sign inDemoInstall
Socket

@serwist/routing

Package Overview
Dependencies
Maintainers
1
Versions
52
Alerts
File Explorer

Advanced tools

Socket logo

Install Socket

Detect and block malicious and high-risk dependencies

Install

@serwist/routing - npm Package Compare versions

Comparing version 9.0.0-preview.16 to 9.0.0-preview.17

dist/chunks/parseRoute.js

401

dist/index.js

@@ -1,66 +0,5 @@

import { assert, logger, getFriendlyURL, SerwistError } from '@serwist/core/internal';
import { assert, logger } from '@serwist/core/internal';
import { R as Route, p as parseRoute, g as getOrCreateDefaultRouter } from './chunks/parseRoute.js';
export { a as RegExpRoute, b as Router } from './chunks/parseRoute.js';
const defaultMethod = "GET";
const validMethods = [
"DELETE",
"GET",
"HEAD",
"PATCH",
"POST",
"PUT"
];
const normalizeHandler = (handler)=>{
if (handler && typeof handler === "object") {
if (process.env.NODE_ENV !== "production") {
assert.hasMethod(handler, "handle", {
moduleName: "@serwist/routing",
className: "Route",
funcName: "constructor",
paramName: "handler"
});
}
return handler;
}
if (process.env.NODE_ENV !== "production") {
assert.isType(handler, "function", {
moduleName: "@serwist/routing",
className: "Route",
funcName: "constructor",
paramName: "handler"
});
}
return {
handle: handler
};
};
class Route {
handler;
match;
method;
catchHandler;
constructor(match, handler, method = defaultMethod){
if (process.env.NODE_ENV !== "production") {
assert.isType(match, "function", {
moduleName: "@serwist/routing",
className: "Route",
funcName: "constructor",
paramName: "match"
});
if (method) {
assert.isOneOf(method, validMethods, {
paramName: "method"
});
}
}
this.handler = normalizeHandler(handler);
this.match = match;
this.method = method;
}
setCatchHandler(handler) {
this.catchHandler = normalizeHandler(handler);
}
}
class NavigationRoute extends Route {

@@ -116,334 +55,4 @@ _allowlist;

class RegExpRoute extends Route {
constructor(regExp, handler, method){
if (process.env.NODE_ENV !== "production") {
assert.isInstance(regExp, RegExp, {
moduleName: "@serwist/routing",
className: "RegExpRoute",
funcName: "constructor",
paramName: "pattern"
});
}
const match = ({ url })=>{
const result = regExp.exec(url.href);
if (!result) {
return;
}
if (url.origin !== location.origin && result.index !== 0) {
if (process.env.NODE_ENV !== "production") {
logger.debug(`The regular expression '${regExp.toString()}' only partially matched against the cross-origin URL '${url.toString()}'. RegExpRoute's will only handle cross-origin requests if they match the entire URL.`);
}
return;
}
return result.slice(1);
};
super(match, handler, method);
}
}
class Router {
_routes;
_defaultHandlerMap;
_catchHandler;
constructor(){
this._routes = new Map();
this._defaultHandlerMap = new Map();
}
get routes() {
return this._routes;
}
addFetchListener() {
self.addEventListener("fetch", (event)=>{
const { request } = event;
const responsePromise = this.handleRequest({
request,
event
});
if (responsePromise) {
event.respondWith(responsePromise);
}
});
}
addCacheListener() {
self.addEventListener("message", (event)=>{
if (event.data && event.data.type === "CACHE_URLS") {
const { payload } = event.data;
if (process.env.NODE_ENV !== "production") {
logger.debug("Caching URLs from the window", payload.urlsToCache);
}
const requestPromises = Promise.all(payload.urlsToCache.map((entry)=>{
if (typeof entry === "string") {
entry = [
entry
];
}
const request = new Request(...entry);
return this.handleRequest({
request,
event
});
}));
event.waitUntil(requestPromises);
if (event.ports?.[0]) {
void requestPromises.then(()=>event.ports[0].postMessage(true));
}
}
});
}
handleRequest({ request, event }) {
if (process.env.NODE_ENV !== "production") {
assert.isInstance(request, Request, {
moduleName: "@serwist/routing",
className: "Router",
funcName: "handleRequest",
paramName: "options.request"
});
}
const url = new URL(request.url, location.href);
if (!url.protocol.startsWith("http")) {
if (process.env.NODE_ENV !== "production") {
logger.debug("The Serwist router only supports URLs that start with 'http'.");
}
return;
}
const sameOrigin = url.origin === location.origin;
const { params, route } = this.findMatchingRoute({
event,
request,
sameOrigin,
url
});
let handler = route?.handler;
const debugMessages = [];
if (process.env.NODE_ENV !== "production") {
if (handler) {
debugMessages.push([
"Found a route to handle this request:",
route
]);
if (params) {
debugMessages.push([
`Passing the following params to the route's handler:`,
params
]);
}
}
}
const method = request.method;
if (!handler && this._defaultHandlerMap.has(method)) {
if (process.env.NODE_ENV !== "production") {
debugMessages.push(`Failed to find a matching route. Falling back to the default handler for ${method}.`);
}
handler = this._defaultHandlerMap.get(method);
}
if (!handler) {
if (process.env.NODE_ENV !== "production") {
logger.debug(`No route found for: ${getFriendlyURL(url)}`);
}
return;
}
if (process.env.NODE_ENV !== "production") {
logger.groupCollapsed(`Router is responding to: ${getFriendlyURL(url)}`);
for (const msg of debugMessages){
if (Array.isArray(msg)) {
logger.log(...msg);
} else {
logger.log(msg);
}
}
logger.groupEnd();
}
let responsePromise;
try {
responsePromise = handler.handle({
url,
request,
event,
params
});
} catch (err) {
responsePromise = Promise.reject(err);
}
const catchHandler = route?.catchHandler;
if (responsePromise instanceof Promise && (this._catchHandler || catchHandler)) {
responsePromise = responsePromise.catch(async (err)=>{
if (catchHandler) {
if (process.env.NODE_ENV !== "production") {
logger.groupCollapsed(`Error thrown when responding to: ${getFriendlyURL(url)}. Falling back to route's Catch Handler.`);
logger.error("Error thrown by:", route);
logger.error(err);
logger.groupEnd();
}
try {
return await catchHandler.handle({
url,
request,
event,
params
});
} catch (catchErr) {
if (catchErr instanceof Error) {
err = catchErr;
}
}
}
if (this._catchHandler) {
if (process.env.NODE_ENV !== "production") {
logger.groupCollapsed(`Error thrown when responding to: ${getFriendlyURL(url)}. Falling back to global Catch Handler.`);
logger.error("Error thrown by:", route);
logger.error(err);
logger.groupEnd();
}
return this._catchHandler.handle({
url,
request,
event
});
}
throw err;
});
}
return responsePromise;
}
findMatchingRoute({ url, sameOrigin, request, event }) {
const routes = this._routes.get(request.method) || [];
for (const route of routes){
let params;
const matchResult = route.match({
url,
sameOrigin,
request,
event
});
if (matchResult) {
if (process.env.NODE_ENV !== "production") {
if (matchResult instanceof Promise) {
logger.warn(`While routing ${getFriendlyURL(url)}, an async matchCallback function was used. Please convert the following route to use a synchronous matchCallback function:`, route);
}
}
params = matchResult;
if (Array.isArray(params) && params.length === 0) {
params = undefined;
} else if (matchResult.constructor === Object && Object.keys(matchResult).length === 0) {
params = undefined;
} else if (typeof matchResult === "boolean") {
params = undefined;
}
return {
route,
params
};
}
}
return {};
}
setDefaultHandler(handler, method = defaultMethod) {
this._defaultHandlerMap.set(method, normalizeHandler(handler));
}
setCatchHandler(handler) {
this._catchHandler = normalizeHandler(handler);
}
registerRoute(route) {
if (process.env.NODE_ENV !== "production") {
assert.isType(route, "object", {
moduleName: "@serwist/routing",
className: "Router",
funcName: "registerRoute",
paramName: "route"
});
assert.hasMethod(route, "match", {
moduleName: "@serwist/routing",
className: "Router",
funcName: "registerRoute",
paramName: "route"
});
assert.isType(route.handler, "object", {
moduleName: "@serwist/routing",
className: "Router",
funcName: "registerRoute",
paramName: "route"
});
assert.hasMethod(route.handler, "handle", {
moduleName: "@serwist/routing",
className: "Router",
funcName: "registerRoute",
paramName: "route.handler"
});
assert.isType(route.method, "string", {
moduleName: "@serwist/routing",
className: "Router",
funcName: "registerRoute",
paramName: "route.method"
});
}
if (!this._routes.has(route.method)) {
this._routes.set(route.method, []);
}
this._routes.get(route.method).push(route);
}
unregisterRoute(route) {
if (!this._routes.has(route.method)) {
throw new SerwistError("unregister-route-but-not-found-with-method", {
method: route.method
});
}
const routeIndex = this._routes.get(route.method).indexOf(route);
if (routeIndex > -1) {
this._routes.get(route.method).splice(routeIndex, 1);
} else {
throw new SerwistError("unregister-route-route-not-registered");
}
}
}
let defaultRouter;
const getOrCreateDefaultRouter = ()=>{
if (!defaultRouter) {
defaultRouter = new Router();
defaultRouter.addFetchListener();
defaultRouter.addCacheListener();
}
return defaultRouter;
};
const registerRoute = (capture, handler, method)=>{
let route;
if (typeof capture === "string") {
const captureUrl = new URL(capture, location.href);
if (process.env.NODE_ENV !== "production") {
if (!(capture.startsWith("/") || capture.startsWith("http"))) {
throw new SerwistError("invalid-string", {
moduleName: "@serwist/routing",
funcName: "registerRoute",
paramName: "capture"
});
}
const valueToCheck = capture.startsWith("http") ? captureUrl.pathname : capture;
const wildcards = "[*:?+]";
if (new RegExp(`${wildcards}`).exec(valueToCheck)) {
logger.debug(`The '$capture' parameter contains an Express-style wildcard character (${wildcards}). Strings are now always interpreted as exact matches; use a RegExp for partial or wildcard matches.`);
}
}
const matchCallback = ({ url })=>{
if (process.env.NODE_ENV !== "production") {
if (url.pathname === captureUrl.pathname && url.origin !== captureUrl.origin) {
logger.debug(`${capture} only partially matches the cross-origin URL ${url.toString()}. This route will only handle cross-origin requests if they match the entire URL.`);
}
}
return url.href === captureUrl.href;
};
route = new Route(matchCallback, handler, method);
} else if (capture instanceof RegExp) {
route = new RegExpRoute(capture, handler, method);
} else if (typeof capture === "function") {
route = new Route(capture, handler, method);
} else if (capture instanceof Route) {
route = capture;
} else {
throw new SerwistError("unsupported-route-type", {
moduleName: "@serwist/routing",
funcName: "registerRoute",
paramName: "capture"
});
}
const route = parseRoute(capture, handler, method);
const defaultRouter = getOrCreateDefaultRouter();

@@ -469,2 +78,2 @@ defaultRouter.registerRoute(route);

export { NavigationRoute, RegExpRoute, Route, Router, registerRoute, setCatchHandler, setDefaultHandler, unregisterRoute };
export { NavigationRoute, Route, registerRoute, setCatchHandler, setDefaultHandler, unregisterRoute };
{
"name": "@serwist/routing",
"version": "9.0.0-preview.16",
"version": "9.0.0-preview.17",
"type": "module",

@@ -25,2 +25,9 @@ "description": "A service worker helper library to route request URLs to handlers.",

"types": "./dist/index.d.ts",
"typesVersions": {
"*": {
"internal": [
"./dist/index.internal.d.ts"
]
}
},
"exports": {

@@ -31,6 +38,10 @@ ".": {

},
"./internal": {
"types": "./dist/index.internal.d.ts",
"default": "./dist/index.internal.js"
},
"./package.json": "./package.json"
},
"dependencies": {
"@serwist/core": "9.0.0-preview.16"
"@serwist/core": "9.0.0-preview.17"
},

@@ -40,3 +51,3 @@ "devDependencies": {

"typescript": "5.5.0-dev.20240323",
"@serwist/constants": "9.0.0-preview.16"
"@serwist/constants": "9.0.0-preview.17"
},

@@ -43,0 +54,0 @@ "peerDependencies": {

@@ -10,8 +10,7 @@ /*

import type { RouteHandler, RouteMatchCallback } from "@serwist/core";
import { SerwistError, logger } from "@serwist/core/internal";
import { RegExpRoute } from "./RegExpRoute.js";
import { Route } from "./Route.js";
import type { HTTPMethod } from "./utils/constants.js";
import { getOrCreateDefaultRouter } from "./utils/getOrCreateDefaultRouter.js";
import { parseRoute } from "./utils/parseRoute.js";

@@ -29,59 +28,4 @@ /**

export const registerRoute = (capture: RegExp | string | RouteMatchCallback | Route, handler?: RouteHandler, method?: HTTPMethod): Route => {
let route: Route;
const route = parseRoute(capture, handler, method);
if (typeof capture === "string") {
const captureUrl = new URL(capture, location.href);
if (process.env.NODE_ENV !== "production") {
if (!(capture.startsWith("/") || capture.startsWith("http"))) {
throw new SerwistError("invalid-string", {
moduleName: "@serwist/routing",
funcName: "registerRoute",
paramName: "capture",
});
}
// We want to check if Express-style wildcards are in the pathname only.
// TODO: Remove this log message in v4.
const valueToCheck = capture.startsWith("http") ? captureUrl.pathname : capture;
// See https://github.com/pillarjs/path-to-regexp#parameters
const wildcards = "[*:?+]";
if (new RegExp(`${wildcards}`).exec(valueToCheck)) {
logger.debug(
`The '$capture' parameter contains an Express-style wildcard character (${wildcards}). Strings are now always interpreted as exact matches; use a RegExp for partial or wildcard matches.`,
);
}
}
const matchCallback: RouteMatchCallback = ({ url }) => {
if (process.env.NODE_ENV !== "production") {
if (url.pathname === captureUrl.pathname && url.origin !== captureUrl.origin) {
logger.debug(
`${capture} only partially matches the cross-origin URL ${url.toString()}. This route will only handle cross-origin requests if they match the entire URL.`,
);
}
}
return url.href === captureUrl.href;
};
// If `capture` is a string then `handler` and `method` must be present.
route = new Route(matchCallback, handler!, method);
} else if (capture instanceof RegExp) {
// If `capture` is a `RegExp` then `handler` and `method` must be present.
route = new RegExpRoute(capture, handler!, method);
} else if (typeof capture === "function") {
// If `capture` is a function then `handler` and `method` must be present.
route = new Route(capture, handler!, method);
} else if (capture instanceof Route) {
route = capture;
} else {
throw new SerwistError("unsupported-route-type", {
moduleName: "@serwist/routing",
funcName: "registerRoute",
paramName: "capture",
});
}
const defaultRouter = getOrCreateDefaultRouter();

@@ -88,0 +32,0 @@ defaultRouter.registerRoute(route);

Sorry, the diff of this file is not supported yet

SocketSocket SOC 2 Logo

Product

  • Package Alerts
  • Integrations
  • Docs
  • Pricing
  • FAQ
  • Roadmap
  • Changelog

Packages

npm

Stay in touch

Get open source security insights delivered straight into your inbox.


  • Terms
  • Privacy
  • Security

Made with ⚡️ by Socket Inc