@lightconexyz/lightcone-sdk 0.8.1 → 0.8.2
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/README.md +150 -3
- package/dist/auth/client.d.ts +17 -1
- package/dist/auth/client.d.ts.map +1 -1
- package/dist/auth/client.js +68 -0
- package/dist/auth/client.js.map +1 -1
- package/dist/auth/index.d.ts +57 -5
- package/dist/auth/index.d.ts.map +1 -1
- package/dist/auth/index.js +26 -5
- package/dist/auth/index.js.map +1 -1
- package/dist/client.d.ts +23 -1
- package/dist/client.d.ts.map +1 -1
- package/dist/client.js +38 -2
- package/dist/client.js.map +1 -1
- package/dist/context.d.ts +23 -2
- package/dist/context.d.ts.map +1 -1
- package/dist/context.js +238 -17
- package/dist/context.js.map +1 -1
- package/dist/domain/market/outcome.d.ts +9 -3
- package/dist/domain/market/outcome.d.ts.map +1 -1
- package/dist/domain/market/outcome.js +10 -7
- package/dist/domain/market/outcome.js.map +1 -1
- package/dist/domain/market/wire.d.ts +3 -3
- package/dist/domain/market/wire.d.ts.map +1 -1
- package/dist/domain/market/wire.js.map +1 -1
- package/dist/domain/orderbook/wire.d.ts +5 -0
- package/dist/domain/orderbook/wire.d.ts.map +1 -1
- package/dist/domain/orderbook/wire.js.map +1 -1
- package/dist/domain/position/client.d.ts +160 -4
- package/dist/domain/position/client.d.ts.map +1 -1
- package/dist/domain/position/client.js +592 -4
- package/dist/domain/position/client.js.map +1 -1
- package/dist/domain/position/index.d.ts +54 -3
- package/dist/domain/position/index.d.ts.map +1 -1
- package/dist/domain/position/index.js +1 -0
- package/dist/domain/position/index.js.map +1 -1
- package/dist/domain/position/state.d.ts +118 -0
- package/dist/domain/position/state.d.ts.map +1 -0
- package/dist/domain/position/state.js +262 -0
- package/dist/domain/position/state.js.map +1 -0
- package/dist/error.d.ts +8 -2
- package/dist/error.d.ts.map +1 -1
- package/dist/error.js +14 -1
- package/dist/error.js.map +1 -1
- package/dist/index.d.ts +4 -3
- package/dist/index.d.ts.map +1 -1
- package/dist/index.js +3 -1
- package/dist/index.js.map +1 -1
- package/dist/prelude.d.ts +6 -5
- package/dist/prelude.d.ts.map +1 -1
- package/dist/prelude.js +10 -1
- package/dist/prelude.js.map +1 -1
- package/dist/privy/client.d.ts +4 -0
- package/dist/privy/client.d.ts.map +1 -1
- package/dist/privy/client.js +4 -0
- package/dist/privy/client.js.map +1 -1
- package/dist/rpc.d.ts +46 -1
- package/dist/rpc.d.ts.map +1 -1
- package/dist/rpc.js +125 -0
- package/dist/rpc.js.map +1 -1
- package/dist/shared/api_response.d.ts +7 -0
- package/dist/shared/api_response.d.ts.map +1 -1
- package/dist/shared/api_response.js +16 -0
- package/dist/shared/api_response.js.map +1 -1
- package/dist/shared/index.d.ts +1 -1
- package/dist/shared/index.d.ts.map +1 -1
- package/dist/shared/index.js +2 -1
- package/dist/shared/index.js.map +1 -1
- package/dist/shared/signing.d.ts +17 -0
- package/dist/shared/signing.d.ts.map +1 -1
- package/dist/shared/signing.js +27 -0
- package/dist/shared/signing.js.map +1 -1
- package/dist/shared/types.d.ts +3 -1
- package/dist/shared/types.d.ts.map +1 -1
- package/dist/shared/types.js +12 -4
- package/dist/shared/types.js.map +1 -1
- package/dist/ws/client.browser.d.ts +4 -0
- package/dist/ws/client.browser.d.ts.map +1 -1
- package/dist/ws/client.browser.js +13 -1
- package/dist/ws/client.browser.js.map +1 -1
- package/dist/ws/client.node.d.ts +4 -0
- package/dist/ws/client.node.d.ts.map +1 -1
- package/dist/ws/client.node.js +13 -1
- package/dist/ws/client.node.js.map +1 -1
- package/dist/ws/index.d.ts +24 -0
- package/dist/ws/index.d.ts.map +1 -1
- package/dist/ws/index.js +162 -1
- package/dist/ws/index.js.map +1 -1
- package/dist/ws/subscriptions.d.ts +12 -1
- package/dist/ws/subscriptions.d.ts.map +1 -1
- package/dist/ws/subscriptions.js +11 -0
- package/dist/ws/subscriptions.js.map +1 -1
- package/dist/ws/types.d.ts +5 -0
- package/dist/ws/types.d.ts.map +1 -1
- package/dist/ws/types.js.map +1 -1
- package/package.json +2 -1
package/README.md
CHANGED
|
@@ -17,6 +17,7 @@ TypeScript SDK for the Lightcone impact market protocol on Solana.
|
|
|
17
17
|
- [Environment Configuration](#environment-configuration)
|
|
18
18
|
- [Examples](#examples)
|
|
19
19
|
- [Error Handling](#error-handling)
|
|
20
|
+
- [Transaction Fee Funding](#transaction-fee-funding)
|
|
20
21
|
- [Retry Strategy](#retry-strategy)
|
|
21
22
|
|
|
22
23
|
## Installation
|
|
@@ -25,6 +26,24 @@ TypeScript SDK for the Lightcone impact market protocol on Solana.
|
|
|
25
26
|
npm install @lightconexyz/lightcone-sdk
|
|
26
27
|
```
|
|
27
28
|
|
|
29
|
+
## Transaction Fee Funding
|
|
30
|
+
|
|
31
|
+
Shared on-chain submission checks the exact prepared message fee and declared
|
|
32
|
+
fee-payer Native SOL Balance before signing when both RPC facts are available.
|
|
33
|
+
A proven shortfall is an `SdkError` with variant
|
|
34
|
+
`InsufficientSolForTransactionFees`, bigint `availableLamports` and
|
|
35
|
+
`requiredLamports` fields, and the canonical deposit-SOL message. Fee or balance
|
|
36
|
+
lookup failure continues through the existing submission path; planner-owned SOL
|
|
37
|
+
actions retain fail-closed live fee, rent, and reserve checks.
|
|
38
|
+
|
|
39
|
+
`LightconeClient.builder().transactionSponsorship(true)` and
|
|
40
|
+
`client.setTransactionSponsorshipEnabled(true)` are trusted application assertions
|
|
41
|
+
for wallet-adapter and Privy signing. The default is false, each transaction
|
|
42
|
+
captures its signer and capability before asynchronous RPC work, `clone()` copies
|
|
43
|
+
the current value, and local-keypair submission rejects an enabled capability. Raw
|
|
44
|
+
`Privy.signAndSendTx` forwarding and off-chain order-message signing are outside
|
|
45
|
+
this contract.
|
|
46
|
+
|
|
28
47
|
## Quick Start
|
|
29
48
|
|
|
30
49
|
```typescript
|
|
@@ -184,20 +203,129 @@ reconnect/resubscribe; `resync: true` requires unsubscribe/resubscribe with the
|
|
|
184
203
|
same aggregation. Each `(orderbook, aggregation)` pair needs its own state.
|
|
185
204
|
Truncation flags are preserved and mean that side is not exhaustive. See
|
|
186
205
|
[`examples/ws_book_and_trades.ts`](examples/ws_book_and_trades.ts).
|
|
206
|
+
Each decoded bid and ask level includes exact decimal-string `quote_notional`.
|
|
207
|
+
For grouped books, `price` is a display bucket boundary, so quote liquidity
|
|
208
|
+
and totals must use `quote_notional` rather than `price * size`. The
|
|
209
|
+
price-to-base-size `OrderbookState` maps do not retain quote notional; read it
|
|
210
|
+
from the decoded `OrderBook` levels.
|
|
187
211
|
Ticker consumers should use the supplied `mid`; it is engine-authoritative and
|
|
188
212
|
may use one-sided-book or last-trade fallback.
|
|
189
213
|
REST depth is a coherent projection that may briefly lag a mutation. Use its
|
|
190
214
|
`revision` and `captured_at_ms` metadata, and expect revision gaps.
|
|
191
215
|
|
|
216
|
+
```typescript
|
|
217
|
+
ws.subscribe({ type: "book_update", orderbook_ids: [orderbook.orderbookId], nSigFigs: 5, mantissa: 2 });
|
|
218
|
+
```
|
|
219
|
+
|
|
192
220
|
Order submission accepts decimal strings and uses exact `bigint` construction.
|
|
193
221
|
`submit()` fetches and caches `/api/orderbooks/{id}/decimals` before invoking a
|
|
194
222
|
signer. Direct `sign()`/`finalize()` calls require the returned `OrderbookRules`.
|
|
195
223
|
Raw amounts, explicit salts, and derived prices are preflighted against the same
|
|
196
224
|
signed-64-bit admission rules; no tick or size normalization is implicit.
|
|
197
225
|
|
|
198
|
-
|
|
199
|
-
|
|
200
|
-
|
|
226
|
+
### Wallet Balances and SOL Action Planning
|
|
227
|
+
|
|
228
|
+
`depositTokenBalances()` returns a required exact nine-decimal
|
|
229
|
+
`native_sol_balance` alongside the separate mint-keyed SPL map. Initialize
|
|
230
|
+
`WalletDepositBalancesState` with `applyRestSnapshot(wallet, snapshot)` and feed
|
|
231
|
+
the outer `wallet_deposit_balances` channel's nested snapshot, absolute SPL,
|
|
232
|
+
absolute native-SOL, and status events to `applyEvent()`. Complete snapshots
|
|
233
|
+
replace state even after a higher component slot; status and wrong-wallet events
|
|
234
|
+
do not mutate it, pre-baseline component updates are ignored, and explicit-zero
|
|
235
|
+
SPL updates remove their mint. Matching SPL updates with invalid or negative
|
|
236
|
+
idle balances return `rejected` without mutation. `contextSlot` records the latest accepted
|
|
237
|
+
component observation rather than enforcing global monotonic ordering.
|
|
238
|
+
`combinedSolBalance()` sums native SOL and canonical WSOL with `bigint` precision
|
|
239
|
+
while retaining both stored values. REST response types are trusted rather than
|
|
240
|
+
runtime-decoded; WebSocket frames are validated strictly, while malformed REST
|
|
241
|
+
exact values fail when a state method scales them. The reducer owns its map
|
|
242
|
+
container but retains balance objects by reference, so treat applied payloads as
|
|
243
|
+
immutable.
|
|
244
|
+
|
|
245
|
+
`planSolSplit`, `planSolMerge`, `planSolRedeem`, and
|
|
246
|
+
`planNativeSolWithdrawal` return unsigned action plans with live fee/rent costs,
|
|
247
|
+
the action-specific reserve and spendable balance, and separate expected native
|
|
248
|
+
and canonical WSOL deltas. Each planner requires complete matching-wallet state,
|
|
249
|
+
checks the canonical account when needed, and fails closed when RPC estimates or
|
|
250
|
+
native reserve are unavailable. Unsponsored actions reserve the greater of live
|
|
251
|
+
costs and the applicable 0.001 SOL or 0.0035 SOL floor. Sponsored planning is
|
|
252
|
+
rejected until a concrete sponsor owns transaction fees and account rent.
|
|
253
|
+
An occupied canonical address is accepted only when it decodes as the wallet's
|
|
254
|
+
initialized, unfrozen Tokenkeg native-mint account.
|
|
255
|
+
|
|
256
|
+
Split plans consume canonical WSOL first and wrap only a shortfall in the same
|
|
257
|
+
transaction. Merge and redeem plans retain proceeds in the persistent canonical
|
|
258
|
+
account. Native withdrawal transfers directly when possible; otherwise it moves
|
|
259
|
+
only the shortfall through a bounded seeded temporary Tokenkeg account and closes
|
|
260
|
+
that temporary account before sending the exact native amount to the recipient.
|
|
261
|
+
The temporary account's create, initialize, WSOL transfer, close, and native
|
|
262
|
+
transfer instructions share one Solana transaction, so an instruction failure
|
|
263
|
+
rolls the entire conversion back atomically. No planner closes the canonical
|
|
264
|
+
account implicitly.
|
|
265
|
+
|
|
266
|
+
Native-keypair self-custody users can explicitly call `planWrapSol` with a
|
|
267
|
+
positive exact `bigint` lamport amount or call no-amount `planUnwrapWsolAll`.
|
|
268
|
+
These standalone planners require the authenticated Trading Wallet's local
|
|
269
|
+
native signing strategy; wallet-adapter and Privy strategies are rejected before
|
|
270
|
+
RPC planning. Wrap creates or reuses only that wallet's canonical Tokenkeg ATA,
|
|
271
|
+
transfers the exact amount, and runs `SyncNative`, the Token Program instruction
|
|
272
|
+
that recalculates the WSOL token amount from account lamports. Wrap retains the
|
|
273
|
+
ordinary 0.0035 SOL account-creation or 0.001 SOL existing-account reserve floor
|
|
274
|
+
above lower live costs. Live decoded canonical amounts must match the authoritative
|
|
275
|
+
wallet state. Wrap also requires an existing account's full lamports to equal
|
|
276
|
+
its decoded token amount plus native rent reserve; unsynchronized direct
|
|
277
|
+
donations reject before `SyncNative` can make the projected canonical delta
|
|
278
|
+
inexact. Unwrap-all still accepts such excess and returns it on close.
|
|
279
|
+
|
|
280
|
+
Unwrap-all accepts no partial amount and closes the entire positive canonical
|
|
281
|
+
account back to the same wallet. Its `SolActionCosts` fields contain the fresh fee, zero
|
|
282
|
+
upfront rent, no account creation, and no sponsorship. Availability reserves
|
|
283
|
+
only that fee rather than the ordinary persistent-account floor;
|
|
284
|
+
`unwrapAllSolBalanceAvailability(components, costs)` validates that complete
|
|
285
|
+
cost tuple before deriving fee-only fields. The
|
|
286
|
+
native delta credits every live account lamport, including refunded rent or
|
|
287
|
+
direct donations, minus the fee and removes the full canonical token amount.
|
|
288
|
+
Closing a pre-existing account returns all of its WSOL and means a future WSOL
|
|
289
|
+
action may need to fund account rent again. Ordinary split, merge, redeem,
|
|
290
|
+
claim, order, and native-withdraw paths never call these conversion planners or
|
|
291
|
+
close canonical WSOL.
|
|
292
|
+
|
|
293
|
+
For either explicit conversion, rebuild immediately before signing,
|
|
294
|
+
submit with `signAndSubmitPreparedTxConfirmedWithSlot` so the wallet cannot
|
|
295
|
+
replace the fee-estimated message, and refresh a complete snapshot covering its
|
|
296
|
+
slot before restoring action authority. Prepared submission is unavailable for
|
|
297
|
+
Privy because its final signed bytes cannot be verified by the SDK. Atomic
|
|
298
|
+
execution does not resolve uncertain submission or confirmation errors; inspect
|
|
299
|
+
authoritative balances before retrying. See the
|
|
300
|
+
[persistent canonical WSOL ADR](../docs/adr/0001-persistent-canonical-wsol.md).
|
|
301
|
+
|
|
302
|
+
WebSocket clients are owned independently from `Auth`; logout does not clean them
|
|
303
|
+
up. For each retained client, `clearAuthedSubscriptions()` purges User/wallet
|
|
304
|
+
reconnect tracking and queued authenticated messages. It does not stop an
|
|
305
|
+
already-open server stream; send the matching unsubscribe or disconnect the socket
|
|
306
|
+
for live teardown.
|
|
307
|
+
|
|
308
|
+
The [`deposit_token_balances`](examples/deposit_token_balances.ts) self-custody
|
|
309
|
+
example is manual-only and runs with `LIGHTCONE_ENV=local` or `staging` only
|
|
310
|
+
when `SDK_API_URL`, `SDK_WS_URL`, `SDK_RPC_URL`, and `SDK_PROGRAM_ID` are all
|
|
311
|
+
unset. It sends 0.001 SOL to the Python SDK wallet configured by
|
|
312
|
+
`LIGHTCONE_WALLET_PATH_PYTHON` from the distinct sender configured by
|
|
313
|
+
`LIGHTCONE_WALLET_PATH_TS`, confirms with a slot, and refreshes a complete
|
|
314
|
+
snapshot at that slot. Running it moves funds. If it fails after submission,
|
|
315
|
+
inspect authoritative balances before retrying because funds may already have moved.
|
|
316
|
+
|
|
317
|
+
The separate [`wsol_conversion`](examples/wsol_conversion.ts) example runs with
|
|
318
|
+
the TypeScript wallet in local aggregate runs and is included when the globally
|
|
319
|
+
gated stateful example workflow is enabled for staging CI; that workflow
|
|
320
|
+
currently disables all stateful CI jobs. Local runs may use a paid RPC while
|
|
321
|
+
retaining built-in API, WebSocket, and program identity; an enabled staging-CI
|
|
322
|
+
run may supply its managed endpoints. Direct staging runs remain override-free.
|
|
323
|
+
It permits a pre-existing canonical balance, wraps exactly 0.001 SOL, prints the
|
|
324
|
+
exact wallet, costs, full-account return, and future-rent warning, then unwraps
|
|
325
|
+
the complete canonical account without pausing. It retains each frozen
|
|
326
|
+
projection until a complete REST snapshot covers the confirmed slot. Any
|
|
327
|
+
planning, signing, submission, or uncertain-confirmation failure exits without
|
|
328
|
+
automatic retry.
|
|
201
329
|
|
|
202
330
|
### Step 5: Cancel an Order
|
|
203
331
|
|
|
@@ -240,9 +368,17 @@ const withdrawIx = client.positions().withdraw()
|
|
|
240
368
|
|
|
241
369
|
Authentication is only required for user-specific endpoints. Authentication is session-based using ED25519 signed messages. The flow is: request a nonce, sign it with your wallet, and exchange it for a session cookie.
|
|
242
370
|
|
|
371
|
+
Privy hosts can also authenticate with passwordless Email, Google, X, or Wallet. After every interactive success, call `client.auth().registerPrivy({ attempted_identity })`. The backend validates the exact selector against Privy's verified methods, creates or synchronizes the Account, and changes the Primary Login Identity only for a new Account. `session.user.identity` is that stable primary; `session.user.linked_identities` contains every connected method with primary first.
|
|
372
|
+
|
|
243
373
|
Use `walletDisplayName(session.user, session.auth_method)` to show a shortened
|
|
244
374
|
label for the wallet the session trades with, regardless of login identity.
|
|
245
375
|
|
|
376
|
+
`session.user.max_slippage_preference` is an exact decimal string strictly below
|
|
377
|
+
`10`, or `null` until one is stored. Persist a value greater than zero and less
|
|
378
|
+
than 10 using `client.auth().updateMaxSlippagePreference(value)`; the method
|
|
379
|
+
returns the canonical exact decimal string. Values at or above 10% remain valid
|
|
380
|
+
order protection but are not remembered through this API.
|
|
381
|
+
|
|
246
382
|
### Cookie handling
|
|
247
383
|
|
|
248
384
|
After login succeeds, the SDK stores the session token internally and attaches it as `Cookie: lightcone-token=…` on every authenticated request. Behaviour depends on the runtime:
|
|
@@ -348,6 +484,16 @@ All examples are runnable with `npx tsx examples/<name>.ts`. Examples default to
|
|
|
348
484
|
| [`onchain_transactions`](examples/onchain_transactions.ts) | Build, sign, and submit mint/merge complete set and increment nonce on-chain |
|
|
349
485
|
| [`global_deposit_withdrawal`](examples/global_deposit_withdrawal.ts) | Init position tokens, deposit to global pool, move capital into a market, extend an existing ALT, withdraw from global, and merge back to keep the run net-neutral |
|
|
350
486
|
|
|
487
|
+
### Manual Fund-Moving Operations
|
|
488
|
+
|
|
489
|
+
These examples refuse production and endpoint overrides and are intentionally
|
|
490
|
+
excluded from routine example runs.
|
|
491
|
+
|
|
492
|
+
| Example | Description |
|
|
493
|
+
|---------|-------------|
|
|
494
|
+
| [`deposit_token_balances`](examples/deposit_token_balances.ts) | Confirm an exact native withdrawal without closing canonical WSOL, then refresh complete state past the confirmed slot |
|
|
495
|
+
| [`wsol_conversion`](examples/wsol_conversion.ts) | Wrap an exact native amount, warn, close and unwrap the complete canonical account, and hold frozen projections through covering refreshes |
|
|
496
|
+
|
|
351
497
|
### WebSocket Streaming
|
|
352
498
|
|
|
353
499
|
| Example | Description |
|
|
@@ -385,6 +531,7 @@ When the backend rejects a request (insufficient balance, expired order, etc.),
|
|
|
385
531
|
| `errorCode` | `string \| undefined` | API-level error code (for example `"NOT_FOUND"` or `"INVALID_ARGUMENT"`) |
|
|
386
532
|
| `errorLogId` | `string \| undefined` | Backend support correlation ID (`LCERR_*`) |
|
|
387
533
|
| `requestId` | `string \| undefined` | SDK-generated `x-request-id` for cross-service tracing |
|
|
534
|
+
| `existingMethod` | `string \| undefined` | Primary method of the conflicting Account when identity ownership has one deterministic owner |
|
|
388
535
|
|
|
389
536
|
`ApiRejectedDetails.toString()` formats all present fields as a multi-line report for logs or support tickets.
|
|
390
537
|
|
package/dist/auth/client.d.ts
CHANGED
|
@@ -1,5 +1,17 @@
|
|
|
1
1
|
import { type LightconeHttp } from "../http";
|
|
2
|
-
import type { AuthCredentials, SessionResponse } from "./index";
|
|
2
|
+
import type { AuthCredentials, LinkedIdentityType, RegisterPrivyRequest, SessionResponse } from "./index";
|
|
3
|
+
/** Bounded ownership conflicts safe for client recovery guidance. */
|
|
4
|
+
export type RegisterPrivyConflict = {
|
|
5
|
+
code: "IDENTITY_OWNED_BY_ANOTHER_ACCOUNT";
|
|
6
|
+
existingMethod?: LinkedIdentityType;
|
|
7
|
+
} | {
|
|
8
|
+
code: "IDENTITIES_OWNED_BY_MULTIPLE_ACCOUNTS";
|
|
9
|
+
} | {
|
|
10
|
+
code: "WALLET_OWNED_BY_ANOTHER_ACCOUNT";
|
|
11
|
+
existingMethod?: LinkedIdentityType;
|
|
12
|
+
};
|
|
13
|
+
/** Classify only stable register-or-sync ownership rejection codes. */
|
|
14
|
+
export declare function classifyRegisterPrivyConflict(error: unknown): RegisterPrivyConflict | undefined;
|
|
3
15
|
interface AuthState {
|
|
4
16
|
getCredentials(): AuthCredentials | undefined;
|
|
5
17
|
setCredentials(credentials: AuthCredentials | undefined): void;
|
|
@@ -27,6 +39,10 @@ export declare class Auth {
|
|
|
27
39
|
*/
|
|
28
40
|
logout(): Promise<void>;
|
|
29
41
|
disconnectX(): Promise<void>;
|
|
42
|
+
/** Create or synchronize a Privy Account and install the resulting session. */
|
|
43
|
+
registerPrivy(request: RegisterPrivyRequest): Promise<SessionResponse>;
|
|
44
|
+
/** Persist an account-wide max-slippage preference strictly below 10%. */
|
|
45
|
+
updateMaxSlippagePreference(maxSlippagePreference: string): Promise<string>;
|
|
30
46
|
connectXUrl(): string;
|
|
31
47
|
credentials(): AuthCredentials | undefined;
|
|
32
48
|
isAuthenticated(): boolean;
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"client.d.ts","sourceRoot":"","sources":["../../src/auth/client.ts"],"names":[],"mappings":"AACA,OAAO,EAAe,KAAK,aAAa,EAAE,MAAM,SAAS,CAAC;AAG1D,OAAO,KAAK,
|
|
1
|
+
{"version":3,"file":"client.d.ts","sourceRoot":"","sources":["../../src/auth/client.ts"],"names":[],"mappings":"AACA,OAAO,EAAe,KAAK,aAAa,EAAE,MAAM,SAAS,CAAC;AAG1D,OAAO,KAAK,EACV,eAAe,EAIf,kBAAkB,EAClB,oBAAoB,EACpB,eAAe,EAChB,MAAM,SAAS,CAAC;AAEjB,qEAAqE;AACrE,MAAM,MAAM,qBAAqB,GAC7B;IACE,IAAI,EAAE,mCAAmC,CAAC;IAC1C,cAAc,CAAC,EAAE,kBAAkB,CAAC;CACrC,GACD;IAAE,IAAI,EAAE,uCAAuC,CAAA;CAAE,GACjD;IACE,IAAI,EAAE,iCAAiC,CAAC;IACxC,cAAc,CAAC,EAAE,kBAAkB,CAAC;CACrC,CAAC;AAEN,uEAAuE;AACvE,wBAAgB,6BAA6B,CAC3C,KAAK,EAAE,OAAO,GACb,qBAAqB,GAAG,SAAS,CAoBnC;AAED,UAAU,SAAS;IACjB,cAAc,IAAI,eAAe,GAAG,SAAS,CAAC;IAC9C,cAAc,CAAC,WAAW,EAAE,eAAe,GAAG,SAAS,GAAG,IAAI,CAAC;IAC/D,WAAW,IAAI,OAAO,CAAC,IAAI,CAAC,CAAC;CAC9B;AAED,UAAU,aAAa;IACrB,IAAI,EAAE,aAAa,CAAC;IACpB,SAAS,EAAE,SAAS,CAAC;CACtB;AAED,qBAAa,IAAI;IACH,OAAO,CAAC,QAAQ,CAAC,MAAM;gBAAN,MAAM,EAAE,aAAa;IAE5C,QAAQ,IAAI,OAAO,CAAC,MAAM,CAAC;IAS3B,gBAAgB,CACpB,OAAO,EAAE,MAAM,EACf,aAAa,EAAE,MAAM,EACrB,WAAW,EAAE,UAAU,EACvB,iBAAiB,CAAC,EAAE,OAAO,GAC1B,OAAO,CAAC,eAAe,CAAC;IAwBrB,YAAY,IAAI,OAAO,CAAC,eAAe,CAAC;IAoB9C;;;;;;;;;OASG;IACG,MAAM,IAAI,OAAO,CAAC,IAAI,CAAC;IAyBvB,WAAW,IAAI,OAAO,CAAC,IAAI,CAAC;IASlC,+EAA+E;IACzE,aAAa,CAAC,OAAO,EAAE,oBAAoB,GAAG,OAAO,CAAC,eAAe,CAAC;IAe5E,0EAA0E;IACpE,2BAA2B,CAC/B,qBAAqB,EAAE,MAAM,GAC5B,OAAO,CAAC,MAAM,CAAC;IAuBlB,WAAW,IAAI,MAAM;IAIrB,WAAW,IAAI,eAAe,GAAG,SAAS;IAI1C,eAAe,IAAI,OAAO;CAO3B"}
|
package/dist/auth/client.js
CHANGED
|
@@ -1,10 +1,33 @@
|
|
|
1
1
|
"use strict";
|
|
2
2
|
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
3
|
exports.Auth = void 0;
|
|
4
|
+
exports.classifyRegisterPrivyConflict = classifyRegisterPrivyConflict;
|
|
4
5
|
const error_1 = require("../error");
|
|
5
6
|
const http_1 = require("../http");
|
|
6
7
|
const shared_1 = require("../shared");
|
|
7
8
|
const index_1 = require("./index");
|
|
9
|
+
/** Classify only stable register-or-sync ownership rejection codes. */
|
|
10
|
+
function classifyRegisterPrivyConflict(error) {
|
|
11
|
+
if (!(error instanceof error_1.SdkError) || error.variant !== "ApiRejected")
|
|
12
|
+
return undefined;
|
|
13
|
+
const details = error.apiRejectedDetails;
|
|
14
|
+
switch (details?.errorCode) {
|
|
15
|
+
case "IDENTITY_OWNED_BY_ANOTHER_ACCOUNT":
|
|
16
|
+
return {
|
|
17
|
+
code: details.errorCode,
|
|
18
|
+
existingMethod: details.existingMethod,
|
|
19
|
+
};
|
|
20
|
+
case "IDENTITIES_OWNED_BY_MULTIPLE_ACCOUNTS":
|
|
21
|
+
return { code: details.errorCode };
|
|
22
|
+
case "WALLET_OWNED_BY_ANOTHER_ACCOUNT":
|
|
23
|
+
return {
|
|
24
|
+
code: details.errorCode,
|
|
25
|
+
existingMethod: details.existingMethod,
|
|
26
|
+
};
|
|
27
|
+
default:
|
|
28
|
+
return undefined;
|
|
29
|
+
}
|
|
30
|
+
}
|
|
8
31
|
class Auth {
|
|
9
32
|
client;
|
|
10
33
|
constructor(client) {
|
|
@@ -28,6 +51,7 @@ class Auth {
|
|
|
28
51
|
// verifying the signature, so a replayed login deterministically fails —
|
|
29
52
|
// and restoring credentials in order to log in is circular.
|
|
30
53
|
const session = await this.client.http.postWithoutCredentialRestore(url, body, http_1.RetryPolicy.None);
|
|
54
|
+
normalizeSessionMaxSlippagePreference(session);
|
|
31
55
|
this.client.authState.setCredentials(credentialsFromSession(session));
|
|
32
56
|
return session;
|
|
33
57
|
}
|
|
@@ -36,6 +60,7 @@ class Auth {
|
|
|
36
60
|
let session;
|
|
37
61
|
try {
|
|
38
62
|
session = await this.client.http.get(url, http_1.RetryPolicy.Idempotent);
|
|
63
|
+
normalizeSessionMaxSlippagePreference(session);
|
|
39
64
|
}
|
|
40
65
|
catch (error) {
|
|
41
66
|
this.client.authState.setCredentials(undefined);
|
|
@@ -78,6 +103,24 @@ class Auth {
|
|
|
78
103
|
const url = `${this.client.http.baseUrl()}/api/auth/disconnect_x`;
|
|
79
104
|
await this.client.http.post(url, {}, http_1.RetryPolicy.None);
|
|
80
105
|
}
|
|
106
|
+
/** Create or synchronize a Privy Account and install the resulting session. */
|
|
107
|
+
async registerPrivy(request) {
|
|
108
|
+
const url = `${this.client.http.baseUrl()}/api/auth/register-privy`;
|
|
109
|
+
const session = await this.client.http.post(url, request, http_1.RetryPolicy.Idempotent);
|
|
110
|
+
normalizeSessionMaxSlippagePreference(session);
|
|
111
|
+
this.client.authState.setCredentials(credentialsFromSession(session));
|
|
112
|
+
return session;
|
|
113
|
+
}
|
|
114
|
+
/** Persist an account-wide max-slippage preference strictly below 10%. */
|
|
115
|
+
async updateMaxSlippagePreference(maxSlippagePreference) {
|
|
116
|
+
const url = `${this.client.http.baseUrl()}/api/auth/max_slippage_preference`;
|
|
117
|
+
const response = await this.client.http.post(url, { max_slippage_preference: maxSlippagePreference }, http_1.RetryPolicy.Idempotent);
|
|
118
|
+
const preference = decodeMaxSlippagePreference(response, false, "update response");
|
|
119
|
+
if (preference === null) {
|
|
120
|
+
throw error_1.SdkError.serde("Max-slippage update response must contain a decimal string");
|
|
121
|
+
}
|
|
122
|
+
return preference;
|
|
123
|
+
}
|
|
81
124
|
connectXUrl() {
|
|
82
125
|
return `${this.client.http.baseUrl()}/api/auth/oauth/link/x`;
|
|
83
126
|
}
|
|
@@ -93,6 +136,31 @@ class Auth {
|
|
|
93
136
|
}
|
|
94
137
|
}
|
|
95
138
|
exports.Auth = Auth;
|
|
139
|
+
function normalizeSessionMaxSlippagePreference(session) {
|
|
140
|
+
const preference = decodeMaxSlippagePreference(session?.user, true, "session user", true);
|
|
141
|
+
session.user.max_slippage_preference = preference;
|
|
142
|
+
}
|
|
143
|
+
/** Enforces the exact nullable/string JSON contract erased by TypeScript types. */
|
|
144
|
+
function decodeMaxSlippagePreference(payload, allowNull, context, allowMissing = false) {
|
|
145
|
+
if (typeof payload !== "object" || payload === null) {
|
|
146
|
+
throw error_1.SdkError.serde(`Max-slippage ${context} is malformed`);
|
|
147
|
+
}
|
|
148
|
+
if (!Object.prototype.hasOwnProperty.call(payload, "max_slippage_preference")) {
|
|
149
|
+
if (allowMissing) {
|
|
150
|
+
return null;
|
|
151
|
+
}
|
|
152
|
+
throw error_1.SdkError.serde(`Max-slippage ${context} is missing max_slippage_preference`);
|
|
153
|
+
}
|
|
154
|
+
const preference = payload
|
|
155
|
+
.max_slippage_preference;
|
|
156
|
+
if (typeof preference === "string") {
|
|
157
|
+
return preference;
|
|
158
|
+
}
|
|
159
|
+
if (allowNull && preference === null) {
|
|
160
|
+
return null;
|
|
161
|
+
}
|
|
162
|
+
throw error_1.SdkError.serde(`Max-slippage ${context} must contain ${allowNull ? "a string or null" : "a string"}`);
|
|
163
|
+
}
|
|
96
164
|
/**
|
|
97
165
|
* Derive session credentials from the envelope. The trading wallet comes from
|
|
98
166
|
* the identity + auth method.
|
package/dist/auth/client.js.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"client.js","sourceRoot":"","sources":["../../src/auth/client.ts"],"names":[],"mappings":"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","sourcesContent":["import { SdkError, isUnauthorized } from \"../error\";\nimport { RetryPolicy, type LightconeHttp } from \"../http\";\nimport { asPubkeyStr } from \"../shared\";\nimport { tradingWallet } from \"./index\";\nimport type { AuthCredentials, LoginRequest, NonceResponse, SessionResponse } from \"./index\";\n\ninterface AuthState {\n getCredentials(): AuthCredentials | undefined;\n setCredentials(credentials: AuthCredentials | undefined): void;\n clearCaches(): Promise<void>;\n}\n\ninterface ClientContext {\n http: LightconeHttp;\n authState: AuthState;\n}\n\nexport class Auth {\n constructor(private readonly client: ClientContext) {}\n\n async getNonce(): Promise<string> {\n const url = `${this.client.http.baseUrl()}/api/auth/nonce`;\n const response = await this.client.http.get<NonceResponse>(url, RetryPolicy.None);\n return response.nonce;\n }\n\n async loginWithMessage(\n message: string,\n signatureBs58: string,\n pubkeyBytes: Uint8Array,\n useEmbeddedWallet?: boolean\n ): Promise<SessionResponse> {\n const url = `${this.client.http.baseUrl()}/api/auth/login_or_register_with_message`;\n const body: LoginRequest = {\n message,\n signature_bs58: signatureBs58,\n pubkey_bytes: Array.from(pubkeyBytes),\n use_embedded_wallet: useEmbeddedWallet,\n };\n\n // Credential-management endpoint: opts out of the transport's 401\n // restore-and-replay. The backend consumes the login nonce before\n // verifying the signature, so a replayed login deterministically fails —\n // and restoring credentials in order to log in is circular.\n const session = await this.client.http.postWithoutCredentialRestore<\n SessionResponse,\n LoginRequest\n >(url, body, RetryPolicy.None);\n\n this.client.authState.setCredentials(credentialsFromSession(session));\n\n return session;\n }\n\n async checkSession(): Promise<SessionResponse> {\n const url = `${this.client.http.baseUrl()}/api/auth/me`;\n\n let session: SessionResponse;\n try {\n session = await this.client.http.get<SessionResponse>(url, RetryPolicy.Idempotent);\n } catch (error) {\n this.client.authState.setCredentials(undefined);\n throw SdkError.from(error);\n }\n\n this.client.authState.setCredentials(credentialsFromSession(session));\n\n return session;\n }\n\n /**\n * Logout — clears the server-side cookie, internal token, and credentials.\n *\n * Local state is cleared even when the server call fails — the caller asked\n * to be signed out locally regardless — but the failure is then rethrown:\n * callers gating security decisions on teardown (e.g. whether an app may\n * restart an authenticated transport) must be able to see that the\n * server-side cookie may still be valid. A 401 counts as success: it means\n * \"already logged out\".\n */\n async logout(): Promise<void> {\n const url = `${this.client.http.baseUrl()}/api/auth/logout`;\n let logoutError: unknown = null;\n try {\n // Credential-management endpoint: opts out of the transport's 401\n // restore-and-replay — a 401 here means \"already logged out\".\n await this.client.http.postWithoutCredentialRestore<\n { success: boolean },\n Record<string, never>\n >(url, {}, RetryPolicy.None);\n } catch (error) {\n if (!isUnauthorized(error)) {\n logoutError = error;\n }\n }\n\n await this.client.http.clearAuthToken();\n this.client.authState.setCredentials(undefined);\n await this.client.authState.clearCaches();\n\n if (logoutError !== null) {\n throw logoutError;\n }\n }\n\n async disconnectX(): Promise<void> {\n const url = `${this.client.http.baseUrl()}/api/auth/disconnect_x`;\n await this.client.http.post<{ success: boolean }, Record<string, never>>(url, {}, RetryPolicy.None);\n }\n\n connectXUrl(): string {\n return `${this.client.http.baseUrl()}/api/auth/oauth/link/x`;\n }\n\n credentials(): AuthCredentials | undefined {\n return this.client.authState.getCredentials();\n }\n\n isAuthenticated(): boolean {\n const credentials = this.credentials();\n if (!credentials) {\n return false;\n }\n return Date.now() < credentials.expires_at.getTime();\n }\n}\n\n/**\n * Derive session credentials from the envelope. The trading wallet comes from\n * the identity + auth method.\n */\nfunction credentialsFromSession(session: SessionResponse): AuthCredentials {\n return {\n user_id: session.user.user_id,\n wallet_address: asPubkeyStr(tradingWallet(session.user, session.auth_method)),\n expires_at: parseExpiry(session.expires_at),\n };\n}\n\nfunction parseExpiry(timestamp: number): Date {\n if (timestamp > 1_000_000_000_000) {\n return new Date(timestamp);\n }\n return new Date(timestamp * 1000);\n}\n"]}
|
|
1
|
+
{"version":3,"file":"client.js","sourceRoot":"","sources":["../../src/auth/client.ts"],"names":[],"mappings":"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","sourcesContent":["import { SdkError, isUnauthorized } from \"../error\";\nimport { RetryPolicy, type LightconeHttp } from \"../http\";\nimport { asPubkeyStr } from \"../shared\";\nimport { tradingWallet } from \"./index\";\nimport type {\n AuthCredentials,\n LoginRequest,\n MaxSlippagePreferenceBody,\n NonceResponse,\n LinkedIdentityType,\n RegisterPrivyRequest,\n SessionResponse,\n} from \"./index\";\n\n/** Bounded ownership conflicts safe for client recovery guidance. */\nexport type RegisterPrivyConflict =\n | {\n code: \"IDENTITY_OWNED_BY_ANOTHER_ACCOUNT\";\n existingMethod?: LinkedIdentityType;\n }\n | { code: \"IDENTITIES_OWNED_BY_MULTIPLE_ACCOUNTS\" }\n | {\n code: \"WALLET_OWNED_BY_ANOTHER_ACCOUNT\";\n existingMethod?: LinkedIdentityType;\n };\n\n/** Classify only stable register-or-sync ownership rejection codes. */\nexport function classifyRegisterPrivyConflict(\n error: unknown,\n): RegisterPrivyConflict | undefined {\n if (!(error instanceof SdkError) || error.variant !== \"ApiRejected\")\n return undefined;\n const details = error.apiRejectedDetails;\n switch (details?.errorCode) {\n case \"IDENTITY_OWNED_BY_ANOTHER_ACCOUNT\":\n return {\n code: details.errorCode,\n existingMethod: details.existingMethod,\n };\n case \"IDENTITIES_OWNED_BY_MULTIPLE_ACCOUNTS\":\n return { code: details.errorCode };\n case \"WALLET_OWNED_BY_ANOTHER_ACCOUNT\":\n return {\n code: details.errorCode,\n existingMethod: details.existingMethod,\n };\n default:\n return undefined;\n }\n}\n\ninterface AuthState {\n getCredentials(): AuthCredentials | undefined;\n setCredentials(credentials: AuthCredentials | undefined): void;\n clearCaches(): Promise<void>;\n}\n\ninterface ClientContext {\n http: LightconeHttp;\n authState: AuthState;\n}\n\nexport class Auth {\n constructor(private readonly client: ClientContext) {}\n\n async getNonce(): Promise<string> {\n const url = `${this.client.http.baseUrl()}/api/auth/nonce`;\n const response = await this.client.http.get<NonceResponse>(\n url,\n RetryPolicy.None,\n );\n return response.nonce;\n }\n\n async loginWithMessage(\n message: string,\n signatureBs58: string,\n pubkeyBytes: Uint8Array,\n useEmbeddedWallet?: boolean,\n ): Promise<SessionResponse> {\n const url = `${this.client.http.baseUrl()}/api/auth/login_or_register_with_message`;\n const body: LoginRequest = {\n message,\n signature_bs58: signatureBs58,\n pubkey_bytes: Array.from(pubkeyBytes),\n use_embedded_wallet: useEmbeddedWallet,\n };\n\n // Credential-management endpoint: opts out of the transport's 401\n // restore-and-replay. The backend consumes the login nonce before\n // verifying the signature, so a replayed login deterministically fails —\n // and restoring credentials in order to log in is circular.\n const session = await this.client.http.postWithoutCredentialRestore<\n SessionResponse,\n LoginRequest\n >(url, body, RetryPolicy.None);\n normalizeSessionMaxSlippagePreference(session);\n\n this.client.authState.setCredentials(credentialsFromSession(session));\n\n return session;\n }\n\n async checkSession(): Promise<SessionResponse> {\n const url = `${this.client.http.baseUrl()}/api/auth/me`;\n\n let session: SessionResponse;\n try {\n session = await this.client.http.get<SessionResponse>(\n url,\n RetryPolicy.Idempotent,\n );\n normalizeSessionMaxSlippagePreference(session);\n } catch (error) {\n this.client.authState.setCredentials(undefined);\n throw SdkError.from(error);\n }\n\n this.client.authState.setCredentials(credentialsFromSession(session));\n\n return session;\n }\n\n /**\n * Logout — clears the server-side cookie, internal token, and credentials.\n *\n * Local state is cleared even when the server call fails — the caller asked\n * to be signed out locally regardless — but the failure is then rethrown:\n * callers gating security decisions on teardown (e.g. whether an app may\n * restart an authenticated transport) must be able to see that the\n * server-side cookie may still be valid. A 401 counts as success: it means\n * \"already logged out\".\n */\n async logout(): Promise<void> {\n const url = `${this.client.http.baseUrl()}/api/auth/logout`;\n let logoutError: unknown = null;\n try {\n // Credential-management endpoint: opts out of the transport's 401\n // restore-and-replay — a 401 here means \"already logged out\".\n await this.client.http.postWithoutCredentialRestore<\n { success: boolean },\n Record<string, never>\n >(url, {}, RetryPolicy.None);\n } catch (error) {\n if (!isUnauthorized(error)) {\n logoutError = error;\n }\n }\n\n await this.client.http.clearAuthToken();\n this.client.authState.setCredentials(undefined);\n await this.client.authState.clearCaches();\n\n if (logoutError !== null) {\n throw logoutError;\n }\n }\n\n async disconnectX(): Promise<void> {\n const url = `${this.client.http.baseUrl()}/api/auth/disconnect_x`;\n await this.client.http.post<{ success: boolean }, Record<string, never>>(\n url,\n {},\n RetryPolicy.None,\n );\n }\n\n /** Create or synchronize a Privy Account and install the resulting session. */\n async registerPrivy(request: RegisterPrivyRequest): Promise<SessionResponse> {\n const url = `${this.client.http.baseUrl()}/api/auth/register-privy`;\n const session = await this.client.http.post<\n SessionResponse,\n RegisterPrivyRequest\n >(\n url,\n request,\n RetryPolicy.Idempotent,\n );\n normalizeSessionMaxSlippagePreference(session);\n this.client.authState.setCredentials(credentialsFromSession(session));\n return session;\n }\n\n /** Persist an account-wide max-slippage preference strictly below 10%. */\n async updateMaxSlippagePreference(\n maxSlippagePreference: string,\n ): Promise<string> {\n const url = `${this.client.http.baseUrl()}/api/auth/max_slippage_preference`;\n const response = await this.client.http.post<\n MaxSlippagePreferenceBody,\n MaxSlippagePreferenceBody\n >(\n url,\n { max_slippage_preference: maxSlippagePreference },\n RetryPolicy.Idempotent,\n );\n const preference = decodeMaxSlippagePreference(\n response,\n false,\n \"update response\",\n );\n if (preference === null) {\n throw SdkError.serde(\n \"Max-slippage update response must contain a decimal string\",\n );\n }\n return preference;\n }\n\n connectXUrl(): string {\n return `${this.client.http.baseUrl()}/api/auth/oauth/link/x`;\n }\n\n credentials(): AuthCredentials | undefined {\n return this.client.authState.getCredentials();\n }\n\n isAuthenticated(): boolean {\n const credentials = this.credentials();\n if (!credentials) {\n return false;\n }\n return Date.now() < credentials.expires_at.getTime();\n }\n}\n\nfunction normalizeSessionMaxSlippagePreference(session: SessionResponse): void {\n const preference = decodeMaxSlippagePreference(\n session?.user,\n true,\n \"session user\",\n true,\n );\n session.user.max_slippage_preference = preference;\n}\n\n/** Enforces the exact nullable/string JSON contract erased by TypeScript types. */\nfunction decodeMaxSlippagePreference(\n payload: unknown,\n allowNull: boolean,\n context: string,\n allowMissing = false,\n): string | null {\n if (typeof payload !== \"object\" || payload === null) {\n throw SdkError.serde(`Max-slippage ${context} is malformed`);\n }\n if (\n !Object.prototype.hasOwnProperty.call(payload, \"max_slippage_preference\")\n ) {\n if (allowMissing) {\n return null;\n }\n throw SdkError.serde(\n `Max-slippage ${context} is missing max_slippage_preference`,\n );\n }\n\n const preference = (payload as Record<string, unknown>)\n .max_slippage_preference;\n if (typeof preference === \"string\") {\n return preference;\n }\n if (allowNull && preference === null) {\n return null;\n }\n throw SdkError.serde(\n `Max-slippage ${context} must contain ${allowNull ? \"a string or null\" : \"a string\"}`,\n );\n}\n\n/**\n * Derive session credentials from the envelope. The trading wallet comes from\n * the identity + auth method.\n */\nfunction credentialsFromSession(session: SessionResponse): AuthCredentials {\n return {\n user_id: session.user.user_id,\n wallet_address: asPubkeyStr(\n tradingWallet(session.user, session.auth_method),\n ),\n expires_at: parseExpiry(session.expires_at),\n };\n}\n\nfunction parseExpiry(timestamp: number): Date {\n if (timestamp > 1_000_000_000_000) {\n return new Date(timestamp);\n }\n return new Date(timestamp * 1000);\n}\n"]}
|
package/dist/auth/index.d.ts
CHANGED
|
@@ -48,6 +48,46 @@ export interface GoogleAccountData {
|
|
|
48
48
|
family_name?: string;
|
|
49
49
|
avatar_url?: string;
|
|
50
50
|
}
|
|
51
|
+
/** Canonical address for a passwordless Email login identity. */
|
|
52
|
+
export interface EmailAccountData {
|
|
53
|
+
email: string;
|
|
54
|
+
}
|
|
55
|
+
/** Public login-method names exposed in profiles and bounded conflicts. */
|
|
56
|
+
export type LinkedIdentityType = "email" | "google" | "x" | "wallet";
|
|
57
|
+
/** Connected Login Identity without repeated Account-level Privy wallet data. */
|
|
58
|
+
export type LinkedIdentity = {
|
|
59
|
+
type: "email";
|
|
60
|
+
account: EmailAccountData;
|
|
61
|
+
} | {
|
|
62
|
+
type: "google";
|
|
63
|
+
account: GoogleAccountData;
|
|
64
|
+
} | {
|
|
65
|
+
type: "x";
|
|
66
|
+
account: XAccountData;
|
|
67
|
+
} | {
|
|
68
|
+
type: "wallet";
|
|
69
|
+
address: string;
|
|
70
|
+
chain: ChainType;
|
|
71
|
+
};
|
|
72
|
+
/** Verified method and canonical identifier that initiated Privy authentication. */
|
|
73
|
+
export type LinkedIdentitySelector = {
|
|
74
|
+
type: "email";
|
|
75
|
+
email: string;
|
|
76
|
+
} | {
|
|
77
|
+
type: "google";
|
|
78
|
+
email: string;
|
|
79
|
+
} | {
|
|
80
|
+
type: "x";
|
|
81
|
+
username: string;
|
|
82
|
+
} | {
|
|
83
|
+
type: "wallet";
|
|
84
|
+
address: string;
|
|
85
|
+
chain: ChainType;
|
|
86
|
+
};
|
|
87
|
+
/** Register-or-sync request naming the verified attempted identity. */
|
|
88
|
+
export interface RegisterPrivyRequest {
|
|
89
|
+
attempted_identity: LinkedIdentitySelector;
|
|
90
|
+
}
|
|
51
91
|
/**
|
|
52
92
|
* The login identity — how the user authenticates. `type` narrows the variant.
|
|
53
93
|
*
|
|
@@ -57,6 +97,10 @@ export interface GoogleAccountData {
|
|
|
57
97
|
* self-custody.
|
|
58
98
|
*/
|
|
59
99
|
export type UserIdentity = {
|
|
100
|
+
type: "email";
|
|
101
|
+
account: EmailAccountData;
|
|
102
|
+
privy: UserPrivyData;
|
|
103
|
+
} | {
|
|
60
104
|
type: "google";
|
|
61
105
|
account: GoogleAccountData;
|
|
62
106
|
privy: UserPrivyData;
|
|
@@ -74,6 +118,10 @@ export type UserIdentity = {
|
|
|
74
118
|
export interface User {
|
|
75
119
|
user_id: string;
|
|
76
120
|
identity: UserIdentity;
|
|
121
|
+
/** Every verified login identity connected to the Account, primary first. */
|
|
122
|
+
linked_identities?: LinkedIdentity[];
|
|
123
|
+
/** Remembered account-wide percentage below 10%; null until one is stored. */
|
|
124
|
+
max_slippage_preference: string | null;
|
|
77
125
|
/** X account connected by a non-X-identity user; absent when identity is X. */
|
|
78
126
|
connected_x?: XAccountData;
|
|
79
127
|
}
|
|
@@ -88,8 +136,12 @@ export interface SessionResponse {
|
|
|
88
136
|
auth_method: AuthMethod;
|
|
89
137
|
is_beta: boolean;
|
|
90
138
|
}
|
|
91
|
-
/**
|
|
92
|
-
export
|
|
139
|
+
/** Exact decimal-string body used to update and return max slippage. */
|
|
140
|
+
export interface MaxSlippagePreferenceBody {
|
|
141
|
+
max_slippage_preference: string;
|
|
142
|
+
}
|
|
143
|
+
/** Human-readable login-method label ("Email" / "Google" / "X" / "Solana"). */
|
|
144
|
+
export declare function identityText(identity: UserIdentity): "Email" | "Google" | "X" | "Solana";
|
|
93
145
|
/** Privy account data, regardless of identity type. */
|
|
94
146
|
export declare function userPrivy(user: User): UserPrivyData | undefined;
|
|
95
147
|
/** The X account, whether it is the login identity or a connected account. */
|
|
@@ -107,9 +159,9 @@ export declare function tradingWallet(user: User, authMethod: AuthMethod): strin
|
|
|
107
159
|
/** Short display label for the wallet a session operates as. */
|
|
108
160
|
export declare function walletDisplayName(user: User, authMethod: AuthMethod): string;
|
|
109
161
|
/**
|
|
110
|
-
* Best display name for the user.
|
|
111
|
-
*
|
|
112
|
-
* shortened address (`FRGk...WcPR`).
|
|
162
|
+
* Best display name for the user. Email addresses are limited to 20 characters;
|
|
163
|
+
* Google uses `name` with an email fallback; X uses `display_name` with a
|
|
164
|
+
* username fallback; wallet identities show the shortened address (`FRGk...WcPR`).
|
|
113
165
|
*/
|
|
114
166
|
export declare function displayName(user: User): string;
|
|
115
167
|
/** Avatar URL from the login identity's OAuth provider, if any. */
|
package/dist/auth/index.d.ts.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../../src/auth/index.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,SAAS,EAAE,MAAM,WAAW,CAAC;AAG3C,cAAc,UAAU,CAAC;AACzB,cAAc,UAAU,CAAC;AAEzB;;;GAGG;AACH,oBAAY,UAAU;IACpB,KAAK,UAAU;IACf,SAAS,cAAc;CACxB;AAED,oBAAY,SAAS;IACnB,MAAM,WAAW;IACjB,QAAQ,aAAa;CACtB;AAED,uCAAuC;AACvC,MAAM,WAAW,mBAAmB;IAClC,QAAQ,EAAE,MAAM,CAAC;IACjB,KAAK,EAAE,SAAS,CAAC;IACjB,OAAO,EAAE,MAAM,CAAC;CACjB;AAED,kDAAkD;AAClD,MAAM,WAAW,aAAa;IAC5B,uCAAuC;IACvC,EAAE,EAAE,MAAM,CAAC;IACX;;;OAGG;IACH,MAAM,EAAE,mBAAmB,CAAC;CAC7B;AAED;;;GAGG;AACH,MAAM,WAAW,YAAY;IAC3B,kEAAkE;IAClE,OAAO,CAAC,EAAE,MAAM,CAAC;IACjB,QAAQ,EAAE,MAAM,CAAC;IACjB,YAAY,CAAC,EAAE,MAAM,CAAC;IACtB,UAAU,CAAC,EAAE,MAAM,CAAC;CACrB;AAED,uDAAuD;AACvD,MAAM,WAAW,iBAAiB;IAChC,KAAK,EAAE,MAAM,CAAC;IACd,IAAI,CAAC,EAAE,MAAM,CAAC;IACd,UAAU,CAAC,EAAE,MAAM,CAAC;IACpB,WAAW,CAAC,EAAE,MAAM,CAAC;IACrB,UAAU,CAAC,EAAE,MAAM,CAAC;CACrB;AAED;;;;;;;GAOG;AACH,MAAM,MAAM,YAAY,GACpB;IAAE,IAAI,EAAE,QAAQ,CAAC;IAAC,OAAO,EAAE,iBAAiB,CAAC;IAAC,KAAK,EAAE,aAAa,CAAA;CAAE,GACpE;IAAE,IAAI,EAAE,GAAG,CAAC;IAAC,OAAO,EAAE,YAAY,CAAC;IAAC,KAAK,EAAE,aAAa,CAAA;CAAE,GAC1D;
|
|
1
|
+
{"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../../src/auth/index.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,SAAS,EAAE,MAAM,WAAW,CAAC;AAG3C,cAAc,UAAU,CAAC;AACzB,cAAc,UAAU,CAAC;AAEzB;;;GAGG;AACH,oBAAY,UAAU;IACpB,KAAK,UAAU;IACf,SAAS,cAAc;CACxB;AAED,oBAAY,SAAS;IACnB,MAAM,WAAW;IACjB,QAAQ,aAAa;CACtB;AAED,uCAAuC;AACvC,MAAM,WAAW,mBAAmB;IAClC,QAAQ,EAAE,MAAM,CAAC;IACjB,KAAK,EAAE,SAAS,CAAC;IACjB,OAAO,EAAE,MAAM,CAAC;CACjB;AAED,kDAAkD;AAClD,MAAM,WAAW,aAAa;IAC5B,uCAAuC;IACvC,EAAE,EAAE,MAAM,CAAC;IACX;;;OAGG;IACH,MAAM,EAAE,mBAAmB,CAAC;CAC7B;AAED;;;GAGG;AACH,MAAM,WAAW,YAAY;IAC3B,kEAAkE;IAClE,OAAO,CAAC,EAAE,MAAM,CAAC;IACjB,QAAQ,EAAE,MAAM,CAAC;IACjB,YAAY,CAAC,EAAE,MAAM,CAAC;IACtB,UAAU,CAAC,EAAE,MAAM,CAAC;CACrB;AAED,uDAAuD;AACvD,MAAM,WAAW,iBAAiB;IAChC,KAAK,EAAE,MAAM,CAAC;IACd,IAAI,CAAC,EAAE,MAAM,CAAC;IACd,UAAU,CAAC,EAAE,MAAM,CAAC;IACpB,WAAW,CAAC,EAAE,MAAM,CAAC;IACrB,UAAU,CAAC,EAAE,MAAM,CAAC;CACrB;AAED,iEAAiE;AACjE,MAAM,WAAW,gBAAgB;IAC/B,KAAK,EAAE,MAAM,CAAC;CACf;AAED,2EAA2E;AAC3E,MAAM,MAAM,kBAAkB,GAAG,OAAO,GAAG,QAAQ,GAAG,GAAG,GAAG,QAAQ,CAAC;AAErE,iFAAiF;AACjF,MAAM,MAAM,cAAc,GACtB;IAAE,IAAI,EAAE,OAAO,CAAC;IAAC,OAAO,EAAE,gBAAgB,CAAA;CAAE,GAC5C;IAAE,IAAI,EAAE,QAAQ,CAAC;IAAC,OAAO,EAAE,iBAAiB,CAAA;CAAE,GAC9C;IAAE,IAAI,EAAE,GAAG,CAAC;IAAC,OAAO,EAAE,YAAY,CAAA;CAAE,GACpC;IAAE,IAAI,EAAE,QAAQ,CAAC;IAAC,OAAO,EAAE,MAAM,CAAC;IAAC,KAAK,EAAE,SAAS,CAAA;CAAE,CAAC;AAE1D,oFAAoF;AACpF,MAAM,MAAM,sBAAsB,GAC9B;IAAE,IAAI,EAAE,OAAO,CAAC;IAAC,KAAK,EAAE,MAAM,CAAA;CAAE,GAChC;IAAE,IAAI,EAAE,QAAQ,CAAC;IAAC,KAAK,EAAE,MAAM,CAAA;CAAE,GACjC;IAAE,IAAI,EAAE,GAAG,CAAC;IAAC,QAAQ,EAAE,MAAM,CAAA;CAAE,GAC/B;IAAE,IAAI,EAAE,QAAQ,CAAC;IAAC,OAAO,EAAE,MAAM,CAAC;IAAC,KAAK,EAAE,SAAS,CAAA;CAAE,CAAC;AAE1D,uEAAuE;AACvE,MAAM,WAAW,oBAAoB;IACnC,kBAAkB,EAAE,sBAAsB,CAAC;CAC5C;AAED;;;;;;;GAOG;AACH,MAAM,MAAM,YAAY,GACpB;IAAE,IAAI,EAAE,OAAO,CAAC;IAAC,OAAO,EAAE,gBAAgB,CAAC;IAAC,KAAK,EAAE,aAAa,CAAA;CAAE,GAClE;IAAE,IAAI,EAAE,QAAQ,CAAC;IAAC,OAAO,EAAE,iBAAiB,CAAC;IAAC,KAAK,EAAE,aAAa,CAAA;CAAE,GACpE;IAAE,IAAI,EAAE,GAAG,CAAC;IAAC,OAAO,EAAE,YAAY,CAAC;IAAC,KAAK,EAAE,aAAa,CAAA;CAAE,GAC1D;IACE,IAAI,EAAE,QAAQ,CAAC;IACf,OAAO,EAAE,MAAM,CAAC;IAChB,KAAK,EAAE,SAAS,CAAC;IACjB,KAAK,CAAC,EAAE,aAAa,CAAC;CACvB,CAAC;AAEN,wEAAwE;AACxE,MAAM,WAAW,IAAI;IACnB,OAAO,EAAE,MAAM,CAAC;IAChB,QAAQ,EAAE,YAAY,CAAC;IACvB,6EAA6E;IAC7E,iBAAiB,CAAC,EAAE,cAAc,EAAE,CAAC;IACrC,8EAA8E;IAC9E,uBAAuB,EAAE,MAAM,GAAG,IAAI,CAAC;IACvC,+EAA+E;IAC/E,WAAW,CAAC,EAAE,YAAY,CAAC;CAC5B;AAED;;;;GAIG;AACH,MAAM,WAAW,eAAe;IAC9B,IAAI,EAAE,IAAI,CAAC;IACX,UAAU,EAAE,MAAM,CAAC;IACnB,WAAW,EAAE,UAAU,CAAC;IACxB,OAAO,EAAE,OAAO,CAAC;CAClB;AAED,wEAAwE;AACxE,MAAM,WAAW,yBAAyB;IACxC,uBAAuB,EAAE,MAAM,CAAC;CACjC;AAED,+EAA+E;AAC/E,wBAAgB,YAAY,CAC1B,QAAQ,EAAE,YAAY,GACrB,OAAO,GAAG,QAAQ,GAAG,GAAG,GAAG,QAAQ,CAerC;AAED,uDAAuD;AACvD,wBAAgB,SAAS,CAAC,IAAI,EAAE,IAAI,GAAG,aAAa,GAAG,SAAS,CAS/D;AAED,8EAA8E;AAC9E,wBAAgB,YAAY,CAAC,IAAI,EAAE,IAAI,GAAG,YAAY,GAAG,SAAS,CAEjE;AAED;;;;;;;;GAQG;AACH,wBAAgB,aAAa,CAAC,IAAI,EAAE,IAAI,EAAE,UAAU,EAAE,UAAU,GAAG,MAAM,CAWxE;AAED,gEAAgE;AAChE,wBAAgB,iBAAiB,CAAC,IAAI,EAAE,IAAI,EAAE,UAAU,EAAE,UAAU,GAAG,MAAM,CAE5E;AAiBD;;;;GAIG;AACH,wBAAgB,WAAW,CAAC,IAAI,EAAE,IAAI,GAAG,MAAM,CAa9C;AAED,mEAAmE;AACnE,wBAAgB,SAAS,CAAC,IAAI,EAAE,IAAI,GAAG,MAAM,GAAG,SAAS,CAUxD;AAED,MAAM,WAAW,eAAe;IAC9B,OAAO,EAAE,MAAM,CAAC;IAChB,cAAc,EAAE,SAAS,CAAC;IAC1B,UAAU,EAAE,IAAI,CAAC;CAClB;AAED,wBAAgB,eAAe,CAAC,WAAW,CAAC,EAAE,eAAe,GAAG,OAAO,CAKtE;AAED,wBAAgB,qBAAqB,CAAC,KAAK,EAAE,MAAM,GAAG,UAAU,CAE/D;AAED,MAAM,WAAW,YAAY;IAC3B,OAAO,EAAE,MAAM,CAAC;IAChB,cAAc,EAAE,MAAM,CAAC;IACvB,YAAY,EAAE,MAAM,EAAE,CAAC;IACvB,mBAAmB,CAAC,EAAE,OAAO,CAAC;CAC/B;AAED,MAAM,WAAW,aAAa;IAC5B,KAAK,EAAE,MAAM,CAAC;CACf"}
|
package/dist/auth/index.js
CHANGED
|
@@ -41,9 +41,11 @@ var ChainType;
|
|
|
41
41
|
ChainType["Solana"] = "solana";
|
|
42
42
|
ChainType["Ethereum"] = "ethereum";
|
|
43
43
|
})(ChainType || (exports.ChainType = ChainType = {}));
|
|
44
|
-
/** Human-readable login-method label ("Google" / "X" / "Solana"). */
|
|
44
|
+
/** Human-readable login-method label ("Email" / "Google" / "X" / "Solana"). */
|
|
45
45
|
function identityText(identity) {
|
|
46
46
|
switch (identity.type) {
|
|
47
|
+
case "email":
|
|
48
|
+
return "Email";
|
|
47
49
|
case "google":
|
|
48
50
|
return "Google";
|
|
49
51
|
case "x":
|
|
@@ -59,6 +61,7 @@ function identityText(identity) {
|
|
|
59
61
|
/** Privy account data, regardless of identity type. */
|
|
60
62
|
function userPrivy(user) {
|
|
61
63
|
switch (user.identity.type) {
|
|
64
|
+
case "email":
|
|
62
65
|
case "google":
|
|
63
66
|
case "x":
|
|
64
67
|
return user.identity.privy;
|
|
@@ -81,6 +84,7 @@ function userXAccount(user) {
|
|
|
81
84
|
*/
|
|
82
85
|
function tradingWallet(user, authMethod) {
|
|
83
86
|
switch (user.identity.type) {
|
|
87
|
+
case "email":
|
|
84
88
|
case "google":
|
|
85
89
|
case "x":
|
|
86
90
|
return user.identity.privy.wallet.address;
|
|
@@ -94,17 +98,32 @@ function tradingWallet(user, authMethod) {
|
|
|
94
98
|
function walletDisplayName(user, authMethod) {
|
|
95
99
|
return (0, str_1.shorten)(tradingWallet(user, authMethod), 8);
|
|
96
100
|
}
|
|
101
|
+
/** Keeps Email labels compact while preserving the recognizable address ends. */
|
|
102
|
+
function emailDisplayName(email) {
|
|
103
|
+
const maxChars = 20;
|
|
104
|
+
const chars = [...email];
|
|
105
|
+
if (chars.length <= maxChars) {
|
|
106
|
+
return email;
|
|
107
|
+
}
|
|
108
|
+
const visibleChars = maxChars - 3;
|
|
109
|
+
const prefixChars = Math.floor(visibleChars / 2);
|
|
110
|
+
return `${chars.slice(0, prefixChars).join("")}...${chars
|
|
111
|
+
.slice(-(visibleChars - prefixChars))
|
|
112
|
+
.join("")}`;
|
|
113
|
+
}
|
|
97
114
|
/**
|
|
98
|
-
* Best display name for the user.
|
|
99
|
-
*
|
|
100
|
-
* shortened address (`FRGk...WcPR`).
|
|
115
|
+
* Best display name for the user. Email addresses are limited to 20 characters;
|
|
116
|
+
* Google uses `name` with an email fallback; X uses `display_name` with a
|
|
117
|
+
* username fallback; wallet identities show the shortened address (`FRGk...WcPR`).
|
|
101
118
|
*/
|
|
102
119
|
function displayName(user) {
|
|
103
120
|
switch (user.identity.type) {
|
|
121
|
+
case "email":
|
|
122
|
+
return emailDisplayName(user.identity.account.email);
|
|
104
123
|
case "google":
|
|
105
124
|
return user.identity.account.name ?? user.identity.account.email;
|
|
106
125
|
case "x":
|
|
107
|
-
return user.identity.account.display_name ?? user.identity.account.username;
|
|
126
|
+
return (user.identity.account.display_name ?? user.identity.account.username);
|
|
108
127
|
case "wallet":
|
|
109
128
|
return (0, str_1.shorten)(user.identity.address, 8);
|
|
110
129
|
}
|
|
@@ -112,6 +131,8 @@ function displayName(user) {
|
|
|
112
131
|
/** Avatar URL from the login identity's OAuth provider, if any. */
|
|
113
132
|
function avatarUrl(user) {
|
|
114
133
|
switch (user.identity.type) {
|
|
134
|
+
case "email":
|
|
135
|
+
return undefined;
|
|
115
136
|
case "google":
|
|
116
137
|
case "x":
|
|
117
138
|
return user.identity.account.avatar_url;
|