website-api 1.0.3 → 1.0.5

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 CHANGED
@@ -1,2 +1,2 @@
1
1
  #!/usr/bin/env node
2
- import{readFileSync as o}from"node:fs";import{dirname as e,join as r}from"node:path";import{fileURLToPath as n}from"node:url";import{program as t}from"commander";import s from"chalk";import i from"cli-table3";import{getDefaultChromeDir as l}from"chrome-tools";import{queryWebsite as c,websites as a,loadAdapters as p}from"../src/website-api.js";const d=r(e(n(import.meta.url)),"..","..","package.json"),{version:m}=JSON.parse(o(d,"utf8"));process.on("unhandledRejection",()=>{console.error("No login found in browser"),process.exit(1)}),t.name("website-api").description("CLI to query website APIs using decrypted Chrome cookies on macOS").version(m),t.option("--profile <name>","specific Chrome profile directory (e.g., 'Default', 'Profile 1')").option("--current-profile","Show the currently resolved/selected Chrome profile directory and name").option("-u, --user-agent <string>","custom User-Agent header for HTTP requests"),t.command("list").description("List all supported website API adapters").action(async()=>{await p(),console.log(s.bold.green("\n🌐 Supported Website APIs:\n"));const o=new i({head:[s.bold.cyan("ID"),s.bold.cyan("Name"),s.bold.cyan("Domain"),s.bold.cyan("Description")],colWidths:[18,25,20,50],wordWrap:!0,style:{head:[],border:[]}});for(const e of a)o.push([s.yellow(e.id),e.name,s.underline(e.domain),e.description]);console.log(o.toString()),console.log(`\nTo run an API query, execute: ${s.bold.cyan("npx website-api <id>")}\n`)}),t.argument("[website]","website ID or domain to query (e.g. 'chatgpt.com')").action(async o=>{const e=t.opts();if(e.currentProfile){const o=process.env.PROFILE_PATH||process.env.CHROME_PROFILE_PATH||l(),r=e.profile||process.env.PROFILE_NAME||"Default";return console.log(s.bold.green("\nšŸ‘¤ Currently Resolved Profile:\n")),console.log(` ${s.bold("Path:")} ${o}`),void console.log(` ${s.bold("Name:")} ${r}\n`)}if(o)try{const r=await c(o,{profile:e.profile,userAgent:e.userAgent});console.log(JSON.stringify(r,null,2))}catch(o){console.error("No login found in browser"),process.exit(1)}else t.outputHelp()}),t.parse(process.argv);
2
+ import{readFileSync as e}from"node:fs";import{dirname as o,join as r}from"node:path";import{fileURLToPath as n}from"node:url";import{program as t}from"commander";import s from"chalk";import i from"cli-table3";import{getDefaultChromeDir as c}from"chrome-tools";import{queryWebsite as l,websites as a,loadAdapters as p}from"../src/website-api.js";const d=r(o(n(import.meta.url)),"..","..","package.json"),{version:m}=JSON.parse(e(d,"utf8"));process.on("unhandledRejection",e=>{console.error(e instanceof Error?e.message:"command not found"),process.exit(1)}),t.name("website-api").description("CLI to query website APIs using decrypted Chrome cookies on macOS").version(m),t.option("--profile <name>","specific Chrome profile directory (e.g., 'Default', 'Profile 1')").option("--current-profile","Show the currently resolved/selected Chrome profile directory and name").option("-u, --user-agent <string>","custom User-Agent header for HTTP requests"),t.option("--debug","Print full HTTP request and response bodies for debugging"),t.command("list").description("List all supported website API adapters").action(async()=>{await p(),console.log(s.bold.green("\n🌐 Supported Website APIs:\n"));const e=new i({head:[s.bold.cyan("ID"),s.bold.cyan("Name"),s.bold.cyan("Domain"),s.bold.cyan("Description")],colWidths:[18,25,20,50],wordWrap:!0,style:{head:[],border:[]}});for(const o of a)e.push([s.yellow(o.id),o.name,s.underline(o.domain),o.description]);console.log(e.toString()),console.log(`\nTo run an API query, execute: ${s.bold.cyan("npx website-api <id>")}\n`)}),t.argument("[website]","website ID or domain to query (e.g. 'chatgpt.com')").action(async e=>{const o=t.opts();if(o.currentProfile){const e=process.env.PROFILE_PATH||process.env.CHROME_PROFILE_PATH||c(),r=o.profile||process.env.PROFILE_NAME||"Default";return console.log(s.bold.green("\nšŸ‘¤ Currently Resolved Profile:\n")),console.log(` ${s.bold("Path:")} ${e}`),void console.log(` ${s.bold("Name:")} ${r}\n`)}if(e)try{const r=await l(e,{profile:o.profile,userAgent:o.userAgent,debug:Boolean(o.debug)});console.log(JSON.stringify(r,null,2))}catch(e){console.error(e instanceof Error?e.message:"command not found"),process.exit(1)}else t.outputHelp()}),t.parse(process.argv);
@@ -1 +1 @@
1
- const t={buildCookieString:t=>t.map(t=>`${t.name}=${t.value}`).join("; "),resolveUserAgent:t=>t.userAgent||process.env.userAgent||process.env.USER_AGENT||"Mozilla/5.0 (Macintosh; Intel Mac OS X 10_15_7) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/148.0.0.0 Safari/537.36",async fetchJson(t,e){const n=await fetch(t,e);if(!n.ok)throw new Error(`HTTP ${n.status}: ${n.statusText}`);const r=await n.text();try{return JSON.parse(r)}catch{return{response:r}}},async fetchText(t,e){const n=await fetch(t,e);if(!n.ok)throw new Error(`HTTP ${n.status}: ${n.statusText}`);return n.text()},async fetchHtml(t,e){return this.fetchText(t,e)}};async function e(t,e){if(!this.endpoints||0===this.endpoints.length)throw new Error(`Adapter "${this.id}" has no endpoints defined and no fetchData override`);const n=this.endpoints[0],r=this.buildCookieString(t),s=this.resolveUserAgent(e),o=await async function(t,e,n){const r=await fetch(t.url,{method:t.method||"GET",headers:{Cookie:e,"User-Agent":n,Accept:"html"===t.responseType?"text/html,application/xhtml+xml,application/xml;q=0.9,*/*;q=0.8":"text"===t.responseType?"text/plain,*/*;q=0.8":"application/json, text/plain, */*",...t.headers}});if(!r.ok)throw new Error(`HTTP ${r.status}: ${r.statusText}`);const s=await r.text(),o=r.headers.get("content-type")?.toLowerCase()??"";if("json"===t.responseType||"text"!==t.responseType&&"html"!==t.responseType&&(o.includes("application/json")||o.includes("+json")))try{return JSON.parse(s)}catch(e){throw new Error(`Expected JSON from ${t.url}, but received invalid JSON: ${e instanceof Error?e.message:String(e)}`)}return s}(n,r,s);return n.transform?n.transform.call(this,o,t,e):o}export function defineAdapter(n){const r={...n,...t,fetchData:n.fetchData??e};return r.fetchData=r.fetchData.bind(r),r}
1
+ const e={buildCookieString:e=>e.map(e=>`${e.name}=${e.value}`).join("; "),resolveUserAgent:e=>e.userAgent||process.env.userAgent||process.env.USER_AGENT||"Mozilla/5.0 (Macintosh; Intel Mac OS X 10_15_7) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/148.0.0.0 Safari/537.36",async fetchJson(e,t){const s=this?._lastQueryOptions?.debug;s&&console.log("[debug] Request:",{url:e,init:t});const r=await fetch(e,t),o=await r.text();if(s&&console.log("[debug] Response:",{url:e,status:r.status,statusText:r.statusText,headers:Array.from(r.headers.entries()),body:o}),!r.ok)throw new Error(`HTTP ${r.status}: ${r.statusText}`);try{return JSON.parse(o)}catch{return{response:o}}},async fetchText(e,t){const s=this?._lastQueryOptions?.debug;s&&console.log("[debug] Request:",{url:e,init:t});const r=await fetch(e,t),o=await r.text();if(s&&console.log("[debug] Response:",{url:e,status:r.status,statusText:r.statusText,headers:Array.from(r.headers.entries()),body:o}),!r.ok)throw new Error(`HTTP ${r.status}: ${r.statusText}`);return o},async fetchHtml(e,t){return this.fetchText(e,t)}};async function t(e,t){if(!this.endpoints||0===this.endpoints.length)throw new Error(`Adapter "${this.id}" has no endpoints defined and no fetchData override`);const s=this.endpoints[0],r=this.buildCookieString(e),o=this.resolveUserAgent(t),n=await async function(e,t,s,r){r?.debug&&console.log("[debug] Request:",{url:e.url,method:e.method||"GET",headers:{Cookie:t,"User-Agent":s,...e.headers}});const o=await fetch(e.url,{method:e.method||"GET",headers:{Cookie:t,"User-Agent":s,Accept:"html"===e.responseType?"text/html,application/xhtml+xml,application/xml;q=0.9,*/*;q=0.8":"text"===e.responseType?"text/plain,*/*;q=0.8":"application/json, text/plain, */*",...e.headers}});if(!o.ok)throw new Error(`HTTP ${o.status}: ${o.statusText}`);const n=await o.text();r?.debug&&console.log("[debug] Response:",{url:e.url,status:o.status,statusText:o.statusText,headers:Array.from(o.headers.entries()),body:n});const a=o.headers.get("content-type")?.toLowerCase()??"";if("json"===e.responseType||"text"!==e.responseType&&"html"!==e.responseType&&(a.includes("application/json")||a.includes("+json")))try{return JSON.parse(n)}catch(t){throw new Error(`Expected JSON from ${e.url}, but received invalid JSON: ${t instanceof Error?t.message:String(t)}`)}return n}(s,r,o,t);return s.transform?s.transform.call(this,n,e,t):n}export function defineAdapter(s){const r={...s,...e,fetchData:s.fetchData??t};return r.fetchData=r.fetchData.bind(r),r}
@@ -59,4 +59,6 @@ export interface QueryOptions {
59
59
  profile?: string;
60
60
  /** Custom User-Agent header for HTTP requests. */
61
61
  userAgent?: string;
62
+ /** When true, print full HTTP request and response details for debugging. */
63
+ debug?: boolean;
62
64
  }
