@lightconexyz/lightcone-sdk 0.8.4-rc.55 → 0.8.4-rc.56
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 +4 -2
- package/dist/auth/client.d.ts +6 -1
- package/dist/auth/client.d.ts.map +1 -1
- package/dist/auth/client.js +6 -1
- package/dist/auth/client.js.map +1 -1
- package/package.json +1 -1
package/README.md
CHANGED
|
@@ -469,9 +469,11 @@ const withdrawIx = client.positions().withdraw()
|
|
|
469
469
|
|
|
470
470
|
## Authentication
|
|
471
471
|
|
|
472
|
-
|
|
472
|
+
Native clients running in Node follow the [native client recovery guide](../docs/auth-session-recovery.md) for session teardown and WebSocket recovery. It explains per-token logout, incomplete teardown, anonymous public continuity, and finite reconnect budgets. Browser clients use Privy authentication.
|
|
473
473
|
|
|
474
|
-
|
|
474
|
+
Authentication is required for user-specific endpoints. Native clients using Lightcone sessions fetch `/api/auth/nonce`. 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.
|
|
475
|
+
|
|
476
|
+
Authenticate before connecting a private WebSocket. Native clients running in Node send the Lightcone session cookie during the upgrade. Browser clients supply their Privy 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).
|
|
475
477
|
|
|
476
478
|
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.
|
|
477
479
|
|
package/dist/auth/client.d.ts
CHANGED
|
@@ -30,11 +30,16 @@ export declare class Auth {
|
|
|
30
30
|
/**
|
|
31
31
|
* Logout — clears the server-side cookie, internal token, and credentials.
|
|
32
32
|
*
|
|
33
|
+
* Server revocation targets native clients' `lightcone-token` credentials.
|
|
34
|
+
* Browser clients must end their Privy session through the Privy SDK.
|
|
35
|
+
*
|
|
33
36
|
* Local state is cleared even when the server call fails — the caller asked
|
|
34
37
|
* to be signed out locally regardless — but the failure is then rethrown:
|
|
35
38
|
* callers gating security decisions on teardown (e.g. whether an app may
|
|
36
39
|
* restart an authenticated transport) must be able to see that the
|
|
37
|
-
*
|
|
40
|
+
* revocation may be unconfirmed, or a revoked token may still await remote
|
|
41
|
+
* WebSocket teardown. Refer to the authentication guide in README.
|
|
42
|
+
* A 401 counts as success: it means
|
|
38
43
|
* "already logged out".
|
|
39
44
|
*/
|
|
40
45
|
logout(): Promise<void>;
|
|
@@ -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,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
|
|
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;;;;;;;;;;;;;;OAcG;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
|
@@ -72,11 +72,16 @@ class Auth {
|
|
|
72
72
|
/**
|
|
73
73
|
* Logout — clears the server-side cookie, internal token, and credentials.
|
|
74
74
|
*
|
|
75
|
+
* Server revocation targets native clients' `lightcone-token` credentials.
|
|
76
|
+
* Browser clients must end their Privy session through the Privy SDK.
|
|
77
|
+
*
|
|
75
78
|
* Local state is cleared even when the server call fails — the caller asked
|
|
76
79
|
* to be signed out locally regardless — but the failure is then rethrown:
|
|
77
80
|
* callers gating security decisions on teardown (e.g. whether an app may
|
|
78
81
|
* restart an authenticated transport) must be able to see that the
|
|
79
|
-
*
|
|
82
|
+
* revocation may be unconfirmed, or a revoked token may still await remote
|
|
83
|
+
* WebSocket teardown. Refer to the authentication guide in README.
|
|
84
|
+
* A 401 counts as success: it means
|
|
80
85
|
* "already logged out".
|
|
81
86
|
*/
|
|
82
87
|
async logout() {
|
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 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"]}
|
|
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 * Server revocation targets native clients' `lightcone-token` credentials.\n * Browser clients must end their Privy session through the Privy SDK.\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 * revocation may be unconfirmed, or a revoked token may still await remote\n * WebSocket teardown. Refer to the authentication guide in README.\n * 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"]}
|