unbrowse 10.3.0 → 10.4.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.
@@ -1,6 +1,7 @@
1
1
  import type { AccountMe, AccountCredits, ApiKeyCreateInput, ApiKeyCreateResponse, ApiKeyListResponse, ApiKeyRevokeResponse, ExecuteInput, ExecuteResponse, HealthResponse, RequestOptions, ResolveInput, ResolveResponse, SearchInput, SearchResponse, SponsorStatus, UnbrowseClientOptions } from "./types.js";
2
2
  import type { WorkerProxyCapabilities, WorkerProxyRequest, WorkerProxyResponse } from "./proxy-types.js";
3
3
  export declare class Unbrowse {
4
+ /** @deprecated web2 wrapper. Use `walletSigner` for web3-native auth. */
4
5
  readonly apiKey: string | undefined;
5
6
  readonly baseURL: string;
6
7
  readonly timeout: number;
@@ -8,6 +9,7 @@ export declare class Unbrowse {
8
9
  readonly logLevel: NonNullable<UnbrowseClientOptions["logLevel"]>;
9
10
  private readonly _fetch;
10
11
  private readonly defaultHeaders;
12
+ private readonly walletSigner;
11
13
  readonly account: AccountResource;
12
14
  readonly keys: KeysResource;
13
15
  readonly proxy: ProxyResource;
@@ -4,6 +4,7 @@ const DEFAULT_TIMEOUT_MS = 60_000;
4
4
  const DEFAULT_MAX_RETRIES = 2;
5
5
  const SDK_VERSION = "7.0.0-preview.1";
6
6
  export class Unbrowse {
7
+ /** @deprecated web2 wrapper. Use `walletSigner` for web3-native auth. */
7
8
  apiKey;
8
9
  baseURL;
9
10
  timeout;
@@ -11,12 +12,21 @@ export class Unbrowse {
11
12
  logLevel;
12
13
  _fetch;
13
14
  defaultHeaders;
15
+ walletSigner;
14
16
  account;
15
17
  keys;
16
18
  proxy;
17
19
  constructor(opts = {}) {
18
20
  const env = readEnv();
21
+ // WEB3-NATIVE: wallet sig is PRIMARY (via walletSigner callback). The api-key
22
+ // Bearer is the deprecated web2 wrapper, kept for account-bound flow
23
+ // continuity. A wallet-only caller (no apiKey, walletSigner set)
24
+ // authenticates as `wallet:<pk>` on the backend — full principal.
19
25
  this.apiKey = opts.apiKey ?? env.UNBROWSE_API_KEY;
26
+ this.walletSigner = opts.walletSigner;
27
+ if (!this.apiKey && !this.walletSigner) {
28
+ throw new UnbrowseError("Unbrowse requires authentication. Pass `walletSigner` (web3-native, preferred) or `apiKey` (deprecated web2 wrapper).");
29
+ }
20
30
  this.baseURL = stripTrailingSlash(opts.baseURL ?? env.UNBROWSE_BASE_URL ?? DEFAULT_BASE_URL);
21
31
  this.timeout = opts.timeout ?? DEFAULT_TIMEOUT_MS;
22
32
  this.maxRetries = opts.maxRetries ?? DEFAULT_MAX_RETRIES;
@@ -55,6 +65,14 @@ export class Unbrowse {
55
65
  ...this.defaultHeaders,
56
66
  ...(opts.headers ?? {}),
57
67
  };
68
+ // WEB3-NATIVE auth: the wallet signature is the SOLE REQUIRED credential.
69
+ // The backend verifies the sig and authenticates as `wallet:<pk>` BEFORE
70
+ // any Bearer 401 path. The apiKey Bearer below is the deprecated web2
71
+ // wrapper, sent only when a legacy key is present.
72
+ if (this.walletSigner) {
73
+ const walletHeaders = await this.walletSigner();
74
+ Object.assign(headers, walletHeaders);
75
+ }
58
76
  if (this.apiKey)
59
77
  headers["Authorization"] = `Bearer ${this.apiKey}`;
60
78
  if (body !== undefined && method !== "GET")
@@ -22,9 +22,10 @@ export interface OnboardingStatus {
22
22
  nextStep: string;
23
23
  }
24
24
  /**
25
- * Ensure the agent has a usable identity, account-first then local wallet. When only a
26
- * local wallet exists and a `sync` is provided, the wallet is published onto an account.
27
- * Throws only when neither an account key nor a local wallet can be found (run setup).
25
+ * Ensure the agent has a usable identity, WALLET-FIRST. The wallet signature alone
26
+ * is a full credential on the backend (`wallet:<pk>` principal). An account-key, if
27
+ * present, is the optional web2 wrapper layered for payouts/sync continuity.
28
+ * Throws only when neither a local wallet nor an account key can be found (run setup).
28
29
  */
29
30
  export declare function ensureIdentity(opts?: OnboardOptions): Promise<Identity>;
30
31
  /** Report onboarding state + the single next step to show the user. */
@@ -1,15 +1,17 @@
1
1
  /**
2
- * src/sdk/onboard.ts — identity onboarding for the hole.
2
+ * src/sdk/onboard.ts — identity onboarding for the agent.
3
3
  *
4
- * Best-practice credential chain, resolved in order:
5
- * 1. a BOUND ACCOUNT an API key (from a frontend OAuth login or `unbrowse register`),
6
- * which already carries payouts + sync;
7
- * 2. else the auto-created LOCAL SELF-CUSTODY WALLET (the keyless fallback every install
8
- * getssee src/values/signer.ts `ensureLocalWalletAddress`, surfaced at
9
- * ~/.unbrowse/wallet.json), which can later be SYNCED onto an account.
4
+ * WEB3-NATIVE credential chain, resolved in order:
5
+ * 1. the LOCAL SELF-CUSTODY WALLET (the root identity every install gets
6
+ * src/values/signer.ts `ensureLocalWalletAddress`, surfaced at
7
+ * ~/.unbrowse/wallet.json). The wallet signature authenticates as
8
+ * `wallet:<pk>` on the backend full principal, never key-gated.
9
+ * 2. else a BOUND ACCOUNT a deprecated web2 api-key wrapper (from a frontend
10
+ * OAuth login or `unbrowse register`), layered on top of the wallet to
11
+ * carry account-bound flows (payouts accrual, dashboard sync).
10
12
  *
11
13
  * `onboardingStatus` reports what's configured and the one next step to tell the user.
12
- * Every input (api-key resolver, wallet peek, sync) is injectable so this is testable
14
+ * Every input (wallet peek, api-key resolver, sync) is injectable so this is testable
13
15
  * offline and embeddable in any frontend.
14
16
  */
15
17
  import { existsSync, readFileSync } from "node:fs";
@@ -35,26 +37,32 @@ function maskKey(key) {
35
37
  return key.length <= 10 ? key : `${key.slice(0, 4)}…${key.slice(-4)}`;
36
38
  }
37
39
  /**
38
- * Ensure the agent has a usable identity, account-first then local wallet. When only a
39
- * local wallet exists and a `sync` is provided, the wallet is published onto an account.
40
- * Throws only when neither an account key nor a local wallet can be found (run setup).
40
+ * Ensure the agent has a usable identity, WALLET-FIRST. The wallet signature alone
41
+ * is a full credential on the backend (`wallet:<pk>` principal). An account-key, if
42
+ * present, is the optional web2 wrapper layered for payouts/sync continuity.
43
+ * Throws only when neither a local wallet nor an account key can be found (run setup).
41
44
  */
42
45
  export async function ensureIdentity(opts = {}) {
43
- const apiKey = (opts.resolveApiKey ?? defaultResolveApiKey)();
44
- if (apiKey) {
45
- return { kind: "account", id: maskKey(apiKey), synced: true };
46
- }
47
46
  const wallet = (opts.peekWallet ?? defaultPeekWallet)();
48
47
  if (wallet) {
49
48
  const id = { kind: "wallet", id: wallet, synced: false };
50
- if (opts.sync) {
49
+ const apiKey = (opts.resolveApiKey ?? defaultResolveApiKey)();
50
+ if (apiKey && opts.sync) {
51
51
  await opts.sync(id);
52
52
  id.synced = true;
53
53
  }
54
54
  return id;
55
55
  }
56
- throw new Error("No identity yet. Run `unbrowse setup` to create a local self-custody wallet, " +
57
- "or set UNBROWSE_API_KEY (`unbrowse register --email you@example.com`) to bind an account.");
56
+ // No wallet: legacy fallback to a web2 account-key (deprecated agents
57
+ // without a wallet cannot sign the web3 auth challenge and will 401 on
58
+ // wallet-sig-required routes once the wrapper is fully retired).
59
+ const apiKey = (opts.resolveApiKey ?? defaultResolveApiKey)();
60
+ if (apiKey) {
61
+ return { kind: "account", id: maskKey(apiKey), synced: true };
62
+ }
63
+ throw new Error("No identity yet. Run `unbrowse setup` to create a local self-custody wallet " +
64
+ "(web3-native principal, preferred). Setting UNBROWSE_API_KEY (`unbrowse register`) " +
65
+ "binds a deprecated web2 account wrapper over the wallet.");
58
66
  }
59
67
  /** Report onboarding state + the single next step to show the user. */
60
68
  export function onboardingStatus(opts = {}) {
@@ -64,18 +72,22 @@ export function onboardingStatus(opts = {}) {
64
72
  const hasWallet = !!wallet;
65
73
  let identity = null;
66
74
  let nextStep;
67
- if (hasAccount) {
68
- identity = { kind: "account", id: maskKey(apiKey), synced: true };
69
- nextStep = "You're set: a bound account handles sync, payouts, and paid routes.";
75
+ if (hasWallet && hasAccount) {
76
+ identity = { kind: "wallet", id: wallet, synced: true };
77
+ nextStep = "You're set: wallet is your principal, account-key wraps payouts/sync.";
70
78
  }
71
79
  else if (hasWallet) {
72
80
  identity = { kind: "wallet", id: wallet, synced: false };
73
81
  nextStep =
74
- "Local self-custody wallet ready. Bind an account to sync earnings across machines: " +
75
- "`unbrowse register --email you@example.com`.";
82
+ "Local self-custody wallet ready (web3-native principal). Optionally bind an account " +
83
+ "for payouts/sync: `unbrowse register --email you@example.com`.";
84
+ }
85
+ else if (hasAccount) {
86
+ identity = { kind: "account", id: maskKey(apiKey), synced: true };
87
+ nextStep = "Bound account-key only (deprecated web2 fallback). Run `unbrowse setup` to create a wallet.";
76
88
  }
77
89
  else {
78
- nextStep = "Run `unbrowse setup` to create your local wallet (or set UNBROWSE_API_KEY).";
90
+ nextStep = "Run `unbrowse setup` to create your local wallet (the web3-native principal).";
79
91
  }
80
92
  return { identity, hasAccount, hasWallet, nextStep };
81
93
  }
@@ -129,7 +129,22 @@ export interface ApiKeyRevokeResponse {
129
129
  _request_id?: string;
130
130
  }
131
131
  export interface UnbrowseClientOptions {
132
+ /**
133
+ * @deprecated web2 web2 wrapper. The web3-native credential is the wallet
134
+ * signature (see `walletSigner`); a wallet-only caller authenticates as
135
+ * `wallet:<pk>` on the backend with no api-key. Kept for account-bound
136
+ * flow continuity during the wrapper's retirement window.
137
+ */
132
138
  apiKey?: string;
139
+ /**
140
+ * Web3-native auth signer. When set, the SDK calls it on every request and
141
+ * merges the returned headers (typically `X-Unbrowse-Wallet`,
142
+ * `X-Unbrowse-Auth-Ts`, `X-Unbrowse-Signature`) into the outbound request.
143
+ * The backend verifies the signature and authenticates as `wallet:<pk>`
144
+ * BEFORE any Bearer 401 path, so callers with NO api-key are full principals.
145
+ * Either `walletSigner` or `apiKey` MUST be set; `walletSigner` preferred.
146
+ */
147
+ walletSigner?: () => Promise<Record<string, string>>;
133
148
  baseURL?: string;
134
149
  timeout?: number;
135
150
  maxRetries?: number;
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "unbrowse",
3
- "version": "10.3.0",
3
+ "version": "10.4.0",
4
4
  "repository": {
5
5
  "type": "git",
6
6
  "url": "git+https://github.com/unbrowse-ai/unbrowse.git"