@unbrowse/sdk 6.17.0-preview.6

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/LICENSE ADDED
@@ -0,0 +1,21 @@
1
+ MIT License
2
+
3
+ Copyright (c) 2025 Unbrowse AI
4
+
5
+ Permission is hereby granted, free of charge, to any person obtaining a copy
6
+ of this software and associated documentation files (the "Software"), to deal
7
+ in the Software without restriction, including without limitation the rights
8
+ to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
9
+ copies of the Software, and to permit persons to whom the Software is
10
+ furnished to do so, subject to the following conditions:
11
+
12
+ The above copyright notice and this permission notice shall be included in all
13
+ copies or substantial portions of the Software.
14
+
15
+ THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
16
+ IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
17
+ FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
18
+ AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
19
+ LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
20
+ OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
21
+ SOFTWARE.
package/README.md ADDED
@@ -0,0 +1,156 @@
1
+ # @unbrowse/sdk
2
+
3
+ TypeScript SDK for Unbrowse — the local agent browser that turns any website into reusable, payable API routes.
4
+
5
+ The SDK auto-spawns the `unbrowse` binary if it isn't already running, so a single `await Unbrowse.local()` is all you need to go from `npm install` to your first resolve.
6
+
7
+ Current version: **6.16.0-preview.0**.
8
+
9
+ > The SDK (this package) is MIT-licensed. The `unbrowse` runtime binary it talks to is distributed via npm. See [`OPEN-SOURCE-NOTICE.md`](../../docs/OPEN-SOURCE-NOTICE.md).
10
+
11
+ ## Install
12
+
13
+ ```bash
14
+ npm install @unbrowse/sdk
15
+ ```
16
+
17
+ The SDK ships the spawn path lazily — `Unbrowse.connect()` callers never pull `child_process`, so it stays tree-shakeable in serverless and edge bundles.
18
+
19
+ ## Quick start
20
+
21
+ ```ts
22
+ import { Unbrowse } from "@unbrowse/sdk";
23
+
24
+ const u = await Unbrowse.local();
25
+ const r = await u.resolve({ intent: "list tomorrow's events", url: "https://calendar.google.com" });
26
+ console.log(r.result);
27
+ ```
28
+
29
+ That's it — `Unbrowse.local()` probes `127.0.0.1:6969`, connects if a daemon is alive, and spawns the `unbrowse` CLI as a child process if not. The spawned daemon's lifecycle is owned by your process; it shuts down cleanly on exit.
30
+
31
+ ## Three factories, three lifecycles
32
+
33
+ ```ts
34
+ // 1. Common case — probe then spawn. The right answer 95% of the time.
35
+ const u = await Unbrowse.local();
36
+
37
+ // 2. External daemon already running (Docker, sidecar, dev server).
38
+ const u = await Unbrowse.connect("http://localhost:6969");
39
+
40
+ // 3. Always spawn fresh — owned lifecycle, useful for tests and isolated workers.
41
+ const u = await Unbrowse.spawn({ port: 7969 });
42
+ ```
43
+
44
+ All three return the same `Unbrowse` client interface. Pass `{ apiKey }` to any factory to override the auto-generated marketplace key.
45
+
46
+ ## Resolve and execute
47
+
48
+ ```ts
49
+ const resolved = await u.resolve({
50
+ intent: "get feed posts",
51
+ url: "https://news.ycombinator.com",
52
+ });
53
+
54
+ // Re-run later with explicit projection
55
+ const rerun = await u.execute(resolved, { projection: { raw: true } });
56
+
57
+ // Or by skill id, with params
58
+ const quote = await u.execute("skill_123", { params: { symbol: "NVDA" } });
59
+ ```
60
+
61
+ ## Payments
62
+
63
+ Unbrowse routes monetize on use via [x402](https://www.x402.org). Every paid execute (priced skills, `search`, `resolve` over a priced shortlist) is gated by a `402 Payment Required` flow. The SDK turns that into a typed error you can catch and retry. v6.16 settles on [Faremeter Flex](https://docs.faremeter.xyz/flex/overview) — your wallet signs an off-chain authorization with a session key, the facilitator settles on-chain in batches, and splits to contributors land atomically.
64
+
65
+ ```ts
66
+ import { Unbrowse, PaymentRequiredError, payAndRetryFlex } from "@unbrowse/sdk";
67
+
68
+ try {
69
+ await u.execute("skill_premium_123", { params: { ticker: "NVDA" } });
70
+ } catch (err) {
71
+ if (err instanceof PaymentRequiredError) {
72
+ await payAndRetryFlex(err, wallet, (header) =>
73
+ u.execute(
74
+ "skill_premium_123",
75
+ { params: { ticker: "NVDA" } },
76
+ { headers: { "X-PAYMENT": header } },
77
+ ),
78
+ ); // signs the Flex authorization, retries with proof attached
79
+ }
80
+ }
81
+ ```
82
+
83
+ `PaymentRequiredError` is thrown at the HTTP-parser layer and carries `accepts[]` — the canonical x402 terms array. `payAndRetryFlex(error, wallet, retry)` is a free function exported from `@unbrowse/sdk`; it picks `accepts[0]`, has your session key sign it, and calls your `retry(paymentHeader)` to replay the original request with `X-PAYMENT` attached.
84
+
85
+ For metered routes there's a higher-level helper that handles the catch + retry for you:
86
+
87
+ ```ts
88
+ const result = await u.executeMetered<{ data: string; usage_units: number }>(
89
+ "skill_id",
90
+ input,
91
+ { wallet, onUsage: (units) => console.log("consumed", units, "units") },
92
+ );
93
+ ```
94
+
95
+ ### Sponsor mode — first calls covered by the platform
96
+
97
+ Brand-new agents get a daily allowance of platform-sponsored execute calls before they need to fund a wallet, so creators start earning USDC the moment their captured routes are reused. Sponsored responses include `X-Sponsored: <ledger_id>`.
98
+
99
+ When the daily allowance is exhausted you get `SponsorExhaustedError` — pair a wallet and switch to `payAndRetryFlex`. Opt out per-request by passing `{ headers: { "X-No-Sponsor": "1" } }` if you'd rather pay yourself from the first call.
100
+
101
+ Full payment docs and worked examples: [`docs/payments/`](./docs/payments/). Wallet + escrow + session-key setup: [`../../docs/wallets.md`](../../docs/wallets.md). Upgrading from v6.15's `exact`-scheme integration: [`../../docs/x402-flex-migration.md`](../../docs/x402-flex-migration.md).
102
+
103
+ ## Auth
104
+
105
+ ```ts
106
+ // Interactive login — opens a real browser window for first-time auth.
107
+ await u.login({ url: "https://calendar.google.com" });
108
+
109
+ // Or import cookies from your local browser storage.
110
+ await u.importAuth({ url: "https://x.com/home", browser: "auto" });
111
+ ```
112
+
113
+ ## Search
114
+
115
+ ```ts
116
+ const global = await u.search({ intent: "get stock prices", k: 5 });
117
+
118
+ const domain = await u.searchDomain({
119
+ intent: "find trending repositories",
120
+ domain: "github.com",
121
+ k: 3,
122
+ });
123
+ ```
124
+
125
+ ## Error handling
126
+
127
+ ```ts
128
+ import { Unbrowse, UnbrowseApiError } from "@unbrowse/sdk";
129
+
130
+ try {
131
+ await u.resolve({ intent: "get inbox", url: "https://mail.google.com" });
132
+ } catch (err) {
133
+ if (err instanceof UnbrowseApiError) {
134
+ console.error(err.status, err.path, err.data);
135
+ }
136
+ throw err;
137
+ }
138
+ ```
139
+
140
+ `UnbrowseApiError` is the generic wrapper. `PaymentRequiredError` and `SponsorExhaustedError` are payment-specific subclasses; both expose `accepts[]` so you can introspect what the gate wants.
141
+
142
+ ## Notes
143
+
144
+ - Default `baseUrl` is `http://localhost:6969`. `Unbrowse.local()` picks this up automatically.
145
+ - Default `apiKey` reads from `UNBROWSE_API_KEY` when present.
146
+ - `resolve({ url })` maps the URL into both `params.url` and `context.url`, matching the CLI path.
147
+ - Response types are strongest on inputs and core trace/skill metadata, lighter on payload bodies, because endpoint payload shape varies by site.
148
+
149
+ ## More
150
+
151
+ - Complete docs: [`docs/`](./docs/)
152
+ - Use case recipes: [`docs/examples/`](./docs/examples/)
153
+ - API reference: [`docs/api-reference/`](./docs/api-reference/)
154
+ - Payment surface: [`docs/payments/`](./docs/payments/)
155
+
156
+ _Audited Day 6 (Dominion): 2026-05-14_
@@ -0,0 +1,120 @@
1
+ import type { AttributionLedger, AvailableEndpoint, CreatorTransactionsResponse, Dashboard, ExecuteInput, ExecuteResponse, FeedbackInput, FeedbackResponse, HealthResponse, LoginInput, LoginResponse, RequestOptions, ResolveInput, ResolveResponse, SearchDomainInput, SearchInput, SearchResponse, SkillManifest, StatsResponse, StealAuthInput, StealAuthResponse, UnbrowseClientOptions } from "./contracts.js";
2
+ import { type SpawnRuntimeOptions } from "./runtime.js";
3
+ export declare class Unbrowse {
4
+ readonly baseUrl: string;
5
+ readonly apiKey?: string;
6
+ readonly clientId?: string;
7
+ private readonly defaultHeaders?;
8
+ private readonly fetchImpl;
9
+ private readonly timeoutMs?;
10
+ private _runtimeHandle;
11
+ constructor(options?: UnbrowseClientOptions);
12
+ /**
13
+ * Build a `params` object from an `AvailableEndpoint.input_params` spec, using
14
+ * the `example_value` of each declared key. Skips keys without an example.
15
+ */
16
+ static paramsFromInputSpec(spec: AvailableEndpoint["input_params"] | undefined): Record<string, unknown>;
17
+ /**
18
+ * Point at an already-running Unbrowse runtime. No probe, no spawn.
19
+ * `.close()` is a no-op for the runtime (the caller owns it).
20
+ */
21
+ static connect(baseUrl: string, opts?: Omit<UnbrowseClientOptions, "baseUrl">): Promise<Unbrowse>;
22
+ /**
23
+ * Spawn a co-located Unbrowse runtime and return a client pointed at it.
24
+ * The client takes ownership of the child process: `.close()` will tear
25
+ * it down.
26
+ */
27
+ static spawn(opts?: SpawnRuntimeOptions & Omit<UnbrowseClientOptions, "baseUrl">): Promise<Unbrowse>;
28
+ /**
29
+ * Probe 127.0.0.1 on the requested port (default 6969). Adopts a live
30
+ * runtime via `connect`; spawns a new one via `spawn` if dead. The
31
+ * resulting client only owns the runtime if it had to spawn.
32
+ */
33
+ static local(opts?: SpawnRuntimeOptions & Omit<UnbrowseClientOptions, "baseUrl">): Promise<Unbrowse>;
34
+ /**
35
+ * Release any resources owned by this client. If the client spawned its
36
+ * own runtime, this kills the child process. Otherwise no-op.
37
+ */
38
+ close(): Promise<void>;
39
+ request<T>(method: string, path: string, body?: unknown, options?: RequestOptions): Promise<T>;
40
+ resolve(input: ResolveInput, options?: RequestOptions): Promise<ResolveResponse>;
41
+ execute(skill: string | ExecuteInput | ResolveResponse, input?: Omit<ExecuteInput, "skillId">, options?: RequestOptions): Promise<ExecuteResponse>;
42
+ getSkill(skillId: string, options?: RequestOptions): Promise<SkillManifest>;
43
+ login(input: LoginInput, options?: RequestOptions): Promise<LoginResponse>;
44
+ importAuth(input: StealAuthInput, options?: RequestOptions): Promise<StealAuthResponse>;
45
+ stealAuth(input: StealAuthInput, options?: RequestOptions): Promise<StealAuthResponse>;
46
+ search(input: SearchInput, options?: RequestOptions): Promise<SearchResponse>;
47
+ searchDomain(input: SearchDomainInput, options?: RequestOptions): Promise<SearchResponse>;
48
+ feedback(input: FeedbackInput, options?: RequestOptions): Promise<FeedbackResponse>;
49
+ stats(options?: RequestOptions): Promise<StatsResponse>;
50
+ health(options?: RequestOptions): Promise<HealthResponse>;
51
+ /**
52
+ * Earnings/spending dashboard for the authenticated agent.
53
+ * Requires `apiKey` set on the client. Backend: `GET /v1/dashboard/me`.
54
+ */
55
+ dashboard(options?: RequestOptions): Promise<Dashboard>;
56
+ /**
57
+ * Public dashboard for any wallet address. Backend: `GET /v1/dashboard/wallet/:walletAddress`.
58
+ */
59
+ dashboardByWallet(walletAddress: string, options?: RequestOptions): Promise<Dashboard>;
60
+ /**
61
+ * Per-transaction earnings ledger for a creator agent.
62
+ * Backend: `GET /v1/transactions/creator/:agentId`.
63
+ */
64
+ creatorTransactions(agentId: string, options?: RequestOptions): Promise<CreatorTransactionsResponse>;
65
+ /**
66
+ * Fund a Flex escrow on the caller's behalf. Thin wrapper around
67
+ * `fundEscrow` in `./flex.ts` — requires the caller to pass
68
+ * `signer` + `rpc` for v6.16-preview.0 (until SDK ships its own
69
+ * @solana/kit pipeline). For pure tx construction without sending,
70
+ * import `buildEscrowCreationTx` from the package root.
71
+ */
72
+ fundEscrow(params: {
73
+ amountUsdc: string;
74
+ walletAddress?: string;
75
+ facilitatorAddress?: string;
76
+ mint?: string;
77
+ refundTimeoutSlots?: number;
78
+ deadmanTimeoutSlots?: number;
79
+ signer?: unknown;
80
+ rpc?: unknown;
81
+ }): Promise<{
82
+ escrowAddress: string;
83
+ txSignature: string;
84
+ }>;
85
+ /**
86
+ * Register a session key against the caller's existing Flex escrow.
87
+ * Thin wrapper around `registerSessionKey` in `./flex.ts`.
88
+ */
89
+ registerSessionKey(params: {
90
+ sessionKeyAddress: string;
91
+ walletAddress?: string;
92
+ escrowAddress?: string;
93
+ expiresAtSlot?: string;
94
+ revocationGracePeriodSlots?: number;
95
+ signer?: unknown;
96
+ rpc?: unknown;
97
+ }): Promise<{
98
+ txSignature: string;
99
+ }>;
100
+ /**
101
+ * Execute a skill against a Flex-metered route. preview.0/preview.1 stub:
102
+ * the backend metered-execute route (`POST /v1/skills/:id/execute` with
103
+ * Flex-shaped 402 + usage_units settlement) ships in v6.16.0-preview.2.
104
+ * Callers must use `Unbrowse#execute` against fixed-price skills until
105
+ * then. The method signature stays for forward compat; the body refuses
106
+ * with a precise version-targeted error.
107
+ */
108
+ executeMetered<T = unknown>(_skillOrId: string | {
109
+ skill_id: string;
110
+ }, _input: unknown, _opts?: {
111
+ onUsage?: (units: number) => void;
112
+ wallet?: import("./flex.js").FlexWalletLike;
113
+ }, _options?: RequestOptions): Promise<T>;
114
+ /**
115
+ * Indexer earnings via delta-based attribution.
116
+ * Backend: `GET /v1/attribution/indexer/:indexerId`.
117
+ */
118
+ indexerAttribution(indexerId: string, options?: RequestOptions): Promise<AttributionLedger>;
119
+ }
120
+ //# sourceMappingURL=client.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"client.d.ts","sourceRoot":"","sources":["../src/client.ts"],"names":[],"mappings":"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"}