@tapicker/bridge 1.0.0 → 1.1.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 +15 -15
- package/dist/bridge/bridge-service.d.ts +1 -1
- package/dist/bridge/bridge-service.js +7 -7
- package/dist/bridge/control.js +1 -1
- package/dist/bridge/export-store.d.ts +35 -0
- package/dist/bridge/export-store.js +195 -0
- package/dist/bridge/extension-session.d.ts +9 -2
- package/dist/bridge/extension-session.js +56 -8
- package/dist/cli.js +563 -148
- package/dist/commands.d.ts +8 -0
- package/dist/commands.js +276 -40
- package/dist/constants.d.ts +2 -2
- package/dist/constants.js +4 -2
- package/dist/http-client.d.ts +24 -0
- package/dist/http-client.js +101 -0
- package/dist/index.d.ts +4 -4
- package/dist/index.js +2 -2
- package/dist/mcp.d.ts +4 -3
- package/dist/mcp.js +221 -134
- package/dist/protocol/schema.d.ts +503 -34
- package/dist/protocol/schema.js +396 -15
- package/dist/server.d.ts +7 -4
- package/dist/server.js +70 -26
- package/dist/update-notifier-worker.d.ts +2 -0
- package/dist/update-notifier-worker.js +3 -0
- package/dist/update-notifier.d.ts +9 -0
- package/dist/update-notifier.js +178 -0
- package/dist/workflow-watch.d.ts +8 -7
- package/dist/workflow-watch.js +39 -29
- package/package.json +16 -6
- package/docs/cli.md +0 -112
- package/docs/http-api.md +0 -149
- package/docs/mcp.md +0 -90
- package/docs/operations.md +0 -85
- package/docs/workflow-watch.md +0 -86
- package/src/bridge/bridge-service.ts +0 -291
- package/src/bridge/control.ts +0 -281
- package/src/bridge/daemon.ts +0 -102
- package/src/bridge/extension-session.ts +0 -286
- package/src/bridge/pairing-state.ts +0 -92
- package/src/cli.ts +0 -1019
- package/src/commands.ts +0 -158
- package/src/constants.ts +0 -10
- package/src/errors.ts +0 -72
- package/src/index.ts +0 -35
- package/src/mcp.ts +0 -386
- package/src/protocol/schema.ts +0 -202
- package/src/server.ts +0 -623
- package/src/workflow-watch.ts +0 -364
package/dist/workflow-watch.js
CHANGED
|
@@ -1,18 +1,17 @@
|
|
|
1
1
|
import { randomUUID } from 'node:crypto';
|
|
2
2
|
import { WebSocket } from 'ws';
|
|
3
|
-
import {
|
|
3
|
+
import { DEFAULT_WORKFLOW_STATUS_WATCH_WS_PATH } from './constants.js';
|
|
4
4
|
import { BridgeError } from './errors.js';
|
|
5
5
|
import { SafeResultSchema, WorkflowStatusEventSchema, createEnvelope, parseEnvelope } from './protocol/schema.js';
|
|
6
|
-
|
|
7
|
-
|
|
8
|
-
const url = new URL(DEFAULT_WORKFLOW_WATCH_WS_PATH, bridgeUrl);
|
|
6
|
+
export function workflowStatusWatchWebSocketUrl(bridgeUrl) {
|
|
7
|
+
const url = new URL(DEFAULT_WORKFLOW_STATUS_WATCH_WS_PATH, bridgeUrl);
|
|
9
8
|
url.protocol = bridgeUrl.protocol === 'https:' ? 'wss:' : 'ws:';
|
|
10
9
|
return url;
|
|
11
10
|
}
|
|
12
|
-
export function
|
|
11
|
+
export function connectWorkflowStatusWatch(url, input, token, signal) {
|
|
13
12
|
return new Promise((resolve, reject) => {
|
|
14
13
|
if (signal?.aborted) {
|
|
15
|
-
reject(new BridgeError('
|
|
14
|
+
reject(new BridgeError('WorkflowStatusWatchCancelled', 'Workflow status watch was cancelled', { status: 499 }));
|
|
16
15
|
return;
|
|
17
16
|
}
|
|
18
17
|
const headers = token ? { Authorization: `Bearer ${token}` } : undefined;
|
|
@@ -56,17 +55,22 @@ export function connectWorkflowWatch(url, input, token, signal) {
|
|
|
56
55
|
intentionalClose = true;
|
|
57
56
|
cleanupAbortListener();
|
|
58
57
|
if (socket.readyState === WebSocket.OPEN) {
|
|
59
|
-
socket.close(1000, 'Workflow watch closed');
|
|
58
|
+
socket.close(1000, 'Workflow status watch closed');
|
|
60
59
|
}
|
|
61
60
|
else if (socket.readyState === WebSocket.CONNECTING) {
|
|
62
61
|
socket.terminate();
|
|
63
62
|
}
|
|
64
63
|
if (acceptedClientId) {
|
|
65
|
-
notifyClose(reason ??
|
|
64
|
+
notifyClose(reason ??
|
|
65
|
+
new BridgeError('WorkflowStatusWatchClosed', 'Workflow status watch was closed by the client', {
|
|
66
|
+
status: 499,
|
|
67
|
+
}));
|
|
66
68
|
}
|
|
67
69
|
};
|
|
68
70
|
abortListener = () => {
|
|
69
|
-
const error = new BridgeError('
|
|
71
|
+
const error = new BridgeError('WorkflowStatusWatchCancelled', 'Workflow status watch was cancelled', {
|
|
72
|
+
status: 499,
|
|
73
|
+
});
|
|
70
74
|
if (!acceptedClientId) {
|
|
71
75
|
failBeforeAccept(error);
|
|
72
76
|
}
|
|
@@ -76,7 +80,7 @@ export function connectWorkflowWatch(url, input, token, signal) {
|
|
|
76
80
|
};
|
|
77
81
|
signal?.addEventListener('abort', abortListener, { once: true });
|
|
78
82
|
socket.once('open', () => {
|
|
79
|
-
socket.send(JSON.stringify(createEnvelope('workflow.watch', {
|
|
83
|
+
socket.send(JSON.stringify(createEnvelope('workflow.status.watch', {
|
|
80
84
|
clientId: input.clientId,
|
|
81
85
|
input: { workflowId: input.workflowId },
|
|
82
86
|
}, { id: requestId })));
|
|
@@ -84,23 +88,23 @@ export function connectWorkflowWatch(url, input, token, signal) {
|
|
|
84
88
|
socket.on('message', (raw) => {
|
|
85
89
|
const parsedEnvelope = parseEnvelope(raw);
|
|
86
90
|
if (!parsedEnvelope.success) {
|
|
87
|
-
const error = new BridgeError('InvalidBridgeResponse', 'Bridge returned an invalid Workflow watch message', {
|
|
91
|
+
const error = new BridgeError('InvalidBridgeResponse', 'Bridge returned an invalid Workflow status watch message', {
|
|
88
92
|
status: 502,
|
|
89
93
|
cause: parsedEnvelope.error,
|
|
90
94
|
});
|
|
91
95
|
if (!acceptedClientId)
|
|
92
96
|
failBeforeAccept(error);
|
|
93
97
|
else {
|
|
94
|
-
socket.close(1007, 'Invalid Workflow watch message');
|
|
98
|
+
socket.close(1007, 'Invalid Workflow status watch message');
|
|
95
99
|
notifyClose(error);
|
|
96
100
|
}
|
|
97
101
|
return;
|
|
98
102
|
}
|
|
99
103
|
const message = parsedEnvelope.data;
|
|
100
|
-
if (message.type === 'workflow.watch:res' && message.id === requestId && !acceptedClientId) {
|
|
104
|
+
if (message.type === 'workflow.status.watch:res' && message.id === requestId && !acceptedClientId) {
|
|
101
105
|
const result = SafeResultSchema.safeParse(message.data);
|
|
102
106
|
if (!result.success) {
|
|
103
|
-
failBeforeAccept(new BridgeError('InvalidBridgeResponse', 'Bridge returned an invalid Workflow watch response', {
|
|
107
|
+
failBeforeAccept(new BridgeError('InvalidBridgeResponse', 'Bridge returned an invalid Workflow status watch response', {
|
|
104
108
|
status: 502,
|
|
105
109
|
}));
|
|
106
110
|
return;
|
|
@@ -114,7 +118,7 @@ export function connectWorkflowWatch(url, input, token, signal) {
|
|
|
114
118
|
}
|
|
115
119
|
const accepted = WorkflowStatusEventSchema.pick({ clientId: true, workflowId: true }).safeParse(result.data.data);
|
|
116
120
|
if (!accepted.success || accepted.data.workflowId !== input.workflowId) {
|
|
117
|
-
failBeforeAccept(new BridgeError('InvalidBridgeResponse', 'Bridge accepted a different Workflow watch target', {
|
|
121
|
+
failBeforeAccept(new BridgeError('InvalidBridgeResponse', 'Bridge accepted a different Workflow status watch target', {
|
|
118
122
|
status: 502,
|
|
119
123
|
}));
|
|
120
124
|
return;
|
|
@@ -143,7 +147,7 @@ export function connectWorkflowWatch(url, input, token, signal) {
|
|
|
143
147
|
resolve(connection);
|
|
144
148
|
return;
|
|
145
149
|
}
|
|
146
|
-
if (message.type !== 'workflow.status' || !acceptedClientId)
|
|
150
|
+
if (message.type !== 'workflow.status.changed' || !acceptedClientId)
|
|
147
151
|
return;
|
|
148
152
|
const event = WorkflowStatusEventSchema.safeParse(message.data);
|
|
149
153
|
if (!event.success)
|
|
@@ -172,7 +176,7 @@ export function connectWorkflowWatch(url, input, token, signal) {
|
|
|
172
176
|
response.once('end', () => {
|
|
173
177
|
const body = Buffer.concat(chunks).toString('utf8');
|
|
174
178
|
let errorCode = 'BridgeRequestFailed';
|
|
175
|
-
let errorMessage = response.statusMessage || 'Bridge rejected the Workflow watch connection';
|
|
179
|
+
let errorMessage = response.statusMessage || 'Bridge rejected the Workflow status watch connection';
|
|
176
180
|
let details;
|
|
177
181
|
try {
|
|
178
182
|
const parsed = JSON.parse(body);
|
|
@@ -187,7 +191,7 @@ export function connectWorkflowWatch(url, input, token, signal) {
|
|
|
187
191
|
});
|
|
188
192
|
});
|
|
189
193
|
socket.on('error', (cause) => {
|
|
190
|
-
const error = new BridgeError('BridgeUnavailable', 'Unable to connect to Tapicker Bridge Workflow watch', {
|
|
194
|
+
const error = new BridgeError('BridgeUnavailable', 'Unable to connect to Tapicker Bridge Workflow status watch', {
|
|
191
195
|
status: 503,
|
|
192
196
|
cause,
|
|
193
197
|
});
|
|
@@ -199,13 +203,13 @@ export function connectWorkflowWatch(url, input, token, signal) {
|
|
|
199
203
|
socket.once('close', (code, reason) => {
|
|
200
204
|
cleanupAbortListener();
|
|
201
205
|
if (!acceptedClientId) {
|
|
202
|
-
failBeforeAccept(new BridgeError('
|
|
206
|
+
failBeforeAccept(new BridgeError('WorkflowStatusWatchClosed', 'Bridge closed the Workflow status watch connection before accepting it', {
|
|
203
207
|
status: 503,
|
|
204
208
|
details: { code, reason: reason.toString() },
|
|
205
209
|
}));
|
|
206
210
|
}
|
|
207
211
|
else if (!intentionalClose) {
|
|
208
|
-
notifyClose(new BridgeError('
|
|
212
|
+
notifyClose(new BridgeError('WorkflowStatusWatchClosed', 'Bridge closed the Workflow status watch connection', {
|
|
209
213
|
status: 503,
|
|
210
214
|
details: { code, reason: reason.toString() },
|
|
211
215
|
}));
|
|
@@ -227,12 +231,12 @@ export function waitForWorkflowStatus(options) {
|
|
|
227
231
|
if (abortListener)
|
|
228
232
|
options.signal?.removeEventListener('abort', abortListener);
|
|
229
233
|
};
|
|
230
|
-
const finish = (status,
|
|
234
|
+
const finish = (status, isTimedOut = false) => {
|
|
231
235
|
if (settled)
|
|
232
236
|
return;
|
|
233
237
|
settled = true;
|
|
234
238
|
cleanup();
|
|
235
|
-
resolve({ ...status,
|
|
239
|
+
resolve({ ...status, isTimedOut });
|
|
236
240
|
};
|
|
237
241
|
const fail = (error) => {
|
|
238
242
|
if (settled)
|
|
@@ -246,6 +250,8 @@ export function waitForWorkflowStatus(options) {
|
|
|
246
250
|
return;
|
|
247
251
|
if (status.clientId !== options.clientId || status.workflowId !== options.workflowId)
|
|
248
252
|
return;
|
|
253
|
+
if (options.runAt !== undefined && status.runAt !== options.runAt)
|
|
254
|
+
return;
|
|
249
255
|
if (latestStatus && sameStatus(latestStatus, status))
|
|
250
256
|
return;
|
|
251
257
|
latestStatus = status;
|
|
@@ -256,11 +262,11 @@ export function waitForWorkflowStatus(options) {
|
|
|
256
262
|
fail(error);
|
|
257
263
|
return;
|
|
258
264
|
}
|
|
259
|
-
if (
|
|
265
|
+
if (status.status === 'stopped')
|
|
260
266
|
finish(status);
|
|
261
267
|
};
|
|
262
268
|
if (options.signal?.aborted) {
|
|
263
|
-
fail(new BridgeError('
|
|
269
|
+
fail(new BridgeError('WorkflowStatusWatchCancelled', 'Workflow status watch was cancelled', { status: 499 }));
|
|
264
270
|
return;
|
|
265
271
|
}
|
|
266
272
|
unsubscribe = options.subscribe(publish, fail);
|
|
@@ -269,7 +275,7 @@ export function waitForWorkflowStatus(options) {
|
|
|
269
275
|
return;
|
|
270
276
|
}
|
|
271
277
|
if (options.signal) {
|
|
272
|
-
abortListener = () => fail(new BridgeError('
|
|
278
|
+
abortListener = () => fail(new BridgeError('WorkflowStatusWatchCancelled', 'Workflow status watch was cancelled', { status: 499 }));
|
|
273
279
|
options.signal.addEventListener('abort', abortListener, { once: true });
|
|
274
280
|
}
|
|
275
281
|
if (options.timeoutMs !== undefined) {
|
|
@@ -277,13 +283,13 @@ export function waitForWorkflowStatus(options) {
|
|
|
277
283
|
if (latestStatus)
|
|
278
284
|
finish(latestStatus, true);
|
|
279
285
|
else
|
|
280
|
-
fail(new BridgeError('
|
|
286
|
+
fail(new BridgeError('WorkflowStatusWatchTimeout', 'Timed out before receiving Workflow status', {
|
|
281
287
|
status: 504,
|
|
282
288
|
details: { timeoutMs: options.timeoutMs },
|
|
283
289
|
}));
|
|
284
290
|
}, options.timeoutMs);
|
|
285
291
|
}
|
|
286
|
-
|
|
292
|
+
options
|
|
287
293
|
.readStatus()
|
|
288
294
|
.then((snapshot) => {
|
|
289
295
|
if (settled)
|
|
@@ -291,7 +297,7 @@ export function waitForWorkflowStatus(options) {
|
|
|
291
297
|
const snapshotIsAtLeastAsNew = latestStatus !== undefined && Date.parse(snapshot.updatedAt) >= Date.parse(latestStatus.updatedAt);
|
|
292
298
|
if (!latestStatus ||
|
|
293
299
|
snapshotIsAtLeastAsNew ||
|
|
294
|
-
(
|
|
300
|
+
(snapshot.status === 'stopped' && latestStatus.status !== 'stopped')) {
|
|
295
301
|
publish(snapshot);
|
|
296
302
|
}
|
|
297
303
|
})
|
|
@@ -299,6 +305,10 @@ export function waitForWorkflowStatus(options) {
|
|
|
299
305
|
});
|
|
300
306
|
}
|
|
301
307
|
function sameStatus(left, right) {
|
|
302
|
-
return left.
|
|
308
|
+
return (left.status === right.status &&
|
|
309
|
+
left.reason === right.reason &&
|
|
310
|
+
left.runAt === right.runAt &&
|
|
311
|
+
left.stopAt === right.stopAt &&
|
|
312
|
+
left.updatedAt === right.updatedAt);
|
|
303
313
|
}
|
|
304
314
|
//# sourceMappingURL=workflow-watch.js.map
|
package/package.json
CHANGED
|
@@ -1,8 +1,20 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@tapicker/bridge",
|
|
3
|
-
"version": "1.
|
|
3
|
+
"version": "1.1.0",
|
|
4
4
|
"description": "Tapicker local and remote command bridge",
|
|
5
|
-
"
|
|
5
|
+
"keywords": [
|
|
6
|
+
"tapicker",
|
|
7
|
+
"web-automation",
|
|
8
|
+
"browser-automation",
|
|
9
|
+
"web-scraping",
|
|
10
|
+
"data-extraction",
|
|
11
|
+
"chrome-extension",
|
|
12
|
+
"ai-agents",
|
|
13
|
+
"mcp",
|
|
14
|
+
"mcp-server",
|
|
15
|
+
"cli"
|
|
16
|
+
],
|
|
17
|
+
"homepage": "https://www.tapicker.com",
|
|
6
18
|
"license": "MIT",
|
|
7
19
|
"type": "module",
|
|
8
20
|
"main": "dist/index.js",
|
|
@@ -19,9 +31,7 @@
|
|
|
19
31
|
"files": [
|
|
20
32
|
"dist/**/*.js",
|
|
21
33
|
"dist/**/*.d.ts",
|
|
22
|
-
"
|
|
23
|
-
"README.md",
|
|
24
|
-
"docs"
|
|
34
|
+
"README.md"
|
|
25
35
|
],
|
|
26
36
|
"scripts": {
|
|
27
37
|
"build": "tsc -p tsconfig.json",
|
|
@@ -49,7 +59,7 @@
|
|
|
49
59
|
"@types/node": "^22.0.0",
|
|
50
60
|
"@types/ws": "^8.5.13",
|
|
51
61
|
"prettier": "^3.6.0",
|
|
52
|
-
"typescript": "
|
|
62
|
+
"typescript": "6.0.3",
|
|
53
63
|
"vitest": "^4.0.0"
|
|
54
64
|
}
|
|
55
65
|
}
|
package/docs/cli.md
DELETED
|
@@ -1,112 +0,0 @@
|
|
|
1
|
-
# CLI Reference
|
|
2
|
-
|
|
3
|
-
The examples below assume the package is installed globally and the `tapicker` command is available in `PATH`. Start with the [Getting Started guide](https://www.tapicker.com/docs/bridge-getting-started). Run `tapicker --help` or `tapicker <command> --help` for concise command help.
|
|
4
|
-
|
|
5
|
-
## Start and Manage Bridge
|
|
6
|
-
|
|
7
|
-
```bash
|
|
8
|
-
tapicker bridge start [options]
|
|
9
|
-
tapicker bridge stop [--data-dir <path>]
|
|
10
|
-
tapicker bridge code [--refresh] [--data-dir <path>]
|
|
11
|
-
tapicker bridge extensions [--data-dir <path>]
|
|
12
|
-
```
|
|
13
|
-
|
|
14
|
-
| Command | Purpose |
|
|
15
|
-
| ----------------------- | ----------------------------------------------------------------------------------------------- |
|
|
16
|
-
| `bridge start` | Run in the foreground; press `Ctrl+C` to stop. Prints the listening addresses and pairing code. |
|
|
17
|
-
| `bridge start --daemon` | Run in the background. |
|
|
18
|
-
| `bridge stop` | Stop a background Bridge. |
|
|
19
|
-
| `bridge code` | Display the current four-digit pairing code. |
|
|
20
|
-
| `bridge code --refresh` | Rotate the pairing code and unlock pairing after rate limiting. |
|
|
21
|
-
| `bridge extensions` | List connected Extension clients, including clients that have not finished pairing. |
|
|
22
|
-
|
|
23
|
-
### `bridge start` Options
|
|
24
|
-
|
|
25
|
-
| Option | Default | Description |
|
|
26
|
-
| ---------------------------------------- | --------------------------------------- | ----------------------------------------------------------------------- |
|
|
27
|
-
| `--host <host>` | `127.0.0.1` | Bind address. Non-loopback binding requires a Token and TLS. |
|
|
28
|
-
| `--port <port>` | First available port from `9520`–`9530` | Set a fixed listening port. |
|
|
29
|
-
| `--token <token>` | `TAPICKER_BRIDGE_TOKEN` or none | Bearer Token for protected HTTP, MCP, and status subscription requests. |
|
|
30
|
-
| `--cors-origin <origins>` | `*` | Comma-separated allowlist of HTTP origins. |
|
|
31
|
-
| `--tls-key <path>` / `--tls-cert <path>` | None | TLS private key and certificate; provide both for remote binding. |
|
|
32
|
-
| `--data-dir <path>` | `TAPICKER_DATA_DIR` or `~/.tapicker` | Directory for pairing credentials and daemon files. |
|
|
33
|
-
| `--daemon` | Off | Run in the background. |
|
|
34
|
-
|
|
35
|
-
If you use a custom `--data-dir`, pass the same directory to `stop`, `code`, and `extensions`.
|
|
36
|
-
|
|
37
|
-
## Control a Workflow
|
|
38
|
-
|
|
39
|
-
```bash
|
|
40
|
-
tapicker workflow start <workflowId> [options]
|
|
41
|
-
tapicker workflow pause <workflowId> [options]
|
|
42
|
-
tapicker workflow resume <workflowId> [options]
|
|
43
|
-
tapicker workflow stop <workflowId> [options]
|
|
44
|
-
tapicker workflow status <workflowId> [options]
|
|
45
|
-
tapicker workflow watch <workflowId> [options]
|
|
46
|
-
```
|
|
47
|
-
|
|
48
|
-
Start with an input object and stream status updates:
|
|
49
|
-
|
|
50
|
-
```bash
|
|
51
|
-
tapicker workflow start jr657xeb --args '{"keyword":"Tapicker"}' --watch
|
|
52
|
-
```
|
|
53
|
-
|
|
54
|
-
Other tab targets are `new` and `id:<positive-tabId>`:
|
|
55
|
-
|
|
56
|
-
```bash
|
|
57
|
-
tapicker workflow start jr657xeb --tab new
|
|
58
|
-
tapicker workflow start jr657xeb --tab id:123
|
|
59
|
-
```
|
|
60
|
-
|
|
61
|
-
`--args` must be a JSON object. The default is `{}`. `--tab` defaults to `active`.
|
|
62
|
-
|
|
63
|
-
| Option | Default | Description |
|
|
64
|
-
| -------------------------- | ----------------------------------------------- | ---------------------------------------------------------------------------- |
|
|
65
|
-
| `--host <host>` | `127.0.0.1` | Bridge host. |
|
|
66
|
-
| `--port <port>` | `9520` | Bridge port. Pass the actual port if Bridge selected another one. |
|
|
67
|
-
| `--token <token>` | None | Bridge Bearer Token. |
|
|
68
|
-
| `--client-id <uuid>` | Auto-select when exactly one Extension is ready | Select an Extension when multiple are ready. |
|
|
69
|
-
| `--https` | Off | Use HTTPS and WSS instead of HTTP and WS. |
|
|
70
|
-
| `--args <json>` | `{}` | Workflow input object; `start` only. |
|
|
71
|
-
| `--tab <target>` | `active` | `active`, `new`, or `id:<positive-tabId>`; `start` only. |
|
|
72
|
-
| `--watch` | Off | After starting, stream updates until a terminal state; `start` only. |
|
|
73
|
-
| `--timeout <milliseconds>` | No limit | Limit how long `watch` or `start --watch` waits. Does not stop the Workflow. |
|
|
74
|
-
|
|
75
|
-
`start --watch` establishes the watch before starting the Workflow to avoid missing initial status changes. `workflow watch` listens to a Workflow that is already running; it does not start or control it. A watch timeout or `Ctrl+C` ends only the listener, not the Workflow. Output is newline-delimited JSON.
|
|
76
|
-
|
|
77
|
-
The start response includes `workflowId`, the full `workflowName`, and the selected `clientId`. A Workflow supports one active instance at a time in its Extension.
|
|
78
|
-
|
|
79
|
-
## Select an Extension
|
|
80
|
-
|
|
81
|
-
List clients first:
|
|
82
|
-
|
|
83
|
-
```bash
|
|
84
|
-
tapicker bridge extensions
|
|
85
|
-
```
|
|
86
|
-
|
|
87
|
-
Pass `--client-id <uuid>` to target one ready Extension. You can omit it only when exactly one ready Extension is connected. Pending pairing connections are not command targets. Bridge never broadcasts a command to every Extension.
|
|
88
|
-
|
|
89
|
-
## Read or Delete Extracted Data
|
|
90
|
-
|
|
91
|
-
```bash
|
|
92
|
-
tapicker data get <tableId> [options]
|
|
93
|
-
tapicker data delete <tableId> [options]
|
|
94
|
-
```
|
|
95
|
-
|
|
96
|
-
Get all rows from a data table:
|
|
97
|
-
|
|
98
|
-
```bash
|
|
99
|
-
tapicker data get 4a1b2c3d
|
|
100
|
-
```
|
|
101
|
-
|
|
102
|
-
`tableId` is copied from the Extension’s Data list or detail page. `data get` returns `tableId`, `tableName`, the row count, and all rows. The row count consumes the connected Extension account’s export quota; if quota is insufficient or unavailable, the command fails without returning the data. `data delete` removes the table from Tapicker Data.
|
|
103
|
-
|
|
104
|
-
Data commands accept `--host`, `--port`, `--token`, `--client-id`, and `--https`.
|
|
105
|
-
|
|
106
|
-
## Connect an MCP Client over stdio
|
|
107
|
-
|
|
108
|
-
```bash
|
|
109
|
-
tapicker mcp [--url <http(s)://host:port>] [--token <token>]
|
|
110
|
-
```
|
|
111
|
-
|
|
112
|
-
This starts an MCP stdio adapter that connects to an already-running Bridge over HTTP. It does not start another Bridge server. The default URL is `http://127.0.0.1:9520`; set `TAPICKER_BRIDGE_URL` and `TAPICKER_BRIDGE_TOKEN` in the MCP client environment when needed. See the [MCP guide](mcp.md) for client configuration examples.
|
package/docs/http-api.md
DELETED
|
@@ -1,149 +0,0 @@
|
|
|
1
|
-
# HTTP API Reference
|
|
2
|
-
|
|
3
|
-
Bridge serves HTTP, WebSocket, and MCP from one port. The default local base URL is `http://127.0.0.1:9520`. At startup, Bridge tries ports `9520`–`9530` and prints the actual address. Use that address in every client.
|
|
4
|
-
|
|
5
|
-
For installation and setup, see the [Getting Started guide](https://www.tapicker.com/docs/bridge-getting-started). For a short integration walkthrough, see [Connect an AI Agent](https://www.tapicker.com/docs/bridge-ai-agents).
|
|
6
|
-
|
|
7
|
-
## Endpoints
|
|
8
|
-
|
|
9
|
-
| Method / transport | Path | Token required when configured? | Purpose |
|
|
10
|
-
| ------------------- | ----------------------------- | ------------------------------- | ------------------------------------------------------ |
|
|
11
|
-
| `GET` | `/v1/health` | No | Check Bridge health. |
|
|
12
|
-
| `GET` | `/v1/discovery` | No | Read Bridge metadata and the Extension WebSocket path. |
|
|
13
|
-
| `GET` | `/v1/capabilities` | No | Discover commands and their input schemas. |
|
|
14
|
-
| `GET` | `/v1/extensions` | Yes | List connected Extension clients. |
|
|
15
|
-
| `POST` | `/v1/commands/{command}` | Yes | Call a Workflow or data command. |
|
|
16
|
-
| WebSocket | `/v1/commands/workflow.watch` | Yes | Subscribe to one Workflow’s status events. |
|
|
17
|
-
| Streamable HTTP MCP | `/mcp` | Yes | Connect a remote MCP client. |
|
|
18
|
-
| WebSocket | `/ws` | Pairing credential | Extension pairing and internal command transport. |
|
|
19
|
-
|
|
20
|
-
When Bridge is started with a Token, protected requests must include:
|
|
21
|
-
|
|
22
|
-
```http
|
|
23
|
-
Authorization: Bearer YOUR_TOKEN
|
|
24
|
-
```
|
|
25
|
-
|
|
26
|
-
`/ws` is for Tapicker Extension connections, not external Agent commands. It uses the pairing code and saved Extension credential, not the HTTP Bearer Token.
|
|
27
|
-
|
|
28
|
-
## CORS and Local Security
|
|
29
|
-
|
|
30
|
-
HTTP and `/mcp` allow all web origins by default (`--cors-origin *`) and support browser `OPTIONS` preflight requests. Use one comma-separated allowlist to restrict origins:
|
|
31
|
-
|
|
32
|
-
```bash
|
|
33
|
-
tapicker bridge start --cors-origin https://agent.example.com,https://app.example.com
|
|
34
|
-
```
|
|
35
|
-
|
|
36
|
-
CORS is not authentication. The default local Bridge has no Bearer Token, so a web page may be able to call its local HTTP API. Keep Bridge bound to `127.0.0.1`, and set an origin allowlist when browser access should be limited. WebSocket connections do not use CORS.
|
|
37
|
-
|
|
38
|
-
## Discover Bridge and Extensions
|
|
39
|
-
|
|
40
|
-
```bash
|
|
41
|
-
curl http://127.0.0.1:9520/v1/health
|
|
42
|
-
curl http://127.0.0.1:9520/v1/discovery
|
|
43
|
-
curl http://127.0.0.1:9520/v1/capabilities
|
|
44
|
-
curl http://127.0.0.1:9520/v1/extensions
|
|
45
|
-
```
|
|
46
|
-
|
|
47
|
-
`/v1/health` reports Bridge health, not Extension readiness. `/v1/extensions` returns connected clients, for example:
|
|
48
|
-
|
|
49
|
-
```json
|
|
50
|
-
{
|
|
51
|
-
"extensions": [
|
|
52
|
-
{
|
|
53
|
-
"clientId": "56a450e6-41f1-448e-9ea7-a2d958cbda37",
|
|
54
|
-
"clientName": "MacOS.Chrome.152.a1b2",
|
|
55
|
-
"connected": true,
|
|
56
|
-
"ready": true,
|
|
57
|
-
"pairingRequired": false,
|
|
58
|
-
"capabilities": ["workflow.start", "workflow.pause"]
|
|
59
|
-
}
|
|
60
|
-
]
|
|
61
|
-
}
|
|
62
|
-
```
|
|
63
|
-
|
|
64
|
-
Only `ready: true` clients can receive commands. The list does not expose pairing codes or saved credentials. Add the Bearer header to `/v1/extensions` when a Token is configured.
|
|
65
|
-
|
|
66
|
-
`/v1/capabilities` lists supported commands, descriptions, JSON input schemas, and the WebSocket path for `workflow.watch`.
|
|
67
|
-
|
|
68
|
-
## Call a Command
|
|
69
|
-
|
|
70
|
-
All HTTP command requests use this shape:
|
|
71
|
-
|
|
72
|
-
```json
|
|
73
|
-
{
|
|
74
|
-
"clientId": "optional-extension-uuid",
|
|
75
|
-
"input": {
|
|
76
|
-
"workflowId": "jr657xeb"
|
|
77
|
-
}
|
|
78
|
-
}
|
|
79
|
-
```
|
|
80
|
-
|
|
81
|
-
`clientId` is optional only when exactly one ready Extension is connected. If multiple are ready, specify one; Bridge returns `409 ClientIdRequired` rather than broadcasting the command. Pending pairing connections are not eligible targets.
|
|
82
|
-
|
|
83
|
-
| Command | `input` |
|
|
84
|
-
| ----------------- | ---------------------------------------------------------------------------------------------------- |
|
|
85
|
-
| `workflow.start` | `workflowId`; optional `args` object (default `{}`); optional `tab` (default `{ "mode": "active" }`) |
|
|
86
|
-
| `workflow.pause` | `workflowId` |
|
|
87
|
-
| `workflow.resume` | `workflowId` |
|
|
88
|
-
| `workflow.stop` | `workflowId` |
|
|
89
|
-
| `workflow.status` | `workflowId` |
|
|
90
|
-
| `data.get` | `tableId` |
|
|
91
|
-
| `data.delete` | `tableId` |
|
|
92
|
-
|
|
93
|
-
`tab` can be `{ "mode": "active" }`, `{ "mode": "new" }`, or `{ "mode": "id", "tabId": 123 }`.
|
|
94
|
-
|
|
95
|
-
Start a Workflow:
|
|
96
|
-
|
|
97
|
-
```bash
|
|
98
|
-
curl -X POST http://127.0.0.1:9520/v1/commands/workflow.start \
|
|
99
|
-
-H 'Content-Type: application/json' \
|
|
100
|
-
-d '{"input":{"workflowId":"jr657xeb","args":{"keyword":"Tapicker"},"tab":{"mode":"active"}}}'
|
|
101
|
-
```
|
|
102
|
-
|
|
103
|
-
If a Token is configured, add `-H 'Authorization: Bearer YOUR_TOKEN'`.
|
|
104
|
-
|
|
105
|
-
Pause, resume, stop, and status use the same request format. For example:
|
|
106
|
-
|
|
107
|
-
```bash
|
|
108
|
-
curl -X POST http://127.0.0.1:9520/v1/commands/workflow.pause \
|
|
109
|
-
-H 'Content-Type: application/json' \
|
|
110
|
-
-d '{"clientId":"56a450e6-41f1-448e-9ea7-a2d958cbda37","input":{"workflowId":"jr657xeb"}}'
|
|
111
|
-
```
|
|
112
|
-
|
|
113
|
-
A successful start response includes the selected `clientId`, `workflowId`, full `workflowName`, and an accepted state. Other successful responses use `{ "ok": true, "data": ... }`. Errors use `{ "ok": false, "error": { "code", "message", "details?" } }`.
|
|
114
|
-
|
|
115
|
-
## Read or Delete a Data Table
|
|
116
|
-
|
|
117
|
-
Use the `tableId` copied from the Extension’s Data list or detail page:
|
|
118
|
-
|
|
119
|
-
```bash
|
|
120
|
-
curl -X POST http://127.0.0.1:9520/v1/commands/data.get \
|
|
121
|
-
-H 'Content-Type: application/json' \
|
|
122
|
-
-d '{"input":{"tableId":"4a1b2c3d"}}'
|
|
123
|
-
```
|
|
124
|
-
|
|
125
|
-
`data.get` returns `tableId`, `tableName`, `count`, and all `rows`. The row count consumes the connected Extension account’s export quota. If the quota is insufficient or unavailable, Bridge returns an error without the data.
|
|
126
|
-
|
|
127
|
-
Delete a table with `POST /v1/commands/data.delete` and the same `input` shape. It removes the table from Tapicker Data; verify the `tableId` before deleting. The success response contains `tableId` and `tableName`.
|
|
128
|
-
|
|
129
|
-
## Get Workflow Status
|
|
130
|
-
|
|
131
|
-
`workflow.status` returns one snapshot with `workflowId`, `state`, and ISO-formatted `updatedAt`. States include `running`, `paused`, `stopping`, `completed`, `stopped`, and `failed`.
|
|
132
|
-
|
|
133
|
-
For ongoing updates, subscribe to the WebSocket endpoint `/v1/commands/workflow.watch` instead of repeatedly calling `workflow.status`. After reconnecting, call `workflow.status` once to get the latest snapshot. See [Workflow Status WebSocket](workflow-watch.md).
|
|
134
|
-
|
|
135
|
-
The `workflow.watch` path requires a WebSocket upgrade; a regular HTTP request returns `405 WebSocketRequired`.
|
|
136
|
-
|
|
137
|
-
## Common Errors
|
|
138
|
-
|
|
139
|
-
| HTTP status | Example codes | Meaning |
|
|
140
|
-
| ----------- | ----------------------------------------------------------------------------- | ------------------------------------------------------ |
|
|
141
|
-
| `400` | `InvalidArguments`, `InvalidJson` | The request body or command input is invalid. |
|
|
142
|
-
| `401` | `Unauthorized` | A required Bearer Token is missing or invalid. |
|
|
143
|
-
| `404` | `NotFound`, `CommandNotFound` | The endpoint or command does not exist. |
|
|
144
|
-
| `409` | `ClientIdRequired`, `ExtensionNotConnected`, `ExtensionCapabilityUnavailable` | Select a ready Extension or check its availability. |
|
|
145
|
-
| `502` | `ExportQuotaExceeded` | Reading the table exceeded the account’s export quota. |
|
|
146
|
-
| `503` | `ExtensionUnavailable` | No paired, ready Extension is connected. |
|
|
147
|
-
| `504` | `ExtensionRequestTimeout` | The Extension did not respond in time. |
|
|
148
|
-
|
|
149
|
-
Use the returned `error.code` and `error.message` as the source of truth for a specific failure.
|
package/docs/mcp.md
DELETED
|
@@ -1,90 +0,0 @@
|
|
|
1
|
-
# MCP Guide
|
|
2
|
-
|
|
3
|
-
Tapicker Bridge exposes Workflow and data commands as MCP tools. The Bridge must already be running, and the target Tapicker Extension must be paired and ready.
|
|
4
|
-
|
|
5
|
-
For a first-time setup, follow the [Getting Started guide](https://www.tapicker.com/docs/bridge-getting-started). For an overview of the user flow, see [Connect an AI Agent](https://www.tapicker.com/docs/bridge-ai-agents).
|
|
6
|
-
|
|
7
|
-
## Choose a Transport
|
|
8
|
-
|
|
9
|
-
| Transport | How the agent connects | Best for |
|
|
10
|
-
| --------------- | -------------------------------------------------------------------- | ------------------------------------------------------ |
|
|
11
|
-
| stdio | The agent starts `tapicker mcp`, which connects to Bridge over HTTP. | An agent running on the same computer as Bridge. |
|
|
12
|
-
| Streamable HTTP | The agent connects directly to `https://<host>:<port>/mcp`. | A remote Bridge and an agent that supports remote MCP. |
|
|
13
|
-
|
|
14
|
-
Both transports expose the same tools. The stdio adapter does not start a Bridge server.
|
|
15
|
-
|
|
16
|
-
## Local MCP over stdio
|
|
17
|
-
|
|
18
|
-
Start Bridge separately, then add an MCP server entry to your agent configuration:
|
|
19
|
-
|
|
20
|
-
```json
|
|
21
|
-
{
|
|
22
|
-
"mcpServers": {
|
|
23
|
-
"tapicker": {
|
|
24
|
-
"command": "tapicker",
|
|
25
|
-
"args": ["mcp"],
|
|
26
|
-
"env": {
|
|
27
|
-
"TAPICKER_BRIDGE_URL": "http://127.0.0.1:9520"
|
|
28
|
-
}
|
|
29
|
-
}
|
|
30
|
-
}
|
|
31
|
-
}
|
|
32
|
-
```
|
|
33
|
-
|
|
34
|
-
Restart or reload the agent after changing its configuration. The CLI defaults to `http://127.0.0.1:9520`; if Bridge selected another port, update `TAPICKER_BRIDGE_URL` to the actual HTTP address printed at startup.
|
|
35
|
-
|
|
36
|
-
When the Bridge uses a Token, add `TAPICKER_BRIDGE_TOKEN` to the MCP server environment. Prefer environment variables or your agent’s secret store over putting a Token in a shared config file.
|
|
37
|
-
|
|
38
|
-
If the agent cannot find `tapicker`, set `command` to the absolute path of the installed executable. When running from a source checkout, use `node` as the command and the absolute path to `dist/cli.js` followed by `mcp` as the arguments.
|
|
39
|
-
|
|
40
|
-
You can also launch the adapter manually:
|
|
41
|
-
|
|
42
|
-
```bash
|
|
43
|
-
tapicker mcp --url http://127.0.0.1:9520
|
|
44
|
-
```
|
|
45
|
-
|
|
46
|
-
## Remote MCP over Streamable HTTP
|
|
47
|
-
|
|
48
|
-
The MCP endpoint uses the same port as HTTP and WebSocket:
|
|
49
|
-
|
|
50
|
-
```text
|
|
51
|
-
https://bridge.example.com:9520/mcp
|
|
52
|
-
```
|
|
53
|
-
|
|
54
|
-
Configure the agent’s remote MCP connection with this URL. If Bridge uses a Token, configure this request header:
|
|
55
|
-
|
|
56
|
-
```http
|
|
57
|
-
Authorization: Bearer YOUR_TOKEN
|
|
58
|
-
```
|
|
59
|
-
|
|
60
|
-
Remote deployments require TLS and a Bearer Token. See [Pairing, Configuration, and Security](operations.md).
|
|
61
|
-
|
|
62
|
-
## Available Tools
|
|
63
|
-
|
|
64
|
-
| Tool | Parameters | Purpose |
|
|
65
|
-
| ----------------- | ------------------------------------------------ | ------------------------------------------------------------- |
|
|
66
|
-
| `extensions_list` | None | List Extension clients and find a target `clientId`. |
|
|
67
|
-
| `workflow_start` | `workflowId`, optional `args`, `tab`, `clientId` | Start a Workflow. Returns when the start request is accepted. |
|
|
68
|
-
| `workflow_pause` | `workflowId`, optional `clientId` | Pause an active Workflow. |
|
|
69
|
-
| `workflow_resume` | `workflowId`, optional `clientId` | Resume a paused Workflow. |
|
|
70
|
-
| `workflow_stop` | `workflowId`, optional `clientId` | Stop an active Workflow. |
|
|
71
|
-
| `workflow_status` | `workflowId`, optional `clientId` | Get one current or most recently persisted status snapshot. |
|
|
72
|
-
| `workflow_watch` | `workflowId`, optional `clientId`, `timeoutMs` | Wait for status updates until a terminal state or timeout. |
|
|
73
|
-
| `data_get` | `tableId`, optional `clientId` | Read all rows from a data table; consumes export quota. |
|
|
74
|
-
| `data_delete` | `tableId`, optional `clientId` | Delete a data table from Tapicker Data. |
|
|
75
|
-
|
|
76
|
-
`workflow_start.tab` accepts `{ "mode": "active" }`, `{ "mode": "new" }`, or `{ "mode": "id", "tabId": 123 }`; it defaults to the active tab. `args` must be an object.
|
|
77
|
-
|
|
78
|
-
`data_get` returns `tableId`, `tableName`, and all rows. The row count consumes the connected Extension account’s export quota; when the quota is insufficient or unavailable, the operation fails without returning data. `data_delete` removes the table, so verify the `tableId` first.
|
|
79
|
-
|
|
80
|
-
## Select an Extension
|
|
81
|
-
|
|
82
|
-
If exactly one ready Extension is connected, `clientId` can be omitted. If multiple are ready, call `extensions_list` and pass the chosen `clientId` to the command. Pending pairing connections may appear in the list but are not command targets. Bridge sends each command to one Extension; it does not broadcast.
|
|
83
|
-
|
|
84
|
-
## Watch a Long-Running Workflow
|
|
85
|
-
|
|
86
|
-
`workflow_start` returns after the Extension accepts the start request. Then call `workflow_watch` to wait for updates without repeatedly calling `workflow_status`. Its terminal states are `completed`, `stopped`, and `failed`.
|
|
87
|
-
|
|
88
|
-
When supported by the MCP client, Bridge also reports intermediate status updates as progress. A `timeoutMs` expiration returns the latest known status with `timedOut: true`. Cancelling the watch stops waiting only; it does not stop the Workflow. Use `workflow_status` when you need a single snapshot.
|
|
89
|
-
|
|
90
|
-
The equivalent HTTP/WebSocket protocol is documented in [Workflow Status WebSocket](workflow-watch.md).
|