@lightconexyz/lightcone-sdk 0.8.4-rc.53 → 0.8.4-rc.55
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 +74 -54
- package/dist/auth/client.js +35 -3
- package/dist/auth/client.js.map +1 -1
- package/dist/auth/index.d.ts +7 -0
- package/dist/auth/index.d.ts.map +1 -1
- package/dist/auth/index.js.map +1 -1
- package/package.json +1 -1
package/README.md
CHANGED
|
@@ -123,23 +123,17 @@ submission is unavailable until signed v1 bytes can be verified.
|
|
|
123
123
|
|
|
124
124
|
## Quick Start
|
|
125
125
|
|
|
126
|
+
This example authenticates and subscribes to public market data. For funded order submission, use the [trading example](examples/submit_order.ts).
|
|
127
|
+
|
|
126
128
|
```typescript
|
|
127
|
-
import { Keypair
|
|
129
|
+
import { Keypair } from "@solana/web3.js";
|
|
128
130
|
import {
|
|
129
131
|
LightconeClient,
|
|
130
|
-
DepositSource,
|
|
131
132
|
auth,
|
|
132
133
|
} from "@lightconexyz/lightcone-sdk";
|
|
133
134
|
|
|
134
135
|
async function main() {
|
|
135
|
-
const client = LightconeClient.builder()
|
|
136
|
-
.depositSource(DepositSource.Market)
|
|
137
|
-
.transactionResources({
|
|
138
|
-
computeUnitLimit: 200_000,
|
|
139
|
-
loadedAccountsDataSizeLimit: 65_536,
|
|
140
|
-
priorityFeeLamports: 0n,
|
|
141
|
-
})
|
|
142
|
-
.build();
|
|
136
|
+
const client = LightconeClient.builder().build();
|
|
143
137
|
const keypair = Keypair.generate();
|
|
144
138
|
|
|
145
139
|
// 1. Authenticate
|
|
@@ -162,31 +156,7 @@ async function main() {
|
|
|
162
156
|
throw new Error("Selected market has no orderbooks");
|
|
163
157
|
}
|
|
164
158
|
|
|
165
|
-
// 3.
|
|
166
|
-
const depositMint = new PublicKey(market.depositAssets[0].pubkey);
|
|
167
|
-
const depositIx = client.positions().deposit()
|
|
168
|
-
.user(keypair.publicKey)
|
|
169
|
-
.mint(depositMint)
|
|
170
|
-
.amount(1_000_000n)
|
|
171
|
-
.buildIx();
|
|
172
|
-
|
|
173
|
-
// 4. Fetch/cache immutable trading rules, validate exactly, sign, and submit
|
|
174
|
-
const response = await client.orders().limitOrder()
|
|
175
|
-
.maker(keypair.publicKey)
|
|
176
|
-
.bid()
|
|
177
|
-
.price("0.55")
|
|
178
|
-
.size("100")
|
|
179
|
-
.submit(client, orderbook);
|
|
180
|
-
console.log("Order submitted:", response);
|
|
181
|
-
|
|
182
|
-
// 5. Withdraw from the global pool
|
|
183
|
-
const withdrawIx = client.positions().withdraw()
|
|
184
|
-
.user(keypair.publicKey)
|
|
185
|
-
.mint(depositMint)
|
|
186
|
-
.amount(1_000_000n)
|
|
187
|
-
.buildIx();
|
|
188
|
-
|
|
189
|
-
// 6. Stream real-time updates
|
|
159
|
+
// 3. Subscribe to real-time updates.
|
|
190
160
|
const ws = client.ws();
|
|
191
161
|
await ws.connect();
|
|
192
162
|
ws.subscribe({ type: "book_update", orderbook_ids: [orderbook.orderbookId] });
|
|
@@ -197,6 +167,8 @@ main().catch(console.error);
|
|
|
197
167
|
|
|
198
168
|
## Start Trading
|
|
199
169
|
|
|
170
|
+
These excerpts use top-level `await` in an ES module. Use a funded keypair for the selected environment. The [submit example](examples/submit_order.ts) confirms the deposit and waits for the API balance before ordering.
|
|
171
|
+
|
|
200
172
|
```typescript
|
|
201
173
|
import * as fs from "fs";
|
|
202
174
|
import * as os from "os";
|
|
@@ -205,6 +177,7 @@ import { Keypair, PublicKey } from "@solana/web3.js";
|
|
|
205
177
|
import {
|
|
206
178
|
LightconeClient,
|
|
207
179
|
DepositSource,
|
|
180
|
+
auth,
|
|
208
181
|
} from "@lightconexyz/lightcone-sdk";
|
|
209
182
|
|
|
210
183
|
function readKeypairFile(filePath: string): Keypair {
|
|
@@ -220,8 +193,19 @@ const keypair = readKeypairFile("~/.config/solana/id.json");
|
|
|
220
193
|
// Defaults to Prod. Use .env(LightconeEnv.Staging) for staging.
|
|
221
194
|
const client = LightconeClient.builder()
|
|
222
195
|
.nativeSigner(keypair)
|
|
223
|
-
.depositSource(DepositSource.
|
|
196
|
+
.depositSource(DepositSource.Global)
|
|
197
|
+
.transactionResources({
|
|
198
|
+
computeUnitLimit: 200_000,
|
|
199
|
+
loadedAccountsDataSizeLimit: 1_048_576,
|
|
200
|
+
priorityFeeLamports: 0n,
|
|
201
|
+
})
|
|
224
202
|
.build();
|
|
203
|
+
const nonce = await client.auth().getNonce();
|
|
204
|
+
const signed = auth.signLoginMessage(keypair, nonce);
|
|
205
|
+
await client.auth().loginWithMessage(
|
|
206
|
+
signed.message, signed.signature_bs58, signed.pubkey_bytes
|
|
207
|
+
);
|
|
208
|
+
client.setOrderNonce(await client.orders().currentNonce(keypair.publicKey));
|
|
225
209
|
```
|
|
226
210
|
|
|
227
211
|
### Step 1: Find a Market
|
|
@@ -241,13 +225,42 @@ if (!orderbook) {
|
|
|
241
225
|
|
|
242
226
|
### Step 2: Deposit Collateral
|
|
243
227
|
|
|
228
|
+
The amount is in the deposit mint's smallest units. Instruction construction alone does not transfer collateral. Submit and confirm the transaction, then wait for the API balance to cover the order. Select the deposit mint backing the orderbook's quote token, as shown in the [submit example](examples/submit_order.ts).
|
|
229
|
+
|
|
230
|
+
Calculate the deposit from the same price and size used by the order. Poll at most 15 times, with two seconds between unsuccessful reads. A timeout or read failure stops before order submission. Check the confirmed deposit before repeating this step.
|
|
231
|
+
|
|
244
232
|
```typescript
|
|
245
|
-
|
|
246
|
-
|
|
233
|
+
import { shared } from "@lightconexyz/lightcone-sdk";
|
|
234
|
+
import { program } from "@lightconexyz/lightcone-sdk";
|
|
235
|
+
|
|
236
|
+
const rules = await client.orderbooks().decimals(orderbook.orderbookId);
|
|
237
|
+
const orderPrice = "0.55"; // Quote tokens per base token.
|
|
238
|
+
const orderSize = "1"; // Base tokens.
|
|
239
|
+
const quoteAtoms = shared.scalePriceSize(
|
|
240
|
+
orderPrice, orderSize, program.OrderSide.BID, rules
|
|
241
|
+
).quoteAtoms;
|
|
242
|
+
const depositMint = new PublicKey(orderbook.quote.depositAsset);
|
|
243
|
+
const depositContext = await client.transactionContext();
|
|
244
|
+
const depositTx = client.positions().deposit()
|
|
247
245
|
.user(keypair.publicKey)
|
|
248
246
|
.mint(depositMint)
|
|
249
|
-
.amount(
|
|
250
|
-
.
|
|
247
|
+
.amount(quoteAtoms)
|
|
248
|
+
.buildTx(depositContext);
|
|
249
|
+
await client.signAndSubmitTxConfirmedWithSlot(depositTx);
|
|
250
|
+
|
|
251
|
+
// Confirmation can precede indexing. Check the available global collateral.
|
|
252
|
+
for (let attempt = 0; attempt < 15; attempt++) {
|
|
253
|
+
const snapshot = await client.positions().depositTokenBalances();
|
|
254
|
+
const entry = Object.values(snapshot.balances).find(
|
|
255
|
+
(balance) => balance.mint === depositMint.toBase58()
|
|
256
|
+
);
|
|
257
|
+
const idleAtoms = shared.exactScaledInteger(entry?.idle ?? "0", rules.quoteDecimals);
|
|
258
|
+
if (idleAtoms >= quoteAtoms) break;
|
|
259
|
+
if (attempt === 14) {
|
|
260
|
+
throw new Error("Global collateral is not indexed yet; order was not submitted");
|
|
261
|
+
}
|
|
262
|
+
await new Promise((resolve) => setTimeout(resolve, 2_000));
|
|
263
|
+
}
|
|
251
264
|
```
|
|
252
265
|
|
|
253
266
|
### Step 3: Place an Order
|
|
@@ -256,8 +269,8 @@ const depositIx = client.positions().deposit()
|
|
|
256
269
|
const order = await client.orders().limitOrder()
|
|
257
270
|
.maker(keypair.publicKey)
|
|
258
271
|
.bid()
|
|
259
|
-
.price(
|
|
260
|
-
.size(
|
|
272
|
+
.price(orderPrice)
|
|
273
|
+
.size(orderSize)
|
|
261
274
|
.submit(client, orderbook);
|
|
262
275
|
```
|
|
263
276
|
|
|
@@ -268,7 +281,7 @@ import { asPubkeyStr } from "@lightconexyz/lightcone-sdk";
|
|
|
268
281
|
|
|
269
282
|
const open = await client
|
|
270
283
|
.orders()
|
|
271
|
-
.getUserOrders(
|
|
284
|
+
.getUserOrders(50);
|
|
272
285
|
const ws = client.ws();
|
|
273
286
|
await ws.connect();
|
|
274
287
|
ws.subscribe({ type: "book_update", orderbook_ids: [orderbook.orderbookId] });
|
|
@@ -305,6 +318,8 @@ signer. Direct `sign()`/`finalize()` calls require the returned `OrderbookRules`
|
|
|
305
318
|
Raw amounts, explicit salts, and derived prices are preflighted against the same
|
|
306
319
|
signed-64-bit admission rules; no tick or size normalization is implicit.
|
|
307
320
|
|
|
321
|
+
The envelope generates a salt when omitted. The price is quote tokens per base token, and the size is base tokens. Example values must satisfy the selected orderbook's trading rules and available collateral.
|
|
322
|
+
|
|
308
323
|
### Wallet Balances and SOL Action Planning
|
|
309
324
|
|
|
310
325
|
`depositTokenBalances()` returns a required exact nine-decimal
|
|
@@ -415,7 +430,7 @@ automatic retry.
|
|
|
415
430
|
### Step 5: Cancel an Order
|
|
416
431
|
|
|
417
432
|
```typescript
|
|
418
|
-
|
|
433
|
+
// program and asPubkeyStr were imported in the preceding steps.
|
|
419
434
|
|
|
420
435
|
const signature = program.signCancelOrder(order.order_hash, keypair);
|
|
421
436
|
await client.orders().cancel({
|
|
@@ -427,6 +442,8 @@ await client.orders().cancel({
|
|
|
427
442
|
|
|
428
443
|
### Step 6: Exit a Position
|
|
429
444
|
|
|
445
|
+
Merge only when the wallet holds a complete set of outcome tokens for this deposit mint. Cancelling an unfilled order does not create that set. To return unused global collateral, proceed to withdrawal.
|
|
446
|
+
|
|
430
447
|
```typescript
|
|
431
448
|
// Uses the explicit transaction resources configured on the client.
|
|
432
449
|
// The signature means RPC acceptance; confirm before dependent account operations.
|
|
@@ -452,7 +469,9 @@ const withdrawIx = client.positions().withdraw()
|
|
|
452
469
|
|
|
453
470
|
## Authentication
|
|
454
471
|
|
|
455
|
-
Authentication is
|
|
472
|
+
Authentication is required for user-specific endpoints. Fetch `/api/auth/nonce`, then sign the exact message `Sign in to Lightcone\nNonce: {nonce}` with ED25519. Use `auth.signLoginMessage` to construct this challenge, then exchange the signed message for a session. Do not sign a timestamp or the nonce alone.
|
|
473
|
+
|
|
474
|
+
Authenticate before connecting a private WebSocket. Node clients send the session cookie during the upgrade, and browsers supply the cookie automatically. Private user subscriptions require `wallet_address`. Derive the Trading Wallet with `tradingWallet(session.user, session.auth_method)`. Refer to the [authenticated streaming example](examples/ws_user_and_market.ts).
|
|
456
475
|
|
|
457
476
|
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.
|
|
458
477
|
|
|
@@ -465,6 +484,8 @@ than 10 using `client.auth().updateMaxSlippagePreference(value)`; the method
|
|
|
465
484
|
returns the canonical exact decimal string. Values at or above 10% remain valid
|
|
466
485
|
order protection but are not remembered through this API.
|
|
467
486
|
|
|
487
|
+
`session.user.telegram_invite_url` is the single-use Telegram group invite URL that the backend assigned to the Account. It is `null` when the Account holds no invite or when an older backend omits the field. The URL is a secret of the Account. Do not log it and do not send it to analytics.
|
|
488
|
+
|
|
468
489
|
### Cookie handling
|
|
469
490
|
|
|
470
491
|
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:
|
|
@@ -472,30 +493,29 @@ After login succeeds, the SDK stores the session token internally and attaches i
|
|
|
472
493
|
- **Node / non-browser**: token is stored on the `LightconeHttp` instance and added as a `Cookie` header per request.
|
|
473
494
|
- **Browser**: requests use `credentials: "include"` and the runtime supplies the cookie automatically — the SDK's internal store is unused.
|
|
474
495
|
|
|
475
|
-
### Server-side cookie forwarding (`*
|
|
496
|
+
### Server-side cookie forwarding (`*WithCookies` variants)
|
|
476
497
|
|
|
477
|
-
|
|
498
|
+
Ordinary authenticated methods use the client's session or the browser cookie. Server-side rendering and route handlers must pass the incoming raw `Cookie` header to the corresponding `*WithCookies` method.
|
|
478
499
|
|
|
479
|
-
|
|
500
|
+
The cookie name is `lightcone-token`. Do not install a user's token on a client shared between requests from different users.
|
|
480
501
|
|
|
481
502
|
> **Behavior change.** `getWithCookies` responses no longer capture `Set-Cookie` into the shared token slot (they previously did): a forwarded per-user request rotating its token must not leak that token to every later request from a shared server client. These requests also never consult the credential restorer.
|
|
482
503
|
|
|
483
|
-
|
|
504
|
+
These methods forward the supplied header for one call:
|
|
484
505
|
|
|
485
506
|
```typescript
|
|
486
|
-
//
|
|
487
|
-
// from the incoming request:
|
|
507
|
+
// cookieHeader is the incoming raw Cookie header, including lightcone-token=...
|
|
488
508
|
const snapshot = await client
|
|
489
509
|
.positions()
|
|
490
|
-
.depositTokenBalancesWithCookies(undefined,
|
|
510
|
+
.depositTokenBalancesWithCookies(undefined, cookieHeader);
|
|
491
511
|
console.log(`snapshot slot ${snapshot.context_slot}: ${Object.keys(snapshot.balances).length} balances`);
|
|
492
512
|
|
|
493
513
|
const positions = await client
|
|
494
514
|
.positions()
|
|
495
|
-
.
|
|
515
|
+
.positionsWithCookies(cookieHeader);
|
|
496
516
|
```
|
|
497
517
|
|
|
498
|
-
In
|
|
518
|
+
In browsers, use the ordinary methods. The browser supplies the cookie through `credentials: "include"`.
|
|
499
519
|
|
|
500
520
|
## Environment Configuration
|
|
501
521
|
|
package/dist/auth/client.js
CHANGED
|
@@ -51,7 +51,7 @@ class Auth {
|
|
|
51
51
|
// verifying the signature, so a replayed login deterministically fails —
|
|
52
52
|
// and restoring credentials in order to log in is circular.
|
|
53
53
|
const session = await this.client.http.postWithoutCredentialRestore(url, body, http_1.RetryPolicy.None);
|
|
54
|
-
|
|
54
|
+
normalizeSessionUser(session);
|
|
55
55
|
this.client.authState.setCredentials(credentialsFromSession(session));
|
|
56
56
|
return session;
|
|
57
57
|
}
|
|
@@ -60,7 +60,7 @@ class Auth {
|
|
|
60
60
|
let session;
|
|
61
61
|
try {
|
|
62
62
|
session = await this.client.http.get(url, http_1.RetryPolicy.Idempotent);
|
|
63
|
-
|
|
63
|
+
normalizeSessionUser(session);
|
|
64
64
|
}
|
|
65
65
|
catch (error) {
|
|
66
66
|
this.client.authState.setCredentials(undefined);
|
|
@@ -107,7 +107,7 @@ class Auth {
|
|
|
107
107
|
async registerPrivy(request) {
|
|
108
108
|
const url = `${this.client.http.baseUrl()}/api/auth/register-privy`;
|
|
109
109
|
const session = await this.client.http.post(url, request, http_1.RetryPolicy.Idempotent);
|
|
110
|
-
|
|
110
|
+
normalizeSessionUser(session);
|
|
111
111
|
this.client.authState.setCredentials(credentialsFromSession(session));
|
|
112
112
|
return session;
|
|
113
113
|
}
|
|
@@ -136,6 +136,38 @@ class Auth {
|
|
|
136
136
|
}
|
|
137
137
|
}
|
|
138
138
|
exports.Auth = Auth;
|
|
139
|
+
/**
|
|
140
|
+
* Enforces the session user's nullable-field contracts after every
|
|
141
|
+
* session-returning call. Login, session restoration, and Privy registration
|
|
142
|
+
* share it so that no entry point skips a field.
|
|
143
|
+
*/
|
|
144
|
+
function normalizeSessionUser(session) {
|
|
145
|
+
normalizeSessionMaxSlippagePreference(session);
|
|
146
|
+
session.user.telegram_invite_url = decodeTelegramInviteUrl(session.user);
|
|
147
|
+
}
|
|
148
|
+
/**
|
|
149
|
+
* Decodes the session user's Telegram invite URL. A missing key (older backend)
|
|
150
|
+
* and an explicit null (Account without an invite) both mean no invite. Any
|
|
151
|
+
* other non-string value is a contract violation. Error text never includes the
|
|
152
|
+
* value, because the URL is a secret of the Account.
|
|
153
|
+
*/
|
|
154
|
+
function decodeTelegramInviteUrl(user) {
|
|
155
|
+
if (typeof user !== "object" || user === null) {
|
|
156
|
+
throw error_1.SdkError.serde("Session user is malformed");
|
|
157
|
+
}
|
|
158
|
+
// An own-property read keeps an inherited value from counting as an invite.
|
|
159
|
+
if (!Object.prototype.hasOwnProperty.call(user, "telegram_invite_url")) {
|
|
160
|
+
return null;
|
|
161
|
+
}
|
|
162
|
+
const inviteUrl = user.telegram_invite_url;
|
|
163
|
+
if (inviteUrl === undefined || inviteUrl === null) {
|
|
164
|
+
return null;
|
|
165
|
+
}
|
|
166
|
+
if (typeof inviteUrl === "string") {
|
|
167
|
+
return inviteUrl;
|
|
168
|
+
}
|
|
169
|
+
throw error_1.SdkError.serde("Session user telegram_invite_url must contain a string or null");
|
|
170
|
+
}
|
|
139
171
|
function normalizeSessionMaxSlippagePreference(session) {
|
|
140
172
|
const preference = decodeMaxSlippagePreference(session?.user, true, "session user", true);
|
|
141
173
|
session.user.max_slippage_preference = preference;
|
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 {\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"]}
|
|
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 normalizeSessionUser(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 normalizeSessionUser(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 normalizeSessionUser(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\n/**\n * Enforces the session user's nullable-field contracts after every\n * session-returning call. Login, session restoration, and Privy registration\n * share it so that no entry point skips a field.\n */\nfunction normalizeSessionUser(session: SessionResponse): void {\n normalizeSessionMaxSlippagePreference(session);\n session.user.telegram_invite_url = decodeTelegramInviteUrl(session.user);\n}\n\n/**\n * Decodes the session user's Telegram invite URL. A missing key (older backend)\n * and an explicit null (Account without an invite) both mean no invite. Any\n * other non-string value is a contract violation. Error text never includes the\n * value, because the URL is a secret of the Account.\n */\nfunction decodeTelegramInviteUrl(user: unknown): string | null {\n if (typeof user !== \"object\" || user === null) {\n throw SdkError.serde(\"Session user is malformed\");\n }\n // An own-property read keeps an inherited value from counting as an invite.\n if (!Object.prototype.hasOwnProperty.call(user, \"telegram_invite_url\")) {\n return null;\n }\n const inviteUrl = (user as Record<string, unknown>).telegram_invite_url;\n if (inviteUrl === undefined || inviteUrl === null) {\n return null;\n }\n if (typeof inviteUrl === \"string\") {\n return inviteUrl;\n }\n throw SdkError.serde(\n \"Session user telegram_invite_url must contain a string or null\",\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
|
@@ -124,6 +124,13 @@ export interface User {
|
|
|
124
124
|
max_slippage_preference: string | null;
|
|
125
125
|
/** X account connected by a non-X-identity user; absent when identity is X. */
|
|
126
126
|
connected_x?: XAccountData;
|
|
127
|
+
/**
|
|
128
|
+
* Single-use Telegram group invite URL assigned to the Account. It is null
|
|
129
|
+
* when the Account holds no invite. Session decoding normalizes a value that
|
|
130
|
+
* an older backend omits to null. The URL is a secret of the Account. Do not
|
|
131
|
+
* log it or send it to analytics.
|
|
132
|
+
*/
|
|
133
|
+
telegram_invite_url?: string | null;
|
|
127
134
|
}
|
|
128
135
|
/**
|
|
129
136
|
* Session envelope returned by `loginWithMessage`, `register-privy`, and
|
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":"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
|
|
1
|
+
{"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../../src/auth/index.ts"],"names":[],"mappings":"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"}
|
package/dist/auth/index.js.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"index.js","sourceRoot":"","sources":["../../src/auth/index.ts"],"names":[],"mappings":"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","sourcesContent":["import type { PubkeyStr } from \"../shared\";\nimport { shorten } from \"../shared/fmt/str\";\n\nexport * from \"./client\";\nexport * from \"./native\";\n\n/**\n * How a session authenticated, as reported by the backend (derived from which\n * token verified the request).\n */\nexport enum AuthMethod {\n Privy = \"privy\",\n Lightcone = \"lightcone\",\n}\n\nexport enum ChainType {\n Solana = \"solana\",\n Ethereum = \"ethereum\",\n}\n\n/** A Privy-managed embedded wallet. */\nexport interface PrivyEmbeddedWallet {\n privy_id: string;\n chain: ChainType;\n address: string;\n}\n\n/** Privy account data attached to an identity. */\nexport interface UserPrivyData {\n /** The Privy DID (`did:privy:...`). */\n id: string;\n /**\n * Always present: Privy registration provisions the embedded wallet in the\n * same transaction that creates the user.\n */\n wallet: PrivyEmbeddedWallet;\n}\n\n/**\n * X account data — the same shape whether X is the login identity or a\n * connected account on a Google/wallet identity.\n */\nexport interface XAccountData {\n /** X numeric user id (Privy `subject`); absent on legacy rows. */\n user_id?: string;\n username: string;\n display_name?: string;\n avatar_url?: string;\n}\n\n/** Google account data for a Google login identity. */\nexport interface GoogleAccountData {\n email: string;\n name?: string;\n given_name?: string;\n family_name?: string;\n avatar_url?: string;\n}\n\n/** Canonical address for a passwordless Email login identity. */\nexport interface EmailAccountData {\n email: string;\n}\n\n/** Public login-method names exposed in profiles and bounded conflicts. */\nexport type LinkedIdentityType = \"email\" | \"google\" | \"x\" | \"wallet\";\n\n/** Connected Login Identity without repeated Account-level Privy wallet data. */\nexport type LinkedIdentity =\n | { type: \"email\"; account: EmailAccountData }\n | { type: \"google\"; account: GoogleAccountData }\n | { type: \"x\"; account: XAccountData }\n | { type: \"wallet\"; address: string; chain: ChainType };\n\n/** Verified method and canonical identifier that initiated Privy authentication. */\nexport type LinkedIdentitySelector =\n | { type: \"email\"; email: string }\n | { type: \"google\"; email: string }\n | { type: \"x\"; username: string }\n | { type: \"wallet\"; address: string; chain: ChainType };\n\n/** Register-or-sync request naming the verified attempted identity. */\nexport interface RegisterPrivyRequest {\n attempted_identity: LinkedIdentitySelector;\n}\n\n/**\n * The login identity — how the user authenticates. `type` narrows the variant.\n *\n * Privy data lives on the variant because its presence is determined by the\n * identity type: Google/X login only exists via Privy OAuth (guaranteed DID +\n * embedded wallet), while wallet users opt into Privy (SIWS) or stay\n * self-custody.\n */\nexport type UserIdentity =\n | { type: \"email\"; account: EmailAccountData; privy: UserPrivyData }\n | { type: \"google\"; account: GoogleAccountData; privy: UserPrivyData }\n | { type: \"x\"; account: XAccountData; privy: UserPrivyData }\n | {\n type: \"wallet\";\n address: string;\n chain: ChainType;\n privy?: UserPrivyData;\n };\n\n/** Full user profile — the `user` object of {@link SessionResponse}. */\nexport interface User {\n user_id: string;\n identity: UserIdentity;\n /** Every verified login identity connected to the Account, primary first. */\n linked_identities?: LinkedIdentity[];\n /** Remembered account-wide percentage below 10%; null until one is stored. */\n max_slippage_preference: string | null;\n /** X account connected by a non-X-identity user; absent when identity is X. */\n connected_x?: XAccountData;\n}\n\n/**\n * Session envelope returned by `loginWithMessage`, `register-privy`, and\n * `GET /api/auth/me`. There is no `wallet_address` field — derive the\n * session's trading wallet with {@link tradingWallet}.\n */\nexport interface SessionResponse {\n user: User;\n expires_at: number;\n auth_method: AuthMethod;\n is_beta: boolean;\n}\n\n/** Exact decimal-string body used to update and return max slippage. */\nexport interface MaxSlippagePreferenceBody {\n max_slippage_preference: string;\n}\n\n/** Human-readable login-method label (\"Email\" / \"Google\" / \"X\" / \"Solana\"). */\nexport function identityText(\n identity: UserIdentity,\n): \"Email\" | \"Google\" | \"X\" | \"Solana\" {\n switch (identity.type) {\n case \"email\":\n return \"Email\";\n case \"google\":\n return \"Google\";\n case \"x\":\n return \"X\";\n case \"wallet\":\n return \"Solana\";\n default: {\n const exhaustive: never = identity;\n throw new Error(`Unknown identity: ${JSON.stringify(exhaustive)}`);\n }\n }\n}\n\n/** Privy account data, regardless of identity type. */\nexport function userPrivy(user: User): UserPrivyData | undefined {\n switch (user.identity.type) {\n case \"email\":\n case \"google\":\n case \"x\":\n return user.identity.privy;\n case \"wallet\":\n return user.identity.privy;\n }\n}\n\n/** The X account, whether it is the login identity or a connected account. */\nexport function userXAccount(user: User): XAccountData | undefined {\n return user.identity.type === \"x\" ? user.identity.account : user.connected_x;\n}\n\n/**\n * The wallet a session operates as.\n *\n * Google/X identities only exist via Privy registration, which always\n * provisions an embedded wallet — that wallet is the answer regardless of\n * auth method. Wallet identities depend on the session: a Privy (SIWS)\n * session trades via the embedded wallet, a Lightcone session trades via the\n * wallet that signed in.\n */\nexport function tradingWallet(user: User, authMethod: AuthMethod): string {\n switch (user.identity.type) {\n case \"email\":\n case \"google\":\n case \"x\":\n return user.identity.privy.wallet.address;\n case \"wallet\":\n return authMethod === AuthMethod.Privy\n ? (user.identity.privy?.wallet.address ?? user.identity.address)\n : user.identity.address;\n }\n}\n\n/** Short display label for the wallet a session operates as. */\nexport function walletDisplayName(user: User, authMethod: AuthMethod): string {\n return shorten(tradingWallet(user, authMethod), 8);\n}\n\n/** Keeps Email labels compact while preserving the recognizable address ends. */\nfunction emailDisplayName(email: string): string {\n const maxChars = 20;\n const chars = [...email];\n if (chars.length <= maxChars) {\n return email;\n }\n\n const visibleChars = maxChars - 3;\n const prefixChars = Math.floor(visibleChars / 2);\n return `${chars.slice(0, prefixChars).join(\"\")}...${chars\n .slice(-(visibleChars - prefixChars))\n .join(\"\")}`;\n}\n\n/**\n * Best display name for the user. Email addresses are limited to 20 characters;\n * Google uses `name` with an email fallback; X uses `display_name` with a\n * username fallback; wallet identities show the shortened address (`FRGk...WcPR`).\n */\nexport function displayName(user: User): string {\n switch (user.identity.type) {\n case \"email\":\n return emailDisplayName(user.identity.account.email);\n case \"google\":\n return user.identity.account.name ?? user.identity.account.email;\n case \"x\":\n return (\n user.identity.account.display_name ?? user.identity.account.username\n );\n case \"wallet\":\n return shorten(user.identity.address, 8);\n }\n}\n\n/** Avatar URL from the login identity's OAuth provider, if any. */\nexport function avatarUrl(user: User): string | undefined {\n switch (user.identity.type) {\n case \"email\":\n return undefined;\n case \"google\":\n case \"x\":\n return user.identity.account.avatar_url;\n case \"wallet\":\n return undefined;\n }\n}\n\nexport interface AuthCredentials {\n user_id: string;\n wallet_address: PubkeyStr;\n expires_at: Date;\n}\n\nexport function isAuthenticated(credentials?: AuthCredentials): boolean {\n if (!credentials) {\n return false;\n }\n return Date.now() < credentials.expires_at.getTime();\n}\n\nexport function generateSigninMessage(nonce: string): Uint8Array {\n return new TextEncoder().encode(`Sign in to Lightcone\\nNonce: ${nonce}`);\n}\n\nexport interface LoginRequest {\n message: string;\n signature_bs58: string;\n pubkey_bytes: number[];\n use_embedded_wallet?: boolean;\n}\n\nexport interface NonceResponse {\n nonce: string;\n}\n"]}
|
|
1
|
+
{"version":3,"file":"index.js","sourceRoot":"","sources":["../../src/auth/index.ts"],"names":[],"mappings":"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","sourcesContent":["import type { PubkeyStr } from \"../shared\";\nimport { shorten } from \"../shared/fmt/str\";\n\nexport * from \"./client\";\nexport * from \"./native\";\n\n/**\n * How a session authenticated, as reported by the backend (derived from which\n * token verified the request).\n */\nexport enum AuthMethod {\n Privy = \"privy\",\n Lightcone = \"lightcone\",\n}\n\nexport enum ChainType {\n Solana = \"solana\",\n Ethereum = \"ethereum\",\n}\n\n/** A Privy-managed embedded wallet. */\nexport interface PrivyEmbeddedWallet {\n privy_id: string;\n chain: ChainType;\n address: string;\n}\n\n/** Privy account data attached to an identity. */\nexport interface UserPrivyData {\n /** The Privy DID (`did:privy:...`). */\n id: string;\n /**\n * Always present: Privy registration provisions the embedded wallet in the\n * same transaction that creates the user.\n */\n wallet: PrivyEmbeddedWallet;\n}\n\n/**\n * X account data — the same shape whether X is the login identity or a\n * connected account on a Google/wallet identity.\n */\nexport interface XAccountData {\n /** X numeric user id (Privy `subject`); absent on legacy rows. */\n user_id?: string;\n username: string;\n display_name?: string;\n avatar_url?: string;\n}\n\n/** Google account data for a Google login identity. */\nexport interface GoogleAccountData {\n email: string;\n name?: string;\n given_name?: string;\n family_name?: string;\n avatar_url?: string;\n}\n\n/** Canonical address for a passwordless Email login identity. */\nexport interface EmailAccountData {\n email: string;\n}\n\n/** Public login-method names exposed in profiles and bounded conflicts. */\nexport type LinkedIdentityType = \"email\" | \"google\" | \"x\" | \"wallet\";\n\n/** Connected Login Identity without repeated Account-level Privy wallet data. */\nexport type LinkedIdentity =\n | { type: \"email\"; account: EmailAccountData }\n | { type: \"google\"; account: GoogleAccountData }\n | { type: \"x\"; account: XAccountData }\n | { type: \"wallet\"; address: string; chain: ChainType };\n\n/** Verified method and canonical identifier that initiated Privy authentication. */\nexport type LinkedIdentitySelector =\n | { type: \"email\"; email: string }\n | { type: \"google\"; email: string }\n | { type: \"x\"; username: string }\n | { type: \"wallet\"; address: string; chain: ChainType };\n\n/** Register-or-sync request naming the verified attempted identity. */\nexport interface RegisterPrivyRequest {\n attempted_identity: LinkedIdentitySelector;\n}\n\n/**\n * The login identity — how the user authenticates. `type` narrows the variant.\n *\n * Privy data lives on the variant because its presence is determined by the\n * identity type: Google/X login only exists via Privy OAuth (guaranteed DID +\n * embedded wallet), while wallet users opt into Privy (SIWS) or stay\n * self-custody.\n */\nexport type UserIdentity =\n | { type: \"email\"; account: EmailAccountData; privy: UserPrivyData }\n | { type: \"google\"; account: GoogleAccountData; privy: UserPrivyData }\n | { type: \"x\"; account: XAccountData; privy: UserPrivyData }\n | {\n type: \"wallet\";\n address: string;\n chain: ChainType;\n privy?: UserPrivyData;\n };\n\n/** Full user profile — the `user` object of {@link SessionResponse}. */\nexport interface User {\n user_id: string;\n identity: UserIdentity;\n /** Every verified login identity connected to the Account, primary first. */\n linked_identities?: LinkedIdentity[];\n /** Remembered account-wide percentage below 10%; null until one is stored. */\n max_slippage_preference: string | null;\n /** X account connected by a non-X-identity user; absent when identity is X. */\n connected_x?: XAccountData;\n /**\n * Single-use Telegram group invite URL assigned to the Account. It is null\n * when the Account holds no invite. Session decoding normalizes a value that\n * an older backend omits to null. The URL is a secret of the Account. Do not\n * log it or send it to analytics.\n */\n telegram_invite_url?: string | null;\n}\n\n/**\n * Session envelope returned by `loginWithMessage`, `register-privy`, and\n * `GET /api/auth/me`. There is no `wallet_address` field — derive the\n * session's trading wallet with {@link tradingWallet}.\n */\nexport interface SessionResponse {\n user: User;\n expires_at: number;\n auth_method: AuthMethod;\n is_beta: boolean;\n}\n\n/** Exact decimal-string body used to update and return max slippage. */\nexport interface MaxSlippagePreferenceBody {\n max_slippage_preference: string;\n}\n\n/** Human-readable login-method label (\"Email\" / \"Google\" / \"X\" / \"Solana\"). */\nexport function identityText(\n identity: UserIdentity,\n): \"Email\" | \"Google\" | \"X\" | \"Solana\" {\n switch (identity.type) {\n case \"email\":\n return \"Email\";\n case \"google\":\n return \"Google\";\n case \"x\":\n return \"X\";\n case \"wallet\":\n return \"Solana\";\n default: {\n const exhaustive: never = identity;\n throw new Error(`Unknown identity: ${JSON.stringify(exhaustive)}`);\n }\n }\n}\n\n/** Privy account data, regardless of identity type. */\nexport function userPrivy(user: User): UserPrivyData | undefined {\n switch (user.identity.type) {\n case \"email\":\n case \"google\":\n case \"x\":\n return user.identity.privy;\n case \"wallet\":\n return user.identity.privy;\n }\n}\n\n/** The X account, whether it is the login identity or a connected account. */\nexport function userXAccount(user: User): XAccountData | undefined {\n return user.identity.type === \"x\" ? user.identity.account : user.connected_x;\n}\n\n/**\n * The wallet a session operates as.\n *\n * Google/X identities only exist via Privy registration, which always\n * provisions an embedded wallet — that wallet is the answer regardless of\n * auth method. Wallet identities depend on the session: a Privy (SIWS)\n * session trades via the embedded wallet, a Lightcone session trades via the\n * wallet that signed in.\n */\nexport function tradingWallet(user: User, authMethod: AuthMethod): string {\n switch (user.identity.type) {\n case \"email\":\n case \"google\":\n case \"x\":\n return user.identity.privy.wallet.address;\n case \"wallet\":\n return authMethod === AuthMethod.Privy\n ? (user.identity.privy?.wallet.address ?? user.identity.address)\n : user.identity.address;\n }\n}\n\n/** Short display label for the wallet a session operates as. */\nexport function walletDisplayName(user: User, authMethod: AuthMethod): string {\n return shorten(tradingWallet(user, authMethod), 8);\n}\n\n/** Keeps Email labels compact while preserving the recognizable address ends. */\nfunction emailDisplayName(email: string): string {\n const maxChars = 20;\n const chars = [...email];\n if (chars.length <= maxChars) {\n return email;\n }\n\n const visibleChars = maxChars - 3;\n const prefixChars = Math.floor(visibleChars / 2);\n return `${chars.slice(0, prefixChars).join(\"\")}...${chars\n .slice(-(visibleChars - prefixChars))\n .join(\"\")}`;\n}\n\n/**\n * Best display name for the user. Email addresses are limited to 20 characters;\n * Google uses `name` with an email fallback; X uses `display_name` with a\n * username fallback; wallet identities show the shortened address (`FRGk...WcPR`).\n */\nexport function displayName(user: User): string {\n switch (user.identity.type) {\n case \"email\":\n return emailDisplayName(user.identity.account.email);\n case \"google\":\n return user.identity.account.name ?? user.identity.account.email;\n case \"x\":\n return (\n user.identity.account.display_name ?? user.identity.account.username\n );\n case \"wallet\":\n return shorten(user.identity.address, 8);\n }\n}\n\n/** Avatar URL from the login identity's OAuth provider, if any. */\nexport function avatarUrl(user: User): string | undefined {\n switch (user.identity.type) {\n case \"email\":\n return undefined;\n case \"google\":\n case \"x\":\n return user.identity.account.avatar_url;\n case \"wallet\":\n return undefined;\n }\n}\n\nexport interface AuthCredentials {\n user_id: string;\n wallet_address: PubkeyStr;\n expires_at: Date;\n}\n\nexport function isAuthenticated(credentials?: AuthCredentials): boolean {\n if (!credentials) {\n return false;\n }\n return Date.now() < credentials.expires_at.getTime();\n}\n\nexport function generateSigninMessage(nonce: string): Uint8Array {\n return new TextEncoder().encode(`Sign in to Lightcone\\nNonce: ${nonce}`);\n}\n\nexport interface LoginRequest {\n message: string;\n signature_bs58: string;\n pubkey_bytes: number[];\n use_embedded_wallet?: boolean;\n}\n\nexport interface NonceResponse {\n nonce: string;\n}\n"]}
|