camofox-mcp 1.0.0
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/LICENSE +21 -0
- package/README.md +201 -0
- package/dist/client.d.ts +33 -0
- package/dist/client.d.ts.map +1 -0
- package/dist/client.js +224 -0
- package/dist/client.js.map +1 -0
- package/dist/config.d.ts +3 -0
- package/dist/config.d.ts.map +1 -0
- package/dist/config.js +41 -0
- package/dist/config.js.map +1 -0
- package/dist/errors.d.ts +23 -0
- package/dist/errors.d.ts.map +1 -0
- package/dist/errors.js +46 -0
- package/dist/errors.js.map +1 -0
- package/dist/index.d.ts +3 -0
- package/dist/index.d.ts.map +1 -0
- package/dist/index.js +32 -0
- package/dist/index.js.map +1 -0
- package/dist/server.d.ts +12 -0
- package/dist/server.d.ts.map +1 -0
- package/dist/server.js +27 -0
- package/dist/server.js.map +1 -0
- package/dist/state.d.ts +11 -0
- package/dist/state.d.ts.map +1 -0
- package/dist/state.js +54 -0
- package/dist/state.js.map +1 -0
- package/dist/tools/health.d.ts +4 -0
- package/dist/tools/health.d.ts.map +1 -0
- package/dist/tools/health.js +21 -0
- package/dist/tools/health.js.map +1 -0
- package/dist/tools/interaction.d.ts +5 -0
- package/dist/tools/interaction.d.ts.map +1 -0
- package/dist/tools/interaction.js +105 -0
- package/dist/tools/interaction.js.map +1 -0
- package/dist/tools/navigation.d.ts +4 -0
- package/dist/tools/navigation.d.ts.map +1 -0
- package/dist/tools/navigation.js +70 -0
- package/dist/tools/navigation.js.map +1 -0
- package/dist/tools/observation.d.ts +4 -0
- package/dist/tools/observation.d.ts.map +1 -0
- package/dist/tools/observation.js +54 -0
- package/dist/tools/observation.js.map +1 -0
- package/dist/tools/search.d.ts +4 -0
- package/dist/tools/search.d.ts.map +1 -0
- package/dist/tools/search.js +52 -0
- package/dist/tools/search.js.map +1 -0
- package/dist/tools/session.d.ts +4 -0
- package/dist/tools/session.d.ts.map +1 -0
- package/dist/tools/session.js +42 -0
- package/dist/tools/session.js.map +1 -0
- package/dist/tools/tabs.d.ts +4 -0
- package/dist/tools/tabs.d.ts.map +1 -0
- package/dist/tools/tabs.js +65 -0
- package/dist/tools/tabs.js.map +1 -0
- package/dist/types.d.ts +62 -0
- package/dist/types.d.ts.map +1 -0
- package/dist/types.js +2 -0
- package/dist/types.js.map +1 -0
- package/package.json +66 -0
package/LICENSE
ADDED
|
@@ -0,0 +1,21 @@
|
|
|
1
|
+
MIT License
|
|
2
|
+
|
|
3
|
+
Copyright (c) 2026 CamoFox MCP Contributors
|
|
4
|
+
|
|
5
|
+
Permission is hereby granted, free of charge, to any person obtaining a copy
|
|
6
|
+
of this software and associated documentation files (the "Software"), to deal
|
|
7
|
+
in the Software without restriction, including without limitation the rights
|
|
8
|
+
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
|
9
|
+
copies of the Software, and to permit persons to whom the Software is
|
|
10
|
+
furnished to do so, subject to the following conditions:
|
|
11
|
+
|
|
12
|
+
The above copyright notice and this permission notice shall be included in all
|
|
13
|
+
copies or substantial portions of the Software.
|
|
14
|
+
|
|
15
|
+
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
|
16
|
+
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
|
17
|
+
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
|
18
|
+
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
|
19
|
+
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
|
20
|
+
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
|
|
21
|
+
SOFTWARE.
|
package/README.md
ADDED
|
@@ -0,0 +1,201 @@
|
|
|
1
|
+
# 🦊 CamoFox MCP
|
|
2
|
+
|
|
3
|
+
**The anti-detection browser MCP server for AI agents.** Navigate, interact, and automate the web without getting blocked.
|
|
4
|
+
|
|
5
|
+
[](https://www.npmjs.com/package/camofox-mcp)
|
|
6
|
+
[](https://opensource.org/licenses/MIT)
|
|
7
|
+
[](https://www.typescriptlang.org/)
|
|
8
|
+
[](https://nodejs.org/)
|
|
9
|
+
[](https://modelcontextprotocol.io/)
|
|
10
|
+
|
|
11
|
+
---
|
|
12
|
+
|
|
13
|
+
## Why CamoFox MCP?
|
|
14
|
+
|
|
15
|
+
AI agents using Playwright get **blocked constantly**. CAPTCHAs, fingerprint detection, IP bans — the web fights back against automation.
|
|
16
|
+
|
|
17
|
+
**CamoFox MCP** wraps the [CamoFox anti-detection browser](https://github.com/jo-inc/camofox-browser) as an MCP server, giving your AI agent:
|
|
18
|
+
|
|
19
|
+
- 🛡️ **Anti-detection fingerprinting** — Each tab gets a unique, human-like browser fingerprint
|
|
20
|
+
- ⚡ **Fast, token-efficient snapshots** — Accessibility tree snapshots use 90% fewer tokens than screenshots
|
|
21
|
+
- 🔍 **Built-in search** — Search Google, YouTube, Amazon + 11 more engines without getting blocked
|
|
22
|
+
- 🍪 **Session persistence** — Import cookies, maintain login state across interactions
|
|
23
|
+
- 🎯 **CSS selector fallback** — Target elements even when accessibility refs aren't available
|
|
24
|
+
|
|
25
|
+
### CamoFox MCP vs Playwright MCP
|
|
26
|
+
|
|
27
|
+
| Feature | CamoFox MCP | Playwright MCP |
|
|
28
|
+
|---------|:-----------:|:--------------:|
|
|
29
|
+
| Anti-detection fingerprinting | ✅ | ❌ |
|
|
30
|
+
| Passes bot detection tests | ✅ | ❌ |
|
|
31
|
+
| Search engine macros (14 engines) | ✅ | ❌ |
|
|
32
|
+
| Accessibility snapshots | ✅ | ✅ |
|
|
33
|
+
| Cookie import/export | ✅ | Limited |
|
|
34
|
+
| Headless support | ✅ | ✅ |
|
|
35
|
+
| Setup complexity | Medium | Easy |
|
|
36
|
+
| Token efficiency | High | High |
|
|
37
|
+
|
|
38
|
+
### CamoFox MCP vs Other Camoufox MCPs
|
|
39
|
+
|
|
40
|
+
| Feature | CamoFox MCP | whit3rabbit/camoufox-mcp | baixianger/camoufox-mcp |
|
|
41
|
+
|---------|:-----------:|:-----------------------:|:-----------------------:|
|
|
42
|
+
| Tools | 18 | 1 | 33 |
|
|
43
|
+
| Architecture | REST API client | Direct browser | Direct browser |
|
|
44
|
+
| Session persistence | ✅ | ❌ (destroyed per request) | ✅ |
|
|
45
|
+
| Token efficiency | High (snapshots) | Low (raw HTML) | High (snapshots) |
|
|
46
|
+
| Search macros | ✅ (14 engines) | ❌ | ❌ |
|
|
47
|
+
| CSS selector fallback | ✅ | ❌ | ❌ |
|
|
48
|
+
| Active maintenance | ✅ | ❌ (stale 8mo) | ✅ |
|
|
49
|
+
| Press key support | ✅ | ❌ | ✅ |
|
|
50
|
+
|
|
51
|
+
## Quick Start
|
|
52
|
+
|
|
53
|
+
### Prerequisites
|
|
54
|
+
|
|
55
|
+
1. Install and run [CamoFox Browser](https://github.com/jo-inc/camofox-browser):
|
|
56
|
+
```bash
|
|
57
|
+
# Follow CamoFox installation guide
|
|
58
|
+
# CamoFox must be running on port 9377 (default)
|
|
59
|
+
```
|
|
60
|
+
|
|
61
|
+
### VS Code / Cursor / Claude Desktop
|
|
62
|
+
|
|
63
|
+
Add to your MCP configuration:
|
|
64
|
+
|
|
65
|
+
```json
|
|
66
|
+
{
|
|
67
|
+
"camofox": {
|
|
68
|
+
"command": "node",
|
|
69
|
+
"args": ["/path/to/camofox-mcp/dist/index.js"],
|
|
70
|
+
"env": {
|
|
71
|
+
"CAMOFOX_URL": "http://localhost:9377"
|
|
72
|
+
},
|
|
73
|
+
"type": "stdio"
|
|
74
|
+
}
|
|
75
|
+
}
|
|
76
|
+
```
|
|
77
|
+
|
|
78
|
+
### From Source
|
|
79
|
+
|
|
80
|
+
```bash
|
|
81
|
+
git clone https://github.com/redf0x1/camofox-mcp.git
|
|
82
|
+
cd camofox-mcp
|
|
83
|
+
npm install
|
|
84
|
+
npm run build
|
|
85
|
+
```
|
|
86
|
+
|
|
87
|
+
## Tools (18)
|
|
88
|
+
|
|
89
|
+
### Tab Management
|
|
90
|
+
| Tool | Description |
|
|
91
|
+
|------|-------------|
|
|
92
|
+
| `create_tab` | Create a new tab with anti-detection fingerprinting |
|
|
93
|
+
| `close_tab` | Close a tab and release resources |
|
|
94
|
+
| `list_tabs` | List all open tabs with URLs and titles |
|
|
95
|
+
|
|
96
|
+
### Navigation
|
|
97
|
+
| Tool | Description |
|
|
98
|
+
|------|-------------|
|
|
99
|
+
| `navigate` | Navigate to a URL, waits for page load |
|
|
100
|
+
| `go_back` | Browser back button |
|
|
101
|
+
| `go_forward` | Browser forward button |
|
|
102
|
+
| `refresh` | Reload current page |
|
|
103
|
+
|
|
104
|
+
### Interaction
|
|
105
|
+
| Tool | Description |
|
|
106
|
+
|------|-------------|
|
|
107
|
+
| `click` | Click element by ref (from snapshot) or CSS selector |
|
|
108
|
+
| `type_text` | Type text into input fields by ref or CSS selector |
|
|
109
|
+
| `press_key` | Press keyboard keys (Enter, Tab, Escape, etc.) |
|
|
110
|
+
| `scroll` | Scroll page up or down by pixel amount |
|
|
111
|
+
|
|
112
|
+
### Observation
|
|
113
|
+
| Tool | Description |
|
|
114
|
+
|------|-------------|
|
|
115
|
+
| `snapshot` | Get accessibility tree — PRIMARY way to read pages. Token-efficient |
|
|
116
|
+
| `screenshot` | Take visual screenshot as base64 PNG |
|
|
117
|
+
| `get_links` | Get all hyperlinks with URLs and text |
|
|
118
|
+
|
|
119
|
+
### Search
|
|
120
|
+
| Tool | Description |
|
|
121
|
+
|------|-------------|
|
|
122
|
+
| `web_search` | Search via 14 engines: Google, YouTube, Amazon, Bing, DuckDuckGo, Reddit, GitHub, StackOverflow, Wikipedia, Twitter, LinkedIn, Facebook, Instagram, TikTok |
|
|
123
|
+
|
|
124
|
+
### Session
|
|
125
|
+
| Tool | Description |
|
|
126
|
+
|------|-------------|
|
|
127
|
+
| `import_cookies` | Import cookies for authenticated sessions |
|
|
128
|
+
| `get_stats` | Get session statistics and performance metrics |
|
|
129
|
+
| `server_status` | Check CamoFox server health and connection |
|
|
130
|
+
|
|
131
|
+
## Configuration
|
|
132
|
+
|
|
133
|
+
### Environment Variables
|
|
134
|
+
|
|
135
|
+
| Variable | Default | Description |
|
|
136
|
+
|----------|---------|-------------|
|
|
137
|
+
| `CAMOFOX_URL` | `http://localhost:9377` | CamoFox server URL |
|
|
138
|
+
| `CAMOFOX_TIMEOUT` | `30000` | Request timeout in ms |
|
|
139
|
+
| `CAMOFOX_API_KEY` | — | API key (if CamoFox requires auth) |
|
|
140
|
+
|
|
141
|
+
## Architecture
|
|
142
|
+
|
|
143
|
+
```
|
|
144
|
+
AI Agent (Claude, GPT, etc.)
|
|
145
|
+
│
|
|
146
|
+
│ MCP Protocol (stdio)
|
|
147
|
+
▼
|
|
148
|
+
┌─────────────────┐
|
|
149
|
+
│ CamoFox MCP │ ← This package
|
|
150
|
+
│ (TypeScript) │
|
|
151
|
+
└────────┬────────┘
|
|
152
|
+
│
|
|
153
|
+
│ REST API (HTTP)
|
|
154
|
+
▼
|
|
155
|
+
┌─────────────────┐
|
|
156
|
+
│ CamoFox Server │ ← Anti-detection browser
|
|
157
|
+
│ (Port 9377) │
|
|
158
|
+
└────────┬────────┘
|
|
159
|
+
│
|
|
160
|
+
│ Browser Engine
|
|
161
|
+
▼
|
|
162
|
+
┌─────────────────┐
|
|
163
|
+
│ Camoufox │ ← Firefox-based, fingerprint spoofing
|
|
164
|
+
│ (Firefox) │
|
|
165
|
+
└─────────────────┘
|
|
166
|
+
```
|
|
167
|
+
|
|
168
|
+
## How It Works
|
|
169
|
+
|
|
170
|
+
1. **Your AI agent** sends MCP tool calls (e.g., `create_tab`, `navigate`, `snapshot`)
|
|
171
|
+
2. **CamoFox MCP** translates these into REST API calls to the CamoFox server
|
|
172
|
+
3. **CamoFox server** manages a Camoufox browser with anti-detection features
|
|
173
|
+
4. **Each tab** gets a unique fingerprint — different user agent, screen size, WebGL, fonts, etc.
|
|
174
|
+
5. **Websites see** what appears to be a normal human browser, not automation
|
|
175
|
+
|
|
176
|
+
## Anti-Detection Features
|
|
177
|
+
|
|
178
|
+
CamoFox (via [Camoufox](https://github.com/jo-inc/camofox-browser)) provides:
|
|
179
|
+
|
|
180
|
+
- ✅ Unique browser fingerprint per tab
|
|
181
|
+
- ✅ Human-like user agent rotation
|
|
182
|
+
- ✅ WebGL fingerprint spoofing
|
|
183
|
+
- ✅ Canvas fingerprint protection
|
|
184
|
+
- ✅ Screen resolution randomization
|
|
185
|
+
- ✅ Font enumeration protection
|
|
186
|
+
- ✅ Navigator properties masking
|
|
187
|
+
- ✅ Timezone/locale consistency
|
|
188
|
+
|
|
189
|
+
## Contributing
|
|
190
|
+
|
|
191
|
+
Contributions are welcome! Please open an issue or submit a PR.
|
|
192
|
+
|
|
193
|
+
## License
|
|
194
|
+
|
|
195
|
+
[MIT](LICENSE)
|
|
196
|
+
|
|
197
|
+
## Acknowledgments
|
|
198
|
+
|
|
199
|
+
- [CamoFox Browser](https://github.com/jo-inc/camofox-browser) — The anti-detection browser this MCP wraps
|
|
200
|
+
- [Camoufox](https://camoufox.com/) — Firefox-based anti-detection browser engine
|
|
201
|
+
- [Model Context Protocol](https://modelcontextprotocol.io/) — The protocol standard by Anthropic
|
package/dist/client.d.ts
ADDED
|
@@ -0,0 +1,33 @@
|
|
|
1
|
+
import type { ClickParams, ClickResponse, Config, CreateTabParams, HealthResponse, LinkResponse, NavigateResponse, SnapshotResponse, StatsResponse, TabResponse } from "./types.js";
|
|
2
|
+
export declare class CamofoxClient {
|
|
3
|
+
private readonly baseUrl;
|
|
4
|
+
private readonly timeout;
|
|
5
|
+
private readonly apiKey?;
|
|
6
|
+
constructor(config: Config);
|
|
7
|
+
healthCheck(): Promise<HealthResponse>;
|
|
8
|
+
createTab(params: CreateTabParams): Promise<TabResponse>;
|
|
9
|
+
closeTab(tabId: string, userId: string): Promise<void>;
|
|
10
|
+
navigate(tabId: string, url: string, userId: string): Promise<NavigateResponse>;
|
|
11
|
+
navigateMacro(tabId: string, macro: string, query: string, userId: string): Promise<NavigateResponse>;
|
|
12
|
+
goBack(tabId: string, userId: string): Promise<void>;
|
|
13
|
+
goForward(tabId: string, userId: string): Promise<void>;
|
|
14
|
+
refresh(tabId: string, userId: string): Promise<void>;
|
|
15
|
+
click(tabId: string, params: ClickParams, userId: string): Promise<ClickResponse>;
|
|
16
|
+
typeText(tabId: string, locator: {
|
|
17
|
+
ref?: string;
|
|
18
|
+
selector?: string;
|
|
19
|
+
}, text: string, userId: string): Promise<void>;
|
|
20
|
+
pressKey(tabId: string, key: string, userId: string): Promise<void>;
|
|
21
|
+
scroll(tabId: string, direction: string, amount: number | undefined, userId: string): Promise<void>;
|
|
22
|
+
snapshot(tabId: string, userId: string): Promise<SnapshotResponse>;
|
|
23
|
+
screenshot(tabId: string, userId: string): Promise<Buffer>;
|
|
24
|
+
getLinks(tabId: string, userId: string): Promise<LinkResponse>;
|
|
25
|
+
getStats(tabId: string, userId: string): Promise<StatsResponse>;
|
|
26
|
+
importCookies(userId: string, cookies: string): Promise<void>;
|
|
27
|
+
private requestJson;
|
|
28
|
+
private requestBinary;
|
|
29
|
+
private requestNoContent;
|
|
30
|
+
private request;
|
|
31
|
+
private buildHttpError;
|
|
32
|
+
}
|
|
33
|
+
//# sourceMappingURL=client.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"client.d.ts","sourceRoot":"","sources":["../src/client.ts"],"names":[],"mappings":"AACA,OAAO,KAAK,EACV,WAAW,EACX,aAAa,EACb,MAAM,EACN,eAAe,EACf,cAAc,EACd,YAAY,EACZ,gBAAgB,EAChB,gBAAgB,EAChB,aAAa,EACb,WAAW,EACZ,MAAM,YAAY,CAAC;AAOpB,qBAAa,aAAa;IACxB,OAAO,CAAC,QAAQ,CAAC,OAAO,CAAS;IAEjC,OAAO,CAAC,QAAQ,CAAC,OAAO,CAAS;IAEjC,OAAO,CAAC,QAAQ,CAAC,MAAM,CAAC,CAAS;gBAErB,MAAM,EAAE,MAAM;IAMpB,WAAW,IAAI,OAAO,CAAC,cAAc,CAAC;IAItC,SAAS,CAAC,MAAM,EAAE,eAAe,GAAG,OAAO,CAAC,WAAW,CAAC;IAsBxD,QAAQ,CAAC,KAAK,EAAE,MAAM,EAAE,MAAM,EAAE,MAAM,GAAG,OAAO,CAAC,IAAI,CAAC;IAOtD,QAAQ,CAAC,KAAK,EAAE,MAAM,EAAE,GAAG,EAAE,MAAM,EAAE,MAAM,EAAE,MAAM,GAAG,OAAO,CAAC,gBAAgB,CAAC;IAY/E,aAAa,CAAC,KAAK,EAAE,MAAM,EAAE,KAAK,EAAE,MAAM,EAAE,KAAK,EAAE,MAAM,EAAE,MAAM,EAAE,MAAM,GAAG,OAAO,CAAC,gBAAgB,CAAC;IAYrG,MAAM,CAAC,KAAK,EAAE,MAAM,EAAE,MAAM,EAAE,MAAM,GAAG,OAAO,CAAC,IAAI,CAAC;IAOpD,SAAS,CAAC,KAAK,EAAE,MAAM,EAAE,MAAM,EAAE,MAAM,GAAG,OAAO,CAAC,IAAI,CAAC;IAOvD,OAAO,CAAC,KAAK,EAAE,MAAM,EAAE,MAAM,EAAE,MAAM,GAAG,OAAO,CAAC,IAAI,CAAC;IAOrD,KAAK,CAAC,KAAK,EAAE,MAAM,EAAE,MAAM,EAAE,WAAW,EAAE,MAAM,EAAE,MAAM,GAAG,OAAO,CAAC,aAAa,CAAC;IAYjF,QAAQ,CAAC,KAAK,EAAE,MAAM,EAAE,OAAO,EAAE;QAAE,GAAG,CAAC,EAAE,MAAM,CAAC;QAAC,QAAQ,CAAC,EAAE,MAAM,CAAA;KAAE,EAAE,IAAI,EAAE,MAAM,EAAE,MAAM,EAAE,MAAM,GAAG,OAAO,CAAC,IAAI,CAAC;IAOlH,QAAQ,CAAC,KAAK,EAAE,MAAM,EAAE,GAAG,EAAE,MAAM,EAAE,MAAM,EAAE,MAAM,GAAG,OAAO,CAAC,IAAI,CAAC;IAOnE,MAAM,CAAC,KAAK,EAAE,MAAM,EAAE,SAAS,EAAE,MAAM,EAAE,MAAM,EAAE,MAAM,GAAG,SAAS,EAAE,MAAM,EAAE,MAAM,GAAG,OAAO,CAAC,IAAI,CAAC;IAOnG,QAAQ,CAAC,KAAK,EAAE,MAAM,EAAE,MAAM,EAAE,MAAM,GAAG,OAAO,CAAC,gBAAgB,CAAC;IAelE,UAAU,CAAC,KAAK,EAAE,MAAM,EAAE,MAAM,EAAE,MAAM,GAAG,OAAO,CAAC,MAAM,CAAC;IAU1D,QAAQ,CAAC,KAAK,EAAE,MAAM,EAAE,MAAM,EAAE,MAAM,GAAG,OAAO,CAAC,YAAY,CAAC;IAiB9D,QAAQ,CAAC,KAAK,EAAE,MAAM,EAAE,MAAM,EAAE,MAAM,GAAG,OAAO,CAAC,aAAa,CAAC;IAS/D,aAAa,CAAC,MAAM,EAAE,MAAM,EAAE,OAAO,EAAE,MAAM,GAAG,OAAO,CAAC,IAAI,CAAC;YAQrD,WAAW;YAQX,aAAa;YAKb,gBAAgB;YAIhB,OAAO;YAmDP,cAAc;CA2B7B"}
|
package/dist/client.js
ADDED
|
@@ -0,0 +1,224 @@
|
|
|
1
|
+
import { AppError } from "./errors.js";
|
|
2
|
+
export class CamofoxClient {
|
|
3
|
+
baseUrl;
|
|
4
|
+
timeout;
|
|
5
|
+
apiKey;
|
|
6
|
+
constructor(config) {
|
|
7
|
+
this.baseUrl = config.camofoxUrl.replace(/\/$/, "");
|
|
8
|
+
this.timeout = config.timeout;
|
|
9
|
+
this.apiKey = config.apiKey;
|
|
10
|
+
}
|
|
11
|
+
async healthCheck() {
|
|
12
|
+
return this.requestJson("/health", { method: "GET" });
|
|
13
|
+
}
|
|
14
|
+
async createTab(params) {
|
|
15
|
+
const response = await this.requestJson("/tabs", {
|
|
16
|
+
method: "POST",
|
|
17
|
+
body: JSON.stringify(params)
|
|
18
|
+
});
|
|
19
|
+
const tabId = response.tabId ??
|
|
20
|
+
response.id ??
|
|
21
|
+
(response.tab?.id ?? undefined);
|
|
22
|
+
if (!tabId) {
|
|
23
|
+
throw new AppError("INTERNAL_ERROR", "CamoFox did not return a valid tab ID");
|
|
24
|
+
}
|
|
25
|
+
return {
|
|
26
|
+
tabId,
|
|
27
|
+
url: response.url ?? params.url ?? "about:blank",
|
|
28
|
+
title: response.title
|
|
29
|
+
};
|
|
30
|
+
}
|
|
31
|
+
async closeTab(tabId, userId) {
|
|
32
|
+
await this.requestNoContent(`/tabs/${encodeURIComponent(tabId)}`, {
|
|
33
|
+
method: "DELETE",
|
|
34
|
+
body: JSON.stringify({ userId })
|
|
35
|
+
});
|
|
36
|
+
}
|
|
37
|
+
async navigate(tabId, url, userId) {
|
|
38
|
+
const response = await this.requestJson(`/tabs/${encodeURIComponent(tabId)}/navigate`, {
|
|
39
|
+
method: "POST",
|
|
40
|
+
body: JSON.stringify({ url, userId })
|
|
41
|
+
});
|
|
42
|
+
return {
|
|
43
|
+
url: response.url ?? url,
|
|
44
|
+
title: response.title
|
|
45
|
+
};
|
|
46
|
+
}
|
|
47
|
+
async navigateMacro(tabId, macro, query, userId) {
|
|
48
|
+
const response = await this.requestJson(`/tabs/${encodeURIComponent(tabId)}/navigate`, {
|
|
49
|
+
method: "POST",
|
|
50
|
+
body: JSON.stringify({ macro, query, userId })
|
|
51
|
+
});
|
|
52
|
+
return {
|
|
53
|
+
url: response.url ?? "",
|
|
54
|
+
title: response.title
|
|
55
|
+
};
|
|
56
|
+
}
|
|
57
|
+
async goBack(tabId, userId) {
|
|
58
|
+
await this.requestNoContent(`/tabs/${encodeURIComponent(tabId)}/back`, {
|
|
59
|
+
method: "POST",
|
|
60
|
+
body: JSON.stringify({ userId })
|
|
61
|
+
});
|
|
62
|
+
}
|
|
63
|
+
async goForward(tabId, userId) {
|
|
64
|
+
await this.requestNoContent(`/tabs/${encodeURIComponent(tabId)}/forward`, {
|
|
65
|
+
method: "POST",
|
|
66
|
+
body: JSON.stringify({ userId })
|
|
67
|
+
});
|
|
68
|
+
}
|
|
69
|
+
async refresh(tabId, userId) {
|
|
70
|
+
await this.requestNoContent(`/tabs/${encodeURIComponent(tabId)}/refresh`, {
|
|
71
|
+
method: "POST",
|
|
72
|
+
body: JSON.stringify({ userId })
|
|
73
|
+
});
|
|
74
|
+
}
|
|
75
|
+
async click(tabId, params, userId) {
|
|
76
|
+
const response = await this.requestJson(`/tabs/${encodeURIComponent(tabId)}/click`, {
|
|
77
|
+
method: "POST",
|
|
78
|
+
body: JSON.stringify({ ...params, userId })
|
|
79
|
+
});
|
|
80
|
+
return {
|
|
81
|
+
success: response.success ?? true,
|
|
82
|
+
navigated: response.navigated
|
|
83
|
+
};
|
|
84
|
+
}
|
|
85
|
+
async typeText(tabId, locator, text, userId) {
|
|
86
|
+
await this.requestNoContent(`/tabs/${encodeURIComponent(tabId)}/type`, {
|
|
87
|
+
method: "POST",
|
|
88
|
+
body: JSON.stringify({ ...locator, text, userId })
|
|
89
|
+
});
|
|
90
|
+
}
|
|
91
|
+
async pressKey(tabId, key, userId) {
|
|
92
|
+
await this.requestNoContent(`/tabs/${encodeURIComponent(tabId)}/press`, {
|
|
93
|
+
method: "POST",
|
|
94
|
+
body: JSON.stringify({ key, userId })
|
|
95
|
+
});
|
|
96
|
+
}
|
|
97
|
+
async scroll(tabId, direction, amount, userId) {
|
|
98
|
+
await this.requestNoContent(`/tabs/${encodeURIComponent(tabId)}/scroll`, {
|
|
99
|
+
method: "POST",
|
|
100
|
+
body: JSON.stringify({ direction, amount, userId })
|
|
101
|
+
});
|
|
102
|
+
}
|
|
103
|
+
async snapshot(tabId, userId) {
|
|
104
|
+
const response = await this.requestJson(`/tabs/${encodeURIComponent(tabId)}/snapshot?userId=${encodeURIComponent(userId)}`, {
|
|
105
|
+
method: "GET"
|
|
106
|
+
});
|
|
107
|
+
return {
|
|
108
|
+
url: response.url ?? "",
|
|
109
|
+
snapshot: response.snapshot ?? "",
|
|
110
|
+
refsCount: response.refsCount ?? 0
|
|
111
|
+
};
|
|
112
|
+
}
|
|
113
|
+
async screenshot(tabId, userId) {
|
|
114
|
+
const binary = await this.requestBinary(`/tabs/${encodeURIComponent(tabId)}/screenshot?userId=${encodeURIComponent(userId)}`, {
|
|
115
|
+
method: "GET"
|
|
116
|
+
});
|
|
117
|
+
return Buffer.from(binary);
|
|
118
|
+
}
|
|
119
|
+
async getLinks(tabId, userId) {
|
|
120
|
+
const response = await this.requestJson(`/tabs/${encodeURIComponent(tabId)}/links?userId=${encodeURIComponent(userId)}`, {
|
|
121
|
+
method: "GET"
|
|
122
|
+
});
|
|
123
|
+
const links = Array.isArray(response.links) ? response.links : [];
|
|
124
|
+
return {
|
|
125
|
+
links: links.map((item) => ({
|
|
126
|
+
text: String(item.text ?? ""),
|
|
127
|
+
href: String(item.href ?? "")
|
|
128
|
+
}))
|
|
129
|
+
};
|
|
130
|
+
}
|
|
131
|
+
async getStats(tabId, userId) {
|
|
132
|
+
return this.requestJson(`/tabs/${encodeURIComponent(tabId)}/stats?userId=${encodeURIComponent(userId)}`, {
|
|
133
|
+
method: "GET"
|
|
134
|
+
});
|
|
135
|
+
}
|
|
136
|
+
async importCookies(userId, cookies) {
|
|
137
|
+
await this.requestNoContent(`/sessions/${encodeURIComponent(userId)}/cookies`, {
|
|
138
|
+
method: "POST",
|
|
139
|
+
body: JSON.stringify({ cookies }),
|
|
140
|
+
requireApiKey: true
|
|
141
|
+
});
|
|
142
|
+
}
|
|
143
|
+
async requestJson(path, init) {
|
|
144
|
+
const response = await this.request(path, init);
|
|
145
|
+
if (response.status === 204) {
|
|
146
|
+
return {};
|
|
147
|
+
}
|
|
148
|
+
return (await response.json());
|
|
149
|
+
}
|
|
150
|
+
async requestBinary(path, init) {
|
|
151
|
+
const response = await this.request(path, init);
|
|
152
|
+
return response.arrayBuffer();
|
|
153
|
+
}
|
|
154
|
+
async requestNoContent(path, init) {
|
|
155
|
+
await this.request(path, init);
|
|
156
|
+
}
|
|
157
|
+
async request(path, init) {
|
|
158
|
+
const controller = new AbortController();
|
|
159
|
+
const timer = setTimeout(() => controller.abort(), this.timeout);
|
|
160
|
+
try {
|
|
161
|
+
if (init.requireApiKey && !this.apiKey) {
|
|
162
|
+
throw new AppError("API_KEY_REQUIRED", "CAMOFOX_API_KEY is required for this operation");
|
|
163
|
+
}
|
|
164
|
+
const headers = {
|
|
165
|
+
"content-type": "application/json"
|
|
166
|
+
};
|
|
167
|
+
if (this.apiKey) {
|
|
168
|
+
headers["x-api-key"] = this.apiKey;
|
|
169
|
+
headers.authorization = `Bearer ${this.apiKey}`;
|
|
170
|
+
}
|
|
171
|
+
const response = await fetch(`${this.baseUrl}${path}`, {
|
|
172
|
+
...init,
|
|
173
|
+
headers: {
|
|
174
|
+
...headers,
|
|
175
|
+
...init.headers
|
|
176
|
+
},
|
|
177
|
+
signal: controller.signal
|
|
178
|
+
});
|
|
179
|
+
if (!response.ok) {
|
|
180
|
+
throw await this.buildHttpError(response);
|
|
181
|
+
}
|
|
182
|
+
return response;
|
|
183
|
+
}
|
|
184
|
+
catch (error) {
|
|
185
|
+
if (error instanceof AppError) {
|
|
186
|
+
throw error;
|
|
187
|
+
}
|
|
188
|
+
if (error instanceof DOMException && error.name === "AbortError") {
|
|
189
|
+
throw new AppError("TIMEOUT", `CamoFox API request timed out after ${this.timeout}ms`);
|
|
190
|
+
}
|
|
191
|
+
if (error instanceof Error) {
|
|
192
|
+
throw new AppError("CONNECTION_REFUSED", `Failed to connect to CamoFox API: ${error.message}`);
|
|
193
|
+
}
|
|
194
|
+
throw new AppError("INTERNAL_ERROR", "Unknown error while calling CamoFox API");
|
|
195
|
+
}
|
|
196
|
+
finally {
|
|
197
|
+
clearTimeout(timer);
|
|
198
|
+
}
|
|
199
|
+
}
|
|
200
|
+
async buildHttpError(response) {
|
|
201
|
+
let message = `CamoFox API request failed with ${response.status}`;
|
|
202
|
+
const rawBody = await response.text();
|
|
203
|
+
if (rawBody) {
|
|
204
|
+
try {
|
|
205
|
+
const body = JSON.parse(rawBody);
|
|
206
|
+
message = body.error ?? body.message ?? rawBody;
|
|
207
|
+
}
|
|
208
|
+
catch {
|
|
209
|
+
message = rawBody;
|
|
210
|
+
}
|
|
211
|
+
}
|
|
212
|
+
if (response.status === 404) {
|
|
213
|
+
return new AppError("TAB_NOT_FOUND", message, response.status);
|
|
214
|
+
}
|
|
215
|
+
if (response.status === 400 && /element|ref|selector/i.test(message)) {
|
|
216
|
+
return new AppError("ELEMENT_NOT_FOUND", message, response.status);
|
|
217
|
+
}
|
|
218
|
+
if (response.status >= 500) {
|
|
219
|
+
return new AppError("NAVIGATION_FAILED", message, response.status);
|
|
220
|
+
}
|
|
221
|
+
return new AppError("INTERNAL_ERROR", message, response.status);
|
|
222
|
+
}
|
|
223
|
+
}
|
|
224
|
+
//# sourceMappingURL=client.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"client.js","sourceRoot":"","sources":["../src/client.ts"],"names":[],"mappings":"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"}
|
package/dist/config.d.ts
ADDED
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"config.d.ts","sourceRoot":"","sources":["../src/config.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,KAAK,MAAM,EAAE,MAAM,YAAY,CAAC;AA8CzC,wBAAgB,UAAU,CAAC,IAAI,WAAwB,EAAE,GAAG,oBAAc,GAAG,MAAM,CAUlF"}
|
package/dist/config.js
ADDED
|
@@ -0,0 +1,41 @@
|
|
|
1
|
+
function parseCliArgs(argv) {
|
|
2
|
+
const args = {};
|
|
3
|
+
for (let i = 0; i < argv.length; i += 1) {
|
|
4
|
+
const current = argv[i];
|
|
5
|
+
const next = argv[i + 1];
|
|
6
|
+
if ((current === "--camofox-url" || current === "--url") && next) {
|
|
7
|
+
args.camofoxUrl = next;
|
|
8
|
+
i += 1;
|
|
9
|
+
continue;
|
|
10
|
+
}
|
|
11
|
+
if ((current === "--api-key" || current === "--key") && next) {
|
|
12
|
+
args.apiKey = next;
|
|
13
|
+
i += 1;
|
|
14
|
+
continue;
|
|
15
|
+
}
|
|
16
|
+
if ((current === "--default-user-id" || current === "--user-id") && next) {
|
|
17
|
+
args.defaultUserId = next;
|
|
18
|
+
i += 1;
|
|
19
|
+
continue;
|
|
20
|
+
}
|
|
21
|
+
if (current === "--timeout" && next) {
|
|
22
|
+
const timeout = Number.parseInt(next, 10);
|
|
23
|
+
if (!Number.isNaN(timeout) && timeout > 0) {
|
|
24
|
+
args.timeout = timeout;
|
|
25
|
+
}
|
|
26
|
+
i += 1;
|
|
27
|
+
}
|
|
28
|
+
}
|
|
29
|
+
return args;
|
|
30
|
+
}
|
|
31
|
+
export function loadConfig(argv = process.argv.slice(2), env = process.env) {
|
|
32
|
+
const cli = parseCliArgs(argv);
|
|
33
|
+
const timeoutFromEnv = Number.parseInt(env.CAMOFOX_TIMEOUT ?? "", 10);
|
|
34
|
+
return {
|
|
35
|
+
camofoxUrl: cli.camofoxUrl ?? env.CAMOFOX_URL ?? "http://localhost:9377",
|
|
36
|
+
apiKey: cli.apiKey ?? env.CAMOFOX_API_KEY,
|
|
37
|
+
defaultUserId: cli.defaultUserId ?? env.CAMOFOX_DEFAULT_USER_ID ?? "default",
|
|
38
|
+
timeout: cli.timeout ?? (Number.isNaN(timeoutFromEnv) ? 30_000 : timeoutFromEnv)
|
|
39
|
+
};
|
|
40
|
+
}
|
|
41
|
+
//# sourceMappingURL=config.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"config.js","sourceRoot":"","sources":["../src/config.ts"],"names":[],"mappings":"AASA,SAAS,YAAY,CAAC,IAAc;IAClC,MAAM,IAAI,GAAY,EAAE,CAAC;IAEzB,KAAK,IAAI,CAAC,GAAG,CAAC,EAAE,CAAC,GAAG,IAAI,CAAC,MAAM,EAAE,CAAC,IAAI,CAAC,EAAE,CAAC;QACxC,MAAM,OAAO,GAAG,IAAI,CAAC,CAAC,CAAC,CAAC;QACxB,MAAM,IAAI,GAAG,IAAI,CAAC,CAAC,GAAG,CAAC,CAAC,CAAC;QAEzB,IAAI,CAAC,OAAO,KAAK,eAAe,IAAI,OAAO,KAAK,OAAO,CAAC,IAAI,IAAI,EAAE,CAAC;YACjE,IAAI,CAAC,UAAU,GAAG,IAAI,CAAC;YACvB,CAAC,IAAI,CAAC,CAAC;YACP,SAAS;QACX,CAAC;QAED,IAAI,CAAC,OAAO,KAAK,WAAW,IAAI,OAAO,KAAK,OAAO,CAAC,IAAI,IAAI,EAAE,CAAC;YAC7D,IAAI,CAAC,MAAM,GAAG,IAAI,CAAC;YACnB,CAAC,IAAI,CAAC,CAAC;YACP,SAAS;QACX,CAAC;QAED,IAAI,CAAC,OAAO,KAAK,mBAAmB,IAAI,OAAO,KAAK,WAAW,CAAC,IAAI,IAAI,EAAE,CAAC;YACzE,IAAI,CAAC,aAAa,GAAG,IAAI,CAAC;YAC1B,CAAC,IAAI,CAAC,CAAC;YACP,SAAS;QACX,CAAC;QAED,IAAI,OAAO,KAAK,WAAW,IAAI,IAAI,EAAE,CAAC;YACpC,MAAM,OAAO,GAAG,MAAM,CAAC,QAAQ,CAAC,IAAI,EAAE,EAAE,CAAC,CAAC;YAC1C,IAAI,CAAC,MAAM,CAAC,KAAK,CAAC,OAAO,CAAC,IAAI,OAAO,GAAG,CAAC,EAAE,CAAC;gBAC1C,IAAI,CAAC,OAAO,GAAG,OAAO,CAAC;YACzB,CAAC;YACD,CAAC,IAAI,CAAC,CAAC;QACT,CAAC;IACH,CAAC;IAED,OAAO,IAAI,CAAC;AACd,CAAC;AAED,MAAM,UAAU,UAAU,CAAC,IAAI,GAAG,OAAO,CAAC,IAAI,CAAC,KAAK,CAAC,CAAC,CAAC,EAAE,GAAG,GAAG,OAAO,CAAC,GAAG;IACxE,MAAM,GAAG,GAAG,YAAY,CAAC,IAAI,CAAC,CAAC;IAC/B,MAAM,cAAc,GAAG,MAAM,CAAC,QAAQ,CAAC,GAAG,CAAC,eAAe,IAAI,EAAE,EAAE,EAAE,CAAC,CAAC;IAEtE,OAAO;QACL,UAAU,EAAE,GAAG,CAAC,UAAU,IAAI,GAAG,CAAC,WAAW,IAAI,uBAAuB;QACxE,MAAM,EAAE,GAAG,CAAC,MAAM,IAAI,GAAG,CAAC,eAAe;QACzC,aAAa,EAAE,GAAG,CAAC,aAAa,IAAI,GAAG,CAAC,uBAAuB,IAAI,SAAS;QAC5E,OAAO,EAAE,GAAG,CAAC,OAAO,IAAI,CAAC,MAAM,CAAC,KAAK,CAAC,cAAc,CAAC,CAAC,CAAC,CAAC,MAAM,CAAC,CAAC,CAAC,cAAc,CAAC;KACjF,CAAC;AACJ,CAAC"}
|
package/dist/errors.d.ts
ADDED
|
@@ -0,0 +1,23 @@
|
|
|
1
|
+
export type ErrorCode = "CONNECTION_REFUSED" | "TAB_NOT_FOUND" | "ELEMENT_NOT_FOUND" | "NAVIGATION_FAILED" | "API_KEY_REQUIRED" | "TIMEOUT" | "VALIDATION_ERROR" | "INTERNAL_ERROR";
|
|
2
|
+
export declare class AppError extends Error {
|
|
3
|
+
readonly code: ErrorCode;
|
|
4
|
+
readonly status?: number;
|
|
5
|
+
constructor(code: ErrorCode, message: string, status?: number);
|
|
6
|
+
}
|
|
7
|
+
export interface ToolResult {
|
|
8
|
+
[key: string]: unknown;
|
|
9
|
+
isError?: boolean;
|
|
10
|
+
content: Array<{
|
|
11
|
+
type: "text";
|
|
12
|
+
text: string;
|
|
13
|
+
} | {
|
|
14
|
+
type: "image";
|
|
15
|
+
data: string;
|
|
16
|
+
mimeType: string;
|
|
17
|
+
}>;
|
|
18
|
+
}
|
|
19
|
+
export declare function okResult(data: unknown): ToolResult;
|
|
20
|
+
export declare function imageResult(base64Png: string): ToolResult;
|
|
21
|
+
export declare function normalizeError(error: unknown): AppError;
|
|
22
|
+
export declare function toErrorResult(error: unknown): ToolResult;
|
|
23
|
+
//# sourceMappingURL=errors.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"errors.d.ts","sourceRoot":"","sources":["../src/errors.ts"],"names":[],"mappings":"AAEA,MAAM,MAAM,SAAS,GACjB,oBAAoB,GACpB,eAAe,GACf,mBAAmB,GACnB,mBAAmB,GACnB,kBAAkB,GAClB,SAAS,GACT,kBAAkB,GAClB,gBAAgB,CAAC;AAErB,qBAAa,QAAS,SAAQ,KAAK;IACjC,SAAgB,IAAI,EAAE,SAAS,CAAC;IAEhC,SAAgB,MAAM,CAAC,EAAE,MAAM,CAAC;gBAEpB,IAAI,EAAE,SAAS,EAAE,OAAO,EAAE,MAAM,EAAE,MAAM,CAAC,EAAE,MAAM;CAM9D;AAED,MAAM,WAAW,UAAU;IACzB,CAAC,GAAG,EAAE,MAAM,GAAG,OAAO,CAAC;IACvB,OAAO,CAAC,EAAE,OAAO,CAAC;IAClB,OAAO,EAAE,KAAK,CACV;QACE,IAAI,EAAE,MAAM,CAAC;QACb,IAAI,EAAE,MAAM,CAAC;KACd,GACD;QACE,IAAI,EAAE,OAAO,CAAC;QACd,IAAI,EAAE,MAAM,CAAC;QACb,QAAQ,EAAE,MAAM,CAAC;KAClB,CACJ,CAAC;CACH;AAED,wBAAgB,QAAQ,CAAC,IAAI,EAAE,OAAO,GAAG,UAAU,CAIlD;AAED,wBAAgB,WAAW,CAAC,SAAS,EAAE,MAAM,GAAG,UAAU,CAIzD;AAED,wBAAgB,cAAc,CAAC,KAAK,EAAE,OAAO,GAAG,QAAQ,CAcvD;AAED,wBAAgB,aAAa,CAAC,KAAK,EAAE,OAAO,GAAG,UAAU,CAYxD"}
|
package/dist/errors.js
ADDED
|
@@ -0,0 +1,46 @@
|
|
|
1
|
+
import { ZodError } from "zod";
|
|
2
|
+
export class AppError extends Error {
|
|
3
|
+
code;
|
|
4
|
+
status;
|
|
5
|
+
constructor(code, message, status) {
|
|
6
|
+
super(message);
|
|
7
|
+
this.name = "AppError";
|
|
8
|
+
this.code = code;
|
|
9
|
+
this.status = status;
|
|
10
|
+
}
|
|
11
|
+
}
|
|
12
|
+
export function okResult(data) {
|
|
13
|
+
return {
|
|
14
|
+
content: [{ type: "text", text: JSON.stringify(data) }]
|
|
15
|
+
};
|
|
16
|
+
}
|
|
17
|
+
export function imageResult(base64Png) {
|
|
18
|
+
return {
|
|
19
|
+
content: [{ type: "image", data: base64Png, mimeType: "image/png" }]
|
|
20
|
+
};
|
|
21
|
+
}
|
|
22
|
+
export function normalizeError(error) {
|
|
23
|
+
if (error instanceof AppError) {
|
|
24
|
+
return error;
|
|
25
|
+
}
|
|
26
|
+
if (error instanceof ZodError) {
|
|
27
|
+
return new AppError("VALIDATION_ERROR", error.issues.map((issue) => issue.message).join(", "));
|
|
28
|
+
}
|
|
29
|
+
if (error instanceof Error) {
|
|
30
|
+
return new AppError("INTERNAL_ERROR", error.message);
|
|
31
|
+
}
|
|
32
|
+
return new AppError("INTERNAL_ERROR", "An unknown internal error occurred");
|
|
33
|
+
}
|
|
34
|
+
export function toErrorResult(error) {
|
|
35
|
+
const appError = normalizeError(error);
|
|
36
|
+
const payload = {
|
|
37
|
+
isError: true,
|
|
38
|
+
code: appError.code,
|
|
39
|
+
message: appError.message
|
|
40
|
+
};
|
|
41
|
+
return {
|
|
42
|
+
isError: true,
|
|
43
|
+
content: [{ type: "text", text: JSON.stringify(payload) }]
|
|
44
|
+
};
|
|
45
|
+
}
|
|
46
|
+
//# sourceMappingURL=errors.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"errors.js","sourceRoot":"","sources":["../src/errors.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,QAAQ,EAAE,MAAM,KAAK,CAAC;AAY/B,MAAM,OAAO,QAAS,SAAQ,KAAK;IACjB,IAAI,CAAY;IAEhB,MAAM,CAAU;IAEhC,YAAY,IAAe,EAAE,OAAe,EAAE,MAAe;QAC3D,KAAK,CAAC,OAAO,CAAC,CAAC;QACf,IAAI,CAAC,IAAI,GAAG,UAAU,CAAC;QACvB,IAAI,CAAC,IAAI,GAAG,IAAI,CAAC;QACjB,IAAI,CAAC,MAAM,GAAG,MAAM,CAAC;IACvB,CAAC;CACF;AAkBD,MAAM,UAAU,QAAQ,CAAC,IAAa;IACpC,OAAO;QACL,OAAO,EAAE,CAAC,EAAE,IAAI,EAAE,MAAM,EAAE,IAAI,EAAE,IAAI,CAAC,SAAS,CAAC,IAAI,CAAC,EAAE,CAAC;KACxD,CAAC;AACJ,CAAC;AAED,MAAM,UAAU,WAAW,CAAC,SAAiB;IAC3C,OAAO;QACL,OAAO,EAAE,CAAC,EAAE,IAAI,EAAE,OAAO,EAAE,IAAI,EAAE,SAAS,EAAE,QAAQ,EAAE,WAAW,EAAE,CAAC;KACrE,CAAC;AACJ,CAAC;AAED,MAAM,UAAU,cAAc,CAAC,KAAc;IAC3C,IAAI,KAAK,YAAY,QAAQ,EAAE,CAAC;QAC9B,OAAO,KAAK,CAAC;IACf,CAAC;IAED,IAAI,KAAK,YAAY,QAAQ,EAAE,CAAC;QAC9B,OAAO,IAAI,QAAQ,CAAC,kBAAkB,EAAE,KAAK,CAAC,MAAM,CAAC,GAAG,CAAC,CAAC,KAAK,EAAE,EAAE,CAAC,KAAK,CAAC,OAAO,CAAC,CAAC,IAAI,CAAC,IAAI,CAAC,CAAC,CAAC;IACjG,CAAC;IAED,IAAI,KAAK,YAAY,KAAK,EAAE,CAAC;QAC3B,OAAO,IAAI,QAAQ,CAAC,gBAAgB,EAAE,KAAK,CAAC,OAAO,CAAC,CAAC;IACvD,CAAC;IAED,OAAO,IAAI,QAAQ,CAAC,gBAAgB,EAAE,oCAAoC,CAAC,CAAC;AAC9E,CAAC;AAED,MAAM,UAAU,aAAa,CAAC,KAAc;IAC1C,MAAM,QAAQ,GAAG,cAAc,CAAC,KAAK,CAAC,CAAC;IACvC,MAAM,OAAO,GAAG;QACd,OAAO,EAAE,IAAI;QACb,IAAI,EAAE,QAAQ,CAAC,IAAI;QACnB,OAAO,EAAE,QAAQ,CAAC,OAAO;KAC1B,CAAC;IAEF,OAAO;QACL,OAAO,EAAE,IAAI;QACb,OAAO,EAAE,CAAC,EAAE,IAAI,EAAE,MAAM,EAAE,IAAI,EAAE,IAAI,CAAC,SAAS,CAAC,OAAO,CAAC,EAAE,CAAC;KAC3D,CAAC;AACJ,CAAC"}
|
package/dist/index.d.ts
ADDED
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":""}
|