@@ -1 +1 @@
1
- import{defineAdapter as e}from"../../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 login found in browser");return this.fetchJson("https://chatgpt.com/backend-api/wham/usage",{headers:{authorization:`Bearer ${o.accessToken}`}})}});
1
+ import{defineAdapter as e}from"../../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 +1 @@
1
- import{readdirSync as o}from"node:fs";import{dirname as e,join as r}from"node:path";import{fileURLToPath as t,pathToFileURL as i}from"node:url";import{getCookies as n}from"chrome-tools";import{loadEnv as s}from"./env.js";import{createUniversalAdapter as a}from"./universal-adapter.js";s();const c=e(t(import.meta.url)),f=r(c,"website");export let websites=[];export async function loadAdapters(){if(!(websites.length>0))try{const e=o(f,{withFileTypes:!0});for(const t of e){if(!t.isDirectory())continue;const e=r(f,t.name),n=o(e).find(o=>o.endsWith("-adapter.js"));if(!n)continue;const s=i(r(e,n)).href,a=(await import(s)).default;a?.id&&websites.push(a)}}catch(o){}}export function getWebsite(o){if(!o)return null;const e=o.toLowerCase().trim();return websites.find(o=>o.id.toLowerCase()===e||o.id.toLowerCase().replace(".com","")===e)??null}export async function queryWebsite(o,e={}){await loadAdapters();const r=process.env.PROFILE_PATH||process.env.CHROME_PROFILE_PATH||void 0,t=e.profile||process.env.PROFILE_NAME||void 0;let i,s=getWebsite(o);if(!s&&(s=a(o),!s))throw new Error("No login found in browser");try{i=n({chromeDir:r,profile:t,domain:s.domain,decrypt:!0})}catch{throw new Error("No login found in browser")}if(!i||0===i.length)throw new Error("No login found in browser");return s.fetchData(i,e)}
1
+ import{readdirSync as t}from"node:fs";import{dirname as e,join as o}from"node:path";import{fileURLToPath as r,pathToFileURL as n}from"node:url";import{getCookies as i}from"chrome-tools";import{loadEnv as s}from"./env.js";import{createUniversalAdapter as a}from"./universal-adapter.js";s();const c=e(r(import.meta.url)),f=o(c,"website");export let websites=[];export async function loadAdapters(){if(!(websites.length>0))try{const e=t(f,{withFileTypes:!0});for(const r of e){if(!r.isDirectory())continue;const e=o(f,r.name),i=t(e).find(t=>t.endsWith("-adapter.js"));if(!i)continue;const s=n(o(e,i)).href,a=(await import(s)).default;a?.id&&websites.push(a)}}catch(t){}}export function getWebsite(t){if(!t)return null;const e=t.toLowerCase().trim();return websites.find(t=>t.id.toLowerCase()===e||t.id.toLowerCase().replace(".com","")===e)??null}export async function queryWebsite(t,e={}){await loadAdapters();const o=process.env.PROFILE_PATH||process.env.CHROME_PROFILE_PATH||void 0,r=e.profile||process.env.PROFILE_NAME||void 0;let n,s=getWebsite(t);if(!s){if(!function(t){return t.startsWith("http://")||t.startsWith("https://")||t.includes(".")||t.includes("/")||t.includes(":")}(t))throw new Error("command not found");if(s=a(t),!s)throw new Error("command not found")}try{n=i({chromeDir:o,profile:r,domain:s.domain,decrypt:!0})}catch{throw new Error("No login found in browser")}if(!n||0===n.length)throw new Error("No login found in browser");s._lastQueryOptions=e;try{return await s.fetchData(n,e)}finally{delete s._lastQueryOptions}}
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "website-api",
3
- "version": "1.0.3",
3
+ "version": "1.0.5",
4
4
  "description": "CLI and library to fetch website API data",
5
5
  "main": "./dist/src/website-api.js",
6
6
  "type": "module",