@usepraxis/sdk 0.2.0 → 0.5.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 +25 -4
- package/dist/index.cjs +100 -5
- package/dist/index.cjs.map +1 -1
- package/dist/index.d.cts +154 -3
- package/dist/index.d.ts +154 -3
- package/dist/index.js +100 -5
- package/dist/index.js.map +1 -1
- package/package.json +5 -5
package/dist/index.d.cts
CHANGED
|
@@ -130,6 +130,14 @@ interface TransferDetail {
|
|
|
130
130
|
recipientName: string;
|
|
131
131
|
recipientAddress: Address;
|
|
132
132
|
recipientNote?: string;
|
|
133
|
+
/** The destination is the owner's own wallet (derived from the address). */
|
|
134
|
+
toSelf?: true;
|
|
135
|
+
/**
|
|
136
|
+
* Server-computed USD value of `amount`, as a decimal string, when a real
|
|
137
|
+
* price is available. Absent means "not known" — display only, and never an
|
|
138
|
+
* input to base-unit math.
|
|
139
|
+
*/
|
|
140
|
+
usdEstimate?: string;
|
|
133
141
|
}
|
|
134
142
|
interface SwapDetail {
|
|
135
143
|
kind: "swap";
|
|
@@ -144,6 +152,14 @@ type ProposalDetail = TransferDetail | SwapDetail;
|
|
|
144
152
|
type ProposalState = "pending" | "signing" | "signed" | "blocked" | "cancelled";
|
|
145
153
|
interface ActionProposal {
|
|
146
154
|
id: string;
|
|
155
|
+
/**
|
|
156
|
+
* Unix seconds when the proposal was produced. The signature gate refuses a
|
|
157
|
+
* proposal older than a week: the amount is fixed and Aegis enforces the
|
|
158
|
+
* envelope live, but the readings on it (fee, simulation, remaining
|
|
159
|
+
* envelope, USD figure) drift. Ask again for a fresh one. Absent on
|
|
160
|
+
* proposals created before this field existed.
|
|
161
|
+
*/
|
|
162
|
+
createdAt?: number;
|
|
147
163
|
detail: ProposalDetail;
|
|
148
164
|
networkFee: BaseUnitString;
|
|
149
165
|
simulation: string;
|
|
@@ -158,15 +174,46 @@ interface ClarifyOption {
|
|
|
158
174
|
}
|
|
159
175
|
interface ResearchMetric {
|
|
160
176
|
label: string;
|
|
177
|
+
/** Already display-formatted, and abbreviated where a raw figure is unreadable. */
|
|
161
178
|
value: string;
|
|
179
|
+
/** The full-precision figure behind an abbreviated `value`, when one was cut. */
|
|
180
|
+
exact?: string;
|
|
181
|
+
/** Why the metric is missing, or what it measures. */
|
|
182
|
+
note?: string;
|
|
162
183
|
trend?: "up" | "down" | "flat";
|
|
163
184
|
}
|
|
185
|
+
/**
|
|
186
|
+
* One step in how a research card was produced. A card whose whole claim is
|
|
187
|
+
* "data, no advice" has to be able to show its working: "unavailable" means
|
|
188
|
+
* something different when an indexer has no pair than when an RPC refused
|
|
189
|
+
* the query.
|
|
190
|
+
*/
|
|
191
|
+
interface ResearchSource {
|
|
192
|
+
/** "Solana RPC", "Market data (…)", "PreStocks", "Token resolution". */
|
|
193
|
+
label: string;
|
|
194
|
+
status: "ok" | "partial" | "unavailable";
|
|
195
|
+
detail: string;
|
|
196
|
+
}
|
|
164
197
|
interface ResearchData {
|
|
165
198
|
token: string;
|
|
199
|
+
/** Project name from the indexer, when it differs from the ticker. */
|
|
200
|
+
name?: string;
|
|
166
201
|
mint: Address;
|
|
167
202
|
metrics: ResearchMetric[];
|
|
203
|
+
/** How the card was produced, in the order the steps ran. */
|
|
204
|
+
sources?: ResearchSource[];
|
|
168
205
|
summary: string;
|
|
169
206
|
}
|
|
207
|
+
/**
|
|
208
|
+
* Stocklana C07: one PreStocks entry from `GET /get-stock-universe`.
|
|
209
|
+
* Empty unless the server runs with `PRAXIS_STOCKS_ENABLED=1`.
|
|
210
|
+
*/
|
|
211
|
+
interface StockUniverseEntry {
|
|
212
|
+
symbol: string;
|
|
213
|
+
name: string;
|
|
214
|
+
mint: Address;
|
|
215
|
+
decimals: number;
|
|
216
|
+
}
|
|
170
217
|
interface PolicyChangeRow {
|
|
171
218
|
label: string;
|
|
172
219
|
from: string;
|
|
@@ -221,6 +268,8 @@ interface ActivityEntry {
|
|
|
221
268
|
id: string;
|
|
222
269
|
kind: "transfer" | "swap";
|
|
223
270
|
label: string;
|
|
271
|
+
/** Destination address for a transfer. Stable where `label` is a lookup. */
|
|
272
|
+
target?: Address;
|
|
224
273
|
asset: string;
|
|
225
274
|
amount: BaseUnitString;
|
|
226
275
|
decimals: number;
|
|
@@ -230,11 +279,46 @@ interface ActivityEntry {
|
|
|
230
279
|
ts: number;
|
|
231
280
|
sig?: string;
|
|
232
281
|
}
|
|
282
|
+
/** When a recurring buy fires. `weekday`: 0=Sunday..6=Saturday (UTC). */
|
|
283
|
+
type DcaCadence = {
|
|
284
|
+
type: "daily";
|
|
285
|
+
} | {
|
|
286
|
+
type: "weekly";
|
|
287
|
+
weekday: number;
|
|
288
|
+
} | {
|
|
289
|
+
type: "monthly";
|
|
290
|
+
day: number;
|
|
291
|
+
};
|
|
292
|
+
/**
|
|
293
|
+
* One recurring-buy schedule from `GET /get-schedules`. Each fire emits one
|
|
294
|
+
* transfer proposal through the same policy checks as a one-off buy — nothing
|
|
295
|
+
* ever auto-signs. Money is a base-unit string per the money rule above.
|
|
296
|
+
*/
|
|
297
|
+
interface DcaSchedule {
|
|
298
|
+
id: string;
|
|
299
|
+
asset: string;
|
|
300
|
+
amount: BaseUnitString;
|
|
301
|
+
decimals: number;
|
|
302
|
+
recipientAddress: Address;
|
|
303
|
+
recipientName: string;
|
|
304
|
+
cadence: DcaCadence;
|
|
305
|
+
/** Unix milliseconds of the next fire. */
|
|
306
|
+
nextFireTs: number;
|
|
307
|
+
createdAt: number;
|
|
308
|
+
threadId: string;
|
|
309
|
+
}
|
|
233
310
|
interface UnsignedOwnerTransaction {
|
|
234
311
|
/** base64-encoded unsigned transaction for the owner wallet to sign. */
|
|
235
312
|
transaction: string;
|
|
236
313
|
blockhash: string;
|
|
237
314
|
lastValidBlockHeight: number;
|
|
315
|
+
/**
|
|
316
|
+
* Opaque, backend-signed fingerprint of this draft. Echo it back verbatim in
|
|
317
|
+
* {@link SignedOwnerTransaction}: the relay refuses any transaction that is
|
|
318
|
+
* not the one Praxis built, which is what keeps the server-side checks for
|
|
319
|
+
* this action from being skippable.
|
|
320
|
+
*/
|
|
321
|
+
draft: string;
|
|
238
322
|
}
|
|
239
323
|
/**
|
|
240
324
|
* An {@link UnsignedOwnerTransaction} after the owner wallet has signed it — the
|
|
@@ -268,6 +352,14 @@ type OwnerAction = {
|
|
|
268
352
|
listKind: AllowListKind;
|
|
269
353
|
address: Address;
|
|
270
354
|
mode: "add" | "remove";
|
|
355
|
+
} | {
|
|
356
|
+
kind: "configureToken";
|
|
357
|
+
tokenMint: Address;
|
|
358
|
+
tokenMaxPerTx: BaseUnitString;
|
|
359
|
+
tokenDailyLimit: BaseUnitString;
|
|
360
|
+
} | {
|
|
361
|
+
kind: "prepareTokenAccounts";
|
|
362
|
+
recipientAddresses?: Address[];
|
|
271
363
|
};
|
|
272
364
|
|
|
273
365
|
type FetchLike = (input: string, init?: RequestInit) => Promise<Response>;
|
|
@@ -349,14 +441,39 @@ declare class PraxisClient {
|
|
|
349
441
|
}>;
|
|
350
442
|
signProposal(proposalId: string): Promise<void>;
|
|
351
443
|
cancelProposal(proposalId: string): Promise<void>;
|
|
444
|
+
/** List recurring-buy schedules (each fire emits one proposal; never signs). */
|
|
445
|
+
getSchedules(): Promise<DcaSchedule[]>;
|
|
446
|
+
/** Stop a recurring-buy schedule. Unknown ids are a no-op (idempotent). */
|
|
447
|
+
cancelSchedule(scheduleId: string): Promise<void>;
|
|
448
|
+
/** Save (or rename) an address-book contact. Labels have no signing power. */
|
|
449
|
+
addContact(label: string, address: string): Promise<void>;
|
|
450
|
+
/** Remove a contact by address or label (case-insensitive, idempotent). */
|
|
451
|
+
removeContact(key: string): Promise<void>;
|
|
352
452
|
getThreads(): Promise<Thread[]>;
|
|
353
453
|
getThread(id: string): Promise<Thread>;
|
|
354
454
|
getProposal(id: string): Promise<ActionProposal>;
|
|
455
|
+
/**
|
|
456
|
+
* Every proposal this wallet holds, in one request. Prefer this over a loop
|
|
457
|
+
* of {@link getProposal}: a per-id fetch is what trips the read rate limit
|
|
458
|
+
* on a busy thread.
|
|
459
|
+
*/
|
|
460
|
+
getProposals(): Promise<ActionProposal[]>;
|
|
355
461
|
getPolicy(): Promise<PolicyView>;
|
|
356
462
|
getActivity(): Promise<ActivityEntry[]>;
|
|
357
463
|
getAddressBook(): Promise<AddressBookEntry[]>;
|
|
358
|
-
isThinking(threadId: string): Promise<boolean>;
|
|
359
464
|
getVersion(): Promise<number>;
|
|
465
|
+
/**
|
|
466
|
+
* The server's stock universe (`[]` when `PRAXIS_STOCKS_ENABLED` is off).
|
|
467
|
+
* Read-only; symbols/mints here are the only pre-IPO stocks Praxis will
|
|
468
|
+
* touch (bounty exclusivity is enforced server-side).
|
|
469
|
+
*/
|
|
470
|
+
getTokenUniverse(): Promise<StockUniverseEntry[]>;
|
|
471
|
+
/**
|
|
472
|
+
* Read-only research for a stock symbol, via the agent (`research <symbol>`).
|
|
473
|
+
* Returns neutral market data — never advice. Throws when the agent has no
|
|
474
|
+
* research to show (unknown symbol or unavailable quotes).
|
|
475
|
+
*/
|
|
476
|
+
getStockResearch(symbol: string): Promise<ResearchData>;
|
|
360
477
|
bootstrapPolicy(fundLamports?: BaseUnitString): Promise<void>;
|
|
361
478
|
/** Deposit SOL (lamports, base-unit string) from the owner into the vault. */
|
|
362
479
|
fundVault(amount: BaseUnitString): Promise<void>;
|
|
@@ -384,21 +501,51 @@ declare class PraxisClient {
|
|
|
384
501
|
}>;
|
|
385
502
|
private get;
|
|
386
503
|
private post;
|
|
504
|
+
/**
|
|
505
|
+
* Run a request, and if the session has expired, sign in again and retry it
|
|
506
|
+
* once.
|
|
507
|
+
*
|
|
508
|
+
* Sessions are deliberately short — holding one is enough to move value
|
|
509
|
+
* within the Aegis envelope — so a long-lived agent process WILL outlive its
|
|
510
|
+
* cookie. Without this, every caller writes the same catch-401-and-reconnect
|
|
511
|
+
* block, and the ones who do not simply stop working after a day. Retried
|
|
512
|
+
* once only, never for the auth endpoints themselves, and only when a signer
|
|
513
|
+
* is configured; without one there is nothing to re-authenticate with and the
|
|
514
|
+
* 401 is the honest answer.
|
|
515
|
+
*/
|
|
387
516
|
private request;
|
|
517
|
+
private send1;
|
|
388
518
|
private captureCookie;
|
|
389
519
|
}
|
|
390
520
|
|
|
521
|
+
/**
|
|
522
|
+
* A stable, machine-readable classification of a backend failure. Branch on
|
|
523
|
+
* this rather than on `message`, which is human prose and free to change.
|
|
524
|
+
* `client_error` is synthesized SDK-side for failures with no HTTP response
|
|
525
|
+
* (timeout, DNS, TLS).
|
|
526
|
+
*/
|
|
527
|
+
type PraxisErrorCode = "config_error" | "unauthorized" | "invalid_input" | "not_found"
|
|
528
|
+
/** The wallet has no Aegis policy account yet — call `bootstrapPolicy`. */
|
|
529
|
+
| "policy_not_found" | "rate_limited"
|
|
530
|
+
/** A concurrent writer changed this wallet's state first; reload and retry. */
|
|
531
|
+
| "conflict" | "internal_error" | "client_error";
|
|
391
532
|
/**
|
|
392
533
|
* Thrown when the Praxis API returns a non-2xx response. The backend's error
|
|
393
|
-
* envelope is `{ error
|
|
534
|
+
* envelope is `{ error, type, code, details? }` with a meaningful HTTP status
|
|
394
535
|
* (400 input, 401 auth, 404 not-found, 429 rate-limit, 503 config, 500 other).
|
|
395
536
|
*/
|
|
396
537
|
declare class PraxisApiError extends Error {
|
|
397
538
|
readonly status: number;
|
|
398
539
|
/** The backend error class name, e.g. "PraxisAuthError", "PraxisRateLimitError". */
|
|
399
540
|
readonly type: string;
|
|
541
|
+
/** Stable error classification — the field to branch on. */
|
|
542
|
+
readonly code: PraxisErrorCode;
|
|
543
|
+
/** Structured facts about the failure, e.g. `{ policyAddress }` for `policy_not_found`. */
|
|
544
|
+
readonly details?: Record<string, string | number | boolean>;
|
|
400
545
|
constructor(status: number, type: string, message: string, options?: {
|
|
401
546
|
cause?: unknown;
|
|
547
|
+
code?: PraxisErrorCode;
|
|
548
|
+
details?: Record<string, string | number | boolean>;
|
|
402
549
|
});
|
|
403
550
|
get isAuth(): boolean;
|
|
404
551
|
get isRateLimited(): boolean;
|
|
@@ -413,6 +560,10 @@ declare class PraxisApiError extends Error {
|
|
|
413
560
|
get isNetwork(): boolean;
|
|
414
561
|
/** Any server-side failure (HTTP >= 500). */
|
|
415
562
|
get isServer(): boolean;
|
|
563
|
+
/** The wallet has no Aegis policy yet — the first-run state, not a fault. */
|
|
564
|
+
get isPolicyNotFound(): boolean;
|
|
565
|
+
/** A concurrent writer won; the call is safe to retry after a reload. */
|
|
566
|
+
get isConflict(): boolean;
|
|
416
567
|
}
|
|
417
568
|
/** Thrown for SDK-side misconfiguration (no fetch, no signer, bad key, …). */
|
|
418
569
|
declare class PraxisConfigError extends Error {
|
|
@@ -443,4 +594,4 @@ declare function humanToBaseUnits(amount: string, decimals: number): string;
|
|
|
443
594
|
/** Convert base units into a human decimal string for `decimals` places. */
|
|
444
595
|
declare function baseUnitsToHuman(value: string | bigint, decimals: number): string;
|
|
445
596
|
|
|
446
|
-
export { ActionKind, type ActionProposal, type ActivityEntry, type Address, type AddressBookEntry, type AgentBlock, type AgentMessage, type AllowListKind, type AskResult, type BaseUnitString, type ClarifyOption, type FetchLike, type Message, type OwnerAction, type PolicyChangeRow, type PolicyCheckResult, type PolicyUpdate, type PolicyView, PraxisApiError, PraxisClient, type PraxisClientOptions, PraxisConfigError, type PraxisSigner, type ProposalDetail, type ProposalState, RejectReason, type ResearchData, type ResearchMetric, type SecretKeyInput, type SessionInfo, type SignedOwnerTransaction, type SwapDetail, type Thread, type TokenEnvelopeConfig, type TokenInfo, type TransferDetail, type UnsignedOwnerTransaction, type UserMessage, type WalletChallenge, baseUnitsToHuman, fromBaseUnits, humanToBaseUnits, keypairSigner, toBaseUnits };
|
|
597
|
+
export { ActionKind, type ActionProposal, type ActivityEntry, type Address, type AddressBookEntry, type AgentBlock, type AgentMessage, type AllowListKind, type AskResult, type BaseUnitString, type ClarifyOption, type DcaCadence, type DcaSchedule, type FetchLike, type Message, type OwnerAction, type PolicyChangeRow, type PolicyCheckResult, type PolicyUpdate, type PolicyView, PraxisApiError, PraxisClient, type PraxisClientOptions, PraxisConfigError, type PraxisErrorCode, type PraxisSigner, type ProposalDetail, type ProposalState, RejectReason, type ResearchData, type ResearchMetric, type ResearchSource, type SecretKeyInput, type SessionInfo, type SignedOwnerTransaction, type StockUniverseEntry, type SwapDetail, type Thread, type TokenEnvelopeConfig, type TokenInfo, type TransferDetail, type UnsignedOwnerTransaction, type UserMessage, type WalletChallenge, baseUnitsToHuman, fromBaseUnits, humanToBaseUnits, keypairSigner, toBaseUnits };
|
package/dist/index.d.ts
CHANGED
|
@@ -130,6 +130,14 @@ interface TransferDetail {
|
|
|
130
130
|
recipientName: string;
|
|
131
131
|
recipientAddress: Address;
|
|
132
132
|
recipientNote?: string;
|
|
133
|
+
/** The destination is the owner's own wallet (derived from the address). */
|
|
134
|
+
toSelf?: true;
|
|
135
|
+
/**
|
|
136
|
+
* Server-computed USD value of `amount`, as a decimal string, when a real
|
|
137
|
+
* price is available. Absent means "not known" — display only, and never an
|
|
138
|
+
* input to base-unit math.
|
|
139
|
+
*/
|
|
140
|
+
usdEstimate?: string;
|
|
133
141
|
}
|
|
134
142
|
interface SwapDetail {
|
|
135
143
|
kind: "swap";
|
|
@@ -144,6 +152,14 @@ type ProposalDetail = TransferDetail | SwapDetail;
|
|
|
144
152
|
type ProposalState = "pending" | "signing" | "signed" | "blocked" | "cancelled";
|
|
145
153
|
interface ActionProposal {
|
|
146
154
|
id: string;
|
|
155
|
+
/**
|
|
156
|
+
* Unix seconds when the proposal was produced. The signature gate refuses a
|
|
157
|
+
* proposal older than a week: the amount is fixed and Aegis enforces the
|
|
158
|
+
* envelope live, but the readings on it (fee, simulation, remaining
|
|
159
|
+
* envelope, USD figure) drift. Ask again for a fresh one. Absent on
|
|
160
|
+
* proposals created before this field existed.
|
|
161
|
+
*/
|
|
162
|
+
createdAt?: number;
|
|
147
163
|
detail: ProposalDetail;
|
|
148
164
|
networkFee: BaseUnitString;
|
|
149
165
|
simulation: string;
|
|
@@ -158,15 +174,46 @@ interface ClarifyOption {
|
|
|
158
174
|
}
|
|
159
175
|
interface ResearchMetric {
|
|
160
176
|
label: string;
|
|
177
|
+
/** Already display-formatted, and abbreviated where a raw figure is unreadable. */
|
|
161
178
|
value: string;
|
|
179
|
+
/** The full-precision figure behind an abbreviated `value`, when one was cut. */
|
|
180
|
+
exact?: string;
|
|
181
|
+
/** Why the metric is missing, or what it measures. */
|
|
182
|
+
note?: string;
|
|
162
183
|
trend?: "up" | "down" | "flat";
|
|
163
184
|
}
|
|
185
|
+
/**
|
|
186
|
+
* One step in how a research card was produced. A card whose whole claim is
|
|
187
|
+
* "data, no advice" has to be able to show its working: "unavailable" means
|
|
188
|
+
* something different when an indexer has no pair than when an RPC refused
|
|
189
|
+
* the query.
|
|
190
|
+
*/
|
|
191
|
+
interface ResearchSource {
|
|
192
|
+
/** "Solana RPC", "Market data (…)", "PreStocks", "Token resolution". */
|
|
193
|
+
label: string;
|
|
194
|
+
status: "ok" | "partial" | "unavailable";
|
|
195
|
+
detail: string;
|
|
196
|
+
}
|
|
164
197
|
interface ResearchData {
|
|
165
198
|
token: string;
|
|
199
|
+
/** Project name from the indexer, when it differs from the ticker. */
|
|
200
|
+
name?: string;
|
|
166
201
|
mint: Address;
|
|
167
202
|
metrics: ResearchMetric[];
|
|
203
|
+
/** How the card was produced, in the order the steps ran. */
|
|
204
|
+
sources?: ResearchSource[];
|
|
168
205
|
summary: string;
|
|
169
206
|
}
|
|
207
|
+
/**
|
|
208
|
+
* Stocklana C07: one PreStocks entry from `GET /get-stock-universe`.
|
|
209
|
+
* Empty unless the server runs with `PRAXIS_STOCKS_ENABLED=1`.
|
|
210
|
+
*/
|
|
211
|
+
interface StockUniverseEntry {
|
|
212
|
+
symbol: string;
|
|
213
|
+
name: string;
|
|
214
|
+
mint: Address;
|
|
215
|
+
decimals: number;
|
|
216
|
+
}
|
|
170
217
|
interface PolicyChangeRow {
|
|
171
218
|
label: string;
|
|
172
219
|
from: string;
|
|
@@ -221,6 +268,8 @@ interface ActivityEntry {
|
|
|
221
268
|
id: string;
|
|
222
269
|
kind: "transfer" | "swap";
|
|
223
270
|
label: string;
|
|
271
|
+
/** Destination address for a transfer. Stable where `label` is a lookup. */
|
|
272
|
+
target?: Address;
|
|
224
273
|
asset: string;
|
|
225
274
|
amount: BaseUnitString;
|
|
226
275
|
decimals: number;
|
|
@@ -230,11 +279,46 @@ interface ActivityEntry {
|
|
|
230
279
|
ts: number;
|
|
231
280
|
sig?: string;
|
|
232
281
|
}
|
|
282
|
+
/** When a recurring buy fires. `weekday`: 0=Sunday..6=Saturday (UTC). */
|
|
283
|
+
type DcaCadence = {
|
|
284
|
+
type: "daily";
|
|
285
|
+
} | {
|
|
286
|
+
type: "weekly";
|
|
287
|
+
weekday: number;
|
|
288
|
+
} | {
|
|
289
|
+
type: "monthly";
|
|
290
|
+
day: number;
|
|
291
|
+
};
|
|
292
|
+
/**
|
|
293
|
+
* One recurring-buy schedule from `GET /get-schedules`. Each fire emits one
|
|
294
|
+
* transfer proposal through the same policy checks as a one-off buy — nothing
|
|
295
|
+
* ever auto-signs. Money is a base-unit string per the money rule above.
|
|
296
|
+
*/
|
|
297
|
+
interface DcaSchedule {
|
|
298
|
+
id: string;
|
|
299
|
+
asset: string;
|
|
300
|
+
amount: BaseUnitString;
|
|
301
|
+
decimals: number;
|
|
302
|
+
recipientAddress: Address;
|
|
303
|
+
recipientName: string;
|
|
304
|
+
cadence: DcaCadence;
|
|
305
|
+
/** Unix milliseconds of the next fire. */
|
|
306
|
+
nextFireTs: number;
|
|
307
|
+
createdAt: number;
|
|
308
|
+
threadId: string;
|
|
309
|
+
}
|
|
233
310
|
interface UnsignedOwnerTransaction {
|
|
234
311
|
/** base64-encoded unsigned transaction for the owner wallet to sign. */
|
|
235
312
|
transaction: string;
|
|
236
313
|
blockhash: string;
|
|
237
314
|
lastValidBlockHeight: number;
|
|
315
|
+
/**
|
|
316
|
+
* Opaque, backend-signed fingerprint of this draft. Echo it back verbatim in
|
|
317
|
+
* {@link SignedOwnerTransaction}: the relay refuses any transaction that is
|
|
318
|
+
* not the one Praxis built, which is what keeps the server-side checks for
|
|
319
|
+
* this action from being skippable.
|
|
320
|
+
*/
|
|
321
|
+
draft: string;
|
|
238
322
|
}
|
|
239
323
|
/**
|
|
240
324
|
* An {@link UnsignedOwnerTransaction} after the owner wallet has signed it — the
|
|
@@ -268,6 +352,14 @@ type OwnerAction = {
|
|
|
268
352
|
listKind: AllowListKind;
|
|
269
353
|
address: Address;
|
|
270
354
|
mode: "add" | "remove";
|
|
355
|
+
} | {
|
|
356
|
+
kind: "configureToken";
|
|
357
|
+
tokenMint: Address;
|
|
358
|
+
tokenMaxPerTx: BaseUnitString;
|
|
359
|
+
tokenDailyLimit: BaseUnitString;
|
|
360
|
+
} | {
|
|
361
|
+
kind: "prepareTokenAccounts";
|
|
362
|
+
recipientAddresses?: Address[];
|
|
271
363
|
};
|
|
272
364
|
|
|
273
365
|
type FetchLike = (input: string, init?: RequestInit) => Promise<Response>;
|
|
@@ -349,14 +441,39 @@ declare class PraxisClient {
|
|
|
349
441
|
}>;
|
|
350
442
|
signProposal(proposalId: string): Promise<void>;
|
|
351
443
|
cancelProposal(proposalId: string): Promise<void>;
|
|
444
|
+
/** List recurring-buy schedules (each fire emits one proposal; never signs). */
|
|
445
|
+
getSchedules(): Promise<DcaSchedule[]>;
|
|
446
|
+
/** Stop a recurring-buy schedule. Unknown ids are a no-op (idempotent). */
|
|
447
|
+
cancelSchedule(scheduleId: string): Promise<void>;
|
|
448
|
+
/** Save (or rename) an address-book contact. Labels have no signing power. */
|
|
449
|
+
addContact(label: string, address: string): Promise<void>;
|
|
450
|
+
/** Remove a contact by address or label (case-insensitive, idempotent). */
|
|
451
|
+
removeContact(key: string): Promise<void>;
|
|
352
452
|
getThreads(): Promise<Thread[]>;
|
|
353
453
|
getThread(id: string): Promise<Thread>;
|
|
354
454
|
getProposal(id: string): Promise<ActionProposal>;
|
|
455
|
+
/**
|
|
456
|
+
* Every proposal this wallet holds, in one request. Prefer this over a loop
|
|
457
|
+
* of {@link getProposal}: a per-id fetch is what trips the read rate limit
|
|
458
|
+
* on a busy thread.
|
|
459
|
+
*/
|
|
460
|
+
getProposals(): Promise<ActionProposal[]>;
|
|
355
461
|
getPolicy(): Promise<PolicyView>;
|
|
356
462
|
getActivity(): Promise<ActivityEntry[]>;
|
|
357
463
|
getAddressBook(): Promise<AddressBookEntry[]>;
|
|
358
|
-
isThinking(threadId: string): Promise<boolean>;
|
|
359
464
|
getVersion(): Promise<number>;
|
|
465
|
+
/**
|
|
466
|
+
* The server's stock universe (`[]` when `PRAXIS_STOCKS_ENABLED` is off).
|
|
467
|
+
* Read-only; symbols/mints here are the only pre-IPO stocks Praxis will
|
|
468
|
+
* touch (bounty exclusivity is enforced server-side).
|
|
469
|
+
*/
|
|
470
|
+
getTokenUniverse(): Promise<StockUniverseEntry[]>;
|
|
471
|
+
/**
|
|
472
|
+
* Read-only research for a stock symbol, via the agent (`research <symbol>`).
|
|
473
|
+
* Returns neutral market data — never advice. Throws when the agent has no
|
|
474
|
+
* research to show (unknown symbol or unavailable quotes).
|
|
475
|
+
*/
|
|
476
|
+
getStockResearch(symbol: string): Promise<ResearchData>;
|
|
360
477
|
bootstrapPolicy(fundLamports?: BaseUnitString): Promise<void>;
|
|
361
478
|
/** Deposit SOL (lamports, base-unit string) from the owner into the vault. */
|
|
362
479
|
fundVault(amount: BaseUnitString): Promise<void>;
|
|
@@ -384,21 +501,51 @@ declare class PraxisClient {
|
|
|
384
501
|
}>;
|
|
385
502
|
private get;
|
|
386
503
|
private post;
|
|
504
|
+
/**
|
|
505
|
+
* Run a request, and if the session has expired, sign in again and retry it
|
|
506
|
+
* once.
|
|
507
|
+
*
|
|
508
|
+
* Sessions are deliberately short — holding one is enough to move value
|
|
509
|
+
* within the Aegis envelope — so a long-lived agent process WILL outlive its
|
|
510
|
+
* cookie. Without this, every caller writes the same catch-401-and-reconnect
|
|
511
|
+
* block, and the ones who do not simply stop working after a day. Retried
|
|
512
|
+
* once only, never for the auth endpoints themselves, and only when a signer
|
|
513
|
+
* is configured; without one there is nothing to re-authenticate with and the
|
|
514
|
+
* 401 is the honest answer.
|
|
515
|
+
*/
|
|
387
516
|
private request;
|
|
517
|
+
private send1;
|
|
388
518
|
private captureCookie;
|
|
389
519
|
}
|
|
390
520
|
|
|
521
|
+
/**
|
|
522
|
+
* A stable, machine-readable classification of a backend failure. Branch on
|
|
523
|
+
* this rather than on `message`, which is human prose and free to change.
|
|
524
|
+
* `client_error` is synthesized SDK-side for failures with no HTTP response
|
|
525
|
+
* (timeout, DNS, TLS).
|
|
526
|
+
*/
|
|
527
|
+
type PraxisErrorCode = "config_error" | "unauthorized" | "invalid_input" | "not_found"
|
|
528
|
+
/** The wallet has no Aegis policy account yet — call `bootstrapPolicy`. */
|
|
529
|
+
| "policy_not_found" | "rate_limited"
|
|
530
|
+
/** A concurrent writer changed this wallet's state first; reload and retry. */
|
|
531
|
+
| "conflict" | "internal_error" | "client_error";
|
|
391
532
|
/**
|
|
392
533
|
* Thrown when the Praxis API returns a non-2xx response. The backend's error
|
|
393
|
-
* envelope is `{ error
|
|
534
|
+
* envelope is `{ error, type, code, details? }` with a meaningful HTTP status
|
|
394
535
|
* (400 input, 401 auth, 404 not-found, 429 rate-limit, 503 config, 500 other).
|
|
395
536
|
*/
|
|
396
537
|
declare class PraxisApiError extends Error {
|
|
397
538
|
readonly status: number;
|
|
398
539
|
/** The backend error class name, e.g. "PraxisAuthError", "PraxisRateLimitError". */
|
|
399
540
|
readonly type: string;
|
|
541
|
+
/** Stable error classification — the field to branch on. */
|
|
542
|
+
readonly code: PraxisErrorCode;
|
|
543
|
+
/** Structured facts about the failure, e.g. `{ policyAddress }` for `policy_not_found`. */
|
|
544
|
+
readonly details?: Record<string, string | number | boolean>;
|
|
400
545
|
constructor(status: number, type: string, message: string, options?: {
|
|
401
546
|
cause?: unknown;
|
|
547
|
+
code?: PraxisErrorCode;
|
|
548
|
+
details?: Record<string, string | number | boolean>;
|
|
402
549
|
});
|
|
403
550
|
get isAuth(): boolean;
|
|
404
551
|
get isRateLimited(): boolean;
|
|
@@ -413,6 +560,10 @@ declare class PraxisApiError extends Error {
|
|
|
413
560
|
get isNetwork(): boolean;
|
|
414
561
|
/** Any server-side failure (HTTP >= 500). */
|
|
415
562
|
get isServer(): boolean;
|
|
563
|
+
/** The wallet has no Aegis policy yet — the first-run state, not a fault. */
|
|
564
|
+
get isPolicyNotFound(): boolean;
|
|
565
|
+
/** A concurrent writer won; the call is safe to retry after a reload. */
|
|
566
|
+
get isConflict(): boolean;
|
|
416
567
|
}
|
|
417
568
|
/** Thrown for SDK-side misconfiguration (no fetch, no signer, bad key, …). */
|
|
418
569
|
declare class PraxisConfigError extends Error {
|
|
@@ -443,4 +594,4 @@ declare function humanToBaseUnits(amount: string, decimals: number): string;
|
|
|
443
594
|
/** Convert base units into a human decimal string for `decimals` places. */
|
|
444
595
|
declare function baseUnitsToHuman(value: string | bigint, decimals: number): string;
|
|
445
596
|
|
|
446
|
-
export { ActionKind, type ActionProposal, type ActivityEntry, type Address, type AddressBookEntry, type AgentBlock, type AgentMessage, type AllowListKind, type AskResult, type BaseUnitString, type ClarifyOption, type FetchLike, type Message, type OwnerAction, type PolicyChangeRow, type PolicyCheckResult, type PolicyUpdate, type PolicyView, PraxisApiError, PraxisClient, type PraxisClientOptions, PraxisConfigError, type PraxisSigner, type ProposalDetail, type ProposalState, RejectReason, type ResearchData, type ResearchMetric, type SecretKeyInput, type SessionInfo, type SignedOwnerTransaction, type SwapDetail, type Thread, type TokenEnvelopeConfig, type TokenInfo, type TransferDetail, type UnsignedOwnerTransaction, type UserMessage, type WalletChallenge, baseUnitsToHuman, fromBaseUnits, humanToBaseUnits, keypairSigner, toBaseUnits };
|
|
597
|
+
export { ActionKind, type ActionProposal, type ActivityEntry, type Address, type AddressBookEntry, type AgentBlock, type AgentMessage, type AllowListKind, type AskResult, type BaseUnitString, type ClarifyOption, type DcaCadence, type DcaSchedule, type FetchLike, type Message, type OwnerAction, type PolicyChangeRow, type PolicyCheckResult, type PolicyUpdate, type PolicyView, PraxisApiError, PraxisClient, type PraxisClientOptions, PraxisConfigError, type PraxisErrorCode, type PraxisSigner, type ProposalDetail, type ProposalState, RejectReason, type ResearchData, type ResearchMetric, type ResearchSource, type SecretKeyInput, type SessionInfo, type SignedOwnerTransaction, type StockUniverseEntry, type SwapDetail, type Thread, type TokenEnvelopeConfig, type TokenInfo, type TransferDetail, type UnsignedOwnerTransaction, type UserMessage, type WalletChallenge, baseUnitsToHuman, fromBaseUnits, humanToBaseUnits, keypairSigner, toBaseUnits };
|
package/dist/index.js
CHANGED
|
@@ -8,11 +8,17 @@ var PraxisApiError = class _PraxisApiError extends Error {
|
|
|
8
8
|
status;
|
|
9
9
|
/** The backend error class name, e.g. "PraxisAuthError", "PraxisRateLimitError". */
|
|
10
10
|
type;
|
|
11
|
+
/** Stable error classification — the field to branch on. */
|
|
12
|
+
code;
|
|
13
|
+
/** Structured facts about the failure, e.g. `{ policyAddress }` for `policy_not_found`. */
|
|
14
|
+
details;
|
|
11
15
|
constructor(status, type, message, options) {
|
|
12
16
|
super(message, options);
|
|
13
17
|
this.name = "PraxisApiError";
|
|
14
18
|
this.status = status;
|
|
15
19
|
this.type = type;
|
|
20
|
+
this.code = options?.code ?? codeFromStatus(status);
|
|
21
|
+
this.details = options?.details;
|
|
16
22
|
Object.setPrototypeOf(this, _PraxisApiError.prototype);
|
|
17
23
|
}
|
|
18
24
|
get isAuth() {
|
|
@@ -44,7 +50,25 @@ var PraxisApiError = class _PraxisApiError extends Error {
|
|
|
44
50
|
get isServer() {
|
|
45
51
|
return this.status >= 500;
|
|
46
52
|
}
|
|
53
|
+
/** The wallet has no Aegis policy yet — the first-run state, not a fault. */
|
|
54
|
+
get isPolicyNotFound() {
|
|
55
|
+
return this.code === "policy_not_found";
|
|
56
|
+
}
|
|
57
|
+
/** A concurrent writer won; the call is safe to retry after a reload. */
|
|
58
|
+
get isConflict() {
|
|
59
|
+
return this.code === "conflict";
|
|
60
|
+
}
|
|
47
61
|
};
|
|
62
|
+
function codeFromStatus(status) {
|
|
63
|
+
if (status === 400) return "invalid_input";
|
|
64
|
+
if (status === 401) return "unauthorized";
|
|
65
|
+
if (status === 404) return "not_found";
|
|
66
|
+
if (status === 409) return "conflict";
|
|
67
|
+
if (status === 429) return "rate_limited";
|
|
68
|
+
if (status === 503) return "config_error";
|
|
69
|
+
if (status === 0) return "client_error";
|
|
70
|
+
return "internal_error";
|
|
71
|
+
}
|
|
48
72
|
var PraxisConfigError = class _PraxisConfigError extends Error {
|
|
49
73
|
constructor(message, options) {
|
|
50
74
|
super(message, options);
|
|
@@ -143,7 +167,9 @@ var PraxisClient = class {
|
|
|
143
167
|
throw new PraxisApiError(500, "Error", "Agent produced no reply message.");
|
|
144
168
|
}
|
|
145
169
|
const proposalIds = message.blocks.filter((b) => b.type === "proposal").map((b) => b.proposalId);
|
|
146
|
-
|
|
170
|
+
if (proposalIds.length === 0) return { threadId: tid, message, proposals: [] };
|
|
171
|
+
const byId = new Map((await this.getProposals()).map((p) => [p.id, p]));
|
|
172
|
+
const proposals = proposalIds.map((id) => byId.get(id)).filter((p) => p !== void 0);
|
|
147
173
|
return { threadId: tid, message, proposals };
|
|
148
174
|
}
|
|
149
175
|
newThread(threadId) {
|
|
@@ -155,6 +181,22 @@ var PraxisClient = class {
|
|
|
155
181
|
cancelProposal(proposalId) {
|
|
156
182
|
return this.post("/cancel-proposal", { proposalId });
|
|
157
183
|
}
|
|
184
|
+
/** List recurring-buy schedules (each fire emits one proposal; never signs). */
|
|
185
|
+
getSchedules() {
|
|
186
|
+
return this.get("/get-schedules");
|
|
187
|
+
}
|
|
188
|
+
/** Stop a recurring-buy schedule. Unknown ids are a no-op (idempotent). */
|
|
189
|
+
cancelSchedule(scheduleId) {
|
|
190
|
+
return this.post("/cancel-schedule", { scheduleId });
|
|
191
|
+
}
|
|
192
|
+
/** Save (or rename) an address-book contact. Labels have no signing power. */
|
|
193
|
+
addContact(label, address) {
|
|
194
|
+
return this.post("/add-contact", { label, address });
|
|
195
|
+
}
|
|
196
|
+
/** Remove a contact by address or label (case-insensitive, idempotent). */
|
|
197
|
+
removeContact(key) {
|
|
198
|
+
return this.post("/remove-contact", { key });
|
|
199
|
+
}
|
|
158
200
|
// --- reads ---------------------------------------------------------------
|
|
159
201
|
getThreads() {
|
|
160
202
|
return this.get("/get-threads");
|
|
@@ -165,6 +207,14 @@ var PraxisClient = class {
|
|
|
165
207
|
getProposal(id) {
|
|
166
208
|
return this.get("/get-proposal", { id });
|
|
167
209
|
}
|
|
210
|
+
/**
|
|
211
|
+
* Every proposal this wallet holds, in one request. Prefer this over a loop
|
|
212
|
+
* of {@link getProposal}: a per-id fetch is what trips the read rate limit
|
|
213
|
+
* on a busy thread.
|
|
214
|
+
*/
|
|
215
|
+
getProposals() {
|
|
216
|
+
return this.get("/get-proposals");
|
|
217
|
+
}
|
|
168
218
|
getPolicy() {
|
|
169
219
|
return this.get("/get-policy");
|
|
170
220
|
}
|
|
@@ -174,12 +224,31 @@ var PraxisClient = class {
|
|
|
174
224
|
getAddressBook() {
|
|
175
225
|
return this.get("/get-address-book");
|
|
176
226
|
}
|
|
177
|
-
isThinking(threadId) {
|
|
178
|
-
return this.get("/is-thinking", { threadId });
|
|
179
|
-
}
|
|
180
227
|
getVersion() {
|
|
181
228
|
return this.get("/get-version");
|
|
182
229
|
}
|
|
230
|
+
// --- stocks (PreStocks universe; empty unless the server enables it) ------
|
|
231
|
+
/**
|
|
232
|
+
* The server's stock universe (`[]` when `PRAXIS_STOCKS_ENABLED` is off).
|
|
233
|
+
* Read-only; symbols/mints here are the only pre-IPO stocks Praxis will
|
|
234
|
+
* touch (bounty exclusivity is enforced server-side).
|
|
235
|
+
*/
|
|
236
|
+
getTokenUniverse() {
|
|
237
|
+
return this.get("/get-stock-universe");
|
|
238
|
+
}
|
|
239
|
+
/**
|
|
240
|
+
* Read-only research for a stock symbol, via the agent (`research <symbol>`).
|
|
241
|
+
* Returns neutral market data — never advice. Throws when the agent has no
|
|
242
|
+
* research to show (unknown symbol or unavailable quotes).
|
|
243
|
+
*/
|
|
244
|
+
async getStockResearch(symbol) {
|
|
245
|
+
const { message } = await this.ask(`research ${symbol}`);
|
|
246
|
+
const block = message.blocks.find((b) => b.type === "research");
|
|
247
|
+
if (!block || block.type !== "research") {
|
|
248
|
+
throw new PraxisApiError(404, "NotFound", `No research available for ${symbol}.`);
|
|
249
|
+
}
|
|
250
|
+
return block.data;
|
|
251
|
+
}
|
|
183
252
|
// --- policy / owner mutations (server-key mode) --------------------------
|
|
184
253
|
bootstrapPolicy(fundLamports) {
|
|
185
254
|
return this.post("/bootstrap-policy", fundLamports ? { fundLamports } : {});
|
|
@@ -238,7 +307,30 @@ var PraxisClient = class {
|
|
|
238
307
|
post(path, body, timeoutMs) {
|
|
239
308
|
return this.request("POST", path, { body, timeoutMs });
|
|
240
309
|
}
|
|
310
|
+
/**
|
|
311
|
+
* Run a request, and if the session has expired, sign in again and retry it
|
|
312
|
+
* once.
|
|
313
|
+
*
|
|
314
|
+
* Sessions are deliberately short — holding one is enough to move value
|
|
315
|
+
* within the Aegis envelope — so a long-lived agent process WILL outlive its
|
|
316
|
+
* cookie. Without this, every caller writes the same catch-401-and-reconnect
|
|
317
|
+
* block, and the ones who do not simply stop working after a day. Retried
|
|
318
|
+
* once only, never for the auth endpoints themselves, and only when a signer
|
|
319
|
+
* is configured; without one there is nothing to re-authenticate with and the
|
|
320
|
+
* 401 is the honest answer.
|
|
321
|
+
*/
|
|
241
322
|
async request(method, path, opts = {}) {
|
|
323
|
+
try {
|
|
324
|
+
return await this.send1(method, path, opts);
|
|
325
|
+
} catch (error) {
|
|
326
|
+
const recoverable = error instanceof PraxisApiError && error.isAuth && Boolean(this.signer) && !path.startsWith("/auth/");
|
|
327
|
+
if (!recoverable) throw error;
|
|
328
|
+
this.sessionCookie = void 0;
|
|
329
|
+
await this.connect();
|
|
330
|
+
return this.send1(method, path, opts);
|
|
331
|
+
}
|
|
332
|
+
}
|
|
333
|
+
async send1(method, path, opts = {}) {
|
|
242
334
|
const url = new URL(this.baseUrl + API_PREFIX + path);
|
|
243
335
|
for (const [k, v] of Object.entries(opts.query ?? {})) url.searchParams.set(k, v);
|
|
244
336
|
const headers = { accept: "application/json" };
|
|
@@ -275,7 +367,10 @@ var PraxisClient = class {
|
|
|
275
367
|
if (!res.ok) {
|
|
276
368
|
const message = (parsed && typeof parsed === "object" && "error" in parsed && typeof parsed.error === "string" ? parsed.error : void 0) ?? `Praxis API error ${res.status}`;
|
|
277
369
|
const type = parsed && typeof parsed === "object" && "type" in parsed && typeof parsed.type === "string" ? parsed.type : "Error";
|
|
278
|
-
|
|
370
|
+
const record = parsed && typeof parsed === "object" ? parsed : void 0;
|
|
371
|
+
const code = typeof record?.code === "string" ? record.code : void 0;
|
|
372
|
+
const details = record?.details && typeof record.details === "object" && !Array.isArray(record.details) ? record.details : void 0;
|
|
373
|
+
throw new PraxisApiError(res.status, type, message, { code, details });
|
|
279
374
|
}
|
|
280
375
|
return parsed;
|
|
281
376
|
}
|