website-api 1.0.6 → 1.1.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/dist/bin/cli.js +1 -1
- package/dist/src/capabilities/browser.d.ts +23 -0
- package/dist/src/capabilities/browser.js +1 -0
- package/dist/src/capabilities/cookies.d.ts +24 -0
- package/dist/src/capabilities/cookies.js +1 -0
- package/dist/src/capabilities/download.d.ts +11 -0
- package/dist/src/capabilities/download.js +1 -0
- package/dist/src/capabilities/fingerprint.d.ts +14 -0
- package/dist/src/capabilities/fingerprint.js +1 -0
- package/dist/src/capabilities/http.d.ts +18 -0
- package/dist/src/capabilities/http.js +1 -0
- package/dist/src/{util → capabilities/login}/login-helper.d.ts +12 -5
- package/dist/src/capabilities/login/login-helper.js +1 -0
- package/dist/src/capabilities/login/login-strategy.d.ts +15 -0
- package/dist/src/capabilities/login/login-strategy.js +1 -0
- package/dist/src/core/context.d.ts +24 -0
- package/dist/src/core/context.js +1 -0
- package/dist/src/core/define-site.d.ts +9 -0
- package/dist/src/core/define-site.js +1 -0
- package/dist/src/core/loader.d.ts +21 -0
- package/dist/src/core/loader.js +1 -0
- package/dist/src/core/runtime.d.ts +20 -0
- package/dist/src/core/runtime.js +1 -0
- package/dist/src/{website → sites}/chase.com/download-helper.d.ts +5 -4
- package/dist/src/sites/chase.com/download-helper.js +1 -0
- package/dist/src/sites/chase.com/index.d.ts +2 -0
- package/dist/src/sites/chase.com/index.js +1 -0
- package/dist/src/sites/chatgpt.com/index.d.ts +10 -0
- package/dist/src/sites/chatgpt.com/index.js +1 -0
- package/dist/src/sites/cursor.com/index.d.ts +6 -0
- package/dist/src/sites/cursor.com/index.js +1 -0
- package/dist/src/sites/gemini.google.com/index.d.ts +5 -0
- package/dist/src/sites/gemini.google.com/index.js +1 -0
- package/dist/src/sites/google.com/google-helpers.d.ts +24 -0
- package/dist/src/sites/google.com/google-helpers.js +1 -0
- package/dist/src/sites/google.com/index.d.ts +2 -0
- package/dist/src/sites/google.com/index.js +1 -0
- package/dist/src/sites/ollama.com/index.d.ts +9 -0
- package/dist/src/sites/ollama.com/index.js +1 -0
- package/dist/src/sites/perplexity.ai/index.d.ts +50 -0
- package/dist/src/sites/perplexity.ai/index.js +1 -0
- package/dist/src/sites/pseg.com/index.d.ts +2 -0
- package/dist/src/sites/pseg.com/index.js +1 -0
- package/dist/src/sites/pseg.com/pseg-helpers.d.ts +13 -0
- package/dist/src/sites/pseg.com/pseg-helpers.js +1 -0
- package/dist/src/types.d.ts +194 -46
- package/dist/src/util/args-parser.js +1 -1
- package/dist/src/website-api.d.ts +7 -34
- package/dist/src/website-api.js +1 -1
- package/package.json +10 -1
- package/dist/src/adapter/base-adapter.d.ts +0 -41
- package/dist/src/adapter/base-adapter.js +0 -1
- package/dist/src/adapter/playwright-attatch-chrome-adapter.d.ts +0 -16
- package/dist/src/adapter/playwright-attatch-chrome-adapter.js +0 -1
- package/dist/src/adapter/playwright-core.d.ts +0 -35
- package/dist/src/adapter/playwright-core.js +0 -1
- package/dist/src/adapter/universal-adapter.d.ts +0 -10
- package/dist/src/adapter/universal-adapter.js +0 -1
- package/dist/src/util/login-helper.js +0 -1
- package/dist/src/website/chase.com/account-helper.d.ts +0 -20
- package/dist/src/website/chase.com/account-helper.js +0 -1
- package/dist/src/website/chase.com/chase-adapter.d.ts +0 -43
- package/dist/src/website/chase.com/chase-adapter.js +0 -1
- package/dist/src/website/chase.com/download-helper.js +0 -1
- package/dist/src/website/chatgpt.com/chatgpt-adapter.d.ts +0 -11
- package/dist/src/website/chatgpt.com/chatgpt-adapter.js +0 -1
- package/dist/src/website/cursor.com/cursor-adapter.d.ts +0 -6
- package/dist/src/website/cursor.com/cursor-adapter.js +0 -1
- package/dist/src/website/example.com/example-adapter.d.ts +0 -12
- package/dist/src/website/example.com/example-adapter.js +0 -1
- package/dist/src/website/gemini.google.com/gemini-adapter.d.ts +0 -12
- package/dist/src/website/gemini.google.com/gemini-adapter.js +0 -1
- package/dist/src/website/google.com/google-adapter.d.ts +0 -62
- package/dist/src/website/google.com/google-adapter.js +0 -1
- package/dist/src/website/ollama.com/ollama-adapter.d.ts +0 -2
- package/dist/src/website/ollama.com/ollama-adapter.js +0 -1
- package/dist/src/website/perplexity.ai/perplexity-adapter.d.ts +0 -2
- package/dist/src/website/perplexity.ai/perplexity-adapter.js +0 -1
- package/dist/src/website/pseg.com/pseg-adapter.d.ts +0 -45
- package/dist/src/website/pseg.com/pseg-adapter.js +0 -1
|
@@ -1 +0,0 @@
|
|
|
1
|
-
import t from"node:fs/promises";import e from"node:path";import n from"node:process";const a={CARD:{mode:"cardGet",count:"/svc/rr/accounts/secure/gateway/credit-card/transactions/inquiry-maintenance/digital-transaction-activity/v1/transaction-counts",csv:"/svc/rr/accounts/secure/gateway/credit-card/transactions/inquiry-maintenance/digital-transaction-activity/v1/transaction-activities"},DDA:{mode:"formPost",count:"/svc/rr/accounts/secure/v1/account/activity/download/count/dda/list",csv:"/svc/rr/accounts/secure/v1/account/activity/download/dda/list"}},r=new Map([["current",{key:"current",label:"Current display, including filters"}],["current-display",{key:"current",label:"Current display, including filters"}],["current display",{key:"current",label:"Current display, including filters"}],["current display, including filters",{key:"current",label:"Current display, including filters"}],["all",{key:"all",label:"All transactions"}],["all-transactions",{key:"all",label:"All transactions"}],["all transactions",{key:"all",label:"All transactions"}],["date-range",{key:"date-range",label:"Choose a date range"}],["date range",{key:"date-range",label:"Choose a date range"}],["choose-date-range",{key:"date-range",label:"Choose a date range"}],["choose a date range",{key:"date-range",label:"Choose a date range"}]]);export function normalizeActivity(t){const e=String(t||"").trim().toLowerCase(),n=r.get(e||"all");if(!n)throw new Error(`Unknown activity option: ${t}`);return n}export async function fetchDownloadOptions(t){t.url().includes("secure.chase.com")||await t.goto("https://secure.chase.com/web/auth/dashboard#/dashboard/overview",{waitUntil:"domcontentloaded"});const e=await t.evaluate(async t=>{const e=await fetch(t.url,{method:"POST",credentials:"include",headers:t.headers,body:""});return{status:e.status,text:await e.text()}},{url:"/svc/rr/accounts/secure/v1/account/activity/download/options/list",headers:{"content-type":"application/x-www-form-urlencoded; charset=UTF-8","x-jpmc-channel":"id=C30","x-jpmc-csrf-token":"NONE"}});if(e.status<200||e.status>=300)throw new Error("Download options request failed with status "+e.status);return JSON.parse(e.text)}export function collectAccounts(t){return(t.downloadAccountActivityOptions||[]).map(t=>({id:String(t.accountId||"").trim(),summaryType:String(t.summaryType||"").trim(),detailType:String(t.detailType||"").trim(),nickname:String(t.nickName||"").trim(),mask:String(t.mask||"").trim()})).filter(t=>t.id&&("CARD"===t.summaryType||"DDA"===t.summaryType)&&t.detailType)}export function formatAccountLabel(t){const e=[];return t.nickname&&e.push(t.nickname),t.mask&&e.push(`****${t.mask}`),e.length||e.push(`${t.summaryType}/${t.detailType}/${t.id}`),e.join(" ")}export function accountFileName(t){return`${[t.nickname||"account",t.summaryType,t.detailType,t.id].map(t=>String(t).trim().replace(/[^A-Za-z0-9._-]+/g,"-")).filter(Boolean).join("-").replace(/-+/g,"-").replace(/^-|-$/g,"")||"account"}.csv`}export function summarizeAccounts(t){const e=[];e.push(`Found ${t.length} downloadable account${1===t.length?"":"s"}:`);for(const[n,a]of t.entries())e.push(`${n+1}. ${formatAccountLabel(a)} | ${a.summaryType},${a.detailType},${a.id}`);return e.join("\n")}export function selectAccounts(t,e){let n=[];if(e.accounts&&(n=e.accounts.split(/[\s,]+/).map(Number).filter(t=>!isNaN(t))),!n.length){const n=void 0!==e.limit?e.limit:e.first?1:null;return t.slice(0,n||void 0)}const a=[],r=new Set;for(const e of n){if(e<1||e>t.length)throw new Error(`Account number ${e} is out of range. Run list to see 1-${t.length}.`);r.has(e)||(r.add(e),a.push(t[e-1]))}return a}function o(t){return`${t.getFullYear()}${String(t.getMonth()+1).padStart(2,"0")}${String(t.getDate()).padStart(2,"0")}`}function c(t){const e=String(t||"").match(/^(\d{1,2})\/(\d{1,2})\/(\d{4})$/);if(!e)throw new Error(`Invalid date "${t}". Use mm/dd/yyyy format.`);const[,n,a,r]=e;return`${r}${n.padStart(2,"0")}${a.padStart(2,"0")}`}function i(t,e){const n=String(t??""),a=n.trimStart();if(/^<!doctype html/i.test(a)||/^<html/i.test(a))throw new Error(`Download for ${e} returned HTML instead of CSV. The session may have expired.`);return n}export async function fetchAccountCsv(t,e,n,r){const i=function(t){const e=a[t.summaryType];if(!e)throw new Error(`Unsupported account type for ${formatAccountLabel(t)}: ${t.summaryType}`);return e}(e),s=function(t,e,n){if("CARD"===t.summaryType){const a=new Date,r=new Date(a);r.setFullYear(a.getFullYear()-2);const i={"account-activity-download-type-code":"CSV","digital-account-identifier":t.id};if("date-range"===n){if(!e.from||!e.to)throw new Error("date-range requires from and to in mm/dd/yyyy format");i["start-date"]=c(e.from),i["end-date"]=c(e.to)}else"all"===n&&(i["start-date"]=o(r),i["end-date"]=o(a),i["eligibility-indicator"]="true");return i}const a={transactionType:"ALL",filterTranType:"ALL",statementPeriodId:"ALL",downloadType:"CSV",accountId:t.id};if("all"===n&&"DDA"===t.summaryType&&(a.dateOption="LAST_24_MONTHS"),"date-range"===n){if(!e.from||!e.to)throw new Error("date-range requires from and to in mm/dd/yyyy format");a.dateOption="DATE_RANGE",a.dateLo=e.from,a.dateHi=e.to}return a}(e,n,r),d={body:s,countUrl:i.count,csvUrl:i.csv,csrfUrl:"/svc/rl/accounts/secure/v1/csrf/token/list",mode:i.mode,headers:{"content-type":"application/x-www-form-urlencoded; charset=UTF-8","x-jpmc-channel":"id=C30","x-jpmc-csrf-token":"NONE"}},l=await t.evaluate(async t=>{const e=t=>new URLSearchParams(t).toString(),n=(n,a)=>fetch(n+"?"+e(a),{method:"GET",credentials:"include",headers:t.headers}),a=(n,a,r=t.headers)=>fetch(n,{method:"POST",credentials:"include",headers:r,body:e(a)}),r="cardGet"===t.mode?await n(t.countUrl,t.body):await a(t.countUrl,t.body);if(!r.ok)throw new Error("Download count request failed with status "+r.status);const o=await fetch(t.csrfUrl,{method:"POST",credentials:"include",headers:t.headers,body:""});if(!o.ok)throw new Error("CSRF token request failed with status "+o.status);const c=await o.json(),i=c.csrfToken||c.response?.csrfToken;if(!i)throw new Error("CSRF token was not present in Chase token response");const s={...t.body,csrftoken:i,submit:"Submit"},d="cardGet"===t.mode?await n(t.csvUrl,s):await a(t.csvUrl,s,{"content-type":"application/x-www-form-urlencoded"});return{status:d.status,contentType:d.headers.get("content-type")||"",text:await d.text()}},d);if(l.status<200||l.status>=300)throw new Error(`Download request failed with status ${l.status} for ${formatAccountLabel(e)}`);if(l.contentType&&!/csv|text|octet-stream/i.test(l.contentType))throw new Error(`Download for ${formatAccountLabel(e)} returned ${l.contentType||"unknown content type"}`);return l.text}export async function downloadAccounts(a,r){const o=normalizeActivity(r.activity||r.range);if(!("date-range"!==o.key||r.from&&r.to))throw new Error("activity date-range requires from and to in mm/dd/yyyy format");const c=collectAccounts(await fetchDownloadOptions(a));if(!c.length)throw new Error("No downloadable accounts were found in the Chase download options response.");if(r.list)return summarizeAccounts(c);const s=selectAccounts(c,r),d=r.download?e.resolve(n.cwd(),r.outDir||"."):null;d&&await t.mkdir(d,{recursive:!0});const l=[];for(const[n,c]of s.entries()){const u=i(await fetchAccountCsv(a,c,r,o.key),formatAccountLabel(c));if(d){const n=r.filename&&1===s.length?r.filename:accountFileName(c),a=e.join(d,n);await t.writeFile(a,u,"utf8"),l.push(`Saved: ${a}`)}else l.push(`\n===== ${n+1}/${s.length}: ${formatAccountLabel(c)} =====\n`+(u.endsWith("\n")?u:`${u}\n`))}return l.join("\n")}
|
|
@@ -1,11 +0,0 @@
|
|
|
1
|
-
/**
|
|
2
|
-
* ChatGPT adapter — fetches rate limit usage from the wham/usage API.
|
|
3
|
-
*
|
|
4
|
-
* This is a multi-step flow:
|
|
5
|
-
* 1. Exchange Chrome cookies for a Bearer JWT via the Next-Auth session endpoint
|
|
6
|
-
* 2. Use the JWT to query the private wham/usage endpoint
|
|
7
|
-
*
|
|
8
|
-
* See request.md in this directory for full endpoint documentation.
|
|
9
|
-
*/
|
|
10
|
-
declare const _default: import("../../types.js").WebsiteAdapter;
|
|
11
|
-
export default _default;
|
|
@@ -1 +0,0 @@
|
|
|
1
|
-
import{defineAdapter as e}from"../../adapter/base-adapter.js";export default e({id:"codex-usage",name:"ChatGPT / Codex Usage",domain:"chatgpt.com",description:"Fetches ChatGPT rate limit usage and quota details from the private wham/usage API.",async fetchData(e,t){const a=this.buildCookieString(e),s=this.resolveUserAgent(t),o=await this.fetchJson("https://chatgpt.com/api/auth/session",{headers:{Cookie:a,"User-Agent":s,Accept:"application/json"}});if(!o?.accessToken)throw new Error("No ChatGPT login found in browser");return this.fetchJson("https://chatgpt.com/backend-api/wham/usage",{headers:{authorization:`Bearer ${o.accessToken}`}})}});
|
|
@@ -1 +0,0 @@
|
|
|
1
|
-
import{defineAdapter as r}from"../../adapter/base-adapter.js";export default r({id:"cursor-usage",name:"Cursor Usage",domain:"cursor.com",description:"Fetches the active Cursor usage summary from the private usage-summary API.",endpoints:[{url:"https://cursor.com/api/usage-summary"}]});
|
|
@@ -1,12 +0,0 @@
|
|
|
1
|
-
import { PlaywrightAdapter } from "../../adapter/playwright-attatch-chrome-adapter.js";
|
|
2
|
-
export default class extends PlaywrightAdapter {
|
|
3
|
-
id: string;
|
|
4
|
-
name: string;
|
|
5
|
-
domain: string;
|
|
6
|
-
description: string;
|
|
7
|
-
optionalCookies: boolean;
|
|
8
|
-
endpoints: {
|
|
9
|
-
url: string;
|
|
10
|
-
}[];
|
|
11
|
-
fetchData(cookies: any, options: any): Promise<void>;
|
|
12
|
-
}
|
|
@@ -1 +0,0 @@
|
|
|
1
|
-
var r=this&&this.__addDisposableResource||function(r,e,o){if(null!=e){if("object"!=typeof e&&"function"!=typeof e)throw new TypeError("Object expected.");var s,t;if(o){if(!Symbol.asyncDispose)throw new TypeError("Symbol.asyncDispose is not defined.");s=e[Symbol.asyncDispose]}if(void 0===s){if(!Symbol.dispose)throw new TypeError("Symbol.dispose is not defined.");s=e[Symbol.dispose],o&&(t=s)}if("function"!=typeof s)throw new TypeError("Object not disposable.");t&&(s=function(){try{t.call(this)}catch(r){return Promise.reject(r)}}),r.stack.push({value:e,dispose:s,async:o})}else o&&r.stack.push({async:!0});return e},e=this&&this.__disposeResources||function(r){return function(e){function o(o){e.error=e.hasError?new r(o,e.error,"An error was suppressed during disposal."):o,e.hasError=!0}var s,t=0;return function r(){for(;s=e.stack.pop();)try{if(!s.async&&1===t)return t=0,e.stack.push(s),Promise.resolve().then(r);if(s.dispose){var n=s.dispose.call(s.value);if(s.async)return t|=2,Promise.resolve(n).then(r,function(e){return o(e),r()})}else t|=1}catch(r){o(r)}if(1===t)return e.hasError?Promise.reject(e.error):Promise.resolve();if(e.hasError)throw e.error}()}}("function"==typeof SuppressedError?SuppressedError:function(r,e,o){var s=new Error(o);return s.name="SuppressedError",s.error=r,s.suppressed=e,s});import{PlaywrightAdapter as o}from"../../adapter/playwright-attatch-chrome-adapter.js";export default class extends o{id="ExampleAdapter";name="Example Playwright Service";domain="example.com";description="Fetches and prints the HTML content of example.com using Playwright connecting to existing Chrome.";optionalCookies=!0;endpoints=[{url:"https://example.com"}];async fetchData(o,s){const t={stack:[],error:void 0,hasError:!1};try{r(t,await this.connect(s),!0)}catch(r){t.error=r,t.hasError=!0}finally{const r=e(t);r&&await r}}}
|
|
@@ -1,12 +0,0 @@
|
|
|
1
|
-
import { PlaywrightAdapter } from "../../adapter/playwright-attatch-chrome-adapter.js";
|
|
2
|
-
export default class extends PlaywrightAdapter {
|
|
3
|
-
id: string;
|
|
4
|
-
name: string;
|
|
5
|
-
domain: string;
|
|
6
|
-
description: string;
|
|
7
|
-
optionalCookies: boolean;
|
|
8
|
-
endpoints: {
|
|
9
|
-
url: string;
|
|
10
|
-
}[];
|
|
11
|
-
fetchData(cookies: any, options: any): Promise<any>;
|
|
12
|
-
}
|
|
@@ -1 +0,0 @@
|
|
|
1
|
-
var e=this&&this.__addDisposableResource||function(e,r,o){if(null!=r){if("object"!=typeof r&&"function"!=typeof r)throw new TypeError("Object expected.");var t,s;if(o){if(!Symbol.asyncDispose)throw new TypeError("Symbol.asyncDispose is not defined.");t=r[Symbol.asyncDispose]}if(void 0===t){if(!Symbol.dispose)throw new TypeError("Symbol.dispose is not defined.");t=r[Symbol.dispose],o&&(s=t)}if("function"!=typeof t)throw new TypeError("Object not disposable.");s&&(t=function(){try{s.call(this)}catch(e){return Promise.reject(e)}}),e.stack.push({value:r,dispose:t,async:o})}else o&&e.stack.push({async:!0});return r},r=this&&this.__disposeResources||function(e){return function(r){function o(o){r.error=r.hasError?new e(o,r.error,"An error was suppressed during disposal."):o,r.hasError=!0}var t,s=0;return function e(){for(;t=r.stack.pop();)try{if(!t.async&&1===s)return s=0,r.stack.push(t),Promise.resolve().then(e);if(t.dispose){var i=t.dispose.call(t.value);if(t.async)return s|=2,Promise.resolve(i).then(e,function(r){return o(r),e()})}else s|=1}catch(e){o(e)}if(1===s)return r.hasError?Promise.reject(r.error):Promise.resolve();if(r.hasError)throw r.error}()}}("function"==typeof SuppressedError?SuppressedError:function(e,r,o){var t=new Error(o);return t.name="SuppressedError",t.error=e,t.suppressed=r,t});import{PlaywrightAdapter as o}from"../../adapter/playwright-attatch-chrome-adapter.js";import{decodeGoogleJsonWithSchema as t}from"../../util/google-json.js";const s={planCode:{path:[0]},planName:{path:[0],transform:e=>2===e?"Gemini Pro":1===e?"Gemini Free":`Unknown (${e})`},limits:{path:[1],items:{rawLimit:{path:[0]},percentageUsed:{path:[1],transform:e=>parseFloat((100*e).toFixed(2))},tierName:{path:[2],transform:e=>1===e?"Hourly Usage Limit":2===e?"Weekly Usage Limit":`Unknown Tier (${e})`},resetTime:{path:[3,0,0],transform:e=>e?new Date(1e3*e).toISOString():null}}}};export default class extends o{id="gemini-usage";name="Gemini Usage";domain="gemini.google.com";description="Fetches Gemini account usage/quota details via browser-attached Playwright.";optionalCookies=!0;endpoints=[{url:"https://gemini.google.com/usage"}];async fetchData(o,i){const n={stack:[],error:void 0,hasError:!1};try{const r=e(n,await this.connect(i),!0),o=new Promise((e,o)=>{const t=setTimeout(()=>{o(new Error("Timeout waiting for Gemini usage RPC payload. Make sure you are logged into gemini.google.com in Chrome."))},15e3);r.on("response",async r=>{if(r.url().includes("jSf9Qc"))try{const o=await r.text();clearTimeout(t),e(o)}catch(e){}})});i.debug&&console.log("Triggering page reload/navigation to capture Gemini usage network request..."),await r.reload({waitUntil:"domcontentloaded"});const a=await o;return t(a,"jSf9Qc",s)}catch(e){n.error=e,n.hasError=!0}finally{const e=r(n);e&&await e}}}
|
|
@@ -1,62 +0,0 @@
|
|
|
1
|
-
import { PlaywrightAdapter } from "../../adapter/playwright-attatch-chrome-adapter.js";
|
|
2
|
-
export default class extends PlaywrightAdapter {
|
|
3
|
-
id: string;
|
|
4
|
-
name: string;
|
|
5
|
-
domain: string;
|
|
6
|
-
description: string;
|
|
7
|
-
optionalCookies: boolean;
|
|
8
|
-
endpoints: {
|
|
9
|
-
url: string;
|
|
10
|
-
}[];
|
|
11
|
-
positionals: {
|
|
12
|
-
name: string;
|
|
13
|
-
description: string;
|
|
14
|
-
required: boolean;
|
|
15
|
-
variadic: boolean;
|
|
16
|
-
}[];
|
|
17
|
-
parameters: ({
|
|
18
|
-
name: string;
|
|
19
|
-
type: string;
|
|
20
|
-
description: string;
|
|
21
|
-
default: number;
|
|
22
|
-
short?: undefined;
|
|
23
|
-
} | {
|
|
24
|
-
name: string;
|
|
25
|
-
type: string;
|
|
26
|
-
description: string;
|
|
27
|
-
short: string;
|
|
28
|
-
default?: undefined;
|
|
29
|
-
})[];
|
|
30
|
-
fetchData(cookies: any, options: any): Promise<{
|
|
31
|
-
question: any;
|
|
32
|
-
answer: string | null;
|
|
33
|
-
finalUrl: string;
|
|
34
|
-
endpoint: any;
|
|
35
|
-
searchPage: {
|
|
36
|
-
title: any;
|
|
37
|
-
url: any;
|
|
38
|
-
bodyText: string;
|
|
39
|
-
};
|
|
40
|
-
endpointResult: {
|
|
41
|
-
title: any;
|
|
42
|
-
url: any;
|
|
43
|
-
bodyText: string;
|
|
44
|
-
htmlPrefix: any;
|
|
45
|
-
decoded: any;
|
|
46
|
-
} | null;
|
|
47
|
-
requests: {
|
|
48
|
-
method: any;
|
|
49
|
-
type: any;
|
|
50
|
-
url: any;
|
|
51
|
-
status: any;
|
|
52
|
-
mimeType: any;
|
|
53
|
-
decodedFormat: string | null;
|
|
54
|
-
recordCount: number;
|
|
55
|
-
bodyPrefix: any;
|
|
56
|
-
}[];
|
|
57
|
-
}>;
|
|
58
|
-
private waitForAiAnswer;
|
|
59
|
-
private collectPageState;
|
|
60
|
-
private buildFolwrEndpoint;
|
|
61
|
-
private summarizeNetwork;
|
|
62
|
-
}
|
|
@@ -1 +0,0 @@
|
|
|
1
|
-
var e=this&&this.__addDisposableResource||function(e,t,r){if(null!=t){if("object"!=typeof t&&"function"!=typeof t)throw new TypeError("Object expected.");var o,n;if(r){if(!Symbol.asyncDispose)throw new TypeError("Symbol.asyncDispose is not defined.");o=t[Symbol.asyncDispose]}if(void 0===o){if(!Symbol.dispose)throw new TypeError("Symbol.dispose is not defined.");o=t[Symbol.dispose],r&&(n=o)}if("function"!=typeof o)throw new TypeError("Object not disposable.");n&&(o=function(){try{n.call(this)}catch(e){return Promise.reject(e)}}),e.stack.push({value:t,dispose:o,async:r})}else r&&e.stack.push({async:!0});return t},t=this&&this.__disposeResources||function(e){return function(t){function r(r){t.error=t.hasError?new e(r,t.error,"An error was suppressed during disposal."):r,t.hasError=!0}var o,n=0;return function e(){for(;o=t.stack.pop();)try{if(!o.async&&1===n)return n=0,t.stack.push(o),Promise.resolve().then(e);if(o.dispose){var s=o.dispose.call(o.value);if(o.async)return n|=2,Promise.resolve(s).then(e,function(t){return r(t),e()})}else n|=1}catch(e){r(e)}if(1===n)return t.hasError?Promise.reject(t.error):Promise.resolve();if(t.hasError)throw t.error}()}}("function"==typeof SuppressedError?SuppressedError:function(e,t,r){var o=new Error(r);return o.name="SuppressedError",o.error=e,o.suppressed=t,o});import{PlaywrightAdapter as r}from"../../adapter/playwright-attatch-chrome-adapter.js";export default class extends r{id="google-ai";name="Google AI Overview";domain="google.com";description="Fetches Google's AI Overview and AI Mode answers using browser-attached Playwright.";optionalCookies=!0;endpoints=[{url:"https://www.google.com"}];positionals=[{name:"question",description:"The search query or question to ask Google",required:!0,variadic:!0}];parameters=[{name:"raw-limit",type:"number",description:"Max raw search/endpoint response chars to include",default:12e3},{name:"timeout",type:"number",description:"Playwright timeout in milliseconds",default:9e4},{name:"text",type:"boolean",description:"Print only the extracted AI Overview answer text",short:"t"}];async fetchData(r,o){const n={stack:[],error:void 0,hasError:!1};try{const t=o.question,r=void 0!==o.rawLimit?Number(o.rawLimit):12e3,s=void 0!==o.timeout?Number(o.timeout):9e4,i=e(n,await this.connect(o),!0),c=await i.context().newCDPSession(i);await c.send("Network.enable",{maxTotalBufferSize:1e8,maxResourceBufferSize:1e8});const g=[],y=new Map,w=e=>{const t=function(e){const t=/^https?:\/\/([^/]+)(\/[^?#]*)?/i.exec(String(e??""));return t&&/(^|\.)google\.[^/]+$/i.test(t[1])?t[2]||"/":null}(e);return"/search"===t||t?.startsWith("/async/")||t?.includes("batchexecute")};c.on("Network.requestWillBeSent",e=>{const t=e.request||{};w(t.url)&&(y.set(e.requestId,g.length),g.push({id:e.requestId,type:e.type,method:t.method,url:t.url,postData:t.postData||null,status:null,mimeType:null,body:null}))}),c.on("Network.responseReceived",e=>{const t=y.get(e.requestId);null!=t&&(g[t].status=e.response.status,g[t].mimeType=e.response.mimeType)}),c.on("Network.loadingFinished",async e=>{const t=y.get(e.requestId);if(null!=t)try{const o=g[t].mimeType||"";if(!/text|json|html|javascript|x-protobuf/.test(o))return;const n=await c.send("Network.getResponseBody",{requestId:e.requestId});g[t].body=n.base64Encoded?null:(n.body||"").slice(0,r)}catch(e){}});const b=`https://www.google.com/search?${a({q:t,udm:"50"})}`;o.debug&&console.log(`Navigating to Google Search: ${b}`),await i.goto(b,{waitUntil:"domcontentloaded"});const k=await this.waitForAiAnswer(i,s),x=await this.collectPageState(i,r),S=await this.buildFolwrEndpoint(i);let v=null;if(S?.url){o.debug&&(console.log(`Discovered folwr endpoint: ${S.url}`),console.log("Querying folwr endpoint in-page via browser fetch..."));try{const e=await i.evaluate(async e=>{const t=await fetch(e);return await t.text()},S.url),t=function(e){try{const t=l(e).trimStart();if(t.startsWith("<")||t.includes("class=")||t.includes("id="))return m(t);const r=u(e);for(const e of r){const t=h(e.value);if(t)return m(t)}}catch(e){}return null}(e),o=p(e),n=!o||o.includes("<")||o.includes("class=")?null:o;v={title:x.title,url:S.url,bodyText:e,htmlPrefix:e.slice(0,r),answer:t||n,decoded:d({body:e,contentType:"text/plain"})}}catch(e){o.debug&&console.warn("Failed to query folwr endpoint in-page:",e)}}await i.waitForTimeout(500);return{question:t,answer:f(v?.answer||k||p(x.bodyText),r)||null,finalUrl:i.url(),endpoint:S||null,searchPage:{title:x.title,url:x.url,bodyText:f(x.bodyText,r)},endpointResult:v?{title:v.title,url:v.url,bodyText:f(v.bodyText,r),htmlPrefix:v.htmlPrefix,decoded:v.decoded}:null,requests:this.summarizeNetwork(g,r)}}catch(e){n.error=e,n.hasError=!0}finally{const e=t(n);e&&await e}}async waitForAiAnswer(e,t){const r=Date.now();for(;Date.now()-r<Math.min(t,45e3);){await e.waitForTimeout(750);const t=await e.evaluate(()=>{const e=Array.from(document.querySelectorAll('[jsname="KFl8ub"], [data-attrid], .kp-wholepage')).map(e=>e.innerText?.trim()).filter(Boolean).find(e=>!/^(Sources|Related|AI Mode response is ready)$/i.test(e));if(e)return e;const t=(document.body?.innerText||"").split("\n").map(e=>e.trim()).filter(Boolean),r=t.findIndex(e=>/AI Mode response is ready/i.test(e));return r>0?t[r-1]:null});if(t)return t}return null}async collectPageState(e,t){return await e.evaluate(e=>{const t=document.body?.innerText||"",r=document.documentElement?.outerHTML||"";return{title:document.title,url:document.location.href,bodyText:t.slice(0,e),htmlPrefix:r.slice(0,e)}},t)}async buildFolwrEndpoint(e){const t=await e.evaluate(()=>{const e=document.querySelector("[data-garc][data-lro-token][data-lro-signature][data-ei]");if(!e)return{url:null,error:"Missing AI Mode token container"};const t=document.getElementById("rKxeg")?.getAttribute("data-stkp")||null;return{origin:document.location.origin,search:document.location.search,stkp:t,fmt:document.querySelector("[data-madl]")?"madl":"adl",tokens:{ei:e.dataset.ei,garc:e.dataset.garc,lroToken:e.dataset.lroToken,lroSignature:e.dataset.lroSignature,xsrfFolwrToken:e.dataset.xsrfFolwrToken||null,srtst:e.dataset.srtst||null,hasGarc:!!e.dataset.garc,hasLroToken:!!e.dataset.lroToken,hasLroSignature:!!e.dataset.lroSignature,hasXsrf:!!e.dataset.xsrfFolwrToken,hasStkp:!!t}}});if(!t?.origin)return t;const r=function(e){const t={};for(const r of String(e??"").replace(/^\?/,"").split("&")){if(!r)continue;const e=r.indexOf("="),o=-1===e?r:r.slice(0,e),n=-1===e?"":r.slice(e+1);t[i(o)]=i(n)}return t}(t.search),n={},s=["q","udm","mstk","csuir","mtid","ved","vet","sei","dpr","hl","gl","source","vsrid","lns_img","cinpts"];for(const e of s)r[e]&&(n[e]=r[e]);t.tokens.srtst&&(n.srtst=t.tokens.srtst),n.garc=t.tokens.garc,n.mlro=t.tokens.lroToken,n.mlros=t.tokens.lroSignature,n.ei=t.tokens.ei,t.stkp&&(n.stkp=t.stkp);const l={_fmt:t.fmt};t.tokens.xsrfFolwrToken&&(l._xsrf=t.tokens.xsrfFolwrToken);const c=a(n),u=Object.entries(l).map(([e,t])=>`${o(e)}:${o(t)}`).join(",");return{url:`${t.origin}/async/folwr?${c}&async=${u}`,tokens:{ei:t.tokens.ei,hasGarc:t.tokens.hasGarc,hasLroToken:t.tokens.hasLroToken,hasLroSignature:t.tokens.hasLroSignature,hasXsrf:t.tokens.hasXsrf,hasStkp:t.tokens.hasStkp}}}summarizeNetwork(e,t){return e.map(e=>{const r=null==e.body?null:d({body:e.body,contentType:e.mimeType});return{method:e.method,type:e.type,url:e.url,status:e.status,mimeType:e.mimeType,decodedFormat:r?.format??null,recordCount:r?.records?.length??0,bodyPrefix:null==e.body?null:e.body.slice(0,t)}})}}function o(e){let t="";const r=String(e??"");for(let e=0;e<r.length;e++){const o=r.codePointAt(e);if(void 0===o)continue;const s=String.fromCodePoint(o);if(o>65535&&e++," "===s)t+="+";else if("ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789-_.~".includes(s))t+=s;else for(const e of n(o))t+=`%${e.toString(16).toUpperCase().padStart(2,"0")}`}return t}function n(e){return e<=127?[e]:e<=2047?[192|e>>6,128|63&e]:e<=65535?[224|e>>12,128|e>>6&63,128|63&e]:[240|e>>18,128|e>>12&63,128|e>>6&63,128|63&e]}function s(e){let t="";for(let r=0;r<e.length;r++){const o=e[r];let n=o;192==(224&o)?n=(31&o)<<6|63&e[++r]:224==(240&o)?n=(15&o)<<12|(63&e[++r])<<6|63&e[++r]:240==(248&o)&&(n=(7&o)<<18|(63&e[++r])<<12|(63&e[++r])<<6|63&e[++r]),t+=String.fromCodePoint(n)}return t}function i(e){const t=String(e??"").replace(/\+/g," ");let r="";for(let e=0;e<t.length;e++){if("%"!==t[e]||!/[0-9a-fA-F]{2}/.test(t.slice(e+1,e+3))){r+=t[e];continue}const o=[];for(;"%"===t[e]&&/[0-9a-fA-F]{2}/.test(t.slice(e+1,e+3));)o.push(Number.parseInt(t.slice(e+1,e+3),16)),e+=3;e--;try{r+=s(o)}catch{r+=o.map(e=>`%${e.toString(16).toUpperCase().padStart(2,"0")}`).join("")}}return r}function a(e){return Object.entries(e).filter(([,e])=>null!=e&&""!==e).map(([e,t])=>`${o(e)}=${o(t)}`).join("&")}function l(e){return e.replace(/^\s*\)\]\}'\s*\n?/,"")}function c(e){try{return JSON.parse(e)}catch{return}}function u(e){const t=[];for(const r of l(e).split(/\r?\n/)){const e=r.trim();if(!e)continue;const o=/^([a-zA-Z0-9_-]+);(.*)$/.exec(e);if(!o)continue;const n=o[2].trim();t.push({id:o[1],value:c(n)??n})}return t}function d({body:e,contentType:t=""}){const r=String(e??""),o=l(r).trimStart(),n=/^\s*\)\]\}'/.test(r),s=/^[\[{]/.test(o)?c(o):void 0,i=void 0===s?u(r):[];let a="text";return(t.includes("html")||/^\s*</.test(o))&&(a="html"),n&&void 0!==s?a="google-xssi-json":n&&i.length?a="google-xssi-record-stream":void 0!==s?a="json":i.length&&(a="google-record-stream"),{format:a,xssiPrefixed:n,parsed:s,records:i}}function f(e,t=4e3){return String(e??"").replace(/\u0000/g,"").replace(/[ \t]+\n/g,"\n").trim().slice(0,t)}function p(e){const t=String(e??"").split("\n").map(e=>e.trim()).filter(Boolean),r=t.findIndex(e=>/AI Mode response is ready/i.test(e));if(r>0)return t[r-1];const o=/^(Skip to main content|Accessibility help|Accessibility feedback|AI Mode|All|Images|Videos|News|More|Search Results|Sources|Related)$/i;return t.find(e=>!o.test(e))??null}function m(e){let t=e.replace(/</g,"<").replace(/>/g,">").replace(/&/g,"&").replace(/ /g," ");return t=function(e){let t="",r=0;for(;r<e.length;){const o=e.toLowerCase().indexOf("<style",r);if(-1===o){t+=e.slice(r);break}t+=e.slice(r,o);const n=e.toLowerCase().indexOf("</style>",o);if(-1===n)break;r=n+8}let o="";r=0;for(;r<t.length;){const e=t.toLowerCase().indexOf("<script",r);if(-1===e){o+=t.slice(r);break}o+=t.slice(r,e);const n=t.toLowerCase().indexOf("<\/script>",e);if(-1===n)break;r=n+9}return o}(t),t=t.replace(/<[^>]+>/g," "),t.replace(/\s+/g," ").trim()}function h(e){if(!e)return null;if("string"==typeof e){const t=e.trim();return t.startsWith("<")||t.includes("class=")||t.includes("id=")?e:null}if(Array.isArray(e))for(const t of e){const e=h(t);if(e)return e}else if("object"==typeof e){if("string"==typeof e.html)return e.html;if("string"==typeof e.aimc_block?.html)return e.aimc_block.html;if("string"==typeof e.value&&(e.value.startsWith("<")||e.value.includes("class=")))return e.value;for(const t of Object.values(e)){const e=h(t);if(e)return e}}return null}
|
|
@@ -1 +0,0 @@
|
|
|
1
|
-
import{defineAdapter as e}from"../../adapter/base-adapter.js";export default e({id:"ollama-usage",name:"Ollama Usage",domain:"ollama.com",description:"Fetches Ollama plan and usage details from the authenticated settings page.",endpoints:[{url:"https://ollama.com/settings",responseType:"html",headers:{Accept:"text/html,application/xhtml+xml,application/xml;q=0.9,*/*;q=0.8"},transform(e){const t="string"==typeof e?e:String(e),n=a(t,"Session usage"),i=a(t,"Weekly usage");return{time:(new Date).toISOString(),Plan:s(t),"Session Usage":n.usage,"Session Reset":n.reset,"Weekly Usage":i.usage,"Weekly Reset":i.reset}}}]});function s(e){const s=e.match(/Cloud Usage[\s\S]*?<\/span>[\s\S]*?<span[^>]*>([\s\S]*?)<\/span/i);return s?.[1]?.trim()??"unknown"}function a(e,s){const a=s.replace(/[.*+?^${}()|[\]\\]/g,"\\$&");const t=new RegExp(`<div[\\s\\S]*?<span[^>]*>\\s*${a}\\s*<\\/span>[\\s\\S]*?aria-label="${a}\\s+([^"]+)"[\\s\\S]*?data-time="([^"]+)"`,"i"),n=e.match(t);return{usage:n?.[1]?.replace(/\s+used$/i,"").trim()??"unknown",reset:n?.[2]?.trim()??"unknown"}}
|
|
@@ -1 +0,0 @@
|
|
|
1
|
-
import{randomUUID as e}from"node:crypto";import{defineAdapter as t}from"../../adapter/base-adapter.js";const n="https://www.perplexity.ai/rest/sse/perplexity_ask";export default t({id:"perplexity",name:"Perplexity AI Ask",domain:"perplexity.ai",description:"Fetches live streaming answers from Perplexity AI using its private REST/SSE API.",positionals:[{name:"question",description:"The query or question to ask Perplexity AI",required:!0,variadic:!0}],parameters:[{name:"model",type:"string",description:"Model preference (e.g. 'claude46sonnet', 'sonar-reasoning')",default:"claude46sonnet",short:"m"},{name:"out",type:"string",description:"Write decoded response JSON to file instead of stdout"},{name:"timeout",type:"number",description:"Request timeout in milliseconds",default:75e3},{name:"text",type:"boolean",description:"Print only the extracted text answer",short:"t"}],async fetchData(t,r){const i=r.question,a=r.model||"claude46sonnet",c=void 0!==r.timeout?Number(r.timeout):75e3;if(!t||0===t.length)throw new Error("No login found in browser. Please log in to perplexity.ai in Google Chrome.");const d=this.buildCookieString(t),l={params:{attachments:[],language:"en-US",timezone:Intl.DateTimeFormat().resolvedOptions().timeZone||"America/New_York",search_focus:"internet",sources:["web"],frontend_uuid:e(),mode:"copilot",model_preference:"claude46sonnet",is_related_query:!1,is_sponsored:!1,frontend_context_uuid:e(),prompt_source:"user",query_source:"home",is_incognito:!1,time_from_first_type:1,local_search_enabled:!1,use_schematized_api:!0,send_back_text_in_streaming_api:!1,supported_block_use_cases:["answer_modes","media_items","knowledge_cards","inline_entity_cards","place_widgets","finance_widgets","prediction_market_widgets","sports_widgets","flight_status_widgets","news_widgets","shopping_widgets","jobs_widgets","search_result_widgets","inline_images","inline_assets","placeholder_cards","diff_blocks","inline_knowledge_cards","entity_group_v2","refinement_filters","canvas_mode","maps_preview","answer_tabs","price_comparison_widgets","preserve_latex","generic_onboarding_widgets","in_context_suggestions","pending_followups","inline_claims","unified_assets","workflow_steps","background_agents"],client_coordinates:null,mentions:[],dsl_query:"",skip_search_enabled:!0,is_nav_suggestions_disabled:!1,source:"default",always_search_override:!1,override_no_search:!1,should_ask_for_mcp_tool_confirmation:!0,browser_agent_allow_once_from_toggle:!1,force_enable_browser_agent:!1,supported_features:["browser_agent_permission_banner_v1.1"],extended_context:!1,version:"2.18"},query_str:""};l.params.frontend_uuid=e(),l.params.frontend_context_uuid=e(),l.params.model_preference=a,l.params.dsl_query=i,l.params.time_from_first_type=1,l.query_str=i;const u=new AbortController,_=setTimeout(()=>u.abort(),c),p=this.resolveUserAgent(r);let f;try{f=await fetch(n,{method:"POST",headers:{accept:"text/event-stream","accept-language":"en-US,en;q=0.9","content-type":"application/json",origin:"https://www.perplexity.ai",referer:"https://www.perplexity.ai/","user-agent":p,"x-perplexity-request-endpoint":n,"x-perplexity-request-reason":"ask-query-state-provider","x-perplexity-request-try-number":"1","x-request-id":l.params.frontend_uuid,cookie:d},body:JSON.stringify(l),signal:u.signal})}catch(e){if(e instanceof Error&&"AbortError"===e.name)throw new Error(`Perplexity request timed out after ${c}ms.`);throw e}finally{clearTimeout(_)}const m=f.headers.get("content-type")||"";if(!f.ok){const e=await f.text();throw new Error(`HTTP ${f.status} (${f.statusText}): ${e}`)}if(m.includes("text/event-stream")){const e=await async function(e){const t=new TextDecoder,n=[],r={};let i=null,a="";function c(e){const t=[];for(const n of e.split("\n"))n.startsWith("data:")&&t.push(n.slice(5).trimStart());if(t.length)try{const e=JSON.parse(t.join("\n"));if(!e||"object"==typeof e&&0===Object.keys(e).length)return;n.push(e),function(e,t){for(const n of t?.blocks??[]){const t=n.intended_usage;for(const[r,s]of Object.entries(n))"intended_usage"!==r&&"diff_block"!==r&&t&&(e[t]=s);const r=n.diff_block;if(r?.field){e[r.field]??=null;for(const t of r.patches??[])e[r.field]=s(e[r.field],t)}}}(r,e),(e.final||"COMPLETED"===e.status||e.text_completed)&&(i=e)}catch{}}const d=e.body?.getReader();if(d)for(;;){const{value:e,done:n}=await d.read();if(n)break;for(a+=t.decode(e,{stream:!0}).replace(/\r\n/g,"\n");;){const e=a.indexOf("\n\n");if(-1===e)break;c(a.slice(0,e)),a=a.slice(e+2)}}else if(e.body&&Symbol.asyncIterator in e.body)for await(const n of e.body)for(a+=t.decode(n,{stream:!0}).replace(/\r\n/g,"\n");;){const e=a.indexOf("\n\n");if(-1===e)break;c(a.slice(0,e)),a=a.slice(e+2)}a+=t.decode(),a.trim()&&c(a);!i&&n.length&&(i=n[n.length-1]);return{chunks:n,state:r,final:i,answer:o(i,r)}}(f);return{endpoint:n,http_code:f.status,content_type:m,request:{query:i,model_preference:a,frontend_uuid:l.params.frontend_uuid,frontend_context_uuid:l.params.frontend_context_uuid},answer:e.answer,state:e.state,final:e.final,chunks:e.chunks}}{const e=await f.text();let t;try{t=JSON.parse(e)}catch{t=e}return{endpoint:n,http_code:f.status,content_type:m,request:{query:i,model_preference:a,frontend_uuid:l.params.frontend_uuid,frontend_context_uuid:l.params.frontend_context_uuid},body:t}}}});function r(e){return e.replace(/~1/g,"/").replace(/~0/g,"~")}function s(e,t){const n=t.op,s=t.path??"";if(""===s){if("replace"===n||"add"===n)return t.value;if("remove"===n)return null}const o=s.split("/").slice(1).map(r);null==e&&(e=/^\d+$/.test(o[0]??"")?[]:{});let i=e;for(let e=0;e<o.length-1;e++){const t=o[e],n=/^\d+$/.test(o[e+1]??"");if(Array.isArray(i)){const e=Number(t);for(;i.length<=e;)i.push(n?[]:{});i=i[e]}else i[t]??=n?[]:{},i=i[t]}const a=o.at(-1);if(null==a)return e;if(Array.isArray(i)){const e="-"===a?i.length:Number(a);"add"===n?i.splice(e,0,t.value):"replace"===n?i[e]=t.value:"remove"===n&&i.splice(e,1)}else"remove"===n?delete i[a]:"add"!==n&&"replace"!==n||(i[a]=t.value);return e}function o(e,t){for(const t of e?.blocks??[]){const e=t.markdown_block;if(null!=e?.answer)return e.answer;if(Array.isArray(e?.chunks))return e.chunks.join("")}for(const e of["ask_text","ask_text_0_markdown","markdown_block"]){const n=t[e];if(null!=n?.answer)return n.answer;if(Array.isArray(n?.chunks))return n.chunks.join("")}return null}
|
|
@@ -1,45 +0,0 @@
|
|
|
1
|
-
import { PlaywrightAdapter } from "../../adapter/playwright-attatch-chrome-adapter.js";
|
|
2
|
-
export default class extends PlaywrightAdapter {
|
|
3
|
-
id: string;
|
|
4
|
-
name: string;
|
|
5
|
-
domain: string;
|
|
6
|
-
description: string;
|
|
7
|
-
optionalCookies: boolean;
|
|
8
|
-
endpoints: {
|
|
9
|
-
url: string;
|
|
10
|
-
}[];
|
|
11
|
-
positionals: {
|
|
12
|
-
name: string;
|
|
13
|
-
description: string;
|
|
14
|
-
required: boolean;
|
|
15
|
-
}[];
|
|
16
|
-
parameters: ({
|
|
17
|
-
name: string;
|
|
18
|
-
type: "string";
|
|
19
|
-
description: string;
|
|
20
|
-
default: string;
|
|
21
|
-
short: string;
|
|
22
|
-
} | {
|
|
23
|
-
name: string;
|
|
24
|
-
type: "boolean";
|
|
25
|
-
description: string;
|
|
26
|
-
short: string;
|
|
27
|
-
default?: undefined;
|
|
28
|
-
})[];
|
|
29
|
-
fetchData(cookies: any, options: any): Promise<string>;
|
|
30
|
-
private gotoDashboardIfNeeded;
|
|
31
|
-
private ensurePropertyOverlayOpen;
|
|
32
|
-
private getProperties;
|
|
33
|
-
private selectPropertyByIndex;
|
|
34
|
-
private selectPropertyByName;
|
|
35
|
-
private openDownloadPanelIfNeeded;
|
|
36
|
-
private setNativeSelectValue;
|
|
37
|
-
private getSelectOptions;
|
|
38
|
-
private setDownloadOptions;
|
|
39
|
-
private fetchDownloadCsvText;
|
|
40
|
-
private normalizeInterval;
|
|
41
|
-
private intervalToValue;
|
|
42
|
-
private inferServiceTypeFromPropertyTitle;
|
|
43
|
-
private extractAddressNumber;
|
|
44
|
-
private formatPropertyLabel;
|
|
45
|
-
}
|
|
@@ -1 +0,0 @@
|
|
|
1
|
-
var e=this&&this.__addDisposableResource||function(e,t,r){if(null!=t){if("object"!=typeof t&&"function"!=typeof t)throw new TypeError("Object expected.");var o,a;if(r){if(!Symbol.asyncDispose)throw new TypeError("Symbol.asyncDispose is not defined.");o=t[Symbol.asyncDispose]}if(void 0===o){if(!Symbol.dispose)throw new TypeError("Symbol.dispose is not defined.");o=t[Symbol.dispose],r&&(a=o)}if("function"!=typeof o)throw new TypeError("Object not disposable.");a&&(o=function(){try{a.call(this)}catch(e){return Promise.reject(e)}}),e.stack.push({value:t,dispose:o,async:r})}else r&&e.stack.push({async:!0});return t},t=this&&this.__disposeResources||function(e){return function(t){function r(r){t.error=t.hasError?new e(r,t.error,"An error was suppressed during disposal."):r,t.hasError=!0}var o,a=0;return function e(){for(;o=t.stack.pop();)try{if(!o.async&&1===a)return a=0,t.stack.push(o),Promise.resolve().then(e);if(o.dispose){var i=o.dispose.call(o.value);if(o.async)return a|=2,Promise.resolve(i).then(e,function(t){return r(t),e()})}else a|=1}catch(e){r(e)}if(1===a)return t.hasError?Promise.reject(t.error):Promise.resolve();if(t.hasError)throw t.error}()}}("function"==typeof SuppressedError?SuppressedError:function(e,t,r){var o=new Error(r);return o.name="SuppressedError",o.error=e,o.suppressed=t,o});import{PlaywrightAdapter as r}from"../../adapter/playwright-attatch-chrome-adapter.js";import{performFormLogin as o}from"../../util/login-helper.js";export default class extends r{id="pseg-usage";name="PSEG Usage";domain="mysmartenergy.nj.pseg.com";description="Downloads PSEG Smart Energy usage data (CSV) or lists available properties.";optionalCookies=!0;endpoints=[{url:"https://mysmartenergy.nj.pseg.com"}];positionals=[{name:"property",description:"Property name (e.g. '100 Electric') or 1-based index to download usage for.",required:!1}];parameters=[{name:"interval",type:"string",description:"Select interval: 15, 30, hourly, daily, weekly, monthly, billing",default:"billing",short:"i"},{name:"list",type:"boolean",description:"List all downloadable properties instead of downloading",short:"l"}];async fetchData(r,a){const i={stack:[],error:void 0,hasError:!1};try{const t=!!a.debug,{username:r,password:n}=this.resolveCredentials(a),s=e(i,await this.connect(a),!0);if(await o({page:s,intendedUrl:"https://mysmartenergy.nj.pseg.com/Dashboard",emailSelector:"#LoginEmail",emailValue:r,passwordSelector:"#LoginPassword",passwordValue:n,submitButtonSelector:"button.loginBtn",delayMs:1e3,debug:t}),a.list){t&&console.log("Listing downloadable properties...");const e=await this.getProperties(s,a);let r=["Downloadable properties:"];for(const t of e){const e=t.isCurrent?" [current]":"";r.push(`${this.formatPropertyLabel(t)}${e} | ${t.address} | ${t.owner}`)}return r.join("\n")}const l=a.property;if(!l)throw new Error("Missing required argument: <property> or --list");let c="Electric",d=this.normalizeInterval(a.interval),p=l;const u=String(l).trim();if(/^\d+$/.test(u)){const e=await this.selectPropertyByIndex(s,Number(u),a);c=e.serviceType,p=e.label}else{const e=await this.selectPropertyByName(s,u,a);c=e.serviceType,p=e.label}t&&console.log(`Opening dashboard and downloading ${p} usage CSV for ${d}...`),await this.gotoDashboardIfNeeded(s,a),await this.openDownloadPanelIfNeeded(s,t),d=await this.setDownloadOptions(s,c,d);return await this.fetchDownloadCsvText(s)}catch(e){i.error=e,i.hasError=!0}finally{const e=t(i);e&&await e}}async gotoDashboardIfNeeded(e,t){if(!e.url().toLowerCase().startsWith("https://mysmartenergy.nj.pseg.com/dashboard")){t.debug&&console.log(`Current URL '${e.url()}' is not in dashboard. Navigating to Dashboard...`),await e.goto("https://mysmartenergy.nj.pseg.com/Dashboard",{waitUntil:"domcontentloaded"});if(await e.locator("#LoginEmail").isVisible().catch(()=>!1)){t.debug&&console.log("Session expired or redirected to login. Re-authenticating...");const{username:r,password:a}=this.resolveCredentials(t);await o({page:e,intendedUrl:"https://mysmartenergy.nj.pseg.com/Dashboard",emailSelector:"#LoginEmail",emailValue:r,passwordSelector:"#LoginPassword",passwordValue:a,submitButtonSelector:"button.loginBtn",delayMs:1e3,debug:!!t.debug})}}}async ensurePropertyOverlayOpen(e,t){await this.gotoDashboardIfNeeded(e,t);if(!await e.locator('.selectPropertyContainer input[placeholder="Search"]').isVisible().catch(()=>!1)){const r=e.getByRole("link",{name:"Select Property"});await r.waitFor({state:"visible",timeout:5e3}).catch(()=>{});try{await r.click()}catch(r){t.debug&&console.warn("Failed to click 'Select Property' by role, trying text locator:",r),await e.locator('a:has-text("Select Property")').first().click()}await e.waitForSelector(".selectPropertyContainer",{state:"visible",timeout:5e3})}}async getProperties(e,t){return await this.ensurePropertyOverlayOpen(e,t),await e.evaluate(()=>Array.from(document.querySelectorAll(".selectPropertyContainer li")).map(e=>{const t=Array.from(e.querySelectorAll("h4"));return{propertyId:e.getAttribute("data-property-id")||"",propertyType:e.getAttribute("data-property-type")||"",title:e.querySelector("h2")?.textContent?.trim()||"",owner:t[0]?.textContent?.trim()||"",address:t[1]?.textContent?.trim()||"",isCurrent:e.classList.contains("current")}}))}async selectPropertyByIndex(e,t,r){const o=await this.getProperties(e,r);if(!Number.isInteger(t)||t<1||t>o.length)throw new Error(`Property index ${t} is out of range. Use 1-${o.length}.`);const a=o[t-1];return await e.goto(`https://mysmartenergy.nj.pseg.com/Dashboard/SetMeterGroup?meterGroupId=${a.propertyId}`,{waitUntil:"domcontentloaded"}),await e.waitForTimeout(1e3),{label:this.formatPropertyLabel(a),title:a.title,serviceType:this.inferServiceTypeFromPropertyTitle(a.title)}}async selectPropertyByName(e,t,r){const o=String(t).trim().toLowerCase();if(!o)throw new Error("Property name is required.");const a=await this.getProperties(e,r);let i=a.find(e=>String(e.title).trim().toLowerCase()===o);if(i||(i=a.find(e=>this.formatPropertyLabel(e).toLowerCase()===o)),!i){const e=a.map(e=>this.formatPropertyLabel(e)).filter(Boolean).join(", ");throw new Error(`Property not found: ${t}. Available properties: ${e}`)}return await e.goto(`https://mysmartenergy.nj.pseg.com/Dashboard/SetMeterGroup?meterGroupId=${i.propertyId}`,{waitUntil:"domcontentloaded"}),await e.waitForTimeout(1e3),{label:this.formatPropertyLabel(i),title:i.title,serviceType:this.inferServiceTypeFromPropertyTitle(i.title)}}async openDownloadPanelIfNeeded(e,t){const r="#downloadOptions";if(!await e.locator(r).isVisible().catch(()=>!1)){t&&console.log("Clicking 'Data' link...");try{await e.getByRole("link",{name:"Data"}).click()}catch(r){t&&console.warn("Failed to click 'Data' by role, trying text locator:",r),await e.locator('a:has-text("Data")').first().click()}try{return void await e.waitForSelector(r,{state:"visible",timeout:5e3})}catch{}t&&console.log("Clicking 'download' link...");try{await e.getByRole("link",{name:"download"}).click()}catch(r){t&&console.warn("Failed to click 'download' by role, trying text locator:",r),await e.locator('a:has-text("download")').first().click()}await e.waitForSelector(r,{state:"visible",timeout:1e4})}}async setNativeSelectValue(e,t,r){const o=`select[name="${t}"]`;return await e.evaluate(({selector:e,value:t})=>{const r=document.querySelector(e);if(!r)throw new Error(`${e} select not found`);return r.value=t,r.dispatchEvent(new Event("change",{bubbles:!0})),{value:r.value}},{selector:o,value:r})}async getSelectOptions(e,t){const r=`select[name="${t}"]`;return await e.evaluate(e=>{const t=document.querySelector(e);if(!t)throw new Error(`${e} select not found`);return{value:t.value,options:Array.from(t.options).map(e=>({value:e.value,text:e.textContent?.trim()||""}))}},r)}async setDownloadOptions(e,t,r){const o="Gas"===t?"4":"1";if("Gas"===t&&"Billing"!==r)throw new Error("Gas usage only supports the Billing interval.");const a=this.intervalToValue(r);if(!a)throw new Error(`Unsupported interval mapping: ${r}`);await e.waitForSelector('select[name="SelectedServiceType"]',{state:"attached",timeout:5e3});const i=await this.setNativeSelectValue(e,"SelectedServiceType",o);if(i.value!==o)throw new Error(`Failed to set service type: ${JSON.stringify(i)}`);await e.waitForTimeout(500),await e.waitForSelector('select[name="SelectedInterval"]',{state:"attached",timeout:5e3});const n=await this.getSelectOptions(e,"SelectedInterval");if(!new Set(n.options.map(e=>e.value)).has(a)){const e=n.options.map(e=>e.text).join(", ");throw new Error(`Interval ${r} is not available for ${t}. Available intervals: ${e}`)}const s=n.value===a?n:await this.setNativeSelectValue(e,"SelectedInterval",a);if(s.value!==a)throw new Error(`Failed to set interval: ${JSON.stringify(s)}`);return r}async fetchDownloadCsvText(e){return await e.evaluate(async()=>{const e=document.querySelector("#downloadOptions");if(!e)throw new Error("Download form not found");const t=await fetch(e.action,{method:"POST",body:new FormData(e),credentials:"same-origin"});if(!t.ok)throw new Error("Download request failed with status "+t.status+" "+t.statusText);return await t.text()})}normalizeInterval(e){const t={15:"15-Minute","15-minute":"15-Minute",30:"30-Minute","30-minute":"30-Minute",hourly:"Hourly",daily:"Daily",weekly:"Weekly",monthly:"Monthly",billing:"Billing"}[String(e||"").trim().toLowerCase()];if(!t)throw new Error(`Invalid interval: ${e}. Use 15, 30, hourly, daily, weekly, monthly, or billing.`);return t}intervalToValue(e){return{"15-Minute":"3","30-Minute":"4",Hourly:"5",Daily:"6",Weekly:"8",Monthly:"9",Billing:"7"}[e]}inferServiceTypeFromPropertyTitle(e){if(/\bgas\b/i.test(e))return"Gas";if(/\belectric\b/i.test(e))return"Electric";throw new Error(`Could not infer service type from property title: ${e}`)}extractAddressNumber(e){const t=String(e||"").match(/^(\d+)/);return t?t[1]:""}formatPropertyLabel(e){const t=String(e.title||"").trim();if(t)return t;const r=e.propertyType||this.inferServiceTypeFromPropertyTitle(e.title);return`${this.extractAddressNumber(e.address)||e.propertyId||"Unknown"} ${r}`}}
|