fetch-css 5.0.1 → 5.0.2
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/README.md +12 -10
- package/dist/index.d.ts +2 -1
- package/dist/index.js +4 -4
- package/package.json +8 -8
package/README.md
CHANGED
|
@@ -1,20 +1,22 @@
|
|
|
1
1
|
# fetch-css
|
|
2
2
|
[](https://www.npmjs.org/package/fetch-css) [](https://www.npmjs.org/package/fetch-css) [](https://packagephobia.com/result?p=fetch-css)
|
|
3
|
+
|
|
3
4
|
> Extract CSS from websites and browser extensions
|
|
4
5
|
|
|
5
6
|
## Usage
|
|
6
7
|
|
|
7
|
-
```
|
|
8
|
-
|
|
8
|
+
```sh
|
|
9
|
+
pnpm add fetch-css
|
|
9
10
|
```
|
|
11
|
+
|
|
10
12
|
```js
|
|
11
13
|
import fetchCss from "fetch-css";
|
|
12
14
|
|
|
13
|
-
|
|
14
|
-
|
|
15
|
-
|
|
16
|
-
|
|
17
|
-
|
|
15
|
+
const [website, extension] = await fetchCss([
|
|
16
|
+
{url: "https://example.com"},
|
|
17
|
+
{crx: "hlepfoohegkhhmjieoechaddaejaokhf"}, // a Chrome extension
|
|
18
|
+
]);
|
|
19
|
+
console.log(website.css, extension.css);
|
|
18
20
|
```
|
|
19
21
|
|
|
20
22
|
## API
|
|
@@ -23,12 +25,12 @@ const [{css}] = await fetchCss([{crx: "hlepfoohegkhhmjieoechaddaejaokhf"}]);
|
|
|
23
25
|
- `sources`: *Array* Array of source objects
|
|
24
26
|
- `source`: *Object*
|
|
25
27
|
- `url`: *string* or *Array* An absolute URL pointing to either a website or directly to a CSS or JS file (to extract inlined CSS strings from)
|
|
26
|
-
- `fetchOpts`: *Object* Options passed to [fetch](https://github.com/
|
|
28
|
+
- `fetchOpts`: *Object* Options passed to [fetch](https://github.com/silverwind/fetch-enhanced#fetchurl-opts)
|
|
27
29
|
- `crx`: *string* A Chrome extension id
|
|
28
|
-
- `contentScriptsOnly`: *boolean* Whether to pull only content scripts from
|
|
30
|
+
- `contentScriptsOnly`: *boolean* Whether to pull only content scripts from an extension. Default: `false`
|
|
29
31
|
- `strict`: *boolean* Whether to throw an error if fetch fails. Default: `false`
|
|
30
32
|
|
|
31
|
-
Returns a `Promise` that resolves to a `sources` array with additional `css` properties present on each source.
|
|
33
|
+
Returns a `Promise` that resolves to a copy of the `sources` array with additional `css` properties present on each source. Sources with an array `url` are expanded into one source per URL.
|
|
32
34
|
|
|
33
35
|
## Related
|
|
34
36
|
|
package/dist/index.d.ts
CHANGED
|
@@ -22,7 +22,8 @@ export type Source = {
|
|
|
22
22
|
/**
|
|
23
23
|
* Extract CSS from websites and browser extensions.
|
|
24
24
|
*
|
|
25
|
-
* Returns the
|
|
25
|
+
* Returns a copy of the `sources` array with an additional `css` property present on each source.
|
|
26
|
+
* Sources with an array `url` are expanded into one source per URL.
|
|
26
27
|
*/
|
|
27
28
|
export default function fetchCss(sources: Array<Source>): Promise<Array<Source>>;
|
|
28
29
|
//#endregion
|
package/dist/index.js
CHANGED
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
import{parse as e}from"acorn";import t from"rfdc";import n from"postcss";import{parseFragment as r}from"parse5";import i from"unzipper";import a from"url-toolkit";import{createHash as o}from"node:crypto";import{fetch as s}from"undici";import c from"fetch-enhanced";function l(e,t,n,r){let i=0;return i+=e,i+=t<<8,i+=n<<16,i+=r<<24>>>0,i}function u(e,t,n){let r=``;for(let i=t;i<n;++i)r+=String.fromCharCode(e[i]);return r}function d(e){
|
|
2
|
-
`)):(
|
|
3
|
-
`),
|
|
4
|
-
`)}`))}return e}export{
|
|
1
|
+
import{parse as e}from"acorn";import t from"rfdc";import n from"postcss";import{parseFragment as r}from"parse5";import i from"unzipper";import a from"url-toolkit";import{createHash as o}from"node:crypto";import{fetch as s}from"undici";import c from"fetch-enhanced";function l(e,t,n,r){let i=0;return i+=e,i+=t<<8,i+=n<<16,i+=r<<24>>>0,i}function u(e,t,n){let r=``;for(let i=t;i<n;++i)r+=String.fromCharCode(e[i]);return r}function d(e){if(e[0]===80&&e[1]===75&&e[2]===3&&e[3]===4)throw Error(`Input is not a CRX file, but a ZIP file.`);if(e[0]!==67||e[1]!==114||e[2]!==50||e[3]!==52)throw p(e)?Error(`Input is not a CRX file, but possibly a ZIP file.`):Error(`Invalid header: Does not start with Cr24.`);if(e[4]!==2&&e[4]!==3||e[5]||e[6]||e[7])throw Error(`Unexpected crx format version number.`);let t;if(e[4]===2){let n=l(e[8],e[9],e[10],e[11]),r=l(e[12],e[13],e[14],e[15]);t=16+n+r}else t=12+l(e[8],e[9],e[10],e[11]),f(e,12,t);return e.slice(t)}function f(e,t,n){function r(){let n=e[t]&127;if(e[t++]<128||(n|=(e[t]&127)<<7,e[t++]<128)||(n|=(e[t]&127)<<14,e[t++]<128)||(n|=(e[t]&127)<<21,e[t++]<128))return n;if(n=(n|(e[t]&15)<<28)>>>0,e[t++]&128)throw Error(`proto: not a uint32`);return n}let i=[],a;for(;t<n;){let o=r(),s=r();if(o===80002){let n=r(),i=r();if(n!==10)throw Error(`proto: Unexpected key in signed_header_data: ${n}`);if(i!==16)throw Error(`proto: Unexpected signed_header_data length ${s}`);if(a)throw Error(`proto: Unexpected duplicate signed_header_data`);a=e.subarray(t,t+16),t+=i;continue}if(o!==18){if(o!==26)throw Error(`proto: Unexpected key: ${o}`);t+=s;continue}let c=t+s,l=r(),d=r();if(l===18){if(t+=d,t>=c)continue;l=r(),d=r()}if(l!==10)throw t+=d,Error(`proto: Unexpected key in AsymmetricKeyProof: ${l}`);if(t+d>n)throw Error(`proto: size of public_key field is too large`);i.push(u(e,t,t+d)),t=c}if(!i.length)throw Error(`proto: Did not find any public key`);if(!a)throw Error(`proto: Did not find crx_id`);let s=Buffer.from(a).toString(`hex`);for(let e of i)if(o(`sha256`).update(e,`latin1`).digest(`hex`).slice(0,32)===s)return btoa(e);throw Error(`proto: None of the public keys matched with crx_id`)}function p(e){for(let t=e.length-22,n=Math.max(0,t-65535);t>=n;--t)if(e[t]===80&&e[t+1]===75&&e[t+2]===5&&e[t+3]===6)return!0;return!1}const m=c(s,{undici:!0}),h=t();async function g(e,t){try{return await m(e,t)}catch(t){throw t.message=`${t.message} (${e})`,t}}function _(e,t,n){if(e.status===200)return;let r=`Failed to fetch ${t}: ${e.status} ${e.statusText}`;if(n)throw Error(r);console.warn(`(fetch-css) Warning: ${r}`)}function v(e){return(e.match(/<link.+?>/gis)||[]).map(e=>{let t={};for(let n of r(e).childNodes[0].attrs)t[n.name]=n.value;return t.href&&t.rel===`stylesheet`||t.href&&/\.css$/i.test(t.href.replace(/\?.+/,`undefined`))?t.href:null}).filter(Boolean)}function y(e){return Array.from(e.matchAll(/<style.*?>(.*?)<\/style>/gis),e=>e[1].trim()).filter(Boolean)}function b(e){try{let{nodes:t}=n.parse(e);return t.length>=1&&t.every(e=>e.type===`rule`)}catch{return!1}}function x(t,n=`script`){let r=``;try{e(t,{ecmaVersion:`latest`,sourceType:n,onToken:e=>{if(e.type.label===`string`){let t=e.value.trim().replace(/\n/g,``).replace(/^\);\}/,``);t.length>25&&b(t)&&(r+=`${t}\n`)}}})}catch(e){if(n===`module`||!(e instanceof SyntaxError))throw e;try{return x(t,`module`)}catch{throw e}}return r.trim()}async function S({crx:e,contentScriptsOnly:t,strict:n}){let r=`https://clients2.google.com/service/update2/crx`;r+=`?response=redirect`,r+=`&os=linux`,r+=`&arch=x86-64`,r+=`&os_arch=x86-64`,r+=`&acceptformat=crx3`,r+=`&prod=chromiumcrx`,r+=`&prodchannel=unknown`,r+=`&prodversion=9999.0.9999.0`,r+=`&x=id%3D${e}`,r+=`%26uc`;let a=await g(r);_(a,r,n);let o=Buffer.from(d(Buffer.from(await a.arrayBuffer()))),s={};for(let e of(await i.Open.buffer(o)).files)s[e.path]=e;if(!s[`manifest.json`])throw Error(`manifest.json not found in extension ${e}`);let c=[],l=[];if(!t)for(let e of Object.keys(s))e.endsWith(`.css`)&&c.push(e),e.endsWith(`.js`)&&l.push(e);let u=JSON.parse(String(await s[`manifest.json`].buffer()));for(let{css:e,js:t}of u.content_scripts||[])Array.isArray(e)&&c.push(...e),Array.isArray(t)&&l.push(...t);let f=``;for(let e of new Set(c))f+=`${String(await s[e.replace(/^\//,``)].buffer())}\n`;for(let e of new Set(l))f+=x(String(await s[e.replace(/^\//,``)].buffer()));return f}async function C(e){e=h(e).flatMap(e=>`url`in e&&Array.isArray(e.url)?e.url.map(t=>({...e,url:t})):[e]);let t=await Promise.all(e.map(e=>{if(!e.url)return Promise.resolve(null);let{pathname:t}=new URL(e.url);return t.endsWith(`.css`)||t.endsWith(`.js`)?Promise.resolve(null):g(e.url,e.fetchOpts)}));for(let[n,r]of t.entries()){let t=e[n];if(t.urls=[],t.styleTags=[],r){_(r,t.url,t.strict);let e=await r.text();t.urls=v(e).map(e=>a.buildAbsoluteURL(r.url,e)),t.styleTags=y(e)}else t.url&&(t.urls=[t.url])}let n=await Promise.all(e.map(e=>e.url?Promise.all(e.urls.map(async t=>(await g(t,t===e.url?e.fetchOpts:void 0)).text())):Promise.resolve(null)));for(let[t,r]of n.entries()){let n=e[t];n.crx?n.css=await S(n):new URL(n.url).pathname.endsWith(`.js`)?n.css=x(r.join(`
|
|
2
|
+
`)):(n.css=r.join(`
|
|
3
|
+
`),n.styleTags.length&&(n.css+=`\n${n.styleTags.join(`
|
|
4
|
+
`)}`))}return e}export{C as default};
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "fetch-css",
|
|
3
|
-
"version": "5.0.
|
|
3
|
+
"version": "5.0.2",
|
|
4
4
|
"description": "Extract CSS from websites and browser extensions",
|
|
5
5
|
"author": "silverwind",
|
|
6
6
|
"repository": {
|
|
@@ -38,17 +38,17 @@
|
|
|
38
38
|
"url-toolkit": "2.2.5"
|
|
39
39
|
},
|
|
40
40
|
"devDependencies": {
|
|
41
|
-
"@types/node": "26.6.
|
|
41
|
+
"@types/node": "26.6.3",
|
|
42
42
|
"@types/unzipper": "0.10.11",
|
|
43
43
|
"@typescript/native-preview": "7.0.0-dev.20260707.2",
|
|
44
44
|
"eslint": "10.11.0",
|
|
45
|
-
"eslint-config-silverwind": "151.0.
|
|
45
|
+
"eslint-config-silverwind": "151.0.1",
|
|
46
46
|
"tsdown": "0.23.0",
|
|
47
|
-
"tsdown-config-silverwind": "4.1.
|
|
47
|
+
"tsdown-config-silverwind": "4.1.2",
|
|
48
48
|
"typescript": "6.0.3",
|
|
49
|
-
"typescript-config-silverwind": "21.0.
|
|
50
|
-
"updates": "19.0.
|
|
51
|
-
"updates-config-silverwind": "4.0.
|
|
52
|
-
"versions": "15.5.
|
|
49
|
+
"typescript-config-silverwind": "21.0.1",
|
|
50
|
+
"updates": "19.0.2",
|
|
51
|
+
"updates-config-silverwind": "4.0.7",
|
|
52
|
+
"versions": "15.5.1"
|
|
53
53
|
}
|
|
54
54
|
}
|