@unbrowse/sdk 11.7.0 → 12.0.0-preview.2
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/README.md +60 -34
- package/dist/client.d.ts +122 -183
- package/dist/index.d.ts +4 -11
- package/dist/index.js +186 -6
- package/dist/mcp-install.d.ts +9 -0
- package/dist/types.d.ts +122 -0
- package/package.json +17 -32
- package/LICENSE +0 -21
- package/dist/client.d.ts.map +0 -1
- package/dist/client.js +0 -503
- package/dist/client.js.map +0 -1
- package/dist/contracts.d.ts +0 -478
- package/dist/contracts.d.ts.map +0 -1
- package/dist/contracts.js +0 -2
- package/dist/contracts.js.map +0 -1
- package/dist/errors.d.ts +0 -52
- package/dist/errors.d.ts.map +0 -1
- package/dist/errors.js +0 -76
- package/dist/errors.js.map +0 -1
- package/dist/flex.d.ts +0 -254
- package/dist/flex.d.ts.map +0 -1
- package/dist/flex.js +0 -396
- package/dist/flex.js.map +0 -1
- package/dist/index.d.ts.map +0 -1
- package/dist/index.js.map +0 -1
- package/dist/runtime.d.ts +0 -78
- package/dist/runtime.d.ts.map +0 -1
- package/dist/runtime.js +0 -339
- package/dist/runtime.js.map +0 -1
- package/dist/server-types.d.ts +0 -97
- package/dist/server-types.d.ts.map +0 -1
- package/dist/server-types.js +0 -2
- package/dist/server-types.js.map +0 -1
- package/dist/x402.d.ts +0 -75
- package/dist/x402.d.ts.map +0 -1
- package/dist/x402.js +0 -29
- package/dist/x402.js.map +0 -1
package/README.md
CHANGED
|
@@ -1,54 +1,80 @@
|
|
|
1
1
|
# @unbrowse/sdk
|
|
2
2
|
|
|
3
|
-
|
|
3
|
+
TypeScript client for the Unbrowse API (`https://unbrowse.ai/api/v1`). Node 18.17+, Bun, Deno,
|
|
4
|
+
or any runtime with `fetch`. No dependencies. The `unbrowse` CLI is built on it.
|
|
5
|
+
|
|
6
|
+
```bash
|
|
7
|
+
npm install https://github.com/unbrowse-ai/unbrowse-skill/releases/download/v12.0.0-alpha.1/unbrowse-sdk-12.0.0-alpha.1.tgz
|
|
8
|
+
```
|
|
4
9
|
|
|
5
10
|
```ts
|
|
6
|
-
import { Unbrowse } from
|
|
7
|
-
|
|
8
|
-
const
|
|
9
|
-
|
|
10
|
-
|
|
11
|
-
|
|
12
|
-
|
|
13
|
-
|
|
14
|
-
|
|
15
|
-
params: { q: 'books' },
|
|
16
|
-
});
|
|
11
|
+
import { Unbrowse } from "@unbrowse/sdk";
|
|
12
|
+
|
|
13
|
+
const ub = new Unbrowse(); // UNBROWSE_API_KEY, https://unbrowse.ai/api/v1
|
|
14
|
+
|
|
15
|
+
let run = await ub.run({ task: "top stories on Hacker News", idempotencyKey: crypto.randomUUID() });
|
|
16
|
+
run = await ub.wait(run.runId); // until it leaves accepted/working
|
|
17
|
+
|
|
18
|
+
// Discover actual capabilities and schemas before selecting a site-specific run.
|
|
19
|
+
console.log(await ub.discover("flight search"));
|
|
17
20
|
```
|
|
18
21
|
|
|
19
|
-
|
|
22
|
+
Pass an `idempotencyKey` when you may retry: the same key returns the same run instead of starting
|
|
23
|
+
a second one.
|
|
20
24
|
|
|
21
|
-
|
|
25
|
+
`new Unbrowse({ apiKey, baseUrl, fetch })`: `apiKey` defaults to `UNBROWSE_API_KEY` (an API key or
|
|
26
|
+
an OAuth access token); `baseUrl` takes an origin or an `/api/v1` URL and defaults to
|
|
27
|
+
`UNBROWSE_BASE_URL`, then v3. Public registry reads need no key.
|
|
22
28
|
|
|
23
|
-
|
|
29
|
+
## Runs
|
|
24
30
|
|
|
25
|
-
|
|
31
|
+
| Method | Route |
|
|
32
|
+
|---|---|
|
|
33
|
+
| `run({ task \| capability, targetUrl?, input?, interactionMode?, idempotencyKey? })` | `POST /runs` (key sent as `idempotency_key` + `Idempotency-Key`) |
|
|
34
|
+
| `inspect(runId)` | `GET /runs/:id` |
|
|
35
|
+
| `wait(runId, { timeoutMs? })` | polls `GET /runs/:id` |
|
|
36
|
+
| `events(runId)` | `GET /runs/:id/events` |
|
|
37
|
+
| `answer(runId, { field: value })` | `GET /runs/:id`, `POST /runs/:id/responses`, `GET /runs/:id` |
|
|
38
|
+
| `resume(runId, expectedStateRevision, responses)` | `POST /runs/:id/responses` |
|
|
39
|
+
| `cancel(runId)` | `POST /runs/:id/cancel` |
|
|
26
40
|
|
|
27
|
-
|
|
41
|
+
A run is `succeeded` only when its result is verified (`verified: true`). `input_required` is not a
|
|
42
|
+
failure: answer on the same run. `outcome_unknown` means a change may have happened; do not retry
|
|
43
|
+
blindly. A run whose site needs a login nobody saved carries `signIn.url`: give it to the person.
|
|
28
44
|
|
|
29
|
-
|
|
30
|
-
const operationKey = crypto.randomUUID(); // retain for this intended operation
|
|
31
|
-
await client.run({
|
|
32
|
-
url: 'https://example.com/api/items',
|
|
33
|
-
intent: 'Create the item requested by the user',
|
|
34
|
-
request: { method: 'POST', body: JSON.stringify({ name: 'Example' }) },
|
|
35
|
-
}, { headers: { 'Idempotency-Key': operationKey } });
|
|
36
|
-
```
|
|
45
|
+
## Capabilities and learning
|
|
37
46
|
|
|
38
|
-
|
|
47
|
+
| Method | Route |
|
|
48
|
+
|---|---|
|
|
49
|
+
| `discover(query)` | `POST /capabilities/search` |
|
|
50
|
+
| `capability(id)`, `skills()` | `GET /capabilities/:id`, `GET /skills` |
|
|
51
|
+
| `learn({ har \| traces, goal?, title? })` | `POST /learn` |
|
|
52
|
+
| `learned(id?)`, `harnessYaml(id)`, `skillMd(id)` | `GET /learned[/:id[/harness.yaml\|/skill.md]]` |
|
|
39
53
|
|
|
40
|
-
|
|
54
|
+
## Account, logins, vault
|
|
41
55
|
|
|
42
|
-
|
|
56
|
+
| Method | Route |
|
|
57
|
+
|---|---|
|
|
58
|
+
| `me()`, `usage()` | `GET /me`, `GET /usage` |
|
|
59
|
+
| `logins.list()`, `.save(login)`, `.remove({ origin } \| { ref })` | `/logins` — values in, masked hints out |
|
|
60
|
+
| `accounts.connect({ origin, username, password })`, `accounts.register({ origin, username })` | `/accounts/connections`, `/accounts/register` |
|
|
61
|
+
| `vault()` | `GET /vault` — refs and audit, never secrets |
|
|
43
62
|
|
|
44
|
-
|
|
63
|
+
## Public registry
|
|
45
64
|
|
|
46
|
-
|
|
65
|
+
| Method | Route |
|
|
66
|
+
|---|---|
|
|
67
|
+
| `sites(query?)`, `site(host)` | `GET /sites`, `GET /sites/:host` (no key) |
|
|
68
|
+
| `openapi(host)` | `GET /sites/:host/openapi.json` |
|
|
69
|
+
| `callTool(host, tool, input)` | `POST /sites/:host/call/:tool` (metered like a run) |
|
|
70
|
+
| `siteMcpUrl(host)` | the site as its own MCP server |
|
|
47
71
|
|
|
48
|
-
|
|
72
|
+
## Errors
|
|
49
73
|
|
|
50
|
-
|
|
74
|
+
Every failure throws `UnbrowseError` with `status`, `code` (the server's, e.g. `quota_exceeded`,
|
|
75
|
+
`unknown_argument`) and `body`.
|
|
51
76
|
|
|
52
|
-
|
|
77
|
+
## Install helpers
|
|
53
78
|
|
|
54
|
-
|
|
79
|
+
`mcpCommands(url)`, `cursorInstallLink(url)`, `vscodeInstallLink(url)` build install commands and
|
|
80
|
+
links for the hosted MCP (`https://unbrowse.ai/mcp`). They never carry a key.
|
package/dist/client.d.ts
CHANGED
|
@@ -1,188 +1,127 @@
|
|
|
1
|
-
import type {
|
|
2
|
-
|
|
3
|
-
|
|
4
|
-
|
|
5
|
-
|
|
6
|
-
|
|
1
|
+
import type { Json, RunRequest, RunView } from "./types.ts";
|
|
2
|
+
export declare const DEFAULT_BASE_URL = "https://unbrowse.ai/api/v1";
|
|
3
|
+
export type UnbrowseOptions = {
|
|
4
|
+
/** API key (`ub_live_…`) or OAuth access token. Defaults to `UNBROWSE_API_KEY`. Public routes need none. */
|
|
5
|
+
apiKey?: string;
|
|
6
|
+
/** Defaults to `UNBROWSE_BASE_URL` (origin or `/api/v1` URL), then https://unbrowse.ai/api/v1. */
|
|
7
|
+
baseUrl?: string;
|
|
8
|
+
fetch?: typeof globalThis.fetch;
|
|
9
|
+
};
|
|
10
|
+
/** An API error: the HTTP status, the server's error code and its body. */
|
|
11
|
+
export declare class UnbrowseError extends Error {
|
|
12
|
+
readonly status: number;
|
|
13
|
+
readonly code: string;
|
|
14
|
+
readonly body?: unknown | undefined;
|
|
15
|
+
constructor(message: string, status: number, code: string, body?: unknown | undefined);
|
|
16
|
+
}
|
|
7
17
|
export declare class Unbrowse {
|
|
8
18
|
readonly baseUrl: string;
|
|
9
|
-
|
|
10
|
-
|
|
11
|
-
|
|
12
|
-
private
|
|
13
|
-
private
|
|
14
|
-
private
|
|
15
|
-
|
|
16
|
-
|
|
17
|
-
|
|
18
|
-
|
|
19
|
-
|
|
20
|
-
|
|
21
|
-
|
|
22
|
-
|
|
23
|
-
/**
|
|
24
|
-
* Point at an already-running Unbrowse runtime. No probe, no spawn.
|
|
25
|
-
* `.close()` is a no-op for the runtime (the caller owns it).
|
|
26
|
-
*/
|
|
27
|
-
static connect(baseUrl: string, opts?: Omit<UnbrowseClientOptions, "baseUrl">): Promise<Unbrowse>;
|
|
28
|
-
/**
|
|
29
|
-
* Spawn a co-located Unbrowse runtime and return a client pointed at it.
|
|
30
|
-
* The client takes ownership of the child process: `.close()` will tear
|
|
31
|
-
* it down.
|
|
32
|
-
*/
|
|
33
|
-
static spawn(opts?: SpawnRuntimeOptions & Omit<UnbrowseClientOptions, "baseUrl">): Promise<Unbrowse>;
|
|
34
|
-
/**
|
|
35
|
-
* Probe 127.0.0.1 on the requested port (default 6969). Adopts a live
|
|
36
|
-
* runtime via `connect`; spawns a new one via `spawn` if dead. The
|
|
37
|
-
* resulting client only owns the runtime if it had to spawn.
|
|
38
|
-
*/
|
|
39
|
-
static local(opts?: SpawnRuntimeOptions & Omit<UnbrowseClientOptions, "baseUrl">): Promise<Unbrowse>;
|
|
40
|
-
/**
|
|
41
|
-
* Release any resources owned by this client. If the client spawned its
|
|
42
|
-
* own runtime, this kills the child process. Otherwise no-op.
|
|
43
|
-
*/
|
|
44
|
-
close(): Promise<void>;
|
|
45
|
-
private reportUsage;
|
|
46
|
-
request<T>(method: string, path: string, body?: unknown, options?: RequestOptions): Promise<T>;
|
|
47
|
-
run(input: ServerRunInput, options?: RequestOptions): Promise<ServerRunResult>;
|
|
48
|
-
registry(options?: RequestOptions): Promise<ServerRegistry>;
|
|
49
|
-
selectPrimitive(goal: string, options?: RequestOptions): Promise<ServerPrimitiveSelection>;
|
|
50
|
-
callPrimitive(input: ServerPrimitiveCall, options?: RequestOptions): Promise<ServerRunResult>;
|
|
51
|
-
runWorkflow(input: ServerWorkflow, options?: RequestOptions): Promise<ServerWorkflowResult>;
|
|
52
|
-
storeCredential(id: string, credential: import("./server-types.js").ServerCredential, options?: RequestOptions): Promise<{
|
|
53
|
-
id: string;
|
|
54
|
-
origin: string;
|
|
55
|
-
storage: "remote";
|
|
56
|
-
}>;
|
|
57
|
-
deleteCredential(id: string, options?: RequestOptions): Promise<{
|
|
58
|
-
deleted: true;
|
|
19
|
+
private apiKey?;
|
|
20
|
+
private fetchImpl;
|
|
21
|
+
constructor(opts?: UnbrowseOptions);
|
|
22
|
+
private send;
|
|
23
|
+
private req;
|
|
24
|
+
private post;
|
|
25
|
+
/**
|
|
26
|
+
* Start a run by capability id or plain-language task. `idempotencyKey` makes retries safe; the route
|
|
27
|
+
* reads it as `idempotency_key` or an `Idempotency-Key` header (camelCase in the body is ignored).
|
|
28
|
+
*/
|
|
29
|
+
run(request: RunRequest): Promise<RunView>;
|
|
30
|
+
inspect(runId: string): Promise<RunView>;
|
|
31
|
+
events(runId: string): Promise<{
|
|
32
|
+
events: RunView["events"];
|
|
59
33
|
}>;
|
|
60
|
-
resolve(input: ResolveInput, options?: RequestOptions): Promise<ResolveResponse>;
|
|
61
|
-
execute(skill: string | ExecuteInput | ResolveResponse, input?: Omit<ExecuteInput, "skillId">, options?: RequestOptions): Promise<ExecuteResponse>;
|
|
62
|
-
getSkill(skillId: string, options?: RequestOptions): Promise<SkillManifest>;
|
|
63
|
-
login(input: LoginInput, options?: RequestOptions): Promise<LoginResponse>;
|
|
64
|
-
importAuth(input: StealAuthInput, options?: RequestOptions): Promise<StealAuthResponse>;
|
|
65
|
-
stealAuth(input: StealAuthInput, options?: RequestOptions): Promise<StealAuthResponse>;
|
|
66
|
-
search(input: SearchInput, options?: RequestOptions): Promise<SearchResponse>;
|
|
67
|
-
searchDomain(input: SearchDomainInput, options?: RequestOptions): Promise<SearchResponse>;
|
|
68
|
-
/**
|
|
69
|
-
* Semantic search across ALL indexed endpoints (flat shape).
|
|
70
|
-
*
|
|
71
|
-
* Returns one row per endpoint, ranked by semantic match against the
|
|
72
|
-
* intent string. Use this when you want to pick endpoints across many
|
|
73
|
-
* skills (vs `search()` which groups by skill).
|
|
74
|
-
*
|
|
75
|
-
* Optional `domain` scopes the search to one host's endpoints; omit for
|
|
76
|
-
* cross-marketplace search. Authenticated agents are charged the
|
|
77
|
-
* standard search fee per the existing x402 economics; anonymous
|
|
78
|
-
* callers get free rate-limited public discovery.
|
|
79
|
-
*
|
|
80
|
-
* @example
|
|
81
|
-
* ```ts
|
|
82
|
-
* const { endpoints } = await u.searchEndpoints({ intent: "trending repositories", k: 5 });
|
|
83
|
-
* for (const ep of endpoints) {
|
|
84
|
-
* console.log(ep.score, ep.skill_id, ep.endpoint_id, ep.description);
|
|
85
|
-
* }
|
|
86
|
-
* ```
|
|
87
|
-
*/
|
|
88
|
-
searchEndpoints(input: SearchEndpointsInput, options?: RequestOptions): Promise<SearchEndpointsResponse>;
|
|
89
|
-
feedback(input: FeedbackInput, options?: RequestOptions): Promise<FeedbackResponse>;
|
|
90
|
-
stats(options?: RequestOptions): Promise<StatsResponse>;
|
|
91
|
-
health(options?: RequestOptions): Promise<HealthResponse>;
|
|
92
|
-
/**
|
|
93
|
-
* Earnings/spending dashboard for the authenticated agent.
|
|
94
|
-
* Requires `apiKey` set on the client. Backend: `GET /v1/dashboard/me`.
|
|
95
|
-
*/
|
|
96
|
-
dashboard(options?: RequestOptions): Promise<Dashboard>;
|
|
97
|
-
/**
|
|
98
|
-
* Public dashboard for any wallet address. Backend: `GET /v1/dashboard/wallet/:walletAddress`.
|
|
99
|
-
*/
|
|
100
|
-
dashboardByWallet(walletAddress: string, options?: RequestOptions): Promise<Dashboard>;
|
|
101
34
|
/**
|
|
102
|
-
*
|
|
103
|
-
*
|
|
104
|
-
*/
|
|
105
|
-
|
|
106
|
-
/**
|
|
107
|
-
|
|
108
|
-
|
|
109
|
-
|
|
110
|
-
|
|
111
|
-
|
|
112
|
-
|
|
113
|
-
|
|
114
|
-
|
|
115
|
-
|
|
116
|
-
|
|
117
|
-
|
|
118
|
-
|
|
119
|
-
|
|
120
|
-
|
|
121
|
-
|
|
122
|
-
|
|
123
|
-
|
|
124
|
-
|
|
125
|
-
|
|
126
|
-
|
|
127
|
-
|
|
128
|
-
|
|
129
|
-
|
|
130
|
-
|
|
131
|
-
|
|
132
|
-
|
|
133
|
-
|
|
134
|
-
|
|
135
|
-
|
|
136
|
-
|
|
137
|
-
|
|
138
|
-
|
|
139
|
-
|
|
140
|
-
|
|
141
|
-
|
|
142
|
-
|
|
143
|
-
|
|
144
|
-
|
|
145
|
-
|
|
146
|
-
|
|
147
|
-
|
|
148
|
-
|
|
149
|
-
|
|
150
|
-
|
|
151
|
-
|
|
152
|
-
|
|
153
|
-
|
|
154
|
-
|
|
155
|
-
|
|
156
|
-
|
|
157
|
-
|
|
158
|
-
|
|
159
|
-
|
|
160
|
-
|
|
161
|
-
|
|
162
|
-
|
|
163
|
-
|
|
164
|
-
|
|
165
|
-
|
|
166
|
-
|
|
167
|
-
|
|
168
|
-
|
|
169
|
-
|
|
170
|
-
|
|
171
|
-
|
|
172
|
-
|
|
173
|
-
|
|
174
|
-
|
|
175
|
-
|
|
176
|
-
/**
|
|
177
|
-
|
|
178
|
-
|
|
179
|
-
|
|
180
|
-
* SDK gap-fill: surface the Wave 2 backend route as a typed SDK
|
|
181
|
-
* method so SDK callers can sync provider choice without rolling
|
|
182
|
-
* a raw fetch. Allowed values are the same six the route whitelists:
|
|
183
|
-
* pay_sh / lobster_cash / external_solana / privy_embedded /
|
|
184
|
-
* privy_embedded_solana / skip.
|
|
185
|
-
*/
|
|
186
|
-
paymentProvider(provider: PaymentProvider, options?: RequestOptions): Promise<PaymentProviderResponse>;
|
|
35
|
+
* Answer a run's open requirements. The route reads snake_case (`requirement_id`, `expected_revision`);
|
|
36
|
+
* the documented camelCase (`requirementId`, `expectedRevision`) is converted here.
|
|
37
|
+
*/
|
|
38
|
+
resume(runId: string, expectedStateRevision: number, responses: Json[]): Promise<any>;
|
|
39
|
+
/** Answer open requirements by field name — `{ origin: "SIN" }` — and return the updated run. */
|
|
40
|
+
answer(runId: string, answers: Record<string, Json>): Promise<RunView>;
|
|
41
|
+
/** Poll a run until it leaves `accepted`/`working` (or the timeout passes). */
|
|
42
|
+
wait(runId: string, opts?: {
|
|
43
|
+
timeoutMs?: number;
|
|
44
|
+
}): Promise<RunView>;
|
|
45
|
+
cancel(runId: string): Promise<any>;
|
|
46
|
+
/** Your private capabilities first, then the public registry. */
|
|
47
|
+
discover(query: string): Promise<any>;
|
|
48
|
+
capability(id: string): Promise<any>;
|
|
49
|
+
skills(): Promise<any>;
|
|
50
|
+
/** Compile HAR files or traces of a task done by hand into a one-call capability. */
|
|
51
|
+
learn(body: {
|
|
52
|
+
har?: Json;
|
|
53
|
+
traces?: Json[];
|
|
54
|
+
goal?: string;
|
|
55
|
+
title?: string;
|
|
56
|
+
}): Promise<any>;
|
|
57
|
+
learned(id?: string): Promise<any>;
|
|
58
|
+
harnessYaml(id: string): Promise<string>;
|
|
59
|
+
skillMd(id: string): Promise<string>;
|
|
60
|
+
usage(): Promise<any>;
|
|
61
|
+
me(): Promise<any>;
|
|
62
|
+
/**
|
|
63
|
+
* The password manager, for services that keep their own "save your login" page (e.g. Kata): values go in,
|
|
64
|
+
* only masked hints come back. One login per site; saving again for the same origin updates it.
|
|
65
|
+
*/
|
|
66
|
+
logins: {
|
|
67
|
+
list: () => Promise<{
|
|
68
|
+
logins: LoginView[];
|
|
69
|
+
}>;
|
|
70
|
+
save: (login: {
|
|
71
|
+
origin: string;
|
|
72
|
+
label?: string;
|
|
73
|
+
username?: string;
|
|
74
|
+
email?: string;
|
|
75
|
+
password?: string;
|
|
76
|
+
totp?: string;
|
|
77
|
+
}) => Promise<{
|
|
78
|
+
login: LoginView;
|
|
79
|
+
updated: boolean;
|
|
80
|
+
}>;
|
|
81
|
+
remove: (by: {
|
|
82
|
+
origin: string;
|
|
83
|
+
} | {
|
|
84
|
+
ref: string;
|
|
85
|
+
}) => Promise<{
|
|
86
|
+
removed: number;
|
|
87
|
+
}>;
|
|
88
|
+
};
|
|
89
|
+
accounts: {
|
|
90
|
+
/** Store a password in the vault; returns a `vault://` ref. */
|
|
91
|
+
connect: (a: {
|
|
92
|
+
origin: string;
|
|
93
|
+
username?: string;
|
|
94
|
+
password?: string;
|
|
95
|
+
label?: string;
|
|
96
|
+
}) => Promise<any>;
|
|
97
|
+
/** Generate and vault a password for a new account. */
|
|
98
|
+
register: (a: {
|
|
99
|
+
origin: string;
|
|
100
|
+
username: string;
|
|
101
|
+
label?: string;
|
|
102
|
+
}) => Promise<any>;
|
|
103
|
+
};
|
|
104
|
+
/** Vault refs and audit, never secrets. */
|
|
105
|
+
vault(): Promise<any>;
|
|
106
|
+
sites(query?: string): Promise<any>;
|
|
107
|
+
site(host: string): Promise<any>;
|
|
108
|
+
openapi(host: string): Promise<any>;
|
|
109
|
+
/** Run one site tool (metered like a run). */
|
|
110
|
+
callTool(host: string, tool: string, input?: Record<string, Json>): Promise<any>;
|
|
111
|
+
/** One site as its own MCP server: its compiled tools, a plain-words task, and the recorded browser on that site. */
|
|
112
|
+
siteMcpUrl(host: string): string;
|
|
187
113
|
}
|
|
188
|
-
|
|
114
|
+
export declare function normalizeHost(site: string): string;
|
|
115
|
+
/** A saved login as anyone but the vault sees it: never a value. */
|
|
116
|
+
export type LoginView = {
|
|
117
|
+
ref: string;
|
|
118
|
+
origin: string;
|
|
119
|
+
label?: string;
|
|
120
|
+
hints: {
|
|
121
|
+
username?: string;
|
|
122
|
+
email?: string;
|
|
123
|
+
};
|
|
124
|
+
fields: string[];
|
|
125
|
+
createdAt: number;
|
|
126
|
+
rotatedAt?: number;
|
|
127
|
+
};
|
package/dist/index.d.ts
CHANGED
|
@@ -1,11 +1,4 @@
|
|
|
1
|
-
export { Unbrowse } from "./client.
|
|
2
|
-
export type {
|
|
3
|
-
export
|
|
4
|
-
export {
|
|
5
|
-
export type { RuntimeHandle, SpawnRuntimeOptions } from "./runtime.js";
|
|
6
|
-
export { payAndRetry } from "./x402.js";
|
|
7
|
-
export type { WalletLike, X402PaymentPayload, X402PaymentRequirement, } from "./x402.js";
|
|
8
|
-
export { buildEscrowCreationTx, buildFlexAuthorization, buildSessionKeyRegistrationTx, fundEscrow, payAndRetryFlex, registerSessionKey, setupDelegation, USDC_MINT_DEVNET, USDC_MINT_MAINNET, } from "./flex.js";
|
|
9
|
-
export type { BuiltFlexTx, DelegationClientLike, DelegationSessionKeyResponse, FlexAuthorization, FlexFundEscrowParams, FlexRegisterSessionKeyParams, FlexWalletLike, SetupDelegationParams, SetupDelegationResult, TransactionSignerOpaque, } from "./flex.js";
|
|
10
|
-
export type { AttributionLedger, AvailableEndpoint, CreatorTransaction, CreatorTransactionsResponse, Dashboard, DashboardContributions, DashboardEarnings, DashboardSpending, EndpointAnnotation, EndpointConstraint, EndpointDescriptor, ExecuteInput, ExecuteResponse, ExecutionTrace, FeedbackInput, FeedbackResponse, HealthResponse, LoginInput, LoginResponse, OrchestrationTiming, ProjectionOptions, RequestOptions, ResolveInput, ResolveResponse, ResponseSchema, SearchDomainInput, SearchHit, SearchInput, SearchResponse, SearchEndpointsInput, SearchEndpointsResponse, EndpointSearchHit, SkillManifest, StatsResponse, StealAuthInput, StealAuthResponse, UnbrowseClientOptions, WalletInfo, } from "./contracts.js";
|
|
11
|
-
//# sourceMappingURL=index.d.ts.map
|
|
1
|
+
export { DEFAULT_BASE_URL, Unbrowse, UnbrowseError, normalizeHost } from "./client.ts";
|
|
2
|
+
export type { LoginView, UnbrowseOptions } from "./client.ts";
|
|
3
|
+
export type * from "./types.ts";
|
|
4
|
+
export { cursorInstallLink, mcpCommands, vscodeInstallLink } from "./mcp-install.ts";
|
package/dist/index.js
CHANGED
|
@@ -1,6 +1,186 @@
|
|
|
1
|
-
|
|
2
|
-
|
|
3
|
-
|
|
4
|
-
|
|
5
|
-
|
|
6
|
-
|
|
1
|
+
// src/client.ts
|
|
2
|
+
var DEFAULT_BASE_URL = "https://unbrowse.ai/api/v1";
|
|
3
|
+
|
|
4
|
+
class UnbrowseError extends Error {
|
|
5
|
+
status;
|
|
6
|
+
code;
|
|
7
|
+
body;
|
|
8
|
+
constructor(message, status, code, body) {
|
|
9
|
+
super(message);
|
|
10
|
+
this.status = status;
|
|
11
|
+
this.code = code;
|
|
12
|
+
this.body = body;
|
|
13
|
+
this.name = "UnbrowseError";
|
|
14
|
+
}
|
|
15
|
+
}
|
|
16
|
+
var env = (name) => (typeof process !== "undefined" ? process.env?.[name] : undefined) || undefined;
|
|
17
|
+
function apiBase(url) {
|
|
18
|
+
const u = url.replace(/\/+$/, "");
|
|
19
|
+
return /\/api\/v1$/.test(u) ? u : `${u}/api/v1`;
|
|
20
|
+
}
|
|
21
|
+
|
|
22
|
+
class Unbrowse {
|
|
23
|
+
baseUrl;
|
|
24
|
+
apiKey;
|
|
25
|
+
fetchImpl;
|
|
26
|
+
constructor(opts = {}) {
|
|
27
|
+
this.baseUrl = apiBase(opts.baseUrl ?? env("UNBROWSE_BASE_URL") ?? DEFAULT_BASE_URL);
|
|
28
|
+
this.apiKey = opts.apiKey ?? env("UNBROWSE_API_KEY");
|
|
29
|
+
this.fetchImpl = opts.fetch ?? ((...a) => globalThis.fetch(...a));
|
|
30
|
+
}
|
|
31
|
+
async send(path, init) {
|
|
32
|
+
const res = await this.fetchImpl(`${this.baseUrl}${path}`, {
|
|
33
|
+
...init,
|
|
34
|
+
headers: {
|
|
35
|
+
...this.apiKey ? { authorization: `Bearer ${this.apiKey}` } : {},
|
|
36
|
+
"content-type": "application/json",
|
|
37
|
+
...init?.headers ?? {}
|
|
38
|
+
}
|
|
39
|
+
});
|
|
40
|
+
if (!res.ok) {
|
|
41
|
+
const body = await res.json().catch(() => ({}));
|
|
42
|
+
const err = typeof body.error === "object" ? body.error : undefined;
|
|
43
|
+
throw new UnbrowseError(err?.message ?? body.error_description ?? res.statusText, res.status, err?.code ?? (typeof body.error === "string" ? body.error : "http_error"), body);
|
|
44
|
+
}
|
|
45
|
+
return res;
|
|
46
|
+
}
|
|
47
|
+
async req(path, init) {
|
|
48
|
+
return (await this.send(path, init)).json();
|
|
49
|
+
}
|
|
50
|
+
post(path, body) {
|
|
51
|
+
return this.req(path, { method: "POST", body: JSON.stringify(body) });
|
|
52
|
+
}
|
|
53
|
+
run(request) {
|
|
54
|
+
const { idempotencyKey, ...rest } = request;
|
|
55
|
+
return this.req("/runs", {
|
|
56
|
+
method: "POST",
|
|
57
|
+
body: JSON.stringify(idempotencyKey ? { ...rest, idempotency_key: idempotencyKey } : rest),
|
|
58
|
+
...idempotencyKey ? { headers: { "idempotency-key": idempotencyKey } } : {}
|
|
59
|
+
});
|
|
60
|
+
}
|
|
61
|
+
inspect(runId) {
|
|
62
|
+
return this.req(`/runs/${runId}`);
|
|
63
|
+
}
|
|
64
|
+
events(runId) {
|
|
65
|
+
return this.req(`/runs/${runId}/events`);
|
|
66
|
+
}
|
|
67
|
+
resume(runId, expectedStateRevision, responses) {
|
|
68
|
+
const wire = responses.map((r) => {
|
|
69
|
+
const x = r ?? {};
|
|
70
|
+
return {
|
|
71
|
+
requirement_id: x.requirement_id ?? x.requirementId,
|
|
72
|
+
expected_revision: x.expected_revision ?? x.expectedRevision,
|
|
73
|
+
action: x.action ?? "accept",
|
|
74
|
+
...x.values !== undefined ? { values: x.values } : {}
|
|
75
|
+
};
|
|
76
|
+
});
|
|
77
|
+
return this.post(`/runs/${runId}/responses`, { expected_state_revision: expectedStateRevision, responses: wire });
|
|
78
|
+
}
|
|
79
|
+
async answer(runId, answers) {
|
|
80
|
+
const view = await this.inspect(runId);
|
|
81
|
+
const open = view.requirements.filter((r) => r.state === "open");
|
|
82
|
+
const responses = Object.entries(answers).map(([field, value]) => {
|
|
83
|
+
const req = open.find((r) => r.affectedAction === field || r.id === field);
|
|
84
|
+
if (!req)
|
|
85
|
+
throw new UnbrowseError(`${field} is not an open requirement. Open: ${open.map((r) => r.affectedAction).join(", ") || "none"}`, 422, "invalid_answer");
|
|
86
|
+
return { requirementId: req.id, expectedRevision: req.revision, action: "accept", values: { [req.affectedAction]: value } };
|
|
87
|
+
});
|
|
88
|
+
await this.resume(runId, view.stateRevision, responses);
|
|
89
|
+
return this.inspect(runId);
|
|
90
|
+
}
|
|
91
|
+
async wait(runId, opts = {}) {
|
|
92
|
+
const deadline = Date.now() + (opts.timeoutMs ?? 600000);
|
|
93
|
+
let view = await this.inspect(runId);
|
|
94
|
+
for (let delay = 500;(view.status === "accepted" || view.status === "working") && Date.now() < deadline; delay = Math.min(delay * 2, 5000)) {
|
|
95
|
+
await new Promise((r) => setTimeout(r, delay));
|
|
96
|
+
view = await this.inspect(runId);
|
|
97
|
+
}
|
|
98
|
+
return view;
|
|
99
|
+
}
|
|
100
|
+
cancel(runId) {
|
|
101
|
+
return this.req(`/runs/${runId}/cancel`, { method: "POST" });
|
|
102
|
+
}
|
|
103
|
+
discover(query) {
|
|
104
|
+
return this.post("/capabilities/search", { query });
|
|
105
|
+
}
|
|
106
|
+
capability(id) {
|
|
107
|
+
return this.req(`/capabilities/${encodeURIComponent(id)}`);
|
|
108
|
+
}
|
|
109
|
+
skills() {
|
|
110
|
+
return this.req("/skills");
|
|
111
|
+
}
|
|
112
|
+
learn(body) {
|
|
113
|
+
return this.post("/learn", body);
|
|
114
|
+
}
|
|
115
|
+
learned(id) {
|
|
116
|
+
return this.req(id ? `/learned/${encodeURIComponent(id)}` : "/learned");
|
|
117
|
+
}
|
|
118
|
+
async harnessYaml(id) {
|
|
119
|
+
return (await this.send(`/learned/${encodeURIComponent(id)}/harness.yaml`)).text();
|
|
120
|
+
}
|
|
121
|
+
async skillMd(id) {
|
|
122
|
+
return (await this.send(`/learned/${encodeURIComponent(id)}/skill.md`)).text();
|
|
123
|
+
}
|
|
124
|
+
usage() {
|
|
125
|
+
return this.req("/usage");
|
|
126
|
+
}
|
|
127
|
+
me() {
|
|
128
|
+
return this.req("/me");
|
|
129
|
+
}
|
|
130
|
+
logins = {
|
|
131
|
+
list: () => this.req("/logins"),
|
|
132
|
+
save: (login) => this.post("/logins", login),
|
|
133
|
+
remove: (by) => this.post("/logins/remove", by)
|
|
134
|
+
};
|
|
135
|
+
accounts = {
|
|
136
|
+
connect: (a) => this.post("/accounts/connections", a),
|
|
137
|
+
register: (a) => this.post("/accounts/register", a)
|
|
138
|
+
};
|
|
139
|
+
vault() {
|
|
140
|
+
return this.req("/vault");
|
|
141
|
+
}
|
|
142
|
+
sites(query = "") {
|
|
143
|
+
return this.req(`/sites${query ? `?q=${encodeURIComponent(query)}` : ""}`);
|
|
144
|
+
}
|
|
145
|
+
site(host) {
|
|
146
|
+
return this.req(`/sites/${normalizeHost(host)}`);
|
|
147
|
+
}
|
|
148
|
+
openapi(host) {
|
|
149
|
+
return this.req(`/sites/${normalizeHost(host)}/openapi.json`);
|
|
150
|
+
}
|
|
151
|
+
callTool(host, tool, input = {}) {
|
|
152
|
+
return this.post(`/sites/${normalizeHost(host)}/call/${encodeURIComponent(tool)}`, input);
|
|
153
|
+
}
|
|
154
|
+
siteMcpUrl(host) {
|
|
155
|
+
return `${this.baseUrl}/sites/${normalizeHost(host)}/mcp`;
|
|
156
|
+
}
|
|
157
|
+
}
|
|
158
|
+
function normalizeHost(site) {
|
|
159
|
+
let host = site.trim().toLowerCase();
|
|
160
|
+
if (/^[a-z]+:\/\//.test(host))
|
|
161
|
+
host = new URL(host).hostname;
|
|
162
|
+
return host.replace(/\/.*$/, "").replace(/^www\./, "");
|
|
163
|
+
}
|
|
164
|
+
// src/mcp-install.ts
|
|
165
|
+
function cursorInstallLink(url) {
|
|
166
|
+
return `cursor://anysphere.cursor-deeplink/mcp/install?name=unbrowse&config=${encodeURIComponent(btoa(JSON.stringify({ url })))}`;
|
|
167
|
+
}
|
|
168
|
+
function vscodeInstallLink(url, insiders = false) {
|
|
169
|
+
return `${insiders ? "vscode-insiders" : "vscode"}:mcp/install?${encodeURIComponent(JSON.stringify({ name: "unbrowse", type: "http", url }))}`;
|
|
170
|
+
}
|
|
171
|
+
function mcpCommands(url) {
|
|
172
|
+
return {
|
|
173
|
+
claudeCode: `claude mcp add --transport http unbrowse ${url}`,
|
|
174
|
+
codex: `codex mcp add unbrowse --url ${url} && codex mcp login unbrowse`,
|
|
175
|
+
json: JSON.stringify({ mcpServers: { unbrowse: { url } } }, null, 2)
|
|
176
|
+
};
|
|
177
|
+
}
|
|
178
|
+
export {
|
|
179
|
+
DEFAULT_BASE_URL,
|
|
180
|
+
Unbrowse,
|
|
181
|
+
UnbrowseError,
|
|
182
|
+
cursorInstallLink,
|
|
183
|
+
mcpCommands,
|
|
184
|
+
normalizeHost,
|
|
185
|
+
vscodeInstallLink
|
|
186
|
+
};
|