Skip to content

Instantly share code, notes, and snippets.

@LorisSigrist
Created January 9, 2024 18:57
Show Gist options
  • Save LorisSigrist/20b9caf91c1deb2a60a66f70669c4437 to your computer and use it in GitHub Desktop.
Save LorisSigrist/20b9caf91c1deb2a60a66f70669c4437 to your computer and use it in GitHub Desktop.
A SvelteKit hook for enforcing rules on a route-level
import { dev } from "$app/environment";
import { sequence } from "@sveltejs/kit/hooks";
// A rule segment has the form ($ruleName)
const ruleSegmentRegex = /^\(\$[a-zA-Z_]+\)$/;
/**
* Checks if a segment is a rule segment.
*
* @param {string} segment
* @returns {segment is `($${string})`}
*/
const isRuleSegment = (segment) => ruleSegmentRegex.test(segment);
/**
* Enforces a set of rules based on the route.
*
* You can apply a rule to a route by adding a segment to the route that looks like this: ($ruleName)
* This will cause the rule with the name "ruleName" to be applied when a request is made to that route.
*
* @param {Record<string, import("@sveltejs/kit").Handle>} rules
* @returns {import("@sveltejs/kit").Handle}
*/
export function enforce(rules) {
const ruleNames = Object.keys(rules);
return async ({ event, resolve }) => {
// ignore 404s
if (!event.route.id) return resolve(event);
// Get all the rules that apply to this route
const applicableRules = event.route.id
.split('/')
.filter(isRuleSegment)
.map((segment) => segment.slice(2, -1));
// If any of the rules that should apply to this route are not defined throw an error
// it's most likely a typo. Ee don't want to miss it & cause a security issue.
for (const rule of applicableRules) {
if (!ruleNames.includes(rule)) {
return new Response(dev ? `Enforcer Error: Rule "${rule}" in route ${event.route.id} is not defined. Did you make a typo?` : "Internal Server Error", {
status: 500,
});
}
}
const ruleHandlers = applicableRules.map((rule) => rules[rule]);
return await sequence(...ruleHandlers)({ event, resolve });
};
}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment