next-csrf
Version:
CSRF mitigation library for Next.js
27 lines • 6.69 kB
JavaScript
;var _interopRequireWildcard=require("@babel/runtime/helpers/interopRequireWildcard");exports.__esModule=true;exports.default=void 0;var _react=_interopRequireWildcard(require("react"));var _router=require("../next-server/lib/router/router");var _router2=require("./router");let cachedObserver;const listeners=new Map();const IntersectionObserver=typeof window!=='undefined'?window.IntersectionObserver:null;const prefetched={};function getObserver(){// Return shared instance of IntersectionObserver if already created
if(cachedObserver){return cachedObserver;}// Only create shared IntersectionObserver if supported in browser
if(!IntersectionObserver){return undefined;}return cachedObserver=new IntersectionObserver(entries=>{entries.forEach(entry=>{if(!listeners.has(entry.target)){return;}const cb=listeners.get(entry.target);if(entry.isIntersecting||entry.intersectionRatio>0){cachedObserver.unobserve(entry.target);listeners.delete(entry.target);cb();}});},{rootMargin:'200px'});}const listenToIntersections=(el,cb)=>{const observer=getObserver();if(!observer){return()=>{};}observer.observe(el);listeners.set(el,cb);return()=>{try{observer.unobserve(el);}catch(err){console.error(err);}listeners.delete(el);};};function prefetch(router,href,as,options){if(typeof window==='undefined')return;if(!(0,_router.isLocalURL)(href))return;// Prefetch the JSON page if asked (only in the client)
// We need to handle a prefetch error here since we may be
// loading with priority which can reject but we don't
// want to force navigation since this is only a prefetch
router.prefetch(href,as,options).catch(err=>{if(process.env.NODE_ENV!=='production'){// rethrow to show invalid URL errors
throw err;}});// Join on an invalid URI character
prefetched[href+'%'+as]=true;}function isModifiedEvent(event){const{target}=event.currentTarget;return target&&target!=='_self'||event.metaKey||event.ctrlKey||event.shiftKey||event.altKey||// triggers resource download
event.nativeEvent&&event.nativeEvent.which===2;}function linkClicked(e,router,href,as,replace,shallow,scroll){const{nodeName}=e.currentTarget;if(nodeName==='A'&&(isModifiedEvent(e)||!(0,_router.isLocalURL)(href))){// ignore click for browser’s default behavior
return;}e.preventDefault();// avoid scroll for urls with anchor refs
if(scroll==null){scroll=as.indexOf('#')<0;}// replace state instead of push if prop is present
router[replace?'replace':'push'](href,as,{shallow}).then(success=>{if(!success)return;if(scroll){window.scrollTo(0,0);document.body.focus();}});}function Link(props){if(process.env.NODE_ENV!=='production'){function createPropError(args){return new Error(`Failed prop type: The prop \`${args.key}\` expects a ${args.expected} in \`<Link>\`, but got \`${args.actual}\` instead.`+(typeof window!=='undefined'?"\nOpen your browser's console to view the Component stack trace.":''));}// TypeScript trick for type-guarding:
const requiredPropsGuard={href:true};const requiredProps=Object.keys(requiredPropsGuard);requiredProps.forEach(key=>{if(key==='href'){if(props[key]==null||typeof props[key]!=='string'&&typeof props[key]!=='object'){throw createPropError({key,expected:'`string` or `object`',actual:props[key]===null?'null':typeof props[key]});}}else{// TypeScript trick for type-guarding:
// eslint-disable-next-line @typescript-eslint/no-unused-vars
const _=key;}});// TypeScript trick for type-guarding:
const optionalPropsGuard={as:true,replace:true,scroll:true,shallow:true,passHref:true,prefetch:true};const optionalProps=Object.keys(optionalPropsGuard);optionalProps.forEach(key=>{if(key==='as'){if(props[key]&&typeof props[key]!=='string'&&typeof props[key]!=='object'){throw createPropError({key,expected:'`string` or `object`',actual:typeof props[key]});}}else if(key==='replace'||key==='scroll'||key==='shallow'||key==='passHref'||key==='prefetch'){if(props[key]!=null&&typeof props[key]!=='boolean'){throw createPropError({key,expected:'`boolean`',actual:typeof props[key]});}}else{// TypeScript trick for type-guarding:
// eslint-disable-next-line @typescript-eslint/no-unused-vars
const _=key;}});// This hook is in a conditional but that is ok because `process.env.NODE_ENV` never changes
// eslint-disable-next-line react-hooks/rules-of-hooks
const hasWarned=_react.default.useRef(false);if(props.prefetch&&!hasWarned.current){hasWarned.current=true;console.warn('Next.js auto-prefetches automatically based on viewport. The prefetch attribute is no longer needed. More: https://err.sh/vercel/next.js/prefetch-true-deprecated');}}const p=props.prefetch!==false;const[childElm,setChildElm]=_react.default.useState();const router=(0,_router2.useRouter)();const pathname=router&&router.pathname||'/';const{href,as}=_react.default.useMemo(()=>{const resolvedHref=(0,_router.resolveHref)(pathname,props.href);return{href:resolvedHref,as:props.as?(0,_router.resolveHref)(pathname,props.as):resolvedHref};},[pathname,props.href,props.as]);_react.default.useEffect(()=>{if(p&&IntersectionObserver&&childElm&&childElm.tagName&&(0,_router.isLocalURL)(href)){// Join on an invalid URI character
const isPrefetched=prefetched[href+'%'+as];if(!isPrefetched){return listenToIntersections(childElm,()=>{prefetch(router,href,as);});}}},[p,childElm,href,as,router]);let{children,replace,shallow,scroll}=props;// Deprecated. Warning shown by propType check. If the children provided is a string (<Link>example</Link>) we wrap it in an <a> tag
if(typeof children==='string'){children=/*#__PURE__*/_react.default.createElement("a",null,children);}// This will return the first child, if multiple are provided it will throw an error
const child=_react.Children.only(children);const childProps={ref:el=>{if(el)setChildElm(el);if(child&&typeof child==='object'&&child.ref){if(typeof child.ref==='function')child.ref(el);else if(typeof child.ref==='object'){child.ref.current=el;}}},onClick:e=>{if(child.props&&typeof child.props.onClick==='function'){child.props.onClick(e);}if(!e.defaultPrevented){linkClicked(e,router,href,as,replace,shallow,scroll);}}};if(p){childProps.onMouseEnter=e=>{if(!(0,_router.isLocalURL)(href))return;if(child.props&&typeof child.props.onMouseEnter==='function'){child.props.onMouseEnter(e);}prefetch(router,href,as,{priority:true});};}// If child is an <a> tag and doesn't have a href attribute, or if the 'passHref' property is
// defined, we specify the current 'href', so that repetition is not needed by the user
if(props.passHref||child.type==='a'&&!('href'in child.props)){childProps.href=(0,_router.addBasePath)(as);}return/*#__PURE__*/_react.default.cloneElement(child,childProps);}var _default=Link;exports.default=_default;
//# sourceMappingURL=link.js.map