@axiom_ai/api 1.0.0 → 1.0.2

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/AGENTS.md ADDED
@@ -0,0 +1,3 @@
1
+ # AGENTS.md
2
+
3
+ This package documents its agent conventions, public API surface, common patterns, and error semantics in [`CLAUDE.md`](./CLAUDE.md) — read that file first, regardless of which agent you're running. Runnable examples live in [`examples/`](./examples/).
package/CLAUDE.md ADDED
@@ -0,0 +1,154 @@
1
+ # CLAUDE.md — `@axiom_ai/api` agent instructions
2
+
3
+ Reference doc Claude (and other agents following the AGENTS.md convention) read when working with this package — both inside this repo and after `npm install @axiom_ai/api` puts a copy at `node_modules/@axiom_ai/api/CLAUDE.md` in a consumer project. Keep this terse and code-truth-aligned; the actual source-of-truth is [`src/axiom-api.js`](./src/axiom-api.js).
4
+
5
+ ## What this package is
6
+
7
+ A small Node library that drives Axiom.ai's cloud browser pool over a REST API (`/api/v5/*`). It is **not** a Puppeteer/Playwright wrapper and **does not** speak CDP — it calls named step functions on a Laravel backend (`https://lar.axiom.ai`) that run inside the cloud browser. If you want raw CDP, that's the separate Chrome API surface — see [the website's API overview](https://axiom.ai/docs/developer-hub/api).
8
+
9
+ Bundled in the npm tarball alongside source-built `dist/`:
10
+ - This file (`CLAUDE.md`) — surface + patterns.
11
+ - `AGENTS.md` — redirect to here for non-Claude agents.
12
+ - `examples/` — three runnable Node scripts: `simple-scrape.js`, `login-then-extract.js`, `parallel-sessions.js`.
13
+
14
+ ## Public method surface
15
+
16
+ Every method below is on the `AxiomApi` class. Construct with `new AxiomApi(apiKey)`; the key comes from the user's account (see "Auth + signup" below).
17
+
18
+ ### Lifecycle (always pair these)
19
+
20
+ | Method | Notes |
21
+ |---|---|
22
+ | `browserOpen()` | Opens a cloud browser session. Returns the CDP endpoint and caches it on the instance as `axiom.cdpLink`. |
23
+ | `browserClose(cdpLink?)` | Closes the session. Pass `cdpLink` only if closing a session from a different instance (rare). |
24
+
25
+ **Wrap every script in `try { … } finally { await axiom.browserClose() }`** so a thrown step doesn't leak a cloud session.
26
+
27
+ ### Navigation
28
+
29
+ | Method | Notes |
30
+ |---|---|
31
+ | `goto(url, doNotShareLocalstorage?, openInNewTab?)` | Navigate the current tab (or a new one if third arg is `true`). |
32
+ | `switchBrowserTab(selectTab)` | Switch focus to a tab by name/URL substring. |
33
+
34
+ ### Interaction
35
+
36
+ | Method | Notes |
37
+ |---|---|
38
+ | `click(select, leftClickRightClick?, optionalClick?)` | Single click. `optionalClick: true` no-ops when the selector doesn't match. |
39
+ | `clickMultiple(select, leftClickRightClick?, maxClicks?)` | Click every match up to `maxClicks`. |
40
+ | `clickEngagementButton(select, setValueToCheck)` | Idempotent like/follow/subscribe toggle. |
41
+ | `hover(select)` | Mouse-over an element. |
42
+ | `clickAndDrag(startCoordinates, endCoordinates)` | Mouse-down at one point, release at another. Coordinates are `{scrollX, scrollY, clientX, clientY}` objects. |
43
+ | `enterText(selectTextField, text, delay?, appendExisting?, customLineBreak?, optionalText?)` | Type into an input field. |
44
+ | `pressKeys(key, delimiter?, delay?)` | Fire keyboard events (Enter, Tab, arrow keys, modifier combos). |
45
+ | `selectList(select, text)` | Pick an option from a `<select>` by visible text. |
46
+ | `datePicker(selectMonth, selectMonthChangeButton, changeMonthTo, changeDayOfMonthTo)` | Step through a calendar widget. |
47
+
48
+ ### Data
49
+
50
+ | Method | Notes |
51
+ |---|---|
52
+ | `scrape(url, selector, pager, max_results, settings)` | Smart-scrape rows. Pass `null` for `url` to scrape the current page. Returns an array of objects. |
53
+ | `scrapeMetadata(metadata)` | Extract structured page-level fields (title, OG tags, schema.org blocks). |
54
+ | `getClipboardContents()` | Read the cloud browser's clipboard (after a copy step). |
55
+
56
+ ### AI and utility
57
+
58
+ | Method | Notes |
59
+ |---|---|
60
+ | `integrateAI(aiOptions)` | Inline LLM call (extract or generate). `aiOptions: {aiFunction, key?, model?, prompt?, extractData?, promptExtract?}`. |
61
+ | `solveCaptcha(apiKey?)` | Hand the current page's captcha to a third-party solver. Omit `apiKey` to use the one stored on the account. |
62
+ | `wait(time)` | Pause **on the cloud pod** (keeps the session alive) for `time` ms. Use this rather than client-side `setTimeout`. |
63
+ | `restartBrowser()` | Restart Chrome within the same session — useful between unrelated flows. |
64
+
65
+ ## Methods NOT to call
66
+
67
+ These exist on the class but are not part of the public surface — don't emit them in generated code:
68
+
69
+ - `step(mode, method, params, cdpLink)` — the internal dispatcher every public method routes through. If you ever feel like calling `step()` directly, that means a named wrapper is missing; file an issue, don't paper over it.
70
+ - `_sleep(ms)` — client-side sleep helper. Internal; use `wait(time)` (cloud-side) for browser pacing.
71
+ - `_pollStepResult(...)` / `_shouldFallBackToPolling(...)` — error-recovery internals.
72
+
73
+ ## Common patterns
74
+
75
+ ### Simplest scrape — open, navigate, scrape, close
76
+
77
+ ```javascript
78
+ import { AxiomApi } from '@axiom_ai/api'
79
+
80
+ const axiom = new AxiomApi(process.env.AXIOM_API_KEY)
81
+ await axiom.browserOpen()
82
+ try {
83
+ await axiom.goto('https://example.com/products')
84
+ const rows = await axiom.scrape(null, '.product-card', null, 50, {})
85
+ console.log(`Found ${rows.length} products`)
86
+ } finally {
87
+ await axiom.browserClose()
88
+ }
89
+ ```
90
+
91
+ ### Login then extract
92
+
93
+ ```javascript
94
+ await axiom.goto('https://example.com/login')
95
+ await axiom.enterText('input[name=email]', process.env.LOGIN_EMAIL)
96
+ await axiom.enterText('input[name=password]', process.env.LOGIN_PASSWORD)
97
+ await axiom.click('button[type=submit]')
98
+ await axiom.wait(2000) // settle on the dashboard
99
+ const rows = await axiom.scrape(null, '.row', null, 100, {})
100
+ ```
101
+
102
+ ### Parallel sessions
103
+
104
+ Create independent `AxiomApi` instances — each calls `browserOpen()` and `browserClose()` independently. Don't share `cdpLink` between them.
105
+
106
+ ```javascript
107
+ const a = new AxiomApi(KEY); const b = new AxiomApi(KEY)
108
+ await Promise.all([a.browserOpen(), b.browserOpen()])
109
+ try {
110
+ const [rowsA, rowsB] = await Promise.all([
111
+ a.goto('https://a.test').then(() => a.scrape(null, '.row', null, 50, {})),
112
+ b.goto('https://b.test').then(() => b.scrape(null, '.row', null, 50, {})),
113
+ ])
114
+ } finally {
115
+ await Promise.all([a.browserClose(), b.browserClose()])
116
+ }
117
+ ```
118
+
119
+ See [`examples/`](./examples/) for runnable versions of these.
120
+
121
+ ## Error semantics
122
+
123
+ The library throws `AxiomHttpError` on non-2xx responses. Common shapes:
124
+
125
+ | Status | Meaning | What to do |
126
+ |---|---|---|
127
+ | 401 | API key invalid / expired | Re-mint the key — don't retry. |
128
+ | 403 | Account-level block (quota, abuse, plan) | Don't retry; surface to the user. |
129
+ | 409 | A step is already in flight on this `cdpLink` | Library auto-polls `/api/v5/step/result` and returns the result transparently. You shouldn't normally see 409 propagate. |
130
+ | 502 / 503 / 504 | Pod transient | Library auto-falls-back to polling. If still failing after polling, retry the whole `browserOpen → … → browserClose` flow. |
131
+ | Other 4xx | Bad params (wrong selector type, missing required arg) | Inspect the error body and fix the call. |
132
+
133
+ ## Auth + signup
134
+
135
+ The `AXIOM_API_KEY` env var holds the long-lived key. Two ways to get one:
136
+
137
+ 1. **Interactive** — sign up at [axiom.ai](https://axiom.ai), open the dashboard, copy the key.
138
+ 2. **Programmatic** — three-call flow documented at [`/docs/developer-hub/api/programmatic-signup`](https://axiom.ai/docs/developer-hub/api/programmatic-signup): `POST /api/user/create` → `POST /api/user/login` → `GET /api/user/key/create`. Suitable for headless onboarding.
139
+
140
+ ## Relationship to `@axiom_ai/claude-skill`
141
+
142
+ If the user is asking Claude to **build an axiom from a prompt** (e.g. "scrape this site daily and email me", "build me a bot that…"), the explicit marketplace plugin [`@axiom_ai/claude-skill`](https://github.com/axiom-browser-automation/claude-skill) gives Claude a richer guided experience — it covers both the *coded* path (this package) and the *no-code* path (saving to the user's dashboard). Use it when the user wants Claude to *invent* an axiom; this CLAUDE.md is enough when the user is *writing their own code* and asking Claude for help with the API surface.
143
+
144
+ ## Build + test (for maintainers working in this repo)
145
+
146
+ ```bash
147
+ npm ci # install deps
148
+ npm test # jest, 26 tests, runs against nock mocks (no live calls)
149
+ npm run build # vite produces dist/{es,cjs}/index.js; tsc emits .d.ts only
150
+ ```
151
+
152
+ **Watch-out from v1.0.1**: `tsconfig.json` is set to `emitDeclarationOnly: true`. If you change that, `tsc` will start emitting multi-file `.js` into `dist/es/` and clobber vite's single-bundle build — the result imports fine under CJS but fails under modern Node ESM with `ERR_MODULE_NOT_FOUND` on extensionless internal imports. Leave the flag alone unless you also wire up vite/tsc differently.
153
+
154
+ Publishing is via the Jenkins job `Publishing/axiom-api-publish` on the team's Jenkins; manual trigger only.
package/LICENSE ADDED
@@ -0,0 +1,15 @@
1
+ ISC License
2
+
3
+ Copyright (c) 2026 Axiom.ai
4
+
5
+ Permission to use, copy, modify, and/or distribute this software for any
6
+ purpose with or without fee is hereby granted, provided that the above
7
+ copyright notice and this permission notice appear in all copies.
8
+
9
+ THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
10
+ WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
11
+ MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
12
+ ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
13
+ WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
14
+ ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
15
+ OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
package/README.md CHANGED
@@ -13,20 +13,31 @@ To use the library, you'll first need to import the `AxiomApi` class and then wr
13
13
  Here is a basic example of how to structure your code:
14
14
 
15
15
  ```javascript
16
- import { AxiomApi } from 'axiom-api';
16
+ import { AxiomApi } from '@axiom_ai/api';
17
17
 
18
18
  async function run() {
19
19
  // 1. Initialize the AxiomApi class
20
20
  const axiom = new AxiomApi('[API_KEY]');
21
-
21
+
22
22
  // 2. Open the browser connection
23
23
  await axiom.browserOpen();
24
24
 
25
- // 3. Add your automation steps here (e.g., axiom.click(), axiom.type(), etc.)
25
+ // 3. Add your automation steps here (e.g., axiom.goto(), axiom.click(), axiom.enterText(), axiom.scrape(), etc.)
26
26
  // ... add steps ...
27
27
 
28
28
  // 4. Close the browser connection when done
29
29
  await axiom.browserClose();
30
30
  }
31
31
 
32
- run();
32
+ run();
33
+ ```
34
+
35
+ ## Working with Claude Code (or other agents)
36
+
37
+ This package bundles agent-targeted documentation alongside the runtime:
38
+
39
+ - [`CLAUDE.md`](./CLAUDE.md) — full method surface, error semantics, common patterns, auth + signup, and the methods *not* to call. Read by Claude automatically when this package is installed in a project.
40
+ - [`AGENTS.md`](./AGENTS.md) — same content, surfaced for non-Claude agents that follow the `AGENTS.md` convention.
41
+ - [`examples/`](./examples/) — three runnable scripts (`simple-scrape.js`, `login-then-extract.js`, `parallel-sessions.js`).
42
+
43
+ If you want Claude to *invent* an axiom from a prompt rather than help you write API calls yourself, also see [`@axiom_ai/claude-skill`](https://github.com/axiom-browser-automation/claude-skill) — the marketplace plugin covers both this library and the no-code dashboard path.
package/dist/cjs/index.js CHANGED
@@ -1 +1 @@
1
- "use strict";Object.defineProperty(exports,Symbol.toStringTag,{value:"Module"});const k="https://lar.axiom.ai";class c extends Error{constructor(t,e,n){super(t),this.name="AxiomHttpError",this.status=e,this.body=n}}class m{async post(t,e,n,i={}){const s=new AbortController;let o=null;i.timeoutMs&&i.timeoutMs>0&&(o=setTimeout(()=>s.abort(),i.timeoutMs));let r;try{r=await fetch(k+t,{method:"POST",headers:{Accept:"application/json","Content-Type":"application/json","X-API-KEY":e},body:JSON.stringify(n),signal:s.signal})}finally{o&&clearTimeout(o)}if(!r.ok){const h=await r.text();let a=null;try{a=JSON.parse(h)}catch{}if(r.status===401)throw new c("Failed to authenticate - please check your token.",401,a);const w=a&&a.message?a.message:`HTTP ${r.status} error: ${h}`;throw new c(w,r.status,a)}return r.json()}}const y=12e4,u=36e5,f=3e3,l=3e4,d=1.5;class g{constructor(t){this.cdpLink="",this.token=t,this.http=new m}async browserOpen(){const t=await this.http.post("/api/v5/browser/open",this.token);return this.cdpLink=t.endpoint,t.endpoint}async browserClose(t=""){t||(t=this.cdpLink);const e=await this.http.post("/api/v5/browser/close",this.token,{cdpLink:t});return this.cdpLink="",e.message}async step(t,e,n,i=""){try{const s=await this.http.post("/api/v5/step",this.token,{mode:t,method:e,params:n,cdpLink:i},{timeoutMs:y});return s&&s.message!==void 0?s.message:s}catch(s){if(!i||!this._shouldFallBackToPolling(s))throw s;return this._pollStepResult(i,s)}}_shouldFallBackToPolling(t){return!!(t&&t.name==="AbortError"||t&&t.name==="TypeError"||t instanceof c&&(t.status===502||t.status===503||t.status===504||t.status===409&&typeof t.message=="string"&&t.message.indexOf("Step already in progress")!==-1))}async _pollStepResult(t,e){const n=Date.now()+u;let i=f;for(;Date.now()<n;){await this._sleep(i);try{const s=await this.http.post("/api/v5/step/result",this.token,{cdpLink:t});if(s&&s.status==="complete")return s.result;if(s&&s.status==="running"){i=Math.min(i*d,l);continue}throw s&&s.status==="none"?new Error("Step did not start on the pod. Original error: "+(e&&e.message?e.message:"unknown")):new Error("Unexpected /step/result response: "+JSON.stringify(s))}catch(s){if(s instanceof c&&s.status===409)throw new Error("Step failed on the pod — check the task report. "+(s.message||""));if(s instanceof c&&s.status>=400&&s.status<500&&s.status!==502&&s.status!==503&&s.status!==504)throw s;i=Math.min(i*d,l)}}throw new Error("Step polling exceeded "+u/1e3+"s. Original error: "+(e&&e.message?e.message:"unknown"))}async scrape(t,e,n,i,s){return this.step("browser","AxiomApiSmartScrapeV440",[t,e,n,i,s],this.cdpLink)}async integrateAI(t){return this.step("browser","AxiomApiAiGeneric",[t],this.cdpLink)}async datePicker(t,e,n,i){return this.step("driver","datePicker",[t,e,n,i],this.cdpLink)}async click(t,e,n){return this.step("driver","clickV3130",[t,e,n],this.cdpLink)}async clickEngagementButton(t,e){return this.step("driver","clickEngagementButton",[t,e],this.cdpLink)}async clickMultiple(t,e,n){return this.step("driver","multiClickV3170",[t,e,n],this.cdpLink)}async getClipboardContents(){return this.step("driver","readClipboardContents",[],this.cdpLink)}async enterText(t,e,n=0,i=!1,s=null,o=!1){return this.step("driver","enterTextV4500",[t,e,n,i,s,o],this.cdpLink)}async goto(t,e=!1,n=!1){return this.step("driver","gotoV4070",[t,null,e,n],this.cdpLink)}async pressKeys(t,e,n){return this.step("driver","keydownV3120",[t,null,e,n],this.cdpLink)}async clickAndDrag(t,e){return this.step("driver","mouseClickDragV0300",[t,e],this.cdpLink)}async scrapeMetadata(t){return this.step("driver","scrapeMetadata",[t],this.cdpLink)}async selectList(t,e){return this.step("driver","selectList",[t,e],this.cdpLink)}async solveCaptcha(t){return this.step("driver","solveCaptchaV450",[null,null,t],this.cdpLink)}async switchBrowserTab(t){return this.step("driver","switchBrowserTab",[t],this.cdpLink)}async wait(t){return this.cdpLink?this.step("driver","wait",[t],this.cdpLink):this._sleep(t)}_sleep(t){return new Promise(e=>setTimeout(e,t))}async hover(t){return this.step("driver","hover",[t],this.cdpLink)}async restartBrowser(){return this.step("browser","AxiomApiRestartBrowser",[],this.cdpLink)}}exports.AxiomApi=g;
1
+ "use strict";Object.defineProperty(exports,Symbol.toStringTag,{value:"Module"});const k="https://lar.axiom.ai";class c extends Error{constructor(t,e,n){super(t),this.name="AxiomHttpError",this.status=e,this.body=n}}class m{async post(t,e,n,i={}){const s=new AbortController;let o=null;i.timeoutMs&&i.timeoutMs>0&&(o=setTimeout(()=>s.abort(),i.timeoutMs));let r;try{r=await fetch(k+t,{method:"POST",headers:{Accept:"application/json","Content-Type":"application/json","X-API-KEY":e},body:JSON.stringify(n),signal:s.signal})}finally{o&&clearTimeout(o)}if(!r.ok){const h=await r.text();let a=null;try{a=JSON.parse(h)}catch{}if(r.status===401)throw new c("Failed to authenticate - please check your token.",401,a);const w=a&&a.message?a.message:`HTTP ${r.status} error: ${h}`;throw new c(w,r.status,a)}return r.json()}}const y=12e4,u=36e5,f=3e3,l=3e4,d=1.5;class g{constructor(t){this.cdpLink="",this.token=t,this.http=new m}async browserOpen(){const t=await this.http.post("/api/v5/browser/open",this.token);return this.cdpLink=t.endpoint,t.endpoint}async browserClose(t=""){t||(t=this.cdpLink);const e=await this.http.post("/api/v5/browser/close",this.token,{cdpLink:t});return this.cdpLink="",e.message}async step(t,e,n,i=""){try{const s=await this.http.post("/api/v5/step",this.token,{mode:t,method:e,params:n,cdpLink:i},{timeoutMs:y});return s&&s.message!==void 0?s.message:s}catch(s){if(!i||!this._shouldFallBackToPolling(s))throw s;return this._pollStepResult(i,s)}}_shouldFallBackToPolling(t){return!!(t&&t.name==="AbortError"||t&&t.name==="TypeError"||t instanceof c&&(t.status===502||t.status===503||t.status===504||t.status===409&&typeof t.message=="string"&&t.message.indexOf("Step already in progress")!==-1))}async _pollStepResult(t,e){const n=Date.now()+u;let i=f;for(;Date.now()<n;){await this._sleep(i);try{const s=await this.http.post("/api/v5/step/result",this.token,{cdpLink:t});if(s&&s.status==="complete")return s.result;if(s&&s.status==="running"){i=Math.min(i*d,l);continue}throw s&&s.status==="none"?new Error("Step did not start on the pod. Original error: "+(e&&e.message?e.message:"unknown")):new Error("Unexpected /step/result response: "+JSON.stringify(s))}catch(s){if(s instanceof c&&s.status===409)throw new Error("Step failed on the pod — check the task report. "+(s.message||""));if(s instanceof c&&s.status>=400&&s.status<500&&s.status!==502&&s.status!==503&&s.status!==504)throw s;i=Math.min(i*d,l)}}throw new Error("Step polling exceeded "+u/1e3+"s. Original error: "+(e&&e.message?e.message:"unknown"))}async scrape(t,e,n,i,s){return this.step("browser","AxiomApiSmartScrapeV4400",[t,e,n,i,s],this.cdpLink)}async integrateAI(t){return this.step("browser","AxiomApiAiGeneric",[t],this.cdpLink)}async datePicker(t,e,n,i){return this.step("driver","datePicker",[t,e,n,i],this.cdpLink)}async click(t,e,n){return this.step("driver","clickV3130",[t,e,n],this.cdpLink)}async clickEngagementButton(t,e){return this.step("driver","clickEngagementButton",[t,e],this.cdpLink)}async clickMultiple(t,e,n){return this.step("driver","multiClickV3170",[t,e,n],this.cdpLink)}async getClipboardContents(){return this.step("driver","readClipboardContents",[],this.cdpLink)}async enterText(t,e,n=0,i=!1,s=null,o=!1){return this.step("driver","enterTextV4500",[t,e,n,i,s,o],this.cdpLink)}async goto(t,e=!1,n=!1){return this.step("driver","gotoV4070",[t,null,e,n],this.cdpLink)}async pressKeys(t,e,n){return this.step("driver","keydownV3120",[t,null,e,n],this.cdpLink)}async clickAndDrag(t,e){return this.step("driver","mouseClickDragV0300",[t,e],this.cdpLink)}async scrapeMetadata(t){return this.step("driver","scrapeMetadata",[t],this.cdpLink)}async selectList(t,e){return this.step("driver","selectList",[t,e],this.cdpLink)}async solveCaptcha(t){return this.step("driver","solveCaptchaV450",[null,null,t],this.cdpLink)}async switchBrowserTab(t){return this.step("driver","switchBrowserTab",[t],this.cdpLink)}async wait(t){return this.cdpLink?this.step("driver","wait",[t],this.cdpLink):this._sleep(t)}_sleep(t){return new Promise(e=>setTimeout(e,t))}async hover(t){return this.step("driver","hover",[t],this.cdpLink)}async restartBrowser(){return this.step("browser","AxiomApiRestartBrowser",[],this.cdpLink)}}exports.AxiomApi=g;
@@ -1 +1 @@
1
- export { AxiomApi } from "./axiom-api";
1
+ export { AxiomApi } from "./axiom-api.js";
package/dist/es/index.js CHANGED
@@ -1 +1,252 @@
1
- export { AxiomApi } from "./axiom-api";
1
+ const k = "https://lar.axiom.ai";
2
+ class c extends Error {
3
+ constructor(t, e, n) {
4
+ super(t), this.name = "AxiomHttpError", this.status = e, this.body = n;
5
+ }
6
+ }
7
+ class m {
8
+ async post(t, e, n, i = {}) {
9
+ const s = new AbortController();
10
+ let o = null;
11
+ i.timeoutMs && i.timeoutMs > 0 && (o = setTimeout(() => s.abort(), i.timeoutMs));
12
+ let r;
13
+ try {
14
+ r = await fetch(k + t, {
15
+ method: "POST",
16
+ headers: {
17
+ Accept: "application/json",
18
+ "Content-Type": "application/json",
19
+ "X-API-KEY": e
20
+ },
21
+ body: JSON.stringify(n),
22
+ signal: s.signal
23
+ });
24
+ } finally {
25
+ o && clearTimeout(o);
26
+ }
27
+ if (!r.ok) {
28
+ const h = await r.text();
29
+ let a = null;
30
+ try {
31
+ a = JSON.parse(h);
32
+ } catch {
33
+ }
34
+ if (r.status === 401)
35
+ throw new c("Failed to authenticate - please check your token.", 401, a);
36
+ const w = a && a.message ? a.message : `HTTP ${r.status} error: ${h}`;
37
+ throw new c(w, r.status, a);
38
+ }
39
+ return r.json();
40
+ }
41
+ }
42
+ const y = 12e4, u = 36e5, f = 3e3, l = 3e4, d = 1.5;
43
+ class _ {
44
+ /**
45
+ * @param {string} token API access token.
46
+ */
47
+ constructor(t) {
48
+ this.cdpLink = "", this.token = t, this.http = new m();
49
+ }
50
+ async browserOpen() {
51
+ const t = await this.http.post("/api/v5/browser/open", this.token);
52
+ return this.cdpLink = t.endpoint, t.endpoint;
53
+ }
54
+ async browserClose(t = "") {
55
+ t || (t = this.cdpLink);
56
+ const e = await this.http.post("/api/v5/browser/close", this.token, { cdpLink: t });
57
+ return this.cdpLink = "", e.message;
58
+ }
59
+ // TODO: Probably should be mvoed to a non-user facing component
60
+ async step(t, e, n, i = "") {
61
+ try {
62
+ const s = await this.http.post("/api/v5/step", this.token, {
63
+ mode: t,
64
+ method: e,
65
+ params: n,
66
+ cdpLink: i
67
+ }, { timeoutMs: y });
68
+ return s && s.message !== void 0 ? s.message : s;
69
+ } catch (s) {
70
+ if (!i || !this._shouldFallBackToPolling(s)) throw s;
71
+ return this._pollStepResult(i, s);
72
+ }
73
+ }
74
+ _shouldFallBackToPolling(t) {
75
+ return !!(t && t.name === "AbortError" || t && t.name === "TypeError" || t instanceof c && (t.status === 502 || t.status === 503 || t.status === 504 || t.status === 409 && typeof t.message == "string" && t.message.indexOf("Step already in progress") !== -1));
76
+ }
77
+ async _pollStepResult(t, e) {
78
+ const n = Date.now() + u;
79
+ let i = f;
80
+ for (; Date.now() < n; ) {
81
+ await this._sleep(i);
82
+ try {
83
+ const s = await this.http.post("/api/v5/step/result", this.token, { cdpLink: t });
84
+ if (s && s.status === "complete") return s.result;
85
+ if (s && s.status === "running") {
86
+ i = Math.min(i * d, l);
87
+ continue;
88
+ }
89
+ throw s && s.status === "none" ? new Error("Step did not start on the pod. Original error: " + (e && e.message ? e.message : "unknown")) : new Error("Unexpected /step/result response: " + JSON.stringify(s));
90
+ } catch (s) {
91
+ if (s instanceof c && s.status === 409)
92
+ throw new Error("Step failed on the pod — check the task report. " + (s.message || ""));
93
+ if (s instanceof c && s.status >= 400 && s.status < 500 && s.status !== 502 && s.status !== 503 && s.status !== 504)
94
+ throw s;
95
+ i = Math.min(i * d, l);
96
+ }
97
+ }
98
+ throw new Error("Step polling exceeded " + u / 1e3 + "s. Original error: " + (e && e.message ? e.message : "unknown"));
99
+ }
100
+ async scrape(t, e, n, i, s) {
101
+ return this.step(
102
+ "browser",
103
+ "AxiomApiSmartScrapeV4400",
104
+ [t, e, n, i, s],
105
+ this.cdpLink
106
+ );
107
+ }
108
+ async integrateAI(t) {
109
+ return this.step(
110
+ "browser",
111
+ "AxiomApiAiGeneric",
112
+ [t],
113
+ this.cdpLink
114
+ );
115
+ }
116
+ async datePicker(t, e, n, i) {
117
+ return this.step(
118
+ "driver",
119
+ "datePicker",
120
+ [t, e, n, i],
121
+ this.cdpLink
122
+ );
123
+ }
124
+ async click(t, e, n) {
125
+ return this.step(
126
+ "driver",
127
+ "clickV3130",
128
+ [t, e, n],
129
+ this.cdpLink
130
+ );
131
+ }
132
+ async clickEngagementButton(t, e) {
133
+ return this.step(
134
+ "driver",
135
+ "clickEngagementButton",
136
+ [t, e],
137
+ this.cdpLink
138
+ );
139
+ }
140
+ async clickMultiple(t, e, n) {
141
+ return this.step(
142
+ "driver",
143
+ "multiClickV3170",
144
+ [t, e, n],
145
+ this.cdpLink
146
+ );
147
+ }
148
+ async getClipboardContents() {
149
+ return this.step(
150
+ "driver",
151
+ "readClipboardContents",
152
+ [],
153
+ this.cdpLink
154
+ );
155
+ }
156
+ async enterText(t, e, n = 0, i = !1, s = null, o = !1) {
157
+ return this.step(
158
+ "driver",
159
+ "enterTextV4500",
160
+ [t, e, n, i, s, o],
161
+ this.cdpLink
162
+ );
163
+ }
164
+ async goto(t, e = !1, n = !1) {
165
+ return this.step(
166
+ "driver",
167
+ "gotoV4070",
168
+ [t, null, e, n],
169
+ this.cdpLink
170
+ );
171
+ }
172
+ async pressKeys(t, e, n) {
173
+ return this.step(
174
+ "driver",
175
+ "keydownV3120",
176
+ [t, null, e, n],
177
+ this.cdpLink
178
+ );
179
+ }
180
+ async clickAndDrag(t, e) {
181
+ return this.step(
182
+ "driver",
183
+ "mouseClickDragV0300",
184
+ [t, e],
185
+ this.cdpLink
186
+ );
187
+ }
188
+ async scrapeMetadata(t) {
189
+ return this.step(
190
+ "driver",
191
+ "scrapeMetadata",
192
+ [t],
193
+ this.cdpLink
194
+ );
195
+ }
196
+ async selectList(t, e) {
197
+ return this.step(
198
+ "driver",
199
+ "selectList",
200
+ [t, e],
201
+ this.cdpLink
202
+ );
203
+ }
204
+ async solveCaptcha(t) {
205
+ return this.step(
206
+ "driver",
207
+ "solveCaptchaV450",
208
+ [null, null, t],
209
+ this.cdpLink
210
+ );
211
+ }
212
+ async switchBrowserTab(t) {
213
+ return this.step(
214
+ "driver",
215
+ "switchBrowserTab",
216
+ [t],
217
+ this.cdpLink
218
+ );
219
+ }
220
+ // Pause on the pod, not in the client process, so the pod's session inactivity
221
+ // timer is reset by the step. A purely local sleep would let the session idle
222
+ // out and auto-close while the client was still happily waiting. Falls back to
223
+ // a local sleep when there is no session — nothing to keep alive.
224
+ async wait(t) {
225
+ return this.cdpLink ? this.step("driver", "wait", [t], this.cdpLink) : this._sleep(t);
226
+ }
227
+ // Local-only sleep, used by the polling loop's backoff. Never routes to the
228
+ // pod — that would be circular (the polling loop's whole purpose is to wait
229
+ // out a pod-side step that has lost its HTTP connection).
230
+ _sleep(t) {
231
+ return new Promise((e) => setTimeout(e, t));
232
+ }
233
+ async hover(t) {
234
+ return this.step(
235
+ "driver",
236
+ "hover",
237
+ [t],
238
+ this.cdpLink
239
+ );
240
+ }
241
+ async restartBrowser() {
242
+ return this.step(
243
+ "browser",
244
+ "AxiomApiRestartBrowser",
245
+ [],
246
+ this.cdpLink
247
+ );
248
+ }
249
+ }
250
+ export {
251
+ _ as AxiomApi
252
+ };
@@ -0,0 +1,17 @@
1
+ # Examples
2
+
3
+ Runnable Node scripts demonstrating common `@axiom_ai/api` patterns. Each is small (20-30 lines), ES-module syntax, and reads its API key from `AXIOM_API_KEY` in the environment.
4
+
5
+ | File | Demonstrates |
6
+ |---|---|
7
+ | [`simple-scrape.js`](./simple-scrape.js) | Smallest valid axiom — `browserOpen → goto → scrape → browserClose` with `try/finally`. |
8
+ | [`login-then-extract.js`](./login-then-extract.js) | `enterText` + `click` + `wait` for an auth flow, then scrape behind the login. |
9
+ | [`parallel-sessions.js`](./parallel-sessions.js) | Two `AxiomApi` instances side by side — each has its own lifecycle. |
10
+
11
+ Run any of them with:
12
+
13
+ ```bash
14
+ AXIOM_API_KEY=your-key node simple-scrape.js
15
+ ```
16
+
17
+ The full method surface, error semantics, and patterns reference is in [`../CLAUDE.md`](../CLAUDE.md).
@@ -0,0 +1,25 @@
1
+ // Log into a site, then scrape behind auth. Demonstrates: enterText, click, wait.
2
+
3
+ import { AxiomApi } from '@axiom_ai/api'
4
+
5
+ async function main() {
6
+ const axiom = new AxiomApi(process.env.AXIOM_API_KEY)
7
+
8
+ await axiom.browserOpen()
9
+ try {
10
+ await axiom.goto('https://example.com/login')
11
+ await axiom.enterText('#email', process.env.SITE_EMAIL)
12
+ await axiom.enterText('#password', process.env.SITE_PASSWORD)
13
+ await axiom.click('button[type=submit]')
14
+ // Wait on the pod (keeps the session alive) rather than a local setTimeout.
15
+ await axiom.wait(2000)
16
+
17
+ await axiom.goto('https://example.com/dashboard')
18
+ const rows = await axiom.scrape(null, '.report-row', null, 100, {})
19
+ return rows
20
+ } finally {
21
+ await axiom.browserClose()
22
+ }
23
+ }
24
+
25
+ await main()
@@ -0,0 +1,26 @@
1
+ // Drive two sessions in parallel. Each gets its own AxiomApi instance + lifecycle.
2
+ // Demonstrates that browserClose() is per-instance, not global.
3
+
4
+ import { AxiomApi } from '@axiom_ai/api'
5
+
6
+ async function scrapeOne(url) {
7
+ const axiom = new AxiomApi(process.env.AXIOM_API_KEY)
8
+ await axiom.browserOpen()
9
+ try {
10
+ await axiom.goto(url)
11
+ return await axiom.scrape(null, '.item', null, 20, {})
12
+ } finally {
13
+ await axiom.browserClose()
14
+ }
15
+ }
16
+
17
+ async function main() {
18
+ const urls = [
19
+ 'https://example.com/category/a',
20
+ 'https://example.com/category/b'
21
+ ]
22
+ const results = await Promise.all(urls.map(scrapeOne))
23
+ console.log('Total rows:', results.flat().length)
24
+ }
25
+
26
+ await main()
@@ -0,0 +1,20 @@
1
+ // Smallest valid axiom: open browser, navigate, scrape, close.
2
+ // Validator checks: methods on allowlist, try/finally lifecycle, no hardcoded token.
3
+
4
+ import { AxiomApi } from '@axiom_ai/api'
5
+
6
+ async function main() {
7
+ const axiom = new AxiomApi(process.env.AXIOM_API_KEY)
8
+
9
+ await axiom.browserOpen()
10
+ try {
11
+ await axiom.goto('https://example.com/products')
12
+ const rows = await axiom.scrape(null, '.product-card', null, 50, {})
13
+ console.log(`Found ${rows.length} products`)
14
+ return rows
15
+ } finally {
16
+ await axiom.browserClose()
17
+ }
18
+ }
19
+
20
+ await main()
package/package.json CHANGED
@@ -2,13 +2,16 @@
2
2
  "name": "@axiom_ai/api",
3
3
  "author": "Axiom.ai",
4
4
  "type": "module",
5
- "version": "1.0.0",
5
+ "version": "1.0.2",
6
6
  "description": "Library for interacting with Axiom.ai browser infrastructure",
7
7
  "main": "dist/cjs/index.js",
8
8
  "module": "dist/es/index.js",
9
9
  "types": "dist/es/index.d.ts",
10
10
  "files": [
11
- "dist"
11
+ "dist",
12
+ "CLAUDE.md",
13
+ "AGENTS.md",
14
+ "examples"
12
15
  ],
13
16
  "scripts": {
14
17
  "build:js": "vite build --mode production",
@@ -56,7 +59,11 @@
56
59
  "axiom.ai",
57
60
  "sdk",
58
61
  "browser",
59
- "automation"
62
+ "automation",
63
+ "claude",
64
+ "claude-code",
65
+ "agents-md",
66
+ "llm-friendly"
60
67
  ],
61
68
  "license": "ISC",
62
69
  "bugs": {
@@ -1,348 +0,0 @@
1
- var __awaiter = (this && this.__awaiter) || function (thisArg, _arguments, P, generator) {
2
- function adopt(value) { return value instanceof P ? value : new P(function (resolve) { resolve(value); }); }
3
- return new (P || (P = Promise))(function (resolve, reject) {
4
- function fulfilled(value) { try { step(generator.next(value)); } catch (e) { reject(e); } }
5
- function rejected(value) { try { step(generator["throw"](value)); } catch (e) { reject(e); } }
6
- function step(result) { result.done ? resolve(result.value) : adopt(result.value).then(fulfilled, rejected); }
7
- step((generator = generator.apply(thisArg, _arguments || [])).next());
8
- });
9
- };
10
- var __generator = (this && this.__generator) || function (thisArg, body) {
11
- var _ = { label: 0, sent: function() { if (t[0] & 1) throw t[1]; return t[1]; }, trys: [], ops: [] }, f, y, t, g = Object.create((typeof Iterator === "function" ? Iterator : Object).prototype);
12
- return g.next = verb(0), g["throw"] = verb(1), g["return"] = verb(2), typeof Symbol === "function" && (g[Symbol.iterator] = function() { return this; }), g;
13
- function verb(n) { return function (v) { return step([n, v]); }; }
14
- function step(op) {
15
- if (f) throw new TypeError("Generator is already executing.");
16
- while (g && (g = 0, op[0] && (_ = 0)), _) try {
17
- if (f = 1, y && (t = op[0] & 2 ? y["return"] : op[0] ? y["throw"] || ((t = y["return"]) && t.call(y), 0) : y.next) && !(t = t.call(y, op[1])).done) return t;
18
- if (y = 0, t) op = [op[0] & 2, t.value];
19
- switch (op[0]) {
20
- case 0: case 1: t = op; break;
21
- case 4: _.label++; return { value: op[1], done: false };
22
- case 5: _.label++; y = op[1]; op = [0]; continue;
23
- case 7: op = _.ops.pop(); _.trys.pop(); continue;
24
- default:
25
- if (!(t = _.trys, t = t.length > 0 && t[t.length - 1]) && (op[0] === 6 || op[0] === 2)) { _ = 0; continue; }
26
- if (op[0] === 3 && (!t || (op[1] > t[0] && op[1] < t[3]))) { _.label = op[1]; break; }
27
- if (op[0] === 6 && _.label < t[1]) { _.label = t[1]; t = op; break; }
28
- if (t && _.label < t[2]) { _.label = t[2]; _.ops.push(op); break; }
29
- if (t[2]) _.ops.pop();
30
- _.trys.pop(); continue;
31
- }
32
- op = body.call(thisArg, _);
33
- } catch (e) { op = [6, e]; y = 0; } finally { f = t = 0; }
34
- if (op[0] & 5) throw op[1]; return { value: op[0] ? op[1] : void 0, done: true };
35
- }
36
- };
37
- import { AxiomHttp, AxiomHttpError } from './axiom-http.js';
38
- // Tuning for the transparent long-running-step polling fallback. The library POSTs
39
- // /step with STEP_HTTP_TIMEOUT_MS as the abort deadline; if the POST times out, hits
40
- // a gateway error, or the backend says a previous step is still in flight, the
41
- // library polls /step/result with exponential backoff until the result lands or
42
- // STEP_MAX_POLL_DURATION_MS elapses.
43
- var STEP_HTTP_TIMEOUT_MS = 120000;
44
- var STEP_MAX_POLL_DURATION_MS = 3600000;
45
- var STEP_POLL_INITIAL_INTERVAL_MS = 3000;
46
- var STEP_POLL_MAX_INTERVAL_MS = 30000;
47
- var STEP_POLL_BACKOFF_FACTOR = 1.5;
48
- /**
49
- * @class
50
- * @public
51
- * A class for interacting with the Axiom API.
52
- */
53
- var AxiomApi = /** @class */ (function () {
54
- /**
55
- * @param {string} token API access token.
56
- */
57
- function AxiomApi(token) {
58
- this.cdpLink = '';
59
- this.token = token;
60
- this.http = new AxiomHttp();
61
- }
62
- AxiomApi.prototype.browserOpen = function () {
63
- return __awaiter(this, void 0, void 0, function () {
64
- var content;
65
- return __generator(this, function (_a) {
66
- switch (_a.label) {
67
- case 0: return [4 /*yield*/, this.http.post('/api/v5/browser/open', this.token)];
68
- case 1:
69
- content = _a.sent();
70
- this.cdpLink = content.endpoint;
71
- return [2 /*return*/, content.endpoint];
72
- }
73
- });
74
- });
75
- };
76
- AxiomApi.prototype.browserClose = function () {
77
- return __awaiter(this, arguments, void 0, function (cdpLink) {
78
- var content;
79
- if (cdpLink === void 0) { cdpLink = ''; }
80
- return __generator(this, function (_a) {
81
- switch (_a.label) {
82
- case 0:
83
- if (!cdpLink) {
84
- cdpLink = this.cdpLink;
85
- }
86
- return [4 /*yield*/, this.http.post('/api/v5/browser/close', this.token, { cdpLink: cdpLink })
87
- // Reset CDPLink to avoid staleness
88
- ];
89
- case 1:
90
- content = _a.sent();
91
- // Reset CDPLink to avoid staleness
92
- this.cdpLink = '';
93
- return [2 /*return*/, content.message];
94
- }
95
- });
96
- });
97
- };
98
- // TODO: Probably should be mvoed to a non-user facing component
99
- AxiomApi.prototype.step = function (mode_1, method_1, params_1) {
100
- return __awaiter(this, arguments, void 0, function (mode, method, params, cdpLink) {
101
- var content, e_1;
102
- if (cdpLink === void 0) { cdpLink = ''; }
103
- return __generator(this, function (_a) {
104
- switch (_a.label) {
105
- case 0:
106
- _a.trys.push([0, 2, , 3]);
107
- return [4 /*yield*/, this.http.post('/api/v5/step', this.token, {
108
- mode: mode,
109
- method: method,
110
- params: params,
111
- cdpLink: cdpLink
112
- }, { timeoutMs: STEP_HTTP_TIMEOUT_MS })];
113
- case 1:
114
- content = _a.sent();
115
- if (content && content.message !== undefined) {
116
- return [2 /*return*/, content.message];
117
- }
118
- return [2 /*return*/, content];
119
- case 2:
120
- e_1 = _a.sent();
121
- // Can only fall back to polling when there is a session to address.
122
- // One-shot /step calls have no cdpLink and surface the original error.
123
- if (!cdpLink || !this._shouldFallBackToPolling(e_1))
124
- throw e_1;
125
- return [2 /*return*/, this._pollStepResult(cdpLink, e_1)];
126
- case 3: return [2 /*return*/];
127
- }
128
- });
129
- });
130
- };
131
- AxiomApi.prototype._shouldFallBackToPolling = function (error) {
132
- // Direct POST never reached or never returned — step may still be running on the pod.
133
- if (error && error.name === 'AbortError')
134
- return true;
135
- // Native fetch network failure (DNS, connection reset, etc.) surfaces as TypeError.
136
- if (error && error.name === 'TypeError')
137
- return true;
138
- if (error instanceof AxiomHttpError) {
139
- if (error.status === 502 || error.status === 503 || error.status === 504)
140
- return true;
141
- if (error.status === 409 && typeof error.message === 'string'
142
- && error.message.indexOf('Step already in progress') !== -1)
143
- return true;
144
- }
145
- return false;
146
- };
147
- AxiomApi.prototype._pollStepResult = function (cdpLink, originalError) {
148
- return __awaiter(this, void 0, void 0, function () {
149
- var deadline, intervalMs, content, e_2;
150
- return __generator(this, function (_a) {
151
- switch (_a.label) {
152
- case 0:
153
- deadline = Date.now() + STEP_MAX_POLL_DURATION_MS;
154
- intervalMs = STEP_POLL_INITIAL_INTERVAL_MS;
155
- _a.label = 1;
156
- case 1:
157
- if (!(Date.now() < deadline)) return [3 /*break*/, 7];
158
- return [4 /*yield*/, this._sleep(intervalMs)];
159
- case 2:
160
- _a.sent();
161
- _a.label = 3;
162
- case 3:
163
- _a.trys.push([3, 5, , 6]);
164
- return [4 /*yield*/, this.http.post('/api/v5/step/result', this.token, { cdpLink: cdpLink })];
165
- case 4:
166
- content = _a.sent();
167
- if (content && content.status === 'complete')
168
- return [2 /*return*/, content.result];
169
- if (content && content.status === 'running') {
170
- intervalMs = Math.min(intervalMs * STEP_POLL_BACKOFF_FACTOR, STEP_POLL_MAX_INTERVAL_MS);
171
- return [3 /*break*/, 1];
172
- }
173
- if (content && content.status === 'none') {
174
- throw new Error('Step did not start on the pod. Original error: '
175
- + (originalError && originalError.message ? originalError.message : 'unknown'));
176
- }
177
- throw new Error('Unexpected /step/result response: ' + JSON.stringify(content));
178
- case 5:
179
- e_2 = _a.sent();
180
- // Executor is gone (step error → finish('Failure') removed it).
181
- // Surface as a hard failure — the task report has the detail.
182
- if (e_2 instanceof AxiomHttpError && e_2.status === 409) {
183
- throw new Error('Step failed on the pod — check the task report. ' + (e_2.message || ''));
184
- }
185
- // Auth or other definite 4xx — don't keep polling.
186
- if (e_2 instanceof AxiomHttpError && e_2.status >= 400 && e_2.status < 500
187
- && e_2.status !== 502 && e_2.status !== 503 && e_2.status !== 504) {
188
- throw e_2;
189
- }
190
- // Transient network issue mid-poll — back off and retry.
191
- intervalMs = Math.min(intervalMs * STEP_POLL_BACKOFF_FACTOR, STEP_POLL_MAX_INTERVAL_MS);
192
- return [3 /*break*/, 6];
193
- case 6: return [3 /*break*/, 1];
194
- case 7: throw new Error('Step polling exceeded ' + (STEP_MAX_POLL_DURATION_MS / 1000)
195
- + 's. Original error: '
196
- + (originalError && originalError.message ? originalError.message : 'unknown'));
197
- }
198
- });
199
- });
200
- };
201
- AxiomApi.prototype.scrape = function (url, selector, pager, max_results, settings) {
202
- return __awaiter(this, void 0, void 0, function () {
203
- return __generator(this, function (_a) {
204
- return [2 /*return*/, this.step('browser', 'AxiomApiSmartScrapeV440', [url, selector, pager, max_results, settings], this.cdpLink)];
205
- });
206
- });
207
- };
208
- AxiomApi.prototype.integrateAI = function (aiOptions) {
209
- return __awaiter(this, void 0, void 0, function () {
210
- return __generator(this, function (_a) {
211
- return [2 /*return*/, this.step('browser', 'AxiomApiAiGeneric', [aiOptions], this.cdpLink)];
212
- });
213
- });
214
- };
215
- AxiomApi.prototype.datePicker = function (selectMonth, selectMonthChangeButton, changeMonthTo, changeDayOfMonthTo) {
216
- return __awaiter(this, void 0, void 0, function () {
217
- return __generator(this, function (_a) {
218
- return [2 /*return*/, this.step('driver', 'datePicker', [selectMonth, selectMonthChangeButton, changeMonthTo, changeDayOfMonthTo], this.cdpLink)];
219
- });
220
- });
221
- };
222
- AxiomApi.prototype.click = function (select, leftClickRightClick, optionalClick) {
223
- return __awaiter(this, void 0, void 0, function () {
224
- return __generator(this, function (_a) {
225
- return [2 /*return*/, this.step('driver', 'clickV3130', [select, leftClickRightClick, optionalClick], this.cdpLink)];
226
- });
227
- });
228
- };
229
- AxiomApi.prototype.clickEngagementButton = function (select, setValueToCheck) {
230
- return __awaiter(this, void 0, void 0, function () {
231
- return __generator(this, function (_a) {
232
- return [2 /*return*/, this.step('driver', 'clickEngagementButton', [select, setValueToCheck], this.cdpLink)];
233
- });
234
- });
235
- };
236
- AxiomApi.prototype.clickMultiple = function (select, leftClickRightClick, maxClicks) {
237
- return __awaiter(this, void 0, void 0, function () {
238
- return __generator(this, function (_a) {
239
- return [2 /*return*/, this.step('driver', 'multiClickV3170', [select, leftClickRightClick, maxClicks], this.cdpLink)];
240
- });
241
- });
242
- };
243
- AxiomApi.prototype.getClipboardContents = function () {
244
- return __awaiter(this, void 0, void 0, function () {
245
- return __generator(this, function (_a) {
246
- return [2 /*return*/, this.step('driver', 'readClipboardContents', [], this.cdpLink)];
247
- });
248
- });
249
- };
250
- AxiomApi.prototype.enterText = function (selectTextField_1, text_1) {
251
- return __awaiter(this, arguments, void 0, function (selectTextField, text, delay, appendExisting, customLineBreak, optionalText) {
252
- if (delay === void 0) { delay = 0; }
253
- if (appendExisting === void 0) { appendExisting = false; }
254
- if (customLineBreak === void 0) { customLineBreak = null; }
255
- if (optionalText === void 0) { optionalText = false; }
256
- return __generator(this, function (_a) {
257
- return [2 /*return*/, this.step('driver', 'enterTextV4500', [selectTextField, text, delay, appendExisting, customLineBreak, optionalText], this.cdpLink)];
258
- });
259
- });
260
- };
261
- AxiomApi.prototype.goto = function (url_1) {
262
- return __awaiter(this, arguments, void 0, function (url, doNotShareLocalstorage, openInNewTab) {
263
- if (doNotShareLocalstorage === void 0) { doNotShareLocalstorage = false; }
264
- if (openInNewTab === void 0) { openInNewTab = false; }
265
- return __generator(this, function (_a) {
266
- return [2 /*return*/, this.step('driver', 'gotoV4070', [url, null, doNotShareLocalstorage, openInNewTab], this.cdpLink)];
267
- });
268
- });
269
- };
270
- AxiomApi.prototype.pressKeys = function (key, delimiter, delay) {
271
- return __awaiter(this, void 0, void 0, function () {
272
- return __generator(this, function (_a) {
273
- return [2 /*return*/, this.step('driver', 'keydownV3120', [key, null, delimiter, delay], this.cdpLink)];
274
- });
275
- });
276
- };
277
- AxiomApi.prototype.clickAndDrag = function (startCoordinates, endCoordinates) {
278
- return __awaiter(this, void 0, void 0, function () {
279
- return __generator(this, function (_a) {
280
- return [2 /*return*/, this.step('driver', 'mouseClickDragV0300', [startCoordinates, endCoordinates], this.cdpLink)];
281
- });
282
- });
283
- };
284
- AxiomApi.prototype.scrapeMetadata = function (metadata) {
285
- return __awaiter(this, void 0, void 0, function () {
286
- return __generator(this, function (_a) {
287
- return [2 /*return*/, this.step('driver', 'scrapeMetadata', [metadata], this.cdpLink)];
288
- });
289
- });
290
- };
291
- AxiomApi.prototype.selectList = function (select, text) {
292
- return __awaiter(this, void 0, void 0, function () {
293
- return __generator(this, function (_a) {
294
- return [2 /*return*/, this.step('driver', 'selectList', [select, text], this.cdpLink)];
295
- });
296
- });
297
- };
298
- AxiomApi.prototype.solveCaptcha = function (apiKey) {
299
- return __awaiter(this, void 0, void 0, function () {
300
- return __generator(this, function (_a) {
301
- return [2 /*return*/, this.step('driver', 'solveCaptchaV450', [null, null, apiKey], this.cdpLink)];
302
- });
303
- });
304
- };
305
- AxiomApi.prototype.switchBrowserTab = function (selectTab) {
306
- return __awaiter(this, void 0, void 0, function () {
307
- return __generator(this, function (_a) {
308
- return [2 /*return*/, this.step('driver', 'switchBrowserTab', [selectTab], this.cdpLink)];
309
- });
310
- });
311
- };
312
- // Pause on the pod, not in the client process, so the pod's session inactivity
313
- // timer is reset by the step. A purely local sleep would let the session idle
314
- // out and auto-close while the client was still happily waiting. Falls back to
315
- // a local sleep when there is no session — nothing to keep alive.
316
- AxiomApi.prototype.wait = function (time) {
317
- return __awaiter(this, void 0, void 0, function () {
318
- return __generator(this, function (_a) {
319
- if (this.cdpLink) {
320
- return [2 /*return*/, this.step('driver', 'wait', [time], this.cdpLink)];
321
- }
322
- return [2 /*return*/, this._sleep(time)];
323
- });
324
- });
325
- };
326
- // Local-only sleep, used by the polling loop's backoff. Never routes to the
327
- // pod — that would be circular (the polling loop's whole purpose is to wait
328
- // out a pod-side step that has lost its HTTP connection).
329
- AxiomApi.prototype._sleep = function (ms) {
330
- return new Promise(function (resolve) { return setTimeout(resolve, ms); });
331
- };
332
- AxiomApi.prototype.hover = function (select) {
333
- return __awaiter(this, void 0, void 0, function () {
334
- return __generator(this, function (_a) {
335
- return [2 /*return*/, this.step('driver', 'hover', [select], this.cdpLink)];
336
- });
337
- });
338
- };
339
- AxiomApi.prototype.restartBrowser = function () {
340
- return __awaiter(this, void 0, void 0, function () {
341
- return __generator(this, function (_a) {
342
- return [2 /*return*/, this.step('browser', 'AxiomApiRestartBrowser', [], this.cdpLink)];
343
- });
344
- });
345
- };
346
- return AxiomApi;
347
- }());
348
- export { AxiomApi };
@@ -1,122 +0,0 @@
1
- var __extends = (this && this.__extends) || (function () {
2
- var extendStatics = function (d, b) {
3
- extendStatics = Object.setPrototypeOf ||
4
- ({ __proto__: [] } instanceof Array && function (d, b) { d.__proto__ = b; }) ||
5
- function (d, b) { for (var p in b) if (Object.prototype.hasOwnProperty.call(b, p)) d[p] = b[p]; };
6
- return extendStatics(d, b);
7
- };
8
- return function (d, b) {
9
- if (typeof b !== "function" && b !== null)
10
- throw new TypeError("Class extends value " + String(b) + " is not a constructor or null");
11
- extendStatics(d, b);
12
- function __() { this.constructor = d; }
13
- d.prototype = b === null ? Object.create(b) : (__.prototype = b.prototype, new __());
14
- };
15
- })();
16
- var __awaiter = (this && this.__awaiter) || function (thisArg, _arguments, P, generator) {
17
- function adopt(value) { return value instanceof P ? value : new P(function (resolve) { resolve(value); }); }
18
- return new (P || (P = Promise))(function (resolve, reject) {
19
- function fulfilled(value) { try { step(generator.next(value)); } catch (e) { reject(e); } }
20
- function rejected(value) { try { step(generator["throw"](value)); } catch (e) { reject(e); } }
21
- function step(result) { result.done ? resolve(result.value) : adopt(result.value).then(fulfilled, rejected); }
22
- step((generator = generator.apply(thisArg, _arguments || [])).next());
23
- });
24
- };
25
- var __generator = (this && this.__generator) || function (thisArg, body) {
26
- var _ = { label: 0, sent: function() { if (t[0] & 1) throw t[1]; return t[1]; }, trys: [], ops: [] }, f, y, t, g = Object.create((typeof Iterator === "function" ? Iterator : Object).prototype);
27
- return g.next = verb(0), g["throw"] = verb(1), g["return"] = verb(2), typeof Symbol === "function" && (g[Symbol.iterator] = function() { return this; }), g;
28
- function verb(n) { return function (v) { return step([n, v]); }; }
29
- function step(op) {
30
- if (f) throw new TypeError("Generator is already executing.");
31
- while (g && (g = 0, op[0] && (_ = 0)), _) try {
32
- if (f = 1, y && (t = op[0] & 2 ? y["return"] : op[0] ? y["throw"] || ((t = y["return"]) && t.call(y), 0) : y.next) && !(t = t.call(y, op[1])).done) return t;
33
- if (y = 0, t) op = [op[0] & 2, t.value];
34
- switch (op[0]) {
35
- case 0: case 1: t = op; break;
36
- case 4: _.label++; return { value: op[1], done: false };
37
- case 5: _.label++; y = op[1]; op = [0]; continue;
38
- case 7: op = _.ops.pop(); _.trys.pop(); continue;
39
- default:
40
- if (!(t = _.trys, t = t.length > 0 && t[t.length - 1]) && (op[0] === 6 || op[0] === 2)) { _ = 0; continue; }
41
- if (op[0] === 3 && (!t || (op[1] > t[0] && op[1] < t[3]))) { _.label = op[1]; break; }
42
- if (op[0] === 6 && _.label < t[1]) { _.label = t[1]; t = op; break; }
43
- if (t && _.label < t[2]) { _.label = t[2]; _.ops.push(op); break; }
44
- if (t[2]) _.ops.pop();
45
- _.trys.pop(); continue;
46
- }
47
- op = body.call(thisArg, _);
48
- } catch (e) { op = [6, e]; y = 0; } finally { f = t = 0; }
49
- if (op[0] & 5) throw op[1]; return { value: op[0] ? op[1] : void 0, done: true };
50
- }
51
- };
52
- import { ENDPOINT } from "./config";
53
- var AxiomHttpError = /** @class */ (function (_super) {
54
- __extends(AxiomHttpError, _super);
55
- function AxiomHttpError(message, status, body) {
56
- var _this = _super.call(this, message) || this;
57
- _this.name = 'AxiomHttpError';
58
- _this.status = status;
59
- _this.body = body;
60
- return _this;
61
- }
62
- return AxiomHttpError;
63
- }(Error));
64
- export { AxiomHttpError };
65
- var AxiomHttp = /** @class */ (function () {
66
- function AxiomHttp() {
67
- }
68
- AxiomHttp.prototype.post = function (uri_1, token_1, body_1) {
69
- return __awaiter(this, arguments, void 0, function (uri, token, body, options) {
70
- var controller, timeoutId, rawResponse, errorText, parsed, msg;
71
- if (options === void 0) { options = {}; }
72
- return __generator(this, function (_a) {
73
- switch (_a.label) {
74
- case 0:
75
- controller = new AbortController();
76
- timeoutId = null;
77
- if (options.timeoutMs && options.timeoutMs > 0) {
78
- timeoutId = setTimeout(function () { return controller.abort(); }, options.timeoutMs);
79
- }
80
- _a.label = 1;
81
- case 1:
82
- _a.trys.push([1, , 3, 4]);
83
- return [4 /*yield*/, fetch(ENDPOINT + uri, {
84
- method: 'POST',
85
- headers: {
86
- 'Accept': 'application/json',
87
- 'Content-Type': 'application/json',
88
- 'X-API-KEY': token
89
- },
90
- body: JSON.stringify(body),
91
- signal: controller.signal
92
- })];
93
- case 2:
94
- rawResponse = _a.sent();
95
- return [3 /*break*/, 4];
96
- case 3:
97
- if (timeoutId)
98
- clearTimeout(timeoutId);
99
- return [7 /*endfinally*/];
100
- case 4:
101
- if (!!rawResponse.ok) return [3 /*break*/, 6];
102
- return [4 /*yield*/, rawResponse.text()];
103
- case 5:
104
- errorText = _a.sent();
105
- parsed = null;
106
- try {
107
- parsed = JSON.parse(errorText);
108
- }
109
- catch (_) { /* non-JSON body */ }
110
- if (rawResponse.status === 401) {
111
- throw new AxiomHttpError("Failed to authenticate - please check your token.", 401, parsed);
112
- }
113
- msg = (parsed && parsed.message) ? parsed.message : "HTTP ".concat(rawResponse.status, " error: ").concat(errorText);
114
- throw new AxiomHttpError(msg, rawResponse.status, parsed);
115
- case 6: return [2 /*return*/, rawResponse.json()];
116
- }
117
- });
118
- });
119
- };
120
- return AxiomHttp;
121
- }());
122
- export { AxiomHttp };
package/dist/es/config.js DELETED
@@ -1 +0,0 @@
1
- export var ENDPOINT = "https://lar.axiom.ai";