@apitap/core 1.1.0 → 1.2.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/README.md +38 -2
- package/dist/bridge/client.d.ts +19 -0
- package/dist/bridge/client.js +52 -0
- package/dist/bridge/client.js.map +1 -0
- package/dist/native-host.d.ts +5 -1
- package/dist/native-host.js +107 -3
- package/dist/native-host.js.map +1 -1
- package/dist/orchestration/browse.d.ts +5 -1
- package/dist/orchestration/browse.js +109 -0
- package/dist/orchestration/browse.js.map +1 -1
- package/package.json +1 -1
- package/src/bridge/client.ts +67 -0
- package/src/native-host.ts +141 -4
- package/src/orchestration/browse.ts +122 -1
package/README.md
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
# ApiTap
|
|
2
2
|
|
|
3
3
|
[](https://www.npmjs.com/package/@apitap/core)
|
|
4
|
-
[](https://github.com/n1byn1kt/apitap)
|
|
5
5
|
[](./LICENSE)
|
|
6
6
|
|
|
7
7
|
**The MCP server that turns any website into an API — no docs, no SDK, no browser.**
|
|
@@ -238,6 +238,42 @@ apitap-mcp
|
|
|
238
238
|
|
|
239
239
|
You can also serve a single skill file as a dedicated MCP server with `apitap serve <domain>` — each endpoint becomes its own tool.
|
|
240
240
|
|
|
241
|
+
## Chrome Extension
|
|
242
|
+
|
|
243
|
+
ApiTap includes a Chrome extension that captures API traffic directly from your already-logged-in browser — no Playwright, no auth dance, no browser popups.
|
|
244
|
+
|
|
245
|
+
**Why use the extension?**
|
|
246
|
+
- You're already logged into Spotify, Discord, Reddit — the extension captures from your live session
|
|
247
|
+
- No `apitap auth request` needed — real tokens are captured automatically
|
|
248
|
+
- Browse naturally while it records in the background
|
|
249
|
+
|
|
250
|
+
### Setup
|
|
251
|
+
|
|
252
|
+
1. Build the extension:
|
|
253
|
+
```bash
|
|
254
|
+
cd extension && npm install && npm run build
|
|
255
|
+
```
|
|
256
|
+
|
|
257
|
+
2. Load in Chrome: `chrome://extensions` → Enable Developer mode → Load unpacked → select the `extension/` folder
|
|
258
|
+
|
|
259
|
+
3. Wire up auto-save (one-time):
|
|
260
|
+
```bash
|
|
261
|
+
apitap extension install --extension-id <your-extension-id>
|
|
262
|
+
```
|
|
263
|
+
Find your extension ID at `chrome://extensions` (enable Developer mode).
|
|
264
|
+
|
|
265
|
+
### Usage
|
|
266
|
+
|
|
267
|
+
1. Click the ApiTap icon in Chrome → **Start Capture**
|
|
268
|
+
2. Browse normally — extension records all API traffic
|
|
269
|
+
3. Click **Stop** → skill files auto-save to `~/.apitap/skills/`
|
|
270
|
+
|
|
271
|
+
The popup shows CLI connection status and live capture stats. Auth tokens are automatically stored to `~/.apitap/auth.enc` with `[stored]` placeholders in the exported skill files.
|
|
272
|
+
|
|
273
|
+
> **Note:** Chrome Web Store submission coming soon. For now, load as an unpacked extension in Developer mode.
|
|
274
|
+
|
|
275
|
+
---
|
|
276
|
+
|
|
241
277
|
## Auth Management
|
|
242
278
|
|
|
243
279
|
ApiTap automatically detects and stores auth credentials (Bearer tokens, API keys, cookies) during capture. Credentials are encrypted at rest with AES-256-GCM.
|
|
@@ -378,7 +414,7 @@ All commands support `--json` for machine-readable output.
|
|
|
378
414
|
git clone https://github.com/n1byn1kt/apitap.git
|
|
379
415
|
cd apitap
|
|
380
416
|
npm install
|
|
381
|
-
npm test #
|
|
417
|
+
npm test # 925 tests, Node built-in test runner
|
|
382
418
|
npm run typecheck # Type checking
|
|
383
419
|
npm run build # Compile to dist/
|
|
384
420
|
npx tsx src/cli.ts capture <url> # Run from source
|
|
@@ -0,0 +1,19 @@
|
|
|
1
|
+
export declare const DEFAULT_SOCKET: string;
|
|
2
|
+
export interface BridgeCaptureResult {
|
|
3
|
+
success: boolean;
|
|
4
|
+
skillFiles?: any[];
|
|
5
|
+
error?: string;
|
|
6
|
+
}
|
|
7
|
+
/**
|
|
8
|
+
* Fast check: does the bridge socket exist?
|
|
9
|
+
* Returns false if the file doesn't exist (costs ~0.1ms).
|
|
10
|
+
* Returns true if the file exists (doesn't verify it's connectable).
|
|
11
|
+
*/
|
|
12
|
+
export declare function bridgeAvailable(socketPath?: string): Promise<boolean>;
|
|
13
|
+
/**
|
|
14
|
+
* Send a capture_request to the extension via the native host bridge.
|
|
15
|
+
* Returns skill files on success, or a structured error.
|
|
16
|
+
*/
|
|
17
|
+
export declare function requestBridgeCapture(domain: string, socketPath?: string, options?: {
|
|
18
|
+
timeout?: number;
|
|
19
|
+
}): Promise<BridgeCaptureResult>;
|
|
@@ -0,0 +1,52 @@
|
|
|
1
|
+
import net from 'node:net';
|
|
2
|
+
import { promises as fs } from 'node:fs';
|
|
3
|
+
import path from 'node:path';
|
|
4
|
+
import os from 'node:os';
|
|
5
|
+
export const DEFAULT_SOCKET = path.join(os.homedir(), '.apitap', 'bridge.sock');
|
|
6
|
+
/**
|
|
7
|
+
* Fast check: does the bridge socket exist?
|
|
8
|
+
* Returns false if the file doesn't exist (costs ~0.1ms).
|
|
9
|
+
* Returns true if the file exists (doesn't verify it's connectable).
|
|
10
|
+
*/
|
|
11
|
+
export async function bridgeAvailable(socketPath = DEFAULT_SOCKET) {
|
|
12
|
+
try {
|
|
13
|
+
await fs.access(socketPath);
|
|
14
|
+
return true;
|
|
15
|
+
}
|
|
16
|
+
catch {
|
|
17
|
+
return false;
|
|
18
|
+
}
|
|
19
|
+
}
|
|
20
|
+
/**
|
|
21
|
+
* Send a capture_request to the extension via the native host bridge.
|
|
22
|
+
* Returns skill files on success, or a structured error.
|
|
23
|
+
*/
|
|
24
|
+
export async function requestBridgeCapture(domain, socketPath = DEFAULT_SOCKET, options = {}) {
|
|
25
|
+
const timeout = options.timeout ?? 120_000; // 2 minutes (capture can take time)
|
|
26
|
+
return new Promise((resolve) => {
|
|
27
|
+
const timer = setTimeout(() => {
|
|
28
|
+
client.destroy();
|
|
29
|
+
resolve({ success: false, error: 'timeout' });
|
|
30
|
+
}, timeout);
|
|
31
|
+
const client = net.createConnection(socketPath, () => {
|
|
32
|
+
const message = JSON.stringify({ action: 'capture_request', domain }) + '\n';
|
|
33
|
+
client.write(message);
|
|
34
|
+
});
|
|
35
|
+
let data = '';
|
|
36
|
+
client.on('data', (chunk) => { data += chunk.toString(); });
|
|
37
|
+
client.on('end', () => {
|
|
38
|
+
clearTimeout(timer);
|
|
39
|
+
try {
|
|
40
|
+
resolve(JSON.parse(data));
|
|
41
|
+
}
|
|
42
|
+
catch {
|
|
43
|
+
resolve({ success: false, error: 'invalid response from bridge' });
|
|
44
|
+
}
|
|
45
|
+
});
|
|
46
|
+
client.on('error', (err) => {
|
|
47
|
+
clearTimeout(timer);
|
|
48
|
+
resolve({ success: false, error: `bridge connection failed: ${err.message}` });
|
|
49
|
+
});
|
|
50
|
+
});
|
|
51
|
+
}
|
|
52
|
+
//# sourceMappingURL=client.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"client.js","sourceRoot":"","sources":["../../src/bridge/client.ts"],"names":[],"mappings":"AAAA,OAAO,GAAG,MAAM,UAAU,CAAC;AAC3B,OAAO,EAAE,QAAQ,IAAI,EAAE,EAAE,MAAM,SAAS,CAAC;AACzC,OAAO,IAAI,MAAM,WAAW,CAAC;AAC7B,OAAO,EAAE,MAAM,SAAS,CAAC;AAEzB,MAAM,CAAC,MAAM,cAAc,GAAG,IAAI,CAAC,IAAI,CAAC,EAAE,CAAC,OAAO,EAAE,EAAE,SAAS,EAAE,aAAa,CAAC,CAAC;AAQhF;;;;GAIG;AACH,MAAM,CAAC,KAAK,UAAU,eAAe,CAAC,aAAqB,cAAc;IACvE,IAAI,CAAC;QACH,MAAM,EAAE,CAAC,MAAM,CAAC,UAAU,CAAC,CAAC;QAC5B,OAAO,IAAI,CAAC;IACd,CAAC;IAAC,MAAM,CAAC;QACP,OAAO,KAAK,CAAC;IACf,CAAC;AACH,CAAC;AAED;;;GAGG;AACH,MAAM,CAAC,KAAK,UAAU,oBAAoB,CACxC,MAAc,EACd,aAAqB,cAAc,EACnC,UAAgC,EAAE;IAElC,MAAM,OAAO,GAAG,OAAO,CAAC,OAAO,IAAI,OAAO,CAAC,CAAC,oCAAoC;IAEhF,OAAO,IAAI,OAAO,CAAC,CAAC,OAAO,EAAE,EAAE;QAC7B,MAAM,KAAK,GAAG,UAAU,CAAC,GAAG,EAAE;YAC5B,MAAM,CAAC,OAAO,EAAE,CAAC;YACjB,OAAO,CAAC,EAAE,OAAO,EAAE,KAAK,EAAE,KAAK,EAAE,SAAS,EAAE,CAAC,CAAC;QAChD,CAAC,EAAE,OAAO,CAAC,CAAC;QAEZ,MAAM,MAAM,GAAG,GAAG,CAAC,gBAAgB,CAAC,UAAU,EAAE,GAAG,EAAE;YACnD,MAAM,OAAO,GAAG,IAAI,CAAC,SAAS,CAAC,EAAE,MAAM,EAAE,iBAAiB,EAAE,MAAM,EAAE,CAAC,GAAG,IAAI,CAAC;YAC7E,MAAM,CAAC,KAAK,CAAC,OAAO,CAAC,CAAC;QACxB,CAAC,CAAC,CAAC;QAEH,IAAI,IAAI,GAAG,EAAE,CAAC;QACd,MAAM,CAAC,EAAE,CAAC,MAAM,EAAE,CAAC,KAAK,EAAE,EAAE,GAAG,IAAI,IAAI,KAAK,CAAC,QAAQ,EAAE,CAAC,CAAC,CAAC,CAAC,CAAC;QAE5D,MAAM,CAAC,EAAE,CAAC,KAAK,EAAE,GAAG,EAAE;YACpB,YAAY,CAAC,KAAK,CAAC,CAAC;YACpB,IAAI,CAAC;gBACH,OAAO,CAAC,IAAI,CAAC,KAAK,CAAC,IAAI,CAAC,CAAC,CAAC;YAC5B,CAAC;YAAC,MAAM,CAAC;gBACP,OAAO,CAAC,EAAE,OAAO,EAAE,KAAK,EAAE,KAAK,EAAE,8BAA8B,EAAE,CAAC,CAAC;YACrE,CAAC;QACH,CAAC,CAAC,CAAC;QAEH,MAAM,CAAC,EAAE,CAAC,OAAO,EAAE,CAAC,GAAG,EAAE,EAAE;YACzB,YAAY,CAAC,KAAK,CAAC,CAAC;YACpB,OAAO,CAAC,EAAE,OAAO,EAAE,KAAK,EAAE,KAAK,EAAE,6BAA6B,GAAG,CAAC,OAAO,EAAE,EAAE,CAAC,CAAC;QACjF,CAAC,CAAC,CAAC;IACL,CAAC,CAAC,CAAC;AACL,CAAC"}
|
package/dist/native-host.d.ts
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
#!/usr/bin/env node
|
|
2
2
|
export interface NativeRequest {
|
|
3
|
-
action: 'save_skill' | 'save_batch' | 'ping';
|
|
3
|
+
action: 'save_skill' | 'save_batch' | 'ping' | 'capture_request';
|
|
4
4
|
domain?: string;
|
|
5
5
|
skillJson?: string;
|
|
6
6
|
skills?: Array<{
|
|
@@ -18,3 +18,7 @@ export interface NativeResponse {
|
|
|
18
18
|
skillsDir?: string;
|
|
19
19
|
}
|
|
20
20
|
export declare function handleNativeMessage(request: NativeRequest, skillsDir?: string): Promise<NativeResponse>;
|
|
21
|
+
export declare function createRelayHandler(sendToExtension: (msg: any) => Promise<any>, skillsDir?: string): MessageHandler;
|
|
22
|
+
export type MessageHandler = (message: any) => Promise<any>;
|
|
23
|
+
export declare function startSocketServer(socketPath: string, handler: MessageHandler): Promise<void>;
|
|
24
|
+
export declare function stopSocketServer(): Promise<void>;
|
package/dist/native-host.js
CHANGED
|
@@ -4,6 +4,7 @@
|
|
|
4
4
|
import { promises as fs } from 'node:fs';
|
|
5
5
|
import path from 'node:path';
|
|
6
6
|
import os from 'node:os';
|
|
7
|
+
import net from 'node:net';
|
|
7
8
|
import { signSkillFile } from './skill/signing.js';
|
|
8
9
|
import { deriveKey } from './auth/crypto.js';
|
|
9
10
|
import { getMachineId } from './auth/manager.js';
|
|
@@ -96,6 +97,68 @@ export async function handleNativeMessage(request, skillsDir = SKILLS_DIR) {
|
|
|
96
97
|
return { success: false, error: String(err) };
|
|
97
98
|
}
|
|
98
99
|
}
|
|
100
|
+
// --- Relay handler ---
|
|
101
|
+
// Actions handled locally by the native host (filesystem operations)
|
|
102
|
+
const LOCAL_ACTIONS = new Set(['save_skill', 'save_batch', 'ping']);
|
|
103
|
+
// Actions relayed to the extension (browser operations)
|
|
104
|
+
const EXTENSION_ACTIONS = new Set(['capture_request']);
|
|
105
|
+
export function createRelayHandler(sendToExtension, skillsDir = SKILLS_DIR) {
|
|
106
|
+
return async (message) => {
|
|
107
|
+
if (LOCAL_ACTIONS.has(message.action)) {
|
|
108
|
+
return handleNativeMessage(message, skillsDir);
|
|
109
|
+
}
|
|
110
|
+
if (EXTENSION_ACTIONS.has(message.action)) {
|
|
111
|
+
try {
|
|
112
|
+
return await sendToExtension(message);
|
|
113
|
+
}
|
|
114
|
+
catch (err) {
|
|
115
|
+
return { success: false, error: String(err) };
|
|
116
|
+
}
|
|
117
|
+
}
|
|
118
|
+
return { success: false, error: `Unknown action: ${message.action}` };
|
|
119
|
+
};
|
|
120
|
+
}
|
|
121
|
+
let socketServer = null;
|
|
122
|
+
export async function startSocketServer(socketPath, handler) {
|
|
123
|
+
// Clean up stale socket
|
|
124
|
+
try {
|
|
125
|
+
await fs.unlink(socketPath);
|
|
126
|
+
}
|
|
127
|
+
catch { /* doesn't exist — fine */ }
|
|
128
|
+
return new Promise((resolve, reject) => {
|
|
129
|
+
socketServer = net.createServer((conn) => {
|
|
130
|
+
let buffer = '';
|
|
131
|
+
conn.on('data', (chunk) => {
|
|
132
|
+
buffer += chunk.toString();
|
|
133
|
+
const newlineIdx = buffer.indexOf('\n');
|
|
134
|
+
if (newlineIdx === -1)
|
|
135
|
+
return;
|
|
136
|
+
const line = buffer.slice(0, newlineIdx);
|
|
137
|
+
buffer = buffer.slice(newlineIdx + 1);
|
|
138
|
+
let request;
|
|
139
|
+
try {
|
|
140
|
+
request = JSON.parse(line);
|
|
141
|
+
}
|
|
142
|
+
catch {
|
|
143
|
+
conn.end(JSON.stringify({ success: false, error: 'Invalid JSON' }) + '\n');
|
|
144
|
+
return;
|
|
145
|
+
}
|
|
146
|
+
handler(request).then((response) => conn.end(JSON.stringify(response) + '\n'), (err) => conn.end(JSON.stringify({ success: false, error: String(err) }) + '\n'));
|
|
147
|
+
});
|
|
148
|
+
conn.on('error', () => { });
|
|
149
|
+
});
|
|
150
|
+
socketServer.on('error', reject);
|
|
151
|
+
socketServer.listen(socketPath, () => resolve());
|
|
152
|
+
});
|
|
153
|
+
}
|
|
154
|
+
export async function stopSocketServer() {
|
|
155
|
+
if (!socketServer)
|
|
156
|
+
return;
|
|
157
|
+
return new Promise((resolve) => {
|
|
158
|
+
socketServer.close(() => resolve());
|
|
159
|
+
socketServer = null;
|
|
160
|
+
});
|
|
161
|
+
}
|
|
99
162
|
// --- stdio framing (only runs when executed directly, not when imported for tests) ---
|
|
100
163
|
function readMessage() {
|
|
101
164
|
return new Promise((resolve) => {
|
|
@@ -171,14 +234,55 @@ function sendMessage(message) {
|
|
|
171
234
|
const isMainModule = process.argv[1] &&
|
|
172
235
|
(process.argv[1].endsWith('native-host.ts') || process.argv[1].endsWith('native-host.js'));
|
|
173
236
|
if (isMainModule) {
|
|
237
|
+
const bridgeDir = path.join(os.homedir(), '.apitap');
|
|
238
|
+
const socketPath = path.join(bridgeDir, 'bridge.sock');
|
|
239
|
+
// Pending CLI requests waiting for extension responses
|
|
240
|
+
const pendingRequests = new Map();
|
|
241
|
+
let requestCounter = 0;
|
|
242
|
+
// Send a message to the extension via stdout and wait for response
|
|
243
|
+
function sendToExtension(message) {
|
|
244
|
+
return new Promise((resolve) => {
|
|
245
|
+
const id = String(++requestCounter);
|
|
246
|
+
const timer = setTimeout(() => {
|
|
247
|
+
pendingRequests.delete(id);
|
|
248
|
+
resolve({ success: false, error: 'approval_timeout' });
|
|
249
|
+
}, 60_000);
|
|
250
|
+
pendingRequests.set(id, { resolve, timer });
|
|
251
|
+
// Tag message with ID so we can match the response
|
|
252
|
+
sendMessage({ ...message, _relayId: id });
|
|
253
|
+
});
|
|
254
|
+
}
|
|
255
|
+
const handler = createRelayHandler(sendToExtension);
|
|
174
256
|
(async () => {
|
|
257
|
+
// Ensure bridge directory exists
|
|
258
|
+
await fs.mkdir(bridgeDir, { recursive: true });
|
|
259
|
+
// Start socket server for CLI connections
|
|
260
|
+
await startSocketServer(socketPath, handler);
|
|
261
|
+
// Read messages from extension via stdin
|
|
175
262
|
while (true) {
|
|
176
|
-
const
|
|
177
|
-
if (!
|
|
263
|
+
const message = await readMessage();
|
|
264
|
+
if (!message)
|
|
178
265
|
break;
|
|
179
|
-
|
|
266
|
+
// Check if this is a response to a relayed request
|
|
267
|
+
const relayId = message._relayId;
|
|
268
|
+
if (relayId && pendingRequests.has(relayId)) {
|
|
269
|
+
const pending = pendingRequests.get(relayId);
|
|
270
|
+
clearTimeout(pending.timer);
|
|
271
|
+
pendingRequests.delete(relayId);
|
|
272
|
+
const { _relayId, ...response } = message;
|
|
273
|
+
pending.resolve(response);
|
|
274
|
+
continue;
|
|
275
|
+
}
|
|
276
|
+
// Otherwise, handle as a direct extension message (save_skill, etc.)
|
|
277
|
+
const response = await handleNativeMessage(message);
|
|
180
278
|
sendMessage(response);
|
|
181
279
|
}
|
|
280
|
+
// Extension disconnected — clean up
|
|
281
|
+
await stopSocketServer();
|
|
282
|
+
try {
|
|
283
|
+
await fs.unlink(socketPath);
|
|
284
|
+
}
|
|
285
|
+
catch { /* already gone */ }
|
|
182
286
|
})();
|
|
183
287
|
}
|
|
184
288
|
//# sourceMappingURL=native-host.js.map
|
package/dist/native-host.js.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"native-host.js","sourceRoot":"","sources":["../src/native-host.ts"],"names":[],"mappings":"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"}
|
|
1
|
+
{"version":3,"file":"native-host.js","sourceRoot":"","sources":["../src/native-host.ts"],"names":[],"mappings":"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"}
|
|
@@ -8,6 +8,10 @@ export interface BrowseOptions {
|
|
|
8
8
|
maxBytes?: number;
|
|
9
9
|
/** @internal Skip SSRF check — for testing only */
|
|
10
10
|
_skipSsrfCheck?: boolean;
|
|
11
|
+
/** @internal Override bridge socket path — for testing only */
|
|
12
|
+
_bridgeSocketPath?: string;
|
|
13
|
+
/** @internal Override bridge timeout — for testing only */
|
|
14
|
+
_bridgeTimeout?: number;
|
|
11
15
|
}
|
|
12
16
|
export interface BrowseSuccess {
|
|
13
17
|
success: true;
|
|
@@ -16,7 +20,7 @@ export interface BrowseSuccess {
|
|
|
16
20
|
domain: string;
|
|
17
21
|
endpointId: string;
|
|
18
22
|
tier: string;
|
|
19
|
-
skillSource: 'disk' | 'discovered' | 'captured';
|
|
23
|
+
skillSource: 'disk' | 'discovered' | 'captured' | 'bridge';
|
|
20
24
|
capturedAt: string;
|
|
21
25
|
task?: string;
|
|
22
26
|
truncated?: boolean;
|
|
@@ -1,6 +1,99 @@
|
|
|
1
1
|
import { readSkillFile } from '../skill/store.js';
|
|
2
2
|
import { replayEndpoint } from '../replay/engine.js';
|
|
3
3
|
import { read } from '../read/index.js';
|
|
4
|
+
import { bridgeAvailable, requestBridgeCapture, DEFAULT_SOCKET } from '../bridge/client.js';
|
|
5
|
+
/**
|
|
6
|
+
* Try escalating to the Chrome extension bridge for authenticated capture.
|
|
7
|
+
* Returns a BrowseResult if the bridge handled it, or null to fall through.
|
|
8
|
+
*/
|
|
9
|
+
async function tryBridgeCapture(domain, fullUrl, options) {
|
|
10
|
+
const socketPath = options._bridgeSocketPath ?? DEFAULT_SOCKET;
|
|
11
|
+
if (!await bridgeAvailable(socketPath))
|
|
12
|
+
return null;
|
|
13
|
+
const result = await requestBridgeCapture(domain, socketPath, { timeout: options._bridgeTimeout });
|
|
14
|
+
if (result.success && result.skillFiles && result.skillFiles.length > 0) {
|
|
15
|
+
const skillFiles = result.skillFiles;
|
|
16
|
+
// Save each skill file to disk
|
|
17
|
+
try {
|
|
18
|
+
const { writeSkillFile: writeSF } = await import('../skill/store.js');
|
|
19
|
+
for (const skill of skillFiles) {
|
|
20
|
+
await writeSF(skill, options.skillsDir);
|
|
21
|
+
}
|
|
22
|
+
}
|
|
23
|
+
catch {
|
|
24
|
+
// Saving failed — still have the data in memory
|
|
25
|
+
}
|
|
26
|
+
// Find the skill file matching the requested domain
|
|
27
|
+
const primarySkill = skillFiles.find((s) => s.domain === domain)
|
|
28
|
+
?? skillFiles[0];
|
|
29
|
+
if (primarySkill?.endpoints?.length > 0) {
|
|
30
|
+
// Pick the best endpoint and replay it
|
|
31
|
+
let urlPath = '/';
|
|
32
|
+
try {
|
|
33
|
+
urlPath = new URL(fullUrl).pathname;
|
|
34
|
+
}
|
|
35
|
+
catch { /* use default */ }
|
|
36
|
+
const endpoint = pickEndpoint(primarySkill, urlPath);
|
|
37
|
+
if (endpoint) {
|
|
38
|
+
try {
|
|
39
|
+
const replayResult = await replayEndpoint(primarySkill, endpoint.id, {
|
|
40
|
+
maxBytes: options.maxBytes,
|
|
41
|
+
_skipSsrfCheck: options._skipSsrfCheck,
|
|
42
|
+
});
|
|
43
|
+
if (replayResult.status >= 200 && replayResult.status < 300) {
|
|
44
|
+
return {
|
|
45
|
+
success: true,
|
|
46
|
+
data: replayResult.data,
|
|
47
|
+
status: replayResult.status,
|
|
48
|
+
domain,
|
|
49
|
+
endpointId: endpoint.id,
|
|
50
|
+
tier: endpoint.replayability?.tier ?? 'unknown',
|
|
51
|
+
skillSource: 'bridge',
|
|
52
|
+
capturedAt: primarySkill.capturedAt ?? new Date().toISOString(),
|
|
53
|
+
task: options.task,
|
|
54
|
+
...(replayResult.truncated ? { truncated: true } : {}),
|
|
55
|
+
};
|
|
56
|
+
}
|
|
57
|
+
}
|
|
58
|
+
catch {
|
|
59
|
+
// Replay failed — but skill file is saved for next time
|
|
60
|
+
}
|
|
61
|
+
}
|
|
62
|
+
}
|
|
63
|
+
// Skill file saved but replay didn't work
|
|
64
|
+
return {
|
|
65
|
+
success: false,
|
|
66
|
+
reason: 'bridge_capture_saved',
|
|
67
|
+
suggestion: `Captured ${skillFiles.length} skill file(s) from browser. Replay failed — try 'apitap replay ${domain}'.`,
|
|
68
|
+
domain,
|
|
69
|
+
url: fullUrl,
|
|
70
|
+
task: options.task,
|
|
71
|
+
};
|
|
72
|
+
}
|
|
73
|
+
// Bridge returned an error
|
|
74
|
+
if (result.error === 'user_denied') {
|
|
75
|
+
return {
|
|
76
|
+
success: false,
|
|
77
|
+
reason: 'user_denied',
|
|
78
|
+
suggestion: `User denied browser access to ${domain}. Use 'apitap auth request ${domain}' for manual login instead.`,
|
|
79
|
+
domain,
|
|
80
|
+
url: fullUrl,
|
|
81
|
+
task: options.task,
|
|
82
|
+
};
|
|
83
|
+
}
|
|
84
|
+
if (result.error === 'approval_timeout') {
|
|
85
|
+
return {
|
|
86
|
+
success: false,
|
|
87
|
+
reason: 'approval_timeout',
|
|
88
|
+
suggestion: `User approval pending for ${domain}. Click Allow in the ApiTap extension and try again.`,
|
|
89
|
+
domain,
|
|
90
|
+
url: fullUrl,
|
|
91
|
+
task: options.task,
|
|
92
|
+
};
|
|
93
|
+
}
|
|
94
|
+
// Other bridge errors — fall through to existing fallback
|
|
95
|
+
return null;
|
|
96
|
+
}
|
|
4
97
|
/**
|
|
5
98
|
* High-level browse: check cache → disk → discover → replay.
|
|
6
99
|
* Auto-escalates cheap steps. Returns guidance for expensive ones.
|
|
@@ -75,6 +168,10 @@ export async function browse(url, options = {}) {
|
|
|
75
168
|
catch {
|
|
76
169
|
// Read failed — fall through to capture_needed
|
|
77
170
|
}
|
|
171
|
+
// Try extension bridge before giving up
|
|
172
|
+
const bridgeResult1 = await tryBridgeCapture(domain, fullUrl, options);
|
|
173
|
+
if (bridgeResult1)
|
|
174
|
+
return bridgeResult1;
|
|
78
175
|
return {
|
|
79
176
|
success: false,
|
|
80
177
|
reason: 'no_replayable_endpoints',
|
|
@@ -113,6 +210,10 @@ export async function browse(url, options = {}) {
|
|
|
113
210
|
// Read failed — fall through to capture_needed
|
|
114
211
|
}
|
|
115
212
|
}
|
|
213
|
+
// Try extension bridge before giving up
|
|
214
|
+
const bridgeResult2 = await tryBridgeCapture(domain, fullUrl, options);
|
|
215
|
+
if (bridgeResult2)
|
|
216
|
+
return bridgeResult2;
|
|
116
217
|
return {
|
|
117
218
|
success: false,
|
|
118
219
|
reason: 'no_skill_file',
|
|
@@ -125,6 +226,10 @@ export async function browse(url, options = {}) {
|
|
|
125
226
|
// Step 4: Pick best endpoint
|
|
126
227
|
const endpoint = pickEndpoint(skill, urlPath);
|
|
127
228
|
if (!endpoint) {
|
|
229
|
+
// Try extension bridge before giving up
|
|
230
|
+
const bridgeResult3 = await tryBridgeCapture(domain, fullUrl, options);
|
|
231
|
+
if (bridgeResult3)
|
|
232
|
+
return bridgeResult3;
|
|
128
233
|
return {
|
|
129
234
|
success: false,
|
|
130
235
|
reason: 'no_replayable_endpoints',
|
|
@@ -165,6 +270,10 @@ export async function browse(url, options = {}) {
|
|
|
165
270
|
};
|
|
166
271
|
}
|
|
167
272
|
catch {
|
|
273
|
+
// Try extension bridge before giving up
|
|
274
|
+
const bridgeResult4 = await tryBridgeCapture(domain, fullUrl, options);
|
|
275
|
+
if (bridgeResult4)
|
|
276
|
+
return bridgeResult4;
|
|
168
277
|
return {
|
|
169
278
|
success: false,
|
|
170
279
|
reason: 'replay_failed',
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"browse.js","sourceRoot":"","sources":["../../src/orchestration/browse.ts"],"names":[],"mappings":"AACA,OAAO,EAAE,aAAa,EAAE,MAAM,mBAAmB,CAAC;AAClD,OAAO,EAAE,cAAc,EAAE,MAAM,qBAAqB,CAAC;AAErD,OAAO,EAAE,IAAI,EAAE,MAAM,kBAAkB,CAAC;
|
|
1
|
+
{"version":3,"file":"browse.js","sourceRoot":"","sources":["../../src/orchestration/browse.ts"],"names":[],"mappings":"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"}
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@apitap/core",
|
|
3
|
-
"version": "1.
|
|
3
|
+
"version": "1.2.0",
|
|
4
4
|
"description": "Intercept web API traffic during browsing. Generate portable skill files so AI agents can call APIs directly instead of scraping.",
|
|
5
5
|
"type": "module",
|
|
6
6
|
"main": "dist/index.js",
|
|
@@ -0,0 +1,67 @@
|
|
|
1
|
+
import net from 'node:net';
|
|
2
|
+
import { promises as fs } from 'node:fs';
|
|
3
|
+
import path from 'node:path';
|
|
4
|
+
import os from 'node:os';
|
|
5
|
+
|
|
6
|
+
export const DEFAULT_SOCKET = path.join(os.homedir(), '.apitap', 'bridge.sock');
|
|
7
|
+
|
|
8
|
+
export interface BridgeCaptureResult {
|
|
9
|
+
success: boolean;
|
|
10
|
+
skillFiles?: any[];
|
|
11
|
+
error?: string;
|
|
12
|
+
}
|
|
13
|
+
|
|
14
|
+
/**
|
|
15
|
+
* Fast check: does the bridge socket exist?
|
|
16
|
+
* Returns false if the file doesn't exist (costs ~0.1ms).
|
|
17
|
+
* Returns true if the file exists (doesn't verify it's connectable).
|
|
18
|
+
*/
|
|
19
|
+
export async function bridgeAvailable(socketPath: string = DEFAULT_SOCKET): Promise<boolean> {
|
|
20
|
+
try {
|
|
21
|
+
await fs.access(socketPath);
|
|
22
|
+
return true;
|
|
23
|
+
} catch {
|
|
24
|
+
return false;
|
|
25
|
+
}
|
|
26
|
+
}
|
|
27
|
+
|
|
28
|
+
/**
|
|
29
|
+
* Send a capture_request to the extension via the native host bridge.
|
|
30
|
+
* Returns skill files on success, or a structured error.
|
|
31
|
+
*/
|
|
32
|
+
export async function requestBridgeCapture(
|
|
33
|
+
domain: string,
|
|
34
|
+
socketPath: string = DEFAULT_SOCKET,
|
|
35
|
+
options: { timeout?: number } = {},
|
|
36
|
+
): Promise<BridgeCaptureResult> {
|
|
37
|
+
const timeout = options.timeout ?? 120_000; // 2 minutes (capture can take time)
|
|
38
|
+
|
|
39
|
+
return new Promise((resolve) => {
|
|
40
|
+
const timer = setTimeout(() => {
|
|
41
|
+
client.destroy();
|
|
42
|
+
resolve({ success: false, error: 'timeout' });
|
|
43
|
+
}, timeout);
|
|
44
|
+
|
|
45
|
+
const client = net.createConnection(socketPath, () => {
|
|
46
|
+
const message = JSON.stringify({ action: 'capture_request', domain }) + '\n';
|
|
47
|
+
client.write(message);
|
|
48
|
+
});
|
|
49
|
+
|
|
50
|
+
let data = '';
|
|
51
|
+
client.on('data', (chunk) => { data += chunk.toString(); });
|
|
52
|
+
|
|
53
|
+
client.on('end', () => {
|
|
54
|
+
clearTimeout(timer);
|
|
55
|
+
try {
|
|
56
|
+
resolve(JSON.parse(data));
|
|
57
|
+
} catch {
|
|
58
|
+
resolve({ success: false, error: 'invalid response from bridge' });
|
|
59
|
+
}
|
|
60
|
+
});
|
|
61
|
+
|
|
62
|
+
client.on('error', (err) => {
|
|
63
|
+
clearTimeout(timer);
|
|
64
|
+
resolve({ success: false, error: `bridge connection failed: ${err.message}` });
|
|
65
|
+
});
|
|
66
|
+
});
|
|
67
|
+
}
|
package/src/native-host.ts
CHANGED
|
@@ -5,6 +5,7 @@
|
|
|
5
5
|
import { promises as fs } from 'node:fs';
|
|
6
6
|
import path from 'node:path';
|
|
7
7
|
import os from 'node:os';
|
|
8
|
+
import net from 'node:net';
|
|
8
9
|
import { signSkillFile } from './skill/signing.js';
|
|
9
10
|
import { deriveKey } from './auth/crypto.js';
|
|
10
11
|
import { getMachineId } from './auth/manager.js';
|
|
@@ -26,7 +27,7 @@ async function signSkillJson(skillJson: string): Promise<string> {
|
|
|
26
27
|
}
|
|
27
28
|
|
|
28
29
|
export interface NativeRequest {
|
|
29
|
-
action: 'save_skill' | 'save_batch' | 'ping';
|
|
30
|
+
action: 'save_skill' | 'save_batch' | 'ping' | 'capture_request';
|
|
30
31
|
domain?: string;
|
|
31
32
|
skillJson?: string;
|
|
32
33
|
skills?: Array<{ domain: string; skillJson: string }>;
|
|
@@ -120,6 +121,90 @@ export async function handleNativeMessage(
|
|
|
120
121
|
}
|
|
121
122
|
}
|
|
122
123
|
|
|
124
|
+
// --- Relay handler ---
|
|
125
|
+
|
|
126
|
+
// Actions handled locally by the native host (filesystem operations)
|
|
127
|
+
const LOCAL_ACTIONS = new Set(['save_skill', 'save_batch', 'ping']);
|
|
128
|
+
|
|
129
|
+
// Actions relayed to the extension (browser operations)
|
|
130
|
+
const EXTENSION_ACTIONS = new Set(['capture_request']);
|
|
131
|
+
|
|
132
|
+
export function createRelayHandler(
|
|
133
|
+
sendToExtension: (msg: any) => Promise<any>,
|
|
134
|
+
skillsDir: string = SKILLS_DIR,
|
|
135
|
+
): MessageHandler {
|
|
136
|
+
return async (message: any) => {
|
|
137
|
+
if (LOCAL_ACTIONS.has(message.action)) {
|
|
138
|
+
return handleNativeMessage(message, skillsDir);
|
|
139
|
+
}
|
|
140
|
+
|
|
141
|
+
if (EXTENSION_ACTIONS.has(message.action)) {
|
|
142
|
+
try {
|
|
143
|
+
return await sendToExtension(message);
|
|
144
|
+
} catch (err) {
|
|
145
|
+
return { success: false, error: String(err) };
|
|
146
|
+
}
|
|
147
|
+
}
|
|
148
|
+
|
|
149
|
+
return { success: false, error: `Unknown action: ${message.action}` };
|
|
150
|
+
};
|
|
151
|
+
}
|
|
152
|
+
|
|
153
|
+
// --- Unix socket server for CLI relay ---
|
|
154
|
+
|
|
155
|
+
export type MessageHandler = (message: any) => Promise<any>;
|
|
156
|
+
|
|
157
|
+
let socketServer: net.Server | null = null;
|
|
158
|
+
|
|
159
|
+
export async function startSocketServer(
|
|
160
|
+
socketPath: string,
|
|
161
|
+
handler: MessageHandler,
|
|
162
|
+
): Promise<void> {
|
|
163
|
+
// Clean up stale socket
|
|
164
|
+
try { await fs.unlink(socketPath); } catch { /* doesn't exist — fine */ }
|
|
165
|
+
|
|
166
|
+
return new Promise((resolve, reject) => {
|
|
167
|
+
socketServer = net.createServer((conn) => {
|
|
168
|
+
let buffer = '';
|
|
169
|
+
|
|
170
|
+
conn.on('data', (chunk) => {
|
|
171
|
+
buffer += chunk.toString();
|
|
172
|
+
const newlineIdx = buffer.indexOf('\n');
|
|
173
|
+
if (newlineIdx === -1) return;
|
|
174
|
+
|
|
175
|
+
const line = buffer.slice(0, newlineIdx);
|
|
176
|
+
buffer = buffer.slice(newlineIdx + 1);
|
|
177
|
+
|
|
178
|
+
let request: any;
|
|
179
|
+
try {
|
|
180
|
+
request = JSON.parse(line);
|
|
181
|
+
} catch {
|
|
182
|
+
conn.end(JSON.stringify({ success: false, error: 'Invalid JSON' }) + '\n');
|
|
183
|
+
return;
|
|
184
|
+
}
|
|
185
|
+
|
|
186
|
+
handler(request).then(
|
|
187
|
+
(response) => conn.end(JSON.stringify(response) + '\n'),
|
|
188
|
+
(err) => conn.end(JSON.stringify({ success: false, error: String(err) }) + '\n'),
|
|
189
|
+
);
|
|
190
|
+
});
|
|
191
|
+
|
|
192
|
+
conn.on('error', () => { /* client disconnect — ignore */ });
|
|
193
|
+
});
|
|
194
|
+
|
|
195
|
+
socketServer.on('error', reject);
|
|
196
|
+
socketServer.listen(socketPath, () => resolve());
|
|
197
|
+
});
|
|
198
|
+
}
|
|
199
|
+
|
|
200
|
+
export async function stopSocketServer(): Promise<void> {
|
|
201
|
+
if (!socketServer) return;
|
|
202
|
+
return new Promise((resolve) => {
|
|
203
|
+
socketServer!.close(() => resolve());
|
|
204
|
+
socketServer = null;
|
|
205
|
+
});
|
|
206
|
+
}
|
|
207
|
+
|
|
123
208
|
// --- stdio framing (only runs when executed directly, not when imported for tests) ---
|
|
124
209
|
|
|
125
210
|
function readMessage(): Promise<NativeRequest | null> {
|
|
@@ -206,12 +291,64 @@ const isMainModule = process.argv[1] &&
|
|
|
206
291
|
(process.argv[1].endsWith('native-host.ts') || process.argv[1].endsWith('native-host.js'));
|
|
207
292
|
|
|
208
293
|
if (isMainModule) {
|
|
294
|
+
const bridgeDir = path.join(os.homedir(), '.apitap');
|
|
295
|
+
const socketPath = path.join(bridgeDir, 'bridge.sock');
|
|
296
|
+
|
|
297
|
+
// Pending CLI requests waiting for extension responses
|
|
298
|
+
const pendingRequests = new Map<string, {
|
|
299
|
+
resolve: (value: any) => void;
|
|
300
|
+
timer: ReturnType<typeof setTimeout>;
|
|
301
|
+
}>();
|
|
302
|
+
let requestCounter = 0;
|
|
303
|
+
|
|
304
|
+
// Send a message to the extension via stdout and wait for response
|
|
305
|
+
function sendToExtension(message: any): Promise<any> {
|
|
306
|
+
return new Promise((resolve) => {
|
|
307
|
+
const id = String(++requestCounter);
|
|
308
|
+
const timer = setTimeout(() => {
|
|
309
|
+
pendingRequests.delete(id);
|
|
310
|
+
resolve({ success: false, error: 'approval_timeout' });
|
|
311
|
+
}, 60_000);
|
|
312
|
+
|
|
313
|
+
pendingRequests.set(id, { resolve, timer });
|
|
314
|
+
|
|
315
|
+
// Tag message with ID so we can match the response
|
|
316
|
+
sendMessage({ ...message, _relayId: id } as any);
|
|
317
|
+
});
|
|
318
|
+
}
|
|
319
|
+
|
|
320
|
+
const handler = createRelayHandler(sendToExtension);
|
|
321
|
+
|
|
209
322
|
(async () => {
|
|
323
|
+
// Ensure bridge directory exists
|
|
324
|
+
await fs.mkdir(bridgeDir, { recursive: true });
|
|
325
|
+
|
|
326
|
+
// Start socket server for CLI connections
|
|
327
|
+
await startSocketServer(socketPath, handler);
|
|
328
|
+
|
|
329
|
+
// Read messages from extension via stdin
|
|
210
330
|
while (true) {
|
|
211
|
-
const
|
|
212
|
-
if (!
|
|
213
|
-
|
|
331
|
+
const message = await readMessage();
|
|
332
|
+
if (!message) break;
|
|
333
|
+
|
|
334
|
+
// Check if this is a response to a relayed request
|
|
335
|
+
const relayId = (message as any)._relayId;
|
|
336
|
+
if (relayId && pendingRequests.has(relayId)) {
|
|
337
|
+
const pending = pendingRequests.get(relayId)!;
|
|
338
|
+
clearTimeout(pending.timer);
|
|
339
|
+
pendingRequests.delete(relayId);
|
|
340
|
+
const { _relayId, ...response } = message as any;
|
|
341
|
+
pending.resolve(response);
|
|
342
|
+
continue;
|
|
343
|
+
}
|
|
344
|
+
|
|
345
|
+
// Otherwise, handle as a direct extension message (save_skill, etc.)
|
|
346
|
+
const response = await handleNativeMessage(message);
|
|
214
347
|
sendMessage(response);
|
|
215
348
|
}
|
|
349
|
+
|
|
350
|
+
// Extension disconnected — clean up
|
|
351
|
+
await stopSocketServer();
|
|
352
|
+
try { await fs.unlink(socketPath); } catch { /* already gone */ }
|
|
216
353
|
})();
|
|
217
354
|
}
|
|
@@ -3,6 +3,7 @@ import { readSkillFile } from '../skill/store.js';
|
|
|
3
3
|
import { replayEndpoint } from '../replay/engine.js';
|
|
4
4
|
import { SessionCache } from './cache.js';
|
|
5
5
|
import { read } from '../read/index.js';
|
|
6
|
+
import { bridgeAvailable, requestBridgeCapture, DEFAULT_SOCKET } from '../bridge/client.js';
|
|
6
7
|
|
|
7
8
|
export interface BrowseOptions {
|
|
8
9
|
skillsDir?: string;
|
|
@@ -13,6 +14,10 @@ export interface BrowseOptions {
|
|
|
13
14
|
maxBytes?: number;
|
|
14
15
|
/** @internal Skip SSRF check — for testing only */
|
|
15
16
|
_skipSsrfCheck?: boolean;
|
|
17
|
+
/** @internal Override bridge socket path — for testing only */
|
|
18
|
+
_bridgeSocketPath?: string;
|
|
19
|
+
/** @internal Override bridge timeout — for testing only */
|
|
20
|
+
_bridgeTimeout?: number;
|
|
16
21
|
}
|
|
17
22
|
|
|
18
23
|
export interface BrowseSuccess {
|
|
@@ -22,7 +27,7 @@ export interface BrowseSuccess {
|
|
|
22
27
|
domain: string;
|
|
23
28
|
endpointId: string;
|
|
24
29
|
tier: string;
|
|
25
|
-
skillSource: 'disk' | 'discovered' | 'captured';
|
|
30
|
+
skillSource: 'disk' | 'discovered' | 'captured' | 'bridge';
|
|
26
31
|
capturedAt: string;
|
|
27
32
|
task?: string;
|
|
28
33
|
truncated?: boolean;
|
|
@@ -40,6 +45,106 @@ export interface BrowseGuidance {
|
|
|
40
45
|
|
|
41
46
|
export type BrowseResult = BrowseSuccess | BrowseGuidance;
|
|
42
47
|
|
|
48
|
+
/**
|
|
49
|
+
* Try escalating to the Chrome extension bridge for authenticated capture.
|
|
50
|
+
* Returns a BrowseResult if the bridge handled it, or null to fall through.
|
|
51
|
+
*/
|
|
52
|
+
async function tryBridgeCapture(
|
|
53
|
+
domain: string,
|
|
54
|
+
fullUrl: string,
|
|
55
|
+
options: BrowseOptions,
|
|
56
|
+
): Promise<BrowseResult | null> {
|
|
57
|
+
const socketPath = options._bridgeSocketPath ?? DEFAULT_SOCKET;
|
|
58
|
+
if (!await bridgeAvailable(socketPath)) return null;
|
|
59
|
+
|
|
60
|
+
const result = await requestBridgeCapture(domain, socketPath, { timeout: options._bridgeTimeout });
|
|
61
|
+
|
|
62
|
+
if (result.success && result.skillFiles && result.skillFiles.length > 0) {
|
|
63
|
+
const skillFiles = result.skillFiles;
|
|
64
|
+
// Save each skill file to disk
|
|
65
|
+
try {
|
|
66
|
+
const { writeSkillFile: writeSF } = await import('../skill/store.js');
|
|
67
|
+
for (const skill of skillFiles) {
|
|
68
|
+
await writeSF(skill, options.skillsDir);
|
|
69
|
+
}
|
|
70
|
+
} catch {
|
|
71
|
+
// Saving failed — still have the data in memory
|
|
72
|
+
}
|
|
73
|
+
|
|
74
|
+
// Find the skill file matching the requested domain
|
|
75
|
+
const primarySkill = skillFiles.find((s: any) => s.domain === domain)
|
|
76
|
+
?? skillFiles[0];
|
|
77
|
+
|
|
78
|
+
if (primarySkill?.endpoints?.length > 0) {
|
|
79
|
+
// Pick the best endpoint and replay it
|
|
80
|
+
let urlPath = '/';
|
|
81
|
+
try { urlPath = new URL(fullUrl).pathname; } catch { /* use default */ }
|
|
82
|
+
const endpoint = pickEndpoint(primarySkill, urlPath);
|
|
83
|
+
|
|
84
|
+
if (endpoint) {
|
|
85
|
+
try {
|
|
86
|
+
const replayResult = await replayEndpoint(primarySkill, endpoint.id, {
|
|
87
|
+
maxBytes: options.maxBytes,
|
|
88
|
+
_skipSsrfCheck: options._skipSsrfCheck,
|
|
89
|
+
});
|
|
90
|
+
if (replayResult.status >= 200 && replayResult.status < 300) {
|
|
91
|
+
return {
|
|
92
|
+
success: true,
|
|
93
|
+
data: replayResult.data,
|
|
94
|
+
status: replayResult.status,
|
|
95
|
+
domain,
|
|
96
|
+
endpointId: endpoint.id,
|
|
97
|
+
tier: endpoint.replayability?.tier ?? 'unknown',
|
|
98
|
+
skillSource: 'bridge',
|
|
99
|
+
capturedAt: primarySkill.capturedAt ?? new Date().toISOString(),
|
|
100
|
+
task: options.task,
|
|
101
|
+
...(replayResult.truncated ? { truncated: true } : {}),
|
|
102
|
+
};
|
|
103
|
+
}
|
|
104
|
+
} catch {
|
|
105
|
+
// Replay failed — but skill file is saved for next time
|
|
106
|
+
}
|
|
107
|
+
}
|
|
108
|
+
}
|
|
109
|
+
|
|
110
|
+
// Skill file saved but replay didn't work
|
|
111
|
+
return {
|
|
112
|
+
success: false,
|
|
113
|
+
reason: 'bridge_capture_saved',
|
|
114
|
+
suggestion: `Captured ${skillFiles.length} skill file(s) from browser. Replay failed — try 'apitap replay ${domain}'.`,
|
|
115
|
+
domain,
|
|
116
|
+
url: fullUrl,
|
|
117
|
+
task: options.task,
|
|
118
|
+
};
|
|
119
|
+
}
|
|
120
|
+
|
|
121
|
+
// Bridge returned an error
|
|
122
|
+
if (result.error === 'user_denied') {
|
|
123
|
+
return {
|
|
124
|
+
success: false,
|
|
125
|
+
reason: 'user_denied',
|
|
126
|
+
suggestion: `User denied browser access to ${domain}. Use 'apitap auth request ${domain}' for manual login instead.`,
|
|
127
|
+
domain,
|
|
128
|
+
url: fullUrl,
|
|
129
|
+
task: options.task,
|
|
130
|
+
};
|
|
131
|
+
}
|
|
132
|
+
|
|
133
|
+
if (result.error === 'approval_timeout') {
|
|
134
|
+
return {
|
|
135
|
+
success: false,
|
|
136
|
+
reason: 'approval_timeout',
|
|
137
|
+
suggestion: `User approval pending for ${domain}. Click Allow in the ApiTap extension and try again.`,
|
|
138
|
+
domain,
|
|
139
|
+
url: fullUrl,
|
|
140
|
+
task: options.task,
|
|
141
|
+
};
|
|
142
|
+
}
|
|
143
|
+
|
|
144
|
+
// Other bridge errors — fall through to existing fallback
|
|
145
|
+
return null;
|
|
146
|
+
}
|
|
147
|
+
|
|
43
148
|
/**
|
|
44
149
|
* High-level browse: check cache → disk → discover → replay.
|
|
45
150
|
* Auto-escalates cheap steps. Returns guidance for expensive ones.
|
|
@@ -121,6 +226,10 @@ export async function browse(
|
|
|
121
226
|
} catch {
|
|
122
227
|
// Read failed — fall through to capture_needed
|
|
123
228
|
}
|
|
229
|
+
// Try extension bridge before giving up
|
|
230
|
+
const bridgeResult1 = await tryBridgeCapture(domain, fullUrl, options);
|
|
231
|
+
if (bridgeResult1) return bridgeResult1;
|
|
232
|
+
|
|
124
233
|
return {
|
|
125
234
|
success: false,
|
|
126
235
|
reason: 'no_replayable_endpoints',
|
|
@@ -158,6 +267,10 @@ export async function browse(
|
|
|
158
267
|
// Read failed — fall through to capture_needed
|
|
159
268
|
}
|
|
160
269
|
}
|
|
270
|
+
// Try extension bridge before giving up
|
|
271
|
+
const bridgeResult2 = await tryBridgeCapture(domain, fullUrl, options);
|
|
272
|
+
if (bridgeResult2) return bridgeResult2;
|
|
273
|
+
|
|
161
274
|
return {
|
|
162
275
|
success: false,
|
|
163
276
|
reason: 'no_skill_file',
|
|
@@ -171,6 +284,10 @@ export async function browse(
|
|
|
171
284
|
// Step 4: Pick best endpoint
|
|
172
285
|
const endpoint = pickEndpoint(skill, urlPath);
|
|
173
286
|
if (!endpoint) {
|
|
287
|
+
// Try extension bridge before giving up
|
|
288
|
+
const bridgeResult3 = await tryBridgeCapture(domain, fullUrl, options);
|
|
289
|
+
if (bridgeResult3) return bridgeResult3;
|
|
290
|
+
|
|
174
291
|
return {
|
|
175
292
|
success: false,
|
|
176
293
|
reason: 'no_replayable_endpoints',
|
|
@@ -213,6 +330,10 @@ export async function browse(
|
|
|
213
330
|
...(result.truncated ? { truncated: true } : {}),
|
|
214
331
|
};
|
|
215
332
|
} catch {
|
|
333
|
+
// Try extension bridge before giving up
|
|
334
|
+
const bridgeResult4 = await tryBridgeCapture(domain, fullUrl, options);
|
|
335
|
+
if (bridgeResult4) return bridgeResult4;
|
|
336
|
+
|
|
216
337
|
return {
|
|
217
338
|
success: false,
|
|
218
339
|
reason: 'replay_failed',
|