@agentgrant.cash/cli 1.4.3 → 1.4.4
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/dist/cli/commands/agent.d.ts +8 -0
- package/dist/cli/commands/auth.d.ts +20 -0
- package/dist/cli/commands/meta.d.ts +2 -0
- package/dist/cli/commands/money.d.ts +2 -0
- package/dist/cli/commands/onboard.d.ts +2 -0
- package/dist/cli/commands/portfolio.d.ts +14 -0
- package/dist/cli/index.d.ts +2 -0
- package/dist/cli/money-helpers.d.ts +100 -0
- package/dist/cli/perfolio-commands/account.d.ts +35 -0
- package/dist/cli/perfolio-commands/borrow.d.ts +2 -0
- package/dist/cli/perfolio-commands/discover.d.ts +2 -0
- package/dist/cli/perfolio-commands/earn.d.ts +9 -0
- package/dist/cli/perfolio-commands/hyperliquid.d.ts +32 -0
- package/dist/cli/perfolio-commands/loans.d.ts +8 -0
- package/dist/cli/perfolio-commands/market.d.ts +11 -0
- package/dist/cli/perfolio-commands/polymarket.d.ts +29 -0
- package/dist/cli/perfolio-commands/session.d.ts +2 -0
- package/dist/cli/perfolio-commands/spending.d.ts +14 -0
- package/dist/cli/perfolio-commands/trade.d.ts +2 -0
- package/dist/cli/perfolio-commands/tx.d.ts +2 -0
- package/dist/lib/agent-client.d.ts +78 -0
- package/dist/lib/amounts.d.ts +14 -0
- package/dist/lib/assets.d.ts +12 -0
- package/dist/lib/auth-session.d.ts +57 -0
- package/dist/lib/client.d.ts +295 -0
- package/dist/lib/config.d.ts +13 -0
- package/dist/lib/context.d.ts +21 -0
- package/dist/lib/currency.d.ts +70 -0
- package/dist/lib/device.d.ts +78 -0
- package/dist/lib/dotenv.d.ts +12 -0
- package/dist/lib/errors.d.ts +33 -0
- package/dist/lib/format.d.ts +5 -0
- package/dist/lib/index.d.ts +22 -0
- package/dist/lib/kyc-status.d.ts +10 -0
- package/dist/lib/money-client.d.ts +66 -0
- package/dist/lib/money-input.d.ts +97 -0
- package/dist/lib/output.d.ts +22 -0
- package/dist/lib/polygon-balance.d.ts +43 -0
- package/dist/lib/portfolio-format.d.ts +79 -0
- package/dist/lib/relay.d.ts +8 -0
- package/dist/lib/sign.d.ts +11 -0
- package/dist/lib/tx-wait.d.ts +19 -0
- package/dist/lib/types.d.ts +377 -0
- package/dist/lib/verify.d.ts +21 -0
- package/package.json +7 -1
|
@@ -0,0 +1,8 @@
|
|
|
1
|
+
import type { Command } from "commander";
|
|
2
|
+
/**
|
|
3
|
+
* Agent side — pay-per-use services routed to the Agent-mode backend. Every
|
|
4
|
+
* spend is owned by the session (delegated, revocable, guardrailed); the CLI
|
|
5
|
+
* carries only the API key. Verbs mirror the agent CLI so a model that knows it
|
|
6
|
+
* drives this with no relearning: search → check → fetch.
|
|
7
|
+
*/
|
|
8
|
+
export declare function registerAgent(program: Command): void;
|
|
@@ -0,0 +1,20 @@
|
|
|
1
|
+
import type { Command } from "commander";
|
|
2
|
+
import { type Credentials, type DeviceCredentials } from "../../lib/index.js";
|
|
3
|
+
/**
|
|
4
|
+
* `grant login` — one connect, one credential (unified auth).
|
|
5
|
+
*
|
|
6
|
+
* Runs a SINGLE perfolio device handshake: `cli/device/*`, the one-time `sid`
|
|
7
|
+
* relayed to the browser via the connect URL. The logged-in browser completes it
|
|
8
|
+
* server-side; the CLI polls until perfolio returns the credential. The result is
|
|
9
|
+
* the perfolio-signed access JWT (`accessJwt`) plus the opaque `pfr_` refresh
|
|
10
|
+
* token — that ONE JWT is sent as `Authorization: Bearer` to BOTH backends
|
|
11
|
+
* (money + agent). The old agent-side `grant_live_` PKCE leg is retired: there is
|
|
12
|
+
* no second handshake, no `--agent-key`, no separate spending credential.
|
|
13
|
+
*/
|
|
14
|
+
/**
|
|
15
|
+
* Map a completed perfolio device flow to the stored credential. A fresh login
|
|
16
|
+
* REPLACES the whole credentials file — no stale agent key is carried over (the
|
|
17
|
+
* `grant_live_` leg is gone) — so the file holds exactly one perfolio credential.
|
|
18
|
+
*/
|
|
19
|
+
export declare function loginCredentials(result: DeviceCredentials): Credentials;
|
|
20
|
+
export declare function registerAuth(program: Command): void;
|
|
@@ -0,0 +1,14 @@
|
|
|
1
|
+
import type { Command } from "commander";
|
|
2
|
+
import { type Ctx, type PortfolioExtras } from "../../lib/index.js";
|
|
3
|
+
/**
|
|
4
|
+
* Prediction available cash + open-bet value. Best-effort; {} on any failure.
|
|
5
|
+
*
|
|
6
|
+
* Available cash comes from the SAME source the predictions screen uses: the
|
|
7
|
+
* backend `/polymarket/positions` `cashUsd` field (an on-chain pUSD read done
|
|
8
|
+
* server-side via a reliable RPC). For older backends that don't return it we
|
|
9
|
+
* fall back to reading the deposit wallet's pUSD balance directly from a public
|
|
10
|
+
* Polygon RPC. Both the positions call and the deposit-wallet lookup run in
|
|
11
|
+
* parallel so the fallback adds no latency in the common case.
|
|
12
|
+
*/
|
|
13
|
+
export declare function gatherPredictions(ctx: Ctx): Promise<PortfolioExtras>;
|
|
14
|
+
export declare function registerPortfolio(program: Command): void;
|
|
@@ -0,0 +1,100 @@
|
|
|
1
|
+
import { Command } from "commander";
|
|
2
|
+
import { PerfolioClient, AssetResolver, type Credentials, type TxResult, type SignTaskInput, type DisplayPrefs, type MoneyResolution, type CashTargetResolution, type ResolvedAsset } from "../lib/index.js";
|
|
3
|
+
/**
|
|
4
|
+
* Money-side command context — bridges the merged Grant Cash credentials to the
|
|
5
|
+
* ported Perfolio money engine.
|
|
6
|
+
*
|
|
7
|
+
* The standalone Perfolio CLI stored a FLAT credential ({ token, refreshToken,
|
|
8
|
+
* … }); Grant Cash stores a MERGED file ({ money: {...}, agent: {...} }). Both
|
|
9
|
+
* mint the same `pfk_` device token against the same Perfolio backend, so the
|
|
10
|
+
* only adaptation needed is reading/writing the `money` slot. Everything
|
|
11
|
+
* downstream (PerfolioClient, resolvers, sign flow) is reused verbatim.
|
|
12
|
+
*/
|
|
13
|
+
export interface Ctx {
|
|
14
|
+
client: PerfolioClient;
|
|
15
|
+
creds: Credentials;
|
|
16
|
+
credsPath: string;
|
|
17
|
+
json: boolean;
|
|
18
|
+
}
|
|
19
|
+
export declare function buildCtx(cmd: Command): Ctx;
|
|
20
|
+
export declare function requireAuth(ctx: Ctx): Credentials;
|
|
21
|
+
/** Load assets once and build a resolver. */
|
|
22
|
+
export declare function resolver(ctx: Ctx): Promise<AssetResolver>;
|
|
23
|
+
/**
|
|
24
|
+
* Resolve a user-entered CASH amount into a USD decimal string for the backend.
|
|
25
|
+
* A bare number is interpreted in the user's display currency; an explicit
|
|
26
|
+
* currency prefix ("$10", "₹50", "100 EUR") always wins. Non-USD amounts are
|
|
27
|
+
* converted via the live FX rate; refuses (throws) if that rate is unavailable.
|
|
28
|
+
*/
|
|
29
|
+
/**
|
|
30
|
+
* Force a bare numeric amount to USD by prefixing `$`. An amount the user already
|
|
31
|
+
* qualified with a currency ($/₹/€/ISO code) is left untouched — an explicit
|
|
32
|
+
* currency always wins (same rule money-input enforces). So `--usd` + "50" → "$50",
|
|
33
|
+
* but `--usd` + "₹50" stays ₹50.
|
|
34
|
+
*/
|
|
35
|
+
export declare function forceUsdAmount(raw: string): string;
|
|
36
|
+
export declare function resolveCash(ctx: Ctx, raw: string, decimals: number, opts?: {
|
|
37
|
+
usd?: boolean;
|
|
38
|
+
}): Promise<MoneyResolution>;
|
|
39
|
+
/**
|
|
40
|
+
* Live USD unit price for a spot asset, used to size a cash-target sell:
|
|
41
|
+
* gold → gold spot; btc/eth → /prices/crypto; stable → 1:1. Throws if the
|
|
42
|
+
* price can't be resolved (caller refuses to guess a quantity).
|
|
43
|
+
*/
|
|
44
|
+
export declare function assetUsdPrice(ctx: Ctx, asset: ResolvedAsset): Promise<number>;
|
|
45
|
+
/**
|
|
46
|
+
* Resolve a cash-denominated SELL/CONVERT target ("sell ₹100 of gold") into a
|
|
47
|
+
* quantity of the asset to sell. Refuses (throws) if either the FX rate or the
|
|
48
|
+
* asset price is unavailable — never guesses a money quantity.
|
|
49
|
+
*/
|
|
50
|
+
export declare function resolveCashTargetQty(ctx: Ctx, asset: ResolvedAsset, cashRaw: string): Promise<CashTargetResolution>;
|
|
51
|
+
/**
|
|
52
|
+
* Resolve the user's money-display preferences (currency, USD-vs-local, gold
|
|
53
|
+
* unit, experience mode) plus the live FX rate. Any failure falls back to safe
|
|
54
|
+
* USD defaults rather than breaking a read command.
|
|
55
|
+
*/
|
|
56
|
+
export declare function loadDisplayPrefs(ctx: Ctx): Promise<DisplayPrefs>;
|
|
57
|
+
/**
|
|
58
|
+
* Build the money-side SUCCESS envelope. The whole CLI — money and agent sides —
|
|
59
|
+
* speaks one contract: `{ ok: true, ...data }`. A plain object is spread in; an
|
|
60
|
+
* array / primitive is nested under `data` (spreading an array would splay its
|
|
61
|
+
* indices as keys). A redundant top-level `success` marker is dropped so `ok` is
|
|
62
|
+
* the single source of truth (closes the "trade cmds use {success:true}" gap).
|
|
63
|
+
* Pure + exported for unit testing.
|
|
64
|
+
*/
|
|
65
|
+
export declare function buildOutPayload(data: unknown): Record<string, unknown>;
|
|
66
|
+
/** Build the money-side FAILURE envelope: `{ ok:false, error:{code,message,recoverable} }`. */
|
|
67
|
+
export declare function buildErrorPayload(msg: string, opts?: {
|
|
68
|
+
code?: string;
|
|
69
|
+
recoverable?: boolean;
|
|
70
|
+
}): {
|
|
71
|
+
ok: false;
|
|
72
|
+
error: {
|
|
73
|
+
code: string;
|
|
74
|
+
message: string;
|
|
75
|
+
recoverable: boolean;
|
|
76
|
+
};
|
|
77
|
+
};
|
|
78
|
+
export declare function out(ctx: Ctx, human: string, data: unknown): void;
|
|
79
|
+
export declare function fail(msg: string, json: boolean, opts?: {
|
|
80
|
+
code?: string;
|
|
81
|
+
recoverable?: boolean;
|
|
82
|
+
}): never;
|
|
83
|
+
/**
|
|
84
|
+
* Report the outcome of a write. With `wait` (the default), poll the tx to a
|
|
85
|
+
* terminal state and report success/failure honestly — never "submitted". A
|
|
86
|
+
* failed tx exits non-zero; a timeout is reported as still-pending.
|
|
87
|
+
*/
|
|
88
|
+
export declare function reportTx(ctx: Ctx, res: TxResult, wait: boolean, label: string): Promise<void>;
|
|
89
|
+
/**
|
|
90
|
+
* Browser-sign hand-off for user-signed operations (withdrawal, gift, HL agent
|
|
91
|
+
* approval). The CLI prepared a self-describing sign task; here we hand it to
|
|
92
|
+
* the relay, open the browser for the user to sign + execute, then (for on-chain
|
|
93
|
+
* ops) confirm the resulting tx. The agent never holds a key — the user's Privy
|
|
94
|
+
* wallet signs.
|
|
95
|
+
*/
|
|
96
|
+
export declare function runSignFlow(ctx: Ctx, opts: {
|
|
97
|
+
task: SignTaskInput;
|
|
98
|
+
label: string;
|
|
99
|
+
confirmTx?: boolean;
|
|
100
|
+
}): Promise<boolean>;
|
|
@@ -0,0 +1,35 @@
|
|
|
1
|
+
import { Command } from 'commander';
|
|
2
|
+
import { type FiatAccount } from '../../lib/index.js';
|
|
3
|
+
export type DepositGate = {
|
|
4
|
+
ok: true;
|
|
5
|
+
status: string;
|
|
6
|
+
} | {
|
|
7
|
+
ok: false;
|
|
8
|
+
reason: 'KYC_REQUIRED' | 'PROVISIONING';
|
|
9
|
+
status: string;
|
|
10
|
+
};
|
|
11
|
+
/** Decide whether deposit details can be shown, or what's blocking. */
|
|
12
|
+
export declare function decideDepositGate(status: unknown, accounts: FiatAccount[]): DepositGate;
|
|
13
|
+
/**
|
|
14
|
+
* A real fiat deposit target = a non-empty IBAN or account number. Crypto accounts
|
|
15
|
+
* (USDT_ETH/USDC_ETH) come back with a bankDetails object full of EMPTY strings, so a
|
|
16
|
+
* mere "object exists / has keys" check is not enough — test the actual wire target.
|
|
17
|
+
*/
|
|
18
|
+
export declare function hasDepositDetails(a: FiatAccount): boolean;
|
|
19
|
+
/** Keep only accounts you can actually wire money to (skips crypto accounts), optionally filtered by currency. */
|
|
20
|
+
export declare function mapDepositAccounts(accounts: FiatAccount[], currency?: string): FiatAccount[];
|
|
21
|
+
/** Render a single account's bank-transfer details, tolerating both field-name variants. */
|
|
22
|
+
export declare function formatBankDetails(a: FiatAccount): string;
|
|
23
|
+
interface GraceOpts {
|
|
24
|
+
timeoutMs: number;
|
|
25
|
+
intervalMs: number;
|
|
26
|
+
sleep?: (ms: number) => Promise<void>;
|
|
27
|
+
now?: () => number;
|
|
28
|
+
}
|
|
29
|
+
/** Poll a KYC status fetcher until approved or a hard timeout. Never blocks past timeoutMs. */
|
|
30
|
+
export declare function gracePollKyc(getStatus: () => Promise<unknown>, opts: GraceOpts): Promise<{
|
|
31
|
+
approved: boolean;
|
|
32
|
+
status: string;
|
|
33
|
+
}>;
|
|
34
|
+
export declare function registerAccount(program: Command): void;
|
|
35
|
+
export {};
|
|
@@ -0,0 +1,9 @@
|
|
|
1
|
+
import { Command } from 'commander';
|
|
2
|
+
/**
|
|
3
|
+
* Whether an earn asset is a stablecoin (cash). Stable amounts are MONEY — entered
|
|
4
|
+
* in the user's currency and FX-resolved to USD (so "100" = ₹100 for an INR user,
|
|
5
|
+
* consistent with buy/borrow). Non-stable assets (WETH) keep asset-QUANTITY input
|
|
6
|
+
* (0.5 WETH = 0.5 WETH), like selling an asset by quantity. Exported for testing.
|
|
7
|
+
*/
|
|
8
|
+
export declare function isStableEarnAsset(symbol: string): boolean;
|
|
9
|
+
export declare function registerEarn(program: Command): void;
|
|
@@ -0,0 +1,32 @@
|
|
|
1
|
+
import { Command } from 'commander';
|
|
2
|
+
import { type DisplayPrefs } from '../../lib/index.js';
|
|
3
|
+
/**
|
|
4
|
+
* Hyperliquid's minimum order value ($10 notional). Used for a client-side
|
|
5
|
+
* pre-submit warning; the backend remains authoritative and re-validates.
|
|
6
|
+
*/
|
|
7
|
+
export declare const HL_MIN_ORDER_USD = 10;
|
|
8
|
+
/**
|
|
9
|
+
* Pre-submit minimum-order check. Returns a currency-aware warning string when
|
|
10
|
+
* `sizeUsd` is below Hyperliquid's $10 minimum, else null. Exported for testing.
|
|
11
|
+
*
|
|
12
|
+
* Renders the minimum in the user's display currency (e.g. ₹800 for an INR user
|
|
13
|
+
* at rate 80) so CLI traders see an amount in their own terms rather than a bare
|
|
14
|
+
* "$10" — the gap that left CLI users guessing why orders were rejected.
|
|
15
|
+
*/
|
|
16
|
+
export declare function minOrderHint(sizeUsd: number, prefs: DisplayPrefs, minUsd?: number): string | null;
|
|
17
|
+
/**
|
|
18
|
+
* Human-readable Hyperliquid account summary. Balance/equity/margin come back as
|
|
19
|
+
* USD strings; localize them. Exported for testing. Shape (from backend
|
|
20
|
+
* GET /api/hl/status): { isSetup, isApproved, balance, equity, availableMargin, marginUsed }.
|
|
21
|
+
*/
|
|
22
|
+
export declare function formatHlStatus(data: Record<string, unknown>, prefs: DisplayPrefs): string;
|
|
23
|
+
/**
|
|
24
|
+
* Hyperliquid perpetual trading.
|
|
25
|
+
*
|
|
26
|
+
* Reads + trades are AUTONOMOUS — the backend signs with a server-held,
|
|
27
|
+
* encrypted per-user agent key (HL's native API-wallet). The only step that
|
|
28
|
+
* needs the user is the one-time agent approval (`hl setup`), which signs an
|
|
29
|
+
* EIP-712 ApproveAgent action in the browser via the sign relay. After that,
|
|
30
|
+
* open/close/leverage/tpsl all run with no further interaction.
|
|
31
|
+
*/
|
|
32
|
+
export declare function registerHyperliquid(program: Command): void;
|
|
@@ -0,0 +1,8 @@
|
|
|
1
|
+
import { Command } from 'commander';
|
|
2
|
+
/**
|
|
3
|
+
* Loan + funding-address commands ported from the standalone Perfolio CLI. The
|
|
4
|
+
* combined `grant portfolio` / `grant balance` view (which folds in predictions
|
|
5
|
+
* + earn) lives separately in commands/portfolio.ts — these are the
|
|
6
|
+
* loan-detail and deposit-address commands that have no combined-view overlap.
|
|
7
|
+
*/
|
|
8
|
+
export declare function registerLoans(program: Command): void;
|
|
@@ -0,0 +1,11 @@
|
|
|
1
|
+
import { Command } from 'commander';
|
|
2
|
+
import { type DisplayPrefs } from '../../lib/index.js';
|
|
3
|
+
/**
|
|
4
|
+
* If a price feed is flagged stale, return a loud inline warning (e.g. " ⚠ stale
|
|
5
|
+
* (16h old)"); '' when fresh/unknown. A quiet `stale:true` boolean was easy to miss
|
|
6
|
+
* — acting on a 16-hour-old gold mark is a real risk, so it must be visible.
|
|
7
|
+
*/
|
|
8
|
+
export declare function staleNote(src: unknown): string;
|
|
9
|
+
/** Human-readable price board, localized to the user's currency + gold unit. Exported for tests. */
|
|
10
|
+
export declare function formatPrices(gold: unknown, crypto: unknown, prefs: DisplayPrefs): string;
|
|
11
|
+
export declare function registerMarket(program: Command): void;
|
|
@@ -0,0 +1,29 @@
|
|
|
1
|
+
import { Command } from 'commander';
|
|
2
|
+
import { type DisplayPrefs, type PolymarketMarket, type PolymarketPositionsResult, type PolymarketActivity } from '../../lib/index.js';
|
|
3
|
+
/**
|
|
4
|
+
* True if an error means the betting path is unavailable, so BOTH `--side yes`
|
|
5
|
+
* and `--side no` surface the same friendly line. The configured-off state comes
|
|
6
|
+
* back as 503 / POLYMARKET_TRADING_NOT_CONFIGURED, but the disabled `no` path was
|
|
7
|
+
* observed returning a bare upstream 502 (and 504 is the same class of gateway
|
|
8
|
+
* outage) — treat those as unavailable too rather than leaking a raw "HTTP 502".
|
|
9
|
+
* Exported for unit testing.
|
|
10
|
+
*/
|
|
11
|
+
export declare function isTradingDisabled(err: unknown): boolean;
|
|
12
|
+
/** Render a market list into human-readable lines. Exported for unit testing. */
|
|
13
|
+
export declare function formatMarkets(markets: PolymarketMarket[], count: number): string;
|
|
14
|
+
/**
|
|
15
|
+
* Render the prediction portfolio: a per-position table showing where each
|
|
16
|
+
* position has moved (entry → now, %) plus portfolio totals. Money is localized
|
|
17
|
+
* to the user's currency (defaults to USD for callers without prefs). Exported for tests.
|
|
18
|
+
*/
|
|
19
|
+
export declare function formatPositions(r: PolymarketPositionsResult, prefs?: DisplayPrefs): string;
|
|
20
|
+
/** Render prediction trade history (most recent first). Money localized. Exported for tests. */
|
|
21
|
+
export declare function formatActivity(activity: PolymarketActivity[], prefs?: DisplayPrefs): string;
|
|
22
|
+
/**
|
|
23
|
+
* Friendly one-liner for a funding-intent status. The backend relays an opaque
|
|
24
|
+
* tracker payload, so we defensively pull a `status` string (top-level or nested
|
|
25
|
+
* under `data`) and map the common terminal states to plain language; anything
|
|
26
|
+
* unrecognized degrades to "still on its way". Exported for tests.
|
|
27
|
+
*/
|
|
28
|
+
export declare function formatFundStatus(raw: unknown): string;
|
|
29
|
+
export declare function registerPolymarket(program: Command): void;
|
|
@@ -0,0 +1,14 @@
|
|
|
1
|
+
import { Command } from 'commander';
|
|
2
|
+
/**
|
|
3
|
+
* Spending account — the agent's pay-per-use balance (USDC on Base). It is
|
|
4
|
+
* funded by bridging cash out of the main account, mirroring the other
|
|
5
|
+
* account-to-account transfers already in the CLI:
|
|
6
|
+
* - cash ↔ trading → `hl deposit` / `hl withdraw`
|
|
7
|
+
* - cash ↔ predictions → `polymarket deposit` / `polymarket withdraw`
|
|
8
|
+
* - cash → spending → `spending deposit` (this file)
|
|
9
|
+
*
|
|
10
|
+
* The reverse (spending → cash) has NO backend route — the spending balance is
|
|
11
|
+
* receive-only, exactly as in the web app (AccountTransferFlow) — so we offer
|
|
12
|
+
* only the inbound transfer and don't fabricate a withdraw.
|
|
13
|
+
*/
|
|
14
|
+
export declare function registerSpending(program: Command): void;
|
|
@@ -0,0 +1,78 @@
|
|
|
1
|
+
import type { TokenHolder } from "./auth-session.js";
|
|
2
|
+
export interface AgentClientOpts {
|
|
3
|
+
agent: string;
|
|
4
|
+
/** Shared holder of the perfolio access JWT + refresh (drives refresh-on-401). */
|
|
5
|
+
auth?: TokenHolder;
|
|
6
|
+
fetchImpl?: typeof fetch;
|
|
7
|
+
}
|
|
8
|
+
export declare class AgentClient {
|
|
9
|
+
private base;
|
|
10
|
+
private auth?;
|
|
11
|
+
private f;
|
|
12
|
+
constructor(opts: AgentClientOpts);
|
|
13
|
+
get connected(): boolean;
|
|
14
|
+
private request;
|
|
15
|
+
/**
|
|
16
|
+
* Spendable funds + session state. Hits `GET /balance` (api-key auth), which
|
|
17
|
+
* returns the credit-aware status shape (active + USDC/USDT, not_set_up,
|
|
18
|
+
* credit_exhausted, or sign-up credit). NOT `/me` — that route is JWT-only and
|
|
19
|
+
* carries identity, not funds.
|
|
20
|
+
*/
|
|
21
|
+
balance(): Promise<Record<string, unknown>>;
|
|
22
|
+
/**
|
|
23
|
+
* The chain-agnostic spendable split — sign-up free credit + funds you added +
|
|
24
|
+
* total. Hits `GET /credit` (dual-auth, so the api-key works). This is the same
|
|
25
|
+
* figure the app shows on the Spending screen; `balance()` (/balance) carries
|
|
26
|
+
* the session status, so the portfolio uses both.
|
|
27
|
+
*/
|
|
28
|
+
credit(): Promise<Record<string, unknown>>;
|
|
29
|
+
/**
|
|
30
|
+
* Find a payable endpoint in the curated catalog. Hits `GET /marketplace/x402`
|
|
31
|
+
* (the grouped, public catalog route) — NOT `/marketplace`, which does not
|
|
32
|
+
* exist on the backend.
|
|
33
|
+
*/
|
|
34
|
+
search(query: string, limit?: number): Promise<Record<string, unknown>>;
|
|
35
|
+
/** Exact pay contract (requestSchema) for a URL — no spend. */
|
|
36
|
+
check(url: string): Promise<Record<string, unknown>>;
|
|
37
|
+
/** Recent transactions, newest first. */
|
|
38
|
+
transactions(limit?: number): Promise<Record<string, unknown>>;
|
|
39
|
+
/** One transaction by id. */
|
|
40
|
+
tx(id: string): Promise<Record<string, unknown>>;
|
|
41
|
+
/** Exact POST /x402/pay contract for a catalog entry by slug (requestSchema + price). No spend. */
|
|
42
|
+
schema(slug: string): Promise<Record<string, unknown>>;
|
|
43
|
+
/** Ingest any x402 origin's endpoints into the catalog so they become searchable/payable. */
|
|
44
|
+
discover(origin: string): Promise<Record<string, unknown>>;
|
|
45
|
+
/** Claim an invite / bonus credit by code. Mints or tops up the session's spendable funds. */
|
|
46
|
+
redeem(code: string): Promise<Record<string, unknown>>;
|
|
47
|
+
/** One-time link (+ code) to secure a full account and add funds. Gated by the session key. */
|
|
48
|
+
linkCode(): Promise<{
|
|
49
|
+
url: string;
|
|
50
|
+
code: string;
|
|
51
|
+
expiresAt: number;
|
|
52
|
+
}>;
|
|
53
|
+
/**
|
|
54
|
+
* Pay + run an endpoint via the session. Body matches `POST /x402/pay`'s
|
|
55
|
+
* schema: `method` is required (uppercased), `expectedPriceMinor` (the spend
|
|
56
|
+
* cap) and `asset` are required, and `body` is a RAW STRING passthrough — not
|
|
57
|
+
* a parsed object. The agent never signs; the session owns the spend.
|
|
58
|
+
*/
|
|
59
|
+
fetchPay(b: {
|
|
60
|
+
url: string;
|
|
61
|
+
method: string;
|
|
62
|
+
expectedPriceMinor: string;
|
|
63
|
+
asset: string;
|
|
64
|
+
body?: string;
|
|
65
|
+
}): Promise<Record<string, unknown>>;
|
|
66
|
+
/**
|
|
67
|
+
* Gasless transfer to an address. Hits `POST /transactions` (there is no
|
|
68
|
+
* `/transfer` route); body is `{ asset, amount, recipient }` where `amount` is
|
|
69
|
+
* the minor-units decimal string.
|
|
70
|
+
*/
|
|
71
|
+
transfer(b: {
|
|
72
|
+
recipient: string;
|
|
73
|
+
amount: string;
|
|
74
|
+
asset: string;
|
|
75
|
+
}): Promise<Record<string, unknown>>;
|
|
76
|
+
/** Stop all spend on this key — revoke the session (terminal). */
|
|
77
|
+
revoke(): Promise<Record<string, unknown>>;
|
|
78
|
+
}
|
|
@@ -0,0 +1,14 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Validate a human decimal amount without converting it. The Perfolio backend
|
|
3
|
+
* accepts decimal strings directly (it runs parseUnits server-side), so the
|
|
4
|
+
* CLI must NOT pre-convert to base units — passing base units would be
|
|
5
|
+
* misread by the Enso heuristic. This gives the same early "too many decimal
|
|
6
|
+
* places" feedback toBaseUnits would, then returns the trimmed decimal string.
|
|
7
|
+
*/
|
|
8
|
+
export declare function assertDecimal(value: string, decimals: number): string;
|
|
9
|
+
/** Convert a human decimal string to integer base units (no floats). */
|
|
10
|
+
export declare function toBaseUnits(value: string, decimals: number): string;
|
|
11
|
+
/** Convert integer base units back to a trimmed decimal string. */
|
|
12
|
+
export declare function fromBaseUnits(base: string, decimals: number): string;
|
|
13
|
+
/** Friendly display. Cash renders as currency; other assets as "<n> <friendly>". */
|
|
14
|
+
export declare function formatAmount(base: string, decimals: number, friendly: string): string;
|
|
@@ -0,0 +1,12 @@
|
|
|
1
|
+
import type { AssetDto, ResolvedAsset } from './types.js';
|
|
2
|
+
export declare const FRIENDLY_TERMS: readonly ["gold", "cash", "bitcoin", "ethereum"];
|
|
3
|
+
export declare class AssetResolver {
|
|
4
|
+
private byFriendly;
|
|
5
|
+
private friendlyBySymbol;
|
|
6
|
+
constructor(assets: AssetDto[]);
|
|
7
|
+
resolve(input: string): ResolvedAsset;
|
|
8
|
+
/** Friendly word for a backend symbol; falls back to the symbol itself. */
|
|
9
|
+
label(symbol: string): string;
|
|
10
|
+
/** True when a backend symbol maps to a v1 friendly term (canonical asset). */
|
|
11
|
+
isFriendly(symbol: string): boolean;
|
|
12
|
+
}
|
|
@@ -0,0 +1,57 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Unified-auth shared token holder.
|
|
3
|
+
*
|
|
4
|
+
* `grant login` mints ONE perfolio-signed access JWT; both backend clients
|
|
5
|
+
* (money + agent) send it as `Authorization: Bearer`. A single {@link TokenHolder}
|
|
6
|
+
* owns that JWT and the opaque `pfr_` refresh token, so a 401 from EITHER backend
|
|
7
|
+
* refreshes once and BOTH clients pick up the new JWT.
|
|
8
|
+
*
|
|
9
|
+
* The refresh is single-flight (concurrent 401s coalesce into one network call)
|
|
10
|
+
* and stale-aware ({@link TokenHolder.refreshIfStale}): a client that 401s with a
|
|
11
|
+
* token another client has already rotated past just uses the current token
|
|
12
|
+
* instead of spending the (rotating) refresh token a second time.
|
|
13
|
+
*/
|
|
14
|
+
export interface RefreshedTokens {
|
|
15
|
+
accessJwt: string;
|
|
16
|
+
refreshToken: string;
|
|
17
|
+
expiresAt: number;
|
|
18
|
+
}
|
|
19
|
+
/** Exchanges the current `pfr_` refresh token for a fresh access JWT (+ rotated refresh). */
|
|
20
|
+
export type RefreshFn = (refreshToken: string) => Promise<RefreshedTokens>;
|
|
21
|
+
export interface TokenHolderOpts {
|
|
22
|
+
accessJwt?: string;
|
|
23
|
+
refreshToken?: string;
|
|
24
|
+
refresh: RefreshFn;
|
|
25
|
+
/** Persist rotated tokens back to disk so the refresh survives across invocations. */
|
|
26
|
+
onRefresh?: (tokens: RefreshedTokens) => void;
|
|
27
|
+
}
|
|
28
|
+
export declare class TokenHolder {
|
|
29
|
+
private accessJwt?;
|
|
30
|
+
private refreshToken?;
|
|
31
|
+
private readonly doRefresh;
|
|
32
|
+
private readonly onRefresh?;
|
|
33
|
+
/** The in-flight refresh, if any — coalesces concurrent callers (single-flight). */
|
|
34
|
+
private inFlight?;
|
|
35
|
+
constructor(opts: TokenHolderOpts);
|
|
36
|
+
/** The current access JWT to send as `Authorization: Bearer`. */
|
|
37
|
+
get token(): string | undefined;
|
|
38
|
+
/**
|
|
39
|
+
* Refresh only if the caller's token is still the live one. If another client
|
|
40
|
+
* already rotated the token (current !== usedToken), return the current token
|
|
41
|
+
* without a second refresh — the caller should just retry with it.
|
|
42
|
+
*/
|
|
43
|
+
refreshIfStale(usedToken?: string): Promise<string | undefined>;
|
|
44
|
+
/**
|
|
45
|
+
* Rotate the access JWT via the refresh token. Single-flight: concurrent calls
|
|
46
|
+
* share one network round-trip. Returns the new JWT, or `undefined` if there is
|
|
47
|
+
* no refresh token or the refresh failed (the old token is left in place).
|
|
48
|
+
*/
|
|
49
|
+
refresh(): Promise<string | undefined>;
|
|
50
|
+
}
|
|
51
|
+
/**
|
|
52
|
+
* `POST {api}/cli/token/refresh` — exchange a `pfr_` refresh token for a fresh
|
|
53
|
+
* perfolio access JWT. Per CONTRACT v1 the payload is `{ accessJwt, refreshToken,
|
|
54
|
+
* expiresAt }`; it arrives inside perfolio's standard `{ success, data }` envelope.
|
|
55
|
+
* The legacy `token` field is accepted as a fallback during the migration window.
|
|
56
|
+
*/
|
|
57
|
+
export declare function refreshAccessToken(api: string, refreshToken: string, f?: typeof fetch): Promise<RefreshedTokens>;
|