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

react-to-print

Package Overview
Dependencies
Maintainers
0
Versions
94
Alerts
File Explorer

Advanced tools

Socket logo

Install Socket

Detect and block malicious and high-risk dependencies

Install

react-to-print - npm Package Compare versions

Comparing version 3.0.3-beta-1 to 3.0.3

2

lib/index.js

@@ -1,1 +0,1 @@

!function(e,t){"object"==typeof exports&&"object"==typeof module?module.exports=t(require("react")):"function"==typeof define&&define.amd?define("lib",["react"],t):"object"==typeof exports?exports.lib=t(require("react")):e.lib=t(e.react)}("undefined"!=typeof self?self:this,(function(e){return function(){"use strict";var t={155:function(t){t.exports=e}},o={};function n(e){var r=o[e];if(void 0!==r)return r.exports;var s=o[e]={exports:{}};return t[e](s,s.exports,n),s.exports}n.d=function(e,t){for(var o in t)n.o(t,o)&&!n.o(e,o)&&Object.defineProperty(e,o,{enumerable:!0,get:t[o]})},n.o=function(e,t){return Object.prototype.hasOwnProperty.call(e,t)},n.r=function(e){"undefined"!=typeof Symbol&&Symbol.toStringTag&&Object.defineProperty(e,Symbol.toStringTag,{value:"Module"}),Object.defineProperty(e,"__esModule",{value:!0})};var r={};n.r(r),n.d(r,{useReactToPrint:function(){return g}});var s=n(155);function i({level:e="error",messages:t,suppressErrors:o=!1}){o||("error"===e?console.error(t):"warning"===e?console.warn(t):console.debug(t))}function l(e,t){if(t||!e){const e=document.getElementById("printWindow");e&&document.body.removeChild(e)}}function a(e){return e instanceof Error?e:new Error("Unknown Error")}function c(e,t){const{documentTitle:o,onAfterPrint:n,onPrintError:r,preserveAfterPrint:s,print:c,suppressErrors:d}=t;setTimeout((()=>{var t,u;if(e.contentWindow)if(e.contentWindow.focus(),c)c(e).then((()=>{null==n||n()})).then((()=>{l(s)})).catch((e=>{r?r("print",a(e)):i({messages:["An error was thrown by the specified `print` function"],suppressErrors:d})}));else{if(e.contentWindow.print){const n=null!==(u=null===(t=e.contentDocument)||void 0===t?void 0:t.title)&&void 0!==u?u:"",r=e.ownerDocument.title;o&&(e.ownerDocument.title=o,e.contentDocument&&(e.contentDocument.title=o)),e.contentWindow.print(),o&&(e.ownerDocument.title=r,e.contentDocument&&(e.contentDocument.title=n))}else i({messages:["Printing for this browser is not currently possible: the browser does not have a `print` method available for iframes."],suppressErrors:d});window.addEventListener("focus",(()=>{null==n||n(),l(s)}),{once:!0})}else i({messages:["Printing failed because the `contentWindow` of the print iframe did not load. This is possibly an error with `react-to-print`. Please file an issue: https://github.com/MatthewHerbst/react-to-print/issues/"],suppressErrors:d})}),500)}function d(e){const t=[],o=document.createTreeWalker(e,NodeFilter.SHOW_ELEMENT,null);let n=o.nextNode();for(;n;)t.push(n),n=o.nextNode();return t}function u(e,t,o){const n=d(e),r=d(t);if(n.length===r.length)for(let e=0;e<n.length;e++){const t=n[e],s=r[e],i=t.shadowRoot;if(null!==i){const e=s.attachShadow({mode:i.mode});e.innerHTML=i.innerHTML,u(i,e,o)}}else i({messages:["When cloning shadow root content, source and target elements have different size. `onBeforePrint` likely resolved too early.",e,t],suppressErrors:o})}const p='\n @page {\n /* Remove browser default header (title) and footer (url) */\n margin: 0;\n }\n @media print {\n body {\n /* Tell browsers to print background colors */\n color-adjust: exact; /* Firefox. This is an older version of "print-color-adjust" */\n print-color-adjust: exact; /* Firefox/Safari */\n -webkit-print-color-adjust: exact; /* Chrome/Safari/Edge/Opera */\n }\n }\n';function h(e,t,o,n){var r,s,l,d,h;const{contentNode:f,clonedContentNode:g,clonedImgNodes:m,clonedVideoNodes:b,numResourcesToLoad:y,originalCanvasNodes:v}=o,{bodyClass:w,fonts:E,ignoreGlobalStyles:A,pageStyle:T,nonce:x,suppressErrors:k,copyShadowRoots:S}=n;e.onload=null;const N=null!==(r=e.contentDocument)&&void 0!==r?r:null===(s=e.contentWindow)||void 0===s?void 0:s.document;if(N){const o=N.body.appendChild(g);S&&u(f,o,!!k),E&&((null===(l=e.contentDocument)||void 0===l?void 0:l.fonts)&&(null===(d=e.contentWindow)||void 0===d?void 0:d.FontFace)?E.forEach((o=>{const n=new FontFace(o.family,o.source,{weight:o.weight,style:o.style});e.contentDocument.fonts.add(n),n.loaded.then((()=>{t(n)})).catch((e=>{t(n,["Failed loading the font:",n,"Load error:",a(e)])}))})):(E.forEach((e=>{t(e)})),i({messages:['"react-to-print" is not able to load custom fonts because the browser does not support the FontFace API but will continue attempting to print the page'],suppressErrors:k})));const n=null!=T?T:p,r=N.createElement("style");x&&(r.setAttribute("nonce",x),N.head.setAttribute("nonce",x)),r.appendChild(N.createTextNode(n)),N.head.appendChild(r),w&&N.body.classList.add(...w.split(" "));const s=N.querySelectorAll("canvas");for(let e=0;e<v.length;++e){const t=v[e],o=s[e];if(void 0===o){i({messages:["A canvas element could not be copied for printing, has it loaded? `onBeforePrint` likely resolved too early.",t],suppressErrors:k});continue}const n=o.getContext("2d");n&&n.drawImage(t,0,0)}for(let e=0;e<m.length;e++){const o=m[e],n=o.getAttribute("src");if(n){const e=new Image;e.onload=()=>{t(o)},e.onerror=(e,n,r,s,i)=>{t(o,["Error loading <img>",o,"Error",i])},e.src=n}else t(o,['Found an <img> tag with an empty "src" attribute. This prevents pre-loading it.',o])}for(let e=0;e<b.length;e++){const o=b[e];o.preload="auto";const n=o.getAttribute("poster");if(n){const e=new Image;e.onload=()=>{t(o)},e.onerror=(e,r,s,i,l)=>{t(o,["Error loading video poster",n,"for video",o,"Error:",l])},e.src=n}else o.readyState>=2?t(o):(o.onloadeddata=()=>{t(o)},o.onerror=(e,n,r,s,i)=>{t(o,["Error loading video",o,"Error",i])},o.onstalled=()=>{t(o,["Loading video stalled, skipping",o])})}const c="select",y=f.querySelectorAll(c),C=N.querySelectorAll(c);for(let e=0;e<y.length;e++)C[e].value=y[e].value;if(!A){const e=document.querySelectorAll("style, link[rel~='stylesheet'], link[as='style']");for(let o=0,n=e.length;o<n;++o){const n=e[o];if("style"===n.tagName.toLowerCase()){const e=N.createElement(n.tagName),t=n.sheet;if(t){let r="";try{const e=t.cssRules.length;for(let o=0;o<e;++o)"string"==typeof t.cssRules[o].cssText&&(r+=`${t.cssRules[o].cssText}\r\n`)}catch(e){i({messages:["A stylesheet could not be accessed. This is likely due to the stylesheet having cross-origin imports, and many browsers block script access to cross-origin stylesheets. See https://github.com/MatthewHerbst/react-to-print/issues/429 for details. You may be able to load the sheet by both marking the stylesheet with the cross `crossorigin` attribute, and setting the `Access-Control-Allow-Origin` header on the server serving the stylesheet. Alternatively, host the stylesheet on your domain to avoid this issue entirely.",n,`Original error: ${a(e).message}`],level:"warning"})}e.setAttribute("id",`react-to-print-${o}`),x&&e.setAttribute("nonce",x),e.appendChild(N.createTextNode(r)),N.head.appendChild(e)}}else if(n.getAttribute("href"))if(n.hasAttribute("disabled"))i({messages:["`react-to-print` encountered a <link> tag with a `disabled` attribute and will ignore it. Note that the `disabled` attribute is deprecated, and some browsers ignore it. You should stop using it. https://developer.mozilla.org/en-US/docs/Web/HTML/Element/link#attr-disabled. The <link> is:",n],level:"warning"}),t(n);else{const e=N.createElement(n.tagName);for(let t=0,o=n.attributes.length;t<o;++t){const o=n.attributes[t];o&&e.setAttribute(o.nodeName,null!==(h=o.nodeValue)&&void 0!==h?h:"")}e.onload=()=>{t(e)},e.onerror=(o,n,r,s,i)=>{t(e,["Failed to load",e,"Error:",i])},x&&e.setAttribute("nonce",x),N.head.appendChild(e)}else i({messages:["`react-to-print` encountered a <link> tag with an empty `href` attribute. In addition to being invalid HTML, this can cause problems in many browsers, and so the <link> was not loaded. The <link> is:",n],level:"warning"}),t(n)}}}0===y&&c(e,n)}function f(e,t,o,n){e.onload=()=>{h(e,t,o,n)},document.body.appendChild(e)}function g(e){const{contentRef:t,fonts:o,ignoreGlobalStyles:n,onBeforePrint:r,onPrintError:d,preserveAfterPrint:u,suppressErrors:p}=e,h=(0,s.useCallback)((s=>{l(u,!0);const h=function({contentRef:e,optionalContent:t,suppressErrors:o}){return t&&(e&&i({level:"warning",messages:['"react-to-print" received a `contentRef` option and a optional-content param passed to its callback. The `contentRef` option will be ignored.']}),"function"==typeof t)?t():e?e.current:void i({messages:['"react-to-print" did not receive a `contentRef` option or a optional-content param pass to its callback.'],suppressErrors:o})}({contentRef:t,optionalContent:s,suppressErrors:p});if(!h)return void i({messages:["There is nothing to print"],suppressErrors:p});const g=h.cloneNode(!0),m=document.querySelectorAll("link[rel~='stylesheet'], link[as='style']"),b=g.querySelectorAll("img"),y=g.querySelectorAll("video"),v=o?o.length:0,w=(n?0:m.length)+b.length+y.length+v,E=[],A=[],T=function(){const e=document.createElement("iframe");return e.width=`${document.documentElement.clientWidth}px`,e.height=`${document.documentElement.clientHeight}px`,e.style.position="absolute",e.style.top=`-${document.documentElement.clientHeight+100}px`,e.style.left=`-${document.documentElement.clientWidth+100}px`,e.id="printWindow",e.srcdoc="<!DOCTYPE html>",e}(),x=(t,o)=>{E.includes(t)?i({level:"debug",messages:["Tried to mark a resource that has already been handled",t],suppressErrors:p}):(o?(i({messages:['"react-to-print" was unable to load a resource but will continue attempting to print the page',...o],suppressErrors:p}),A.push(t)):E.push(t),E.length+A.length===w&&c(T,e))},k={contentNode:h,clonedContentNode:g,clonedImgNodes:b,clonedVideoNodes:y,numResourcesToLoad:w,originalCanvasNodes:h.querySelectorAll("canvas")};r?r().then((()=>{f(T,x,k,e)})).catch((e=>{null==d||d("onBeforePrint",a(e))})):f(T,x,k,e)}),[e]);return h}return r}()}));
!function(e,t){"object"==typeof exports&&"object"==typeof module?module.exports=t(require("react")):"function"==typeof define&&define.amd?define("lib",["react"],t):"object"==typeof exports?exports.lib=t(require("react")):e.lib=t(e.react)}("undefined"!=typeof self?self:this,(function(e){return function(){"use strict";var t={155:function(t){t.exports=e}},o={};function n(e){var r=o[e];if(void 0!==r)return r.exports;var s=o[e]={exports:{}};return t[e](s,s.exports,n),s.exports}n.d=function(e,t){for(var o in t)n.o(t,o)&&!n.o(e,o)&&Object.defineProperty(e,o,{enumerable:!0,get:t[o]})},n.o=function(e,t){return Object.prototype.hasOwnProperty.call(e,t)},n.r=function(e){"undefined"!=typeof Symbol&&Symbol.toStringTag&&Object.defineProperty(e,Symbol.toStringTag,{value:"Module"}),Object.defineProperty(e,"__esModule",{value:!0})};var r={};n.r(r),n.d(r,{useReactToPrint:function(){return g}});var s=n(155);function i({level:e="error",messages:t,suppressErrors:o=!1}){o||("error"===e?console.error(t):"warning"===e?console.warn(t):console.debug(t))}function l(e,t){if(t||!e){const e=document.getElementById("printWindow");e&&document.body.removeChild(e)}}function a(e){return e instanceof Error?e:new Error("Unknown Error")}function c(e,t){const{documentTitle:o,onAfterPrint:n,onPrintError:r,preserveAfterPrint:s,print:c,suppressErrors:d}=t;setTimeout((()=>{var t,u;if(e.contentWindow)if(e.contentWindow.focus(),c)c(e).then((()=>{null==n||n(),l(s)})).catch((e=>{r?r("print",a(e)):i({messages:["An error was thrown by the specified `print` function"],suppressErrors:d})}));else{if(e.contentWindow.print){const n=null!==(u=null===(t=e.contentDocument)||void 0===t?void 0:t.title)&&void 0!==u?u:"",r=e.ownerDocument.title;o&&(e.ownerDocument.title=o,e.contentDocument&&(e.contentDocument.title=o)),e.contentWindow.print(),o&&(e.ownerDocument.title=r,e.contentDocument&&(e.contentDocument.title=n))}else i({messages:["Printing for this browser is not currently possible: the browser does not have a `print` method available for iframes."],suppressErrors:d});window.addEventListener("focus",(()=>{null==n||n(),l(s)}),{once:!0})}else i({messages:["Printing failed because the `contentWindow` of the print iframe did not load. This is possibly an error with `react-to-print`. Please file an issue: https://github.com/MatthewHerbst/react-to-print/issues/"],suppressErrors:d})}),500)}function d(e){const t=[],o=document.createTreeWalker(e,NodeFilter.SHOW_ELEMENT,null);let n=o.nextNode();for(;n;)t.push(n),n=o.nextNode();return t}function u(e,t,o){const n=d(e),r=d(t);if(n.length===r.length)for(let e=0;e<n.length;e++){const t=n[e],s=r[e],i=t.shadowRoot;if(null!==i){const e=s.attachShadow({mode:i.mode});e.innerHTML=i.innerHTML,u(i,e,o)}}else i({messages:["When cloning shadow root content, source and target elements have different size. `onBeforePrint` likely resolved too early.",e,t],suppressErrors:o})}const p='\n @page {\n /* Remove browser default header (title) and footer (url) */\n margin: 0;\n }\n @media print {\n body {\n /* Tell browsers to print background colors */\n color-adjust: exact; /* Firefox. This is an older version of "print-color-adjust" */\n print-color-adjust: exact; /* Firefox/Safari */\n -webkit-print-color-adjust: exact; /* Chrome/Safari/Edge/Opera */\n }\n }\n';function h(e,t,o,n){var r,s,l,d,h;const{contentNode:f,clonedContentNode:g,clonedImgNodes:m,clonedVideoNodes:b,numResourcesToLoad:y,originalCanvasNodes:v}=o,{bodyClass:w,fonts:E,ignoreGlobalStyles:A,pageStyle:T,nonce:x,suppressErrors:k,copyShadowRoots:S}=n;e.onload=null;const N=null!==(r=e.contentDocument)&&void 0!==r?r:null===(s=e.contentWindow)||void 0===s?void 0:s.document;if(N){const o=N.body.appendChild(g);S&&u(f,o,!!k),E&&((null===(l=e.contentDocument)||void 0===l?void 0:l.fonts)&&(null===(d=e.contentWindow)||void 0===d?void 0:d.FontFace)?E.forEach((o=>{const n=new FontFace(o.family,o.source,{weight:o.weight,style:o.style});e.contentDocument.fonts.add(n),n.loaded.then((()=>{t(n)})).catch((e=>{t(n,["Failed loading the font:",n,"Load error:",a(e)])}))})):(E.forEach((e=>{t(e)})),i({messages:['"react-to-print" is not able to load custom fonts because the browser does not support the FontFace API but will continue attempting to print the page'],suppressErrors:k})));const n=null!=T?T:p,r=N.createElement("style");x&&(r.setAttribute("nonce",x),N.head.setAttribute("nonce",x)),r.appendChild(N.createTextNode(n)),N.head.appendChild(r),w&&N.body.classList.add(...w.split(" "));const s=N.querySelectorAll("canvas");for(let e=0;e<v.length;++e){const t=v[e],o=s[e];if(void 0===o){i({messages:["A canvas element could not be copied for printing, has it loaded? `onBeforePrint` likely resolved too early.",t],suppressErrors:k});continue}const n=o.getContext("2d");n&&n.drawImage(t,0,0)}for(let e=0;e<m.length;e++){const o=m[e],n=o.getAttribute("src");if(n){const e=new Image;e.onload=()=>{t(o)},e.onerror=(e,n,r,s,i)=>{t(o,["Error loading <img>",o,"Error",i])},e.src=n}else t(o,['Found an <img> tag with an empty "src" attribute. This prevents pre-loading it.',o])}for(let e=0;e<b.length;e++){const o=b[e];o.preload="auto";const n=o.getAttribute("poster");if(n){const e=new Image;e.onload=()=>{t(o)},e.onerror=(e,r,s,i,l)=>{t(o,["Error loading video poster",n,"for video",o,"Error:",l])},e.src=n}else o.readyState>=2?t(o):(o.onloadeddata=()=>{t(o)},o.onerror=(e,n,r,s,i)=>{t(o,["Error loading video",o,"Error",i])},o.onstalled=()=>{t(o,["Loading video stalled, skipping",o])})}const c="select",y=f.querySelectorAll(c),C=N.querySelectorAll(c);for(let e=0;e<y.length;e++)C[e].value=y[e].value;if(!A){const e=document.querySelectorAll("style, link[rel~='stylesheet'], link[as='style']");for(let o=0,n=e.length;o<n;++o){const n=e[o];if("style"===n.tagName.toLowerCase()){const e=N.createElement(n.tagName),t=n.sheet;if(t){let r="";try{const e=t.cssRules.length;for(let o=0;o<e;++o)"string"==typeof t.cssRules[o].cssText&&(r+=`${t.cssRules[o].cssText}\r\n`)}catch(e){i({messages:["A stylesheet could not be accessed. This is likely due to the stylesheet having cross-origin imports, and many browsers block script access to cross-origin stylesheets. See https://github.com/MatthewHerbst/react-to-print/issues/429 for details. You may be able to load the sheet by both marking the stylesheet with the cross `crossorigin` attribute, and setting the `Access-Control-Allow-Origin` header on the server serving the stylesheet. Alternatively, host the stylesheet on your domain to avoid this issue entirely.",n,`Original error: ${a(e).message}`],level:"warning"})}e.setAttribute("id",`react-to-print-${o}`),x&&e.setAttribute("nonce",x),e.appendChild(N.createTextNode(r)),N.head.appendChild(e)}}else if(n.getAttribute("href"))if(n.hasAttribute("disabled"))i({messages:["`react-to-print` encountered a <link> tag with a `disabled` attribute and will ignore it. Note that the `disabled` attribute is deprecated, and some browsers ignore it. You should stop using it. https://developer.mozilla.org/en-US/docs/Web/HTML/Element/link#attr-disabled. The <link> is:",n],level:"warning"}),t(n);else{const e=N.createElement(n.tagName);for(let t=0,o=n.attributes.length;t<o;++t){const o=n.attributes[t];o&&e.setAttribute(o.nodeName,null!==(h=o.nodeValue)&&void 0!==h?h:"")}e.onload=()=>{t(e)},e.onerror=(o,n,r,s,i)=>{t(e,["Failed to load",e,"Error:",i])},x&&e.setAttribute("nonce",x),N.head.appendChild(e)}else i({messages:["`react-to-print` encountered a <link> tag with an empty `href` attribute. In addition to being invalid HTML, this can cause problems in many browsers, and so the <link> was not loaded. The <link> is:",n],level:"warning"}),t(n)}}}0===y&&c(e,n)}function f(e,t,o,n){e.onload=()=>{h(e,t,o,n)},document.body.appendChild(e)}function g(e){const{contentRef:t,fonts:o,ignoreGlobalStyles:n,onBeforePrint:r,onPrintError:d,preserveAfterPrint:u,suppressErrors:p}=e,h=(0,s.useCallback)((s=>{l(u,!0);const h=function({contentRef:e,optionalContent:t,suppressErrors:o}){return t&&(e&&i({level:"warning",messages:['"react-to-print" received a `contentRef` option and a optional-content param passed to its callback. The `contentRef` option will be ignored.']}),"function"==typeof t)?t():e?e.current:void i({messages:['"react-to-print" did not receive a `contentRef` option or a optional-content param pass to its callback.'],suppressErrors:o})}({contentRef:t,optionalContent:s,suppressErrors:p});if(!h)return void i({messages:["There is nothing to print"],suppressErrors:p});const g=h.cloneNode(!0),m=document.querySelectorAll("link[rel~='stylesheet'], link[as='style']"),b=g.querySelectorAll("img"),y=g.querySelectorAll("video"),v=o?o.length:0,w=(n?0:m.length)+b.length+y.length+v,E=[],A=[],T=function(){const e=document.createElement("iframe");return e.width=`${document.documentElement.clientWidth}px`,e.height=`${document.documentElement.clientHeight}px`,e.style.position="absolute",e.style.top=`-${document.documentElement.clientHeight+100}px`,e.style.left=`-${document.documentElement.clientWidth+100}px`,e.id="printWindow",e.srcdoc="<!DOCTYPE html>",e}(),x=(t,o)=>{E.includes(t)?i({level:"debug",messages:["Tried to mark a resource that has already been handled",t],suppressErrors:p}):(o?(i({messages:['"react-to-print" was unable to load a resource but will continue attempting to print the page',...o],suppressErrors:p}),A.push(t)):E.push(t),E.length+A.length===w&&c(T,e))},k={contentNode:h,clonedContentNode:g,clonedImgNodes:b,clonedVideoNodes:y,numResourcesToLoad:w,originalCanvasNodes:h.querySelectorAll("canvas")};r?r().then((()=>{f(T,x,k,e)})).catch((e=>{null==d||d("onBeforePrint",a(e))})):f(T,x,k,e)}),[e]);return h}return r}()}));
import { RefObject } from "react";
import type { Font } from "./font";
import { ContentNode } from "./ContentNode";
export interface UseReactToPrintOptions {
bodyClass?: string;
contentRef?: RefObject<Element | Text>;
contentRef?: RefObject<ContentNode>;
documentTitle?: string;

@@ -7,0 +8,0 @@ fonts?: Font[];

{
"name": "react-to-print",
"version": "3.0.3-beta-1",
"version": "3.0.3",
"description": "Print React components in the browser",

@@ -39,5 +39,5 @@ "main": "lib/index.js",

"devDependencies": {
"@eslint/js": "^9.16.0",
"@types/react": "^18.3.12",
"@types/react-dom": "^18.3.1",
"@eslint/js": "^9.17.0",
"@types/react": "^19.0.2",
"@types/react-dom": "^19.0.2",
"acorn": "^8.14.0",

@@ -47,10 +47,10 @@ "clean-webpack-plugin": "^4.0.0",

"css-loader": "^7.1.2",
"eslint": "^9.16.0",
"eslint": "^9.17.0",
"eslint-plugin-react": "^7.37.2",
"html-webpack-plugin": "^5.6.3",
"husky": "^9.1.7",
"lint-staged": "^15.2.10",
"react": "^18.3.1",
"react-dom": "^18.3.1",
"react-tabs": "^6.0.2",
"lint-staged": "^15.2.11",
"react": "^19.0.0",
"react-dom": "^19.0.0",
"react-tabs": "^6.1.0",
"style-loader": "^4.0.0",

@@ -60,7 +60,7 @@ "ts-loader": "^9.5.1",

"typescript": "^5.7.2",
"typescript-eslint": "^8.16.0",
"typescript-eslint": "^8.16.1",
"url-loader": "^4.1.1",
"webpack": "^5.96.1",
"webpack-cli": "^5.1.4",
"webpack-dev-server": "^5.1.0"
"webpack": "^5.97.1",
"webpack-cli": "^6.0.1",
"webpack-dev-server": "^5.2.0"
},

@@ -67,0 +67,0 @@ "lint-staged": {

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