@cloro-dev/response-parser 0.3.1 → 0.4.1

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 CHANGED
@@ -1,6 +1,6 @@
1
1
  # @cloro-dev/response-parser
2
2
 
3
- A powerful TypeScript library for parsing AI model responses from ChatGPT, Gemini, Perplexity, Copilot, and Google AI Overview/Mode.
3
+ A powerful TypeScript library for parsing AI model responses from ChatGPT, Gemini, Perplexity, Copilot, Grok, and Google AI Overview/Mode.
4
4
 
5
5
  > **Framework-Agnostic**: This library returns HTML strings that can be rendered in any framework (React, Vue, Svelte, vanilla JS, etc.).
6
6
 
@@ -111,7 +111,10 @@ Parse an AI response with auto-detected provider.
111
111
  - `removeLinks`: `boolean` - Remove all hyperlinks from HTML (default: `false`)
112
112
  - `removeHeader`: `boolean` - Remove navigation bar/header (default: `false`, Perplexity, Gemini, Copilot, AI Overview & AI Mode)
113
113
  - `removeFooter`: `boolean` - Remove follow-up input box/footer (default: `false`, ChatGPT, Perplexity, Gemini, Copilot, AI Overview & AI Mode)
114
- - `removeSidebar`: `boolean` - Remove sidebar (default: `false`, ChatGPT, Gemini & Copilot)
114
+ - `removeSidebar`: `boolean` - Remove sidebar (default: `false`, ChatGPT, Gemini, Copilot & AI Mode)
115
+ - `removeSources`: `boolean` - Remove sources/references panel (default: `false`, Gemini, Perplexity, Copilot & Grok)
116
+
117
+ > **Note:** Cookie/privacy banners are automatically removed for AI Mode, Copilot, Grok, and Perplexity — no option needed.
115
118
 
116
119
  **Returns:** `ParsedResponse | null`
117
120
 
@@ -140,22 +143,22 @@ type AIProvider =
140
143
  | 'GEMINI'
141
144
  | 'PERPLEXITY'
142
145
  | 'COPILOT'
143
- | 'AI_OVERVIEW'
144
- | 'AI_MODE'
146
+ | 'AIOVERVIEW'
147
+ | 'AIMODE'
145
148
  | 'GROK';
146
149
  ```
147
150
 
148
151
  ## Supported Providers
149
152
 
150
- | Provider | Status | Features |
151
- | ----------- | ------ | ---------------------------------------- |
152
- | ChatGPT | ✅ | Sidebar hiding |
153
- | Gemini | ✅ | Navbar removal |
154
- | Perplexity | ✅ | Link removal, UI element removal |
155
- | Copilot | ✅ | UI element hiding |
156
- | AI Overview | ✅ | WIZ data extraction |
157
- | AI Mode | ✅ | Google UI hiding |
158
- | Grok | ✅ | UI element removal |
153
+ | Provider | Status | Features |
154
+ | ----------- | ------ | ----------------------------------------------------------- |
155
+ | ChatGPT | ✅ | Sidebar, header, footer removal |
156
+ | Gemini | ✅ | Sidebar, header, footer, sources removal |
157
+ | Perplexity | ✅ | Header, footer, sources removal, auto cookie banner hiding |
158
+ | Copilot | ✅ | Sidebar, header, footer, sources removal, auto cookie banner hiding |
159
+ | AI Overview | ✅ | Header, footer removal, WIZ data extraction |
160
+ | AI Mode | ✅ | Sidebar, header, footer removal, auto cookie banner hiding |
161
+ | Grok | ✅ | Sources removal, auto cookie banner hiding |
159
162
 
160
163
  ## Common Use Cases
161
164
 
@@ -173,9 +176,10 @@ const parsed = parseAiResponse(response, {
173
176
 
174
177
  ```typescript
175
178
  const parsed = parseAiResponse(response, {
176
- removeHeader: true, // Remove top navigation bar
177
- removeFooter: true, // Remove follow-up input box
178
- removeLinks: true, // Remove all hyperlinks
179
+ removeHeader: true, // Remove top navigation bar
180
+ removeFooter: true, // Remove follow-up input box
181
+ removeLinks: true, // Remove all hyperlinks
182
+ removeSources: true, // Remove sources/references panel
179
183
  });
180
184
  ```
181
185
 
@@ -232,6 +236,17 @@ The core parsing logic is identical - you just need to handle the HTML rendering
232
236
 
233
237
  ## What's Changed
234
238
 
239
+ ### v0.4.0
240
+
241
+ - ✅ **Added** `removeSources` option for Gemini, Perplexity, Copilot, and Grok
242
+ - ✅ **Added** automatic cookie/privacy banner removal for Perplexity and Grok
243
+ - ✅ **Fixed** Perplexity collapsed answer container (JS animation height workaround)
244
+
245
+ ### v0.3.0
246
+
247
+ - ✅ **Added** Grok provider support
248
+ - ✅ **Simplified** codebase and removed colour inversion
249
+
235
250
  ### v0.2.0
236
251
 
237
252
  - ✅ **Removed** React components and hooks (now framework-agnostic)
@@ -1 +1 @@
1
- {"version":3,"file":"detector.d.ts","sourceRoot":"","sources":["../../src/core/detector.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,UAAU,EAAE,gBAAgB,EAAE,MAAM,SAAS,CAAC;AAEvD,qBAAa,gBAAgB;IAC3B,OAAO,CAAC,MAAM,CAAC,QAAQ,CAAC,iBAAiB,CAiEvC;IAEF;;OAEG;IACH,MAAM,CAAC,MAAM,CAAC,QAAQ,EAAE,GAAG,GAAG,gBAAgB,GAAG,IAAI;IA4CrD;;OAEG;IACH,MAAM,CAAC,eAAe,CAAC,QAAQ,EAAE,GAAG,GAAG,gBAAgB,EAAE;IA2BzD;;OAEG;IACH,MAAM,CAAC,QAAQ,CAAC,QAAQ,EAAE,GAAG,EAAE,QAAQ,EAAE,UAAU,GAAG,OAAO;CAI9D"}
1
+ {"version":3,"file":"detector.d.ts","sourceRoot":"","sources":["../../src/core/detector.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,UAAU,EAAE,gBAAgB,EAAE,MAAM,SAAS,CAAC;AAEvD,qBAAa,gBAAgB;IAC3B,OAAO,CAAC,MAAM,CAAC,QAAQ,CAAC,iBAAiB,CAkFvC;IAEF;;OAEG;IACH,MAAM,CAAC,MAAM,CAAC,QAAQ,EAAE,GAAG,GAAG,gBAAgB,GAAG,IAAI;IA4CrD;;OAEG;IACH,MAAM,CAAC,eAAe,CAAC,QAAQ,EAAE,GAAG,GAAG,gBAAgB,EAAE;IA2BzD;;OAEG;IACH,MAAM,CAAC,QAAQ,CAAC,QAAQ,EAAE,GAAG,EAAE,QAAQ,EAAE,UAAU,GAAG,OAAO;CAI9D"}
@@ -11,6 +11,7 @@ export interface ParseOptions {
11
11
  removeHeader?: boolean;
12
12
  removeFooter?: boolean;
13
13
  removeSidebar?: boolean;
14
+ removeSources?: boolean;
14
15
  }
15
16
  export interface ProviderConfig {
16
17
  name: AIProvider;
@@ -40,6 +41,7 @@ export interface ProviderMetadata {
40
41
  sidebarRemoved?: boolean;
41
42
  linksRemoved?: boolean;
42
43
  cookieBannerRemoved?: boolean;
44
+ sourcesRemoved?: boolean;
43
45
  detectionConfidence?: number;
44
46
  }
45
47
  /**
@@ -1 +1 @@
1
- {"version":3,"file":"types.d.ts","sourceRoot":"","sources":["../../src/core/types.ts"],"names":[],"mappings":"AAAA,MAAM,MAAM,UAAU,GAClB,SAAS,GACT,QAAQ,GACR,YAAY,GACZ,SAAS,GACT,YAAY,GACZ,QAAQ,GACR,MAAM,CAAC;AAEX,MAAM,WAAW,cAAc;IAC7B,QAAQ,EAAE,UAAU,CAAC;IACrB,IAAI,EAAE,MAAM,CAAC;IACb,IAAI,CAAC,EAAE,MAAM,CAAC;IACd,OAAO,CAAC,EAAE,GAAG,EAAE,CAAC;IAChB,QAAQ,CAAC,EAAE,MAAM,CAAC,MAAM,EAAE,GAAG,CAAC,CAAC;CAChC;AAED,MAAM,WAAW,YAAY;IAC3B,WAAW,CAAC,EAAE,OAAO,CAAC;IACtB,YAAY,CAAC,EAAE,OAAO,CAAC;IACvB,YAAY,CAAC,EAAE,OAAO,CAAC;IACvB,aAAa,CAAC,EAAE,OAAO,CAAC;CACzB;AAED,MAAM,WAAW,cAAc;IAC7B,IAAI,EAAE,UAAU,CAAC;IACjB,OAAO,EAAE,MAAM,CAAC;CACjB;AAED,MAAM,WAAW,gBAAgB;IAC/B,QAAQ,EAAE,UAAU,CAAC;IACrB,UAAU,EAAE,MAAM,CAAC;CACpB;AAED,MAAM,WAAW,YAAY;IAC3B,SAAS,CAAC,EAAE,MAAM,CAAC;IACnB,MAAM,CAAC,EAAE,OAAO,CAAC;IACjB,OAAO,CAAC,EAAE,MAAM,CAAC;CAClB;AAED,MAAM,MAAM,iBAAiB,GAAG;IAC9B,IAAI,CAAC,EAAE,MAAM,CAAC;IACd,IAAI,CAAC,EAAE,MAAM,CAAC;IACd,OAAO,CAAC,EAAE,GAAG,EAAE,CAAC;CACjB,CAAC;AAEF;;GAEG;AACH,MAAM,WAAW,gBAAgB;IAC/B,cAAc,CAAC,EAAE,OAAO,CAAC;IACzB,aAAa,CAAC,EAAE,OAAO,CAAC;IACxB,aAAa,CAAC,EAAE,OAAO,CAAC;IACxB,cAAc,CAAC,EAAE,OAAO,CAAC;IACzB,YAAY,CAAC,EAAE,OAAO,CAAC;IACvB,mBAAmB,CAAC,EAAE,OAAO,CAAC;IAC9B,mBAAmB,CAAC,EAAE,MAAM,CAAC;CAC9B;AAED;;GAEG;AACH,wBAAgB,oBAAoB,CAAC,QAAQ,EAAE,GAAG,GAAG,iBAAiB,CAgCrE"}
1
+ {"version":3,"file":"types.d.ts","sourceRoot":"","sources":["../../src/core/types.ts"],"names":[],"mappings":"AAAA,MAAM,MAAM,UAAU,GAClB,SAAS,GACT,QAAQ,GACR,YAAY,GACZ,SAAS,GACT,YAAY,GACZ,QAAQ,GACR,MAAM,CAAC;AAEX,MAAM,WAAW,cAAc;IAC7B,QAAQ,EAAE,UAAU,CAAC;IACrB,IAAI,EAAE,MAAM,CAAC;IACb,IAAI,CAAC,EAAE,MAAM,CAAC;IACd,OAAO,CAAC,EAAE,GAAG,EAAE,CAAC;IAChB,QAAQ,CAAC,EAAE,MAAM,CAAC,MAAM,EAAE,GAAG,CAAC,CAAC;CAChC;AAED,MAAM,WAAW,YAAY;IAC3B,WAAW,CAAC,EAAE,OAAO,CAAC;IACtB,YAAY,CAAC,EAAE,OAAO,CAAC;IACvB,YAAY,CAAC,EAAE,OAAO,CAAC;IACvB,aAAa,CAAC,EAAE,OAAO,CAAC;IACxB,aAAa,CAAC,EAAE,OAAO,CAAC;CACzB;AAED,MAAM,WAAW,cAAc;IAC7B,IAAI,EAAE,UAAU,CAAC;IACjB,OAAO,EAAE,MAAM,CAAC;CACjB;AAED,MAAM,WAAW,gBAAgB;IAC/B,QAAQ,EAAE,UAAU,CAAC;IACrB,UAAU,EAAE,MAAM,CAAC;CACpB;AAED,MAAM,WAAW,YAAY;IAC3B,SAAS,CAAC,EAAE,MAAM,CAAC;IACnB,MAAM,CAAC,EAAE,OAAO,CAAC;IACjB,OAAO,CAAC,EAAE,MAAM,CAAC;CAClB;AAED,MAAM,MAAM,iBAAiB,GAAG;IAC9B,IAAI,CAAC,EAAE,MAAM,CAAC;IACd,IAAI,CAAC,EAAE,MAAM,CAAC;IACd,OAAO,CAAC,EAAE,GAAG,EAAE,CAAC;CACjB,CAAC;AAEF;;GAEG;AACH,MAAM,WAAW,gBAAgB;IAC/B,cAAc,CAAC,EAAE,OAAO,CAAC;IACzB,aAAa,CAAC,EAAE,OAAO,CAAC;IACxB,aAAa,CAAC,EAAE,OAAO,CAAC;IACxB,cAAc,CAAC,EAAE,OAAO,CAAC;IACzB,YAAY,CAAC,EAAE,OAAO,CAAC;IACvB,mBAAmB,CAAC,EAAE,OAAO,CAAC;IAC9B,cAAc,CAAC,EAAE,OAAO,CAAC;IACzB,mBAAmB,CAAC,EAAE,MAAM,CAAC;CAC9B;AAED;;GAEG;AACH,wBAAgB,oBAAoB,CAAC,QAAQ,EAAE,GAAG,GAAG,iBAAiB,CAgCrE"}
package/dist/index.d.ts CHANGED
@@ -11,6 +11,7 @@ interface ParseOptions {
11
11
  removeHeader?: boolean;
12
12
  removeFooter?: boolean;
13
13
  removeSidebar?: boolean;
14
+ removeSources?: boolean;
14
15
  }
15
16
  interface ProviderConfig {
16
17
  name: AIProvider;
@@ -40,6 +41,7 @@ interface ProviderMetadata {
40
41
  sidebarRemoved?: boolean;
41
42
  linksRemoved?: boolean;
42
43
  cookieBannerRemoved?: boolean;
44
+ sourcesRemoved?: boolean;
43
45
  detectionConfidence?: number;
44
46
  }
45
47
 
@@ -175,6 +177,10 @@ declare class GeminiProvider extends BaseProvider {
175
177
  * Remove Gemini sidebar from HTML
176
178
  */
177
179
  removeSidebar(html: string): string;
180
+ /**
181
+ * Remove Gemini sources panel from HTML
182
+ */
183
+ removeSources(html: string): string;
178
184
  parse(response: any, options?: ParseOptions): ParsedResponse;
179
185
  }
180
186
 
@@ -190,6 +196,10 @@ declare class PerplexityProvider extends BaseProvider {
190
196
  * Remove Perplexity footer/followup input from HTML
191
197
  */
192
198
  removeFooter(html: string): string;
199
+ /**
200
+ * Remove Perplexity sources panel from HTML
201
+ */
202
+ removeSources(html: string): string;
193
203
  parse(response: any, options?: ParseOptions): ParsedResponse;
194
204
  }
195
205
 
@@ -209,6 +219,10 @@ declare class CopilotProvider extends BaseProvider {
209
219
  * Remove Copilot cookie banner from HTML
210
220
  */
211
221
  removeCookieBanner(html: string): string;
222
+ /**
223
+ * Remove Copilot sources/references panel from HTML
224
+ */
225
+ removeSources(html: string): string;
212
226
  /**
213
227
  * Remove Copilot sidebar from HTML
214
228
  */
package/dist/index.esm.js CHANGED
@@ -1,2 +1,2 @@
1
- function e(e){let t="",r="",i=e;return e.result&&(i=e.result),"string"==typeof i?i.trim().startsWith("<")&&i.includes(">")?t=i:r=i:"object"==typeof i&&null!==i&&(i.html?t=i.html:i.content?i.content.trim().startsWith("<")?t=i.content:r=i.content:i.text&&(r=i.text)),{html:t,text:r}}class t{static detect(e){const t={CHATGPT:0,GEMINI:0,PERPLEXITY:0,COPILOT:0,AIOVERVIEW:0,AIMODE:0,GROK:0};for(const[r,i]of Object.entries(this.PROVIDER_PATTERNS))for(const o of i)try{o(e)&&t[r]++}catch(e){}let r=0,i=null;for(const[e,o]of Object.entries(t))o>r&&(r=o,i=e);return 0===r?null:{provider:i,confidence:r/Object.values(t).reduce((e,t)=>Math.max(e,t),1)}}static getAllProviders(e){const t=[];for(const[r,i]of Object.entries(this.PROVIDER_PATTERNS)){let o=0;for(const t of i)try{t(e)&&o++}catch(e){}o>0&&t.push({provider:r,confidence:o/i.length})}return t.sort((e,t)=>t.confidence-e.confidence)}static validate(e,t){const r=this.detect(e);return(null==r?void 0:r.provider)===t&&r.confidence>.5}}t.PROVIDER_PATTERNS={CHATGPT:[e=>{var t;const r=(null===(t=null==e?void 0:e.result)||void 0===t?void 0:t.html)||(null==e?void 0:e.html)||"";return r.includes("bg-token-bg-primary")||r.includes("text-token-text-secondary")},e=>{var t;const r=(null===(t=null==e?void 0:e.result)||void 0===t?void 0:t.html)||(null==e?void 0:e.html)||"";return r.includes("chatgpt.com")||r.includes("openai.com")}],GEMINI:[e=>{var t;const r=(null===(t=null==e?void 0:e.result)||void 0===t?void 0:t.html)||(null==e?void 0:e.html)||"";return r.includes("bard-sidenav")||r.includes("mat-sidenav")},e=>{var t;const r=(null===(t=null==e?void 0:e.result)||void 0===t?void 0:t.html)||(null==e?void 0:e.html)||"";return r.includes("gemini.google.com")||r.includes("gem-sys-color")}],PERPLEXITY:[e=>{var t;const r=(null===(t=null==e?void 0:e.result)||void 0===t?void 0:t.html)||(null==e?void 0:e.html)||"";return r.includes("perplexity.ai")||r.includes("prose")}],COPILOT:[e=>{var t;const r=(null===(t=null==e?void 0:e.result)||void 0===t?void 0:t.html)||(null==e?void 0:e.html)||"";return r.includes("copilot.microsoft.com")||r.includes('data-testid="sidebar-container"')}],AIOVERVIEW:[e=>{var t,r,i,o;if(null===(r=null===(t=null==e?void 0:e.result)||void 0===t?void 0:t.aioverview)||void 0===r?void 0:r.text)return!0;if(null===(i=null==e?void 0:e.aioverview)||void 0===i?void 0:i.text)return!0;const n=(null===(o=null==e?void 0:e.result)||void 0===o?void 0:o.html)||(null==e?void 0:e.html)||"";return n.includes("WIZ_global_data")||n.includes("DnVkpd")}],AIMODE:[e=>{var t;const r=(null===(t=null==e?void 0:e.result)||void 0===t?void 0:t.html)||(null==e?void 0:e.html)||"";return r.includes("DZ13He")||r.includes("wYq63b")||r.includes("AI Mode")}],GROK:[e=>{var t;const r=(null===(t=null==e?void 0:e.result)||void 0===t?void 0:t.html)||(null==e?void 0:e.html)||"";return r.includes("grok.com")||r.includes("x.ai")}]};class r{extractContentCommon(t,r=!1){var i;const o=e(t);if(r){let e=[];const r=t.result||t;return"object"==typeof r&&null!==r&&((null===(i=r.aioverview)||void 0===i?void 0:i.sources)?e=r.aioverview.sources:r.sources&&(e=r.sources)),{...o,sources:e}}return o}injectStyles(e,t){let r=e;(null==t?void 0:t.baseUrl)&&!e.includes("<base ")&&(r=r.includes("<head>")?r.replace("<head>",`<head><base href="${t.baseUrl}">`):r.replace(/(<html[^>]*>)/i,`$1<head><base href="${t.baseUrl}"></head>`));const i=(null==t?void 0:t.customCSS)||"";return i&&r.includes("<head>")?r=r.replace("<head>",`<head><style>${i}</style>`):i&&(r=r.replace(/(<html[^>]*>)/i,`$1<head><style>${i}</style></head>`)),r}sanitizeHtml(e){let t=e.replace(/<script\b[^>]*>[\s\S]*?<\/script>/gim,"");return t=t.replace(/<noscript[\s\S]*?<\/noscript>/gi,""),t}isFullDocument(e){return/^\s*(<html|<!DOCTYPE)/i.test(e)}removeLinks(e){return e.replace(/<a\b[^>]*>([\s\S]*?)<\/a>/gim,"$1")}wrapFragment(e){return`<!DOCTYPE html>\n<html>\n<head>\n <meta charset="utf-8">\n <meta http-equiv="Content-Security-Policy" content="default-src 'none'; script-src 'none'; style-src 'unsafe-inline';">\n <style>\n body {\n margin: 0;\n padding: 16px;\n font-family: system-ui, -apple-system, sans-serif;\n white-space: pre-wrap;\n word-wrap: break-word;\n }\n img { max-width: 100%; height: auto; }\n body {\n pointer-events: none;\n user-select: none;\n }\n </style>\n</head>\n<body>\n ${e}\n</body>\n</html>`}}class i extends r{constructor(){super(...arguments),this.name="CHATGPT",this.baseUrl="https://chatgpt.com"}extractContent(e){return this.extractContentCommon(e)}removeLinks(e){return e.replace(/<a\b([^>]*)>/gi,(e,t)=>{const r=t.replace(/\s+href\s*=\s*["'][^"']*["']/gi,"").replace(/\s+alt\s*=\s*["'][^"']*["']/gi,"").replace(/\s+rel\s*=\s*["'][^"']*["']/gi,"").replace(/\s+target\s*=\s*["'][^"']*["']/gi,"").trim();return`<span${r?" "+r:""}>`}).replace(/<\/a>/gi,"</span>")}removeHeader(e){let t=e;return t=t.replace(/<header[^>]*id="page-header"[^>]*>.*?<\/header>/gis,""),t}removeSidebar(e){let t=e;return t=t.replace(/<nav[^>]*>.*?<\/nav>/gis,""),t=t.replace(/<div[^>]*class="[^"]*sidebar[^"]*"[^>]*>.*?<\/div>/gis,""),t}removeFooter(e){let t=e;return t=t.replace(/<div[^>]*id="thread-bottom-container"[^>]*>.*?<\/div><\/div><\/div>/gis,""),t=t.replace(/<div[^>]*id="thread-bottom"[^>]*>.*?<\/div><\/div><\/div><\/div><\/div>/gis,""),t=t.replace(/<div[^>]*class="[^"]*\[grid-area:leading\][^"]*"[^>]*>.*?<\/div><\/div><\/div>/gis,""),t=t.replace(/<div[^>]*class="[^"]*\[grid-area:footer\][^"]*"[^>]*>.*?<\/div><\/div><\/div><\/div><\/div>/gis,""),t=t.replace(/<div[^>]*class="[^"]*\[grid-area:trailing\][^"]*"[^>]*>.*?<\/div><\/div><\/div>/gis,""),t=t.replace(/<div[^>]*\[view-transition-name:var\(--vt-disclaimer\)\][^>]*>.*?<\/div><\/div>/gis,""),t}parse(e,t){var r;const{html:i,text:o}=this.extractContent(e);if(!i)throw new Error("No HTML content found in ChatGPT response");let n=i;const s=null!==(r=null==t?void 0:t.removeFooter)&&void 0!==r&&r;return n=this.sanitizeHtml(n),(null==t?void 0:t.removeHeader)&&(n=this.removeHeader(n)),(null==t?void 0:t.removeSidebar)&&(n=this.removeSidebar(n)),s&&(n=this.removeFooter(n)),(null==t?void 0:t.removeLinks)&&(n=this.removeLinks(n)),n=this.injectStyles(n,{baseUrl:this.baseUrl,customCSS:""}),{provider:this.name,html:n,text:o,metadata:{isFullDocument:this.isFullDocument(n),headerRemoved:(null==t?void 0:t.removeHeader)||!1,sidebarRemoved:(null==t?void 0:t.removeSidebar)||!1,footerRemoved:s,linksRemoved:(null==t?void 0:t.removeLinks)||!1}}}}class o extends r{constructor(){super(...arguments),this.name="GEMINI",this.baseUrl="https://gemini.google.com"}extractContent(e){return this.extractContentCommon(e,!0)}removeHeader(e){let t=e;return t=t.replace(/<div[^>]*class="[^"]*boqOnegoogleliteOgbOneGoogleBar[^"]*"[^>]*>.*?<\/div><\/div><\/div><\/div>/gis,""),t=t.replace(/<div[^>]*class="[^"]*side-nav-menu-button[^"]*"[^>]*>.*?<\/div>/gis,""),t=t.replace(/<top-bar-actions[^>]*>.*?<\/top-bar-actions>/gis,""),t=t.replace(/<div[^>]*class="[^"]*desktop-ogb-buffer[^"]*"[^>]*><\/div>/gis,""),t}removeFooter(e){return e.replace(/<input-container[^>]*>.*?<\/input-container>/gis,"")}removeSidebar(e){return e.replace(/<bard-sidenav[^>]*>.*?<\/bard-sidenav>/gis,"")}parse(e,t){var r,i;const{html:o,text:n,sources:s}=this.extractContent(e);if(!o)throw new Error("No HTML content found in Gemini response");let l=o;const d=null!==(r=null==t?void 0:t.removeHeader)&&void 0!==r&&r,a=null!==(i=null==t?void 0:t.removeFooter)&&void 0!==i&&i;return l=this.sanitizeHtml(l),d&&(l=this.removeHeader(l)),a&&(l=this.removeFooter(l)),(null==t?void 0:t.removeSidebar)&&(l=this.removeSidebar(l)),(null==t?void 0:t.removeLinks)&&(l=this.removeLinks(l)),l=this.injectStyles(l,{baseUrl:this.baseUrl,customCSS:""}),{provider:this.name,html:l,text:n,sources:s,metadata:{isFullDocument:this.isFullDocument(l),headerRemoved:d,footerRemoved:a,sidebarRemoved:(null==t?void 0:t.removeSidebar)||!1,linksRemoved:(null==t?void 0:t.removeLinks)||!1}}}}class n extends r{constructor(){super(...arguments),this.name="PERPLEXITY",this.baseUrl="https://www.perplexity.ai"}extractContent(e){return this.extractContentCommon(e)}removeHeader(e){return e.replace(/<div[^>]*class="[^"]*@container\/header[^"]*"[^>]*>.*?<div[^>]*class="[^"]*absolute bottom-0 inset-x-0 border-b[^"]*"[^>]*><\/div>/gis,"")}removeFooter(e){let t=e;return t=t.replace(/<div[^>]*class="[^"]*erp-sidecar:fixed erp-sidecar:w-full bottom-safeAreaInsetBottom p-md pointer-events-none z-10 absolute border-subtlest ring-subtlest divide-subtlest bg-transparent[^"]*"[^>]*>[\s\S]*?(?=<div[^>]*class="[^"]*fixed inset-y-0 right-0[^"]*")/gis,""),t}parse(e,t){var r,i;const{html:o,text:n}=this.extractContent(e);if(!o)throw new Error("No HTML content found in Perplexity response");let s=o;const l=null!==(r=null==t?void 0:t.removeHeader)&&void 0!==r&&r,d=null!==(i=null==t?void 0:t.removeFooter)&&void 0!==i&&i;return s=this.sanitizeHtml(s),l&&(s=this.removeHeader(s)),d&&(s=this.removeFooter(s)),(null==t?void 0:t.removeLinks)&&(s=this.removeLinks(s)),s=this.injectStyles(s,{baseUrl:this.baseUrl,customCSS:""}),{provider:this.name,html:s,text:n,metadata:{isFullDocument:this.isFullDocument(s),linksRemoved:(null==t?void 0:t.removeLinks)||!1,headerRemoved:l,footerRemoved:d}}}}class s extends r{constructor(){super(...arguments),this.name="COPILOT",this.baseUrl="https://copilot.microsoft.com"}extractContent(e){return this.extractContentCommon(e)}removeHeader(e){let t=e;return t=t.replace(/<div[^>]*class="[^"]*relative shrink-0 min-h-14[^"]*"[^>]*data-testid="backstage-chats"[^>]*>.*?<\/div>/gis,""),t=t.replace(/<div[^>]*class="[^"]*flex items-center px-6 mx-auto w-full max-w-chat[^"]*"[^>]*>.*?<span[^>]*data-testid="date-divider"[^>]*>.*?<\/span>.*?<div[^>]*class="[^"]*border-t-\[1px\][^"]*"[^>]*>.*?<\/div>.*?<\/div>/gis,""),t=t.replace(/<div[^>]*class="[^"]*absolute flex end-6 origin-top-right flex-col items-end[^"]*"[^>]*data-testid="settings-wrapper"[^>]*>.*?<\/div><\/div>/gis,""),t}removeFooter(e){let t=e;return t=t.replace(/<div[^>]*class="[^"]*absolute bottom-0 w-full[^"]*"[^>]*>.*?<\/div><\/div><\/div><\/div><\/div><\/div><\/div><\/div><\/div><\/div><\/div><\/div>/gis,""),t=t.replace(/<div[^>]*class="[^"]*mt-\[var\(--composer-container-height\)\][^"]*"[^>]*><\/div>/gis,""),t=t.replace(/<div[^>]*class="[^"]*pointer-events-none absolute flex justify-center z-20 inset-x-0 bottom-\[calc\(var\(--composer-container-height\)\+1rem\)\][^"]*"[^>]*>.*?<button[^>]*data-testid="scroll-to-bottom-button"[^>]*>.*?<\/button><\/div>/gis,""),t}removeCookieBanner(e){let t=e;return t=t.replace(/<div[^>]*id="cookie-banner"[^>]*>.*?<\/div>.*?<\/div>.*?<\/div>.*?<\/div>/gis,""),t=t.replace(/<div[^>]*class="[^"]*max-w-cookie-banner[^"]*"[^>]*>.*?<\/div>.*?<\/div>.*?<\/div>.*?<\/div>/gis,""),t}removeSidebar(e){let t=e;return t=t.replace(/<div[^>]*class="[^"]*absolute h-full w-0 will-change-auto max-md:bg-sidebar-light[^"]*"[^>]*style="[^"]*"[^>]*>.*?<main/gis,"<main"),t}parse(e,t){var r,i;const{html:o,text:n}=this.extractContent(e);if(!o)throw new Error("No HTML content found in Copilot response");let s=o;const l=null!==(r=null==t?void 0:t.removeHeader)&&void 0!==r&&r,d=null!==(i=null==t?void 0:t.removeFooter)&&void 0!==i&&i;return s=this.sanitizeHtml(s),s=this.removeCookieBanner(s),l&&(s=this.removeHeader(s)),d&&(s=this.removeFooter(s)),(null==t?void 0:t.removeSidebar)&&(s=this.removeSidebar(s)),(null==t?void 0:t.removeLinks)&&(s=this.removeLinks(s)),s=this.injectStyles(s,{baseUrl:this.baseUrl,customCSS:""}),{provider:this.name,html:s,text:n,metadata:{isFullDocument:this.isFullDocument(s),cookieBannerRemoved:!0,headerRemoved:l,footerRemoved:d,sidebarRemoved:(null==t?void 0:t.removeSidebar)||!1,linksRemoved:(null==t?void 0:t.removeLinks)||!1}}}}class l extends r{constructor(){super(...arguments),this.name="AIOVERVIEW",this.baseUrl="https://www.google.com"}extractContent(e){return this.extractContentCommon(e,!0)}removeHeader(e){return e}removeFooter(e){return e}removeSidebar(e){return e}parse(e,t){var r,i;const{html:o,sources:n}=this.extractContent(e);if(!o)throw new Error("No HTML content found in AI Overview response");let s=o;const l=null===(r=null==t?void 0:t.removeHeader)||void 0===r||r,d=null===(i=null==t?void 0:t.removeFooter)||void 0===i||i;s=this.sanitizeHtml(s),l&&(s=this.removeHeader(s)),d&&(s=this.removeFooter(s)),(null==t?void 0:t.removeSidebar)&&(s=this.removeSidebar(s)),(null==t?void 0:t.removeLinks)&&(s=this.removeLinks(s));let a="";return l&&(a+='\n /* Header hiding */\n header, #header, #searchform, .sfbg, #appbar,\n div[role="navigation"], #leftnav, #sidetogether,\n [role="banner"], .Fgvgjc, #hdtb, .hdtb-msb,\n .DZ13He, .wYq63b, .eT9Cje, .bNg8Rb, .S6VXfe, .Lu57id {\n display: none !important;\n }\n '),(null==t?void 0:t.removeSidebar)&&(a+="\n /* Sidebar hiding */\n #leftnav, #sidetogether {\n display: none !important;\n }\n "),d&&(a+='\n /* Footer hiding */\n footer, #footer, .fbar,\n .pdp-nav, [aria-label="Main menu"], .gb_Td, .gb_L {\n display: none !important;\n }\n '),s=this.injectStyles(s,{baseUrl:this.baseUrl,customCSS:a}),{provider:this.name,html:s,sources:n,metadata:{isFullDocument:this.isFullDocument(s),headerRemoved:l,footerRemoved:d,sidebarRemoved:(null==t?void 0:t.removeSidebar)||!1,linksRemoved:(null==t?void 0:t.removeLinks)||!1}}}}class d extends r{constructor(){super(...arguments),this.name="AIMODE",this.baseUrl="https://www.google.com"}extractContent(e){return this.extractContentCommon(e)}removeHeader(e){let t=e;return t=t.replace(/<div[^>]*jsname="oEQ3x"[^>]*class="[^"]*DZ13He[^"]*"[^>]*>.*?<hr class="e9c7U">.*?<\/div><\/div><\/div><\/div><\/div>/gis,""),t}removeFooter(e){let t=e;return t=t.replace(/<div[^>]*data-xid="aim-mars-input-plate"[^>]*>[\s\S]*?<\/div><\/div><\/div><\/div><\/div>/gis,""),t=t.replace(/<div[^>]*jscontroller="P5gZDb"[^>]*>[\s\S]*?<\/div><\/div><\/div>/gis,""),t=t.replace(/<div[^>]*class="[^"]*t0ITR hh3ttd[^"]*"[^>]*>[\s\S]*?<\/div><\/div>/gis,""),t=t.replace(/<div[^>]*class="[^"]*y4VEUd vve6Ce[^"]*"[^>]*>[\s\S]*?<\/div><\/div>/gis,""),t}removeSidebar(e){let t=e;return t=t.replace(/<div[^>]*class="[^"]*ho072b[^"]*"[^>]*aria-label="AI Mode history"[^>]*>[\s\S]*?<\/div><\/div><\/div><\/div><\/div><\/div>/gis,""),t=t.replace(/<div[^>]*jsname="NlVIob"[^>]*class="[^"]*qEn1od[^"]*"[^>]*>[\s\S]*?<\/div><\/div><\/div>/gis,""),t=t.replace(/<div[^>]*class="[^"]*OEwhSe[^"]*"[^>]*>[\s\S]*?<\/div><\/div>/gis,""),t=t.replace(/<button[^>]*aria-label="Start new search"[^>]*>[\s\S]*?<\/button>/gis,""),t=t.replace(/<button[^>]*aria-label="AI Mode history"[^>]*>[\s\S]*?<\/button>/gis,""),t}parse(e,t){var r,i;const{html:o,text:n}=this.extractContent(e);if(!o)throw new Error("No HTML content found in AI Mode response");let s=o;const l=null===(r=null==t?void 0:t.removeHeader)||void 0===r||r,d=null===(i=null==t?void 0:t.removeFooter)||void 0===i||i;s=this.sanitizeHtml(s),l&&(s=this.removeHeader(s)),d&&(s=this.removeFooter(s)),(null==t?void 0:t.removeSidebar)&&(s=this.removeSidebar(s)),(null==t?void 0:t.removeLinks)&&(s=this.removeLinks(s));let a="";return a+="\n .KxvlWc, #CXQnmb {\n display: none !important;\n }\n ",l&&(a+='\n /* Header hiding */\n header, #header, #searchform, .sfbg, #appbar,\n div[role="navigation"], #leftnav, #sidetogether,\n [role="banner"], .Fgvgjc, #hdtb, .hdtb-msb,\n .DZ13He, .wYq63b, .eT9Cje, .bNg8Rb, .S6VXfe, .Lu57id {\n display: none !important;\n }\n '),(null==t?void 0:t.removeSidebar)&&(a+="\n /* Sidebar hiding */\n #leftnav, #sidetogether {\n display: none !important;\n }\n "),d&&(a+='\n /* Footer hiding */\n footer, #footer, .fbar,\n .pdp-nav, [aria-label="Main menu"], .gb_Td, .gb_L {\n display: none !important;\n }\n '),s=this.injectStyles(s,{baseUrl:this.baseUrl,customCSS:a}),{provider:this.name,html:s,text:n,metadata:{isFullDocument:this.isFullDocument(s),headerRemoved:l,footerRemoved:d,sidebarRemoved:(null==t?void 0:t.removeSidebar)||!1,linksRemoved:(null==t?void 0:t.removeLinks)||!1}}}}class a extends r{constructor(){super(...arguments),this.name="GROK",this.baseUrl="https://grok.com"}extractContent(e){return this.extractContentCommon(e)}removeHeader(e){return e}removeFooter(e){return e}parse(e,t){const{html:r,text:i}=this.extractContent(e);if(!r)throw new Error("No HTML content found in Grok response");let o=r;o=this.sanitizeHtml(o);let n="";return(null==t?void 0:t.removeHeader)&&(n+='\n /* Header hiding - hide elements with Grok\'s header class pattern */\n div[class*="h-16"][class*="top-0"][class*="z-10"],\n div[class*="absolute"][class*="inset-x-0"][class*="top-0"] {\n display: none !important;\n }\n '),(null==t?void 0:t.removeFooter)&&(n+='\n /* Footer hiding - hide Grok\'s footer/input area */\n div[class*="absolute"][class*="inset-x-0"][class*="bottom-0"][class*="max-w-breakout"],\n div[class*="absolute"][class*="bottom-0"][class*="w-full"] {\n display: none !important;\n }\n '),(null==t?void 0:t.removeLinks)&&(o=this.removeLinks(o)),o=this.injectStyles(o,{baseUrl:this.baseUrl,customCSS:n}),{provider:this.name,html:o,text:i,metadata:{isFullDocument:this.isFullDocument(o),linksRemoved:(null==t?void 0:t.removeLinks)||!1,headerRemoved:(null==t?void 0:t.removeHeader)||!1,footerRemoved:(null==t?void 0:t.removeFooter)||!1}}}}class v{constructor(){this.providers=new Map,this.providers.set("CHATGPT",new i),this.providers.set("GEMINI",new o),this.providers.set("PERPLEXITY",new n),this.providers.set("COPILOT",new s),this.providers.set("AIOVERVIEW",new l),this.providers.set("AIMODE",new d),this.providers.set("GROK",new a)}parse(e,r){const i=t.detect(e);if(!i)return this.parseGeneric(e);const o=this.providers.get(i.provider);if(!o)return null;try{const t=o.parse(e,r);return{...t,metadata:{...t.metadata,detectionConfidence:i.confidence}}}catch(e){return console.error(`Failed to parse response with ${i.provider}:`,e),null}}parseWithProvider(e,t,r){const i=this.providers.get(t);if(!i)throw new Error(`Unknown provider: ${t}`);try{return i.parse(e,r)}catch(e){return console.error(`Failed to parse response with ${t}:`,e),null}}detectProvider(e){const r=t.detect(e);return(null==r?void 0:r.provider)||null}detectAllProviders(e){return t.getAllProviders(e)}parseGeneric(t){const{html:r,text:i}=e(t);if(!r&&!i)return null;let o=r;return o&&(o=o.replace(/<script\b[^>]*>[\s\S]*?<\/script>/gim,""),o=o.replace(/<noscript[\s\S]*?<\/noscript>/gi,"")),{provider:"CHATGPT",html:o||"",text:i||"",metadata:{isGeneric:!0}}}getSupportedProviders(){return Array.from(this.providers.keys())}registerProvider(e,t){this.providers.set(e,t)}}const c=new v,u=(e,t)=>c.parse(e,t),m=e=>c.detectProvider(e);export{d as AIModeProvider,l as AIOverviewProvider,v as AIResponseParser,r as BaseProvider,i as ChatGPTProvider,s as CopilotProvider,o as GeminiProvider,a as GrokProvider,n as PerplexityProvider,t as ProviderDetector,m as detectProvider,u as parseAiResponse,c as parser};
1
+ function e(e){let t="",r="",o=e;return e.result&&(o=e.result),"string"==typeof o?o.trim().startsWith("<")&&o.includes(">")?t=o:r=o:"object"==typeof o&&null!==o&&(o.html?t=o.html:o.content?o.content.trim().startsWith("<")?t=o.content:r=o.content:o.text&&(r=o.text)),{html:t,text:r}}class t{static detect(e){const t={CHATGPT:0,GEMINI:0,PERPLEXITY:0,COPILOT:0,AIOVERVIEW:0,AIMODE:0,GROK:0};for(const[r,o]of Object.entries(this.PROVIDER_PATTERNS))for(const i of o)try{i(e)&&t[r]++}catch(e){}let r=0,o=null;for(const[e,i]of Object.entries(t))i>r&&(r=i,o=e);return 0===r?null:{provider:o,confidence:r/Object.values(t).reduce((e,t)=>Math.max(e,t),1)}}static getAllProviders(e){const t=[];for(const[r,o]of Object.entries(this.PROVIDER_PATTERNS)){let i=0;for(const t of o)try{t(e)&&i++}catch(e){}i>0&&t.push({provider:r,confidence:i/o.length})}return t.sort((e,t)=>t.confidence-e.confidence)}static validate(e,t){const r=this.detect(e);return(null==r?void 0:r.provider)===t&&r.confidence>.5}}t.PROVIDER_PATTERNS={CHATGPT:[e=>{var t;const r=(null===(t=null==e?void 0:e.result)||void 0===t?void 0:t.html)||(null==e?void 0:e.html)||"";return r.includes("bg-token-bg-primary")||r.includes("text-token-text-secondary")},e=>{var t;const r=(null===(t=null==e?void 0:e.result)||void 0===t?void 0:t.html)||(null==e?void 0:e.html)||"";return r.includes("chatgpt.com")||r.includes("openai.com")}],GEMINI:[e=>{var t;const r=(null===(t=null==e?void 0:e.result)||void 0===t?void 0:t.html)||(null==e?void 0:e.html)||"";return r.includes("bard-sidenav")||r.includes("mat-sidenav")},e=>{var t;const r=(null===(t=null==e?void 0:e.result)||void 0===t?void 0:t.html)||(null==e?void 0:e.html)||"";return r.includes("gemini.google.com")||r.includes("gem-sys-color")}],PERPLEXITY:[e=>{var t;return((null===(t=null==e?void 0:e.result)||void 0===t?void 0:t.html)||(null==e?void 0:e.html)||"").includes("perplexity.ai")},e=>{var t;const r=(null===(t=null==e?void 0:e.result)||void 0===t?void 0:t.html)||(null==e?void 0:e.html)||"";return r.includes("prose")&&!r.includes("grok.com")&&!r.includes("chatgpt.com")}],COPILOT:[e=>{var t;const r=(null===(t=null==e?void 0:e.result)||void 0===t?void 0:t.html)||(null==e?void 0:e.html)||"";return r.includes("copilot.microsoft.com")||r.includes('data-testid="sidebar-container"')}],AIOVERVIEW:[e=>{var t,r,o,i;if(null===(r=null===(t=null==e?void 0:e.result)||void 0===t?void 0:t.aioverview)||void 0===r?void 0:r.text)return!0;if(null===(o=null==e?void 0:e.aioverview)||void 0===o?void 0:o.text)return!0;return((null===(i=null==e?void 0:e.result)||void 0===i?void 0:i.html)||(null==e?void 0:e.html)||"").includes("DnVkpd")},e=>{var t;const r=(null===(t=null==e?void 0:e.result)||void 0===t?void 0:t.html)||(null==e?void 0:e.html)||"";return r.includes("WIZ_global_data")&&!r.includes("aim-mars")&&!r.includes("ho072b")}],AIMODE:[e=>{var t;const r=(null===(t=null==e?void 0:e.result)||void 0===t?void 0:t.html)||(null==e?void 0:e.html)||"";return r.includes("DZ13He")||r.includes("wYq63b")||r.includes("AI Mode")},e=>{var t;const r=(null===(t=null==e?void 0:e.result)||void 0===t?void 0:t.html)||(null==e?void 0:e.html)||"";return r.includes("aim-mars")||r.includes("ho072b")}],GROK:[e=>{var t;const r=(null===(t=null==e?void 0:e.result)||void 0===t?void 0:t.html)||(null==e?void 0:e.html)||"";return r.includes("grok.com")||r.includes("x.ai")},e=>{var t;const r=(null===(t=null==e?void 0:e.result)||void 0===t?void 0:t.html)||(null==e?void 0:e.html)||"";return r.includes("cdn.grok.com")||r.includes("vaul-drawer")}]};class r{extractContentCommon(t,r=!1){var o;const i=e(t);if(r){let e=[];const r=t.result||t;return"object"==typeof r&&null!==r&&((null===(o=r.aioverview)||void 0===o?void 0:o.sources)?e=r.aioverview.sources:r.sources&&(e=r.sources)),{...i,sources:e}}return i}injectStyles(e,t){let r=e;(null==t?void 0:t.baseUrl)&&!e.includes("<base ")&&(r=r.includes("<head>")?r.replace("<head>",`<head><base href="${t.baseUrl}">`):r.replace(/(<html[^>]*>)/i,`$1<head><base href="${t.baseUrl}"></head>`));const o=(null==t?void 0:t.customCSS)||"";return o&&r.includes("<head>")?r=r.replace("<head>",`<head><style>${o}</style>`):o&&(r=r.replace(/(<html[^>]*>)/i,`$1<head><style>${o}</style></head>`)),r}sanitizeHtml(e){let t=e.replace(/<script\b[^>]*>[\s\S]*?<\/script>/gim,"");return t=t.replace(/<noscript[\s\S]*?<\/noscript>/gi,""),t}isFullDocument(e){return/^\s*(<html|<!DOCTYPE)/i.test(e)}removeLinks(e){return e.replace(/<a\b[^>]*>([\s\S]*?)<\/a>/gim,"$1")}wrapFragment(e){return`<!DOCTYPE html>\n<html>\n<head>\n <meta charset="utf-8">\n <meta http-equiv="Content-Security-Policy" content="default-src 'none'; script-src 'none'; style-src 'unsafe-inline';">\n <style>\n body {\n margin: 0;\n padding: 16px;\n font-family: system-ui, -apple-system, sans-serif;\n white-space: pre-wrap;\n word-wrap: break-word;\n }\n img { max-width: 100%; height: auto; }\n body {\n pointer-events: none;\n user-select: none;\n }\n </style>\n</head>\n<body>\n ${e}\n</body>\n</html>`}}class o extends r{constructor(){super(...arguments),this.name="CHATGPT",this.baseUrl="https://chatgpt.com"}extractContent(e){return this.extractContentCommon(e)}removeLinks(e){return e.replace(/<a\b([^>]*)>/gi,(e,t)=>{const r=t.replace(/\s+href\s*=\s*["'][^"']*["']/gi,"").replace(/\s+alt\s*=\s*["'][^"']*["']/gi,"").replace(/\s+rel\s*=\s*["'][^"']*["']/gi,"").replace(/\s+target\s*=\s*["'][^"']*["']/gi,"").trim();return`<span${r?" "+r:""}>`}).replace(/<\/a>/gi,"</span>")}removeHeader(e){let t=e;return t=t.replace(/<header[^>]*id="page-header"[^>]*>.*?<\/header>/gis,""),t}removeSidebar(e){let t=e;return t=t.replace(/<nav[^>]*>.*?<\/nav>/gis,""),t=t.replace(/<div[^>]*class="[^"]*sidebar[^"]*"[^>]*>.*?<\/div>/gis,""),t}removeFooter(e){let t=e;return t=t.replace(/<div[^>]*id="thread-bottom-container"[^>]*>.*?<\/div><\/div><\/div>/gis,""),t=t.replace(/<div[^>]*id="thread-bottom"[^>]*>.*?<\/div><\/div><\/div><\/div><\/div>/gis,""),t=t.replace(/<div[^>]*class="[^"]*\[grid-area:leading\][^"]*"[^>]*>.*?<\/div><\/div><\/div>/gis,""),t=t.replace(/<div[^>]*class="[^"]*\[grid-area:footer\][^"]*"[^>]*>.*?<\/div><\/div><\/div><\/div><\/div>/gis,""),t=t.replace(/<div[^>]*class="[^"]*\[grid-area:trailing\][^"]*"[^>]*>.*?<\/div><\/div><\/div>/gis,""),t=t.replace(/<div[^>]*\[view-transition-name:var\(--vt-disclaimer\)\][^>]*>.*?<\/div><\/div>/gis,""),t}parse(e,t){var r;const{html:o,text:i}=this.extractContent(e);if(!o)throw new Error("No HTML content found in ChatGPT response");let n=o;const s=null!==(r=null==t?void 0:t.removeFooter)&&void 0!==r&&r;return n=this.sanitizeHtml(n),(null==t?void 0:t.removeHeader)&&(n=this.removeHeader(n)),(null==t?void 0:t.removeSidebar)&&(n=this.removeSidebar(n)),s&&(n=this.removeFooter(n)),(null==t?void 0:t.removeLinks)&&(n=this.removeLinks(n)),n=this.injectStyles(n,{baseUrl:this.baseUrl,customCSS:""}),{provider:this.name,html:n,text:i,metadata:{isFullDocument:this.isFullDocument(n),headerRemoved:(null==t?void 0:t.removeHeader)||!1,sidebarRemoved:(null==t?void 0:t.removeSidebar)||!1,footerRemoved:s,linksRemoved:(null==t?void 0:t.removeLinks)||!1}}}}class i extends r{constructor(){super(...arguments),this.name="GEMINI",this.baseUrl="https://gemini.google.com"}extractContent(e){return this.extractContentCommon(e,!0)}removeHeader(e){let t=e;return t=t.replace(/<div[^>]*class="[^"]*boqOnegoogleliteOgbOneGoogleBar[^"]*"[^>]*>.*?<\/div><\/div><\/div><\/div>/gis,""),t=t.replace(/<div[^>]*class="[^"]*side-nav-menu-button[^"]*"[^>]*>.*?<\/div>/gis,""),t=t.replace(/<top-bar-actions[^>]*>.*?<\/top-bar-actions>/gis,""),t=t.replace(/<div[^>]*class="[^"]*desktop-ogb-buffer[^"]*"[^>]*><\/div>/gis,""),t}removeFooter(e){return e.replace(/<input-container[^>]*>.*?<\/input-container>/gis,"")}removeSidebar(e){return e.replace(/<bard-sidenav[^>]*>.*?<\/bard-sidenav>/gis,"")}removeSources(e){let t=e;return t=t.replace(/<context-sidebar[^>]*>[\s\S]*?<\/context-sidebar>/gi,""),t=t.replace(/<sources-sidebar-button[^>]*>[\s\S]*?<\/sources-sidebar-button>/gi,""),t}parse(e,t){var r,o;const{html:i,text:n,sources:s}=this.extractContent(e);if(!i)throw new Error("No HTML content found in Gemini response");let l=i;const d=null!==(r=null==t?void 0:t.removeHeader)&&void 0!==r&&r,a=null!==(o=null==t?void 0:t.removeFooter)&&void 0!==o&&o;return l=this.sanitizeHtml(l),d&&(l=this.removeHeader(l)),a&&(l=this.removeFooter(l)),(null==t?void 0:t.removeSidebar)&&(l=this.removeSidebar(l)),(null==t?void 0:t.removeSources)&&(l=this.removeSources(l)),(null==t?void 0:t.removeLinks)&&(l=this.removeLinks(l)),l=this.injectStyles(l,{baseUrl:this.baseUrl,customCSS:""}),{provider:this.name,html:l,text:n,sources:s,metadata:{isFullDocument:this.isFullDocument(l),headerRemoved:d,footerRemoved:a,sidebarRemoved:(null==t?void 0:t.removeSidebar)||!1,sourcesRemoved:(null==t?void 0:t.removeSources)||!1,linksRemoved:(null==t?void 0:t.removeLinks)||!1}}}}class n extends r{constructor(){super(...arguments),this.name="PERPLEXITY",this.baseUrl="https://www.perplexity.ai"}extractContent(e){return this.extractContentCommon(e)}removeHeader(e){return e.replace(/<div[^>]*class="[^"]*@container\/header[^"]*"[^>]*>.*?<div[^>]*class="[^"]*absolute bottom-0 inset-x-0 border-b[^"]*"[^>]*><\/div>/gis,"")}removeFooter(e){let t=e;return t=t.replace(/<div[^>]*class="[^"]*erp-sidecar:fixed erp-sidecar:w-full bottom-safeAreaInsetBottom p-md pointer-events-none z-10 absolute border-subtlest ring-subtlest divide-subtlest bg-transparent[^"]*"[^>]*>[\s\S]*?(?=<div[^>]*class="[^"]*fixed inset-y-0 right-0[^"]*")/gis,""),t}removeSources(e){return e.replace(/<div[^>]*class="[^"]*fixed inset-y-0 right-0[^"]*"[^>]*>[\s\S]*?(?=<span[^>]*data-radix-focus-guard)/gi,"")}parse(e,t){var r,o;const{html:i,text:n}=this.extractContent(e);if(!i)throw new Error("No HTML content found in Perplexity response");let s=i;const l=null!==(r=null==t?void 0:t.removeHeader)&&void 0!==r&&r,d=null!==(o=null==t?void 0:t.removeFooter)&&void 0!==o&&o;s=this.sanitizeHtml(s),s=s.replace(/style="transition: none; overflow: hidden; height: 48px;"/gi,""),l&&(s=this.removeHeader(s)),d&&(s=this.removeFooter(s)),(null==t?void 0:t.removeSources)&&(s=this.removeSources(s)),(null==t?void 0:t.removeLinks)&&(s=this.removeLinks(s));return s=this.injectStyles(s,{baseUrl:this.baseUrl,customCSS:'\n #cookie-consent,\n [role="dialog"]:has(#cookie-consent) {\n display: none !important;\n }\n '}),{provider:this.name,html:s,text:n,metadata:{isFullDocument:this.isFullDocument(s),linksRemoved:(null==t?void 0:t.removeLinks)||!1,headerRemoved:l,footerRemoved:d,cookieBannerRemoved:!0,sourcesRemoved:(null==t?void 0:t.removeSources)||!1}}}}class s extends r{constructor(){super(...arguments),this.name="COPILOT",this.baseUrl="https://copilot.microsoft.com"}extractContent(e){return this.extractContentCommon(e)}removeHeader(e){let t=e;return t=t.replace(/<div[^>]*class="[^"]*relative shrink-0 min-h-14[^"]*"[^>]*data-testid="backstage-chats"[^>]*>.*?<\/div>/gis,""),t=t.replace(/<div[^>]*class="[^"]*flex items-center px-6 mx-auto w-full max-w-chat[^"]*"[^>]*>.*?<span[^>]*data-testid="date-divider"[^>]*>.*?<\/span>.*?<div[^>]*class="[^"]*border-t-\[1px\][^"]*"[^>]*>.*?<\/div>.*?<\/div>/gis,""),t=t.replace(/<div[^>]*class="[^"]*absolute flex end-6 origin-top-right flex-col items-end[^"]*"[^>]*data-testid="settings-wrapper"[^>]*>.*?<\/div><\/div>/gis,""),t}removeFooter(e){let t=e;return t=t.replace(/<div[^>]*class="[^"]*absolute bottom-0 w-full[^"]*"[^>]*>.*?<\/div><\/div><\/div><\/div><\/div><\/div><\/div><\/div><\/div><\/div><\/div><\/div>/gis,""),t=t.replace(/<div[^>]*class="[^"]*mt-\[var\(--composer-container-height\)\][^"]*"[^>]*><\/div>/gis,""),t=t.replace(/<div[^>]*class="[^"]*pointer-events-none absolute flex justify-center z-20 inset-x-0 bottom-\[calc\(var\(--composer-container-height\)\+1rem\)\][^"]*"[^>]*>.*?<button[^>]*data-testid="scroll-to-bottom-button"[^>]*>.*?<\/button><\/div>/gis,""),t}removeCookieBanner(e){let t=e;return t=t.replace(/<div[^>]*id="cookie-banner"[^>]*>.*?<\/div>.*?<\/div>.*?<\/div>.*?<\/div>/gis,""),t=t.replace(/<div[^>]*class="[^"]*max-w-cookie-banner[^"]*"[^>]*>.*?<\/div>.*?<\/div>.*?<\/div>.*?<\/div>/gis,""),t}removeSources(e){return e.replace(/<div[^>]*class="[^"]*relative h-full overflow-hidden will-change-auto[^"]*"[^>]*style="[^"]*width:\s*352px[^"]*"[^>]*>[\s\S]*?(?=<div[^>]*class="[^"]*pointer-events-none fixed[^"]*")/gi,"")}removeSidebar(e){let t=e;return t=t.replace(/<div[^>]*class="[^"]*bg-sidebar-light[^"]*"[^>]*>[\s\S]*?(?=<main)/gi,""),t}parse(e,t){var r,o;const{html:i,text:n}=this.extractContent(e);if(!i)throw new Error("No HTML content found in Copilot response");let s=i;const l=null!==(r=null==t?void 0:t.removeHeader)&&void 0!==r&&r,d=null!==(o=null==t?void 0:t.removeFooter)&&void 0!==o&&o;return s=this.sanitizeHtml(s),s=this.removeCookieBanner(s),l&&(s=this.removeHeader(s)),d&&(s=this.removeFooter(s)),(null==t?void 0:t.removeSidebar)&&(s=this.removeSidebar(s)),(null==t?void 0:t.removeSources)&&(s=this.removeSources(s)),(null==t?void 0:t.removeLinks)&&(s=this.removeLinks(s)),s=this.injectStyles(s,{baseUrl:this.baseUrl,customCSS:""}),{provider:this.name,html:s,text:n,metadata:{isFullDocument:this.isFullDocument(s),cookieBannerRemoved:!0,headerRemoved:l,footerRemoved:d,sidebarRemoved:(null==t?void 0:t.removeSidebar)||!1,sourcesRemoved:(null==t?void 0:t.removeSources)||!1,linksRemoved:(null==t?void 0:t.removeLinks)||!1}}}}class l extends r{constructor(){super(...arguments),this.name="AIOVERVIEW",this.baseUrl="https://www.google.com"}extractContent(e){return this.extractContentCommon(e,!0)}removeHeader(e){return e}removeFooter(e){return e}removeSidebar(e){return e}parse(e,t){var r,o;const{html:i,sources:n}=this.extractContent(e);if(!i)throw new Error("No HTML content found in AI Overview response");let s=i;const l=null===(r=null==t?void 0:t.removeHeader)||void 0===r||r,d=null===(o=null==t?void 0:t.removeFooter)||void 0===o||o;s=this.sanitizeHtml(s),l&&(s=this.removeHeader(s)),d&&(s=this.removeFooter(s)),(null==t?void 0:t.removeSidebar)&&(s=this.removeSidebar(s)),(null==t?void 0:t.removeLinks)&&(s=this.removeLinks(s));let a="";return l&&(a+='\n /* Header hiding */\n header, #header, #searchform, .sfbg, #appbar,\n div[role="navigation"], #leftnav, #sidetogether,\n [role="banner"], .Fgvgjc, #hdtb, .hdtb-msb,\n .DZ13He, .wYq63b, .eT9Cje, .bNg8Rb, .S6VXfe, .Lu57id {\n display: none !important;\n }\n '),(null==t?void 0:t.removeSidebar)&&(a+="\n /* Sidebar hiding */\n #leftnav, #sidetogether {\n display: none !important;\n }\n "),d&&(a+='\n /* Footer hiding */\n footer, #footer, .fbar,\n .pdp-nav, [aria-label="Main menu"], .gb_Td, .gb_L {\n display: none !important;\n }\n '),s=this.injectStyles(s,{baseUrl:this.baseUrl,customCSS:a}),{provider:this.name,html:s,sources:n,metadata:{isFullDocument:this.isFullDocument(s),headerRemoved:l,footerRemoved:d,sidebarRemoved:(null==t?void 0:t.removeSidebar)||!1,linksRemoved:(null==t?void 0:t.removeLinks)||!1}}}}class d extends r{constructor(){super(...arguments),this.name="AIMODE",this.baseUrl="https://www.google.com"}extractContent(e){return this.extractContentCommon(e)}removeHeader(e){let t=e;return t=t.replace(/<div[^>]*jsname="oEQ3x"[^>]*class="[^"]*DZ13He[^"]*"[^>]*>.*?<hr class="e9c7U">.*?<\/div><\/div><\/div><\/div><\/div>/gis,""),t}removeFooter(e){let t=e;return t=t.replace(/<div[^>]*data-xid="aim-mars-input-plate"[^>]*>[\s\S]*?<\/div><\/div><\/div><\/div><\/div>/gis,""),t=t.replace(/<div[^>]*jscontroller="P5gZDb"[^>]*>[\s\S]*?<\/div><\/div><\/div>/gis,""),t=t.replace(/<div[^>]*class="[^"]*t0ITR hh3ttd[^"]*"[^>]*>[\s\S]*?<\/div><\/div>/gis,""),t=t.replace(/<div[^>]*class="[^"]*y4VEUd vve6Ce[^"]*"[^>]*>[\s\S]*?<\/div><\/div>/gis,""),t}removeSidebar(e){let t=e;return t=t.replace(/<div[^>]*aria-label="AI Mode history"[^>]*class="[^"]*ho072b[^"]*"[^>]*>[\s\S]*?(?=<!--TgQPHd)/gi,""),t=t.replace(/<div[^>]*class="[^"]*ho072b[^"]*"[^>]*aria-label="AI Mode history"[^>]*>[\s\S]*?(?=<!--TgQPHd)/gi,""),t=t.replace(/<div[^>]*class="[^"]*OEwhSe[^"]*"[^>]*>[\s\S]*?<\/div><\/div>/gis,""),t=t.replace(/<button[^>]*aria-label="AI Mode history"[^>]*>[\s\S]*?<\/button>/gis,""),t}parse(e,t){var r,o;const{html:i,text:n}=this.extractContent(e);if(!i)throw new Error("No HTML content found in AI Mode response");let s=i;const l=null===(r=null==t?void 0:t.removeHeader)||void 0===r||r,d=null===(o=null==t?void 0:t.removeFooter)||void 0===o||o;s=this.sanitizeHtml(s),l&&(s=this.removeHeader(s)),d&&(s=this.removeFooter(s)),(null==t?void 0:t.removeSidebar)&&(s=this.removeSidebar(s)),(null==t?void 0:t.removeLinks)&&(s=this.removeLinks(s));let a="";return a+="\n .KxvlWc, #CXQnmb {\n display: none !important;\n }\n ",l&&(a+='\n /* Header hiding */\n header, #header, #searchform, .sfbg, #appbar,\n div[role="navigation"], #leftnav, #sidetogether,\n [role="banner"], .Fgvgjc, #hdtb, .hdtb-msb,\n .DZ13He, .wYq63b, .eT9Cje, .bNg8Rb, .S6VXfe, .Lu57id {\n display: none !important;\n }\n '),d&&(a+='\n /* Footer hiding */\n footer, #footer, .fbar,\n .pdp-nav, [aria-label="Main menu"], .gb_Td, .gb_L {\n display: none !important;\n }\n /* Hide the "Ask anything" input bar */\n [data-xid="aim-mars-input-plate"],\n .UAbVe, .y4VEUd, .t0ITR.hh3ttd {\n display: none !important;\n }\n '),(null==t?void 0:t.removeSidebar)&&(a+="\n /* Hide AI Mode history panel */\n .ho072b, .OEwhSe, .qEn1od {\n display: none !important;\n }\n "),s=this.injectStyles(s,{baseUrl:this.baseUrl,customCSS:a}),{provider:this.name,html:s,text:n,metadata:{isFullDocument:this.isFullDocument(s),headerRemoved:l,footerRemoved:d,sidebarRemoved:(null==t?void 0:t.removeSidebar)||!1,linksRemoved:(null==t?void 0:t.removeLinks)||!1}}}}class a extends r{constructor(){super(...arguments),this.name="GROK",this.baseUrl="https://grok.com"}extractContent(e){return this.extractContentCommon(e)}removeHeader(e){return e}removeFooter(e){return e}parse(e,t){const{html:r,text:o}=this.extractContent(e);if(!r)throw new Error("No HTML content found in Grok response");let i=r;i=this.sanitizeHtml(i);let n="";return n+='\n [data-cookie-banner],\n [data-cookie-banner="true"] {\n display: none !important;\n }\n ',n+='\n [data-sonner-toaster],\n [data-sonner-toast],\n [class*="sonner-toast"] {\n display: none !important;\n }\n ',(null==t?void 0:t.removeSources)&&(i=i.replace(/<div[^>]*class="[^"]*h-dvh[^"]*flex-shrink-0[^"]*max-w-[^"]*"[^>]*>[\s\S]*?<\/aside>[\s\S]*?(?=<section)/gi,""),n+='\n div[data-state] > div.flex.flex-row.gap-1.items-center.rounded-full.cursor-pointer {\n display: none !important;\n }\n [vaul-drawer][vaul-drawer-direction="right"],\n [vaul-overlay] {\n display: none !important;\n }\n '),(null==t?void 0:t.removeHeader)&&(n+='\n /* Header hiding - hide elements with Grok\'s header class pattern */\n div[class*="h-16"][class*="top-0"][class*="z-10"],\n div[class*="absolute"][class*="inset-x-0"][class*="top-0"] {\n display: none !important;\n }\n '),(null==t?void 0:t.removeFooter)&&(n+='\n /* Footer hiding - hide Grok\'s footer/input area */\n div[class*="absolute"][class*="inset-x-0"][class*="bottom-0"][class*="max-w-breakout"],\n div[class*="absolute"][class*="bottom-0"][class*="w-full"] {\n display: none !important;\n }\n '),(null==t?void 0:t.removeLinks)&&(i=this.removeLinks(i)),i=this.injectStyles(i,{baseUrl:this.baseUrl,customCSS:n}),{provider:this.name,html:i,text:o,metadata:{isFullDocument:this.isFullDocument(i),linksRemoved:(null==t?void 0:t.removeLinks)||!1,headerRemoved:(null==t?void 0:t.removeHeader)||!1,footerRemoved:(null==t?void 0:t.removeFooter)||!1,cookieBannerRemoved:!0,sourcesRemoved:(null==t?void 0:t.removeSources)||!1}}}}class v{constructor(){this.providers=new Map,this.providers.set("CHATGPT",new o),this.providers.set("GEMINI",new i),this.providers.set("PERPLEXITY",new n),this.providers.set("COPILOT",new s),this.providers.set("AIOVERVIEW",new l),this.providers.set("AIMODE",new d),this.providers.set("GROK",new a)}parse(e,r){const o=t.detect(e);if(!o)return this.parseGeneric(e);const i=this.providers.get(o.provider);if(!i)return null;try{const t=i.parse(e,r);return{...t,metadata:{...t.metadata,detectionConfidence:o.confidence}}}catch(e){return console.error(`Failed to parse response with ${o.provider}:`,e),null}}parseWithProvider(e,t,r){const o=this.providers.get(t);if(!o)throw new Error(`Unknown provider: ${t}`);try{return o.parse(e,r)}catch(e){return console.error(`Failed to parse response with ${t}:`,e),null}}detectProvider(e){const r=t.detect(e);return(null==r?void 0:r.provider)||null}detectAllProviders(e){return t.getAllProviders(e)}parseGeneric(t){const{html:r,text:o}=e(t);if(!r&&!o)return null;let i=r;return i&&(i=i.replace(/<script\b[^>]*>[\s\S]*?<\/script>/gim,""),i=i.replace(/<noscript[\s\S]*?<\/noscript>/gi,"")),{provider:"CHATGPT",html:i||"",text:o||"",metadata:{isGeneric:!0}}}getSupportedProviders(){return Array.from(this.providers.keys())}registerProvider(e,t){this.providers.set(e,t)}}const c=new v,u=(e,t)=>c.parse(e,t),m=e=>c.detectProvider(e);export{d as AIModeProvider,l as AIOverviewProvider,v as AIResponseParser,r as BaseProvider,o as ChatGPTProvider,s as CopilotProvider,i as GeminiProvider,a as GrokProvider,n as PerplexityProvider,t as ProviderDetector,m as detectProvider,u as parseAiResponse,c as parser};
2
2
  //# sourceMappingURL=index.esm.js.map
@@ -1 +1 @@
1
- {"version":3,"file":"index.esm.js","sources":["../src/core/types.ts","../src/core/detector.ts","../src/providers/base-provider.ts","../src/providers/chatgpt.ts","../src/providers/gemini.ts","../src/providers/perplexity.ts","../src/providers/copilot.ts","../src/providers/ai-overview.ts","../src/providers/ai-mode.ts","../src/providers/grok.ts","../src/core/parser.ts"],"sourcesContent":["export type AIProvider =\n | 'CHATGPT'\n | 'GEMINI'\n | 'PERPLEXITY'\n | 'COPILOT'\n | 'AIOVERVIEW'\n | 'AIMODE'\n | 'GROK';\n\nexport interface ParsedResponse {\n provider: AIProvider;\n html: string;\n text?: string;\n sources?: any[];\n metadata?: Record<string, any>;\n}\n\nexport interface ParseOptions {\n removeLinks?: boolean;\n removeHeader?: boolean;\n removeFooter?: boolean;\n removeSidebar?: boolean;\n}\n\nexport interface ProviderConfig {\n name: AIProvider;\n baseUrl: string;\n}\n\nexport interface DetectedProvider {\n provider: AIProvider;\n confidence: number;\n}\n\nexport interface StyleOptions {\n customCSS?: string;\n hideUI?: boolean;\n baseUrl?: string;\n}\n\nexport type ContentExtraction = {\n html?: string;\n text?: string;\n sources?: any[];\n};\n\n/**\n * Standardized metadata for provider responses\n */\nexport interface ProviderMetadata {\n isFullDocument?: boolean;\n headerRemoved?: boolean;\n footerRemoved?: boolean;\n sidebarRemoved?: boolean;\n linksRemoved?: boolean;\n cookieBannerRemoved?: boolean;\n detectionConfidence?: number;\n}\n\n/**\n * Common content extraction utility - shared across providers and parser\n */\nexport function extractContentCommon(response: any): ContentExtraction {\n let html = '';\n let text = '';\n\n // Handle nested structure\n let dataToCheck = response;\n if (response.result) {\n dataToCheck = response.result;\n }\n\n // Extract content\n if (typeof dataToCheck === 'string') {\n if (dataToCheck.trim().startsWith('<') && dataToCheck.includes('>')) {\n html = dataToCheck;\n } else {\n text = dataToCheck;\n }\n } else if (typeof dataToCheck === 'object' && dataToCheck !== null) {\n if (dataToCheck.html) {\n html = dataToCheck.html;\n } else if (dataToCheck.content) {\n if (dataToCheck.content.trim().startsWith('<')) {\n html = dataToCheck.content;\n } else {\n text = dataToCheck.content;\n }\n } else if (dataToCheck.text) {\n text = dataToCheck.text;\n }\n }\n\n return { html, text };\n}","import { AIProvider, DetectedProvider } from './types';\n\nexport class ProviderDetector {\n private static readonly PROVIDER_PATTERNS = {\n CHATGPT: [\n // Check for token-based CSS classes\n (response: any) => {\n const html = response?.result?.html || response?.html || '';\n return html.includes('bg-token-bg-primary') || html.includes('text-token-text-secondary');\n },\n // Check for OpenAI-specific patterns\n (response: any) => {\n const html = response?.result?.html || response?.html || '';\n return html.includes('chatgpt.com') || html.includes('openai.com');\n },\n ],\n GEMINI: [\n // Check for Material Design components\n (response: any) => {\n const html = response?.result?.html || response?.html || '';\n return html.includes('bard-sidenav') || html.includes('mat-sidenav');\n },\n // Check for Gemini-specific classes\n (response: any) => {\n const html = response?.result?.html || response?.html || '';\n return html.includes('gemini.google.com') || html.includes('gem-sys-color');\n },\n ],\n PERPLEXITY: [\n // Check for Perplexity-specific structure\n (response: any) => {\n const html = response?.result?.html || response?.html || '';\n return html.includes('perplexity.ai') || html.includes('prose');\n },\n ],\n COPILOT: [\n // Check for Copilot-specific elements\n (response: any) => {\n const html = response?.result?.html || response?.html || '';\n return html.includes('copilot.microsoft.com') || html.includes('data-testid=\"sidebar-container\"');\n },\n ],\n AIOVERVIEW: [\n // Check for AI Overview specific structure\n (response: any) => {\n // Check for aioverview nested structure\n if (response?.result?.aioverview?.text) return true;\n if (response?.aioverview?.text) return true;\n\n // Check for WIZ_global_data (AI Overview specific)\n const html = response?.result?.html || response?.html || '';\n return html.includes('WIZ_global_data') || html.includes('DnVkpd');\n },\n ],\n AIMODE: [\n // Check for AI Mode specific elements\n (response: any) => {\n const html = response?.result?.html || response?.html || '';\n return html.includes('DZ13He') || html.includes('wYq63b') || html.includes('AI Mode');\n },\n ],\n GROK: [\n // Check for Grok-specific structure\n (response: any) => {\n const html = response?.result?.html || response?.html || '';\n return html.includes('grok.com') || html.includes('x.ai');\n },\n ],\n };\n\n /**\n * Detect the AI provider from the response\n */\n static detect(response: any): DetectedProvider | null {\n const scores: Record<AIProvider, number> = {\n CHATGPT: 0,\n GEMINI: 0,\n PERPLEXITY: 0,\n COPILOT: 0,\n AIOVERVIEW: 0,\n AIMODE: 0,\n GROK: 0,\n };\n\n // Score each provider based on pattern matches\n for (const [provider, patterns] of Object.entries(this.PROVIDER_PATTERNS)) {\n for (const pattern of patterns) {\n try {\n if (pattern(response)) {\n scores[provider as AIProvider]++;\n }\n } catch {\n // Ignore pattern errors\n }\n }\n }\n\n // Find the provider with the highest score\n let maxScore = 0;\n let detectedProvider: AIProvider | null = null;\n\n for (const [provider, score] of Object.entries(scores)) {\n if (score > maxScore) {\n maxScore = score;\n detectedProvider = provider as AIProvider;\n }\n }\n\n // Return null if no patterns matched\n if (maxScore === 0) return null;\n\n return {\n provider: detectedProvider!,\n confidence: maxScore / Object.values(scores).reduce((a, b) => Math.max(a, b), 1),\n };\n }\n\n /**\n * Get all possible providers with their confidence scores\n */\n static getAllProviders(response: any): DetectedProvider[] {\n const providers: DetectedProvider[] = [];\n\n for (const [provider, patterns] of Object.entries(this.PROVIDER_PATTERNS)) {\n let matches = 0;\n for (const pattern of patterns) {\n try {\n if (pattern(response)) {\n matches++;\n }\n } catch {\n // Ignore pattern errors\n }\n }\n\n if (matches > 0) {\n providers.push({\n provider: provider as AIProvider,\n confidence: matches / patterns.length,\n });\n }\n }\n\n // Sort by confidence (highest first)\n return providers.sort((a, b) => b.confidence - a.confidence);\n }\n\n /**\n * Validate if a detected provider is likely correct\n */\n static validate(response: any, provider: AIProvider): boolean {\n const detected = this.detect(response);\n return detected?.provider === provider && detected.confidence > 0.5;\n }\n}","import { AIProvider, ParsedResponse, ParseOptions, StyleOptions, ContentExtraction, extractContentCommon } from '../core/types';\n\nexport abstract class BaseProvider {\n abstract readonly name: AIProvider;\n abstract readonly baseUrl: string;\n\n /**\n * Parse an AI response and return structured content\n */\n abstract parse(response: any, options?: ParseOptions): ParsedResponse;\n\n /**\n * Extract content from the response object\n */\n abstract extractContent(response: any): ContentExtraction;\n\n /**\n * Common content extraction logic - can be used by providers\n */\n protected extractContentCommon(response: any, includeSources = false): ContentExtraction {\n const result = extractContentCommon(response);\n\n if (includeSources) {\n let sources: any[] = [];\n const dataToCheck = response.result || response;\n\n if (typeof dataToCheck === 'object' && dataToCheck !== null) {\n if (dataToCheck.aioverview?.sources) {\n sources = dataToCheck.aioverview.sources;\n } else if (dataToCheck.sources) {\n sources = dataToCheck.sources;\n }\n }\n\n return { ...result, sources };\n }\n\n return result;\n }\n\n /**\n * Inject provider-specific styles into HTML\n */\n injectStyles(html: string, options?: StyleOptions): string {\n let styledHtml = html;\n\n // Inject base URL if not already present\n if (options?.baseUrl && !html.includes('<base ')) {\n if (styledHtml.includes('<head>')) {\n styledHtml = styledHtml.replace(\n '<head>',\n `<head><base href=\"${options.baseUrl}\">`,\n );\n } else {\n styledHtml = styledHtml.replace(\n /(<html[^>]*>)/i,\n `$1<head><base href=\"${options.baseUrl}\"></head>`,\n );\n }\n }\n\n // Inject styles only if customCSS is provided\n const styles = options?.customCSS || '';\n\n if (styles && styledHtml.includes('<head>')) {\n styledHtml = styledHtml.replace('<head>', `<head><style>${styles}</style>`);\n } else if (styles) {\n styledHtml = styledHtml.replace(\n /(<html[^>]*>)/i,\n `$1<head><style>${styles}</style></head>`,\n );\n }\n\n return styledHtml;\n }\n\n /**\n * Sanitize HTML content\n */\n sanitizeHtml(html: string): string {\n // Remove scripts\n let sanitized = html.replace(/<script\\b[^>]*>[\\s\\S]*?<\\/script>/gim, '');\n\n // Remove noscript tags\n sanitized = sanitized.replace(/<noscript[\\s\\S]*?<\\/noscript>/gi, '');\n\n return sanitized;\n }\n\n /**\n * Check if content is a full HTML document\n */\n isFullDocument(html: string): boolean {\n return /^\\s*(<html|<!DOCTYPE)/i.test(html);\n }\n\n /**\n * Remove all links from HTML, keeping the text content\n */\n removeLinks(html: string): string {\n // Replace anchor tags with their text content\n return html.replace(/<a\\b[^>]*>([\\s\\S]*?)<\\/a>/gim, '$1');\n }\n\n /**\n * Wrap HTML fragment in a document\n */\n wrapFragment(html: string): string {\n return `<!DOCTYPE html>\n<html>\n<head>\n <meta charset=\"utf-8\">\n <meta http-equiv=\"Content-Security-Policy\" content=\"default-src 'none'; script-src 'none'; style-src 'unsafe-inline';\">\n <style>\n body {\n margin: 0;\n padding: 16px;\n font-family: system-ui, -apple-system, sans-serif;\n white-space: pre-wrap;\n word-wrap: break-word;\n }\n img { max-width: 100%; height: auto; }\n body {\n pointer-events: none;\n user-select: none;\n }\n </style>\n</head>\n<body>\n ${html}\n</body>\n</html>`;\n }\n}","import { BaseProvider } from \"./base-provider\";\nimport {\n AIProvider,\n ParsedResponse,\n ParseOptions,\n ContentExtraction,\n ProviderMetadata,\n} from \"../core/types\";\n\nexport class ChatGPTProvider extends BaseProvider {\n readonly name: AIProvider = \"CHATGPT\";\n readonly baseUrl = \"https://chatgpt.com\";\n\n\n extractContent(response: any): ContentExtraction {\n return this.extractContentCommon(response);\n }\n\n /**\n * Remove links from HTML, preserving badge styling\n * Converts <a> tags to <span> while keeping class attributes\n */\n removeLinks(html: string): string {\n // Replace anchor tags with span tags, keeping all attributes except href/alt/rel/target\n return html\n .replace(/<a\\b([^>]*)>/gi, (match, attributes) => {\n // Remove link-specific attributes but keep others (class, style, etc.)\n const cleanedAttrs = attributes\n .replace(/\\s+href\\s*=\\s*[\"'][^\"']*[\"']/gi, \"\")\n .replace(/\\s+alt\\s*=\\s*[\"'][^\"']*[\"']/gi, \"\")\n .replace(/\\s+rel\\s*=\\s*[\"'][^\"']*[\"']/gi, \"\")\n .replace(/\\s+target\\s*=\\s*[\"'][^\"']*[\"']/gi, \"\")\n .trim();\n return `<span${cleanedAttrs ? \" \" + cleanedAttrs : \"\"}>`;\n })\n .replace(/<\\/a>/gi, \"</span>\");\n }\n\n /**\n * Remove ChatGPT header from HTML\n */\n removeHeader(html: string): string {\n let cleaned = html;\n\n // Remove page header by id\n cleaned = cleaned.replace(\n /<header[^>]*id=\"page-header\"[^>]*>.*?<\\/header>/gis,\n \"\"\n );\n\n return cleaned;\n }\n\n /**\n * Remove ChatGPT sidebar from HTML\n */\n removeSidebar(html: string): string {\n let cleaned = html;\n\n // Hide Sidebar\n cleaned = cleaned.replace(/<nav[^>]*>.*?<\\/nav>/gis, \"\");\n cleaned = cleaned.replace(\n /<div[^>]*class=\"[^\"]*sidebar[^\"]*\"[^>]*>.*?<\\/div>/gis,\n \"\"\n );\n\n return cleaned;\n }\n\n /**\n * Remove ChatGPT footer/composer from HTML\n */\n removeFooter(html: string): string {\n let cleaned = html;\n\n // Remove the thread-bottom-container (scroll button container)\n cleaned = cleaned.replace(\n /<div[^>]*id=\"thread-bottom-container\"[^>]*>.*?<\\/div><\\/div><\\/div>/gis,\n \"\"\n );\n\n // Remove the entire thread-bottom div (contains composer and inputs)\n cleaned = cleaned.replace(\n /<div[^>]*id=\"thread-bottom\"[^>]*>.*?<\\/div><\\/div><\\/div><\\/div><\\/div>/gis,\n \"\"\n );\n\n // Remove composer leading button (plus button)\n cleaned = cleaned.replace(\n /<div[^>]*class=\"[^\"]*\\[grid-area:leading\\][^\"]*\"[^>]*>.*?<\\/div><\\/div><\\/div>/gis,\n \"\"\n );\n\n // Remove composer footer actions (search button, etc.)\n cleaned = cleaned.replace(\n /<div[^>]*class=\"[^\"]*\\[grid-area:footer\\][^\"]*\"[^>]*>.*?<\\/div><\\/div><\\/div><\\/div><\\/div>/gis,\n \"\"\n );\n\n // Remove composer trailing buttons (dictate, send buttons)\n cleaned = cleaned.replace(\n /<div[^>]*class=\"[^\"]*\\[grid-area:trailing\\][^\"]*\"[^>]*>.*?<\\/div><\\/div><\\/div>/gis,\n \"\"\n );\n\n // Remove disclaimer footer (language-agnostic, targets view-transition-name)\n cleaned = cleaned.replace(\n /<div[^>]*\\[view-transition-name:var\\(--vt-disclaimer\\)\\][^>]*>.*?<\\/div><\\/div>/gis,\n \"\"\n );\n\n return cleaned;\n }\n\n parse(response: any, options?: ParseOptions): ParsedResponse {\n const { html, text } = this.extractContent(response);\n\n if (!html) {\n throw new Error(\"No HTML content found in ChatGPT response\");\n }\n\n let finalHtml = html;\n\n const removeFooter = options?.removeFooter ?? false;\n\n // Sanitize HTML\n finalHtml = this.sanitizeHtml(finalHtml);\n\n // Remove header if requested\n if (options?.removeHeader) {\n finalHtml = this.removeHeader(finalHtml);\n }\n\n // Remove sidebar if requested\n if (options?.removeSidebar) {\n finalHtml = this.removeSidebar(finalHtml);\n }\n\n // Remove footer if requested\n if (removeFooter) {\n finalHtml = this.removeFooter(finalHtml);\n }\n\n // Remove links if requested\n if (options?.removeLinks) {\n finalHtml = this.removeLinks(finalHtml);\n }\n\n finalHtml = this.injectStyles(finalHtml, {\n baseUrl: this.baseUrl,\n customCSS: \"\",\n });\n\n return {\n provider: this.name,\n html: finalHtml,\n text,\n metadata: {\n isFullDocument: this.isFullDocument(finalHtml),\n headerRemoved: options?.removeHeader || false,\n sidebarRemoved: options?.removeSidebar || false,\n footerRemoved: removeFooter,\n linksRemoved: options?.removeLinks || false,\n } as ProviderMetadata,\n };\n }\n}\n","import { BaseProvider } from './base-provider';\nimport { AIProvider, ParsedResponse, ParseOptions, ContentExtraction, ProviderMetadata } from '../core/types';\n\nexport class GeminiProvider extends BaseProvider {\n readonly name: AIProvider = 'GEMINI';\n readonly baseUrl = 'https://gemini.google.com';\n\n\n extractContent(response: any): ContentExtraction {\n return this.extractContentCommon(response, true);\n }\n\n /**\n * Remove Gemini header/navbar from HTML\n */\n removeHeader(html: string): string {\n let cleaned = html;\n\n // Remove the Google navbar with boqOnegoogleliteOgbOneGoogleBar class\n cleaned = cleaned.replace(/<div[^>]*class=\"[^\"]*boqOnegoogleliteOgbOneGoogleBar[^\"]*\"[^>]*>.*?<\\/div><\\/div><\\/div><\\/div>/gis, '');\n\n // Remove side-nav-menu-button (hamburger menu)\n cleaned = cleaned.replace(/<div[^>]*class=\"[^\"]*side-nav-menu-button[^\"]*\"[^>]*>.*?<\\/div>/gis, '');\n\n // Remove top-bar-actions (About Gemini, Gemini App, Subscriptions, For Business links)\n cleaned = cleaned.replace(/<top-bar-actions[^>]*>.*?<\\/top-bar-actions>/gis, '');\n\n // Remove desktop-ogb-buffer\n cleaned = cleaned.replace(/<div[^>]*class=\"[^\"]*desktop-ogb-buffer[^\"]*\"[^>]*><\\/div>/gis, '');\n\n return cleaned;\n }\n\n /**\n * Remove Gemini footer/follow-up input box from HTML\n */\n removeFooter(html: string): string {\n // Remove input-container (text input, upload button, send button, disclaimer)\n return html.replace(/<input-container[^>]*>.*?<\\/input-container>/gis, '');\n }\n\n /**\n * Remove Gemini sidebar from HTML\n */\n removeSidebar(html: string): string {\n // Remove bard-sidenav element\n return html.replace(/<bard-sidenav[^>]*>.*?<\\/bard-sidenav>/gis, '');\n }\n\n parse(response: any, options?: ParseOptions): ParsedResponse {\n const { html, text, sources } = this.extractContent(response);\n\n if (!html) {\n throw new Error('No HTML content found in Gemini response');\n }\n\n let finalHtml = html;\n\n const removeHeader = options?.removeHeader ?? false;\n const removeFooter = options?.removeFooter ?? false;\n\n // Sanitize HTML (remove scripts and noscript)\n finalHtml = this.sanitizeHtml(finalHtml);\n\n // Remove header if requested\n if (removeHeader) {\n finalHtml = this.removeHeader(finalHtml);\n }\n\n // Remove footer if requested\n if (removeFooter) {\n finalHtml = this.removeFooter(finalHtml);\n }\n\n // Remove sidebar if requested\n if (options?.removeSidebar) {\n finalHtml = this.removeSidebar(finalHtml);\n }\n\n // Remove links if requested\n if (options?.removeLinks) {\n finalHtml = this.removeLinks(finalHtml);\n }\n\n finalHtml = this.injectStyles(finalHtml, {\n baseUrl: this.baseUrl,\n customCSS: '',\n });\n\n return {\n provider: this.name,\n html: finalHtml,\n text,\n sources,\n metadata: {\n isFullDocument: this.isFullDocument(finalHtml),\n headerRemoved: removeHeader,\n footerRemoved: removeFooter,\n sidebarRemoved: options?.removeSidebar || false,\n linksRemoved: options?.removeLinks || false,\n } as ProviderMetadata,\n };\n }\n}","import { BaseProvider } from \"./base-provider\";\nimport {\n AIProvider,\n ParsedResponse,\n ParseOptions,\n ContentExtraction,\n ProviderMetadata,\n} from \"../core/types\";\n\nexport class PerplexityProvider extends BaseProvider {\n readonly name: AIProvider = \"PERPLEXITY\";\n readonly baseUrl = \"https://www.perplexity.ai\";\n\n extractContent(response: any): ContentExtraction {\n return this.extractContentCommon(response);\n }\n\n /**\n * Remove Perplexity header/navbar from HTML\n */\n removeHeader(html: string): string {\n // Remove navbar by targeting the unique @container/header class\n // Matches from the navbar opening div through the border divider at the bottom\n return html.replace(\n /<div[^>]*class=\"[^\"]*@container\\/header[^\"]*\"[^>]*>.*?<div[^>]*class=\"[^\"]*absolute bottom-0 inset-x-0 border-b[^\"]*\"[^>]*><\\/div>/gis,\n \"\"\n );\n }\n\n /**\n * Remove Perplexity footer/followup input from HTML\n */\n removeFooter(html: string): string {\n let cleaned = html;\n const regex =\n /<div[^>]*class=\"[^\"]*erp-sidecar:fixed erp-sidecar:w-full bottom-safeAreaInsetBottom p-md pointer-events-none z-10 absolute border-subtlest ring-subtlest divide-subtlest bg-transparent[^\"]*\"[^>]*>[\\s\\S]*?(?=<div[^>]*class=\"[^\"]*fixed inset-y-0 right-0[^\"]*\")/gis;\n cleaned = cleaned.replace(regex, \"\");\n return cleaned;\n }\n\n parse(response: any, options?: ParseOptions): ParsedResponse {\n const { html, text } = this.extractContent(response);\n\n if (!html) {\n throw new Error(\"No HTML content found in Perplexity response\");\n }\n\n let finalHtml = html;\n\n const removeHeader = options?.removeHeader ?? false;\n const removeFooter = options?.removeFooter ?? false;\n\n // Sanitize HTML\n finalHtml = this.sanitizeHtml(finalHtml);\n\n // Remove header if requested\n if (removeHeader) {\n finalHtml = this.removeHeader(finalHtml);\n }\n\n // Remove footer if requested\n if (removeFooter) {\n finalHtml = this.removeFooter(finalHtml);\n }\n\n // Remove links if requested\n if (options?.removeLinks) {\n finalHtml = this.removeLinks(finalHtml);\n }\n\n finalHtml = this.injectStyles(finalHtml, {\n baseUrl: this.baseUrl,\n customCSS: '',\n });\n\n return {\n provider: this.name,\n html: finalHtml,\n text,\n metadata: {\n isFullDocument: this.isFullDocument(finalHtml),\n linksRemoved: options?.removeLinks || false,\n headerRemoved: removeHeader,\n footerRemoved: removeFooter,\n } as ProviderMetadata,\n };\n }\n}\n","import { BaseProvider } from './base-provider';\nimport { AIProvider, ParsedResponse, ParseOptions, ContentExtraction, ProviderMetadata } from '../core/types';\n\nexport class CopilotProvider extends BaseProvider {\n readonly name: AIProvider = 'COPILOT';\n readonly baseUrl = 'https://copilot.microsoft.com';\n\n\n extractContent(response: any): ContentExtraction {\n return this.extractContentCommon(response);\n }\n\n /**\n * Remove Copilot header/navbar from HTML\n */\n removeHeader(html: string): string {\n let cleaned = html;\n\n // Remove backstage-chats (hidden navbar element)\n cleaned = cleaned.replace(/<div[^>]*class=\"[^\"]*relative shrink-0 min-h-14[^\"]*\"[^>]*data-testid=\"backstage-chats\"[^>]*>.*?<\\/div>/gis, '');\n\n // Remove date divider (e.g., \"Today\" with horizontal line)\n cleaned = cleaned.replace(/<div[^>]*class=\"[^\"]*flex items-center px-6 mx-auto w-full max-w-chat[^\"]*\"[^>]*>.*?<span[^>]*data-testid=\"date-divider\"[^>]*>.*?<\\/span>.*?<div[^>]*class=\"[^\"]*border-t-\\[1px\\][^\"]*\"[^>]*>.*?<\\/div>.*?<\\/div>/gis, '');\n\n // Remove settings wrapper (share/settings buttons in top-right corner)\n cleaned = cleaned.replace(/<div[^>]*class=\"[^\"]*absolute flex end-6 origin-top-right flex-col items-end[^\"]*\"[^>]*data-testid=\"settings-wrapper\"[^>]*>.*?<\\/div><\\/div>/gis, '');\n\n return cleaned;\n }\n\n /**\n * Remove Copilot footer/followup input box from HTML\n */\n removeFooter(html: string): string {\n let cleaned = html;\n\n // Remove the composer (input box at bottom)\n // Starts with: <div class=\"absolute bottom-0 w-full\">\n // Contains: file input, composer content with textarea, buttons (home, attach, chat mode, audio call)\n cleaned = cleaned.replace(/<div[^>]*class=\"[^\"]*absolute bottom-0 w-full[^\"]*\"[^>]*>.*?<\\/div><\\/div><\\/div><\\/div><\\/div><\\/div><\\/div><\\/div><\\/div><\\/div><\\/div><\\/div>/gis, '');\n\n // Remove spacer div for composer height\n cleaned = cleaned.replace(/<div[^>]*class=\"[^\"]*mt-\\[var\\(--composer-container-height\\)\\][^\"]*\"[^>]*><\\/div>/gis, '');\n\n // Remove \"scroll to bottom\" button (full container with button and inner content)\n cleaned = cleaned.replace(/<div[^>]*class=\"[^\"]*pointer-events-none absolute flex justify-center z-20 inset-x-0 bottom-\\[calc\\(var\\(--composer-container-height\\)\\+1rem\\)\\][^\"]*\"[^>]*>.*?<button[^>]*data-testid=\"scroll-to-bottom-button\"[^>]*>.*?<\\/button><\\/div>/gis, '');\n\n return cleaned;\n }\n\n /**\n * Remove Copilot cookie banner from HTML\n */\n removeCookieBanner(html: string): string {\n let cleaned = html;\n\n // Remove cookie banner by id\n cleaned = cleaned.replace(/<div[^>]*id=\"cookie-banner\"[^>]*>.*?<\\/div>.*?<\\/div>.*?<\\/div>.*?<\\/div>/gis, '');\n\n // Remove cookie banner by max-w-cookie-banner class (outer container)\n cleaned = cleaned.replace(/<div[^>]*class=\"[^\"]*max-w-cookie-banner[^\"]*\"[^>]*>.*?<\\/div>.*?<\\/div>.*?<\\/div>.*?<\\/div>/gis, '');\n\n return cleaned;\n }\n\n /**\n * Remove Copilot sidebar from HTML\n */\n removeSidebar(html: string): string {\n let cleaned = html;\n\n // Remove the inner sidebar div\n // Starts with: <div class=\"absolute h-full w-0 will-change-auto max-md:bg-sidebar-light...\" style=\"width: 52px;\">\n // Ends right before: <main class=\"relative flex w-full min-w-0 will-change-auto...\n cleaned = cleaned.replace(/<div[^>]*class=\"[^\"]*absolute h-full w-0 will-change-auto max-md:bg-sidebar-light[^\"]*\"[^>]*style=\"[^\"]*\"[^>]*>.*?<main/gis, '<main');\n\n return cleaned;\n }\n\n parse(response: any, options?: ParseOptions): ParsedResponse {\n const { html, text } = this.extractContent(response);\n\n if (!html) {\n throw new Error('No HTML content found in Copilot response');\n }\n\n let finalHtml = html;\n\n const removeHeader = options?.removeHeader ?? false;\n const removeFooter = options?.removeFooter ?? false;\n\n // Sanitize HTML\n finalHtml = this.sanitizeHtml(finalHtml);\n\n // Remove cookie banner (always)\n finalHtml = this.removeCookieBanner(finalHtml);\n\n // Remove header if requested\n if (removeHeader) {\n finalHtml = this.removeHeader(finalHtml);\n }\n\n // Remove footer if requested\n if (removeFooter) {\n finalHtml = this.removeFooter(finalHtml);\n }\n\n // Remove sidebar if requested\n if (options?.removeSidebar) {\n finalHtml = this.removeSidebar(finalHtml);\n }\n\n // Remove links if requested\n if (options?.removeLinks) {\n finalHtml = this.removeLinks(finalHtml);\n }\n\n finalHtml = this.injectStyles(finalHtml, {\n baseUrl: this.baseUrl,\n customCSS: '',\n });\n\n return {\n provider: this.name,\n html: finalHtml,\n text,\n metadata: {\n isFullDocument: this.isFullDocument(finalHtml),\n cookieBannerRemoved: true,\n headerRemoved: removeHeader,\n footerRemoved: removeFooter,\n sidebarRemoved: options?.removeSidebar || false,\n linksRemoved: options?.removeLinks || false,\n } as ProviderMetadata,\n };\n }\n}","import { BaseProvider } from \"./base-provider\";\nimport {\n AIProvider,\n ParsedResponse,\n ParseOptions,\n ContentExtraction,\n ProviderMetadata,\n} from \"../core/types\";\n\nexport class AIOverviewProvider extends BaseProvider {\n readonly name: AIProvider = \"AIOVERVIEW\";\n readonly baseUrl = \"https://www.google.com\";\n\n extractContent(response: any): ContentExtraction {\n return this.extractContentCommon(response, true);\n }\n\n /**\n * Remove Google Search header/navbar from HTML\n */\n removeHeader(html: string): string {\n // Remove header elements via CSS injection\n return html;\n }\n\n /**\n * Remove Google Search footer from HTML\n */\n removeFooter(html: string): string {\n // Remove footer elements via CSS injection\n return html;\n }\n\n /**\n * Remove Google Search sidebar from HTML\n */\n removeSidebar(html: string): string {\n // Remove sidebar elements via CSS injection\n return html;\n }\n\n parse(response: any, options?: ParseOptions): ParsedResponse {\n const { html, sources } = this.extractContent(response);\n\n if (!html) {\n throw new Error(\"No HTML content found in AI Overview response\");\n }\n\n let finalHtml = html;\n\n // For AI Overview, default to removing header and footer for cleaner display\n const removeHeader = options?.removeHeader ?? true;\n const removeFooter = options?.removeFooter ?? true;\n\n // Sanitize HTML\n finalHtml = this.sanitizeHtml(finalHtml);\n\n // Remove header if requested\n if (removeHeader) {\n finalHtml = this.removeHeader(finalHtml);\n }\n\n // Remove footer if requested\n if (removeFooter) {\n finalHtml = this.removeFooter(finalHtml);\n }\n\n // Remove sidebar if requested\n if (options?.removeSidebar) {\n finalHtml = this.removeSidebar(finalHtml);\n }\n\n // Remove links if requested\n if (options?.removeLinks) {\n finalHtml = this.removeLinks(finalHtml);\n }\n\n // Build CSS based on options\n let stylesToInject = \"\";\n\n // Header removal styles\n if (removeHeader) {\n stylesToInject += `\n /* Header hiding */\n header, #header, #searchform, .sfbg, #appbar,\n div[role=\"navigation\"], #leftnav, #sidetogether,\n [role=\"banner\"], .Fgvgjc, #hdtb, .hdtb-msb,\n .DZ13He, .wYq63b, .eT9Cje, .bNg8Rb, .S6VXfe, .Lu57id {\n display: none !important;\n }\n `;\n }\n\n // Sidebar removal styles\n if (options?.removeSidebar) {\n stylesToInject += `\n /* Sidebar hiding */\n #leftnav, #sidetogether {\n display: none !important;\n }\n `;\n }\n\n // Footer removal styles\n if (removeFooter) {\n stylesToInject += `\n /* Footer hiding */\n footer, #footer, .fbar,\n .pdp-nav, [aria-label=\"Main menu\"], .gb_Td, .gb_L {\n display: none !important;\n }\n `;\n }\n\n // Inject base URL and styles\n finalHtml = this.injectStyles(finalHtml, {\n baseUrl: this.baseUrl,\n customCSS: stylesToInject,\n });\n\n return {\n provider: this.name,\n html: finalHtml,\n sources,\n metadata: {\n isFullDocument: this.isFullDocument(finalHtml),\n headerRemoved: removeHeader,\n footerRemoved: removeFooter,\n sidebarRemoved: options?.removeSidebar || false,\n linksRemoved: options?.removeLinks || false,\n } as ProviderMetadata,\n };\n }\n}\n","import { BaseProvider } from \"./base-provider\";\nimport {\n AIProvider,\n ParsedResponse,\n ParseOptions,\n ContentExtraction,\n ProviderMetadata,\n} from \"../core/types\";\n\nexport class AIModeProvider extends BaseProvider {\n readonly name: AIProvider = \"AIMODE\";\n readonly baseUrl = \"https://www.google.com\";\n\n extractContent(response: any): ContentExtraction {\n return this.extractContentCommon(response);\n }\n\n /**\n * Remove Google Search header/navbar from HTML\n */\n removeHeader(html: string): string {\n let cleaned = html;\n\n // Remove the AI Mode filter/header bar\n // Starts with <div jsname=\"oEQ3x\" class=\"DZ13He YNk70c EjQTId\">\n // Contains the Filters and Topics navigation (AI Mode, All, Images, Videos, News, More)\n // Ends with closing divs after <hr class=\"e9c7U\">\n cleaned = cleaned.replace(\n /<div[^>]*jsname=\"oEQ3x\"[^>]*class=\"[^\"]*DZ13He[^\"]*\"[^>]*>.*?<hr class=\"e9c7U\">.*?<\\/div><\\/div><\\/div><\\/div><\\/div>/gis,\n \"\"\n );\n\n return cleaned;\n }\n\n /**\n * Remove Google Search footer from HTML\n */\n removeFooter(html: string): string {\n let cleaned = html;\n\n // Remove the AI Mode input bar/footer\n // Target the most unique identifier: data-xid=\"aim-mars-input-plate\"\n // This element is deeply nested, so we need to match many closing divs\n cleaned = cleaned.replace(\n /<div[^>]*data-xid=\"aim-mars-input-plate\"[^>]*>[\\s\\S]*?<\\/div><\\/div><\\/div><\\/div><\\/div>/gis,\n \"\"\n );\n\n // Fallback: Target by jscontroller P5gZDb which wraps the input plate\n cleaned = cleaned.replace(\n /<div[^>]*jscontroller=\"P5gZDb\"[^>]*>[\\s\\S]*?<\\/div><\\/div><\\/div>/gis,\n \"\"\n );\n\n // Fallback: Target the t0ITR container\n cleaned = cleaned.replace(\n /<div[^>]*class=\"[^\"]*t0ITR hh3ttd[^\"]*\"[^>]*>[\\s\\S]*?<\\/div><\\/div>/gis,\n \"\"\n );\n\n // Fallback: Target outer y4VEUd vve6Ce wrapper\n cleaned = cleaned.replace(\n /<div[^>]*class=\"[^\"]*y4VEUd vve6Ce[^\"]*\"[^>]*>[\\s\\S]*?<\\/div><\\/div>/gis,\n \"\"\n );\n\n return cleaned;\n }\n\n /**\n * Remove Google Search sidebar from HTML\n */\n removeSidebar(html: string): string {\n let cleaned = html;\n\n // Remove the AI Mode history panel/slide-over\n // Target by aria-label and class\n cleaned = cleaned.replace(\n /<div[^>]*class=\"[^\"]*ho072b[^\"]*\"[^>]*aria-label=\"AI Mode history\"[^>]*>[\\s\\S]*?<\\/div><\\/div><\\/div><\\/div><\\/div><\\/div>/gis,\n \"\"\n );\n\n // Remove the floating action button (FAB) with \"Start new search\" and \"AI Mode history\"\n // Target by jsname and class, contains OEwhSe wrapper\n cleaned = cleaned.replace(\n /<div[^>]*jsname=\"NlVIob\"[^>]*class=\"[^\"]*qEn1od[^\"]*\"[^>]*>[\\s\\S]*?<\\/div><\\/div><\\/div>/gis,\n \"\"\n );\n\n // Fallback: Target by inner class OEwhSe\n cleaned = cleaned.replace(\n /<div[^>]*class=\"[^\"]*OEwhSe[^\"]*\"[^>]*>[\\s\\S]*?<\\/div><\\/div>/gis,\n \"\"\n );\n\n // Fallback: Target buttons with aria-label\n cleaned = cleaned.replace(\n /<button[^>]*aria-label=\"Start new search\"[^>]*>[\\s\\S]*?<\\/button>/gis,\n \"\"\n );\n cleaned = cleaned.replace(\n /<button[^>]*aria-label=\"AI Mode history\"[^>]*>[\\s\\S]*?<\\/button>/gis,\n \"\"\n );\n\n return cleaned;\n }\n\n parse(response: any, options?: ParseOptions): ParsedResponse {\n const { html, text } = this.extractContent(response);\n\n if (!html) {\n throw new Error(\"No HTML content found in AI Mode response\");\n }\n\n let finalHtml = html;\n\n // For AI Mode, default to removing header and footer for cleaner display\n const removeHeader = options?.removeHeader ?? true;\n const removeFooter = options?.removeFooter ?? true;\n\n // Sanitize HTML\n finalHtml = this.sanitizeHtml(finalHtml);\n\n // Remove header if requested\n if (removeHeader) {\n finalHtml = this.removeHeader(finalHtml);\n }\n\n // Remove footer if requested\n if (removeFooter) {\n finalHtml = this.removeFooter(finalHtml);\n }\n\n // Remove sidebar if requested\n if (options?.removeSidebar) {\n finalHtml = this.removeSidebar(finalHtml);\n }\n\n // Remove links if requested\n if (options?.removeLinks) {\n finalHtml = this.removeLinks(finalHtml);\n }\n\n // Build CSS based on options\n let stylesToInject = \"\";\n\n // Always inject general layout\n /* Remove cookie consent banner */\n stylesToInject += `\n .KxvlWc, #CXQnmb {\n display: none !important;\n }\n `;\n\n // Header removal styles\n if (removeHeader) {\n stylesToInject += `\n /* Header hiding */\n header, #header, #searchform, .sfbg, #appbar,\n div[role=\"navigation\"], #leftnav, #sidetogether,\n [role=\"banner\"], .Fgvgjc, #hdtb, .hdtb-msb,\n .DZ13He, .wYq63b, .eT9Cje, .bNg8Rb, .S6VXfe, .Lu57id {\n display: none !important;\n }\n `;\n }\n\n // Sidebar removal styles\n if (options?.removeSidebar) {\n stylesToInject += `\n /* Sidebar hiding */\n #leftnav, #sidetogether {\n display: none !important;\n }\n `;\n }\n\n // Footer removal styles\n if (removeFooter) {\n stylesToInject += `\n /* Footer hiding */\n footer, #footer, .fbar,\n .pdp-nav, [aria-label=\"Main menu\"], .gb_Td, .gb_L {\n display: none !important;\n }\n `;\n }\n\n // Inject base URL and styles\n finalHtml = this.injectStyles(finalHtml, {\n baseUrl: this.baseUrl,\n customCSS: stylesToInject,\n });\n\n return {\n provider: this.name,\n html: finalHtml,\n text,\n metadata: {\n isFullDocument: this.isFullDocument(finalHtml),\n headerRemoved: removeHeader,\n footerRemoved: removeFooter,\n sidebarRemoved: options?.removeSidebar || false,\n linksRemoved: options?.removeLinks || false,\n } as ProviderMetadata,\n };\n }\n}\n","import { BaseProvider } from \"./base-provider\";\nimport {\n AIProvider,\n ParsedResponse,\n ParseOptions,\n ContentExtraction,\n ProviderMetadata,\n} from \"../core/types\";\n\nexport class GrokProvider extends BaseProvider {\n readonly name: AIProvider = \"GROK\";\n readonly baseUrl = \"https://grok.com\";\n\n extractContent(response: any): ContentExtraction {\n return this.extractContentCommon(response);\n }\n\n /**\n * Remove Grok header from HTML (using CSS-based hiding)\n */\n removeHeader(html: string): string {\n // Header removal is now done via CSS in the parse method\n return html;\n }\n\n /**\n * Remove Grok footer/input area from HTML (using CSS-based hiding)\n */\n removeFooter(html: string): string {\n // Footer removal is now done via CSS in the parse method\n return html;\n }\n\n parse(response: any, options?: ParseOptions): ParsedResponse {\n const { html, text } = this.extractContent(response);\n\n if (!html) {\n throw new Error(\"No HTML content found in Grok response\");\n }\n\n let finalHtml = html;\n\n // Sanitize HTML\n finalHtml = this.sanitizeHtml(finalHtml);\n\n // Build CSS based on options\n let stylesToInject = '';\n\n // Header hiding via CSS\n if (options?.removeHeader) {\n stylesToInject += `\n /* Header hiding - hide elements with Grok's header class pattern */\n div[class*=\"h-16\"][class*=\"top-0\"][class*=\"z-10\"],\n div[class*=\"absolute\"][class*=\"inset-x-0\"][class*=\"top-0\"] {\n display: none !important;\n }\n `;\n }\n\n // Footer hiding via CSS\n if (options?.removeFooter) {\n stylesToInject += `\n /* Footer hiding - hide Grok's footer/input area */\n div[class*=\"absolute\"][class*=\"inset-x-0\"][class*=\"bottom-0\"][class*=\"max-w-breakout\"],\n div[class*=\"absolute\"][class*=\"bottom-0\"][class*=\"w-full\"] {\n display: none !important;\n }\n `;\n }\n\n // Remove links if requested\n if (options?.removeLinks) {\n finalHtml = this.removeLinks(finalHtml);\n }\n\n finalHtml = this.injectStyles(finalHtml, {\n baseUrl: this.baseUrl,\n customCSS: stylesToInject,\n });\n\n return {\n provider: this.name,\n html: finalHtml,\n text,\n metadata: {\n isFullDocument: this.isFullDocument(finalHtml),\n linksRemoved: options?.removeLinks || false,\n headerRemoved: options?.removeHeader || false,\n footerRemoved: options?.removeFooter || false,\n } as ProviderMetadata,\n };\n }\n}\n","import { AIProvider, ParsedResponse, ParseOptions, extractContentCommon } from './types';\nimport { ProviderDetector } from './detector';\nimport { ChatGPTProvider } from '../providers/chatgpt';\nimport { GeminiProvider } from '../providers/gemini';\nimport { PerplexityProvider } from '../providers/perplexity';\nimport { CopilotProvider } from '../providers/copilot';\nimport { AIOverviewProvider } from '../providers/ai-overview';\nimport { AIModeProvider } from '../providers/ai-mode';\nimport { GrokProvider } from '../providers/grok';\n\nexport class AIResponseParser {\n private providers: Map<AIProvider, any> = new Map();\n\n constructor() {\n this.providers.set('CHATGPT', new ChatGPTProvider());\n this.providers.set('GEMINI', new GeminiProvider());\n this.providers.set('PERPLEXITY', new PerplexityProvider());\n this.providers.set('COPILOT', new CopilotProvider());\n this.providers.set('AIOVERVIEW', new AIOverviewProvider());\n this.providers.set('AIMODE', new AIModeProvider());\n this.providers.set('GROK', new GrokProvider());\n }\n\n /**\n * Parse an AI response with auto-detected provider\n */\n parse(response: any, options?: ParseOptions): ParsedResponse | null {\n const detection = ProviderDetector.detect(response);\n\n if (!detection) {\n // Try to parse as generic HTML if no provider detected\n return this.parseGeneric(response);\n }\n\n const provider = this.providers.get(detection.provider);\n if (!provider) {\n return null;\n }\n\n try {\n const parsed = provider.parse(response, options);\n return {\n ...parsed,\n metadata: {\n ...parsed.metadata,\n detectionConfidence: detection.confidence,\n },\n };\n } catch (error) {\n console.error(`Failed to parse response with ${detection.provider}:`, error);\n return null;\n }\n }\n\n /**\n * Parse with explicit provider specification\n */\n parseWithProvider(\n response: any,\n provider: AIProvider,\n options?: ParseOptions\n ): ParsedResponse | null {\n const providerInstance = this.providers.get(provider);\n if (!providerInstance) {\n throw new Error(`Unknown provider: ${provider}`);\n }\n\n try {\n return providerInstance.parse(response, options);\n } catch (error) {\n console.error(`Failed to parse response with ${provider}:`, error);\n return null;\n }\n }\n\n /**\n * Detect the provider from a response\n */\n detectProvider(response: any): AIProvider | null {\n const detection = ProviderDetector.detect(response);\n return detection?.provider || null;\n }\n\n /**\n * Get all possible providers with confidence scores\n */\n detectAllProviders(response: any): Array<{ provider: AIProvider; confidence: number }> {\n return ProviderDetector.getAllProviders(response);\n }\n\n /**\n * Parse as generic HTML when no specific provider is detected\n */\n private parseGeneric(response: any): ParsedResponse | null {\n const { html, text } = extractContentCommon(response);\n\n if (!html && !text) {\n return null;\n }\n\n // Basic sanitization\n let sanitizedHtml = html;\n if (sanitizedHtml) {\n sanitizedHtml = sanitizedHtml.replace(/<script\\b[^>]*>[\\s\\S]*?<\\/script>/gim, '');\n sanitizedHtml = sanitizedHtml.replace(/<noscript[\\s\\S]*?<\\/noscript>/gi, '');\n }\n\n return {\n provider: 'CHATGPT' as AIProvider, // Default to ChatGPT for unknown\n html: sanitizedHtml || '',\n text: text || '',\n metadata: {\n isGeneric: true,\n },\n };\n }\n\n /**\n * Get list of supported providers\n */\n getSupportedProviders(): AIProvider[] {\n return Array.from(this.providers.keys());\n }\n\n /**\n * Register a custom provider\n */\n registerProvider(provider: AIProvider, instance: any): void {\n this.providers.set(provider, instance);\n }\n}\n\n// Export a singleton instance\nexport const parser = new AIResponseParser();\n\n// Convenience functions\nexport const parseAiResponse = (response: any, options?: ParseOptions) =>\n parser.parse(response, options);\n\nexport const detectProvider = (response: any) =>\n parser.detectProvider(response);"],"names":["extractContentCommon","response","html","text","dataToCheck","result","trim","startsWith","includes","content","ProviderDetector","detect","scores","CHATGPT","GEMINI","PERPLEXITY","COPILOT","AIOVERVIEW","AIMODE","GROK","provider","patterns","Object","entries","this","PROVIDER_PATTERNS","pattern","_a","maxScore","detectedProvider","score","confidence","values","reduce","a","b","Math","max","getAllProviders","providers","matches","push","length","sort","validate","detected","_b","aioverview","_c","_d","BaseProvider","includeSources","sources","injectStyles","options","styledHtml","baseUrl","replace","styles","customCSS","sanitizeHtml","sanitized","isFullDocument","test","removeLinks","wrapFragment","ChatGPTProvider","constructor","name","extractContent","match","attributes","cleanedAttrs","removeHeader","cleaned","removeSidebar","removeFooter","parse","Error","finalHtml","metadata","headerRemoved","sidebarRemoved","footerRemoved","linksRemoved","GeminiProvider","PerplexityProvider","CopilotProvider","removeCookieBanner","cookieBannerRemoved","AIOverviewProvider","stylesToInject","AIModeProvider","GrokProvider","AIResponseParser","Map","set","detection","parseGeneric","get","parsed","detectionConfidence","error","console","parseWithProvider","providerInstance","detectProvider","detectAllProviders","sanitizedHtml","isGeneric","getSupportedProviders","Array","from","keys","registerProvider","instance","parser","parseAiResponse"],"mappings":"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"}
1
+ {"version":3,"file":"index.esm.js","sources":["../src/core/types.ts","../src/core/detector.ts","../src/providers/base-provider.ts","../src/providers/chatgpt.ts","../src/providers/gemini.ts","../src/providers/perplexity.ts","../src/providers/copilot.ts","../src/providers/ai-overview.ts","../src/providers/ai-mode.ts","../src/providers/grok.ts","../src/core/parser.ts"],"sourcesContent":["export type AIProvider =\n | 'CHATGPT'\n | 'GEMINI'\n | 'PERPLEXITY'\n | 'COPILOT'\n | 'AIOVERVIEW'\n | 'AIMODE'\n | 'GROK';\n\nexport interface ParsedResponse {\n provider: AIProvider;\n html: string;\n text?: string;\n sources?: any[];\n metadata?: Record<string, any>;\n}\n\nexport interface ParseOptions {\n removeLinks?: boolean;\n removeHeader?: boolean;\n removeFooter?: boolean;\n removeSidebar?: boolean;\n removeSources?: boolean;\n}\n\nexport interface ProviderConfig {\n name: AIProvider;\n baseUrl: string;\n}\n\nexport interface DetectedProvider {\n provider: AIProvider;\n confidence: number;\n}\n\nexport interface StyleOptions {\n customCSS?: string;\n hideUI?: boolean;\n baseUrl?: string;\n}\n\nexport type ContentExtraction = {\n html?: string;\n text?: string;\n sources?: any[];\n};\n\n/**\n * Standardized metadata for provider responses\n */\nexport interface ProviderMetadata {\n isFullDocument?: boolean;\n headerRemoved?: boolean;\n footerRemoved?: boolean;\n sidebarRemoved?: boolean;\n linksRemoved?: boolean;\n cookieBannerRemoved?: boolean;\n sourcesRemoved?: boolean;\n detectionConfidence?: number;\n}\n\n/**\n * Common content extraction utility - shared across providers and parser\n */\nexport function extractContentCommon(response: any): ContentExtraction {\n let html = '';\n let text = '';\n\n // Handle nested structure\n let dataToCheck = response;\n if (response.result) {\n dataToCheck = response.result;\n }\n\n // Extract content\n if (typeof dataToCheck === 'string') {\n if (dataToCheck.trim().startsWith('<') && dataToCheck.includes('>')) {\n html = dataToCheck;\n } else {\n text = dataToCheck;\n }\n } else if (typeof dataToCheck === 'object' && dataToCheck !== null) {\n if (dataToCheck.html) {\n html = dataToCheck.html;\n } else if (dataToCheck.content) {\n if (dataToCheck.content.trim().startsWith('<')) {\n html = dataToCheck.content;\n } else {\n text = dataToCheck.content;\n }\n } else if (dataToCheck.text) {\n text = dataToCheck.text;\n }\n }\n\n return { html, text };\n}","import { AIProvider, DetectedProvider } from './types';\n\nexport class ProviderDetector {\n private static readonly PROVIDER_PATTERNS = {\n CHATGPT: [\n // Check for token-based CSS classes\n (response: any) => {\n const html = response?.result?.html || response?.html || '';\n return html.includes('bg-token-bg-primary') || html.includes('text-token-text-secondary');\n },\n // Check for OpenAI-specific patterns\n (response: any) => {\n const html = response?.result?.html || response?.html || '';\n return html.includes('chatgpt.com') || html.includes('openai.com');\n },\n ],\n GEMINI: [\n // Check for Material Design components\n (response: any) => {\n const html = response?.result?.html || response?.html || '';\n return html.includes('bard-sidenav') || html.includes('mat-sidenav');\n },\n // Check for Gemini-specific classes\n (response: any) => {\n const html = response?.result?.html || response?.html || '';\n return html.includes('gemini.google.com') || html.includes('gem-sys-color');\n },\n ],\n PERPLEXITY: [\n // Check for Perplexity domain\n (response: any) => {\n const html = response?.result?.html || response?.html || '';\n return html.includes('perplexity.ai');\n },\n // Check for Perplexity-specific structure\n (response: any) => {\n const html = response?.result?.html || response?.html || '';\n return html.includes('prose') && !html.includes('grok.com') && !html.includes('chatgpt.com');\n },\n ],\n COPILOT: [\n // Check for Copilot-specific elements\n (response: any) => {\n const html = response?.result?.html || response?.html || '';\n return html.includes('copilot.microsoft.com') || html.includes('data-testid=\"sidebar-container\"');\n },\n ],\n AIOVERVIEW: [\n // Check for AI Overview specific structure\n (response: any) => {\n if (response?.result?.aioverview?.text) return true;\n if (response?.aioverview?.text) return true;\n const html = response?.result?.html || response?.html || '';\n return html.includes('DnVkpd');\n },\n // Check for WIZ_global_data without AI Mode markers\n (response: any) => {\n const html = response?.result?.html || response?.html || '';\n return html.includes('WIZ_global_data') && !html.includes('aim-mars') && !html.includes('ho072b');\n },\n ],\n AIMODE: [\n // Check for AI Mode specific elements\n (response: any) => {\n const html = response?.result?.html || response?.html || '';\n return html.includes('DZ13He') || html.includes('wYq63b') || html.includes('AI Mode');\n },\n // Check for AI Mode specific input/sidebar\n (response: any) => {\n const html = response?.result?.html || response?.html || '';\n return html.includes('aim-mars') || html.includes('ho072b');\n },\n ],\n GROK: [\n // Check for Grok domain\n (response: any) => {\n const html = response?.result?.html || response?.html || '';\n return html.includes('grok.com') || html.includes('x.ai');\n },\n // Check for Grok CDN or app-specific patterns\n (response: any) => {\n const html = response?.result?.html || response?.html || '';\n return html.includes('cdn.grok.com') || html.includes('vaul-drawer');\n },\n ],\n };\n\n /**\n * Detect the AI provider from the response\n */\n static detect(response: any): DetectedProvider | null {\n const scores: Record<AIProvider, number> = {\n CHATGPT: 0,\n GEMINI: 0,\n PERPLEXITY: 0,\n COPILOT: 0,\n AIOVERVIEW: 0,\n AIMODE: 0,\n GROK: 0,\n };\n\n // Score each provider based on pattern matches\n for (const [provider, patterns] of Object.entries(this.PROVIDER_PATTERNS)) {\n for (const pattern of patterns) {\n try {\n if (pattern(response)) {\n scores[provider as AIProvider]++;\n }\n } catch {\n // Ignore pattern errors\n }\n }\n }\n\n // Find the provider with the highest score\n let maxScore = 0;\n let detectedProvider: AIProvider | null = null;\n\n for (const [provider, score] of Object.entries(scores)) {\n if (score > maxScore) {\n maxScore = score;\n detectedProvider = provider as AIProvider;\n }\n }\n\n // Return null if no patterns matched\n if (maxScore === 0) return null;\n\n return {\n provider: detectedProvider!,\n confidence: maxScore / Object.values(scores).reduce((a, b) => Math.max(a, b), 1),\n };\n }\n\n /**\n * Get all possible providers with their confidence scores\n */\n static getAllProviders(response: any): DetectedProvider[] {\n const providers: DetectedProvider[] = [];\n\n for (const [provider, patterns] of Object.entries(this.PROVIDER_PATTERNS)) {\n let matches = 0;\n for (const pattern of patterns) {\n try {\n if (pattern(response)) {\n matches++;\n }\n } catch {\n // Ignore pattern errors\n }\n }\n\n if (matches > 0) {\n providers.push({\n provider: provider as AIProvider,\n confidence: matches / patterns.length,\n });\n }\n }\n\n // Sort by confidence (highest first)\n return providers.sort((a, b) => b.confidence - a.confidence);\n }\n\n /**\n * Validate if a detected provider is likely correct\n */\n static validate(response: any, provider: AIProvider): boolean {\n const detected = this.detect(response);\n return detected?.provider === provider && detected.confidence > 0.5;\n }\n}","import { AIProvider, ParsedResponse, ParseOptions, StyleOptions, ContentExtraction, extractContentCommon } from '../core/types';\n\nexport abstract class BaseProvider {\n abstract readonly name: AIProvider;\n abstract readonly baseUrl: string;\n\n /**\n * Parse an AI response and return structured content\n */\n abstract parse(response: any, options?: ParseOptions): ParsedResponse;\n\n /**\n * Extract content from the response object\n */\n abstract extractContent(response: any): ContentExtraction;\n\n /**\n * Common content extraction logic - can be used by providers\n */\n protected extractContentCommon(response: any, includeSources = false): ContentExtraction {\n const result = extractContentCommon(response);\n\n if (includeSources) {\n let sources: any[] = [];\n const dataToCheck = response.result || response;\n\n if (typeof dataToCheck === 'object' && dataToCheck !== null) {\n if (dataToCheck.aioverview?.sources) {\n sources = dataToCheck.aioverview.sources;\n } else if (dataToCheck.sources) {\n sources = dataToCheck.sources;\n }\n }\n\n return { ...result, sources };\n }\n\n return result;\n }\n\n /**\n * Inject provider-specific styles into HTML\n */\n injectStyles(html: string, options?: StyleOptions): string {\n let styledHtml = html;\n\n // Inject base URL if not already present\n if (options?.baseUrl && !html.includes('<base ')) {\n if (styledHtml.includes('<head>')) {\n styledHtml = styledHtml.replace(\n '<head>',\n `<head><base href=\"${options.baseUrl}\">`,\n );\n } else {\n styledHtml = styledHtml.replace(\n /(<html[^>]*>)/i,\n `$1<head><base href=\"${options.baseUrl}\"></head>`,\n );\n }\n }\n\n // Inject styles only if customCSS is provided\n const styles = options?.customCSS || '';\n\n if (styles && styledHtml.includes('<head>')) {\n styledHtml = styledHtml.replace('<head>', `<head><style>${styles}</style>`);\n } else if (styles) {\n styledHtml = styledHtml.replace(\n /(<html[^>]*>)/i,\n `$1<head><style>${styles}</style></head>`,\n );\n }\n\n return styledHtml;\n }\n\n /**\n * Sanitize HTML content\n */\n sanitizeHtml(html: string): string {\n // Remove scripts\n let sanitized = html.replace(/<script\\b[^>]*>[\\s\\S]*?<\\/script>/gim, '');\n\n // Remove noscript tags\n sanitized = sanitized.replace(/<noscript[\\s\\S]*?<\\/noscript>/gi, '');\n\n return sanitized;\n }\n\n /**\n * Check if content is a full HTML document\n */\n isFullDocument(html: string): boolean {\n return /^\\s*(<html|<!DOCTYPE)/i.test(html);\n }\n\n /**\n * Remove all links from HTML, keeping the text content\n */\n removeLinks(html: string): string {\n // Replace anchor tags with their text content\n return html.replace(/<a\\b[^>]*>([\\s\\S]*?)<\\/a>/gim, '$1');\n }\n\n /**\n * Wrap HTML fragment in a document\n */\n wrapFragment(html: string): string {\n return `<!DOCTYPE html>\n<html>\n<head>\n <meta charset=\"utf-8\">\n <meta http-equiv=\"Content-Security-Policy\" content=\"default-src 'none'; script-src 'none'; style-src 'unsafe-inline';\">\n <style>\n body {\n margin: 0;\n padding: 16px;\n font-family: system-ui, -apple-system, sans-serif;\n white-space: pre-wrap;\n word-wrap: break-word;\n }\n img { max-width: 100%; height: auto; }\n body {\n pointer-events: none;\n user-select: none;\n }\n </style>\n</head>\n<body>\n ${html}\n</body>\n</html>`;\n }\n}","import { BaseProvider } from \"./base-provider\";\nimport {\n AIProvider,\n ParsedResponse,\n ParseOptions,\n ContentExtraction,\n ProviderMetadata,\n} from \"../core/types\";\n\nexport class ChatGPTProvider extends BaseProvider {\n readonly name: AIProvider = \"CHATGPT\";\n readonly baseUrl = \"https://chatgpt.com\";\n\n\n extractContent(response: any): ContentExtraction {\n return this.extractContentCommon(response);\n }\n\n /**\n * Remove links from HTML, preserving badge styling\n * Converts <a> tags to <span> while keeping class attributes\n */\n removeLinks(html: string): string {\n // Replace anchor tags with span tags, keeping all attributes except href/alt/rel/target\n return html\n .replace(/<a\\b([^>]*)>/gi, (match, attributes) => {\n // Remove link-specific attributes but keep others (class, style, etc.)\n const cleanedAttrs = attributes\n .replace(/\\s+href\\s*=\\s*[\"'][^\"']*[\"']/gi, \"\")\n .replace(/\\s+alt\\s*=\\s*[\"'][^\"']*[\"']/gi, \"\")\n .replace(/\\s+rel\\s*=\\s*[\"'][^\"']*[\"']/gi, \"\")\n .replace(/\\s+target\\s*=\\s*[\"'][^\"']*[\"']/gi, \"\")\n .trim();\n return `<span${cleanedAttrs ? \" \" + cleanedAttrs : \"\"}>`;\n })\n .replace(/<\\/a>/gi, \"</span>\");\n }\n\n /**\n * Remove ChatGPT header from HTML\n */\n removeHeader(html: string): string {\n let cleaned = html;\n\n // Remove page header by id\n cleaned = cleaned.replace(\n /<header[^>]*id=\"page-header\"[^>]*>.*?<\\/header>/gis,\n \"\"\n );\n\n return cleaned;\n }\n\n /**\n * Remove ChatGPT sidebar from HTML\n */\n removeSidebar(html: string): string {\n let cleaned = html;\n\n // Hide Sidebar\n cleaned = cleaned.replace(/<nav[^>]*>.*?<\\/nav>/gis, \"\");\n cleaned = cleaned.replace(\n /<div[^>]*class=\"[^\"]*sidebar[^\"]*\"[^>]*>.*?<\\/div>/gis,\n \"\"\n );\n\n return cleaned;\n }\n\n /**\n * Remove ChatGPT footer/composer from HTML\n */\n removeFooter(html: string): string {\n let cleaned = html;\n\n // Remove the thread-bottom-container (scroll button container)\n cleaned = cleaned.replace(\n /<div[^>]*id=\"thread-bottom-container\"[^>]*>.*?<\\/div><\\/div><\\/div>/gis,\n \"\"\n );\n\n // Remove the entire thread-bottom div (contains composer and inputs)\n cleaned = cleaned.replace(\n /<div[^>]*id=\"thread-bottom\"[^>]*>.*?<\\/div><\\/div><\\/div><\\/div><\\/div>/gis,\n \"\"\n );\n\n // Remove composer leading button (plus button)\n cleaned = cleaned.replace(\n /<div[^>]*class=\"[^\"]*\\[grid-area:leading\\][^\"]*\"[^>]*>.*?<\\/div><\\/div><\\/div>/gis,\n \"\"\n );\n\n // Remove composer footer actions (search button, etc.)\n cleaned = cleaned.replace(\n /<div[^>]*class=\"[^\"]*\\[grid-area:footer\\][^\"]*\"[^>]*>.*?<\\/div><\\/div><\\/div><\\/div><\\/div>/gis,\n \"\"\n );\n\n // Remove composer trailing buttons (dictate, send buttons)\n cleaned = cleaned.replace(\n /<div[^>]*class=\"[^\"]*\\[grid-area:trailing\\][^\"]*\"[^>]*>.*?<\\/div><\\/div><\\/div>/gis,\n \"\"\n );\n\n // Remove disclaimer footer (language-agnostic, targets view-transition-name)\n cleaned = cleaned.replace(\n /<div[^>]*\\[view-transition-name:var\\(--vt-disclaimer\\)\\][^>]*>.*?<\\/div><\\/div>/gis,\n \"\"\n );\n\n return cleaned;\n }\n\n parse(response: any, options?: ParseOptions): ParsedResponse {\n const { html, text } = this.extractContent(response);\n\n if (!html) {\n throw new Error(\"No HTML content found in ChatGPT response\");\n }\n\n let finalHtml = html;\n\n const removeFooter = options?.removeFooter ?? false;\n\n // Sanitize HTML\n finalHtml = this.sanitizeHtml(finalHtml);\n\n // Remove header if requested\n if (options?.removeHeader) {\n finalHtml = this.removeHeader(finalHtml);\n }\n\n // Remove sidebar if requested\n if (options?.removeSidebar) {\n finalHtml = this.removeSidebar(finalHtml);\n }\n\n // Remove footer if requested\n if (removeFooter) {\n finalHtml = this.removeFooter(finalHtml);\n }\n\n // Remove links if requested\n if (options?.removeLinks) {\n finalHtml = this.removeLinks(finalHtml);\n }\n\n finalHtml = this.injectStyles(finalHtml, {\n baseUrl: this.baseUrl,\n customCSS: \"\",\n });\n\n return {\n provider: this.name,\n html: finalHtml,\n text,\n metadata: {\n isFullDocument: this.isFullDocument(finalHtml),\n headerRemoved: options?.removeHeader || false,\n sidebarRemoved: options?.removeSidebar || false,\n footerRemoved: removeFooter,\n linksRemoved: options?.removeLinks || false,\n } as ProviderMetadata,\n };\n }\n}\n","import { BaseProvider } from './base-provider';\nimport { AIProvider, ParsedResponse, ParseOptions, ContentExtraction, ProviderMetadata } from '../core/types';\n\nexport class GeminiProvider extends BaseProvider {\n readonly name: AIProvider = 'GEMINI';\n readonly baseUrl = 'https://gemini.google.com';\n\n\n extractContent(response: any): ContentExtraction {\n return this.extractContentCommon(response, true);\n }\n\n /**\n * Remove Gemini header/navbar from HTML\n */\n removeHeader(html: string): string {\n let cleaned = html;\n\n // Remove the Google navbar with boqOnegoogleliteOgbOneGoogleBar class\n cleaned = cleaned.replace(/<div[^>]*class=\"[^\"]*boqOnegoogleliteOgbOneGoogleBar[^\"]*\"[^>]*>.*?<\\/div><\\/div><\\/div><\\/div>/gis, '');\n\n // Remove side-nav-menu-button (hamburger menu)\n cleaned = cleaned.replace(/<div[^>]*class=\"[^\"]*side-nav-menu-button[^\"]*\"[^>]*>.*?<\\/div>/gis, '');\n\n // Remove top-bar-actions (About Gemini, Gemini App, Subscriptions, For Business links)\n cleaned = cleaned.replace(/<top-bar-actions[^>]*>.*?<\\/top-bar-actions>/gis, '');\n\n // Remove desktop-ogb-buffer\n cleaned = cleaned.replace(/<div[^>]*class=\"[^\"]*desktop-ogb-buffer[^\"]*\"[^>]*><\\/div>/gis, '');\n\n return cleaned;\n }\n\n /**\n * Remove Gemini footer/follow-up input box from HTML\n */\n removeFooter(html: string): string {\n // Remove input-container (text input, upload button, send button, disclaimer)\n return html.replace(/<input-container[^>]*>.*?<\\/input-container>/gis, '');\n }\n\n /**\n * Remove Gemini sidebar from HTML\n */\n removeSidebar(html: string): string {\n // Remove bard-sidenav element\n return html.replace(/<bard-sidenav[^>]*>.*?<\\/bard-sidenav>/gis, '');\n }\n\n /**\n * Remove Gemini sources panel from HTML\n */\n removeSources(html: string): string {\n let cleaned = html;\n\n // Remove the context-sidebar element (contains source cards)\n cleaned = cleaned.replace(/<context-sidebar[^>]*>[\\s\\S]*?<\\/context-sidebar>/gi, '');\n\n // Remove the sources-sidebar-button trigger\n cleaned = cleaned.replace(/<sources-sidebar-button[^>]*>[\\s\\S]*?<\\/sources-sidebar-button>/gi, '');\n\n return cleaned;\n }\n\n parse(response: any, options?: ParseOptions): ParsedResponse {\n const { html, text, sources } = this.extractContent(response);\n\n if (!html) {\n throw new Error('No HTML content found in Gemini response');\n }\n\n let finalHtml = html;\n\n const removeHeader = options?.removeHeader ?? false;\n const removeFooter = options?.removeFooter ?? false;\n\n // Sanitize HTML (remove scripts and noscript)\n finalHtml = this.sanitizeHtml(finalHtml);\n\n // Remove header if requested\n if (removeHeader) {\n finalHtml = this.removeHeader(finalHtml);\n }\n\n // Remove footer if requested\n if (removeFooter) {\n finalHtml = this.removeFooter(finalHtml);\n }\n\n // Remove sidebar if requested\n if (options?.removeSidebar) {\n finalHtml = this.removeSidebar(finalHtml);\n }\n\n // Remove sources panel if requested\n if (options?.removeSources) {\n finalHtml = this.removeSources(finalHtml);\n }\n\n // Remove links if requested\n if (options?.removeLinks) {\n finalHtml = this.removeLinks(finalHtml);\n }\n\n finalHtml = this.injectStyles(finalHtml, {\n baseUrl: this.baseUrl,\n customCSS: '',\n });\n\n return {\n provider: this.name,\n html: finalHtml,\n text,\n sources,\n metadata: {\n isFullDocument: this.isFullDocument(finalHtml),\n headerRemoved: removeHeader,\n footerRemoved: removeFooter,\n sidebarRemoved: options?.removeSidebar || false,\n sourcesRemoved: options?.removeSources || false,\n linksRemoved: options?.removeLinks || false,\n } as ProviderMetadata,\n };\n }\n}","import { BaseProvider } from \"./base-provider\";\nimport {\n AIProvider,\n ParsedResponse,\n ParseOptions,\n ContentExtraction,\n ProviderMetadata,\n} from \"../core/types\";\n\nexport class PerplexityProvider extends BaseProvider {\n readonly name: AIProvider = \"PERPLEXITY\";\n readonly baseUrl = \"https://www.perplexity.ai\";\n\n extractContent(response: any): ContentExtraction {\n return this.extractContentCommon(response);\n }\n\n /**\n * Remove Perplexity header/navbar from HTML\n */\n removeHeader(html: string): string {\n // Remove navbar by targeting the unique @container/header class\n // Matches from the navbar opening div through the border divider at the bottom\n return html.replace(\n /<div[^>]*class=\"[^\"]*@container\\/header[^\"]*\"[^>]*>.*?<div[^>]*class=\"[^\"]*absolute bottom-0 inset-x-0 border-b[^\"]*\"[^>]*><\\/div>/gis,\n \"\"\n );\n }\n\n /**\n * Remove Perplexity footer/followup input from HTML\n */\n removeFooter(html: string): string {\n let cleaned = html;\n const regex =\n /<div[^>]*class=\"[^\"]*erp-sidecar:fixed erp-sidecar:w-full bottom-safeAreaInsetBottom p-md pointer-events-none z-10 absolute border-subtlest ring-subtlest divide-subtlest bg-transparent[^\"]*\"[^>]*>[\\s\\S]*?(?=<div[^>]*class=\"[^\"]*fixed inset-y-0 right-0[^\"]*\")/gis;\n cleaned = cleaned.replace(regex, \"\");\n return cleaned;\n }\n\n /**\n * Remove Perplexity sources panel from HTML\n */\n removeSources(html: string): string {\n // Remove the fixed right-side sources panel (contains citations/links and cookie dialog)\n return html.replace(/<div[^>]*class=\"[^\"]*fixed inset-y-0 right-0[^\"]*\"[^>]*>[\\s\\S]*?(?=<span[^>]*data-radix-focus-guard)/gi, '');\n }\n\n parse(response: any, options?: ParseOptions): ParsedResponse {\n const { html, text } = this.extractContent(response);\n\n if (!html) {\n throw new Error(\"No HTML content found in Perplexity response\");\n }\n\n let finalHtml = html;\n\n const removeHeader = options?.removeHeader ?? false;\n const removeFooter = options?.removeFooter ?? false;\n\n // Sanitize HTML\n finalHtml = this.sanitizeHtml(finalHtml);\n\n // Fix collapsed answer container: Perplexity uses JS animation to expand the\n // answer area from height:48px. Without scripts, it stays collapsed.\n finalHtml = finalHtml.replace(\n /style=\"transition: none; overflow: hidden; height: 48px;\"/gi,\n ''\n );\n\n // Remove header if requested\n if (removeHeader) {\n finalHtml = this.removeHeader(finalHtml);\n }\n\n // Remove footer if requested\n if (removeFooter) {\n finalHtml = this.removeFooter(finalHtml);\n }\n\n // Remove sources panel if requested\n if (options?.removeSources) {\n finalHtml = this.removeSources(finalHtml);\n }\n\n // Remove links if requested\n if (options?.removeLinks) {\n finalHtml = this.removeLinks(finalHtml);\n }\n\n // Always hide cookie consent banner via CSS\n const customCSS = `\n #cookie-consent,\n [role=\"dialog\"]:has(#cookie-consent) {\n display: none !important;\n }\n `;\n\n finalHtml = this.injectStyles(finalHtml, {\n baseUrl: this.baseUrl,\n customCSS,\n });\n\n return {\n provider: this.name,\n html: finalHtml,\n text,\n metadata: {\n isFullDocument: this.isFullDocument(finalHtml),\n linksRemoved: options?.removeLinks || false,\n headerRemoved: removeHeader,\n footerRemoved: removeFooter,\n cookieBannerRemoved: true,\n sourcesRemoved: options?.removeSources || false,\n } as ProviderMetadata,\n };\n }\n}\n","import { BaseProvider } from './base-provider';\nimport { AIProvider, ParsedResponse, ParseOptions, ContentExtraction, ProviderMetadata } from '../core/types';\n\nexport class CopilotProvider extends BaseProvider {\n readonly name: AIProvider = 'COPILOT';\n readonly baseUrl = 'https://copilot.microsoft.com';\n\n\n extractContent(response: any): ContentExtraction {\n return this.extractContentCommon(response);\n }\n\n /**\n * Remove Copilot header/navbar from HTML\n */\n removeHeader(html: string): string {\n let cleaned = html;\n\n // Remove backstage-chats (hidden navbar element)\n cleaned = cleaned.replace(/<div[^>]*class=\"[^\"]*relative shrink-0 min-h-14[^\"]*\"[^>]*data-testid=\"backstage-chats\"[^>]*>.*?<\\/div>/gis, '');\n\n // Remove date divider (e.g., \"Today\" with horizontal line)\n cleaned = cleaned.replace(/<div[^>]*class=\"[^\"]*flex items-center px-6 mx-auto w-full max-w-chat[^\"]*\"[^>]*>.*?<span[^>]*data-testid=\"date-divider\"[^>]*>.*?<\\/span>.*?<div[^>]*class=\"[^\"]*border-t-\\[1px\\][^\"]*\"[^>]*>.*?<\\/div>.*?<\\/div>/gis, '');\n\n // Remove settings wrapper (share/settings buttons in top-right corner)\n cleaned = cleaned.replace(/<div[^>]*class=\"[^\"]*absolute flex end-6 origin-top-right flex-col items-end[^\"]*\"[^>]*data-testid=\"settings-wrapper\"[^>]*>.*?<\\/div><\\/div>/gis, '');\n\n return cleaned;\n }\n\n /**\n * Remove Copilot footer/followup input box from HTML\n */\n removeFooter(html: string): string {\n let cleaned = html;\n\n // Remove the composer (input box at bottom)\n // Starts with: <div class=\"absolute bottom-0 w-full\">\n // Contains: file input, composer content with textarea, buttons (home, attach, chat mode, audio call)\n cleaned = cleaned.replace(/<div[^>]*class=\"[^\"]*absolute bottom-0 w-full[^\"]*\"[^>]*>.*?<\\/div><\\/div><\\/div><\\/div><\\/div><\\/div><\\/div><\\/div><\\/div><\\/div><\\/div><\\/div>/gis, '');\n\n // Remove spacer div for composer height\n cleaned = cleaned.replace(/<div[^>]*class=\"[^\"]*mt-\\[var\\(--composer-container-height\\)\\][^\"]*\"[^>]*><\\/div>/gis, '');\n\n // Remove \"scroll to bottom\" button (full container with button and inner content)\n cleaned = cleaned.replace(/<div[^>]*class=\"[^\"]*pointer-events-none absolute flex justify-center z-20 inset-x-0 bottom-\\[calc\\(var\\(--composer-container-height\\)\\+1rem\\)\\][^\"]*\"[^>]*>.*?<button[^>]*data-testid=\"scroll-to-bottom-button\"[^>]*>.*?<\\/button><\\/div>/gis, '');\n\n return cleaned;\n }\n\n /**\n * Remove Copilot cookie banner from HTML\n */\n removeCookieBanner(html: string): string {\n let cleaned = html;\n\n // Remove cookie banner by id\n cleaned = cleaned.replace(/<div[^>]*id=\"cookie-banner\"[^>]*>.*?<\\/div>.*?<\\/div>.*?<\\/div>.*?<\\/div>/gis, '');\n\n // Remove cookie banner by max-w-cookie-banner class (outer container)\n cleaned = cleaned.replace(/<div[^>]*class=\"[^\"]*max-w-cookie-banner[^\"]*\"[^>]*>.*?<\\/div>.*?<\\/div>.*?<\\/div>.*?<\\/div>/gis, '');\n\n return cleaned;\n }\n\n /**\n * Remove Copilot sources/references panel from HTML\n */\n removeSources(html: string): string {\n // Remove the references panel (right-side panel with width: 352px containing citations)\n return html.replace(/<div[^>]*class=\"[^\"]*relative h-full overflow-hidden will-change-auto[^\"]*\"[^>]*style=\"[^\"]*width:\\s*352px[^\"]*\"[^>]*>[\\s\\S]*?(?=<div[^>]*class=\"[^\"]*pointer-events-none fixed[^\"]*\")/gi, '');\n }\n\n /**\n * Remove Copilot sidebar from HTML\n */\n removeSidebar(html: string): string {\n let cleaned = html;\n\n // Remove the sidebar container (everything between bg-sidebar-light wrapper and <main>)\n // Handles both old layout (absolute h-full w-0) and new layout (flex h-full overflow-hidden bg-sidebar-light)\n cleaned = cleaned.replace(/<div[^>]*class=\"[^\"]*bg-sidebar-light[^\"]*\"[^>]*>[\\s\\S]*?(?=<main)/gi, '');\n\n return cleaned;\n }\n\n parse(response: any, options?: ParseOptions): ParsedResponse {\n const { html, text } = this.extractContent(response);\n\n if (!html) {\n throw new Error('No HTML content found in Copilot response');\n }\n\n let finalHtml = html;\n\n const removeHeader = options?.removeHeader ?? false;\n const removeFooter = options?.removeFooter ?? false;\n\n // Sanitize HTML\n finalHtml = this.sanitizeHtml(finalHtml);\n\n // Remove cookie banner (always)\n finalHtml = this.removeCookieBanner(finalHtml);\n\n // Remove header if requested\n if (removeHeader) {\n finalHtml = this.removeHeader(finalHtml);\n }\n\n // Remove footer if requested\n if (removeFooter) {\n finalHtml = this.removeFooter(finalHtml);\n }\n\n // Remove sidebar if requested\n if (options?.removeSidebar) {\n finalHtml = this.removeSidebar(finalHtml);\n }\n\n // Remove sources/references panel if requested\n if (options?.removeSources) {\n finalHtml = this.removeSources(finalHtml);\n }\n\n // Remove links if requested\n if (options?.removeLinks) {\n finalHtml = this.removeLinks(finalHtml);\n }\n\n finalHtml = this.injectStyles(finalHtml, {\n baseUrl: this.baseUrl,\n customCSS: '',\n });\n\n return {\n provider: this.name,\n html: finalHtml,\n text,\n metadata: {\n isFullDocument: this.isFullDocument(finalHtml),\n cookieBannerRemoved: true,\n headerRemoved: removeHeader,\n footerRemoved: removeFooter,\n sidebarRemoved: options?.removeSidebar || false,\n sourcesRemoved: options?.removeSources || false,\n linksRemoved: options?.removeLinks || false,\n } as ProviderMetadata,\n };\n }\n}","import { BaseProvider } from \"./base-provider\";\nimport {\n AIProvider,\n ParsedResponse,\n ParseOptions,\n ContentExtraction,\n ProviderMetadata,\n} from \"../core/types\";\n\nexport class AIOverviewProvider extends BaseProvider {\n readonly name: AIProvider = \"AIOVERVIEW\";\n readonly baseUrl = \"https://www.google.com\";\n\n extractContent(response: any): ContentExtraction {\n return this.extractContentCommon(response, true);\n }\n\n /**\n * Remove Google Search header/navbar from HTML\n */\n removeHeader(html: string): string {\n // Remove header elements via CSS injection\n return html;\n }\n\n /**\n * Remove Google Search footer from HTML\n */\n removeFooter(html: string): string {\n // Remove footer elements via CSS injection\n return html;\n }\n\n /**\n * Remove Google Search sidebar from HTML\n */\n removeSidebar(html: string): string {\n // Remove sidebar elements via CSS injection\n return html;\n }\n\n parse(response: any, options?: ParseOptions): ParsedResponse {\n const { html, sources } = this.extractContent(response);\n\n if (!html) {\n throw new Error(\"No HTML content found in AI Overview response\");\n }\n\n let finalHtml = html;\n\n // For AI Overview, default to removing header and footer for cleaner display\n const removeHeader = options?.removeHeader ?? true;\n const removeFooter = options?.removeFooter ?? true;\n\n // Sanitize HTML\n finalHtml = this.sanitizeHtml(finalHtml);\n\n // Remove header if requested\n if (removeHeader) {\n finalHtml = this.removeHeader(finalHtml);\n }\n\n // Remove footer if requested\n if (removeFooter) {\n finalHtml = this.removeFooter(finalHtml);\n }\n\n // Remove sidebar if requested\n if (options?.removeSidebar) {\n finalHtml = this.removeSidebar(finalHtml);\n }\n\n // Remove links if requested\n if (options?.removeLinks) {\n finalHtml = this.removeLinks(finalHtml);\n }\n\n // Build CSS based on options\n let stylesToInject = \"\";\n\n // Header removal styles\n if (removeHeader) {\n stylesToInject += `\n /* Header hiding */\n header, #header, #searchform, .sfbg, #appbar,\n div[role=\"navigation\"], #leftnav, #sidetogether,\n [role=\"banner\"], .Fgvgjc, #hdtb, .hdtb-msb,\n .DZ13He, .wYq63b, .eT9Cje, .bNg8Rb, .S6VXfe, .Lu57id {\n display: none !important;\n }\n `;\n }\n\n // Sidebar removal styles\n if (options?.removeSidebar) {\n stylesToInject += `\n /* Sidebar hiding */\n #leftnav, #sidetogether {\n display: none !important;\n }\n `;\n }\n\n // Footer removal styles\n if (removeFooter) {\n stylesToInject += `\n /* Footer hiding */\n footer, #footer, .fbar,\n .pdp-nav, [aria-label=\"Main menu\"], .gb_Td, .gb_L {\n display: none !important;\n }\n `;\n }\n\n // Inject base URL and styles\n finalHtml = this.injectStyles(finalHtml, {\n baseUrl: this.baseUrl,\n customCSS: stylesToInject,\n });\n\n return {\n provider: this.name,\n html: finalHtml,\n sources,\n metadata: {\n isFullDocument: this.isFullDocument(finalHtml),\n headerRemoved: removeHeader,\n footerRemoved: removeFooter,\n sidebarRemoved: options?.removeSidebar || false,\n linksRemoved: options?.removeLinks || false,\n } as ProviderMetadata,\n };\n }\n}\n","import { BaseProvider } from \"./base-provider\";\nimport {\n AIProvider,\n ParsedResponse,\n ParseOptions,\n ContentExtraction,\n ProviderMetadata,\n} from \"../core/types\";\n\nexport class AIModeProvider extends BaseProvider {\n readonly name: AIProvider = \"AIMODE\";\n readonly baseUrl = \"https://www.google.com\";\n\n extractContent(response: any): ContentExtraction {\n return this.extractContentCommon(response);\n }\n\n /**\n * Remove Google Search header/navbar from HTML\n */\n removeHeader(html: string): string {\n let cleaned = html;\n\n // Remove the AI Mode filter/header bar\n // Starts with <div jsname=\"oEQ3x\" class=\"DZ13He YNk70c EjQTId\">\n // Contains the Filters and Topics navigation (AI Mode, All, Images, Videos, News, More)\n // Ends with closing divs after <hr class=\"e9c7U\">\n cleaned = cleaned.replace(\n /<div[^>]*jsname=\"oEQ3x\"[^>]*class=\"[^\"]*DZ13He[^\"]*\"[^>]*>.*?<hr class=\"e9c7U\">.*?<\\/div><\\/div><\\/div><\\/div><\\/div>/gis,\n \"\"\n );\n\n return cleaned;\n }\n\n /**\n * Remove Google Search footer from HTML\n */\n removeFooter(html: string): string {\n let cleaned = html;\n\n // Remove the AI Mode input bar/footer\n // Target the most unique identifier: data-xid=\"aim-mars-input-plate\"\n // This element is deeply nested, so we need to match many closing divs\n cleaned = cleaned.replace(\n /<div[^>]*data-xid=\"aim-mars-input-plate\"[^>]*>[\\s\\S]*?<\\/div><\\/div><\\/div><\\/div><\\/div>/gis,\n \"\"\n );\n\n // Fallback: Target by jscontroller P5gZDb which wraps the input plate\n cleaned = cleaned.replace(\n /<div[^>]*jscontroller=\"P5gZDb\"[^>]*>[\\s\\S]*?<\\/div><\\/div><\\/div>/gis,\n \"\"\n );\n\n // Fallback: Target the t0ITR container\n cleaned = cleaned.replace(\n /<div[^>]*class=\"[^\"]*t0ITR hh3ttd[^\"]*\"[^>]*>[\\s\\S]*?<\\/div><\\/div>/gis,\n \"\"\n );\n\n // Fallback: Target outer y4VEUd vve6Ce wrapper\n cleaned = cleaned.replace(\n /<div[^>]*class=\"[^\"]*y4VEUd vve6Ce[^\"]*\"[^>]*>[\\s\\S]*?<\\/div><\\/div>/gis,\n \"\"\n );\n\n return cleaned;\n }\n\n /**\n * Remove Google Search sidebar from HTML\n */\n removeSidebar(html: string): string {\n let cleaned = html;\n\n // Remove the AI Mode history panel/dialog\n // Target by aria-label (handles both attribute orderings)\n cleaned = cleaned.replace(\n /<div[^>]*aria-label=\"AI Mode history\"[^>]*class=\"[^\"]*ho072b[^\"]*\"[^>]*>[\\s\\S]*?(?=<!--TgQPHd)/gi,\n \"\"\n );\n // Fallback: class before aria-label\n cleaned = cleaned.replace(\n /<div[^>]*class=\"[^\"]*ho072b[^\"]*\"[^>]*aria-label=\"AI Mode history\"[^>]*>[\\s\\S]*?(?=<!--TgQPHd)/gi,\n \"\"\n );\n\n // Remove the floating action buttons (OEwhSe wrapper)\n cleaned = cleaned.replace(\n /<div[^>]*class=\"[^\"]*OEwhSe[^\"]*\"[^>]*>[\\s\\S]*?<\\/div><\\/div>/gis,\n \"\"\n );\n\n // Remove buttons with aria-label\n cleaned = cleaned.replace(\n /<button[^>]*aria-label=\"AI Mode history\"[^>]*>[\\s\\S]*?<\\/button>/gis,\n \"\"\n );\n\n return cleaned;\n }\n\n parse(response: any, options?: ParseOptions): ParsedResponse {\n const { html, text } = this.extractContent(response);\n\n if (!html) {\n throw new Error(\"No HTML content found in AI Mode response\");\n }\n\n let finalHtml = html;\n\n // For AI Mode, default to removing header and footer for cleaner display\n const removeHeader = options?.removeHeader ?? true;\n const removeFooter = options?.removeFooter ?? true;\n\n // Sanitize HTML\n finalHtml = this.sanitizeHtml(finalHtml);\n\n // Remove header if requested\n if (removeHeader) {\n finalHtml = this.removeHeader(finalHtml);\n }\n\n // Remove footer if requested\n if (removeFooter) {\n finalHtml = this.removeFooter(finalHtml);\n }\n\n // Remove sidebar if requested\n if (options?.removeSidebar) {\n finalHtml = this.removeSidebar(finalHtml);\n }\n\n // Remove links if requested\n if (options?.removeLinks) {\n finalHtml = this.removeLinks(finalHtml);\n }\n\n // Build CSS based on options\n let stylesToInject = \"\";\n\n // Always inject general layout\n /* Remove cookie consent banner */\n stylesToInject += `\n .KxvlWc, #CXQnmb {\n display: none !important;\n }\n `;\n\n // Header removal styles\n if (removeHeader) {\n stylesToInject += `\n /* Header hiding */\n header, #header, #searchform, .sfbg, #appbar,\n div[role=\"navigation\"], #leftnav, #sidetogether,\n [role=\"banner\"], .Fgvgjc, #hdtb, .hdtb-msb,\n .DZ13He, .wYq63b, .eT9Cje, .bNg8Rb, .S6VXfe, .Lu57id {\n display: none !important;\n }\n `;\n }\n\n // Footer removal styles\n if (removeFooter) {\n stylesToInject += `\n /* Footer hiding */\n footer, #footer, .fbar,\n .pdp-nav, [aria-label=\"Main menu\"], .gb_Td, .gb_L {\n display: none !important;\n }\n /* Hide the \"Ask anything\" input bar */\n [data-xid=\"aim-mars-input-plate\"],\n .UAbVe, .y4VEUd, .t0ITR.hh3ttd {\n display: none !important;\n }\n `;\n }\n\n // Sidebar removal styles\n if (options?.removeSidebar) {\n stylesToInject += `\n /* Hide AI Mode history panel */\n .ho072b, .OEwhSe, .qEn1od {\n display: none !important;\n }\n `;\n }\n\n // Inject base URL and styles\n finalHtml = this.injectStyles(finalHtml, {\n baseUrl: this.baseUrl,\n customCSS: stylesToInject,\n });\n\n return {\n provider: this.name,\n html: finalHtml,\n text,\n metadata: {\n isFullDocument: this.isFullDocument(finalHtml),\n headerRemoved: removeHeader,\n footerRemoved: removeFooter,\n sidebarRemoved: options?.removeSidebar || false,\n linksRemoved: options?.removeLinks || false,\n } as ProviderMetadata,\n };\n }\n}\n","import { BaseProvider } from \"./base-provider\";\nimport {\n AIProvider,\n ParsedResponse,\n ParseOptions,\n ContentExtraction,\n ProviderMetadata,\n} from \"../core/types\";\n\nexport class GrokProvider extends BaseProvider {\n readonly name: AIProvider = \"GROK\";\n readonly baseUrl = \"https://grok.com\";\n\n extractContent(response: any): ContentExtraction {\n return this.extractContentCommon(response);\n }\n\n /**\n * Remove Grok header from HTML (using CSS-based hiding)\n */\n removeHeader(html: string): string {\n // Header removal is now done via CSS in the parse method\n return html;\n }\n\n /**\n * Remove Grok footer/input area from HTML (using CSS-based hiding)\n */\n removeFooter(html: string): string {\n // Footer removal is now done via CSS in the parse method\n return html;\n }\n\n parse(response: any, options?: ParseOptions): ParsedResponse {\n const { html, text } = this.extractContent(response);\n\n if (!html) {\n throw new Error(\"No HTML content found in Grok response\");\n }\n\n let finalHtml = html;\n\n // Sanitize HTML\n finalHtml = this.sanitizeHtml(finalHtml);\n\n // Build CSS based on options\n let stylesToInject = '';\n\n // Always-on: hide cookie/privacy policy banner (Grok uses data-cookie-banner attribute)\n stylesToInject += `\n [data-cookie-banner],\n [data-cookie-banner=\"true\"] {\n display: none !important;\n }\n `;\n\n // Always-on: hide rate-limit banners and toast notifications\n stylesToInject += `\n [data-sonner-toaster],\n [data-sonner-toast],\n [class*=\"sonner-toast\"] {\n display: none !important;\n }\n `;\n\n // Sources panel removal via regex (CSS selectors don't reliably hide this element)\n if (options?.removeSources) {\n // Remove the sources panel wrapper containing the aside\n finalHtml = finalHtml.replace(/<div[^>]*class=\"[^\"]*h-dvh[^\"]*flex-shrink-0[^\"]*max-w-[^\"]*\"[^>]*>[\\s\\S]*?<\\/aside>[\\s\\S]*?(?=<section)/gi, '');\n\n // Hide the inline \"N sources\" trigger button and vaul-drawer overlay via CSS\n stylesToInject += `\n div[data-state] > div.flex.flex-row.gap-1.items-center.rounded-full.cursor-pointer {\n display: none !important;\n }\n [vaul-drawer][vaul-drawer-direction=\"right\"],\n [vaul-overlay] {\n display: none !important;\n }\n `;\n }\n\n // Header hiding via CSS\n if (options?.removeHeader) {\n stylesToInject += `\n /* Header hiding - hide elements with Grok's header class pattern */\n div[class*=\"h-16\"][class*=\"top-0\"][class*=\"z-10\"],\n div[class*=\"absolute\"][class*=\"inset-x-0\"][class*=\"top-0\"] {\n display: none !important;\n }\n `;\n }\n\n // Footer hiding via CSS\n if (options?.removeFooter) {\n stylesToInject += `\n /* Footer hiding - hide Grok's footer/input area */\n div[class*=\"absolute\"][class*=\"inset-x-0\"][class*=\"bottom-0\"][class*=\"max-w-breakout\"],\n div[class*=\"absolute\"][class*=\"bottom-0\"][class*=\"w-full\"] {\n display: none !important;\n }\n `;\n }\n\n // Remove links if requested\n if (options?.removeLinks) {\n finalHtml = this.removeLinks(finalHtml);\n }\n\n finalHtml = this.injectStyles(finalHtml, {\n baseUrl: this.baseUrl,\n customCSS: stylesToInject,\n });\n\n return {\n provider: this.name,\n html: finalHtml,\n text,\n metadata: {\n isFullDocument: this.isFullDocument(finalHtml),\n linksRemoved: options?.removeLinks || false,\n headerRemoved: options?.removeHeader || false,\n footerRemoved: options?.removeFooter || false,\n cookieBannerRemoved: true,\n sourcesRemoved: options?.removeSources || false,\n } as ProviderMetadata,\n };\n }\n}\n","import { AIProvider, ParsedResponse, ParseOptions, extractContentCommon } from './types';\nimport { ProviderDetector } from './detector';\nimport { ChatGPTProvider } from '../providers/chatgpt';\nimport { GeminiProvider } from '../providers/gemini';\nimport { PerplexityProvider } from '../providers/perplexity';\nimport { CopilotProvider } from '../providers/copilot';\nimport { AIOverviewProvider } from '../providers/ai-overview';\nimport { AIModeProvider } from '../providers/ai-mode';\nimport { GrokProvider } from '../providers/grok';\n\nexport class AIResponseParser {\n private providers: Map<AIProvider, any> = new Map();\n\n constructor() {\n this.providers.set('CHATGPT', new ChatGPTProvider());\n this.providers.set('GEMINI', new GeminiProvider());\n this.providers.set('PERPLEXITY', new PerplexityProvider());\n this.providers.set('COPILOT', new CopilotProvider());\n this.providers.set('AIOVERVIEW', new AIOverviewProvider());\n this.providers.set('AIMODE', new AIModeProvider());\n this.providers.set('GROK', new GrokProvider());\n }\n\n /**\n * Parse an AI response with auto-detected provider\n */\n parse(response: any, options?: ParseOptions): ParsedResponse | null {\n const detection = ProviderDetector.detect(response);\n\n if (!detection) {\n // Try to parse as generic HTML if no provider detected\n return this.parseGeneric(response);\n }\n\n const provider = this.providers.get(detection.provider);\n if (!provider) {\n return null;\n }\n\n try {\n const parsed = provider.parse(response, options);\n return {\n ...parsed,\n metadata: {\n ...parsed.metadata,\n detectionConfidence: detection.confidence,\n },\n };\n } catch (error) {\n console.error(`Failed to parse response with ${detection.provider}:`, error);\n return null;\n }\n }\n\n /**\n * Parse with explicit provider specification\n */\n parseWithProvider(\n response: any,\n provider: AIProvider,\n options?: ParseOptions\n ): ParsedResponse | null {\n const providerInstance = this.providers.get(provider);\n if (!providerInstance) {\n throw new Error(`Unknown provider: ${provider}`);\n }\n\n try {\n return providerInstance.parse(response, options);\n } catch (error) {\n console.error(`Failed to parse response with ${provider}:`, error);\n return null;\n }\n }\n\n /**\n * Detect the provider from a response\n */\n detectProvider(response: any): AIProvider | null {\n const detection = ProviderDetector.detect(response);\n return detection?.provider || null;\n }\n\n /**\n * Get all possible providers with confidence scores\n */\n detectAllProviders(response: any): Array<{ provider: AIProvider; confidence: number }> {\n return ProviderDetector.getAllProviders(response);\n }\n\n /**\n * Parse as generic HTML when no specific provider is detected\n */\n private parseGeneric(response: any): ParsedResponse | null {\n const { html, text } = extractContentCommon(response);\n\n if (!html && !text) {\n return null;\n }\n\n // Basic sanitization\n let sanitizedHtml = html;\n if (sanitizedHtml) {\n sanitizedHtml = sanitizedHtml.replace(/<script\\b[^>]*>[\\s\\S]*?<\\/script>/gim, '');\n sanitizedHtml = sanitizedHtml.replace(/<noscript[\\s\\S]*?<\\/noscript>/gi, '');\n }\n\n return {\n provider: 'CHATGPT' as AIProvider, // Default to ChatGPT for unknown\n html: sanitizedHtml || '',\n text: text || '',\n metadata: {\n isGeneric: true,\n },\n };\n }\n\n /**\n * Get list of supported providers\n */\n getSupportedProviders(): AIProvider[] {\n return Array.from(this.providers.keys());\n }\n\n /**\n * Register a custom provider\n */\n registerProvider(provider: AIProvider, instance: any): void {\n this.providers.set(provider, instance);\n }\n}\n\n// Export a singleton instance\nexport const parser = new AIResponseParser();\n\n// Convenience functions\nexport const parseAiResponse = (response: any, options?: ParseOptions) =>\n parser.parse(response, options);\n\nexport const detectProvider = (response: any) =>\n parser.detectProvider(response);"],"names":["extractContentCommon","response","html","text","dataToCheck","result","trim","startsWith","includes","content","ProviderDetector","detect","scores","CHATGPT","GEMINI","PERPLEXITY","COPILOT","AIOVERVIEW","AIMODE","GROK","provider","patterns","Object","entries","this","PROVIDER_PATTERNS","pattern","_a","maxScore","detectedProvider","score","confidence","values","reduce","a","b","Math","max","getAllProviders","providers","matches","push","length","sort","validate","detected","_b","aioverview","_c","_d","BaseProvider","includeSources","sources","injectStyles","options","styledHtml","baseUrl","replace","styles","customCSS","sanitizeHtml","sanitized","isFullDocument","test","removeLinks","wrapFragment","ChatGPTProvider","constructor","name","extractContent","match","attributes","cleanedAttrs","removeHeader","cleaned","removeSidebar","removeFooter","parse","Error","finalHtml","metadata","headerRemoved","sidebarRemoved","footerRemoved","linksRemoved","GeminiProvider","removeSources","sourcesRemoved","PerplexityProvider","cookieBannerRemoved","CopilotProvider","removeCookieBanner","AIOverviewProvider","stylesToInject","AIModeProvider","GrokProvider","AIResponseParser","Map","set","detection","parseGeneric","get","parsed","detectionConfidence","error","console","parseWithProvider","providerInstance","detectProvider","detectAllProviders","sanitizedHtml","isGeneric","getSupportedProviders","Array","from","keys","registerProvider","instance","parser","parseAiResponse"],"mappings":"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"}
package/dist/index.js CHANGED
@@ -1,2 +1,2 @@
1
- "use strict";function e(e){let t="",r="",i=e;return e.result&&(i=e.result),"string"==typeof i?i.trim().startsWith("<")&&i.includes(">")?t=i:r=i:"object"==typeof i&&null!==i&&(i.html?t=i.html:i.content?i.content.trim().startsWith("<")?t=i.content:r=i.content:i.text&&(r=i.text)),{html:t,text:r}}class t{static detect(e){const t={CHATGPT:0,GEMINI:0,PERPLEXITY:0,COPILOT:0,AIOVERVIEW:0,AIMODE:0,GROK:0};for(const[r,i]of Object.entries(this.PROVIDER_PATTERNS))for(const o of i)try{o(e)&&t[r]++}catch(e){}let r=0,i=null;for(const[e,o]of Object.entries(t))o>r&&(r=o,i=e);return 0===r?null:{provider:i,confidence:r/Object.values(t).reduce((e,t)=>Math.max(e,t),1)}}static getAllProviders(e){const t=[];for(const[r,i]of Object.entries(this.PROVIDER_PATTERNS)){let o=0;for(const t of i)try{t(e)&&o++}catch(e){}o>0&&t.push({provider:r,confidence:o/i.length})}return t.sort((e,t)=>t.confidence-e.confidence)}static validate(e,t){const r=this.detect(e);return(null==r?void 0:r.provider)===t&&r.confidence>.5}}t.PROVIDER_PATTERNS={CHATGPT:[e=>{var t;const r=(null===(t=null==e?void 0:e.result)||void 0===t?void 0:t.html)||(null==e?void 0:e.html)||"";return r.includes("bg-token-bg-primary")||r.includes("text-token-text-secondary")},e=>{var t;const r=(null===(t=null==e?void 0:e.result)||void 0===t?void 0:t.html)||(null==e?void 0:e.html)||"";return r.includes("chatgpt.com")||r.includes("openai.com")}],GEMINI:[e=>{var t;const r=(null===(t=null==e?void 0:e.result)||void 0===t?void 0:t.html)||(null==e?void 0:e.html)||"";return r.includes("bard-sidenav")||r.includes("mat-sidenav")},e=>{var t;const r=(null===(t=null==e?void 0:e.result)||void 0===t?void 0:t.html)||(null==e?void 0:e.html)||"";return r.includes("gemini.google.com")||r.includes("gem-sys-color")}],PERPLEXITY:[e=>{var t;const r=(null===(t=null==e?void 0:e.result)||void 0===t?void 0:t.html)||(null==e?void 0:e.html)||"";return r.includes("perplexity.ai")||r.includes("prose")}],COPILOT:[e=>{var t;const r=(null===(t=null==e?void 0:e.result)||void 0===t?void 0:t.html)||(null==e?void 0:e.html)||"";return r.includes("copilot.microsoft.com")||r.includes('data-testid="sidebar-container"')}],AIOVERVIEW:[e=>{var t,r,i,o;if(null===(r=null===(t=null==e?void 0:e.result)||void 0===t?void 0:t.aioverview)||void 0===r?void 0:r.text)return!0;if(null===(i=null==e?void 0:e.aioverview)||void 0===i?void 0:i.text)return!0;const n=(null===(o=null==e?void 0:e.result)||void 0===o?void 0:o.html)||(null==e?void 0:e.html)||"";return n.includes("WIZ_global_data")||n.includes("DnVkpd")}],AIMODE:[e=>{var t;const r=(null===(t=null==e?void 0:e.result)||void 0===t?void 0:t.html)||(null==e?void 0:e.html)||"";return r.includes("DZ13He")||r.includes("wYq63b")||r.includes("AI Mode")}],GROK:[e=>{var t;const r=(null===(t=null==e?void 0:e.result)||void 0===t?void 0:t.html)||(null==e?void 0:e.html)||"";return r.includes("grok.com")||r.includes("x.ai")}]};class r{extractContentCommon(t,r=!1){var i;const o=e(t);if(r){let e=[];const r=t.result||t;return"object"==typeof r&&null!==r&&((null===(i=r.aioverview)||void 0===i?void 0:i.sources)?e=r.aioverview.sources:r.sources&&(e=r.sources)),{...o,sources:e}}return o}injectStyles(e,t){let r=e;(null==t?void 0:t.baseUrl)&&!e.includes("<base ")&&(r=r.includes("<head>")?r.replace("<head>",`<head><base href="${t.baseUrl}">`):r.replace(/(<html[^>]*>)/i,`$1<head><base href="${t.baseUrl}"></head>`));const i=(null==t?void 0:t.customCSS)||"";return i&&r.includes("<head>")?r=r.replace("<head>",`<head><style>${i}</style>`):i&&(r=r.replace(/(<html[^>]*>)/i,`$1<head><style>${i}</style></head>`)),r}sanitizeHtml(e){let t=e.replace(/<script\b[^>]*>[\s\S]*?<\/script>/gim,"");return t=t.replace(/<noscript[\s\S]*?<\/noscript>/gi,""),t}isFullDocument(e){return/^\s*(<html|<!DOCTYPE)/i.test(e)}removeLinks(e){return e.replace(/<a\b[^>]*>([\s\S]*?)<\/a>/gim,"$1")}wrapFragment(e){return`<!DOCTYPE html>\n<html>\n<head>\n <meta charset="utf-8">\n <meta http-equiv="Content-Security-Policy" content="default-src 'none'; script-src 'none'; style-src 'unsafe-inline';">\n <style>\n body {\n margin: 0;\n padding: 16px;\n font-family: system-ui, -apple-system, sans-serif;\n white-space: pre-wrap;\n word-wrap: break-word;\n }\n img { max-width: 100%; height: auto; }\n body {\n pointer-events: none;\n user-select: none;\n }\n </style>\n</head>\n<body>\n ${e}\n</body>\n</html>`}}class i extends r{constructor(){super(...arguments),this.name="CHATGPT",this.baseUrl="https://chatgpt.com"}extractContent(e){return this.extractContentCommon(e)}removeLinks(e){return e.replace(/<a\b([^>]*)>/gi,(e,t)=>{const r=t.replace(/\s+href\s*=\s*["'][^"']*["']/gi,"").replace(/\s+alt\s*=\s*["'][^"']*["']/gi,"").replace(/\s+rel\s*=\s*["'][^"']*["']/gi,"").replace(/\s+target\s*=\s*["'][^"']*["']/gi,"").trim();return`<span${r?" "+r:""}>`}).replace(/<\/a>/gi,"</span>")}removeHeader(e){let t=e;return t=t.replace(/<header[^>]*id="page-header"[^>]*>.*?<\/header>/gis,""),t}removeSidebar(e){let t=e;return t=t.replace(/<nav[^>]*>.*?<\/nav>/gis,""),t=t.replace(/<div[^>]*class="[^"]*sidebar[^"]*"[^>]*>.*?<\/div>/gis,""),t}removeFooter(e){let t=e;return t=t.replace(/<div[^>]*id="thread-bottom-container"[^>]*>.*?<\/div><\/div><\/div>/gis,""),t=t.replace(/<div[^>]*id="thread-bottom"[^>]*>.*?<\/div><\/div><\/div><\/div><\/div>/gis,""),t=t.replace(/<div[^>]*class="[^"]*\[grid-area:leading\][^"]*"[^>]*>.*?<\/div><\/div><\/div>/gis,""),t=t.replace(/<div[^>]*class="[^"]*\[grid-area:footer\][^"]*"[^>]*>.*?<\/div><\/div><\/div><\/div><\/div>/gis,""),t=t.replace(/<div[^>]*class="[^"]*\[grid-area:trailing\][^"]*"[^>]*>.*?<\/div><\/div><\/div>/gis,""),t=t.replace(/<div[^>]*\[view-transition-name:var\(--vt-disclaimer\)\][^>]*>.*?<\/div><\/div>/gis,""),t}parse(e,t){var r;const{html:i,text:o}=this.extractContent(e);if(!i)throw new Error("No HTML content found in ChatGPT response");let n=i;const s=null!==(r=null==t?void 0:t.removeFooter)&&void 0!==r&&r;return n=this.sanitizeHtml(n),(null==t?void 0:t.removeHeader)&&(n=this.removeHeader(n)),(null==t?void 0:t.removeSidebar)&&(n=this.removeSidebar(n)),s&&(n=this.removeFooter(n)),(null==t?void 0:t.removeLinks)&&(n=this.removeLinks(n)),n=this.injectStyles(n,{baseUrl:this.baseUrl,customCSS:""}),{provider:this.name,html:n,text:o,metadata:{isFullDocument:this.isFullDocument(n),headerRemoved:(null==t?void 0:t.removeHeader)||!1,sidebarRemoved:(null==t?void 0:t.removeSidebar)||!1,footerRemoved:s,linksRemoved:(null==t?void 0:t.removeLinks)||!1}}}}class o extends r{constructor(){super(...arguments),this.name="GEMINI",this.baseUrl="https://gemini.google.com"}extractContent(e){return this.extractContentCommon(e,!0)}removeHeader(e){let t=e;return t=t.replace(/<div[^>]*class="[^"]*boqOnegoogleliteOgbOneGoogleBar[^"]*"[^>]*>.*?<\/div><\/div><\/div><\/div>/gis,""),t=t.replace(/<div[^>]*class="[^"]*side-nav-menu-button[^"]*"[^>]*>.*?<\/div>/gis,""),t=t.replace(/<top-bar-actions[^>]*>.*?<\/top-bar-actions>/gis,""),t=t.replace(/<div[^>]*class="[^"]*desktop-ogb-buffer[^"]*"[^>]*><\/div>/gis,""),t}removeFooter(e){return e.replace(/<input-container[^>]*>.*?<\/input-container>/gis,"")}removeSidebar(e){return e.replace(/<bard-sidenav[^>]*>.*?<\/bard-sidenav>/gis,"")}parse(e,t){var r,i;const{html:o,text:n,sources:s}=this.extractContent(e);if(!o)throw new Error("No HTML content found in Gemini response");let l=o;const d=null!==(r=null==t?void 0:t.removeHeader)&&void 0!==r&&r,a=null!==(i=null==t?void 0:t.removeFooter)&&void 0!==i&&i;return l=this.sanitizeHtml(l),d&&(l=this.removeHeader(l)),a&&(l=this.removeFooter(l)),(null==t?void 0:t.removeSidebar)&&(l=this.removeSidebar(l)),(null==t?void 0:t.removeLinks)&&(l=this.removeLinks(l)),l=this.injectStyles(l,{baseUrl:this.baseUrl,customCSS:""}),{provider:this.name,html:l,text:n,sources:s,metadata:{isFullDocument:this.isFullDocument(l),headerRemoved:d,footerRemoved:a,sidebarRemoved:(null==t?void 0:t.removeSidebar)||!1,linksRemoved:(null==t?void 0:t.removeLinks)||!1}}}}class n extends r{constructor(){super(...arguments),this.name="PERPLEXITY",this.baseUrl="https://www.perplexity.ai"}extractContent(e){return this.extractContentCommon(e)}removeHeader(e){return e.replace(/<div[^>]*class="[^"]*@container\/header[^"]*"[^>]*>.*?<div[^>]*class="[^"]*absolute bottom-0 inset-x-0 border-b[^"]*"[^>]*><\/div>/gis,"")}removeFooter(e){let t=e;return t=t.replace(/<div[^>]*class="[^"]*erp-sidecar:fixed erp-sidecar:w-full bottom-safeAreaInsetBottom p-md pointer-events-none z-10 absolute border-subtlest ring-subtlest divide-subtlest bg-transparent[^"]*"[^>]*>[\s\S]*?(?=<div[^>]*class="[^"]*fixed inset-y-0 right-0[^"]*")/gis,""),t}parse(e,t){var r,i;const{html:o,text:n}=this.extractContent(e);if(!o)throw new Error("No HTML content found in Perplexity response");let s=o;const l=null!==(r=null==t?void 0:t.removeHeader)&&void 0!==r&&r,d=null!==(i=null==t?void 0:t.removeFooter)&&void 0!==i&&i;return s=this.sanitizeHtml(s),l&&(s=this.removeHeader(s)),d&&(s=this.removeFooter(s)),(null==t?void 0:t.removeLinks)&&(s=this.removeLinks(s)),s=this.injectStyles(s,{baseUrl:this.baseUrl,customCSS:""}),{provider:this.name,html:s,text:n,metadata:{isFullDocument:this.isFullDocument(s),linksRemoved:(null==t?void 0:t.removeLinks)||!1,headerRemoved:l,footerRemoved:d}}}}class s extends r{constructor(){super(...arguments),this.name="COPILOT",this.baseUrl="https://copilot.microsoft.com"}extractContent(e){return this.extractContentCommon(e)}removeHeader(e){let t=e;return t=t.replace(/<div[^>]*class="[^"]*relative shrink-0 min-h-14[^"]*"[^>]*data-testid="backstage-chats"[^>]*>.*?<\/div>/gis,""),t=t.replace(/<div[^>]*class="[^"]*flex items-center px-6 mx-auto w-full max-w-chat[^"]*"[^>]*>.*?<span[^>]*data-testid="date-divider"[^>]*>.*?<\/span>.*?<div[^>]*class="[^"]*border-t-\[1px\][^"]*"[^>]*>.*?<\/div>.*?<\/div>/gis,""),t=t.replace(/<div[^>]*class="[^"]*absolute flex end-6 origin-top-right flex-col items-end[^"]*"[^>]*data-testid="settings-wrapper"[^>]*>.*?<\/div><\/div>/gis,""),t}removeFooter(e){let t=e;return t=t.replace(/<div[^>]*class="[^"]*absolute bottom-0 w-full[^"]*"[^>]*>.*?<\/div><\/div><\/div><\/div><\/div><\/div><\/div><\/div><\/div><\/div><\/div><\/div>/gis,""),t=t.replace(/<div[^>]*class="[^"]*mt-\[var\(--composer-container-height\)\][^"]*"[^>]*><\/div>/gis,""),t=t.replace(/<div[^>]*class="[^"]*pointer-events-none absolute flex justify-center z-20 inset-x-0 bottom-\[calc\(var\(--composer-container-height\)\+1rem\)\][^"]*"[^>]*>.*?<button[^>]*data-testid="scroll-to-bottom-button"[^>]*>.*?<\/button><\/div>/gis,""),t}removeCookieBanner(e){let t=e;return t=t.replace(/<div[^>]*id="cookie-banner"[^>]*>.*?<\/div>.*?<\/div>.*?<\/div>.*?<\/div>/gis,""),t=t.replace(/<div[^>]*class="[^"]*max-w-cookie-banner[^"]*"[^>]*>.*?<\/div>.*?<\/div>.*?<\/div>.*?<\/div>/gis,""),t}removeSidebar(e){let t=e;return t=t.replace(/<div[^>]*class="[^"]*absolute h-full w-0 will-change-auto max-md:bg-sidebar-light[^"]*"[^>]*style="[^"]*"[^>]*>.*?<main/gis,"<main"),t}parse(e,t){var r,i;const{html:o,text:n}=this.extractContent(e);if(!o)throw new Error("No HTML content found in Copilot response");let s=o;const l=null!==(r=null==t?void 0:t.removeHeader)&&void 0!==r&&r,d=null!==(i=null==t?void 0:t.removeFooter)&&void 0!==i&&i;return s=this.sanitizeHtml(s),s=this.removeCookieBanner(s),l&&(s=this.removeHeader(s)),d&&(s=this.removeFooter(s)),(null==t?void 0:t.removeSidebar)&&(s=this.removeSidebar(s)),(null==t?void 0:t.removeLinks)&&(s=this.removeLinks(s)),s=this.injectStyles(s,{baseUrl:this.baseUrl,customCSS:""}),{provider:this.name,html:s,text:n,metadata:{isFullDocument:this.isFullDocument(s),cookieBannerRemoved:!0,headerRemoved:l,footerRemoved:d,sidebarRemoved:(null==t?void 0:t.removeSidebar)||!1,linksRemoved:(null==t?void 0:t.removeLinks)||!1}}}}class l extends r{constructor(){super(...arguments),this.name="AIOVERVIEW",this.baseUrl="https://www.google.com"}extractContent(e){return this.extractContentCommon(e,!0)}removeHeader(e){return e}removeFooter(e){return e}removeSidebar(e){return e}parse(e,t){var r,i;const{html:o,sources:n}=this.extractContent(e);if(!o)throw new Error("No HTML content found in AI Overview response");let s=o;const l=null===(r=null==t?void 0:t.removeHeader)||void 0===r||r,d=null===(i=null==t?void 0:t.removeFooter)||void 0===i||i;s=this.sanitizeHtml(s),l&&(s=this.removeHeader(s)),d&&(s=this.removeFooter(s)),(null==t?void 0:t.removeSidebar)&&(s=this.removeSidebar(s)),(null==t?void 0:t.removeLinks)&&(s=this.removeLinks(s));let a="";return l&&(a+='\n /* Header hiding */\n header, #header, #searchform, .sfbg, #appbar,\n div[role="navigation"], #leftnav, #sidetogether,\n [role="banner"], .Fgvgjc, #hdtb, .hdtb-msb,\n .DZ13He, .wYq63b, .eT9Cje, .bNg8Rb, .S6VXfe, .Lu57id {\n display: none !important;\n }\n '),(null==t?void 0:t.removeSidebar)&&(a+="\n /* Sidebar hiding */\n #leftnav, #sidetogether {\n display: none !important;\n }\n "),d&&(a+='\n /* Footer hiding */\n footer, #footer, .fbar,\n .pdp-nav, [aria-label="Main menu"], .gb_Td, .gb_L {\n display: none !important;\n }\n '),s=this.injectStyles(s,{baseUrl:this.baseUrl,customCSS:a}),{provider:this.name,html:s,sources:n,metadata:{isFullDocument:this.isFullDocument(s),headerRemoved:l,footerRemoved:d,sidebarRemoved:(null==t?void 0:t.removeSidebar)||!1,linksRemoved:(null==t?void 0:t.removeLinks)||!1}}}}class d extends r{constructor(){super(...arguments),this.name="AIMODE",this.baseUrl="https://www.google.com"}extractContent(e){return this.extractContentCommon(e)}removeHeader(e){let t=e;return t=t.replace(/<div[^>]*jsname="oEQ3x"[^>]*class="[^"]*DZ13He[^"]*"[^>]*>.*?<hr class="e9c7U">.*?<\/div><\/div><\/div><\/div><\/div>/gis,""),t}removeFooter(e){let t=e;return t=t.replace(/<div[^>]*data-xid="aim-mars-input-plate"[^>]*>[\s\S]*?<\/div><\/div><\/div><\/div><\/div>/gis,""),t=t.replace(/<div[^>]*jscontroller="P5gZDb"[^>]*>[\s\S]*?<\/div><\/div><\/div>/gis,""),t=t.replace(/<div[^>]*class="[^"]*t0ITR hh3ttd[^"]*"[^>]*>[\s\S]*?<\/div><\/div>/gis,""),t=t.replace(/<div[^>]*class="[^"]*y4VEUd vve6Ce[^"]*"[^>]*>[\s\S]*?<\/div><\/div>/gis,""),t}removeSidebar(e){let t=e;return t=t.replace(/<div[^>]*class="[^"]*ho072b[^"]*"[^>]*aria-label="AI Mode history"[^>]*>[\s\S]*?<\/div><\/div><\/div><\/div><\/div><\/div>/gis,""),t=t.replace(/<div[^>]*jsname="NlVIob"[^>]*class="[^"]*qEn1od[^"]*"[^>]*>[\s\S]*?<\/div><\/div><\/div>/gis,""),t=t.replace(/<div[^>]*class="[^"]*OEwhSe[^"]*"[^>]*>[\s\S]*?<\/div><\/div>/gis,""),t=t.replace(/<button[^>]*aria-label="Start new search"[^>]*>[\s\S]*?<\/button>/gis,""),t=t.replace(/<button[^>]*aria-label="AI Mode history"[^>]*>[\s\S]*?<\/button>/gis,""),t}parse(e,t){var r,i;const{html:o,text:n}=this.extractContent(e);if(!o)throw new Error("No HTML content found in AI Mode response");let s=o;const l=null===(r=null==t?void 0:t.removeHeader)||void 0===r||r,d=null===(i=null==t?void 0:t.removeFooter)||void 0===i||i;s=this.sanitizeHtml(s),l&&(s=this.removeHeader(s)),d&&(s=this.removeFooter(s)),(null==t?void 0:t.removeSidebar)&&(s=this.removeSidebar(s)),(null==t?void 0:t.removeLinks)&&(s=this.removeLinks(s));let a="";return a+="\n .KxvlWc, #CXQnmb {\n display: none !important;\n }\n ",l&&(a+='\n /* Header hiding */\n header, #header, #searchform, .sfbg, #appbar,\n div[role="navigation"], #leftnav, #sidetogether,\n [role="banner"], .Fgvgjc, #hdtb, .hdtb-msb,\n .DZ13He, .wYq63b, .eT9Cje, .bNg8Rb, .S6VXfe, .Lu57id {\n display: none !important;\n }\n '),(null==t?void 0:t.removeSidebar)&&(a+="\n /* Sidebar hiding */\n #leftnav, #sidetogether {\n display: none !important;\n }\n "),d&&(a+='\n /* Footer hiding */\n footer, #footer, .fbar,\n .pdp-nav, [aria-label="Main menu"], .gb_Td, .gb_L {\n display: none !important;\n }\n '),s=this.injectStyles(s,{baseUrl:this.baseUrl,customCSS:a}),{provider:this.name,html:s,text:n,metadata:{isFullDocument:this.isFullDocument(s),headerRemoved:l,footerRemoved:d,sidebarRemoved:(null==t?void 0:t.removeSidebar)||!1,linksRemoved:(null==t?void 0:t.removeLinks)||!1}}}}class a extends r{constructor(){super(...arguments),this.name="GROK",this.baseUrl="https://grok.com"}extractContent(e){return this.extractContentCommon(e)}removeHeader(e){return e}removeFooter(e){return e}parse(e,t){const{html:r,text:i}=this.extractContent(e);if(!r)throw new Error("No HTML content found in Grok response");let o=r;o=this.sanitizeHtml(o);let n="";return(null==t?void 0:t.removeHeader)&&(n+='\n /* Header hiding - hide elements with Grok\'s header class pattern */\n div[class*="h-16"][class*="top-0"][class*="z-10"],\n div[class*="absolute"][class*="inset-x-0"][class*="top-0"] {\n display: none !important;\n }\n '),(null==t?void 0:t.removeFooter)&&(n+='\n /* Footer hiding - hide Grok\'s footer/input area */\n div[class*="absolute"][class*="inset-x-0"][class*="bottom-0"][class*="max-w-breakout"],\n div[class*="absolute"][class*="bottom-0"][class*="w-full"] {\n display: none !important;\n }\n '),(null==t?void 0:t.removeLinks)&&(o=this.removeLinks(o)),o=this.injectStyles(o,{baseUrl:this.baseUrl,customCSS:n}),{provider:this.name,html:o,text:i,metadata:{isFullDocument:this.isFullDocument(o),linksRemoved:(null==t?void 0:t.removeLinks)||!1,headerRemoved:(null==t?void 0:t.removeHeader)||!1,footerRemoved:(null==t?void 0:t.removeFooter)||!1}}}}class v{constructor(){this.providers=new Map,this.providers.set("CHATGPT",new i),this.providers.set("GEMINI",new o),this.providers.set("PERPLEXITY",new n),this.providers.set("COPILOT",new s),this.providers.set("AIOVERVIEW",new l),this.providers.set("AIMODE",new d),this.providers.set("GROK",new a)}parse(e,r){const i=t.detect(e);if(!i)return this.parseGeneric(e);const o=this.providers.get(i.provider);if(!o)return null;try{const t=o.parse(e,r);return{...t,metadata:{...t.metadata,detectionConfidence:i.confidence}}}catch(e){return console.error(`Failed to parse response with ${i.provider}:`,e),null}}parseWithProvider(e,t,r){const i=this.providers.get(t);if(!i)throw new Error(`Unknown provider: ${t}`);try{return i.parse(e,r)}catch(e){return console.error(`Failed to parse response with ${t}:`,e),null}}detectProvider(e){const r=t.detect(e);return(null==r?void 0:r.provider)||null}detectAllProviders(e){return t.getAllProviders(e)}parseGeneric(t){const{html:r,text:i}=e(t);if(!r&&!i)return null;let o=r;return o&&(o=o.replace(/<script\b[^>]*>[\s\S]*?<\/script>/gim,""),o=o.replace(/<noscript[\s\S]*?<\/noscript>/gi,"")),{provider:"CHATGPT",html:o||"",text:i||"",metadata:{isGeneric:!0}}}getSupportedProviders(){return Array.from(this.providers.keys())}registerProvider(e,t){this.providers.set(e,t)}}const c=new v;exports.AIModeProvider=d,exports.AIOverviewProvider=l,exports.AIResponseParser=v,exports.BaseProvider=r,exports.ChatGPTProvider=i,exports.CopilotProvider=s,exports.GeminiProvider=o,exports.GrokProvider=a,exports.PerplexityProvider=n,exports.ProviderDetector=t,exports.detectProvider=e=>c.detectProvider(e),exports.parseAiResponse=(e,t)=>c.parse(e,t),exports.parser=c;
1
+ "use strict";function e(e){let t="",r="",o=e;return e.result&&(o=e.result),"string"==typeof o?o.trim().startsWith("<")&&o.includes(">")?t=o:r=o:"object"==typeof o&&null!==o&&(o.html?t=o.html:o.content?o.content.trim().startsWith("<")?t=o.content:r=o.content:o.text&&(r=o.text)),{html:t,text:r}}class t{static detect(e){const t={CHATGPT:0,GEMINI:0,PERPLEXITY:0,COPILOT:0,AIOVERVIEW:0,AIMODE:0,GROK:0};for(const[r,o]of Object.entries(this.PROVIDER_PATTERNS))for(const i of o)try{i(e)&&t[r]++}catch(e){}let r=0,o=null;for(const[e,i]of Object.entries(t))i>r&&(r=i,o=e);return 0===r?null:{provider:o,confidence:r/Object.values(t).reduce((e,t)=>Math.max(e,t),1)}}static getAllProviders(e){const t=[];for(const[r,o]of Object.entries(this.PROVIDER_PATTERNS)){let i=0;for(const t of o)try{t(e)&&i++}catch(e){}i>0&&t.push({provider:r,confidence:i/o.length})}return t.sort((e,t)=>t.confidence-e.confidence)}static validate(e,t){const r=this.detect(e);return(null==r?void 0:r.provider)===t&&r.confidence>.5}}t.PROVIDER_PATTERNS={CHATGPT:[e=>{var t;const r=(null===(t=null==e?void 0:e.result)||void 0===t?void 0:t.html)||(null==e?void 0:e.html)||"";return r.includes("bg-token-bg-primary")||r.includes("text-token-text-secondary")},e=>{var t;const r=(null===(t=null==e?void 0:e.result)||void 0===t?void 0:t.html)||(null==e?void 0:e.html)||"";return r.includes("chatgpt.com")||r.includes("openai.com")}],GEMINI:[e=>{var t;const r=(null===(t=null==e?void 0:e.result)||void 0===t?void 0:t.html)||(null==e?void 0:e.html)||"";return r.includes("bard-sidenav")||r.includes("mat-sidenav")},e=>{var t;const r=(null===(t=null==e?void 0:e.result)||void 0===t?void 0:t.html)||(null==e?void 0:e.html)||"";return r.includes("gemini.google.com")||r.includes("gem-sys-color")}],PERPLEXITY:[e=>{var t;return((null===(t=null==e?void 0:e.result)||void 0===t?void 0:t.html)||(null==e?void 0:e.html)||"").includes("perplexity.ai")},e=>{var t;const r=(null===(t=null==e?void 0:e.result)||void 0===t?void 0:t.html)||(null==e?void 0:e.html)||"";return r.includes("prose")&&!r.includes("grok.com")&&!r.includes("chatgpt.com")}],COPILOT:[e=>{var t;const r=(null===(t=null==e?void 0:e.result)||void 0===t?void 0:t.html)||(null==e?void 0:e.html)||"";return r.includes("copilot.microsoft.com")||r.includes('data-testid="sidebar-container"')}],AIOVERVIEW:[e=>{var t,r,o,i;if(null===(r=null===(t=null==e?void 0:e.result)||void 0===t?void 0:t.aioverview)||void 0===r?void 0:r.text)return!0;if(null===(o=null==e?void 0:e.aioverview)||void 0===o?void 0:o.text)return!0;return((null===(i=null==e?void 0:e.result)||void 0===i?void 0:i.html)||(null==e?void 0:e.html)||"").includes("DnVkpd")},e=>{var t;const r=(null===(t=null==e?void 0:e.result)||void 0===t?void 0:t.html)||(null==e?void 0:e.html)||"";return r.includes("WIZ_global_data")&&!r.includes("aim-mars")&&!r.includes("ho072b")}],AIMODE:[e=>{var t;const r=(null===(t=null==e?void 0:e.result)||void 0===t?void 0:t.html)||(null==e?void 0:e.html)||"";return r.includes("DZ13He")||r.includes("wYq63b")||r.includes("AI Mode")},e=>{var t;const r=(null===(t=null==e?void 0:e.result)||void 0===t?void 0:t.html)||(null==e?void 0:e.html)||"";return r.includes("aim-mars")||r.includes("ho072b")}],GROK:[e=>{var t;const r=(null===(t=null==e?void 0:e.result)||void 0===t?void 0:t.html)||(null==e?void 0:e.html)||"";return r.includes("grok.com")||r.includes("x.ai")},e=>{var t;const r=(null===(t=null==e?void 0:e.result)||void 0===t?void 0:t.html)||(null==e?void 0:e.html)||"";return r.includes("cdn.grok.com")||r.includes("vaul-drawer")}]};class r{extractContentCommon(t,r=!1){var o;const i=e(t);if(r){let e=[];const r=t.result||t;return"object"==typeof r&&null!==r&&((null===(o=r.aioverview)||void 0===o?void 0:o.sources)?e=r.aioverview.sources:r.sources&&(e=r.sources)),{...i,sources:e}}return i}injectStyles(e,t){let r=e;(null==t?void 0:t.baseUrl)&&!e.includes("<base ")&&(r=r.includes("<head>")?r.replace("<head>",`<head><base href="${t.baseUrl}">`):r.replace(/(<html[^>]*>)/i,`$1<head><base href="${t.baseUrl}"></head>`));const o=(null==t?void 0:t.customCSS)||"";return o&&r.includes("<head>")?r=r.replace("<head>",`<head><style>${o}</style>`):o&&(r=r.replace(/(<html[^>]*>)/i,`$1<head><style>${o}</style></head>`)),r}sanitizeHtml(e){let t=e.replace(/<script\b[^>]*>[\s\S]*?<\/script>/gim,"");return t=t.replace(/<noscript[\s\S]*?<\/noscript>/gi,""),t}isFullDocument(e){return/^\s*(<html|<!DOCTYPE)/i.test(e)}removeLinks(e){return e.replace(/<a\b[^>]*>([\s\S]*?)<\/a>/gim,"$1")}wrapFragment(e){return`<!DOCTYPE html>\n<html>\n<head>\n <meta charset="utf-8">\n <meta http-equiv="Content-Security-Policy" content="default-src 'none'; script-src 'none'; style-src 'unsafe-inline';">\n <style>\n body {\n margin: 0;\n padding: 16px;\n font-family: system-ui, -apple-system, sans-serif;\n white-space: pre-wrap;\n word-wrap: break-word;\n }\n img { max-width: 100%; height: auto; }\n body {\n pointer-events: none;\n user-select: none;\n }\n </style>\n</head>\n<body>\n ${e}\n</body>\n</html>`}}class o extends r{constructor(){super(...arguments),this.name="CHATGPT",this.baseUrl="https://chatgpt.com"}extractContent(e){return this.extractContentCommon(e)}removeLinks(e){return e.replace(/<a\b([^>]*)>/gi,(e,t)=>{const r=t.replace(/\s+href\s*=\s*["'][^"']*["']/gi,"").replace(/\s+alt\s*=\s*["'][^"']*["']/gi,"").replace(/\s+rel\s*=\s*["'][^"']*["']/gi,"").replace(/\s+target\s*=\s*["'][^"']*["']/gi,"").trim();return`<span${r?" "+r:""}>`}).replace(/<\/a>/gi,"</span>")}removeHeader(e){let t=e;return t=t.replace(/<header[^>]*id="page-header"[^>]*>.*?<\/header>/gis,""),t}removeSidebar(e){let t=e;return t=t.replace(/<nav[^>]*>.*?<\/nav>/gis,""),t=t.replace(/<div[^>]*class="[^"]*sidebar[^"]*"[^>]*>.*?<\/div>/gis,""),t}removeFooter(e){let t=e;return t=t.replace(/<div[^>]*id="thread-bottom-container"[^>]*>.*?<\/div><\/div><\/div>/gis,""),t=t.replace(/<div[^>]*id="thread-bottom"[^>]*>.*?<\/div><\/div><\/div><\/div><\/div>/gis,""),t=t.replace(/<div[^>]*class="[^"]*\[grid-area:leading\][^"]*"[^>]*>.*?<\/div><\/div><\/div>/gis,""),t=t.replace(/<div[^>]*class="[^"]*\[grid-area:footer\][^"]*"[^>]*>.*?<\/div><\/div><\/div><\/div><\/div>/gis,""),t=t.replace(/<div[^>]*class="[^"]*\[grid-area:trailing\][^"]*"[^>]*>.*?<\/div><\/div><\/div>/gis,""),t=t.replace(/<div[^>]*\[view-transition-name:var\(--vt-disclaimer\)\][^>]*>.*?<\/div><\/div>/gis,""),t}parse(e,t){var r;const{html:o,text:i}=this.extractContent(e);if(!o)throw new Error("No HTML content found in ChatGPT response");let n=o;const s=null!==(r=null==t?void 0:t.removeFooter)&&void 0!==r&&r;return n=this.sanitizeHtml(n),(null==t?void 0:t.removeHeader)&&(n=this.removeHeader(n)),(null==t?void 0:t.removeSidebar)&&(n=this.removeSidebar(n)),s&&(n=this.removeFooter(n)),(null==t?void 0:t.removeLinks)&&(n=this.removeLinks(n)),n=this.injectStyles(n,{baseUrl:this.baseUrl,customCSS:""}),{provider:this.name,html:n,text:i,metadata:{isFullDocument:this.isFullDocument(n),headerRemoved:(null==t?void 0:t.removeHeader)||!1,sidebarRemoved:(null==t?void 0:t.removeSidebar)||!1,footerRemoved:s,linksRemoved:(null==t?void 0:t.removeLinks)||!1}}}}class i extends r{constructor(){super(...arguments),this.name="GEMINI",this.baseUrl="https://gemini.google.com"}extractContent(e){return this.extractContentCommon(e,!0)}removeHeader(e){let t=e;return t=t.replace(/<div[^>]*class="[^"]*boqOnegoogleliteOgbOneGoogleBar[^"]*"[^>]*>.*?<\/div><\/div><\/div><\/div>/gis,""),t=t.replace(/<div[^>]*class="[^"]*side-nav-menu-button[^"]*"[^>]*>.*?<\/div>/gis,""),t=t.replace(/<top-bar-actions[^>]*>.*?<\/top-bar-actions>/gis,""),t=t.replace(/<div[^>]*class="[^"]*desktop-ogb-buffer[^"]*"[^>]*><\/div>/gis,""),t}removeFooter(e){return e.replace(/<input-container[^>]*>.*?<\/input-container>/gis,"")}removeSidebar(e){return e.replace(/<bard-sidenav[^>]*>.*?<\/bard-sidenav>/gis,"")}removeSources(e){let t=e;return t=t.replace(/<context-sidebar[^>]*>[\s\S]*?<\/context-sidebar>/gi,""),t=t.replace(/<sources-sidebar-button[^>]*>[\s\S]*?<\/sources-sidebar-button>/gi,""),t}parse(e,t){var r,o;const{html:i,text:n,sources:s}=this.extractContent(e);if(!i)throw new Error("No HTML content found in Gemini response");let l=i;const d=null!==(r=null==t?void 0:t.removeHeader)&&void 0!==r&&r,a=null!==(o=null==t?void 0:t.removeFooter)&&void 0!==o&&o;return l=this.sanitizeHtml(l),d&&(l=this.removeHeader(l)),a&&(l=this.removeFooter(l)),(null==t?void 0:t.removeSidebar)&&(l=this.removeSidebar(l)),(null==t?void 0:t.removeSources)&&(l=this.removeSources(l)),(null==t?void 0:t.removeLinks)&&(l=this.removeLinks(l)),l=this.injectStyles(l,{baseUrl:this.baseUrl,customCSS:""}),{provider:this.name,html:l,text:n,sources:s,metadata:{isFullDocument:this.isFullDocument(l),headerRemoved:d,footerRemoved:a,sidebarRemoved:(null==t?void 0:t.removeSidebar)||!1,sourcesRemoved:(null==t?void 0:t.removeSources)||!1,linksRemoved:(null==t?void 0:t.removeLinks)||!1}}}}class n extends r{constructor(){super(...arguments),this.name="PERPLEXITY",this.baseUrl="https://www.perplexity.ai"}extractContent(e){return this.extractContentCommon(e)}removeHeader(e){return e.replace(/<div[^>]*class="[^"]*@container\/header[^"]*"[^>]*>.*?<div[^>]*class="[^"]*absolute bottom-0 inset-x-0 border-b[^"]*"[^>]*><\/div>/gis,"")}removeFooter(e){let t=e;return t=t.replace(/<div[^>]*class="[^"]*erp-sidecar:fixed erp-sidecar:w-full bottom-safeAreaInsetBottom p-md pointer-events-none z-10 absolute border-subtlest ring-subtlest divide-subtlest bg-transparent[^"]*"[^>]*>[\s\S]*?(?=<div[^>]*class="[^"]*fixed inset-y-0 right-0[^"]*")/gis,""),t}removeSources(e){return e.replace(/<div[^>]*class="[^"]*fixed inset-y-0 right-0[^"]*"[^>]*>[\s\S]*?(?=<span[^>]*data-radix-focus-guard)/gi,"")}parse(e,t){var r,o;const{html:i,text:n}=this.extractContent(e);if(!i)throw new Error("No HTML content found in Perplexity response");let s=i;const l=null!==(r=null==t?void 0:t.removeHeader)&&void 0!==r&&r,d=null!==(o=null==t?void 0:t.removeFooter)&&void 0!==o&&o;s=this.sanitizeHtml(s),s=s.replace(/style="transition: none; overflow: hidden; height: 48px;"/gi,""),l&&(s=this.removeHeader(s)),d&&(s=this.removeFooter(s)),(null==t?void 0:t.removeSources)&&(s=this.removeSources(s)),(null==t?void 0:t.removeLinks)&&(s=this.removeLinks(s));return s=this.injectStyles(s,{baseUrl:this.baseUrl,customCSS:'\n #cookie-consent,\n [role="dialog"]:has(#cookie-consent) {\n display: none !important;\n }\n '}),{provider:this.name,html:s,text:n,metadata:{isFullDocument:this.isFullDocument(s),linksRemoved:(null==t?void 0:t.removeLinks)||!1,headerRemoved:l,footerRemoved:d,cookieBannerRemoved:!0,sourcesRemoved:(null==t?void 0:t.removeSources)||!1}}}}class s extends r{constructor(){super(...arguments),this.name="COPILOT",this.baseUrl="https://copilot.microsoft.com"}extractContent(e){return this.extractContentCommon(e)}removeHeader(e){let t=e;return t=t.replace(/<div[^>]*class="[^"]*relative shrink-0 min-h-14[^"]*"[^>]*data-testid="backstage-chats"[^>]*>.*?<\/div>/gis,""),t=t.replace(/<div[^>]*class="[^"]*flex items-center px-6 mx-auto w-full max-w-chat[^"]*"[^>]*>.*?<span[^>]*data-testid="date-divider"[^>]*>.*?<\/span>.*?<div[^>]*class="[^"]*border-t-\[1px\][^"]*"[^>]*>.*?<\/div>.*?<\/div>/gis,""),t=t.replace(/<div[^>]*class="[^"]*absolute flex end-6 origin-top-right flex-col items-end[^"]*"[^>]*data-testid="settings-wrapper"[^>]*>.*?<\/div><\/div>/gis,""),t}removeFooter(e){let t=e;return t=t.replace(/<div[^>]*class="[^"]*absolute bottom-0 w-full[^"]*"[^>]*>.*?<\/div><\/div><\/div><\/div><\/div><\/div><\/div><\/div><\/div><\/div><\/div><\/div>/gis,""),t=t.replace(/<div[^>]*class="[^"]*mt-\[var\(--composer-container-height\)\][^"]*"[^>]*><\/div>/gis,""),t=t.replace(/<div[^>]*class="[^"]*pointer-events-none absolute flex justify-center z-20 inset-x-0 bottom-\[calc\(var\(--composer-container-height\)\+1rem\)\][^"]*"[^>]*>.*?<button[^>]*data-testid="scroll-to-bottom-button"[^>]*>.*?<\/button><\/div>/gis,""),t}removeCookieBanner(e){let t=e;return t=t.replace(/<div[^>]*id="cookie-banner"[^>]*>.*?<\/div>.*?<\/div>.*?<\/div>.*?<\/div>/gis,""),t=t.replace(/<div[^>]*class="[^"]*max-w-cookie-banner[^"]*"[^>]*>.*?<\/div>.*?<\/div>.*?<\/div>.*?<\/div>/gis,""),t}removeSources(e){return e.replace(/<div[^>]*class="[^"]*relative h-full overflow-hidden will-change-auto[^"]*"[^>]*style="[^"]*width:\s*352px[^"]*"[^>]*>[\s\S]*?(?=<div[^>]*class="[^"]*pointer-events-none fixed[^"]*")/gi,"")}removeSidebar(e){let t=e;return t=t.replace(/<div[^>]*class="[^"]*bg-sidebar-light[^"]*"[^>]*>[\s\S]*?(?=<main)/gi,""),t}parse(e,t){var r,o;const{html:i,text:n}=this.extractContent(e);if(!i)throw new Error("No HTML content found in Copilot response");let s=i;const l=null!==(r=null==t?void 0:t.removeHeader)&&void 0!==r&&r,d=null!==(o=null==t?void 0:t.removeFooter)&&void 0!==o&&o;return s=this.sanitizeHtml(s),s=this.removeCookieBanner(s),l&&(s=this.removeHeader(s)),d&&(s=this.removeFooter(s)),(null==t?void 0:t.removeSidebar)&&(s=this.removeSidebar(s)),(null==t?void 0:t.removeSources)&&(s=this.removeSources(s)),(null==t?void 0:t.removeLinks)&&(s=this.removeLinks(s)),s=this.injectStyles(s,{baseUrl:this.baseUrl,customCSS:""}),{provider:this.name,html:s,text:n,metadata:{isFullDocument:this.isFullDocument(s),cookieBannerRemoved:!0,headerRemoved:l,footerRemoved:d,sidebarRemoved:(null==t?void 0:t.removeSidebar)||!1,sourcesRemoved:(null==t?void 0:t.removeSources)||!1,linksRemoved:(null==t?void 0:t.removeLinks)||!1}}}}class l extends r{constructor(){super(...arguments),this.name="AIOVERVIEW",this.baseUrl="https://www.google.com"}extractContent(e){return this.extractContentCommon(e,!0)}removeHeader(e){return e}removeFooter(e){return e}removeSidebar(e){return e}parse(e,t){var r,o;const{html:i,sources:n}=this.extractContent(e);if(!i)throw new Error("No HTML content found in AI Overview response");let s=i;const l=null===(r=null==t?void 0:t.removeHeader)||void 0===r||r,d=null===(o=null==t?void 0:t.removeFooter)||void 0===o||o;s=this.sanitizeHtml(s),l&&(s=this.removeHeader(s)),d&&(s=this.removeFooter(s)),(null==t?void 0:t.removeSidebar)&&(s=this.removeSidebar(s)),(null==t?void 0:t.removeLinks)&&(s=this.removeLinks(s));let a="";return l&&(a+='\n /* Header hiding */\n header, #header, #searchform, .sfbg, #appbar,\n div[role="navigation"], #leftnav, #sidetogether,\n [role="banner"], .Fgvgjc, #hdtb, .hdtb-msb,\n .DZ13He, .wYq63b, .eT9Cje, .bNg8Rb, .S6VXfe, .Lu57id {\n display: none !important;\n }\n '),(null==t?void 0:t.removeSidebar)&&(a+="\n /* Sidebar hiding */\n #leftnav, #sidetogether {\n display: none !important;\n }\n "),d&&(a+='\n /* Footer hiding */\n footer, #footer, .fbar,\n .pdp-nav, [aria-label="Main menu"], .gb_Td, .gb_L {\n display: none !important;\n }\n '),s=this.injectStyles(s,{baseUrl:this.baseUrl,customCSS:a}),{provider:this.name,html:s,sources:n,metadata:{isFullDocument:this.isFullDocument(s),headerRemoved:l,footerRemoved:d,sidebarRemoved:(null==t?void 0:t.removeSidebar)||!1,linksRemoved:(null==t?void 0:t.removeLinks)||!1}}}}class d extends r{constructor(){super(...arguments),this.name="AIMODE",this.baseUrl="https://www.google.com"}extractContent(e){return this.extractContentCommon(e)}removeHeader(e){let t=e;return t=t.replace(/<div[^>]*jsname="oEQ3x"[^>]*class="[^"]*DZ13He[^"]*"[^>]*>.*?<hr class="e9c7U">.*?<\/div><\/div><\/div><\/div><\/div>/gis,""),t}removeFooter(e){let t=e;return t=t.replace(/<div[^>]*data-xid="aim-mars-input-plate"[^>]*>[\s\S]*?<\/div><\/div><\/div><\/div><\/div>/gis,""),t=t.replace(/<div[^>]*jscontroller="P5gZDb"[^>]*>[\s\S]*?<\/div><\/div><\/div>/gis,""),t=t.replace(/<div[^>]*class="[^"]*t0ITR hh3ttd[^"]*"[^>]*>[\s\S]*?<\/div><\/div>/gis,""),t=t.replace(/<div[^>]*class="[^"]*y4VEUd vve6Ce[^"]*"[^>]*>[\s\S]*?<\/div><\/div>/gis,""),t}removeSidebar(e){let t=e;return t=t.replace(/<div[^>]*aria-label="AI Mode history"[^>]*class="[^"]*ho072b[^"]*"[^>]*>[\s\S]*?(?=<!--TgQPHd)/gi,""),t=t.replace(/<div[^>]*class="[^"]*ho072b[^"]*"[^>]*aria-label="AI Mode history"[^>]*>[\s\S]*?(?=<!--TgQPHd)/gi,""),t=t.replace(/<div[^>]*class="[^"]*OEwhSe[^"]*"[^>]*>[\s\S]*?<\/div><\/div>/gis,""),t=t.replace(/<button[^>]*aria-label="AI Mode history"[^>]*>[\s\S]*?<\/button>/gis,""),t}parse(e,t){var r,o;const{html:i,text:n}=this.extractContent(e);if(!i)throw new Error("No HTML content found in AI Mode response");let s=i;const l=null===(r=null==t?void 0:t.removeHeader)||void 0===r||r,d=null===(o=null==t?void 0:t.removeFooter)||void 0===o||o;s=this.sanitizeHtml(s),l&&(s=this.removeHeader(s)),d&&(s=this.removeFooter(s)),(null==t?void 0:t.removeSidebar)&&(s=this.removeSidebar(s)),(null==t?void 0:t.removeLinks)&&(s=this.removeLinks(s));let a="";return a+="\n .KxvlWc, #CXQnmb {\n display: none !important;\n }\n ",l&&(a+='\n /* Header hiding */\n header, #header, #searchform, .sfbg, #appbar,\n div[role="navigation"], #leftnav, #sidetogether,\n [role="banner"], .Fgvgjc, #hdtb, .hdtb-msb,\n .DZ13He, .wYq63b, .eT9Cje, .bNg8Rb, .S6VXfe, .Lu57id {\n display: none !important;\n }\n '),d&&(a+='\n /* Footer hiding */\n footer, #footer, .fbar,\n .pdp-nav, [aria-label="Main menu"], .gb_Td, .gb_L {\n display: none !important;\n }\n /* Hide the "Ask anything" input bar */\n [data-xid="aim-mars-input-plate"],\n .UAbVe, .y4VEUd, .t0ITR.hh3ttd {\n display: none !important;\n }\n '),(null==t?void 0:t.removeSidebar)&&(a+="\n /* Hide AI Mode history panel */\n .ho072b, .OEwhSe, .qEn1od {\n display: none !important;\n }\n "),s=this.injectStyles(s,{baseUrl:this.baseUrl,customCSS:a}),{provider:this.name,html:s,text:n,metadata:{isFullDocument:this.isFullDocument(s),headerRemoved:l,footerRemoved:d,sidebarRemoved:(null==t?void 0:t.removeSidebar)||!1,linksRemoved:(null==t?void 0:t.removeLinks)||!1}}}}class a extends r{constructor(){super(...arguments),this.name="GROK",this.baseUrl="https://grok.com"}extractContent(e){return this.extractContentCommon(e)}removeHeader(e){return e}removeFooter(e){return e}parse(e,t){const{html:r,text:o}=this.extractContent(e);if(!r)throw new Error("No HTML content found in Grok response");let i=r;i=this.sanitizeHtml(i);let n="";return n+='\n [data-cookie-banner],\n [data-cookie-banner="true"] {\n display: none !important;\n }\n ',n+='\n [data-sonner-toaster],\n [data-sonner-toast],\n [class*="sonner-toast"] {\n display: none !important;\n }\n ',(null==t?void 0:t.removeSources)&&(i=i.replace(/<div[^>]*class="[^"]*h-dvh[^"]*flex-shrink-0[^"]*max-w-[^"]*"[^>]*>[\s\S]*?<\/aside>[\s\S]*?(?=<section)/gi,""),n+='\n div[data-state] > div.flex.flex-row.gap-1.items-center.rounded-full.cursor-pointer {\n display: none !important;\n }\n [vaul-drawer][vaul-drawer-direction="right"],\n [vaul-overlay] {\n display: none !important;\n }\n '),(null==t?void 0:t.removeHeader)&&(n+='\n /* Header hiding - hide elements with Grok\'s header class pattern */\n div[class*="h-16"][class*="top-0"][class*="z-10"],\n div[class*="absolute"][class*="inset-x-0"][class*="top-0"] {\n display: none !important;\n }\n '),(null==t?void 0:t.removeFooter)&&(n+='\n /* Footer hiding - hide Grok\'s footer/input area */\n div[class*="absolute"][class*="inset-x-0"][class*="bottom-0"][class*="max-w-breakout"],\n div[class*="absolute"][class*="bottom-0"][class*="w-full"] {\n display: none !important;\n }\n '),(null==t?void 0:t.removeLinks)&&(i=this.removeLinks(i)),i=this.injectStyles(i,{baseUrl:this.baseUrl,customCSS:n}),{provider:this.name,html:i,text:o,metadata:{isFullDocument:this.isFullDocument(i),linksRemoved:(null==t?void 0:t.removeLinks)||!1,headerRemoved:(null==t?void 0:t.removeHeader)||!1,footerRemoved:(null==t?void 0:t.removeFooter)||!1,cookieBannerRemoved:!0,sourcesRemoved:(null==t?void 0:t.removeSources)||!1}}}}class v{constructor(){this.providers=new Map,this.providers.set("CHATGPT",new o),this.providers.set("GEMINI",new i),this.providers.set("PERPLEXITY",new n),this.providers.set("COPILOT",new s),this.providers.set("AIOVERVIEW",new l),this.providers.set("AIMODE",new d),this.providers.set("GROK",new a)}parse(e,r){const o=t.detect(e);if(!o)return this.parseGeneric(e);const i=this.providers.get(o.provider);if(!i)return null;try{const t=i.parse(e,r);return{...t,metadata:{...t.metadata,detectionConfidence:o.confidence}}}catch(e){return console.error(`Failed to parse response with ${o.provider}:`,e),null}}parseWithProvider(e,t,r){const o=this.providers.get(t);if(!o)throw new Error(`Unknown provider: ${t}`);try{return o.parse(e,r)}catch(e){return console.error(`Failed to parse response with ${t}:`,e),null}}detectProvider(e){const r=t.detect(e);return(null==r?void 0:r.provider)||null}detectAllProviders(e){return t.getAllProviders(e)}parseGeneric(t){const{html:r,text:o}=e(t);if(!r&&!o)return null;let i=r;return i&&(i=i.replace(/<script\b[^>]*>[\s\S]*?<\/script>/gim,""),i=i.replace(/<noscript[\s\S]*?<\/noscript>/gi,"")),{provider:"CHATGPT",html:i||"",text:o||"",metadata:{isGeneric:!0}}}getSupportedProviders(){return Array.from(this.providers.keys())}registerProvider(e,t){this.providers.set(e,t)}}const c=new v;exports.AIModeProvider=d,exports.AIOverviewProvider=l,exports.AIResponseParser=v,exports.BaseProvider=r,exports.ChatGPTProvider=o,exports.CopilotProvider=s,exports.GeminiProvider=i,exports.GrokProvider=a,exports.PerplexityProvider=n,exports.ProviderDetector=t,exports.detectProvider=e=>c.detectProvider(e),exports.parseAiResponse=(e,t)=>c.parse(e,t),exports.parser=c;
2
2
  //# sourceMappingURL=index.js.map
package/dist/index.js.map CHANGED
@@ -1 +1 @@
1
- {"version":3,"file":"index.js","sources":["../src/core/types.ts","../src/core/detector.ts","../src/providers/base-provider.ts","../src/providers/chatgpt.ts","../src/providers/gemini.ts","../src/providers/perplexity.ts","../src/providers/copilot.ts","../src/providers/ai-overview.ts","../src/providers/ai-mode.ts","../src/providers/grok.ts","../src/core/parser.ts"],"sourcesContent":["export type AIProvider =\n | 'CHATGPT'\n | 'GEMINI'\n | 'PERPLEXITY'\n | 'COPILOT'\n | 'AIOVERVIEW'\n | 'AIMODE'\n | 'GROK';\n\nexport interface ParsedResponse {\n provider: AIProvider;\n html: string;\n text?: string;\n sources?: any[];\n metadata?: Record<string, any>;\n}\n\nexport interface ParseOptions {\n removeLinks?: boolean;\n removeHeader?: boolean;\n removeFooter?: boolean;\n removeSidebar?: boolean;\n}\n\nexport interface ProviderConfig {\n name: AIProvider;\n baseUrl: string;\n}\n\nexport interface DetectedProvider {\n provider: AIProvider;\n confidence: number;\n}\n\nexport interface StyleOptions {\n customCSS?: string;\n hideUI?: boolean;\n baseUrl?: string;\n}\n\nexport type ContentExtraction = {\n html?: string;\n text?: string;\n sources?: any[];\n};\n\n/**\n * Standardized metadata for provider responses\n */\nexport interface ProviderMetadata {\n isFullDocument?: boolean;\n headerRemoved?: boolean;\n footerRemoved?: boolean;\n sidebarRemoved?: boolean;\n linksRemoved?: boolean;\n cookieBannerRemoved?: boolean;\n detectionConfidence?: number;\n}\n\n/**\n * Common content extraction utility - shared across providers and parser\n */\nexport function extractContentCommon(response: any): ContentExtraction {\n let html = '';\n let text = '';\n\n // Handle nested structure\n let dataToCheck = response;\n if (response.result) {\n dataToCheck = response.result;\n }\n\n // Extract content\n if (typeof dataToCheck === 'string') {\n if (dataToCheck.trim().startsWith('<') && dataToCheck.includes('>')) {\n html = dataToCheck;\n } else {\n text = dataToCheck;\n }\n } else if (typeof dataToCheck === 'object' && dataToCheck !== null) {\n if (dataToCheck.html) {\n html = dataToCheck.html;\n } else if (dataToCheck.content) {\n if (dataToCheck.content.trim().startsWith('<')) {\n html = dataToCheck.content;\n } else {\n text = dataToCheck.content;\n }\n } else if (dataToCheck.text) {\n text = dataToCheck.text;\n }\n }\n\n return { html, text };\n}","import { AIProvider, DetectedProvider } from './types';\n\nexport class ProviderDetector {\n private static readonly PROVIDER_PATTERNS = {\n CHATGPT: [\n // Check for token-based CSS classes\n (response: any) => {\n const html = response?.result?.html || response?.html || '';\n return html.includes('bg-token-bg-primary') || html.includes('text-token-text-secondary');\n },\n // Check for OpenAI-specific patterns\n (response: any) => {\n const html = response?.result?.html || response?.html || '';\n return html.includes('chatgpt.com') || html.includes('openai.com');\n },\n ],\n GEMINI: [\n // Check for Material Design components\n (response: any) => {\n const html = response?.result?.html || response?.html || '';\n return html.includes('bard-sidenav') || html.includes('mat-sidenav');\n },\n // Check for Gemini-specific classes\n (response: any) => {\n const html = response?.result?.html || response?.html || '';\n return html.includes('gemini.google.com') || html.includes('gem-sys-color');\n },\n ],\n PERPLEXITY: [\n // Check for Perplexity-specific structure\n (response: any) => {\n const html = response?.result?.html || response?.html || '';\n return html.includes('perplexity.ai') || html.includes('prose');\n },\n ],\n COPILOT: [\n // Check for Copilot-specific elements\n (response: any) => {\n const html = response?.result?.html || response?.html || '';\n return html.includes('copilot.microsoft.com') || html.includes('data-testid=\"sidebar-container\"');\n },\n ],\n AIOVERVIEW: [\n // Check for AI Overview specific structure\n (response: any) => {\n // Check for aioverview nested structure\n if (response?.result?.aioverview?.text) return true;\n if (response?.aioverview?.text) return true;\n\n // Check for WIZ_global_data (AI Overview specific)\n const html = response?.result?.html || response?.html || '';\n return html.includes('WIZ_global_data') || html.includes('DnVkpd');\n },\n ],\n AIMODE: [\n // Check for AI Mode specific elements\n (response: any) => {\n const html = response?.result?.html || response?.html || '';\n return html.includes('DZ13He') || html.includes('wYq63b') || html.includes('AI Mode');\n },\n ],\n GROK: [\n // Check for Grok-specific structure\n (response: any) => {\n const html = response?.result?.html || response?.html || '';\n return html.includes('grok.com') || html.includes('x.ai');\n },\n ],\n };\n\n /**\n * Detect the AI provider from the response\n */\n static detect(response: any): DetectedProvider | null {\n const scores: Record<AIProvider, number> = {\n CHATGPT: 0,\n GEMINI: 0,\n PERPLEXITY: 0,\n COPILOT: 0,\n AIOVERVIEW: 0,\n AIMODE: 0,\n GROK: 0,\n };\n\n // Score each provider based on pattern matches\n for (const [provider, patterns] of Object.entries(this.PROVIDER_PATTERNS)) {\n for (const pattern of patterns) {\n try {\n if (pattern(response)) {\n scores[provider as AIProvider]++;\n }\n } catch {\n // Ignore pattern errors\n }\n }\n }\n\n // Find the provider with the highest score\n let maxScore = 0;\n let detectedProvider: AIProvider | null = null;\n\n for (const [provider, score] of Object.entries(scores)) {\n if (score > maxScore) {\n maxScore = score;\n detectedProvider = provider as AIProvider;\n }\n }\n\n // Return null if no patterns matched\n if (maxScore === 0) return null;\n\n return {\n provider: detectedProvider!,\n confidence: maxScore / Object.values(scores).reduce((a, b) => Math.max(a, b), 1),\n };\n }\n\n /**\n * Get all possible providers with their confidence scores\n */\n static getAllProviders(response: any): DetectedProvider[] {\n const providers: DetectedProvider[] = [];\n\n for (const [provider, patterns] of Object.entries(this.PROVIDER_PATTERNS)) {\n let matches = 0;\n for (const pattern of patterns) {\n try {\n if (pattern(response)) {\n matches++;\n }\n } catch {\n // Ignore pattern errors\n }\n }\n\n if (matches > 0) {\n providers.push({\n provider: provider as AIProvider,\n confidence: matches / patterns.length,\n });\n }\n }\n\n // Sort by confidence (highest first)\n return providers.sort((a, b) => b.confidence - a.confidence);\n }\n\n /**\n * Validate if a detected provider is likely correct\n */\n static validate(response: any, provider: AIProvider): boolean {\n const detected = this.detect(response);\n return detected?.provider === provider && detected.confidence > 0.5;\n }\n}","import { AIProvider, ParsedResponse, ParseOptions, StyleOptions, ContentExtraction, extractContentCommon } from '../core/types';\n\nexport abstract class BaseProvider {\n abstract readonly name: AIProvider;\n abstract readonly baseUrl: string;\n\n /**\n * Parse an AI response and return structured content\n */\n abstract parse(response: any, options?: ParseOptions): ParsedResponse;\n\n /**\n * Extract content from the response object\n */\n abstract extractContent(response: any): ContentExtraction;\n\n /**\n * Common content extraction logic - can be used by providers\n */\n protected extractContentCommon(response: any, includeSources = false): ContentExtraction {\n const result = extractContentCommon(response);\n\n if (includeSources) {\n let sources: any[] = [];\n const dataToCheck = response.result || response;\n\n if (typeof dataToCheck === 'object' && dataToCheck !== null) {\n if (dataToCheck.aioverview?.sources) {\n sources = dataToCheck.aioverview.sources;\n } else if (dataToCheck.sources) {\n sources = dataToCheck.sources;\n }\n }\n\n return { ...result, sources };\n }\n\n return result;\n }\n\n /**\n * Inject provider-specific styles into HTML\n */\n injectStyles(html: string, options?: StyleOptions): string {\n let styledHtml = html;\n\n // Inject base URL if not already present\n if (options?.baseUrl && !html.includes('<base ')) {\n if (styledHtml.includes('<head>')) {\n styledHtml = styledHtml.replace(\n '<head>',\n `<head><base href=\"${options.baseUrl}\">`,\n );\n } else {\n styledHtml = styledHtml.replace(\n /(<html[^>]*>)/i,\n `$1<head><base href=\"${options.baseUrl}\"></head>`,\n );\n }\n }\n\n // Inject styles only if customCSS is provided\n const styles = options?.customCSS || '';\n\n if (styles && styledHtml.includes('<head>')) {\n styledHtml = styledHtml.replace('<head>', `<head><style>${styles}</style>`);\n } else if (styles) {\n styledHtml = styledHtml.replace(\n /(<html[^>]*>)/i,\n `$1<head><style>${styles}</style></head>`,\n );\n }\n\n return styledHtml;\n }\n\n /**\n * Sanitize HTML content\n */\n sanitizeHtml(html: string): string {\n // Remove scripts\n let sanitized = html.replace(/<script\\b[^>]*>[\\s\\S]*?<\\/script>/gim, '');\n\n // Remove noscript tags\n sanitized = sanitized.replace(/<noscript[\\s\\S]*?<\\/noscript>/gi, '');\n\n return sanitized;\n }\n\n /**\n * Check if content is a full HTML document\n */\n isFullDocument(html: string): boolean {\n return /^\\s*(<html|<!DOCTYPE)/i.test(html);\n }\n\n /**\n * Remove all links from HTML, keeping the text content\n */\n removeLinks(html: string): string {\n // Replace anchor tags with their text content\n return html.replace(/<a\\b[^>]*>([\\s\\S]*?)<\\/a>/gim, '$1');\n }\n\n /**\n * Wrap HTML fragment in a document\n */\n wrapFragment(html: string): string {\n return `<!DOCTYPE html>\n<html>\n<head>\n <meta charset=\"utf-8\">\n <meta http-equiv=\"Content-Security-Policy\" content=\"default-src 'none'; script-src 'none'; style-src 'unsafe-inline';\">\n <style>\n body {\n margin: 0;\n padding: 16px;\n font-family: system-ui, -apple-system, sans-serif;\n white-space: pre-wrap;\n word-wrap: break-word;\n }\n img { max-width: 100%; height: auto; }\n body {\n pointer-events: none;\n user-select: none;\n }\n </style>\n</head>\n<body>\n ${html}\n</body>\n</html>`;\n }\n}","import { BaseProvider } from \"./base-provider\";\nimport {\n AIProvider,\n ParsedResponse,\n ParseOptions,\n ContentExtraction,\n ProviderMetadata,\n} from \"../core/types\";\n\nexport class ChatGPTProvider extends BaseProvider {\n readonly name: AIProvider = \"CHATGPT\";\n readonly baseUrl = \"https://chatgpt.com\";\n\n\n extractContent(response: any): ContentExtraction {\n return this.extractContentCommon(response);\n }\n\n /**\n * Remove links from HTML, preserving badge styling\n * Converts <a> tags to <span> while keeping class attributes\n */\n removeLinks(html: string): string {\n // Replace anchor tags with span tags, keeping all attributes except href/alt/rel/target\n return html\n .replace(/<a\\b([^>]*)>/gi, (match, attributes) => {\n // Remove link-specific attributes but keep others (class, style, etc.)\n const cleanedAttrs = attributes\n .replace(/\\s+href\\s*=\\s*[\"'][^\"']*[\"']/gi, \"\")\n .replace(/\\s+alt\\s*=\\s*[\"'][^\"']*[\"']/gi, \"\")\n .replace(/\\s+rel\\s*=\\s*[\"'][^\"']*[\"']/gi, \"\")\n .replace(/\\s+target\\s*=\\s*[\"'][^\"']*[\"']/gi, \"\")\n .trim();\n return `<span${cleanedAttrs ? \" \" + cleanedAttrs : \"\"}>`;\n })\n .replace(/<\\/a>/gi, \"</span>\");\n }\n\n /**\n * Remove ChatGPT header from HTML\n */\n removeHeader(html: string): string {\n let cleaned = html;\n\n // Remove page header by id\n cleaned = cleaned.replace(\n /<header[^>]*id=\"page-header\"[^>]*>.*?<\\/header>/gis,\n \"\"\n );\n\n return cleaned;\n }\n\n /**\n * Remove ChatGPT sidebar from HTML\n */\n removeSidebar(html: string): string {\n let cleaned = html;\n\n // Hide Sidebar\n cleaned = cleaned.replace(/<nav[^>]*>.*?<\\/nav>/gis, \"\");\n cleaned = cleaned.replace(\n /<div[^>]*class=\"[^\"]*sidebar[^\"]*\"[^>]*>.*?<\\/div>/gis,\n \"\"\n );\n\n return cleaned;\n }\n\n /**\n * Remove ChatGPT footer/composer from HTML\n */\n removeFooter(html: string): string {\n let cleaned = html;\n\n // Remove the thread-bottom-container (scroll button container)\n cleaned = cleaned.replace(\n /<div[^>]*id=\"thread-bottom-container\"[^>]*>.*?<\\/div><\\/div><\\/div>/gis,\n \"\"\n );\n\n // Remove the entire thread-bottom div (contains composer and inputs)\n cleaned = cleaned.replace(\n /<div[^>]*id=\"thread-bottom\"[^>]*>.*?<\\/div><\\/div><\\/div><\\/div><\\/div>/gis,\n \"\"\n );\n\n // Remove composer leading button (plus button)\n cleaned = cleaned.replace(\n /<div[^>]*class=\"[^\"]*\\[grid-area:leading\\][^\"]*\"[^>]*>.*?<\\/div><\\/div><\\/div>/gis,\n \"\"\n );\n\n // Remove composer footer actions (search button, etc.)\n cleaned = cleaned.replace(\n /<div[^>]*class=\"[^\"]*\\[grid-area:footer\\][^\"]*\"[^>]*>.*?<\\/div><\\/div><\\/div><\\/div><\\/div>/gis,\n \"\"\n );\n\n // Remove composer trailing buttons (dictate, send buttons)\n cleaned = cleaned.replace(\n /<div[^>]*class=\"[^\"]*\\[grid-area:trailing\\][^\"]*\"[^>]*>.*?<\\/div><\\/div><\\/div>/gis,\n \"\"\n );\n\n // Remove disclaimer footer (language-agnostic, targets view-transition-name)\n cleaned = cleaned.replace(\n /<div[^>]*\\[view-transition-name:var\\(--vt-disclaimer\\)\\][^>]*>.*?<\\/div><\\/div>/gis,\n \"\"\n );\n\n return cleaned;\n }\n\n parse(response: any, options?: ParseOptions): ParsedResponse {\n const { html, text } = this.extractContent(response);\n\n if (!html) {\n throw new Error(\"No HTML content found in ChatGPT response\");\n }\n\n let finalHtml = html;\n\n const removeFooter = options?.removeFooter ?? false;\n\n // Sanitize HTML\n finalHtml = this.sanitizeHtml(finalHtml);\n\n // Remove header if requested\n if (options?.removeHeader) {\n finalHtml = this.removeHeader(finalHtml);\n }\n\n // Remove sidebar if requested\n if (options?.removeSidebar) {\n finalHtml = this.removeSidebar(finalHtml);\n }\n\n // Remove footer if requested\n if (removeFooter) {\n finalHtml = this.removeFooter(finalHtml);\n }\n\n // Remove links if requested\n if (options?.removeLinks) {\n finalHtml = this.removeLinks(finalHtml);\n }\n\n finalHtml = this.injectStyles(finalHtml, {\n baseUrl: this.baseUrl,\n customCSS: \"\",\n });\n\n return {\n provider: this.name,\n html: finalHtml,\n text,\n metadata: {\n isFullDocument: this.isFullDocument(finalHtml),\n headerRemoved: options?.removeHeader || false,\n sidebarRemoved: options?.removeSidebar || false,\n footerRemoved: removeFooter,\n linksRemoved: options?.removeLinks || false,\n } as ProviderMetadata,\n };\n }\n}\n","import { BaseProvider } from './base-provider';\nimport { AIProvider, ParsedResponse, ParseOptions, ContentExtraction, ProviderMetadata } from '../core/types';\n\nexport class GeminiProvider extends BaseProvider {\n readonly name: AIProvider = 'GEMINI';\n readonly baseUrl = 'https://gemini.google.com';\n\n\n extractContent(response: any): ContentExtraction {\n return this.extractContentCommon(response, true);\n }\n\n /**\n * Remove Gemini header/navbar from HTML\n */\n removeHeader(html: string): string {\n let cleaned = html;\n\n // Remove the Google navbar with boqOnegoogleliteOgbOneGoogleBar class\n cleaned = cleaned.replace(/<div[^>]*class=\"[^\"]*boqOnegoogleliteOgbOneGoogleBar[^\"]*\"[^>]*>.*?<\\/div><\\/div><\\/div><\\/div>/gis, '');\n\n // Remove side-nav-menu-button (hamburger menu)\n cleaned = cleaned.replace(/<div[^>]*class=\"[^\"]*side-nav-menu-button[^\"]*\"[^>]*>.*?<\\/div>/gis, '');\n\n // Remove top-bar-actions (About Gemini, Gemini App, Subscriptions, For Business links)\n cleaned = cleaned.replace(/<top-bar-actions[^>]*>.*?<\\/top-bar-actions>/gis, '');\n\n // Remove desktop-ogb-buffer\n cleaned = cleaned.replace(/<div[^>]*class=\"[^\"]*desktop-ogb-buffer[^\"]*\"[^>]*><\\/div>/gis, '');\n\n return cleaned;\n }\n\n /**\n * Remove Gemini footer/follow-up input box from HTML\n */\n removeFooter(html: string): string {\n // Remove input-container (text input, upload button, send button, disclaimer)\n return html.replace(/<input-container[^>]*>.*?<\\/input-container>/gis, '');\n }\n\n /**\n * Remove Gemini sidebar from HTML\n */\n removeSidebar(html: string): string {\n // Remove bard-sidenav element\n return html.replace(/<bard-sidenav[^>]*>.*?<\\/bard-sidenav>/gis, '');\n }\n\n parse(response: any, options?: ParseOptions): ParsedResponse {\n const { html, text, sources } = this.extractContent(response);\n\n if (!html) {\n throw new Error('No HTML content found in Gemini response');\n }\n\n let finalHtml = html;\n\n const removeHeader = options?.removeHeader ?? false;\n const removeFooter = options?.removeFooter ?? false;\n\n // Sanitize HTML (remove scripts and noscript)\n finalHtml = this.sanitizeHtml(finalHtml);\n\n // Remove header if requested\n if (removeHeader) {\n finalHtml = this.removeHeader(finalHtml);\n }\n\n // Remove footer if requested\n if (removeFooter) {\n finalHtml = this.removeFooter(finalHtml);\n }\n\n // Remove sidebar if requested\n if (options?.removeSidebar) {\n finalHtml = this.removeSidebar(finalHtml);\n }\n\n // Remove links if requested\n if (options?.removeLinks) {\n finalHtml = this.removeLinks(finalHtml);\n }\n\n finalHtml = this.injectStyles(finalHtml, {\n baseUrl: this.baseUrl,\n customCSS: '',\n });\n\n return {\n provider: this.name,\n html: finalHtml,\n text,\n sources,\n metadata: {\n isFullDocument: this.isFullDocument(finalHtml),\n headerRemoved: removeHeader,\n footerRemoved: removeFooter,\n sidebarRemoved: options?.removeSidebar || false,\n linksRemoved: options?.removeLinks || false,\n } as ProviderMetadata,\n };\n }\n}","import { BaseProvider } from \"./base-provider\";\nimport {\n AIProvider,\n ParsedResponse,\n ParseOptions,\n ContentExtraction,\n ProviderMetadata,\n} from \"../core/types\";\n\nexport class PerplexityProvider extends BaseProvider {\n readonly name: AIProvider = \"PERPLEXITY\";\n readonly baseUrl = \"https://www.perplexity.ai\";\n\n extractContent(response: any): ContentExtraction {\n return this.extractContentCommon(response);\n }\n\n /**\n * Remove Perplexity header/navbar from HTML\n */\n removeHeader(html: string): string {\n // Remove navbar by targeting the unique @container/header class\n // Matches from the navbar opening div through the border divider at the bottom\n return html.replace(\n /<div[^>]*class=\"[^\"]*@container\\/header[^\"]*\"[^>]*>.*?<div[^>]*class=\"[^\"]*absolute bottom-0 inset-x-0 border-b[^\"]*\"[^>]*><\\/div>/gis,\n \"\"\n );\n }\n\n /**\n * Remove Perplexity footer/followup input from HTML\n */\n removeFooter(html: string): string {\n let cleaned = html;\n const regex =\n /<div[^>]*class=\"[^\"]*erp-sidecar:fixed erp-sidecar:w-full bottom-safeAreaInsetBottom p-md pointer-events-none z-10 absolute border-subtlest ring-subtlest divide-subtlest bg-transparent[^\"]*\"[^>]*>[\\s\\S]*?(?=<div[^>]*class=\"[^\"]*fixed inset-y-0 right-0[^\"]*\")/gis;\n cleaned = cleaned.replace(regex, \"\");\n return cleaned;\n }\n\n parse(response: any, options?: ParseOptions): ParsedResponse {\n const { html, text } = this.extractContent(response);\n\n if (!html) {\n throw new Error(\"No HTML content found in Perplexity response\");\n }\n\n let finalHtml = html;\n\n const removeHeader = options?.removeHeader ?? false;\n const removeFooter = options?.removeFooter ?? false;\n\n // Sanitize HTML\n finalHtml = this.sanitizeHtml(finalHtml);\n\n // Remove header if requested\n if (removeHeader) {\n finalHtml = this.removeHeader(finalHtml);\n }\n\n // Remove footer if requested\n if (removeFooter) {\n finalHtml = this.removeFooter(finalHtml);\n }\n\n // Remove links if requested\n if (options?.removeLinks) {\n finalHtml = this.removeLinks(finalHtml);\n }\n\n finalHtml = this.injectStyles(finalHtml, {\n baseUrl: this.baseUrl,\n customCSS: '',\n });\n\n return {\n provider: this.name,\n html: finalHtml,\n text,\n metadata: {\n isFullDocument: this.isFullDocument(finalHtml),\n linksRemoved: options?.removeLinks || false,\n headerRemoved: removeHeader,\n footerRemoved: removeFooter,\n } as ProviderMetadata,\n };\n }\n}\n","import { BaseProvider } from './base-provider';\nimport { AIProvider, ParsedResponse, ParseOptions, ContentExtraction, ProviderMetadata } from '../core/types';\n\nexport class CopilotProvider extends BaseProvider {\n readonly name: AIProvider = 'COPILOT';\n readonly baseUrl = 'https://copilot.microsoft.com';\n\n\n extractContent(response: any): ContentExtraction {\n return this.extractContentCommon(response);\n }\n\n /**\n * Remove Copilot header/navbar from HTML\n */\n removeHeader(html: string): string {\n let cleaned = html;\n\n // Remove backstage-chats (hidden navbar element)\n cleaned = cleaned.replace(/<div[^>]*class=\"[^\"]*relative shrink-0 min-h-14[^\"]*\"[^>]*data-testid=\"backstage-chats\"[^>]*>.*?<\\/div>/gis, '');\n\n // Remove date divider (e.g., \"Today\" with horizontal line)\n cleaned = cleaned.replace(/<div[^>]*class=\"[^\"]*flex items-center px-6 mx-auto w-full max-w-chat[^\"]*\"[^>]*>.*?<span[^>]*data-testid=\"date-divider\"[^>]*>.*?<\\/span>.*?<div[^>]*class=\"[^\"]*border-t-\\[1px\\][^\"]*\"[^>]*>.*?<\\/div>.*?<\\/div>/gis, '');\n\n // Remove settings wrapper (share/settings buttons in top-right corner)\n cleaned = cleaned.replace(/<div[^>]*class=\"[^\"]*absolute flex end-6 origin-top-right flex-col items-end[^\"]*\"[^>]*data-testid=\"settings-wrapper\"[^>]*>.*?<\\/div><\\/div>/gis, '');\n\n return cleaned;\n }\n\n /**\n * Remove Copilot footer/followup input box from HTML\n */\n removeFooter(html: string): string {\n let cleaned = html;\n\n // Remove the composer (input box at bottom)\n // Starts with: <div class=\"absolute bottom-0 w-full\">\n // Contains: file input, composer content with textarea, buttons (home, attach, chat mode, audio call)\n cleaned = cleaned.replace(/<div[^>]*class=\"[^\"]*absolute bottom-0 w-full[^\"]*\"[^>]*>.*?<\\/div><\\/div><\\/div><\\/div><\\/div><\\/div><\\/div><\\/div><\\/div><\\/div><\\/div><\\/div>/gis, '');\n\n // Remove spacer div for composer height\n cleaned = cleaned.replace(/<div[^>]*class=\"[^\"]*mt-\\[var\\(--composer-container-height\\)\\][^\"]*\"[^>]*><\\/div>/gis, '');\n\n // Remove \"scroll to bottom\" button (full container with button and inner content)\n cleaned = cleaned.replace(/<div[^>]*class=\"[^\"]*pointer-events-none absolute flex justify-center z-20 inset-x-0 bottom-\\[calc\\(var\\(--composer-container-height\\)\\+1rem\\)\\][^\"]*\"[^>]*>.*?<button[^>]*data-testid=\"scroll-to-bottom-button\"[^>]*>.*?<\\/button><\\/div>/gis, '');\n\n return cleaned;\n }\n\n /**\n * Remove Copilot cookie banner from HTML\n */\n removeCookieBanner(html: string): string {\n let cleaned = html;\n\n // Remove cookie banner by id\n cleaned = cleaned.replace(/<div[^>]*id=\"cookie-banner\"[^>]*>.*?<\\/div>.*?<\\/div>.*?<\\/div>.*?<\\/div>/gis, '');\n\n // Remove cookie banner by max-w-cookie-banner class (outer container)\n cleaned = cleaned.replace(/<div[^>]*class=\"[^\"]*max-w-cookie-banner[^\"]*\"[^>]*>.*?<\\/div>.*?<\\/div>.*?<\\/div>.*?<\\/div>/gis, '');\n\n return cleaned;\n }\n\n /**\n * Remove Copilot sidebar from HTML\n */\n removeSidebar(html: string): string {\n let cleaned = html;\n\n // Remove the inner sidebar div\n // Starts with: <div class=\"absolute h-full w-0 will-change-auto max-md:bg-sidebar-light...\" style=\"width: 52px;\">\n // Ends right before: <main class=\"relative flex w-full min-w-0 will-change-auto...\n cleaned = cleaned.replace(/<div[^>]*class=\"[^\"]*absolute h-full w-0 will-change-auto max-md:bg-sidebar-light[^\"]*\"[^>]*style=\"[^\"]*\"[^>]*>.*?<main/gis, '<main');\n\n return cleaned;\n }\n\n parse(response: any, options?: ParseOptions): ParsedResponse {\n const { html, text } = this.extractContent(response);\n\n if (!html) {\n throw new Error('No HTML content found in Copilot response');\n }\n\n let finalHtml = html;\n\n const removeHeader = options?.removeHeader ?? false;\n const removeFooter = options?.removeFooter ?? false;\n\n // Sanitize HTML\n finalHtml = this.sanitizeHtml(finalHtml);\n\n // Remove cookie banner (always)\n finalHtml = this.removeCookieBanner(finalHtml);\n\n // Remove header if requested\n if (removeHeader) {\n finalHtml = this.removeHeader(finalHtml);\n }\n\n // Remove footer if requested\n if (removeFooter) {\n finalHtml = this.removeFooter(finalHtml);\n }\n\n // Remove sidebar if requested\n if (options?.removeSidebar) {\n finalHtml = this.removeSidebar(finalHtml);\n }\n\n // Remove links if requested\n if (options?.removeLinks) {\n finalHtml = this.removeLinks(finalHtml);\n }\n\n finalHtml = this.injectStyles(finalHtml, {\n baseUrl: this.baseUrl,\n customCSS: '',\n });\n\n return {\n provider: this.name,\n html: finalHtml,\n text,\n metadata: {\n isFullDocument: this.isFullDocument(finalHtml),\n cookieBannerRemoved: true,\n headerRemoved: removeHeader,\n footerRemoved: removeFooter,\n sidebarRemoved: options?.removeSidebar || false,\n linksRemoved: options?.removeLinks || false,\n } as ProviderMetadata,\n };\n }\n}","import { BaseProvider } from \"./base-provider\";\nimport {\n AIProvider,\n ParsedResponse,\n ParseOptions,\n ContentExtraction,\n ProviderMetadata,\n} from \"../core/types\";\n\nexport class AIOverviewProvider extends BaseProvider {\n readonly name: AIProvider = \"AIOVERVIEW\";\n readonly baseUrl = \"https://www.google.com\";\n\n extractContent(response: any): ContentExtraction {\n return this.extractContentCommon(response, true);\n }\n\n /**\n * Remove Google Search header/navbar from HTML\n */\n removeHeader(html: string): string {\n // Remove header elements via CSS injection\n return html;\n }\n\n /**\n * Remove Google Search footer from HTML\n */\n removeFooter(html: string): string {\n // Remove footer elements via CSS injection\n return html;\n }\n\n /**\n * Remove Google Search sidebar from HTML\n */\n removeSidebar(html: string): string {\n // Remove sidebar elements via CSS injection\n return html;\n }\n\n parse(response: any, options?: ParseOptions): ParsedResponse {\n const { html, sources } = this.extractContent(response);\n\n if (!html) {\n throw new Error(\"No HTML content found in AI Overview response\");\n }\n\n let finalHtml = html;\n\n // For AI Overview, default to removing header and footer for cleaner display\n const removeHeader = options?.removeHeader ?? true;\n const removeFooter = options?.removeFooter ?? true;\n\n // Sanitize HTML\n finalHtml = this.sanitizeHtml(finalHtml);\n\n // Remove header if requested\n if (removeHeader) {\n finalHtml = this.removeHeader(finalHtml);\n }\n\n // Remove footer if requested\n if (removeFooter) {\n finalHtml = this.removeFooter(finalHtml);\n }\n\n // Remove sidebar if requested\n if (options?.removeSidebar) {\n finalHtml = this.removeSidebar(finalHtml);\n }\n\n // Remove links if requested\n if (options?.removeLinks) {\n finalHtml = this.removeLinks(finalHtml);\n }\n\n // Build CSS based on options\n let stylesToInject = \"\";\n\n // Header removal styles\n if (removeHeader) {\n stylesToInject += `\n /* Header hiding */\n header, #header, #searchform, .sfbg, #appbar,\n div[role=\"navigation\"], #leftnav, #sidetogether,\n [role=\"banner\"], .Fgvgjc, #hdtb, .hdtb-msb,\n .DZ13He, .wYq63b, .eT9Cje, .bNg8Rb, .S6VXfe, .Lu57id {\n display: none !important;\n }\n `;\n }\n\n // Sidebar removal styles\n if (options?.removeSidebar) {\n stylesToInject += `\n /* Sidebar hiding */\n #leftnav, #sidetogether {\n display: none !important;\n }\n `;\n }\n\n // Footer removal styles\n if (removeFooter) {\n stylesToInject += `\n /* Footer hiding */\n footer, #footer, .fbar,\n .pdp-nav, [aria-label=\"Main menu\"], .gb_Td, .gb_L {\n display: none !important;\n }\n `;\n }\n\n // Inject base URL and styles\n finalHtml = this.injectStyles(finalHtml, {\n baseUrl: this.baseUrl,\n customCSS: stylesToInject,\n });\n\n return {\n provider: this.name,\n html: finalHtml,\n sources,\n metadata: {\n isFullDocument: this.isFullDocument(finalHtml),\n headerRemoved: removeHeader,\n footerRemoved: removeFooter,\n sidebarRemoved: options?.removeSidebar || false,\n linksRemoved: options?.removeLinks || false,\n } as ProviderMetadata,\n };\n }\n}\n","import { BaseProvider } from \"./base-provider\";\nimport {\n AIProvider,\n ParsedResponse,\n ParseOptions,\n ContentExtraction,\n ProviderMetadata,\n} from \"../core/types\";\n\nexport class AIModeProvider extends BaseProvider {\n readonly name: AIProvider = \"AIMODE\";\n readonly baseUrl = \"https://www.google.com\";\n\n extractContent(response: any): ContentExtraction {\n return this.extractContentCommon(response);\n }\n\n /**\n * Remove Google Search header/navbar from HTML\n */\n removeHeader(html: string): string {\n let cleaned = html;\n\n // Remove the AI Mode filter/header bar\n // Starts with <div jsname=\"oEQ3x\" class=\"DZ13He YNk70c EjQTId\">\n // Contains the Filters and Topics navigation (AI Mode, All, Images, Videos, News, More)\n // Ends with closing divs after <hr class=\"e9c7U\">\n cleaned = cleaned.replace(\n /<div[^>]*jsname=\"oEQ3x\"[^>]*class=\"[^\"]*DZ13He[^\"]*\"[^>]*>.*?<hr class=\"e9c7U\">.*?<\\/div><\\/div><\\/div><\\/div><\\/div>/gis,\n \"\"\n );\n\n return cleaned;\n }\n\n /**\n * Remove Google Search footer from HTML\n */\n removeFooter(html: string): string {\n let cleaned = html;\n\n // Remove the AI Mode input bar/footer\n // Target the most unique identifier: data-xid=\"aim-mars-input-plate\"\n // This element is deeply nested, so we need to match many closing divs\n cleaned = cleaned.replace(\n /<div[^>]*data-xid=\"aim-mars-input-plate\"[^>]*>[\\s\\S]*?<\\/div><\\/div><\\/div><\\/div><\\/div>/gis,\n \"\"\n );\n\n // Fallback: Target by jscontroller P5gZDb which wraps the input plate\n cleaned = cleaned.replace(\n /<div[^>]*jscontroller=\"P5gZDb\"[^>]*>[\\s\\S]*?<\\/div><\\/div><\\/div>/gis,\n \"\"\n );\n\n // Fallback: Target the t0ITR container\n cleaned = cleaned.replace(\n /<div[^>]*class=\"[^\"]*t0ITR hh3ttd[^\"]*\"[^>]*>[\\s\\S]*?<\\/div><\\/div>/gis,\n \"\"\n );\n\n // Fallback: Target outer y4VEUd vve6Ce wrapper\n cleaned = cleaned.replace(\n /<div[^>]*class=\"[^\"]*y4VEUd vve6Ce[^\"]*\"[^>]*>[\\s\\S]*?<\\/div><\\/div>/gis,\n \"\"\n );\n\n return cleaned;\n }\n\n /**\n * Remove Google Search sidebar from HTML\n */\n removeSidebar(html: string): string {\n let cleaned = html;\n\n // Remove the AI Mode history panel/slide-over\n // Target by aria-label and class\n cleaned = cleaned.replace(\n /<div[^>]*class=\"[^\"]*ho072b[^\"]*\"[^>]*aria-label=\"AI Mode history\"[^>]*>[\\s\\S]*?<\\/div><\\/div><\\/div><\\/div><\\/div><\\/div>/gis,\n \"\"\n );\n\n // Remove the floating action button (FAB) with \"Start new search\" and \"AI Mode history\"\n // Target by jsname and class, contains OEwhSe wrapper\n cleaned = cleaned.replace(\n /<div[^>]*jsname=\"NlVIob\"[^>]*class=\"[^\"]*qEn1od[^\"]*\"[^>]*>[\\s\\S]*?<\\/div><\\/div><\\/div>/gis,\n \"\"\n );\n\n // Fallback: Target by inner class OEwhSe\n cleaned = cleaned.replace(\n /<div[^>]*class=\"[^\"]*OEwhSe[^\"]*\"[^>]*>[\\s\\S]*?<\\/div><\\/div>/gis,\n \"\"\n );\n\n // Fallback: Target buttons with aria-label\n cleaned = cleaned.replace(\n /<button[^>]*aria-label=\"Start new search\"[^>]*>[\\s\\S]*?<\\/button>/gis,\n \"\"\n );\n cleaned = cleaned.replace(\n /<button[^>]*aria-label=\"AI Mode history\"[^>]*>[\\s\\S]*?<\\/button>/gis,\n \"\"\n );\n\n return cleaned;\n }\n\n parse(response: any, options?: ParseOptions): ParsedResponse {\n const { html, text } = this.extractContent(response);\n\n if (!html) {\n throw new Error(\"No HTML content found in AI Mode response\");\n }\n\n let finalHtml = html;\n\n // For AI Mode, default to removing header and footer for cleaner display\n const removeHeader = options?.removeHeader ?? true;\n const removeFooter = options?.removeFooter ?? true;\n\n // Sanitize HTML\n finalHtml = this.sanitizeHtml(finalHtml);\n\n // Remove header if requested\n if (removeHeader) {\n finalHtml = this.removeHeader(finalHtml);\n }\n\n // Remove footer if requested\n if (removeFooter) {\n finalHtml = this.removeFooter(finalHtml);\n }\n\n // Remove sidebar if requested\n if (options?.removeSidebar) {\n finalHtml = this.removeSidebar(finalHtml);\n }\n\n // Remove links if requested\n if (options?.removeLinks) {\n finalHtml = this.removeLinks(finalHtml);\n }\n\n // Build CSS based on options\n let stylesToInject = \"\";\n\n // Always inject general layout\n /* Remove cookie consent banner */\n stylesToInject += `\n .KxvlWc, #CXQnmb {\n display: none !important;\n }\n `;\n\n // Header removal styles\n if (removeHeader) {\n stylesToInject += `\n /* Header hiding */\n header, #header, #searchform, .sfbg, #appbar,\n div[role=\"navigation\"], #leftnav, #sidetogether,\n [role=\"banner\"], .Fgvgjc, #hdtb, .hdtb-msb,\n .DZ13He, .wYq63b, .eT9Cje, .bNg8Rb, .S6VXfe, .Lu57id {\n display: none !important;\n }\n `;\n }\n\n // Sidebar removal styles\n if (options?.removeSidebar) {\n stylesToInject += `\n /* Sidebar hiding */\n #leftnav, #sidetogether {\n display: none !important;\n }\n `;\n }\n\n // Footer removal styles\n if (removeFooter) {\n stylesToInject += `\n /* Footer hiding */\n footer, #footer, .fbar,\n .pdp-nav, [aria-label=\"Main menu\"], .gb_Td, .gb_L {\n display: none !important;\n }\n `;\n }\n\n // Inject base URL and styles\n finalHtml = this.injectStyles(finalHtml, {\n baseUrl: this.baseUrl,\n customCSS: stylesToInject,\n });\n\n return {\n provider: this.name,\n html: finalHtml,\n text,\n metadata: {\n isFullDocument: this.isFullDocument(finalHtml),\n headerRemoved: removeHeader,\n footerRemoved: removeFooter,\n sidebarRemoved: options?.removeSidebar || false,\n linksRemoved: options?.removeLinks || false,\n } as ProviderMetadata,\n };\n }\n}\n","import { BaseProvider } from \"./base-provider\";\nimport {\n AIProvider,\n ParsedResponse,\n ParseOptions,\n ContentExtraction,\n ProviderMetadata,\n} from \"../core/types\";\n\nexport class GrokProvider extends BaseProvider {\n readonly name: AIProvider = \"GROK\";\n readonly baseUrl = \"https://grok.com\";\n\n extractContent(response: any): ContentExtraction {\n return this.extractContentCommon(response);\n }\n\n /**\n * Remove Grok header from HTML (using CSS-based hiding)\n */\n removeHeader(html: string): string {\n // Header removal is now done via CSS in the parse method\n return html;\n }\n\n /**\n * Remove Grok footer/input area from HTML (using CSS-based hiding)\n */\n removeFooter(html: string): string {\n // Footer removal is now done via CSS in the parse method\n return html;\n }\n\n parse(response: any, options?: ParseOptions): ParsedResponse {\n const { html, text } = this.extractContent(response);\n\n if (!html) {\n throw new Error(\"No HTML content found in Grok response\");\n }\n\n let finalHtml = html;\n\n // Sanitize HTML\n finalHtml = this.sanitizeHtml(finalHtml);\n\n // Build CSS based on options\n let stylesToInject = '';\n\n // Header hiding via CSS\n if (options?.removeHeader) {\n stylesToInject += `\n /* Header hiding - hide elements with Grok's header class pattern */\n div[class*=\"h-16\"][class*=\"top-0\"][class*=\"z-10\"],\n div[class*=\"absolute\"][class*=\"inset-x-0\"][class*=\"top-0\"] {\n display: none !important;\n }\n `;\n }\n\n // Footer hiding via CSS\n if (options?.removeFooter) {\n stylesToInject += `\n /* Footer hiding - hide Grok's footer/input area */\n div[class*=\"absolute\"][class*=\"inset-x-0\"][class*=\"bottom-0\"][class*=\"max-w-breakout\"],\n div[class*=\"absolute\"][class*=\"bottom-0\"][class*=\"w-full\"] {\n display: none !important;\n }\n `;\n }\n\n // Remove links if requested\n if (options?.removeLinks) {\n finalHtml = this.removeLinks(finalHtml);\n }\n\n finalHtml = this.injectStyles(finalHtml, {\n baseUrl: this.baseUrl,\n customCSS: stylesToInject,\n });\n\n return {\n provider: this.name,\n html: finalHtml,\n text,\n metadata: {\n isFullDocument: this.isFullDocument(finalHtml),\n linksRemoved: options?.removeLinks || false,\n headerRemoved: options?.removeHeader || false,\n footerRemoved: options?.removeFooter || false,\n } as ProviderMetadata,\n };\n }\n}\n","import { AIProvider, ParsedResponse, ParseOptions, extractContentCommon } from './types';\nimport { ProviderDetector } from './detector';\nimport { ChatGPTProvider } from '../providers/chatgpt';\nimport { GeminiProvider } from '../providers/gemini';\nimport { PerplexityProvider } from '../providers/perplexity';\nimport { CopilotProvider } from '../providers/copilot';\nimport { AIOverviewProvider } from '../providers/ai-overview';\nimport { AIModeProvider } from '../providers/ai-mode';\nimport { GrokProvider } from '../providers/grok';\n\nexport class AIResponseParser {\n private providers: Map<AIProvider, any> = new Map();\n\n constructor() {\n this.providers.set('CHATGPT', new ChatGPTProvider());\n this.providers.set('GEMINI', new GeminiProvider());\n this.providers.set('PERPLEXITY', new PerplexityProvider());\n this.providers.set('COPILOT', new CopilotProvider());\n this.providers.set('AIOVERVIEW', new AIOverviewProvider());\n this.providers.set('AIMODE', new AIModeProvider());\n this.providers.set('GROK', new GrokProvider());\n }\n\n /**\n * Parse an AI response with auto-detected provider\n */\n parse(response: any, options?: ParseOptions): ParsedResponse | null {\n const detection = ProviderDetector.detect(response);\n\n if (!detection) {\n // Try to parse as generic HTML if no provider detected\n return this.parseGeneric(response);\n }\n\n const provider = this.providers.get(detection.provider);\n if (!provider) {\n return null;\n }\n\n try {\n const parsed = provider.parse(response, options);\n return {\n ...parsed,\n metadata: {\n ...parsed.metadata,\n detectionConfidence: detection.confidence,\n },\n };\n } catch (error) {\n console.error(`Failed to parse response with ${detection.provider}:`, error);\n return null;\n }\n }\n\n /**\n * Parse with explicit provider specification\n */\n parseWithProvider(\n response: any,\n provider: AIProvider,\n options?: ParseOptions\n ): ParsedResponse | null {\n const providerInstance = this.providers.get(provider);\n if (!providerInstance) {\n throw new Error(`Unknown provider: ${provider}`);\n }\n\n try {\n return providerInstance.parse(response, options);\n } catch (error) {\n console.error(`Failed to parse response with ${provider}:`, error);\n return null;\n }\n }\n\n /**\n * Detect the provider from a response\n */\n detectProvider(response: any): AIProvider | null {\n const detection = ProviderDetector.detect(response);\n return detection?.provider || null;\n }\n\n /**\n * Get all possible providers with confidence scores\n */\n detectAllProviders(response: any): Array<{ provider: AIProvider; confidence: number }> {\n return ProviderDetector.getAllProviders(response);\n }\n\n /**\n * Parse as generic HTML when no specific provider is detected\n */\n private parseGeneric(response: any): ParsedResponse | null {\n const { html, text } = extractContentCommon(response);\n\n if (!html && !text) {\n return null;\n }\n\n // Basic sanitization\n let sanitizedHtml = html;\n if (sanitizedHtml) {\n sanitizedHtml = sanitizedHtml.replace(/<script\\b[^>]*>[\\s\\S]*?<\\/script>/gim, '');\n sanitizedHtml = sanitizedHtml.replace(/<noscript[\\s\\S]*?<\\/noscript>/gi, '');\n }\n\n return {\n provider: 'CHATGPT' as AIProvider, // Default to ChatGPT for unknown\n html: sanitizedHtml || '',\n text: text || '',\n metadata: {\n isGeneric: true,\n },\n };\n }\n\n /**\n * Get list of supported providers\n */\n getSupportedProviders(): AIProvider[] {\n return Array.from(this.providers.keys());\n }\n\n /**\n * Register a custom provider\n */\n registerProvider(provider: AIProvider, instance: any): void {\n this.providers.set(provider, instance);\n }\n}\n\n// Export a singleton instance\nexport const parser = new AIResponseParser();\n\n// Convenience functions\nexport const parseAiResponse = (response: any, options?: ParseOptions) =>\n parser.parse(response, options);\n\nexport const detectProvider = (response: any) =>\n parser.detectProvider(response);"],"names":["extractContentCommon","response","html","text","dataToCheck","result","trim","startsWith","includes","content","ProviderDetector","detect","scores","CHATGPT","GEMINI","PERPLEXITY","COPILOT","AIOVERVIEW","AIMODE","GROK","provider","patterns","Object","entries","this","PROVIDER_PATTERNS","pattern","_a","maxScore","detectedProvider","score","confidence","values","reduce","a","b","Math","max","getAllProviders","providers","matches","push","length","sort","validate","detected","_b","aioverview","_c","_d","BaseProvider","includeSources","sources","injectStyles","options","styledHtml","baseUrl","replace","styles","customCSS","sanitizeHtml","sanitized","isFullDocument","test","removeLinks","wrapFragment","ChatGPTProvider","constructor","name","extractContent","match","attributes","cleanedAttrs","removeHeader","cleaned","removeSidebar","removeFooter","parse","Error","finalHtml","metadata","headerRemoved","sidebarRemoved","footerRemoved","linksRemoved","GeminiProvider","PerplexityProvider","CopilotProvider","removeCookieBanner","cookieBannerRemoved","AIOverviewProvider","stylesToInject","AIModeProvider","GrokProvider","AIResponseParser","Map","set","detection","parseGeneric","get","parsed","detectionConfidence","error","console","parseWithProvider","providerInstance","detectProvider","detectAllProviders","sanitizedHtml","isGeneric","getSupportedProviders","Array","from","keys","registerProvider","instance","parser"],"mappings":"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"}
1
+ {"version":3,"file":"index.js","sources":["../src/core/types.ts","../src/core/detector.ts","../src/providers/base-provider.ts","../src/providers/chatgpt.ts","../src/providers/gemini.ts","../src/providers/perplexity.ts","../src/providers/copilot.ts","../src/providers/ai-overview.ts","../src/providers/ai-mode.ts","../src/providers/grok.ts","../src/core/parser.ts"],"sourcesContent":["export type AIProvider =\n | 'CHATGPT'\n | 'GEMINI'\n | 'PERPLEXITY'\n | 'COPILOT'\n | 'AIOVERVIEW'\n | 'AIMODE'\n | 'GROK';\n\nexport interface ParsedResponse {\n provider: AIProvider;\n html: string;\n text?: string;\n sources?: any[];\n metadata?: Record<string, any>;\n}\n\nexport interface ParseOptions {\n removeLinks?: boolean;\n removeHeader?: boolean;\n removeFooter?: boolean;\n removeSidebar?: boolean;\n removeSources?: boolean;\n}\n\nexport interface ProviderConfig {\n name: AIProvider;\n baseUrl: string;\n}\n\nexport interface DetectedProvider {\n provider: AIProvider;\n confidence: number;\n}\n\nexport interface StyleOptions {\n customCSS?: string;\n hideUI?: boolean;\n baseUrl?: string;\n}\n\nexport type ContentExtraction = {\n html?: string;\n text?: string;\n sources?: any[];\n};\n\n/**\n * Standardized metadata for provider responses\n */\nexport interface ProviderMetadata {\n isFullDocument?: boolean;\n headerRemoved?: boolean;\n footerRemoved?: boolean;\n sidebarRemoved?: boolean;\n linksRemoved?: boolean;\n cookieBannerRemoved?: boolean;\n sourcesRemoved?: boolean;\n detectionConfidence?: number;\n}\n\n/**\n * Common content extraction utility - shared across providers and parser\n */\nexport function extractContentCommon(response: any): ContentExtraction {\n let html = '';\n let text = '';\n\n // Handle nested structure\n let dataToCheck = response;\n if (response.result) {\n dataToCheck = response.result;\n }\n\n // Extract content\n if (typeof dataToCheck === 'string') {\n if (dataToCheck.trim().startsWith('<') && dataToCheck.includes('>')) {\n html = dataToCheck;\n } else {\n text = dataToCheck;\n }\n } else if (typeof dataToCheck === 'object' && dataToCheck !== null) {\n if (dataToCheck.html) {\n html = dataToCheck.html;\n } else if (dataToCheck.content) {\n if (dataToCheck.content.trim().startsWith('<')) {\n html = dataToCheck.content;\n } else {\n text = dataToCheck.content;\n }\n } else if (dataToCheck.text) {\n text = dataToCheck.text;\n }\n }\n\n return { html, text };\n}","import { AIProvider, DetectedProvider } from './types';\n\nexport class ProviderDetector {\n private static readonly PROVIDER_PATTERNS = {\n CHATGPT: [\n // Check for token-based CSS classes\n (response: any) => {\n const html = response?.result?.html || response?.html || '';\n return html.includes('bg-token-bg-primary') || html.includes('text-token-text-secondary');\n },\n // Check for OpenAI-specific patterns\n (response: any) => {\n const html = response?.result?.html || response?.html || '';\n return html.includes('chatgpt.com') || html.includes('openai.com');\n },\n ],\n GEMINI: [\n // Check for Material Design components\n (response: any) => {\n const html = response?.result?.html || response?.html || '';\n return html.includes('bard-sidenav') || html.includes('mat-sidenav');\n },\n // Check for Gemini-specific classes\n (response: any) => {\n const html = response?.result?.html || response?.html || '';\n return html.includes('gemini.google.com') || html.includes('gem-sys-color');\n },\n ],\n PERPLEXITY: [\n // Check for Perplexity domain\n (response: any) => {\n const html = response?.result?.html || response?.html || '';\n return html.includes('perplexity.ai');\n },\n // Check for Perplexity-specific structure\n (response: any) => {\n const html = response?.result?.html || response?.html || '';\n return html.includes('prose') && !html.includes('grok.com') && !html.includes('chatgpt.com');\n },\n ],\n COPILOT: [\n // Check for Copilot-specific elements\n (response: any) => {\n const html = response?.result?.html || response?.html || '';\n return html.includes('copilot.microsoft.com') || html.includes('data-testid=\"sidebar-container\"');\n },\n ],\n AIOVERVIEW: [\n // Check for AI Overview specific structure\n (response: any) => {\n if (response?.result?.aioverview?.text) return true;\n if (response?.aioverview?.text) return true;\n const html = response?.result?.html || response?.html || '';\n return html.includes('DnVkpd');\n },\n // Check for WIZ_global_data without AI Mode markers\n (response: any) => {\n const html = response?.result?.html || response?.html || '';\n return html.includes('WIZ_global_data') && !html.includes('aim-mars') && !html.includes('ho072b');\n },\n ],\n AIMODE: [\n // Check for AI Mode specific elements\n (response: any) => {\n const html = response?.result?.html || response?.html || '';\n return html.includes('DZ13He') || html.includes('wYq63b') || html.includes('AI Mode');\n },\n // Check for AI Mode specific input/sidebar\n (response: any) => {\n const html = response?.result?.html || response?.html || '';\n return html.includes('aim-mars') || html.includes('ho072b');\n },\n ],\n GROK: [\n // Check for Grok domain\n (response: any) => {\n const html = response?.result?.html || response?.html || '';\n return html.includes('grok.com') || html.includes('x.ai');\n },\n // Check for Grok CDN or app-specific patterns\n (response: any) => {\n const html = response?.result?.html || response?.html || '';\n return html.includes('cdn.grok.com') || html.includes('vaul-drawer');\n },\n ],\n };\n\n /**\n * Detect the AI provider from the response\n */\n static detect(response: any): DetectedProvider | null {\n const scores: Record<AIProvider, number> = {\n CHATGPT: 0,\n GEMINI: 0,\n PERPLEXITY: 0,\n COPILOT: 0,\n AIOVERVIEW: 0,\n AIMODE: 0,\n GROK: 0,\n };\n\n // Score each provider based on pattern matches\n for (const [provider, patterns] of Object.entries(this.PROVIDER_PATTERNS)) {\n for (const pattern of patterns) {\n try {\n if (pattern(response)) {\n scores[provider as AIProvider]++;\n }\n } catch {\n // Ignore pattern errors\n }\n }\n }\n\n // Find the provider with the highest score\n let maxScore = 0;\n let detectedProvider: AIProvider | null = null;\n\n for (const [provider, score] of Object.entries(scores)) {\n if (score > maxScore) {\n maxScore = score;\n detectedProvider = provider as AIProvider;\n }\n }\n\n // Return null if no patterns matched\n if (maxScore === 0) return null;\n\n return {\n provider: detectedProvider!,\n confidence: maxScore / Object.values(scores).reduce((a, b) => Math.max(a, b), 1),\n };\n }\n\n /**\n * Get all possible providers with their confidence scores\n */\n static getAllProviders(response: any): DetectedProvider[] {\n const providers: DetectedProvider[] = [];\n\n for (const [provider, patterns] of Object.entries(this.PROVIDER_PATTERNS)) {\n let matches = 0;\n for (const pattern of patterns) {\n try {\n if (pattern(response)) {\n matches++;\n }\n } catch {\n // Ignore pattern errors\n }\n }\n\n if (matches > 0) {\n providers.push({\n provider: provider as AIProvider,\n confidence: matches / patterns.length,\n });\n }\n }\n\n // Sort by confidence (highest first)\n return providers.sort((a, b) => b.confidence - a.confidence);\n }\n\n /**\n * Validate if a detected provider is likely correct\n */\n static validate(response: any, provider: AIProvider): boolean {\n const detected = this.detect(response);\n return detected?.provider === provider && detected.confidence > 0.5;\n }\n}","import { AIProvider, ParsedResponse, ParseOptions, StyleOptions, ContentExtraction, extractContentCommon } from '../core/types';\n\nexport abstract class BaseProvider {\n abstract readonly name: AIProvider;\n abstract readonly baseUrl: string;\n\n /**\n * Parse an AI response and return structured content\n */\n abstract parse(response: any, options?: ParseOptions): ParsedResponse;\n\n /**\n * Extract content from the response object\n */\n abstract extractContent(response: any): ContentExtraction;\n\n /**\n * Common content extraction logic - can be used by providers\n */\n protected extractContentCommon(response: any, includeSources = false): ContentExtraction {\n const result = extractContentCommon(response);\n\n if (includeSources) {\n let sources: any[] = [];\n const dataToCheck = response.result || response;\n\n if (typeof dataToCheck === 'object' && dataToCheck !== null) {\n if (dataToCheck.aioverview?.sources) {\n sources = dataToCheck.aioverview.sources;\n } else if (dataToCheck.sources) {\n sources = dataToCheck.sources;\n }\n }\n\n return { ...result, sources };\n }\n\n return result;\n }\n\n /**\n * Inject provider-specific styles into HTML\n */\n injectStyles(html: string, options?: StyleOptions): string {\n let styledHtml = html;\n\n // Inject base URL if not already present\n if (options?.baseUrl && !html.includes('<base ')) {\n if (styledHtml.includes('<head>')) {\n styledHtml = styledHtml.replace(\n '<head>',\n `<head><base href=\"${options.baseUrl}\">`,\n );\n } else {\n styledHtml = styledHtml.replace(\n /(<html[^>]*>)/i,\n `$1<head><base href=\"${options.baseUrl}\"></head>`,\n );\n }\n }\n\n // Inject styles only if customCSS is provided\n const styles = options?.customCSS || '';\n\n if (styles && styledHtml.includes('<head>')) {\n styledHtml = styledHtml.replace('<head>', `<head><style>${styles}</style>`);\n } else if (styles) {\n styledHtml = styledHtml.replace(\n /(<html[^>]*>)/i,\n `$1<head><style>${styles}</style></head>`,\n );\n }\n\n return styledHtml;\n }\n\n /**\n * Sanitize HTML content\n */\n sanitizeHtml(html: string): string {\n // Remove scripts\n let sanitized = html.replace(/<script\\b[^>]*>[\\s\\S]*?<\\/script>/gim, '');\n\n // Remove noscript tags\n sanitized = sanitized.replace(/<noscript[\\s\\S]*?<\\/noscript>/gi, '');\n\n return sanitized;\n }\n\n /**\n * Check if content is a full HTML document\n */\n isFullDocument(html: string): boolean {\n return /^\\s*(<html|<!DOCTYPE)/i.test(html);\n }\n\n /**\n * Remove all links from HTML, keeping the text content\n */\n removeLinks(html: string): string {\n // Replace anchor tags with their text content\n return html.replace(/<a\\b[^>]*>([\\s\\S]*?)<\\/a>/gim, '$1');\n }\n\n /**\n * Wrap HTML fragment in a document\n */\n wrapFragment(html: string): string {\n return `<!DOCTYPE html>\n<html>\n<head>\n <meta charset=\"utf-8\">\n <meta http-equiv=\"Content-Security-Policy\" content=\"default-src 'none'; script-src 'none'; style-src 'unsafe-inline';\">\n <style>\n body {\n margin: 0;\n padding: 16px;\n font-family: system-ui, -apple-system, sans-serif;\n white-space: pre-wrap;\n word-wrap: break-word;\n }\n img { max-width: 100%; height: auto; }\n body {\n pointer-events: none;\n user-select: none;\n }\n </style>\n</head>\n<body>\n ${html}\n</body>\n</html>`;\n }\n}","import { BaseProvider } from \"./base-provider\";\nimport {\n AIProvider,\n ParsedResponse,\n ParseOptions,\n ContentExtraction,\n ProviderMetadata,\n} from \"../core/types\";\n\nexport class ChatGPTProvider extends BaseProvider {\n readonly name: AIProvider = \"CHATGPT\";\n readonly baseUrl = \"https://chatgpt.com\";\n\n\n extractContent(response: any): ContentExtraction {\n return this.extractContentCommon(response);\n }\n\n /**\n * Remove links from HTML, preserving badge styling\n * Converts <a> tags to <span> while keeping class attributes\n */\n removeLinks(html: string): string {\n // Replace anchor tags with span tags, keeping all attributes except href/alt/rel/target\n return html\n .replace(/<a\\b([^>]*)>/gi, (match, attributes) => {\n // Remove link-specific attributes but keep others (class, style, etc.)\n const cleanedAttrs = attributes\n .replace(/\\s+href\\s*=\\s*[\"'][^\"']*[\"']/gi, \"\")\n .replace(/\\s+alt\\s*=\\s*[\"'][^\"']*[\"']/gi, \"\")\n .replace(/\\s+rel\\s*=\\s*[\"'][^\"']*[\"']/gi, \"\")\n .replace(/\\s+target\\s*=\\s*[\"'][^\"']*[\"']/gi, \"\")\n .trim();\n return `<span${cleanedAttrs ? \" \" + cleanedAttrs : \"\"}>`;\n })\n .replace(/<\\/a>/gi, \"</span>\");\n }\n\n /**\n * Remove ChatGPT header from HTML\n */\n removeHeader(html: string): string {\n let cleaned = html;\n\n // Remove page header by id\n cleaned = cleaned.replace(\n /<header[^>]*id=\"page-header\"[^>]*>.*?<\\/header>/gis,\n \"\"\n );\n\n return cleaned;\n }\n\n /**\n * Remove ChatGPT sidebar from HTML\n */\n removeSidebar(html: string): string {\n let cleaned = html;\n\n // Hide Sidebar\n cleaned = cleaned.replace(/<nav[^>]*>.*?<\\/nav>/gis, \"\");\n cleaned = cleaned.replace(\n /<div[^>]*class=\"[^\"]*sidebar[^\"]*\"[^>]*>.*?<\\/div>/gis,\n \"\"\n );\n\n return cleaned;\n }\n\n /**\n * Remove ChatGPT footer/composer from HTML\n */\n removeFooter(html: string): string {\n let cleaned = html;\n\n // Remove the thread-bottom-container (scroll button container)\n cleaned = cleaned.replace(\n /<div[^>]*id=\"thread-bottom-container\"[^>]*>.*?<\\/div><\\/div><\\/div>/gis,\n \"\"\n );\n\n // Remove the entire thread-bottom div (contains composer and inputs)\n cleaned = cleaned.replace(\n /<div[^>]*id=\"thread-bottom\"[^>]*>.*?<\\/div><\\/div><\\/div><\\/div><\\/div>/gis,\n \"\"\n );\n\n // Remove composer leading button (plus button)\n cleaned = cleaned.replace(\n /<div[^>]*class=\"[^\"]*\\[grid-area:leading\\][^\"]*\"[^>]*>.*?<\\/div><\\/div><\\/div>/gis,\n \"\"\n );\n\n // Remove composer footer actions (search button, etc.)\n cleaned = cleaned.replace(\n /<div[^>]*class=\"[^\"]*\\[grid-area:footer\\][^\"]*\"[^>]*>.*?<\\/div><\\/div><\\/div><\\/div><\\/div>/gis,\n \"\"\n );\n\n // Remove composer trailing buttons (dictate, send buttons)\n cleaned = cleaned.replace(\n /<div[^>]*class=\"[^\"]*\\[grid-area:trailing\\][^\"]*\"[^>]*>.*?<\\/div><\\/div><\\/div>/gis,\n \"\"\n );\n\n // Remove disclaimer footer (language-agnostic, targets view-transition-name)\n cleaned = cleaned.replace(\n /<div[^>]*\\[view-transition-name:var\\(--vt-disclaimer\\)\\][^>]*>.*?<\\/div><\\/div>/gis,\n \"\"\n );\n\n return cleaned;\n }\n\n parse(response: any, options?: ParseOptions): ParsedResponse {\n const { html, text } = this.extractContent(response);\n\n if (!html) {\n throw new Error(\"No HTML content found in ChatGPT response\");\n }\n\n let finalHtml = html;\n\n const removeFooter = options?.removeFooter ?? false;\n\n // Sanitize HTML\n finalHtml = this.sanitizeHtml(finalHtml);\n\n // Remove header if requested\n if (options?.removeHeader) {\n finalHtml = this.removeHeader(finalHtml);\n }\n\n // Remove sidebar if requested\n if (options?.removeSidebar) {\n finalHtml = this.removeSidebar(finalHtml);\n }\n\n // Remove footer if requested\n if (removeFooter) {\n finalHtml = this.removeFooter(finalHtml);\n }\n\n // Remove links if requested\n if (options?.removeLinks) {\n finalHtml = this.removeLinks(finalHtml);\n }\n\n finalHtml = this.injectStyles(finalHtml, {\n baseUrl: this.baseUrl,\n customCSS: \"\",\n });\n\n return {\n provider: this.name,\n html: finalHtml,\n text,\n metadata: {\n isFullDocument: this.isFullDocument(finalHtml),\n headerRemoved: options?.removeHeader || false,\n sidebarRemoved: options?.removeSidebar || false,\n footerRemoved: removeFooter,\n linksRemoved: options?.removeLinks || false,\n } as ProviderMetadata,\n };\n }\n}\n","import { BaseProvider } from './base-provider';\nimport { AIProvider, ParsedResponse, ParseOptions, ContentExtraction, ProviderMetadata } from '../core/types';\n\nexport class GeminiProvider extends BaseProvider {\n readonly name: AIProvider = 'GEMINI';\n readonly baseUrl = 'https://gemini.google.com';\n\n\n extractContent(response: any): ContentExtraction {\n return this.extractContentCommon(response, true);\n }\n\n /**\n * Remove Gemini header/navbar from HTML\n */\n removeHeader(html: string): string {\n let cleaned = html;\n\n // Remove the Google navbar with boqOnegoogleliteOgbOneGoogleBar class\n cleaned = cleaned.replace(/<div[^>]*class=\"[^\"]*boqOnegoogleliteOgbOneGoogleBar[^\"]*\"[^>]*>.*?<\\/div><\\/div><\\/div><\\/div>/gis, '');\n\n // Remove side-nav-menu-button (hamburger menu)\n cleaned = cleaned.replace(/<div[^>]*class=\"[^\"]*side-nav-menu-button[^\"]*\"[^>]*>.*?<\\/div>/gis, '');\n\n // Remove top-bar-actions (About Gemini, Gemini App, Subscriptions, For Business links)\n cleaned = cleaned.replace(/<top-bar-actions[^>]*>.*?<\\/top-bar-actions>/gis, '');\n\n // Remove desktop-ogb-buffer\n cleaned = cleaned.replace(/<div[^>]*class=\"[^\"]*desktop-ogb-buffer[^\"]*\"[^>]*><\\/div>/gis, '');\n\n return cleaned;\n }\n\n /**\n * Remove Gemini footer/follow-up input box from HTML\n */\n removeFooter(html: string): string {\n // Remove input-container (text input, upload button, send button, disclaimer)\n return html.replace(/<input-container[^>]*>.*?<\\/input-container>/gis, '');\n }\n\n /**\n * Remove Gemini sidebar from HTML\n */\n removeSidebar(html: string): string {\n // Remove bard-sidenav element\n return html.replace(/<bard-sidenav[^>]*>.*?<\\/bard-sidenav>/gis, '');\n }\n\n /**\n * Remove Gemini sources panel from HTML\n */\n removeSources(html: string): string {\n let cleaned = html;\n\n // Remove the context-sidebar element (contains source cards)\n cleaned = cleaned.replace(/<context-sidebar[^>]*>[\\s\\S]*?<\\/context-sidebar>/gi, '');\n\n // Remove the sources-sidebar-button trigger\n cleaned = cleaned.replace(/<sources-sidebar-button[^>]*>[\\s\\S]*?<\\/sources-sidebar-button>/gi, '');\n\n return cleaned;\n }\n\n parse(response: any, options?: ParseOptions): ParsedResponse {\n const { html, text, sources } = this.extractContent(response);\n\n if (!html) {\n throw new Error('No HTML content found in Gemini response');\n }\n\n let finalHtml = html;\n\n const removeHeader = options?.removeHeader ?? false;\n const removeFooter = options?.removeFooter ?? false;\n\n // Sanitize HTML (remove scripts and noscript)\n finalHtml = this.sanitizeHtml(finalHtml);\n\n // Remove header if requested\n if (removeHeader) {\n finalHtml = this.removeHeader(finalHtml);\n }\n\n // Remove footer if requested\n if (removeFooter) {\n finalHtml = this.removeFooter(finalHtml);\n }\n\n // Remove sidebar if requested\n if (options?.removeSidebar) {\n finalHtml = this.removeSidebar(finalHtml);\n }\n\n // Remove sources panel if requested\n if (options?.removeSources) {\n finalHtml = this.removeSources(finalHtml);\n }\n\n // Remove links if requested\n if (options?.removeLinks) {\n finalHtml = this.removeLinks(finalHtml);\n }\n\n finalHtml = this.injectStyles(finalHtml, {\n baseUrl: this.baseUrl,\n customCSS: '',\n });\n\n return {\n provider: this.name,\n html: finalHtml,\n text,\n sources,\n metadata: {\n isFullDocument: this.isFullDocument(finalHtml),\n headerRemoved: removeHeader,\n footerRemoved: removeFooter,\n sidebarRemoved: options?.removeSidebar || false,\n sourcesRemoved: options?.removeSources || false,\n linksRemoved: options?.removeLinks || false,\n } as ProviderMetadata,\n };\n }\n}","import { BaseProvider } from \"./base-provider\";\nimport {\n AIProvider,\n ParsedResponse,\n ParseOptions,\n ContentExtraction,\n ProviderMetadata,\n} from \"../core/types\";\n\nexport class PerplexityProvider extends BaseProvider {\n readonly name: AIProvider = \"PERPLEXITY\";\n readonly baseUrl = \"https://www.perplexity.ai\";\n\n extractContent(response: any): ContentExtraction {\n return this.extractContentCommon(response);\n }\n\n /**\n * Remove Perplexity header/navbar from HTML\n */\n removeHeader(html: string): string {\n // Remove navbar by targeting the unique @container/header class\n // Matches from the navbar opening div through the border divider at the bottom\n return html.replace(\n /<div[^>]*class=\"[^\"]*@container\\/header[^\"]*\"[^>]*>.*?<div[^>]*class=\"[^\"]*absolute bottom-0 inset-x-0 border-b[^\"]*\"[^>]*><\\/div>/gis,\n \"\"\n );\n }\n\n /**\n * Remove Perplexity footer/followup input from HTML\n */\n removeFooter(html: string): string {\n let cleaned = html;\n const regex =\n /<div[^>]*class=\"[^\"]*erp-sidecar:fixed erp-sidecar:w-full bottom-safeAreaInsetBottom p-md pointer-events-none z-10 absolute border-subtlest ring-subtlest divide-subtlest bg-transparent[^\"]*\"[^>]*>[\\s\\S]*?(?=<div[^>]*class=\"[^\"]*fixed inset-y-0 right-0[^\"]*\")/gis;\n cleaned = cleaned.replace(regex, \"\");\n return cleaned;\n }\n\n /**\n * Remove Perplexity sources panel from HTML\n */\n removeSources(html: string): string {\n // Remove the fixed right-side sources panel (contains citations/links and cookie dialog)\n return html.replace(/<div[^>]*class=\"[^\"]*fixed inset-y-0 right-0[^\"]*\"[^>]*>[\\s\\S]*?(?=<span[^>]*data-radix-focus-guard)/gi, '');\n }\n\n parse(response: any, options?: ParseOptions): ParsedResponse {\n const { html, text } = this.extractContent(response);\n\n if (!html) {\n throw new Error(\"No HTML content found in Perplexity response\");\n }\n\n let finalHtml = html;\n\n const removeHeader = options?.removeHeader ?? false;\n const removeFooter = options?.removeFooter ?? false;\n\n // Sanitize HTML\n finalHtml = this.sanitizeHtml(finalHtml);\n\n // Fix collapsed answer container: Perplexity uses JS animation to expand the\n // answer area from height:48px. Without scripts, it stays collapsed.\n finalHtml = finalHtml.replace(\n /style=\"transition: none; overflow: hidden; height: 48px;\"/gi,\n ''\n );\n\n // Remove header if requested\n if (removeHeader) {\n finalHtml = this.removeHeader(finalHtml);\n }\n\n // Remove footer if requested\n if (removeFooter) {\n finalHtml = this.removeFooter(finalHtml);\n }\n\n // Remove sources panel if requested\n if (options?.removeSources) {\n finalHtml = this.removeSources(finalHtml);\n }\n\n // Remove links if requested\n if (options?.removeLinks) {\n finalHtml = this.removeLinks(finalHtml);\n }\n\n // Always hide cookie consent banner via CSS\n const customCSS = `\n #cookie-consent,\n [role=\"dialog\"]:has(#cookie-consent) {\n display: none !important;\n }\n `;\n\n finalHtml = this.injectStyles(finalHtml, {\n baseUrl: this.baseUrl,\n customCSS,\n });\n\n return {\n provider: this.name,\n html: finalHtml,\n text,\n metadata: {\n isFullDocument: this.isFullDocument(finalHtml),\n linksRemoved: options?.removeLinks || false,\n headerRemoved: removeHeader,\n footerRemoved: removeFooter,\n cookieBannerRemoved: true,\n sourcesRemoved: options?.removeSources || false,\n } as ProviderMetadata,\n };\n }\n}\n","import { BaseProvider } from './base-provider';\nimport { AIProvider, ParsedResponse, ParseOptions, ContentExtraction, ProviderMetadata } from '../core/types';\n\nexport class CopilotProvider extends BaseProvider {\n readonly name: AIProvider = 'COPILOT';\n readonly baseUrl = 'https://copilot.microsoft.com';\n\n\n extractContent(response: any): ContentExtraction {\n return this.extractContentCommon(response);\n }\n\n /**\n * Remove Copilot header/navbar from HTML\n */\n removeHeader(html: string): string {\n let cleaned = html;\n\n // Remove backstage-chats (hidden navbar element)\n cleaned = cleaned.replace(/<div[^>]*class=\"[^\"]*relative shrink-0 min-h-14[^\"]*\"[^>]*data-testid=\"backstage-chats\"[^>]*>.*?<\\/div>/gis, '');\n\n // Remove date divider (e.g., \"Today\" with horizontal line)\n cleaned = cleaned.replace(/<div[^>]*class=\"[^\"]*flex items-center px-6 mx-auto w-full max-w-chat[^\"]*\"[^>]*>.*?<span[^>]*data-testid=\"date-divider\"[^>]*>.*?<\\/span>.*?<div[^>]*class=\"[^\"]*border-t-\\[1px\\][^\"]*\"[^>]*>.*?<\\/div>.*?<\\/div>/gis, '');\n\n // Remove settings wrapper (share/settings buttons in top-right corner)\n cleaned = cleaned.replace(/<div[^>]*class=\"[^\"]*absolute flex end-6 origin-top-right flex-col items-end[^\"]*\"[^>]*data-testid=\"settings-wrapper\"[^>]*>.*?<\\/div><\\/div>/gis, '');\n\n return cleaned;\n }\n\n /**\n * Remove Copilot footer/followup input box from HTML\n */\n removeFooter(html: string): string {\n let cleaned = html;\n\n // Remove the composer (input box at bottom)\n // Starts with: <div class=\"absolute bottom-0 w-full\">\n // Contains: file input, composer content with textarea, buttons (home, attach, chat mode, audio call)\n cleaned = cleaned.replace(/<div[^>]*class=\"[^\"]*absolute bottom-0 w-full[^\"]*\"[^>]*>.*?<\\/div><\\/div><\\/div><\\/div><\\/div><\\/div><\\/div><\\/div><\\/div><\\/div><\\/div><\\/div>/gis, '');\n\n // Remove spacer div for composer height\n cleaned = cleaned.replace(/<div[^>]*class=\"[^\"]*mt-\\[var\\(--composer-container-height\\)\\][^\"]*\"[^>]*><\\/div>/gis, '');\n\n // Remove \"scroll to bottom\" button (full container with button and inner content)\n cleaned = cleaned.replace(/<div[^>]*class=\"[^\"]*pointer-events-none absolute flex justify-center z-20 inset-x-0 bottom-\\[calc\\(var\\(--composer-container-height\\)\\+1rem\\)\\][^\"]*\"[^>]*>.*?<button[^>]*data-testid=\"scroll-to-bottom-button\"[^>]*>.*?<\\/button><\\/div>/gis, '');\n\n return cleaned;\n }\n\n /**\n * Remove Copilot cookie banner from HTML\n */\n removeCookieBanner(html: string): string {\n let cleaned = html;\n\n // Remove cookie banner by id\n cleaned = cleaned.replace(/<div[^>]*id=\"cookie-banner\"[^>]*>.*?<\\/div>.*?<\\/div>.*?<\\/div>.*?<\\/div>/gis, '');\n\n // Remove cookie banner by max-w-cookie-banner class (outer container)\n cleaned = cleaned.replace(/<div[^>]*class=\"[^\"]*max-w-cookie-banner[^\"]*\"[^>]*>.*?<\\/div>.*?<\\/div>.*?<\\/div>.*?<\\/div>/gis, '');\n\n return cleaned;\n }\n\n /**\n * Remove Copilot sources/references panel from HTML\n */\n removeSources(html: string): string {\n // Remove the references panel (right-side panel with width: 352px containing citations)\n return html.replace(/<div[^>]*class=\"[^\"]*relative h-full overflow-hidden will-change-auto[^\"]*\"[^>]*style=\"[^\"]*width:\\s*352px[^\"]*\"[^>]*>[\\s\\S]*?(?=<div[^>]*class=\"[^\"]*pointer-events-none fixed[^\"]*\")/gi, '');\n }\n\n /**\n * Remove Copilot sidebar from HTML\n */\n removeSidebar(html: string): string {\n let cleaned = html;\n\n // Remove the sidebar container (everything between bg-sidebar-light wrapper and <main>)\n // Handles both old layout (absolute h-full w-0) and new layout (flex h-full overflow-hidden bg-sidebar-light)\n cleaned = cleaned.replace(/<div[^>]*class=\"[^\"]*bg-sidebar-light[^\"]*\"[^>]*>[\\s\\S]*?(?=<main)/gi, '');\n\n return cleaned;\n }\n\n parse(response: any, options?: ParseOptions): ParsedResponse {\n const { html, text } = this.extractContent(response);\n\n if (!html) {\n throw new Error('No HTML content found in Copilot response');\n }\n\n let finalHtml = html;\n\n const removeHeader = options?.removeHeader ?? false;\n const removeFooter = options?.removeFooter ?? false;\n\n // Sanitize HTML\n finalHtml = this.sanitizeHtml(finalHtml);\n\n // Remove cookie banner (always)\n finalHtml = this.removeCookieBanner(finalHtml);\n\n // Remove header if requested\n if (removeHeader) {\n finalHtml = this.removeHeader(finalHtml);\n }\n\n // Remove footer if requested\n if (removeFooter) {\n finalHtml = this.removeFooter(finalHtml);\n }\n\n // Remove sidebar if requested\n if (options?.removeSidebar) {\n finalHtml = this.removeSidebar(finalHtml);\n }\n\n // Remove sources/references panel if requested\n if (options?.removeSources) {\n finalHtml = this.removeSources(finalHtml);\n }\n\n // Remove links if requested\n if (options?.removeLinks) {\n finalHtml = this.removeLinks(finalHtml);\n }\n\n finalHtml = this.injectStyles(finalHtml, {\n baseUrl: this.baseUrl,\n customCSS: '',\n });\n\n return {\n provider: this.name,\n html: finalHtml,\n text,\n metadata: {\n isFullDocument: this.isFullDocument(finalHtml),\n cookieBannerRemoved: true,\n headerRemoved: removeHeader,\n footerRemoved: removeFooter,\n sidebarRemoved: options?.removeSidebar || false,\n sourcesRemoved: options?.removeSources || false,\n linksRemoved: options?.removeLinks || false,\n } as ProviderMetadata,\n };\n }\n}","import { BaseProvider } from \"./base-provider\";\nimport {\n AIProvider,\n ParsedResponse,\n ParseOptions,\n ContentExtraction,\n ProviderMetadata,\n} from \"../core/types\";\n\nexport class AIOverviewProvider extends BaseProvider {\n readonly name: AIProvider = \"AIOVERVIEW\";\n readonly baseUrl = \"https://www.google.com\";\n\n extractContent(response: any): ContentExtraction {\n return this.extractContentCommon(response, true);\n }\n\n /**\n * Remove Google Search header/navbar from HTML\n */\n removeHeader(html: string): string {\n // Remove header elements via CSS injection\n return html;\n }\n\n /**\n * Remove Google Search footer from HTML\n */\n removeFooter(html: string): string {\n // Remove footer elements via CSS injection\n return html;\n }\n\n /**\n * Remove Google Search sidebar from HTML\n */\n removeSidebar(html: string): string {\n // Remove sidebar elements via CSS injection\n return html;\n }\n\n parse(response: any, options?: ParseOptions): ParsedResponse {\n const { html, sources } = this.extractContent(response);\n\n if (!html) {\n throw new Error(\"No HTML content found in AI Overview response\");\n }\n\n let finalHtml = html;\n\n // For AI Overview, default to removing header and footer for cleaner display\n const removeHeader = options?.removeHeader ?? true;\n const removeFooter = options?.removeFooter ?? true;\n\n // Sanitize HTML\n finalHtml = this.sanitizeHtml(finalHtml);\n\n // Remove header if requested\n if (removeHeader) {\n finalHtml = this.removeHeader(finalHtml);\n }\n\n // Remove footer if requested\n if (removeFooter) {\n finalHtml = this.removeFooter(finalHtml);\n }\n\n // Remove sidebar if requested\n if (options?.removeSidebar) {\n finalHtml = this.removeSidebar(finalHtml);\n }\n\n // Remove links if requested\n if (options?.removeLinks) {\n finalHtml = this.removeLinks(finalHtml);\n }\n\n // Build CSS based on options\n let stylesToInject = \"\";\n\n // Header removal styles\n if (removeHeader) {\n stylesToInject += `\n /* Header hiding */\n header, #header, #searchform, .sfbg, #appbar,\n div[role=\"navigation\"], #leftnav, #sidetogether,\n [role=\"banner\"], .Fgvgjc, #hdtb, .hdtb-msb,\n .DZ13He, .wYq63b, .eT9Cje, .bNg8Rb, .S6VXfe, .Lu57id {\n display: none !important;\n }\n `;\n }\n\n // Sidebar removal styles\n if (options?.removeSidebar) {\n stylesToInject += `\n /* Sidebar hiding */\n #leftnav, #sidetogether {\n display: none !important;\n }\n `;\n }\n\n // Footer removal styles\n if (removeFooter) {\n stylesToInject += `\n /* Footer hiding */\n footer, #footer, .fbar,\n .pdp-nav, [aria-label=\"Main menu\"], .gb_Td, .gb_L {\n display: none !important;\n }\n `;\n }\n\n // Inject base URL and styles\n finalHtml = this.injectStyles(finalHtml, {\n baseUrl: this.baseUrl,\n customCSS: stylesToInject,\n });\n\n return {\n provider: this.name,\n html: finalHtml,\n sources,\n metadata: {\n isFullDocument: this.isFullDocument(finalHtml),\n headerRemoved: removeHeader,\n footerRemoved: removeFooter,\n sidebarRemoved: options?.removeSidebar || false,\n linksRemoved: options?.removeLinks || false,\n } as ProviderMetadata,\n };\n }\n}\n","import { BaseProvider } from \"./base-provider\";\nimport {\n AIProvider,\n ParsedResponse,\n ParseOptions,\n ContentExtraction,\n ProviderMetadata,\n} from \"../core/types\";\n\nexport class AIModeProvider extends BaseProvider {\n readonly name: AIProvider = \"AIMODE\";\n readonly baseUrl = \"https://www.google.com\";\n\n extractContent(response: any): ContentExtraction {\n return this.extractContentCommon(response);\n }\n\n /**\n * Remove Google Search header/navbar from HTML\n */\n removeHeader(html: string): string {\n let cleaned = html;\n\n // Remove the AI Mode filter/header bar\n // Starts with <div jsname=\"oEQ3x\" class=\"DZ13He YNk70c EjQTId\">\n // Contains the Filters and Topics navigation (AI Mode, All, Images, Videos, News, More)\n // Ends with closing divs after <hr class=\"e9c7U\">\n cleaned = cleaned.replace(\n /<div[^>]*jsname=\"oEQ3x\"[^>]*class=\"[^\"]*DZ13He[^\"]*\"[^>]*>.*?<hr class=\"e9c7U\">.*?<\\/div><\\/div><\\/div><\\/div><\\/div>/gis,\n \"\"\n );\n\n return cleaned;\n }\n\n /**\n * Remove Google Search footer from HTML\n */\n removeFooter(html: string): string {\n let cleaned = html;\n\n // Remove the AI Mode input bar/footer\n // Target the most unique identifier: data-xid=\"aim-mars-input-plate\"\n // This element is deeply nested, so we need to match many closing divs\n cleaned = cleaned.replace(\n /<div[^>]*data-xid=\"aim-mars-input-plate\"[^>]*>[\\s\\S]*?<\\/div><\\/div><\\/div><\\/div><\\/div>/gis,\n \"\"\n );\n\n // Fallback: Target by jscontroller P5gZDb which wraps the input plate\n cleaned = cleaned.replace(\n /<div[^>]*jscontroller=\"P5gZDb\"[^>]*>[\\s\\S]*?<\\/div><\\/div><\\/div>/gis,\n \"\"\n );\n\n // Fallback: Target the t0ITR container\n cleaned = cleaned.replace(\n /<div[^>]*class=\"[^\"]*t0ITR hh3ttd[^\"]*\"[^>]*>[\\s\\S]*?<\\/div><\\/div>/gis,\n \"\"\n );\n\n // Fallback: Target outer y4VEUd vve6Ce wrapper\n cleaned = cleaned.replace(\n /<div[^>]*class=\"[^\"]*y4VEUd vve6Ce[^\"]*\"[^>]*>[\\s\\S]*?<\\/div><\\/div>/gis,\n \"\"\n );\n\n return cleaned;\n }\n\n /**\n * Remove Google Search sidebar from HTML\n */\n removeSidebar(html: string): string {\n let cleaned = html;\n\n // Remove the AI Mode history panel/dialog\n // Target by aria-label (handles both attribute orderings)\n cleaned = cleaned.replace(\n /<div[^>]*aria-label=\"AI Mode history\"[^>]*class=\"[^\"]*ho072b[^\"]*\"[^>]*>[\\s\\S]*?(?=<!--TgQPHd)/gi,\n \"\"\n );\n // Fallback: class before aria-label\n cleaned = cleaned.replace(\n /<div[^>]*class=\"[^\"]*ho072b[^\"]*\"[^>]*aria-label=\"AI Mode history\"[^>]*>[\\s\\S]*?(?=<!--TgQPHd)/gi,\n \"\"\n );\n\n // Remove the floating action buttons (OEwhSe wrapper)\n cleaned = cleaned.replace(\n /<div[^>]*class=\"[^\"]*OEwhSe[^\"]*\"[^>]*>[\\s\\S]*?<\\/div><\\/div>/gis,\n \"\"\n );\n\n // Remove buttons with aria-label\n cleaned = cleaned.replace(\n /<button[^>]*aria-label=\"AI Mode history\"[^>]*>[\\s\\S]*?<\\/button>/gis,\n \"\"\n );\n\n return cleaned;\n }\n\n parse(response: any, options?: ParseOptions): ParsedResponse {\n const { html, text } = this.extractContent(response);\n\n if (!html) {\n throw new Error(\"No HTML content found in AI Mode response\");\n }\n\n let finalHtml = html;\n\n // For AI Mode, default to removing header and footer for cleaner display\n const removeHeader = options?.removeHeader ?? true;\n const removeFooter = options?.removeFooter ?? true;\n\n // Sanitize HTML\n finalHtml = this.sanitizeHtml(finalHtml);\n\n // Remove header if requested\n if (removeHeader) {\n finalHtml = this.removeHeader(finalHtml);\n }\n\n // Remove footer if requested\n if (removeFooter) {\n finalHtml = this.removeFooter(finalHtml);\n }\n\n // Remove sidebar if requested\n if (options?.removeSidebar) {\n finalHtml = this.removeSidebar(finalHtml);\n }\n\n // Remove links if requested\n if (options?.removeLinks) {\n finalHtml = this.removeLinks(finalHtml);\n }\n\n // Build CSS based on options\n let stylesToInject = \"\";\n\n // Always inject general layout\n /* Remove cookie consent banner */\n stylesToInject += `\n .KxvlWc, #CXQnmb {\n display: none !important;\n }\n `;\n\n // Header removal styles\n if (removeHeader) {\n stylesToInject += `\n /* Header hiding */\n header, #header, #searchform, .sfbg, #appbar,\n div[role=\"navigation\"], #leftnav, #sidetogether,\n [role=\"banner\"], .Fgvgjc, #hdtb, .hdtb-msb,\n .DZ13He, .wYq63b, .eT9Cje, .bNg8Rb, .S6VXfe, .Lu57id {\n display: none !important;\n }\n `;\n }\n\n // Footer removal styles\n if (removeFooter) {\n stylesToInject += `\n /* Footer hiding */\n footer, #footer, .fbar,\n .pdp-nav, [aria-label=\"Main menu\"], .gb_Td, .gb_L {\n display: none !important;\n }\n /* Hide the \"Ask anything\" input bar */\n [data-xid=\"aim-mars-input-plate\"],\n .UAbVe, .y4VEUd, .t0ITR.hh3ttd {\n display: none !important;\n }\n `;\n }\n\n // Sidebar removal styles\n if (options?.removeSidebar) {\n stylesToInject += `\n /* Hide AI Mode history panel */\n .ho072b, .OEwhSe, .qEn1od {\n display: none !important;\n }\n `;\n }\n\n // Inject base URL and styles\n finalHtml = this.injectStyles(finalHtml, {\n baseUrl: this.baseUrl,\n customCSS: stylesToInject,\n });\n\n return {\n provider: this.name,\n html: finalHtml,\n text,\n metadata: {\n isFullDocument: this.isFullDocument(finalHtml),\n headerRemoved: removeHeader,\n footerRemoved: removeFooter,\n sidebarRemoved: options?.removeSidebar || false,\n linksRemoved: options?.removeLinks || false,\n } as ProviderMetadata,\n };\n }\n}\n","import { BaseProvider } from \"./base-provider\";\nimport {\n AIProvider,\n ParsedResponse,\n ParseOptions,\n ContentExtraction,\n ProviderMetadata,\n} from \"../core/types\";\n\nexport class GrokProvider extends BaseProvider {\n readonly name: AIProvider = \"GROK\";\n readonly baseUrl = \"https://grok.com\";\n\n extractContent(response: any): ContentExtraction {\n return this.extractContentCommon(response);\n }\n\n /**\n * Remove Grok header from HTML (using CSS-based hiding)\n */\n removeHeader(html: string): string {\n // Header removal is now done via CSS in the parse method\n return html;\n }\n\n /**\n * Remove Grok footer/input area from HTML (using CSS-based hiding)\n */\n removeFooter(html: string): string {\n // Footer removal is now done via CSS in the parse method\n return html;\n }\n\n parse(response: any, options?: ParseOptions): ParsedResponse {\n const { html, text } = this.extractContent(response);\n\n if (!html) {\n throw new Error(\"No HTML content found in Grok response\");\n }\n\n let finalHtml = html;\n\n // Sanitize HTML\n finalHtml = this.sanitizeHtml(finalHtml);\n\n // Build CSS based on options\n let stylesToInject = '';\n\n // Always-on: hide cookie/privacy policy banner (Grok uses data-cookie-banner attribute)\n stylesToInject += `\n [data-cookie-banner],\n [data-cookie-banner=\"true\"] {\n display: none !important;\n }\n `;\n\n // Always-on: hide rate-limit banners and toast notifications\n stylesToInject += `\n [data-sonner-toaster],\n [data-sonner-toast],\n [class*=\"sonner-toast\"] {\n display: none !important;\n }\n `;\n\n // Sources panel removal via regex (CSS selectors don't reliably hide this element)\n if (options?.removeSources) {\n // Remove the sources panel wrapper containing the aside\n finalHtml = finalHtml.replace(/<div[^>]*class=\"[^\"]*h-dvh[^\"]*flex-shrink-0[^\"]*max-w-[^\"]*\"[^>]*>[\\s\\S]*?<\\/aside>[\\s\\S]*?(?=<section)/gi, '');\n\n // Hide the inline \"N sources\" trigger button and vaul-drawer overlay via CSS\n stylesToInject += `\n div[data-state] > div.flex.flex-row.gap-1.items-center.rounded-full.cursor-pointer {\n display: none !important;\n }\n [vaul-drawer][vaul-drawer-direction=\"right\"],\n [vaul-overlay] {\n display: none !important;\n }\n `;\n }\n\n // Header hiding via CSS\n if (options?.removeHeader) {\n stylesToInject += `\n /* Header hiding - hide elements with Grok's header class pattern */\n div[class*=\"h-16\"][class*=\"top-0\"][class*=\"z-10\"],\n div[class*=\"absolute\"][class*=\"inset-x-0\"][class*=\"top-0\"] {\n display: none !important;\n }\n `;\n }\n\n // Footer hiding via CSS\n if (options?.removeFooter) {\n stylesToInject += `\n /* Footer hiding - hide Grok's footer/input area */\n div[class*=\"absolute\"][class*=\"inset-x-0\"][class*=\"bottom-0\"][class*=\"max-w-breakout\"],\n div[class*=\"absolute\"][class*=\"bottom-0\"][class*=\"w-full\"] {\n display: none !important;\n }\n `;\n }\n\n // Remove links if requested\n if (options?.removeLinks) {\n finalHtml = this.removeLinks(finalHtml);\n }\n\n finalHtml = this.injectStyles(finalHtml, {\n baseUrl: this.baseUrl,\n customCSS: stylesToInject,\n });\n\n return {\n provider: this.name,\n html: finalHtml,\n text,\n metadata: {\n isFullDocument: this.isFullDocument(finalHtml),\n linksRemoved: options?.removeLinks || false,\n headerRemoved: options?.removeHeader || false,\n footerRemoved: options?.removeFooter || false,\n cookieBannerRemoved: true,\n sourcesRemoved: options?.removeSources || false,\n } as ProviderMetadata,\n };\n }\n}\n","import { AIProvider, ParsedResponse, ParseOptions, extractContentCommon } from './types';\nimport { ProviderDetector } from './detector';\nimport { ChatGPTProvider } from '../providers/chatgpt';\nimport { GeminiProvider } from '../providers/gemini';\nimport { PerplexityProvider } from '../providers/perplexity';\nimport { CopilotProvider } from '../providers/copilot';\nimport { AIOverviewProvider } from '../providers/ai-overview';\nimport { AIModeProvider } from '../providers/ai-mode';\nimport { GrokProvider } from '../providers/grok';\n\nexport class AIResponseParser {\n private providers: Map<AIProvider, any> = new Map();\n\n constructor() {\n this.providers.set('CHATGPT', new ChatGPTProvider());\n this.providers.set('GEMINI', new GeminiProvider());\n this.providers.set('PERPLEXITY', new PerplexityProvider());\n this.providers.set('COPILOT', new CopilotProvider());\n this.providers.set('AIOVERVIEW', new AIOverviewProvider());\n this.providers.set('AIMODE', new AIModeProvider());\n this.providers.set('GROK', new GrokProvider());\n }\n\n /**\n * Parse an AI response with auto-detected provider\n */\n parse(response: any, options?: ParseOptions): ParsedResponse | null {\n const detection = ProviderDetector.detect(response);\n\n if (!detection) {\n // Try to parse as generic HTML if no provider detected\n return this.parseGeneric(response);\n }\n\n const provider = this.providers.get(detection.provider);\n if (!provider) {\n return null;\n }\n\n try {\n const parsed = provider.parse(response, options);\n return {\n ...parsed,\n metadata: {\n ...parsed.metadata,\n detectionConfidence: detection.confidence,\n },\n };\n } catch (error) {\n console.error(`Failed to parse response with ${detection.provider}:`, error);\n return null;\n }\n }\n\n /**\n * Parse with explicit provider specification\n */\n parseWithProvider(\n response: any,\n provider: AIProvider,\n options?: ParseOptions\n ): ParsedResponse | null {\n const providerInstance = this.providers.get(provider);\n if (!providerInstance) {\n throw new Error(`Unknown provider: ${provider}`);\n }\n\n try {\n return providerInstance.parse(response, options);\n } catch (error) {\n console.error(`Failed to parse response with ${provider}:`, error);\n return null;\n }\n }\n\n /**\n * Detect the provider from a response\n */\n detectProvider(response: any): AIProvider | null {\n const detection = ProviderDetector.detect(response);\n return detection?.provider || null;\n }\n\n /**\n * Get all possible providers with confidence scores\n */\n detectAllProviders(response: any): Array<{ provider: AIProvider; confidence: number }> {\n return ProviderDetector.getAllProviders(response);\n }\n\n /**\n * Parse as generic HTML when no specific provider is detected\n */\n private parseGeneric(response: any): ParsedResponse | null {\n const { html, text } = extractContentCommon(response);\n\n if (!html && !text) {\n return null;\n }\n\n // Basic sanitization\n let sanitizedHtml = html;\n if (sanitizedHtml) {\n sanitizedHtml = sanitizedHtml.replace(/<script\\b[^>]*>[\\s\\S]*?<\\/script>/gim, '');\n sanitizedHtml = sanitizedHtml.replace(/<noscript[\\s\\S]*?<\\/noscript>/gi, '');\n }\n\n return {\n provider: 'CHATGPT' as AIProvider, // Default to ChatGPT for unknown\n html: sanitizedHtml || '',\n text: text || '',\n metadata: {\n isGeneric: true,\n },\n };\n }\n\n /**\n * Get list of supported providers\n */\n getSupportedProviders(): AIProvider[] {\n return Array.from(this.providers.keys());\n }\n\n /**\n * Register a custom provider\n */\n registerProvider(provider: AIProvider, instance: any): void {\n this.providers.set(provider, instance);\n }\n}\n\n// Export a singleton instance\nexport const parser = new AIResponseParser();\n\n// Convenience functions\nexport const parseAiResponse = (response: any, options?: ParseOptions) =>\n parser.parse(response, options);\n\nexport const detectProvider = (response: any) =>\n parser.detectProvider(response);"],"names":["extractContentCommon","response","html","text","dataToCheck","result","trim","startsWith","includes","content","ProviderDetector","detect","scores","CHATGPT","GEMINI","PERPLEXITY","COPILOT","AIOVERVIEW","AIMODE","GROK","provider","patterns","Object","entries","this","PROVIDER_PATTERNS","pattern","_a","maxScore","detectedProvider","score","confidence","values","reduce","a","b","Math","max","getAllProviders","providers","matches","push","length","sort","validate","detected","_b","aioverview","_c","_d","BaseProvider","includeSources","sources","injectStyles","options","styledHtml","baseUrl","replace","styles","customCSS","sanitizeHtml","sanitized","isFullDocument","test","removeLinks","wrapFragment","ChatGPTProvider","constructor","name","extractContent","match","attributes","cleanedAttrs","removeHeader","cleaned","removeSidebar","removeFooter","parse","Error","finalHtml","metadata","headerRemoved","sidebarRemoved","footerRemoved","linksRemoved","GeminiProvider","removeSources","sourcesRemoved","PerplexityProvider","cookieBannerRemoved","CopilotProvider","removeCookieBanner","AIOverviewProvider","stylesToInject","AIModeProvider","GrokProvider","AIResponseParser","Map","set","detection","parseGeneric","get","parsed","detectionConfidence","error","console","parseWithProvider","providerInstance","detectProvider","detectAllProviders","sanitizedHtml","isGeneric","getSupportedProviders","Array","from","keys","registerProvider","instance","parser"],"mappings":"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"}
@@ -1 +1 @@
1
- {"version":3,"file":"ai-mode.d.ts","sourceRoot":"","sources":["../../src/providers/ai-mode.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,YAAY,EAAE,MAAM,iBAAiB,CAAC;AAC/C,OAAO,EACL,UAAU,EACV,cAAc,EACd,YAAY,EACZ,iBAAiB,EAElB,MAAM,eAAe,CAAC;AAEvB,qBAAa,cAAe,SAAQ,YAAY;IAC9C,QAAQ,CAAC,IAAI,EAAE,UAAU,CAAY;IACrC,QAAQ,CAAC,OAAO,4BAA4B;IAE5C,cAAc,CAAC,QAAQ,EAAE,GAAG,GAAG,iBAAiB;IAIhD;;OAEG;IACH,YAAY,CAAC,IAAI,EAAE,MAAM,GAAG,MAAM;IAelC;;OAEG;IACH,YAAY,CAAC,IAAI,EAAE,MAAM,GAAG,MAAM;IAgClC;;OAEG;IACH,aAAa,CAAC,IAAI,EAAE,MAAM,GAAG,MAAM;IAoCnC,KAAK,CAAC,QAAQ,EAAE,GAAG,EAAE,OAAO,CAAC,EAAE,YAAY,GAAG,cAAc;CAoG7D"}
1
+ {"version":3,"file":"ai-mode.d.ts","sourceRoot":"","sources":["../../src/providers/ai-mode.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,YAAY,EAAE,MAAM,iBAAiB,CAAC;AAC/C,OAAO,EACL,UAAU,EACV,cAAc,EACd,YAAY,EACZ,iBAAiB,EAElB,MAAM,eAAe,CAAC;AAEvB,qBAAa,cAAe,SAAQ,YAAY;IAC9C,QAAQ,CAAC,IAAI,EAAE,UAAU,CAAY;IACrC,QAAQ,CAAC,OAAO,4BAA4B;IAE5C,cAAc,CAAC,QAAQ,EAAE,GAAG,GAAG,iBAAiB;IAIhD;;OAEG;IACH,YAAY,CAAC,IAAI,EAAE,MAAM,GAAG,MAAM;IAelC;;OAEG;IACH,YAAY,CAAC,IAAI,EAAE,MAAM,GAAG,MAAM;IAgClC;;OAEG;IACH,aAAa,CAAC,IAAI,EAAE,MAAM,GAAG,MAAM;IA8BnC,KAAK,CAAC,QAAQ,EAAE,GAAG,EAAE,OAAO,CAAC,EAAE,YAAY,GAAG,cAAc;CAyG7D"}
@@ -16,6 +16,10 @@ export declare class CopilotProvider extends BaseProvider {
16
16
  * Remove Copilot cookie banner from HTML
17
17
  */
18
18
  removeCookieBanner(html: string): string;
19
+ /**
20
+ * Remove Copilot sources/references panel from HTML
21
+ */
22
+ removeSources(html: string): string;
19
23
  /**
20
24
  * Remove Copilot sidebar from HTML
21
25
  */
@@ -1 +1 @@
1
- {"version":3,"file":"copilot.d.ts","sourceRoot":"","sources":["../../src/providers/copilot.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,YAAY,EAAE,MAAM,iBAAiB,CAAC;AAC/C,OAAO,EAAE,UAAU,EAAE,cAAc,EAAE,YAAY,EAAE,iBAAiB,EAAoB,MAAM,eAAe,CAAC;AAE9G,qBAAa,eAAgB,SAAQ,YAAY;IAC/C,QAAQ,CAAC,IAAI,EAAE,UAAU,CAAa;IACtC,QAAQ,CAAC,OAAO,mCAAmC;IAGnD,cAAc,CAAC,QAAQ,EAAE,GAAG,GAAG,iBAAiB;IAIhD;;OAEG;IACH,YAAY,CAAC,IAAI,EAAE,MAAM,GAAG,MAAM;IAelC;;OAEG;IACH,YAAY,CAAC,IAAI,EAAE,MAAM,GAAG,MAAM;IAiBlC;;OAEG;IACH,kBAAkB,CAAC,IAAI,EAAE,MAAM,GAAG,MAAM;IAYxC;;OAEG;IACH,aAAa,CAAC,IAAI,EAAE,MAAM,GAAG,MAAM;IAWnC,KAAK,CAAC,QAAQ,EAAE,GAAG,EAAE,OAAO,CAAC,EAAE,YAAY,GAAG,cAAc;CAyD7D"}
1
+ {"version":3,"file":"copilot.d.ts","sourceRoot":"","sources":["../../src/providers/copilot.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,YAAY,EAAE,MAAM,iBAAiB,CAAC;AAC/C,OAAO,EAAE,UAAU,EAAE,cAAc,EAAE,YAAY,EAAE,iBAAiB,EAAoB,MAAM,eAAe,CAAC;AAE9G,qBAAa,eAAgB,SAAQ,YAAY;IAC/C,QAAQ,CAAC,IAAI,EAAE,UAAU,CAAa;IACtC,QAAQ,CAAC,OAAO,mCAAmC;IAGnD,cAAc,CAAC,QAAQ,EAAE,GAAG,GAAG,iBAAiB;IAIhD;;OAEG;IACH,YAAY,CAAC,IAAI,EAAE,MAAM,GAAG,MAAM;IAelC;;OAEG;IACH,YAAY,CAAC,IAAI,EAAE,MAAM,GAAG,MAAM;IAiBlC;;OAEG;IACH,kBAAkB,CAAC,IAAI,EAAE,MAAM,GAAG,MAAM;IAYxC;;OAEG;IACH,aAAa,CAAC,IAAI,EAAE,MAAM,GAAG,MAAM;IAKnC;;OAEG;IACH,aAAa,CAAC,IAAI,EAAE,MAAM,GAAG,MAAM;IAUnC,KAAK,CAAC,QAAQ,EAAE,GAAG,EAAE,OAAO,CAAC,EAAE,YAAY,GAAG,cAAc;CA+D7D"}
@@ -16,6 +16,10 @@ export declare class GeminiProvider extends BaseProvider {
16
16
  * Remove Gemini sidebar from HTML
17
17
  */
18
18
  removeSidebar(html: string): string;
19
+ /**
20
+ * Remove Gemini sources panel from HTML
21
+ */
22
+ removeSources(html: string): string;
19
23
  parse(response: any, options?: ParseOptions): ParsedResponse;
20
24
  }
21
25
  //# sourceMappingURL=gemini.d.ts.map
@@ -1 +1 @@
1
- {"version":3,"file":"gemini.d.ts","sourceRoot":"","sources":["../../src/providers/gemini.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,YAAY,EAAE,MAAM,iBAAiB,CAAC;AAC/C,OAAO,EAAE,UAAU,EAAE,cAAc,EAAE,YAAY,EAAE,iBAAiB,EAAoB,MAAM,eAAe,CAAC;AAE9G,qBAAa,cAAe,SAAQ,YAAY;IAC9C,QAAQ,CAAC,IAAI,EAAE,UAAU,CAAY;IACrC,QAAQ,CAAC,OAAO,+BAA+B;IAG/C,cAAc,CAAC,QAAQ,EAAE,GAAG,GAAG,iBAAiB;IAIhD;;OAEG;IACH,YAAY,CAAC,IAAI,EAAE,MAAM,GAAG,MAAM;IAkBlC;;OAEG;IACH,YAAY,CAAC,IAAI,EAAE,MAAM,GAAG,MAAM;IAKlC;;OAEG;IACH,aAAa,CAAC,IAAI,EAAE,MAAM,GAAG,MAAM;IAKnC,KAAK,CAAC,QAAQ,EAAE,GAAG,EAAE,OAAO,CAAC,EAAE,YAAY,GAAG,cAAc;CAsD7D"}
1
+ {"version":3,"file":"gemini.d.ts","sourceRoot":"","sources":["../../src/providers/gemini.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,YAAY,EAAE,MAAM,iBAAiB,CAAC;AAC/C,OAAO,EAAE,UAAU,EAAE,cAAc,EAAE,YAAY,EAAE,iBAAiB,EAAoB,MAAM,eAAe,CAAC;AAE9G,qBAAa,cAAe,SAAQ,YAAY;IAC9C,QAAQ,CAAC,IAAI,EAAE,UAAU,CAAY;IACrC,QAAQ,CAAC,OAAO,+BAA+B;IAG/C,cAAc,CAAC,QAAQ,EAAE,GAAG,GAAG,iBAAiB;IAIhD;;OAEG;IACH,YAAY,CAAC,IAAI,EAAE,MAAM,GAAG,MAAM;IAkBlC;;OAEG;IACH,YAAY,CAAC,IAAI,EAAE,MAAM,GAAG,MAAM;IAKlC;;OAEG;IACH,aAAa,CAAC,IAAI,EAAE,MAAM,GAAG,MAAM;IAKnC;;OAEG;IACH,aAAa,CAAC,IAAI,EAAE,MAAM,GAAG,MAAM;IAYnC,KAAK,CAAC,QAAQ,EAAE,GAAG,EAAE,OAAO,CAAC,EAAE,YAAY,GAAG,cAAc;CA4D7D"}
@@ -1 +1 @@
1
- {"version":3,"file":"grok.d.ts","sourceRoot":"","sources":["../../src/providers/grok.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,YAAY,EAAE,MAAM,iBAAiB,CAAC;AAC/C,OAAO,EACL,UAAU,EACV,cAAc,EACd,YAAY,EACZ,iBAAiB,EAElB,MAAM,eAAe,CAAC;AAEvB,qBAAa,YAAa,SAAQ,YAAY;IAC5C,QAAQ,CAAC,IAAI,EAAE,UAAU,CAAU;IACnC,QAAQ,CAAC,OAAO,sBAAsB;IAEtC,cAAc,CAAC,QAAQ,EAAE,GAAG,GAAG,iBAAiB;IAIhD;;OAEG;IACH,YAAY,CAAC,IAAI,EAAE,MAAM,GAAG,MAAM;IAKlC;;OAEG;IACH,YAAY,CAAC,IAAI,EAAE,MAAM,GAAG,MAAM;IAKlC,KAAK,CAAC,QAAQ,EAAE,GAAG,EAAE,OAAO,CAAC,EAAE,YAAY,GAAG,cAAc;CA2D7D"}
1
+ {"version":3,"file":"grok.d.ts","sourceRoot":"","sources":["../../src/providers/grok.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,YAAY,EAAE,MAAM,iBAAiB,CAAC;AAC/C,OAAO,EACL,UAAU,EACV,cAAc,EACd,YAAY,EACZ,iBAAiB,EAElB,MAAM,eAAe,CAAC;AAEvB,qBAAa,YAAa,SAAQ,YAAY;IAC5C,QAAQ,CAAC,IAAI,EAAE,UAAU,CAAU;IACnC,QAAQ,CAAC,OAAO,sBAAsB;IAEtC,cAAc,CAAC,QAAQ,EAAE,GAAG,GAAG,iBAAiB;IAIhD;;OAEG;IACH,YAAY,CAAC,IAAI,EAAE,MAAM,GAAG,MAAM;IAKlC;;OAEG;IACH,YAAY,CAAC,IAAI,EAAE,MAAM,GAAG,MAAM;IAKlC,KAAK,CAAC,QAAQ,EAAE,GAAG,EAAE,OAAO,CAAC,EAAE,YAAY,GAAG,cAAc;CA+F7D"}
@@ -12,6 +12,10 @@ export declare class PerplexityProvider extends BaseProvider {
12
12
  * Remove Perplexity footer/followup input from HTML
13
13
  */
14
14
  removeFooter(html: string): string;
15
+ /**
16
+ * Remove Perplexity sources panel from HTML
17
+ */
18
+ removeSources(html: string): string;
15
19
  parse(response: any, options?: ParseOptions): ParsedResponse;
16
20
  }
17
21
  //# sourceMappingURL=perplexity.d.ts.map
@@ -1 +1 @@
1
- {"version":3,"file":"perplexity.d.ts","sourceRoot":"","sources":["../../src/providers/perplexity.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,YAAY,EAAE,MAAM,iBAAiB,CAAC;AAC/C,OAAO,EACL,UAAU,EACV,cAAc,EACd,YAAY,EACZ,iBAAiB,EAElB,MAAM,eAAe,CAAC;AAEvB,qBAAa,kBAAmB,SAAQ,YAAY;IAClD,QAAQ,CAAC,IAAI,EAAE,UAAU,CAAgB;IACzC,QAAQ,CAAC,OAAO,+BAA+B;IAE/C,cAAc,CAAC,QAAQ,EAAE,GAAG,GAAG,iBAAiB;IAIhD;;OAEG;IACH,YAAY,CAAC,IAAI,EAAE,MAAM,GAAG,MAAM;IASlC;;OAEG;IACH,YAAY,CAAC,IAAI,EAAE,MAAM,GAAG,MAAM;IAQlC,KAAK,CAAC,QAAQ,EAAE,GAAG,EAAE,OAAO,CAAC,EAAE,YAAY,GAAG,cAAc;CA+C7D"}
1
+ {"version":3,"file":"perplexity.d.ts","sourceRoot":"","sources":["../../src/providers/perplexity.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,YAAY,EAAE,MAAM,iBAAiB,CAAC;AAC/C,OAAO,EACL,UAAU,EACV,cAAc,EACd,YAAY,EACZ,iBAAiB,EAElB,MAAM,eAAe,CAAC;AAEvB,qBAAa,kBAAmB,SAAQ,YAAY;IAClD,QAAQ,CAAC,IAAI,EAAE,UAAU,CAAgB;IACzC,QAAQ,CAAC,OAAO,+BAA+B;IAE/C,cAAc,CAAC,QAAQ,EAAE,GAAG,GAAG,iBAAiB;IAIhD;;OAEG;IACH,YAAY,CAAC,IAAI,EAAE,MAAM,GAAG,MAAM;IASlC;;OAEG;IACH,YAAY,CAAC,IAAI,EAAE,MAAM,GAAG,MAAM;IAQlC;;OAEG;IACH,aAAa,CAAC,IAAI,EAAE,MAAM,GAAG,MAAM;IAKnC,KAAK,CAAC,QAAQ,EAAE,GAAG,EAAE,OAAO,CAAC,EAAE,YAAY,GAAG,cAAc;CAqE7D"}
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@cloro-dev/response-parser",
3
- "version": "0.3.1",
3
+ "version": "0.4.1",
4
4
  "type": "module",
5
5
  "description": "Parse and render AI model responses from ChatGPT, Gemini, Perplexity, and more",
6
6
  "main": "dist/index.js",