lens-convex-auth 0.1.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
@@ -0,0 +1,526 @@
1
+ "use client";
2
+
3
+ // src/core/constants.ts
4
+ var LENS_API_ORIGINS = {
5
+ mainnet: "https://api.lens.xyz",
6
+ testnet: "https://api.testnet.lens.xyz"
7
+ };
8
+ function lensApiOrigin(environment = "mainnet") {
9
+ return LENS_API_ORIGINS[environment];
10
+ }
11
+ var LENS_CHAIN_IDS = {
12
+ mainnet: 232,
13
+ testnet: 37111
14
+ };
15
+ var LENS_TOKEN_LIFETIME_MS = 10 * 60 * 1e3;
16
+ var ADDRESS_RE = /^0x[0-9a-fA-F]{40}$/;
17
+ var DEFAULT_CONVEX_TOKEN_ENDPOINT = "/api/convex-token";
18
+
19
+ // src/core/jwt.ts
20
+ function decodeJwtPayload(token) {
21
+ try {
22
+ const payload = token.split(".")[1];
23
+ if (!payload) return null;
24
+ const base64 = payload.replace(/-/g, "+").replace(/_/g, "/");
25
+ const binary = atob(base64.padEnd(base64.length + (4 - base64.length % 4) % 4, "="));
26
+ const json = new TextDecoder().decode(Uint8Array.from(binary, (c) => c.charCodeAt(0)));
27
+ const claims = JSON.parse(json);
28
+ return claims && typeof claims === "object" ? claims : null;
29
+ } catch {
30
+ return null;
31
+ }
32
+ }
33
+ function jwtExpiresAt(token) {
34
+ const exp = Number(decodeJwtPayload(token)?.exp);
35
+ return Number.isFinite(exp) && exp > 0 ? exp * 1e3 : null;
36
+ }
37
+ function lensSessionFromIdToken(idToken) {
38
+ const claims = decodeJwtPayload(idToken);
39
+ const act = claims?.act;
40
+ if (typeof act?.sub !== "string") return null;
41
+ return { account: act.sub.toLowerCase(), sessionId: String(claims?.sid ?? "") };
42
+ }
43
+
44
+ // src/core/storage.ts
45
+ var LensTokenStorage = class {
46
+ constructor(tokens, prefix) {
47
+ this.tokens = tokens;
48
+ this.prefix = prefix;
49
+ }
50
+ tokens;
51
+ prefix;
52
+ isCredentials(key) {
53
+ return key.includes("credentials") || key.includes("session");
54
+ }
55
+ // The SDK only accepts a stored credentials item whose metadata is exactly
56
+ // { version, createdAt, updatedAt }, so keep the metadata it wrote and hand it back unchanged.
57
+ metadataKey(key) {
58
+ return `${this.prefix}${key}:metadata`;
59
+ }
60
+ credentialsMetadata(key) {
61
+ const stored = localStorage.getItem(this.metadataKey(key));
62
+ if (stored) return JSON.parse(stored);
63
+ const now = Date.now();
64
+ return { version: 3, createdAt: now, updatedAt: now };
65
+ }
66
+ getItem(key) {
67
+ if (typeof window === "undefined") return null;
68
+ try {
69
+ if (!this.isCredentials(key)) return localStorage.getItem(this.prefix + key);
70
+ const tokens = this.tokens.getStoredTokens();
71
+ if (!tokens) return null;
72
+ return JSON.stringify({
73
+ data: { accessToken: tokens.accessToken, idToken: tokens.idToken, refreshToken: tokens.refreshToken },
74
+ metadata: this.credentialsMetadata(key)
75
+ });
76
+ } catch {
77
+ return null;
78
+ }
79
+ }
80
+ setItem(key, value) {
81
+ if (typeof window === "undefined") return;
82
+ try {
83
+ if (!this.isCredentials(key)) return localStorage.setItem(this.prefix + key, value);
84
+ const parsed = JSON.parse(value);
85
+ const data = typeof parsed.data === "string" ? JSON.parse(parsed.data) : parsed.data;
86
+ if (data?.accessToken && data?.idToken && data?.refreshToken) {
87
+ this.tokens.storeCredentials(data);
88
+ localStorage.setItem(this.metadataKey(key), JSON.stringify(parsed.metadata));
89
+ }
90
+ } catch {
91
+ }
92
+ }
93
+ removeItem(key) {
94
+ if (typeof window === "undefined") return;
95
+ try {
96
+ if (!this.isCredentials(key)) return localStorage.removeItem(this.prefix + key);
97
+ this.tokens.clearTokens();
98
+ localStorage.removeItem(this.metadataKey(key));
99
+ } catch {
100
+ }
101
+ }
102
+ };
103
+
104
+ // src/core/tokens.ts
105
+ var TOKENS_CHANGED_EVENT = "lens-convex-auth:tokens-changed";
106
+ var REFRESH_BUFFER_MS = 60 * 1e3;
107
+ var REFRESH_MUTATION = `
108
+ mutation Refresh($request: RefreshRequest!) {
109
+ refresh(request: $request) {
110
+ ... on AuthenticationTokens {
111
+ accessToken
112
+ idToken
113
+ refreshToken
114
+ }
115
+ ... on ForbiddenError {
116
+ reason
117
+ }
118
+ }
119
+ }
120
+ `;
121
+ function notifyTokensChanged() {
122
+ try {
123
+ window.dispatchEvent(new Event(TOKENS_CHANGED_EVENT));
124
+ } catch {
125
+ }
126
+ }
127
+ var TokenService = class {
128
+ constructor(options) {
129
+ this.options = options;
130
+ const p = options.storagePrefix;
131
+ this.storageKeys = {
132
+ accessToken: `${p}access_token`,
133
+ idToken: `${p}id_token`,
134
+ refreshToken: `${p}refresh_token`,
135
+ expiresAt: `${p}token_expires_at`
136
+ };
137
+ }
138
+ options;
139
+ storageKeys;
140
+ refreshPromise = null;
141
+ storeTokens(tokens) {
142
+ if (typeof window === "undefined") return;
143
+ try {
144
+ localStorage.setItem(this.storageKeys.accessToken, tokens.accessToken);
145
+ localStorage.setItem(this.storageKeys.idToken, tokens.idToken);
146
+ localStorage.setItem(this.storageKeys.refreshToken, tokens.refreshToken);
147
+ localStorage.setItem(this.storageKeys.expiresAt, tokens.expiresAt.toString());
148
+ } catch {
149
+ }
150
+ notifyTokensChanged();
151
+ }
152
+ storeCredentials(credentials) {
153
+ this.storeTokens({ ...credentials, expiresAt: Date.now() + LENS_TOKEN_LIFETIME_MS });
154
+ }
155
+ getStoredTokens() {
156
+ if (typeof window === "undefined") return null;
157
+ try {
158
+ const accessToken = localStorage.getItem(this.storageKeys.accessToken);
159
+ const idToken = localStorage.getItem(this.storageKeys.idToken);
160
+ const refreshToken = localStorage.getItem(this.storageKeys.refreshToken);
161
+ const storedExpiresAt = localStorage.getItem(this.storageKeys.expiresAt);
162
+ if (!accessToken || !idToken || !refreshToken) return null;
163
+ const expiresAt = jwtExpiresAt(accessToken) ?? (storedExpiresAt ? parseInt(storedExpiresAt, 10) : 0);
164
+ return { accessToken, idToken, refreshToken, expiresAt };
165
+ } catch {
166
+ return null;
167
+ }
168
+ }
169
+ clearTokens() {
170
+ if (typeof window === "undefined") return;
171
+ try {
172
+ for (const key of Object.values(this.storageKeys)) localStorage.removeItem(key);
173
+ } catch {
174
+ }
175
+ notifyTokensChanged();
176
+ }
177
+ // Current access token, refreshed first if it's about to expire
178
+ async getValidAccessToken() {
179
+ const tokens = this.getStoredTokens();
180
+ if (!tokens) return null;
181
+ if (tokens.expiresAt > Date.now() + REFRESH_BUFFER_MS) return tokens.accessToken;
182
+ return (await this.refreshTokens())?.accessToken ?? null;
183
+ }
184
+ // ID token for authenticating to your backend (Convex, API routes), refreshed when it's about to
185
+ // expire (by the token's own `exp` claim). `forceRefresh` is for when the backend rejected it.
186
+ async getFreshIdToken(forceRefresh = false) {
187
+ const tokens = this.getStoredTokens();
188
+ if (!tokens) return null;
189
+ const expiresAt = jwtExpiresAt(tokens.idToken) ?? 0;
190
+ const fresh = expiresAt > Date.now() + REFRESH_BUFFER_MS;
191
+ const justIssued = expiresAt > Date.now() + 2 * REFRESH_BUFFER_MS;
192
+ if (fresh && (!forceRefresh || justIssued)) return tokens.idToken;
193
+ return (await this.refreshTokens())?.idToken ?? null;
194
+ }
195
+ async isAuthenticated() {
196
+ return !!await this.getValidAccessToken();
197
+ }
198
+ // Concurrent calls share one request. Clears the tokens when the session can't be refreshed.
199
+ refreshTokens() {
200
+ this.refreshPromise ??= this.performRefresh().finally(() => {
201
+ this.refreshPromise = null;
202
+ });
203
+ return this.refreshPromise;
204
+ }
205
+ async performRefresh() {
206
+ const refreshToken = this.getStoredTokens()?.refreshToken;
207
+ if (!refreshToken) {
208
+ this.clearTokens();
209
+ return null;
210
+ }
211
+ try {
212
+ const response = await fetch(this.options.graphqlUrl, {
213
+ method: "POST",
214
+ headers: { "Content-Type": "application/json" },
215
+ body: JSON.stringify({ query: REFRESH_MUTATION, variables: { request: { refreshToken } } })
216
+ });
217
+ const data = await response.json();
218
+ const result = data?.data?.refresh;
219
+ if (data.errors || !result || result.reason) throw new Error(result?.reason ?? "Refresh failed");
220
+ const tokens = {
221
+ accessToken: result.accessToken,
222
+ idToken: result.idToken,
223
+ refreshToken: result.refreshToken,
224
+ expiresAt: Date.now() + LENS_TOKEN_LIFETIME_MS
225
+ };
226
+ this.storeTokens(tokens);
227
+ return tokens;
228
+ } catch {
229
+ this.clearTokens();
230
+ return null;
231
+ }
232
+ }
233
+ };
234
+
235
+ // src/core/wallet.ts
236
+ import { createWalletClient, custom, defineChain as defineViemChain, getAddress, hexToBigInt, hexToNumber } from "viem";
237
+ import { lens as viemLens, lensTestnet as viemLensTestnet } from "viem/chains";
238
+ import { chainConfig } from "viem/zksync";
239
+ import { defineChain } from "thirdweb/chains";
240
+ import { EIP1193 } from "thirdweb/wallets";
241
+ function lensThirdwebChain(environment, rpcUrl) {
242
+ const testnet2 = environment === "testnet";
243
+ return defineChain({
244
+ id: LENS_CHAIN_IDS[environment],
245
+ name: testnet2 ? "Lens Chain Testnet" : "Lens Chain",
246
+ nativeCurrency: testnet2 ? { name: "GRASS", symbol: "GRASS", decimals: 18 } : { name: "GHO", symbol: "GHO", decimals: 18 },
247
+ ...rpcUrl ? { rpc: rpcUrl } : {},
248
+ ...testnet2 ? { testnet: true } : {}
249
+ });
250
+ }
251
+ function lensViemChain(environment) {
252
+ return defineViemChain({ ...environment === "testnet" ? viemLensTestnet : viemLens, ...chainConfig });
253
+ }
254
+ function createLensWalletClient(opts) {
255
+ const account = opts.wallet.getAccount();
256
+ if (!account) throw new Error("Connect your wallet");
257
+ const provider = EIP1193.toProvider({ wallet: opts.wallet, chain: opts.chain, client: opts.client });
258
+ return createWalletClient({
259
+ account: getAddress(account.address),
260
+ chain: opts.viemChain,
261
+ transport: custom({
262
+ request: ({ method, params }) => {
263
+ if (method === "eth_sendTransaction") {
264
+ const [tx] = params;
265
+ return provider.request({
266
+ method,
267
+ params: [{
268
+ to: tx.to,
269
+ data: tx.data,
270
+ value: tx.value ? hexToBigInt(tx.value) : void 0,
271
+ nonce: tx.nonce ? hexToNumber(tx.nonce) : void 0
272
+ }]
273
+ });
274
+ }
275
+ return provider.request({ method, params });
276
+ }
277
+ })
278
+ });
279
+ }
280
+
281
+ // src/core/auth.ts
282
+ import { PublicClient, evmAddress, mainnet, signatureFrom, testnet } from "@lens-protocol/client";
283
+ import { createThirdwebClient } from "thirdweb";
284
+ var CHALLENGE_REFRESH_MS = 2 * 60 * 1e3;
285
+ var CHALLENGE_MAX_AGE_MS = 4 * 60 * 1e3;
286
+ function opensWalletWithDeepLink() {
287
+ if (typeof navigator === "undefined") return false;
288
+ const ua = navigator.userAgent;
289
+ return /iPhone|iPad|iPod|Android/i.test(ua) || /Macintosh/.test(ua) && navigator.maxTouchPoints > 1;
290
+ }
291
+ function signLensChallenge(challenge, signer) {
292
+ return signer.signMessage({ message: challenge.text });
293
+ }
294
+ function sessionCredentials(session) {
295
+ const credentials = session.getCredentials();
296
+ if (credentials.isErr()) throw credentials.error;
297
+ if (!credentials.value) throw new Error("The Lens session has no credentials");
298
+ return credentials.value;
299
+ }
300
+ function createLensAuth(options) {
301
+ if (!options.thirdwebClientId) throw new Error("lens-convex-auth: thirdwebClientId is required");
302
+ if (!ADDRESS_RE.test(options.lensAppAddress ?? "")) {
303
+ throw new Error("lens-convex-auth: lensAppAddress must be your Lens app address (0x\u2026)");
304
+ }
305
+ const environment = options.environment ?? "mainnet";
306
+ const storagePrefix = options.storagePrefix ?? "lens_";
307
+ const appAddress = options.lensAppAddress;
308
+ const convexTokenEndpoint = options.convexTokenEndpoint ?? DEFAULT_CONVEX_TOKEN_ENDPOINT;
309
+ const tokens = new TokenService({ storagePrefix, graphqlUrl: `${lensApiOrigin(environment)}/graphql` });
310
+ const thirdwebClient = createThirdwebClient({ clientId: options.thirdwebClientId });
311
+ const chain = lensThirdwebChain(environment, options.lensChainRpcUrl);
312
+ const viemChain = lensViemChain(environment);
313
+ const lensEnvironment = environment === "testnet" ? testnet : mainnet;
314
+ const lensClient = PublicClient.create({
315
+ environment: lensEnvironment,
316
+ storage: typeof window !== "undefined" ? new LensTokenStorage(tokens, `${storagePrefix}custom_`) : void 0
317
+ });
318
+ function getSession() {
319
+ const idToken = tokens.getStoredTokens()?.idToken;
320
+ return idToken ? lensSessionFromIdToken(idToken) : null;
321
+ }
322
+ async function resumeSession() {
323
+ if (!await tokens.isAuthenticated()) return false;
324
+ if (!lensClient.currentSession?.isSessionClient()) await lensClient.resumeSession();
325
+ return true;
326
+ }
327
+ async function requestChallenge(opts) {
328
+ const app = evmAddress(appAddress);
329
+ const account = evmAddress(opts.account);
330
+ const signer = evmAddress(opts.signer);
331
+ const challenge = await lensClient.challenge(
332
+ opts.role === "ACCOUNT_MANAGER" ? { accountManager: { account, app, manager: signer } } : { accountOwner: { account, app, owner: signer } }
333
+ );
334
+ if (challenge.isErr()) throw challenge.error;
335
+ return challenge.value;
336
+ }
337
+ async function authenticate(challenge, signature) {
338
+ const authenticated = await lensClient.authenticate({ id: challenge.id, signature: signatureFrom(signature) });
339
+ if (authenticated.isErr()) throw authenticated.error;
340
+ tokens.storeCredentials(sessionCredentials(authenticated.value));
341
+ return authenticated.value;
342
+ }
343
+ async function logout() {
344
+ tokens.clearTokens();
345
+ const session = lensClient.currentSession;
346
+ if (session && session.isSessionClient()) await session.logout();
347
+ }
348
+ async function authFetch(input, init = {}) {
349
+ const send = async (forceRefresh) => {
350
+ const idToken = await tokens.getFreshIdToken(forceRefresh);
351
+ const headers = new Headers(init.headers);
352
+ if (idToken) headers.set("Authorization", `Bearer ${idToken}`);
353
+ return fetch(input, { ...init, headers });
354
+ };
355
+ const response = await send(false);
356
+ return response.status === 401 && getSession() ? send(true) : response;
357
+ }
358
+ async function fetchConvexToken(forceRefresh = false) {
359
+ const idToken = await tokens.getFreshIdToken(forceRefresh);
360
+ if (!idToken) return null;
361
+ try {
362
+ const res = await fetch(convexTokenEndpoint, { method: "POST", headers: { Authorization: `Bearer ${idToken}` } });
363
+ if (!res.ok) return null;
364
+ const { token } = await res.json();
365
+ return typeof token === "string" ? token : null;
366
+ } catch {
367
+ return null;
368
+ }
369
+ }
370
+ return {
371
+ environment,
372
+ appAddress,
373
+ storagePrefix,
374
+ thirdwebClient,
375
+ chain,
376
+ viemChain,
377
+ lensClient,
378
+ lensEnvironment,
379
+ tokens,
380
+ getSession,
381
+ resumeSession,
382
+ requestChallenge,
383
+ signChallenge: signLensChallenge,
384
+ authenticate,
385
+ logout,
386
+ fetch: authFetch,
387
+ fetchConvexToken
388
+ };
389
+ }
390
+
391
+ // src/core/onboarding.ts
392
+ import { PublicClient as PublicClient2, evmAddress as evmAddress2, signatureFrom as signatureFrom2, uri } from "@lens-protocol/client";
393
+ import { canCreateUsername, createAccountWithUsername, fetchAccount, fetchUsername } from "@lens-protocol/client/actions";
394
+ import { handleOperationWith } from "@lens-protocol/client/viem";
395
+ import { account as accountMetadata } from "@lens-protocol/metadata";
396
+ import { StorageClient, immutable } from "@lens-chain/storage-client";
397
+ import { getTransactionReceipt } from "viem/actions";
398
+ var OnboardingError = class extends Error {
399
+ name = "OnboardingError";
400
+ };
401
+ function createOnboardingClient(auth) {
402
+ return PublicClient2.create({ environment: auth.lensEnvironment });
403
+ }
404
+ async function requestOnboardingChallenge(auth, client, walletAddress) {
405
+ const challenge = await client.challenge({
406
+ onboardingUser: { app: evmAddress2(auth.appAddress), wallet: evmAddress2(walletAddress) }
407
+ });
408
+ if (challenge.isErr()) throw challenge.error;
409
+ return challenge.value;
410
+ }
411
+ async function authenticateOnboarding(client, challenge, signature) {
412
+ const authenticated = await client.authenticate({ id: challenge.id, signature: signatureFrom2(signature) });
413
+ if (authenticated.isErr()) throw authenticated.error;
414
+ return authenticated.value;
415
+ }
416
+ var USERNAME_PATTERN = /^[a-z0-9][a-z0-9_-]*$/;
417
+ function usernameFormatError(localName) {
418
+ if (!localName) return "Choose a username";
419
+ if (/^[-_]/.test(localName)) return "Start with a letter or a number";
420
+ if (!USERNAME_PATTERN.test(localName)) return "Use only lowercase letters, numbers, - and _";
421
+ return null;
422
+ }
423
+ async function isUsernameTaken(auth, localName) {
424
+ const result = await fetchUsername(auth.lensClient, { username: { localName } });
425
+ if (result.isErr()) throw result.error;
426
+ return result.value !== null;
427
+ }
428
+ function validationFailedMessage(failed) {
429
+ return failed.unsatisfiedRules?.required[0]?.message || failed.reason;
430
+ }
431
+ async function checkUsername(session, localName) {
432
+ const result = await canCreateUsername(session, { localName });
433
+ if (result.isErr()) throw result.error;
434
+ switch (result.value.__typename) {
435
+ case "NamespaceOperationValidationPassed":
436
+ return null;
437
+ case "UsernameTaken":
438
+ return "This username is taken";
439
+ case "NamespaceOperationValidationFailed":
440
+ return validationFailedMessage(result.value);
441
+ case "NamespaceOperationValidationUnknown":
442
+ return "This username can\u2019t be created here. Try another one.";
443
+ }
444
+ }
445
+ var storageClient = null;
446
+ async function uploadAccountMetadata(auth, profile) {
447
+ storageClient ??= StorageClient.create();
448
+ const acl = immutable(LENS_CHAIN_IDS[auth.environment]);
449
+ const picture = profile.picture ? (await storageClient.uploadFile(profile.picture, { acl })).uri : void 0;
450
+ const metadata = accountMetadata({
451
+ name: profile.name || void 0,
452
+ bio: profile.bio || void 0,
453
+ picture
454
+ });
455
+ const { uri: metadataUri } = await storageClient.uploadAsJson(metadata, { acl });
456
+ return metadataUri;
457
+ }
458
+ var ACCOUNT_POLL_ATTEMPTS = 15;
459
+ var ACCOUNT_POLL_INTERVAL_MS = 2e3;
460
+ async function createLensAccount(auth, session, wallet, request) {
461
+ const created = await createAccountWithUsername(session, {
462
+ username: { localName: request.localName },
463
+ metadataUri: uri(request.metadataUri)
464
+ });
465
+ if (created.isErr()) throw created.error;
466
+ const result = created.value;
467
+ switch (result.__typename) {
468
+ case "UsernameTaken":
469
+ throw new OnboardingError("This username is taken");
470
+ case "NamespaceOperationValidationFailed":
471
+ throw new OnboardingError(validationFailedMessage(result));
472
+ case "TransactionWillFail":
473
+ throw new OnboardingError(result.reason);
474
+ }
475
+ const walletClient = createLensWalletClient({ wallet, client: auth.thirdwebClient, chain: auth.chain, viemChain: auth.viemChain });
476
+ const sent = await handleOperationWith(walletClient)(result);
477
+ if (sent.isErr()) throw sent.error;
478
+ const hash = sent.value;
479
+ const indexed = await session.waitForTransaction(hash);
480
+ if (indexed.isErr()) {
481
+ const receipt = await getTransactionReceipt(walletClient, { hash }).catch(() => null);
482
+ if (receipt?.status === "reverted") throw indexed.error;
483
+ }
484
+ for (let attempt = 0; attempt < ACCOUNT_POLL_ATTEMPTS; attempt++) {
485
+ const fetched = await fetchAccount(session, { txHash: hash });
486
+ if (fetched.isOk() && fetched.value) return fetched.value;
487
+ await new Promise((resolve) => setTimeout(resolve, ACCOUNT_POLL_INTERVAL_MS));
488
+ }
489
+ throw new OnboardingError("Your account was created but isn\u2019t ready yet. Sign in to it again in a minute.");
490
+ }
491
+ async function signInToCreatedAccount(auth, session, accountAddress) {
492
+ const switched = await session.switchAccount({ account: evmAddress2(accountAddress) });
493
+ if (switched.isErr()) throw switched.error;
494
+ auth.tokens.storeCredentials(sessionCredentials(switched.value));
495
+ const resumed = await auth.lensClient.resumeSession();
496
+ if (resumed.isErr()) throw resumed.error;
497
+ }
498
+
499
+ export {
500
+ lensApiOrigin,
501
+ LENS_CHAIN_IDS,
502
+ decodeJwtPayload,
503
+ lensSessionFromIdToken,
504
+ LensTokenStorage,
505
+ TOKENS_CHANGED_EVENT,
506
+ TokenService,
507
+ lensThirdwebChain,
508
+ lensViemChain,
509
+ createLensWalletClient,
510
+ CHALLENGE_REFRESH_MS,
511
+ CHALLENGE_MAX_AGE_MS,
512
+ opensWalletWithDeepLink,
513
+ signLensChallenge,
514
+ createLensAuth,
515
+ OnboardingError,
516
+ createOnboardingClient,
517
+ requestOnboardingChallenge,
518
+ authenticateOnboarding,
519
+ usernameFormatError,
520
+ isUsernameTaken,
521
+ checkUsername,
522
+ uploadAccountMetadata,
523
+ createLensAccount,
524
+ signInToCreatedAccount
525
+ };
526
+ //# sourceMappingURL=chunk-2UCSL2CL.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"sources":["../src/core/constants.ts","../src/core/jwt.ts","../src/core/storage.ts","../src/core/tokens.ts","../src/core/wallet.ts","../src/core/auth.ts","../src/core/onboarding.ts"],"sourcesContent":["// Dependency-free values shared by every entry point, including the server and Convex ones.\n\nexport type LensEnvironmentName = \"mainnet\" | \"testnet\"\n\nconst LENS_API_ORIGINS: Record<LensEnvironmentName, string> = {\n mainnet: \"https://api.lens.xyz\",\n testnet: \"https://api.testnet.lens.xyz\",\n}\n\n// Lens signs its tokens as the API origin, and publishes its keys under it.\nexport function lensApiOrigin(environment: LensEnvironmentName = \"mainnet\"): string {\n return LENS_API_ORIGINS[environment]\n}\n\nexport const LENS_CHAIN_IDS: Record<LensEnvironmentName, number> = {\n mainnet: 232,\n testnet: 37111,\n}\n\n// Lens access and ID tokens are valid for 10 minutes.\nexport const LENS_TOKEN_LIFETIME_MS = 10 * 60 * 1000\n\nexport const ADDRESS_RE = /^0x[0-9a-fA-F]{40}$/\n\n// The token the server issues for Convex (server/, convex/, cli/). Both sides must agree on these.\nexport const DEFAULT_CONVEX_TOKEN_ISSUER = \"https://lens-convex-auth.local\"\nexport const DEFAULT_CONVEX_TOKEN_AUDIENCE = \"convex\"\nexport const DEFAULT_CONVEX_TOKEN_KEY_ID = \"convex-auth-1\"\nexport const DEFAULT_CONVEX_TOKEN_ENDPOINT = \"/api/convex-token\"\n","// Claims of a JWT, without verifying it (the server verifies). Null if it isn't a JWT.\nexport function decodeJwtPayload(token: string): Record<string, unknown> | null {\n try {\n const payload = token.split(\".\")[1]\n if (!payload) return null\n const base64 = payload.replace(/-/g, \"+\").replace(/_/g, \"/\")\n const binary = atob(base64.padEnd(base64.length + ((4 - (base64.length % 4)) % 4), \"=\"))\n const json = new TextDecoder().decode(Uint8Array.from(binary, (c) => c.charCodeAt(0)))\n const claims = JSON.parse(json)\n return claims && typeof claims === \"object\" ? claims : null\n } catch {\n return null\n }\n}\n\n// When a JWT expires (ms since epoch), from its `exp` claim\nexport function jwtExpiresAt(token: string): number | null {\n const exp = Number(decodeJwtPayload(token)?.exp)\n return Number.isFinite(exp) && exp > 0 ? exp * 1000 : null\n}\n\n// The Lens account a Lens ID token acts for (`act.sub`), lowercased, and the session it belongs to.\n// Null for tokens without an account (onboarding users) or that aren't JWTs.\nexport function lensSessionFromIdToken(idToken: string): { account: string; sessionId: string } | null {\n const claims = decodeJwtPayload(idToken)\n const act = claims?.act as { sub?: unknown } | null | undefined\n if (typeof act?.sub !== \"string\") return null\n return { account: act.sub.toLowerCase(), sessionId: String(claims?.sid ?? \"\") }\n}\n","import type { IStorageProvider } from \"@lens-protocol/client\"\nimport type { TokenService } from \"./tokens\"\n\n// Storage for the Lens SDK that keeps its credentials in the TokenService, so the SDK and the app\n// share one copy of the session. Everything else the SDK stores goes to localStorage under a prefix.\nexport class LensTokenStorage implements IStorageProvider {\n constructor(private tokens: TokenService, private prefix: string) {}\n\n private isCredentials(key: string) {\n return key.includes(\"credentials\") || key.includes(\"session\")\n }\n\n // The SDK only accepts a stored credentials item whose metadata is exactly\n // { version, createdAt, updatedAt }, so keep the metadata it wrote and hand it back unchanged.\n private metadataKey(key: string) {\n return `${this.prefix}${key}:metadata`\n }\n\n private credentialsMetadata(key: string) {\n const stored = localStorage.getItem(this.metadataKey(key))\n if (stored) return JSON.parse(stored)\n // Tokens stored before the metadata was kept: 3 is the SDK's current credentials schema version.\n const now = Date.now()\n return { version: 3, createdAt: now, updatedAt: now }\n }\n\n getItem(key: string): string | null {\n if (typeof window === \"undefined\") return null\n try {\n if (!this.isCredentials(key)) return localStorage.getItem(this.prefix + key)\n const tokens = this.tokens.getStoredTokens()\n if (!tokens) return null\n return JSON.stringify({\n data: { accessToken: tokens.accessToken, idToken: tokens.idToken, refreshToken: tokens.refreshToken },\n metadata: this.credentialsMetadata(key),\n })\n } catch {\n return null\n }\n }\n\n setItem(key: string, value: string): void {\n if (typeof window === \"undefined\") return\n try {\n if (!this.isCredentials(key)) return localStorage.setItem(this.prefix + key, value)\n const parsed = JSON.parse(value)\n const data = typeof parsed.data === \"string\" ? JSON.parse(parsed.data) : parsed.data\n if (data?.accessToken && data?.idToken && data?.refreshToken) {\n this.tokens.storeCredentials(data)\n localStorage.setItem(this.metadataKey(key), JSON.stringify(parsed.metadata))\n }\n } catch {}\n }\n\n removeItem(key: string): void {\n if (typeof window === \"undefined\") return\n try {\n if (!this.isCredentials(key)) return localStorage.removeItem(this.prefix + key)\n this.tokens.clearTokens()\n localStorage.removeItem(this.metadataKey(key))\n } catch {}\n }\n}\n","import { LENS_TOKEN_LIFETIME_MS } from \"./constants\"\nimport { jwtExpiresAt } from \"./jwt\"\n\nexport interface TokenData {\n accessToken: string\n idToken: string\n refreshToken: string\n expiresAt: number // when the access token expires (ms since epoch)\n}\n\nexport type LensCredentials = Pick<TokenData, \"accessToken\" | \"idToken\" | \"refreshToken\">\n\n// Dispatched on window whenever tokens are stored or cleared in this tab\nexport const TOKENS_CHANGED_EVENT = \"lens-convex-auth:tokens-changed\"\n\n// Refresh a minute before expiry for smoother UX\nconst REFRESH_BUFFER_MS = 60 * 1000\n\nconst REFRESH_MUTATION = `\n mutation Refresh($request: RefreshRequest!) {\n refresh(request: $request) {\n ... on AuthenticationTokens {\n accessToken\n idToken\n refreshToken\n }\n ... on ForbiddenError {\n reason\n }\n }\n }\n`\n\nfunction notifyTokensChanged() {\n try {\n window.dispatchEvent(new Event(TOKENS_CHANGED_EVENT))\n } catch {}\n}\n\n// Keeps the Lens session's tokens in localStorage, the single place every part of the app (the Lens\n// SDK, Convex, API calls) reads them from, and refreshes them.\nexport class TokenService {\n readonly storageKeys: { accessToken: string; idToken: string; refreshToken: string; expiresAt: string }\n private refreshPromise: Promise<TokenData | null> | null = null\n\n constructor(private options: { storagePrefix: string; graphqlUrl: string }) {\n const p = options.storagePrefix\n this.storageKeys = {\n accessToken: `${p}access_token`,\n idToken: `${p}id_token`,\n refreshToken: `${p}refresh_token`,\n expiresAt: `${p}token_expires_at`,\n }\n }\n\n storeTokens(tokens: TokenData): void {\n if (typeof window === \"undefined\") return\n try {\n localStorage.setItem(this.storageKeys.accessToken, tokens.accessToken)\n localStorage.setItem(this.storageKeys.idToken, tokens.idToken)\n localStorage.setItem(this.storageKeys.refreshToken, tokens.refreshToken)\n localStorage.setItem(this.storageKeys.expiresAt, tokens.expiresAt.toString())\n } catch {}\n notifyTokensChanged()\n }\n\n storeCredentials(credentials: LensCredentials): void {\n this.storeTokens({ ...credentials, expiresAt: Date.now() + LENS_TOKEN_LIFETIME_MS })\n }\n\n getStoredTokens(): TokenData | null {\n if (typeof window === \"undefined\") return null\n try {\n const accessToken = localStorage.getItem(this.storageKeys.accessToken)\n const idToken = localStorage.getItem(this.storageKeys.idToken)\n const refreshToken = localStorage.getItem(this.storageKeys.refreshToken)\n const storedExpiresAt = localStorage.getItem(this.storageKeys.expiresAt)\n if (!accessToken || !idToken || !refreshToken) return null\n // The access token's own expiry. The stored value is only an estimate (store time + 10 min),\n // which marks tokens read back from an old session as fresh long after they expired.\n const expiresAt = jwtExpiresAt(accessToken) ?? (storedExpiresAt ? parseInt(storedExpiresAt, 10) : 0)\n return { accessToken, idToken, refreshToken, expiresAt }\n } catch {\n return null\n }\n }\n\n clearTokens(): void {\n if (typeof window === \"undefined\") return\n try {\n for (const key of Object.values(this.storageKeys)) localStorage.removeItem(key)\n } catch {}\n notifyTokensChanged()\n }\n\n // Current access token, refreshed first if it's about to expire\n async getValidAccessToken(): Promise<string | null> {\n const tokens = this.getStoredTokens()\n if (!tokens) return null\n if (tokens.expiresAt > Date.now() + REFRESH_BUFFER_MS) return tokens.accessToken\n return (await this.refreshTokens())?.accessToken ?? null\n }\n\n // ID token for authenticating to your backend (Convex, API routes), refreshed when it's about to\n // expire (by the token's own `exp` claim). `forceRefresh` is for when the backend rejected it.\n async getFreshIdToken(forceRefresh = false): Promise<string | null> {\n const tokens = this.getStoredTokens()\n if (!tokens) return null\n const expiresAt = jwtExpiresAt(tokens.idToken) ?? 0\n const fresh = expiresAt > Date.now() + REFRESH_BUFFER_MS\n // A forced refresh right after another tab or the background refresher got new tokens reuses them\n const justIssued = expiresAt > Date.now() + 2 * REFRESH_BUFFER_MS\n if (fresh && (!forceRefresh || justIssued)) return tokens.idToken\n return (await this.refreshTokens())?.idToken ?? null\n }\n\n async isAuthenticated(): Promise<boolean> {\n return !!(await this.getValidAccessToken())\n }\n\n // Concurrent calls share one request. Clears the tokens when the session can't be refreshed.\n refreshTokens(): Promise<TokenData | null> {\n this.refreshPromise ??= this.performRefresh().finally(() => {\n this.refreshPromise = null\n })\n return this.refreshPromise\n }\n\n private async performRefresh(): Promise<TokenData | null> {\n const refreshToken = this.getStoredTokens()?.refreshToken\n if (!refreshToken) {\n this.clearTokens()\n return null\n }\n try {\n // Resuming the Lens session only reads these same tokens back, so ask the API for new ones.\n // (Each Lens SDK session keeps its own copy of the tokens and refreshes that copy itself.)\n const response = await fetch(this.options.graphqlUrl, {\n method: \"POST\",\n headers: { \"Content-Type\": \"application/json\" },\n body: JSON.stringify({ query: REFRESH_MUTATION, variables: { request: { refreshToken } } }),\n })\n const data = await response.json()\n const result = data?.data?.refresh\n if (data.errors || !result || result.reason) throw new Error(result?.reason ?? \"Refresh failed\")\n const tokens: TokenData = {\n accessToken: result.accessToken,\n idToken: result.idToken,\n refreshToken: result.refreshToken,\n expiresAt: Date.now() + LENS_TOKEN_LIFETIME_MS,\n }\n this.storeTokens(tokens)\n return tokens\n } catch {\n this.clearTokens()\n return null\n }\n }\n}\n","import { createWalletClient, custom, defineChain as defineViemChain, getAddress, hexToBigInt, hexToNumber, type Account as ViemAccount, type Chain as ViemChain, type Hex, type Transport, type WalletClient } from \"viem\"\nimport { lens as viemLens, lensTestnet as viemLensTestnet } from \"viem/chains\"\nimport { chainConfig } from \"viem/zksync\"\nimport { defineChain, type Chain } from \"thirdweb/chains\"\nimport { EIP1193, type Wallet } from \"thirdweb/wallets\"\nimport type { ThirdwebClient } from \"thirdweb\"\nimport { LENS_CHAIN_IDS, type LensEnvironmentName } from \"./constants\"\n\n// Lens Chain for thirdweb. Without an RPC URL thirdweb uses its own RPC for the chain.\nexport function lensThirdwebChain(environment: LensEnvironmentName, rpcUrl?: string): Chain {\n const testnet = environment === \"testnet\"\n return defineChain({\n id: LENS_CHAIN_IDS[environment],\n name: testnet ? \"Lens Chain Testnet\" : \"Lens Chain\",\n nativeCurrency: testnet\n ? { name: \"GRASS\", symbol: \"GRASS\", decimals: 18 }\n : { name: \"GHO\", symbol: \"GHO\", decimals: 18 },\n ...(rpcUrl ? { rpc: rpcUrl } : {}),\n ...(testnet ? { testnet: true as const } : {}),\n })\n}\n\n// Lens Chain with the zkSync config (same as `chains.mainnet` from @lens-chain/sdk/viem), so viem can\n// sign the sponsored EIP-712 transactions the Lens API returns. Typed as a plain `Chain` because\n// `handleOperationWith` takes a plain viem `WalletClient`.\nexport function lensViemChain(environment: LensEnvironmentName): ViemChain {\n return defineViemChain({ ...(environment === \"testnet\" ? viemLensTestnet : viemLens), ...chainConfig })\n}\n\n// A viem wallet client for the connected thirdweb wallet, as `handleOperationWith` expects:\n// hoisted account and a Lens chain. Works for every thirdweb wallet, not only injected ones.\nexport function createLensWalletClient(opts: {\n wallet: Wallet\n client: ThirdwebClient\n chain: Chain\n viemChain: ViemChain\n}): WalletClient<Transport, ViemChain, ViemAccount> {\n const account = opts.wallet.getAccount()\n if (!account) throw new Error(\"Connect your wallet\")\n const provider = EIP1193.toProvider({ wallet: opts.wallet, chain: opts.chain, client: opts.client })\n return createWalletClient({\n account: getAddress(account.address),\n chain: opts.viemChain,\n transport: custom({\n request: ({ method, params }) => {\n if (method === \"eth_sendTransaction\") {\n // viem sends hex-encoded fields (e.g. `type: \"0x2\"`) that thirdweb's local signers reject.\n // thirdweb re-estimates gas and fees for Lens Chain anyway, so pass only what it needs.\n const [tx] = params as [{ to: Hex; data?: Hex; value?: Hex; nonce?: Hex }]\n return provider.request({\n method,\n params: [{\n to: tx.to,\n data: tx.data,\n value: tx.value ? hexToBigInt(tx.value) : undefined,\n nonce: tx.nonce ? hexToNumber(tx.nonce) : undefined,\n }],\n })\n }\n return provider.request({ method, params })\n },\n }),\n })\n}\n","import { PublicClient, evmAddress, mainnet, signatureFrom, testnet, type SessionClient, type UUID } from \"@lens-protocol/client\"\nimport { createThirdwebClient, type ThirdwebClient } from \"thirdweb\"\nimport type { Chain } from \"thirdweb/chains\"\nimport type { Chain as ViemChain } from \"viem\"\nimport { ADDRESS_RE, DEFAULT_CONVEX_TOKEN_ENDPOINT, lensApiOrigin, type LensEnvironmentName } from \"./constants\"\nimport { lensSessionFromIdToken } from \"./jwt\"\nimport { LensTokenStorage } from \"./storage\"\nimport { TokenService, type LensCredentials } from \"./tokens\"\nimport { lensThirdwebChain, lensViemChain } from \"./wallet\"\n\nexport type LensAuthOptions = {\n /** thirdweb client ID (https://thirdweb.com/dashboard) */\n thirdwebClientId: string\n /** Your Lens app address (https://developer.lens.xyz/apps). Tokens are issued for this app. */\n lensAppAddress: string\n /** Defaults to \"mainnet\" */\n environment?: LensEnvironmentName\n /** Lens Chain RPC for thirdweb. Defaults to thirdweb's RPC. */\n lensChainRpcUrl?: string\n /** Prefix of the localStorage keys the session is stored under. Defaults to \"lens_\". */\n storagePrefix?: string\n /** Route that exchanges a Lens ID token for a Convex token. Defaults to \"/api/convex-token\". */\n convexTokenEndpoint?: string\n}\n\nexport type LensLoginRole = \"ACCOUNT_OWNER\" | \"ACCOUNT_MANAGER\"\n\nexport type LensChallenge = { id: UUID; text: string }\n\nexport type MessageSigner = {\n signMessage: (args: { message: string }) => Promise<string>\n}\n\n// The signed-in Lens account (lowercased address) and its session, read from the stored ID token\nexport type LensSessionInfo = { account: string; sessionId: string }\n\nexport type LensAuth = ReturnType<typeof createLensAuth>\n\n// Challenges are fetched ahead of time so a tap can sign right away: how often they're replaced, and how\n// old one can be to still be used.\nexport const CHALLENGE_REFRESH_MS = 2 * 60 * 1000\nexport const CHALLENGE_MAX_AGE_MS = 4 * 60 * 1000\n\n// On phones and tablets thirdweb opens the wallet app with a deep link to sign (same check as its\n// internal isMobile), and that deep link only works right after a tap.\nexport function opensWalletWithDeepLink() {\n if (typeof navigator === \"undefined\") return false\n const ua = navigator.userAgent\n return /iPhone|iPad|iPod|Android/i.test(ua) || (/Macintosh/.test(ua) && navigator.maxTouchPoints > 1)\n}\n\n// Asks the wallet to sign synchronously (no awaits before it), so call it directly from a click handler.\nexport function signLensChallenge(challenge: LensChallenge, signer: MessageSigner): Promise<string> {\n return signer.signMessage({ message: challenge.text })\n}\n\n// A Lens SDK session's tokens\nexport function sessionCredentials(session: SessionClient): LensCredentials {\n const credentials = session.getCredentials()\n if (credentials.isErr()) throw credentials.error\n if (!credentials.value) throw new Error(\"The Lens session has no credentials\")\n return credentials.value\n}\n\n// Create once per app (at module level) and pass to <LensAuthProvider>.\nexport function createLensAuth(options: LensAuthOptions) {\n if (!options.thirdwebClientId) throw new Error(\"lens-convex-auth: thirdwebClientId is required\")\n if (!ADDRESS_RE.test(options.lensAppAddress ?? \"\")) {\n throw new Error(\"lens-convex-auth: lensAppAddress must be your Lens app address (0x…)\")\n }\n\n const environment: LensEnvironmentName = options.environment ?? \"mainnet\"\n const storagePrefix = options.storagePrefix ?? \"lens_\"\n const appAddress = options.lensAppAddress\n const convexTokenEndpoint = options.convexTokenEndpoint ?? DEFAULT_CONVEX_TOKEN_ENDPOINT\n\n const tokens = new TokenService({ storagePrefix, graphqlUrl: `${lensApiOrigin(environment)}/graphql` })\n const thirdwebClient: ThirdwebClient = createThirdwebClient({ clientId: options.thirdwebClientId })\n const chain: Chain = lensThirdwebChain(environment, options.lensChainRpcUrl)\n const viemChain: ViemChain = lensViemChain(environment)\n const lensEnvironment = environment === \"testnet\" ? testnet : mainnet\n const lensClient = PublicClient.create({\n environment: lensEnvironment,\n storage: typeof window !== \"undefined\" ? new LensTokenStorage(tokens, `${storagePrefix}custom_`) : undefined,\n })\n\n // The signed-in account, or null when signed out\n function getSession(): LensSessionInfo | null {\n const idToken = tokens.getStoredTokens()?.idToken\n return idToken ? lensSessionFromIdToken(idToken) : null\n }\n\n // True when there's a valid session, refreshing its tokens first if needed (a session that can't be\n // refreshed is cleared). Also resumes it in the Lens client, so Lens SDK calls and hooks act as the\n // signed-in account.\n async function resumeSession(): Promise<boolean> {\n if (!(await tokens.isAuthenticated())) return false\n if (!lensClient.currentSession?.isSessionClient()) await lensClient.resumeSession()\n return true\n }\n\n // Logging in is split in two (challenge, then sign + authenticate) instead of using `lensClient.login`,\n // so the signature can be requested straight from a tap. On mobile, WalletConnect opens the wallet app\n // with a deep link when asked to sign, and iOS only allows that right after a user gesture: after the\n // challenge round trip the link is blocked and the wallet never shows the request.\n async function requestChallenge(opts: { role: LensLoginRole; account: string; signer: string }): Promise<LensChallenge> {\n const app = evmAddress(appAddress)\n const account = evmAddress(opts.account)\n const signer = evmAddress(opts.signer)\n const challenge = await lensClient.challenge(\n opts.role === \"ACCOUNT_MANAGER\"\n ? { accountManager: { account, app, manager: signer } }\n : { accountOwner: { account, app, owner: signer } },\n )\n if (challenge.isErr()) throw challenge.error\n return challenge.value\n }\n\n async function authenticate(challenge: LensChallenge, signature: string): Promise<SessionClient> {\n const authenticated = await lensClient.authenticate({ id: challenge.id, signature: signatureFrom(signature) })\n if (authenticated.isErr()) throw authenticated.error\n tokens.storeCredentials(sessionCredentials(authenticated.value))\n return authenticated.value\n }\n\n async function logout(): Promise<void> {\n tokens.clearTokens()\n // PublicClient has no logout; logout exists on SessionClient\n const session = lensClient.currentSession\n if (session && session.isSessionClient()) await session.logout()\n }\n\n // fetch() with the Lens ID token as `Authorization: Bearer`, retried once with a refreshed token on 401.\n // Verify it on the server with `getLensSession` from \"lens-convex-auth/server\".\n async function authFetch(input: RequestInfo | URL, init: RequestInit = {}): Promise<Response> {\n const send = async (forceRefresh: boolean) => {\n const idToken = await tokens.getFreshIdToken(forceRefresh)\n const headers = new Headers(init.headers)\n if (idToken) headers.set(\"Authorization\", `Bearer ${idToken}`)\n return fetch(input, { ...init, headers })\n }\n const response = await send(false)\n return response.status === 401 && getSession() ? send(true) : response\n }\n\n // Convex can't verify Lens ID tokens itself (they have no `kid` header), so the server verifies the\n // Lens ID token and issues a Convex token for the same account (see \"lens-convex-auth/server\").\n async function fetchConvexToken(forceRefresh = false): Promise<string | null> {\n const idToken = await tokens.getFreshIdToken(forceRefresh)\n if (!idToken) return null\n try {\n const res = await fetch(convexTokenEndpoint, { method: \"POST\", headers: { Authorization: `Bearer ${idToken}` } })\n if (!res.ok) return null\n const { token } = await res.json()\n return typeof token === \"string\" ? token : null\n } catch {\n return null\n }\n }\n\n return {\n environment,\n appAddress,\n storagePrefix,\n thirdwebClient,\n chain,\n viemChain,\n lensClient,\n lensEnvironment,\n tokens,\n getSession,\n resumeSession,\n requestChallenge,\n signChallenge: signLensChallenge,\n authenticate,\n logout,\n fetch: authFetch,\n fetchConvexToken,\n }\n}\n","import { PublicClient, evmAddress, signatureFrom, uri, type Account, type SessionClient } from \"@lens-protocol/client\"\nimport { canCreateUsername, createAccountWithUsername, fetchAccount, fetchUsername } from \"@lens-protocol/client/actions\"\nimport { handleOperationWith } from \"@lens-protocol/client/viem\"\nimport { account as accountMetadata } from \"@lens-protocol/metadata\"\nimport { StorageClient, immutable } from \"@lens-chain/storage-client\"\nimport { getTransactionReceipt } from \"viem/actions\"\nimport type { Wallet } from \"thirdweb/wallets\"\nimport type { LensAuth, LensChallenge } from \"./auth\"\nimport { sessionCredentials } from \"./auth\"\nimport { LENS_CHAIN_IDS } from \"./constants\"\nimport { createLensWalletClient } from \"./wallet\"\n\n// An error whose message can be shown to the user as is.\nexport class OnboardingError extends Error {\n name = \"OnboardingError\"\n}\n\n// Creating an account takes a session as an onboarding user (a wallet signed in without a Lens Account).\n// It runs on its own client, whose storage is in memory, so that session never reaches the app's token\n// storage: until the account exists and is signed in to, the app must not treat the wallet as signed in.\nexport function createOnboardingClient(auth: LensAuth) {\n return PublicClient.create({ environment: auth.lensEnvironment })\n}\n\nexport async function requestOnboardingChallenge(auth: LensAuth, client: PublicClient, walletAddress: string): Promise<LensChallenge> {\n const challenge = await client.challenge({\n onboardingUser: { app: evmAddress(auth.appAddress), wallet: evmAddress(walletAddress) },\n })\n if (challenge.isErr()) throw challenge.error\n return challenge.value\n}\n\nexport async function authenticateOnboarding(client: PublicClient, challenge: LensChallenge, signature: string): Promise<SessionClient> {\n const authenticated = await client.authenticate({ id: challenge.id, signature: signatureFrom(signature) })\n if (authenticated.isErr()) throw authenticated.error\n return authenticated.value\n}\n\n// The global Lens namespace takes lowercase letters, numbers, \"-\" and \"_\", and can't start with \"-\" or \"_\".\n// Its other rules (length, reserved names, price) are checked by the Lens API in checkUsername.\nconst USERNAME_PATTERN = /^[a-z0-9][a-z0-9_-]*$/\n\nexport function usernameFormatError(localName: string): string | null {\n if (!localName) return \"Choose a username\"\n if (/^[-_]/.test(localName)) return \"Start with a letter or a number\"\n if (!USERNAME_PATTERN.test(localName)) return \"Use only lowercase letters, numbers, - and _\"\n return null\n}\n\n// Needs no session, so it can run while the user types.\nexport async function isUsernameTaken(auth: LensAuth, localName: string): Promise<boolean> {\n const result = await fetchUsername(auth.lensClient, { username: { localName } })\n if (result.isErr()) throw result.error\n return result.value !== null\n}\n\ntype NamespaceValidationFailed = {\n reason: string\n unsatisfiedRules: { required: { message: string }[] } | null\n}\n\nfunction validationFailedMessage(failed: NamespaceValidationFailed) {\n return failed.unsatisfiedRules?.required[0]?.message || failed.reason\n}\n\n// Returns why the username can't be created, or null if it can.\nexport async function checkUsername(session: SessionClient, localName: string): Promise<string | null> {\n const result = await canCreateUsername(session, { localName })\n if (result.isErr()) throw result.error\n switch (result.value.__typename) {\n case \"NamespaceOperationValidationPassed\":\n return null\n case \"UsernameTaken\":\n return \"This username is taken\"\n case \"NamespaceOperationValidationFailed\":\n return validationFailedMessage(result.value)\n case \"NamespaceOperationValidationUnknown\":\n return \"This username can’t be created here. Try another one.\"\n }\n}\n\nlet storageClient: StorageClient | null = null\n\nexport type AccountProfile = {\n name?: string\n bio?: string\n picture?: File | null\n}\n\n// Uploads the account metadata (and its picture) to Grove, and returns the metadata URI.\nexport async function uploadAccountMetadata(auth: LensAuth, profile: AccountProfile): Promise<string> {\n storageClient ??= StorageClient.create()\n const acl = immutable(LENS_CHAIN_IDS[auth.environment])\n const picture = profile.picture ? (await storageClient.uploadFile(profile.picture, { acl })).uri : undefined\n const metadata = accountMetadata({\n name: profile.name || undefined,\n bio: profile.bio || undefined,\n picture,\n })\n const { uri: metadataUri } = await storageClient.uploadAsJson(metadata, { acl })\n return metadataUri\n}\n\n// How long to wait for a new account to be listed once its transaction is indexed\nconst ACCOUNT_POLL_ATTEMPTS = 15\nconst ACCOUNT_POLL_INTERVAL_MS = 2000\n\n// Creates an account owned by the onboarding user's wallet. Most apps sponsor it; otherwise the wallet\n// is asked to send the transaction.\nexport async function createLensAccount(\n auth: LensAuth,\n session: SessionClient,\n wallet: Wallet,\n request: { localName: string; metadataUri: string },\n): Promise<Account> {\n const created = await createAccountWithUsername(session, {\n username: { localName: request.localName },\n metadataUri: uri(request.metadataUri),\n })\n if (created.isErr()) throw created.error\n const result = created.value\n switch (result.__typename) {\n case \"UsernameTaken\":\n throw new OnboardingError(\"This username is taken\")\n case \"NamespaceOperationValidationFailed\":\n throw new OnboardingError(validationFailedMessage(result))\n case \"TransactionWillFail\":\n throw new OnboardingError(result.reason)\n }\n\n const walletClient = createLensWalletClient({ wallet, client: auth.thirdwebClient, chain: auth.chain, viemChain: auth.viemChain })\n const sent = await handleOperationWith(walletClient)(result)\n if (sent.isErr()) throw sent.error\n const hash = sent.value\n\n const indexed = await session.waitForTransaction(hash)\n if (indexed.isErr()) {\n // The Lens API stops waiting for indexing after 10s on mainnet, so the receipt decides whether\n // the transaction failed. If it can't be read either, the account lookup below still settles it.\n const receipt = await getTransactionReceipt(walletClient, { hash }).catch(() => null)\n if (receipt?.status === \"reverted\") throw indexed.error\n }\n\n for (let attempt = 0; attempt < ACCOUNT_POLL_ATTEMPTS; attempt++) {\n const fetched = await fetchAccount(session, { txHash: hash })\n if (fetched.isOk() && fetched.value) return fetched.value\n await new Promise((resolve) => setTimeout(resolve, ACCOUNT_POLL_INTERVAL_MS))\n }\n throw new OnboardingError(\"Your account was created but isn’t ready yet. Sign in to it again in a minute.\")\n}\n\n// Signs the app in to the new account without another signature: the onboarding session switches to it,\n// and its tokens are handed to the app's Lens client, like a sign-in from the account list.\nexport async function signInToCreatedAccount(auth: LensAuth, session: SessionClient, accountAddress: string): Promise<void> {\n const switched = await session.switchAccount({ account: evmAddress(accountAddress) })\n if (switched.isErr()) throw switched.error\n auth.tokens.storeCredentials(sessionCredentials(switched.value))\n const resumed = await auth.lensClient.resumeSession()\n if (resumed.isErr()) throw resumed.error\n}\n"],"mappings":"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","names":["testnet","PublicClient","evmAddress","signatureFrom","PublicClient","evmAddress","signatureFrom"]}
@@ -0,0 +1,22 @@
1
+ // src/core/constants.ts
2
+ var LENS_API_ORIGINS = {
3
+ mainnet: "https://api.lens.xyz",
4
+ testnet: "https://api.testnet.lens.xyz"
5
+ };
6
+ function lensApiOrigin(environment = "mainnet") {
7
+ return LENS_API_ORIGINS[environment];
8
+ }
9
+ var LENS_TOKEN_LIFETIME_MS = 10 * 60 * 1e3;
10
+ var ADDRESS_RE = /^0x[0-9a-fA-F]{40}$/;
11
+ var DEFAULT_CONVEX_TOKEN_ISSUER = "https://lens-convex-auth.local";
12
+ var DEFAULT_CONVEX_TOKEN_AUDIENCE = "convex";
13
+ var DEFAULT_CONVEX_TOKEN_KEY_ID = "convex-auth-1";
14
+
15
+ export {
16
+ lensApiOrigin,
17
+ ADDRESS_RE,
18
+ DEFAULT_CONVEX_TOKEN_ISSUER,
19
+ DEFAULT_CONVEX_TOKEN_AUDIENCE,
20
+ DEFAULT_CONVEX_TOKEN_KEY_ID
21
+ };
22
+ //# sourceMappingURL=chunk-CDAKZCYM.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"sources":["../src/core/constants.ts"],"sourcesContent":["// Dependency-free values shared by every entry point, including the server and Convex ones.\n\nexport type LensEnvironmentName = \"mainnet\" | \"testnet\"\n\nconst LENS_API_ORIGINS: Record<LensEnvironmentName, string> = {\n mainnet: \"https://api.lens.xyz\",\n testnet: \"https://api.testnet.lens.xyz\",\n}\n\n// Lens signs its tokens as the API origin, and publishes its keys under it.\nexport function lensApiOrigin(environment: LensEnvironmentName = \"mainnet\"): string {\n return LENS_API_ORIGINS[environment]\n}\n\nexport const LENS_CHAIN_IDS: Record<LensEnvironmentName, number> = {\n mainnet: 232,\n testnet: 37111,\n}\n\n// Lens access and ID tokens are valid for 10 minutes.\nexport const LENS_TOKEN_LIFETIME_MS = 10 * 60 * 1000\n\nexport const ADDRESS_RE = /^0x[0-9a-fA-F]{40}$/\n\n// The token the server issues for Convex (server/, convex/, cli/). Both sides must agree on these.\nexport const DEFAULT_CONVEX_TOKEN_ISSUER = \"https://lens-convex-auth.local\"\nexport const DEFAULT_CONVEX_TOKEN_AUDIENCE = \"convex\"\nexport const DEFAULT_CONVEX_TOKEN_KEY_ID = \"convex-auth-1\"\nexport const DEFAULT_CONVEX_TOKEN_ENDPOINT = \"/api/convex-token\"\n"],"mappings":";AAIA,IAAM,mBAAwD;AAAA,EAC5D,SAAS;AAAA,EACT,SAAS;AACX;AAGO,SAAS,cAAc,cAAmC,WAAmB;AAClF,SAAO,iBAAiB,WAAW;AACrC;AAQO,IAAM,yBAAyB,KAAK,KAAK;AAEzC,IAAM,aAAa;AAGnB,IAAM,8BAA8B;AACpC,IAAM,gCAAgC;AACtC,IAAM,8BAA8B;","names":[]}