Repository: lens-protocol/lens-sdk Branch: main Commit: 342abd5efb3b Files: 423 Total size: 1.9 MB Directory structure: gitextract_d8sflke8/ ├── .changeset/ │ ├── README.md │ ├── config.json │ ├── giant-buckets-melt.md │ ├── nice-baboons-protect.md │ └── pre.json ├── .editorconfig ├── .github/ │ ├── actions/ │ │ ├── setup/ │ │ │ └── action.yml │ │ └── tests/ │ │ └── action.yml │ └── workflows/ │ ├── dependency-review.yml │ ├── pull-request.yml │ ├── snapshot.yml │ ├── trigger-tests.yml │ └── verify.yml ├── .gitignore ├── .npmrc ├── .nvmrc ├── .prettierignore ├── .vscode/ │ └── settings.json ├── LICENSE ├── README.md ├── biome.json ├── examples/ │ ├── create-app/ │ │ ├── README.md │ │ ├── index.html │ │ ├── index.ts │ │ ├── package.json │ │ └── tsconfig.json │ ├── custom-fragments/ │ │ ├── README.md │ │ ├── index.html │ │ ├── index.ts │ │ ├── package.json │ │ └── tsconfig.json │ ├── nextjs-client/ │ │ ├── .gitignore │ │ ├── .stackblitzrc │ │ ├── README.md │ │ ├── next.config.ts │ │ ├── package.json │ │ ├── src/ │ │ │ └── app/ │ │ │ ├── Web3Providers.tsx │ │ │ ├── client.ts │ │ │ ├── globals.css │ │ │ ├── layout.tsx │ │ │ └── page.tsx │ │ └── tsconfig.json │ ├── react-follow/ │ │ ├── README.md │ │ ├── index.html │ │ ├── package.json │ │ ├── src/ │ │ │ ├── AccountToFollow.tsx │ │ │ ├── App.tsx │ │ │ ├── FollowButton.tsx │ │ │ ├── Web3Providers.tsx │ │ │ ├── client.ts │ │ │ ├── config.ts │ │ │ ├── main.tsx │ │ │ ├── vite-env.d.ts │ │ │ └── wallet.ts │ │ ├── tsconfig.json │ │ └── vite.config.ts │ ├── react-login/ │ │ ├── README.md │ │ ├── index.html │ │ ├── package.json │ │ ├── src/ │ │ │ ├── App.tsx │ │ │ ├── LoginForm.tsx │ │ │ ├── LogoutButton.tsx │ │ │ ├── MyAccount.tsx │ │ │ ├── Web3Providers.tsx │ │ │ ├── client.ts │ │ │ ├── config.ts │ │ │ ├── main.tsx │ │ │ └── vite-env.d.ts │ │ ├── tsconfig.json │ │ └── vite.config.ts │ ├── react-post/ │ │ ├── README.md │ │ ├── index.html │ │ ├── package.json │ │ ├── src/ │ │ │ ├── App.tsx │ │ │ ├── client.ts │ │ │ ├── config.ts │ │ │ ├── main.tsx │ │ │ ├── vite-env.d.ts │ │ │ └── wallet.ts │ │ ├── tsconfig.json │ │ └── vite.config.ts │ ├── react-post-action/ │ │ ├── README.md │ │ ├── index.html │ │ ├── package.json │ │ ├── src/ │ │ │ ├── App.tsx │ │ │ ├── client.ts │ │ │ ├── config.ts │ │ │ ├── main.tsx │ │ │ ├── vite-env.d.ts │ │ │ └── wallet.ts │ │ ├── tsconfig.json │ │ └── vite.config.ts │ ├── sponsored-tx/ │ │ ├── .stackblitzrc │ │ ├── README.md │ │ ├── index.ts │ │ ├── package.json │ │ └── tsconfig.json │ ├── sponsored-tx-poc/ │ │ ├── README.md │ │ ├── index.html │ │ ├── index.ts │ │ ├── package.json │ │ └── tsconfig.json │ ├── thirdweb-onramp/ │ │ ├── README.md │ │ ├── index.html │ │ ├── package.json │ │ ├── src/ │ │ │ ├── App.tsx │ │ │ └── main.tsx │ │ ├── tsconfig.json │ │ └── vite.config.ts │ └── user-onboarding/ │ ├── README.md │ ├── index.html │ ├── index.ts │ ├── package.json │ └── tsconfig.json ├── jest-extended.d.ts ├── package.json ├── packages/ │ ├── client/ │ │ ├── CHANGELOG.md │ │ ├── README.md │ │ ├── package.json │ │ ├── src/ │ │ │ ├── AuthenticatedUser.ts │ │ │ ├── actions/ │ │ │ │ ├── account.test.ts │ │ │ │ ├── account.ts │ │ │ │ ├── accountManager.test.ts │ │ │ │ ├── accountManager.ts │ │ │ │ ├── actions.ts │ │ │ │ ├── admins.ts │ │ │ │ ├── app.ts │ │ │ │ ├── authentication.ts │ │ │ │ ├── feed.ts │ │ │ │ ├── follow.ts │ │ │ │ ├── frames.ts │ │ │ │ ├── funds.e2e.ts │ │ │ │ ├── funds.ts │ │ │ │ ├── graph.ts │ │ │ │ ├── group.e2e.ts │ │ │ │ ├── group.ts │ │ │ │ ├── helpers.ts │ │ │ │ ├── index.ts │ │ │ │ ├── metadata.test.ts │ │ │ │ ├── metadata.ts │ │ │ │ ├── misc.ts │ │ │ │ ├── ml.e2e.ts │ │ │ │ ├── ml.ts │ │ │ │ ├── namespace.ts │ │ │ │ ├── notifications.test.ts │ │ │ │ ├── notifications.ts │ │ │ │ ├── onboarding.e2e.ts │ │ │ │ ├── post.test.ts │ │ │ │ ├── post.ts │ │ │ │ ├── posts.test.ts │ │ │ │ ├── posts.ts │ │ │ │ ├── sns.ts │ │ │ │ ├── sponsorship.ts │ │ │ │ ├── timeline.ts │ │ │ │ ├── tipping.e2e.ts │ │ │ │ ├── transactions.ts │ │ │ │ ├── transfer.ts │ │ │ │ └── username.ts │ │ │ ├── authorization.ts │ │ │ ├── batch.ts │ │ │ ├── cache.ts │ │ │ ├── clients.test.ts │ │ │ ├── clients.ts │ │ │ ├── config.ts │ │ │ ├── context.ts │ │ │ ├── crossRegion.e2e.ts │ │ │ ├── errors.ts │ │ │ ├── ethers/ │ │ │ │ ├── __snapshots__/ │ │ │ │ │ └── encoding.test.ts.snap │ │ │ │ ├── encoding.test.ts │ │ │ │ ├── encoding.ts │ │ │ │ ├── index.ts │ │ │ │ ├── signer.test.ts │ │ │ │ ├── signer.ts │ │ │ │ ├── sponsorship.test.ts │ │ │ │ └── sponsorship.ts │ │ │ ├── fragments.test.ts │ │ │ ├── fragments.ts │ │ │ ├── index.ts │ │ │ ├── logger.ts │ │ │ ├── sponsorship.ts │ │ │ ├── test-utils.ts │ │ │ ├── tokens.ts │ │ │ ├── types.ts │ │ │ ├── utils.ts │ │ │ └── viem/ │ │ │ ├── __snapshots__/ │ │ │ │ └── encoding.test.ts.snap │ │ │ ├── authorization.test.ts │ │ │ ├── authorization.ts │ │ │ ├── encoding.test.ts │ │ │ ├── encoding.ts │ │ │ ├── index.ts │ │ │ ├── signer.test.ts │ │ │ ├── signer.ts │ │ │ ├── sponsorship.test.ts │ │ │ ├── sponsorship.ts │ │ │ └── types.ts │ │ ├── tsconfig.build.json │ │ ├── tsconfig.json │ │ └── tsup.config.ts │ ├── env/ │ │ ├── CHANGELOG.md │ │ ├── README.md │ │ ├── package.json │ │ ├── src/ │ │ │ └── index.ts │ │ ├── tsconfig.build.json │ │ ├── tsconfig.json │ │ └── tsup.config.ts │ ├── graphql/ │ │ ├── .gitignore │ │ ├── CHANGELOG.md │ │ ├── README.md │ │ ├── package.json │ │ ├── schema.d.ts │ │ ├── schema.graphql │ │ ├── scripts/ │ │ │ └── fetch-schema.ts │ │ ├── src/ │ │ │ ├── accounts/ │ │ │ │ ├── account.ts │ │ │ │ ├── index.ts │ │ │ │ ├── managers.ts │ │ │ │ └── signless.ts │ │ │ ├── actions.ts │ │ │ ├── admins.ts │ │ │ ├── app.ts │ │ │ ├── authentication.ts │ │ │ ├── common.ts │ │ │ ├── enums.ts │ │ │ ├── feed.ts │ │ │ ├── follow.ts │ │ │ ├── fragments/ │ │ │ │ ├── account.ts │ │ │ │ ├── common.ts │ │ │ │ ├── index.ts │ │ │ │ ├── media.ts │ │ │ │ ├── metadata.ts │ │ │ │ ├── pagination.ts │ │ │ │ ├── post.ts │ │ │ │ ├── primitives.ts │ │ │ │ ├── transactions.ts │ │ │ │ └── username.ts │ │ │ ├── frames.ts │ │ │ ├── funds.ts │ │ │ ├── graph.ts │ │ │ ├── graphql-env.d.ts │ │ │ ├── graphql.ts │ │ │ ├── group.ts │ │ │ ├── index.ts │ │ │ ├── metadata.ts │ │ │ ├── misc.ts │ │ │ ├── ml.ts │ │ │ ├── namespace.ts │ │ │ ├── notifications.ts │ │ │ ├── post.ts │ │ │ ├── refinements.ts │ │ │ ├── scalars.ts │ │ │ ├── schema.json │ │ │ ├── schema.ts │ │ │ ├── sns.ts │ │ │ ├── sponsorship.ts │ │ │ ├── test-utils.ts │ │ │ ├── timeline.ts │ │ │ ├── transactions.ts │ │ │ ├── transferOwnership.ts │ │ │ └── username.ts │ │ ├── tsconfig.build.json │ │ ├── tsconfig.json │ │ └── tsup.config.ts │ ├── react/ │ │ ├── CHANGELOG.md │ │ ├── README.md │ │ ├── package.json │ │ ├── src/ │ │ │ ├── LensProvider.tsx │ │ │ ├── account/ │ │ │ │ ├── index.ts │ │ │ │ ├── useAccount.ts │ │ │ │ ├── useAccountFeedsStats.ts │ │ │ │ ├── useAccountManagers.ts │ │ │ │ ├── useAccountStats.ts │ │ │ │ ├── useAccounts.ts │ │ │ │ ├── useAccountsBlocked.ts │ │ │ │ ├── useAccountsBulk.ts │ │ │ │ ├── useAddAccountManager.ts │ │ │ │ ├── useBalancesBulk.ts │ │ │ │ ├── useCreateAccountWithFreeUsername.ts │ │ │ │ ├── useCreateAccountWithRestrictedUsername.ts │ │ │ │ ├── useEnableSignless.ts │ │ │ │ ├── useRemoveAccountManager.ts │ │ │ │ ├── useRemoveSignless.ts │ │ │ │ ├── useSetAccountMetadata.ts │ │ │ │ └── useWhoExecutedActionOnAccount.ts │ │ │ ├── app/ │ │ │ │ ├── index.ts │ │ │ │ └── useAppUsers.ts │ │ │ ├── authentication/ │ │ │ │ ├── index.ts │ │ │ │ ├── useAccountsAvailable.ts │ │ │ │ ├── useAuthenticatedUser.test.ts │ │ │ │ ├── useAuthenticatedUser.ts │ │ │ │ ├── useLogin.test.ts │ │ │ │ ├── useLogin.ts │ │ │ │ ├── useLogout.ts │ │ │ │ ├── useMeDetails.ts │ │ │ │ ├── usePublicClient.ts │ │ │ │ ├── useSessionClient.test.ts │ │ │ │ ├── useSessionClient.ts │ │ │ │ └── useSwitchAccount.ts │ │ │ ├── context.tsx │ │ │ ├── ethers/ │ │ │ │ ├── index.ts │ │ │ │ └── useUnknownPostActionEncoder.ts │ │ │ ├── feed/ │ │ │ │ ├── index.ts │ │ │ │ ├── useFeed.ts │ │ │ │ └── useFeeds.ts │ │ │ ├── follow/ │ │ │ │ ├── index.ts │ │ │ │ ├── useFollow.ts │ │ │ │ ├── useFollowStatus.ts │ │ │ │ ├── useFollowers.ts │ │ │ │ ├── useFollowersYouKnow.ts │ │ │ │ ├── useFollowing.ts │ │ │ │ └── useUnfollow.ts │ │ │ ├── graph/ │ │ │ │ ├── index.ts │ │ │ │ └── useGraph.ts │ │ │ ├── group/ │ │ │ │ ├── index.ts │ │ │ │ ├── useGroup.ts │ │ │ │ ├── useGroupBannedAccounts.ts │ │ │ │ ├── useGroupMembers.ts │ │ │ │ ├── useGroupMembershipRequests.ts │ │ │ │ └── useGroups.ts │ │ │ ├── helpers/ │ │ │ │ ├── index.ts │ │ │ │ ├── reads.ts │ │ │ │ ├── results.ts │ │ │ │ ├── tasks.test.ts │ │ │ │ └── tasks.ts │ │ │ ├── index.ts │ │ │ ├── ml/ │ │ │ │ ├── index.ts │ │ │ │ ├── useAccountRecommendations.ts │ │ │ │ ├── useDismissRecommendedAccounts.ts │ │ │ │ ├── usePostsForYou.ts │ │ │ │ └── usePostsToExplore.ts │ │ │ ├── notification/ │ │ │ │ ├── index.ts │ │ │ │ └── useNotifications.ts │ │ │ ├── post/ │ │ │ │ ├── index.ts │ │ │ │ ├── useBookmarkPost.ts │ │ │ │ ├── useCreatePost.test.ts │ │ │ │ ├── useCreatePost.ts │ │ │ │ ├── useExecutePostAction.ts │ │ │ │ ├── usePost.ts │ │ │ │ ├── usePostBookmarks.ts │ │ │ │ ├── usePostReactions.ts │ │ │ │ ├── usePostReferences.ts │ │ │ │ ├── usePostTags.ts │ │ │ │ ├── usePosts.ts │ │ │ │ ├── useUndoBookmarkPost.ts │ │ │ │ ├── useWhoExecutedActionOnPost.ts │ │ │ │ └── useWhoReferencedPost.ts │ │ │ ├── test-utils.tsx │ │ │ ├── timeline/ │ │ │ │ ├── index.ts │ │ │ │ ├── useTimeline.ts │ │ │ │ └── useTimelineHighlights.ts │ │ │ ├── tokenDistribution/ │ │ │ │ ├── index.ts │ │ │ │ └── useTokenDistributions.ts │ │ │ ├── username/ │ │ │ │ ├── index.ts │ │ │ │ ├── useCanCreateUsername.ts │ │ │ │ ├── useNamespace.ts │ │ │ │ └── useUsernames.ts │ │ │ └── viem/ │ │ │ ├── index.ts │ │ │ └── useUnknownPostActionEncoder.ts │ │ ├── tsconfig.build.json │ │ ├── tsconfig.json │ │ ├── tsup.config.ts │ │ └── vitest.setup.ts │ ├── storage/ │ │ ├── CHANGELOG.md │ │ ├── README.md │ │ ├── package.json │ │ ├── src/ │ │ │ ├── BaseStorageSchema.ts │ │ │ ├── CredentialsStorageSchema.ts │ │ │ ├── IStorage.ts │ │ │ ├── InMemoryStorageProvider.ts │ │ │ ├── Storage.test.ts │ │ │ ├── Storage.ts │ │ │ ├── __helpers__/ │ │ │ │ └── mocks.ts │ │ │ └── index.ts │ │ ├── tsconfig.build.json │ │ ├── tsconfig.json │ │ └── tsup.config.ts │ └── types/ │ ├── CHANGELOG.md │ ├── README.md │ ├── package.json │ ├── src/ │ │ ├── errors.ts │ │ ├── helpers/ │ │ │ ├── Deferred.ts │ │ │ ├── assertions.ts │ │ │ ├── fail.ts │ │ │ ├── identity.ts │ │ │ ├── index.ts │ │ │ ├── invariant.ts │ │ │ ├── never.ts │ │ │ ├── refinements.ts │ │ │ └── typeguards.ts │ │ ├── hex.ts │ │ ├── id.ts │ │ ├── index.ts │ │ ├── jwt.ts │ │ ├── misc.ts │ │ ├── number.ts │ │ ├── tag.ts │ │ └── uri.ts │ ├── tsconfig.build.json │ ├── tsconfig.json │ └── tsup.config.ts ├── plopfile.ts ├── pnpm-workspace.yaml ├── renovate.json ├── templates/ │ ├── example-react/ │ │ ├── README.md │ │ ├── index.html │ │ ├── package.json │ │ ├── src/ │ │ │ ├── App.tsx │ │ │ ├── client.ts │ │ │ ├── main.tsx │ │ │ └── vite-env.d.ts │ │ ├── tsconfig.json │ │ └── vite.config.ts │ └── lib/ │ ├── README.md.hbs │ ├── package.json.hbs │ ├── src/ │ │ └── index.ts │ ├── tsconfig.build.json │ ├── tsconfig.json │ └── tsup.config.ts ├── tsconfig.base.json ├── tsconfig.json ├── turbo.json ├── vite-env.d.ts ├── vitest.config.ts ├── vitest.d.ts └── vitest.setup.ts ================================================ FILE CONTENTS ================================================ ================================================ FILE: .changeset/README.md ================================================ # Changesets Hello and welcome! This folder has been automatically generated by `@changesets/cli`, a build tool that works with multi-package repos, or single-package repos to help you version and publish your code. You can find the full documentation for it [in our repository](https://github.com/changesets/changesets) We have a quick list of common questions to get you started engaging with this project in [our documentation](https://github.com/changesets/changesets/blob/main/docs/common-questions.md) ================================================ FILE: .changeset/config.json ================================================ { "$schema": "https://unpkg.com/@changesets/config@3.0.4/schema.json", "changelog": "@changesets/cli/changelog", "commit": false, "fixed": [["@lens-protocol/client", "@lens-protocol/react"]], "linked": [], "access": "public", "baseBranch": "main", "updateInternalDependencies": "patch", "ignore": [] } ================================================ FILE: .changeset/giant-buckets-melt.md ================================================ --- "@lens-protocol/client": minor "@lens-protocol/react": minor --- **feat**: add post action encoder and execution hooks ================================================ FILE: .changeset/nice-baboons-protect.md ================================================ --- "@lens-protocol/client": major "@lens-protocol/react": major "@lens-protocol/storage": minor "@lens-protocol/env": minor "@lens-protocol/graphql": minor "@lens-protocol/types": minor --- **chore**: transition to new major release ================================================ FILE: .changeset/pre.json ================================================ { "mode": "pre", "tag": "alpha", "initialVersions": { "@lens-protocol/client": "2.3.2", "@lens-protocol/env": "0.0.1", "@lens-protocol/graphql": "0.0.1", "@lens-protocol/react": "2.3.2", "@lens-protocol/storage": "0.8.1", "@lens-protocol/types": "0.0.1" }, "changesets": [ "nice-baboons-protect" ] } ================================================ FILE: .editorconfig ================================================ root = true [*] charset = utf-8 insert_final_newline = true end_of_line = lf indent_style = space indent_size = 2 max_line_length = 100 ================================================ FILE: .github/actions/setup/action.yml ================================================ name: 'Setup' description: 'Setup repo and install dependencies' runs: using: 'composite' steps: - name: Setup pnpm uses: pnpm/action-setup@v4 - name: Setup Node.js uses: actions/setup-node@v4 with: node-version-file: '.nvmrc' cache: 'pnpm' - name: Install Dependencies shell: bash run: pnpm install --frozen-lockfile ================================================ FILE: .github/actions/tests/action.yml ================================================ name: 'Test Workflow' description: 'Run tests against a specified environment' inputs: environment: description: 'Environment to run tests against' required: true default: 'staging' private_key: description: 'Private key for authentication' required: true global_sponsorship: description: 'The Global Sponsorship address' required: true sponsorship_approver_private_key: description: 'Private key for a Global Sponsorship Signer' required: true publish_results: description: 'Publish test results' required: false default: 'false' test_app: description: 'A valid Lens App address' required: true test_account: description: 'A Lens Account address' required: true test_erc20: description: 'An ERC20 token address' required: true runs: using: 'composite' steps: - uses: actions/checkout@v4 - name: Setup Repository uses: ./.github/actions/setup - name: Build shell: bash run: pnpm build - name: Setup Environment Variables shell: bash run: | echo "PRIVATE_KEY=${{ inputs.private_key }}" >> .env echo "TEST_APP=${{ inputs.test_app }}" >> .env echo "TEST_ACCOUNT=${{ inputs.test_account }}" >> .env echo "TEST_ERC20=${{ inputs.test_erc20 }}" >> .env echo "ENVIRONMENT=${{ inputs.environment }}" >> .env echo "GLOBAL_SPONSORSHIP=${{ inputs.global_sponsorship }}" >> .env echo "SPONSORSHIP_APPROVER_PRIVATE_KEY=${{ inputs.sponsorship_approver_private_key }}" >> .env - name: Run Tests shell: bash run: pnpm test - name: Publish Test Results if: ${{ inputs.publish_results == 'true' }} shell: bash run: | echo "Publishing test results..." # Add logic to upload test results to a service or save artifacts echo "Test results published." ================================================ FILE: .github/workflows/dependency-review.yml ================================================ name: Dependency Review on: - pull_request permissions: contents: read pull-requests: write jobs: dependency-review: runs-on: ubuntu-latest steps: - name: Checkout Repository uses: actions/checkout@v5 - name: Dependency Review uses: actions/dependency-review-action@v4 with: comment-summary-in-pr: on-failure fail-on-severity: moderate license-check: false ================================================ FILE: .github/workflows/pull-request.yml ================================================ name: Pull Request on: workflow_dispatch: pull_request: branches: [main] concurrency: group: ${{ github.workflow }}-${{ github.head_ref || github.run_id }} cancel-in-progress: true jobs: verify: name: Verify uses: ./.github/workflows/verify.yml secrets: inherit ================================================ FILE: .github/workflows/snapshot.yml ================================================ name: Canary Release on: push: branches: [main] concurrency: group: ${{ github.workflow }}-${{ github.head_ref || github.run_id }} cancel-in-progress: true jobs: verify: name: Verify uses: ./.github/workflows/verify.yml secrets: inherit publish: name: Publish Snapshot runs-on: ubuntu-latest needs: verify steps: - uses: actions/checkout@v4 - name: Setup Repository uses: ./.github/actions/setup - name: Configure NPM Auth Token run: echo "//registry.npmjs.org/:_authToken=${{ secrets.NODE_AUTH_TOKEN }}" >> ~/.npmrc - name: Create Snapshot id: create_snapshot run: pnpm changeset version --snapshot canary || echo "No unreleased changesets found" - name: Check for Changeset id: check_changeset run: echo "changeset_exists=$(grep -q 'No unreleased changesets found' <<< '${{ steps.create_snapshot.outputs.stdout }}' && echo false || echo true)" >> $GITHUB_ENV - name: Build if: env.changeset_exists == 'true' run: pnpm build - name: Publish Snapshot if: env.changeset_exists == 'true' run: pnpm changeset publish --snapshot --tag canary --no-git-tag ================================================ FILE: .github/workflows/trigger-tests.yml ================================================ name: Run Tests on Demand on: repository_dispatch: types: [on-demand-test] workflow_dispatch: inputs: environment: description: 'Environment to run tests against' required: true default: 'staging' type: choice options: - staging - testnet publish_results: description: 'Publish test results' required: false default: 'true' type: string jobs: tests: name: Full Test Suite runs-on: ubuntu-latest steps: - uses: actions/checkout@v4 - name: Run Tests uses: ./.github/actions/tests with: environment: ${{ github.event_name == 'workflow_dispatch' && github.event.inputs.environment || github.event.client_payload.lens_env || 'staging' }} private_key: ${{ secrets.PRIVATE_KEY }} test_app: ${{ vars.TEST_APP }} test_account: ${{ vars.TEST_ACCOUNT }} test_erc20: ${{ vars.TEST_ERC20 }} global_sponsorship: ${{ secrets.GLOBAL_SPONSORSHIP }} sponsorship_approver_private_key: ${{ secrets.SPONSORSHIP_APPROVER_PRIVATE_KEY }} publish_results: ${{ github.event_name == 'workflow_dispatch' && github.event.inputs.publish_results || 'true' }} ================================================ FILE: .github/workflows/verify.yml ================================================ name: 'Verify' on: workflow_call: workflow_dispatch: jobs: lint: name: Lint runs-on: ubuntu-latest steps: - uses: actions/checkout@v4 - name: Setup Biome uses: biomejs/setup-biome@v2 with: version: 2.0.6 - name: Run Biome run: biome ci . test: name: Test runs-on: ubuntu-latest steps: - uses: actions/checkout@v4 - name: Run Tests uses: ./.github/actions/tests with: environment: 'staging' private_key: ${{ secrets.PRIVATE_KEY }} test_app: ${{ vars.TEST_APP }} test_account: ${{ vars.TEST_ACCOUNT }} test_erc20: ${{ vars.TEST_ERC20 }} global_sponsorship: ${{ secrets.GLOBAL_SPONSORSHIP }} sponsorship_approver_private_key: ${{ secrets.SPONSORSHIP_APPROVER_PRIVATE_KEY }} publish_results: 'false' ================================================ FILE: .gitignore ================================================ # See https://help.github.com/articles/ignoring-files/ for more about ignoring files. # dependencies node_modules .pnp .pnp.js # build output **/dist /docs */graphql-cache.d.ts # misc .DS_Store *.pem # turbo .turbo # lockfiles package-lock.json yarn.lock examples/*/pnpm-lock.yaml # debug .pnpm-debug.log* # local env files .env # typescript *.tsbuildinfo # cursor .cursorignore ================================================ FILE: .npmrc ================================================ engine-strict=true auto-install-peers=false strict-peer-dependencies=false link-workspace-packages=false ================================================ FILE: .nvmrc ================================================ 20.13.1 ================================================ FILE: .prettierignore ================================================ # use biome instead * ================================================ FILE: .vscode/settings.json ================================================ { "[graphql]": { "editor.defaultFormatter": "biomejs.biome", "editor.formatOnSave": false }, "[typescript]": { "editor.defaultFormatter": "biomejs.biome", "editor.codeActionsOnSave": { "source.fixAll": "explicit", "source.removeUnused.ts": "never", "source.removeUnusedImports": "never", "source.organizeImports.biome": "explicit" }, "editor.formatOnSave": true }, "[typescriptreact]": { "editor.defaultFormatter": "biomejs.biome", "editor.codeActionsOnSave": { "source.fixAll": "explicit", "source.removeUnused.ts": "never", "source.removeUnusedImports": "never", "source.organizeImports.biome": "explicit" }, "editor.formatOnSave": true }, "[json]": { "editor.defaultFormatter": "biomejs.biome", "editor.quickSuggestions": { "strings": true }, "editor.formatOnSave": true, "editor.suggest.insertMode": "replace" }, "disabledExtensions": ["Orta.vscode-jest"], "typescript.tsdk": "node_modules/typescript/lib", "typescript.enablePromptUseWorkspaceTsdk": true } ================================================ FILE: LICENSE ================================================ MIT License Copyright (c) Avara Labs Cayman Holdings SEZC Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation files (the "Software"), to deal in the Software without restriction, including without limitation the rights to use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of the Software, and to permit persons to whom the Software is furnished to do so, subject to the following conditions: The above copyright notice and this permission notice shall be included in all copies or substantial portions of the Software. THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. ================================================ FILE: README.md ================================================ # Lens SDK The official SDK for the Lens 🌿. ## Table of Contents - [Installation](#installation) - [Development Workflow](#development-workflow) - [Troubleshooting](#troubleshooting) - [Contributing](#contributing) - [License](#license) ## Installation ## Development Workflow This section is for developers who want to contribute to the SDK. ### Initial Setup Clone the repository: ```bash git clone https://github.com/lens-network/sdk.git ``` Install the dependencies: ```bash pnpm install ``` ### Pre-requisites: - Node.js: >= v20. See [installation guide](https://nodejs.org/en/download/package-manager). - pnpm: v9.1.2. See [installation guide](https://pnpm.io/installation). Use [nvm](https://github.com/nvm-sh/nvm) to manage your Node.js versions. Run the following command in the project root folder: ```bash nvm use ``` to switch to the correct Node.js version. Enable [corepack](https://www.totaltypescript.com/how-to-use-corepack) to use the the correct version of `pnpm`. Run the following command in the project root folder: ```bash corepack install ``` to install the correct version once. After that corepack will automatically use the correct version of `pnpm` when entering the project folder. ### Usage Run the tests: - `pnpm test:client`: Run the tests for the `@lens-protocol/client` package. Lint the code: ```bash pnpm lint ``` Compile the code: ```bash pnpm build ``` Clean the build: ```bash pnpm clean ``` Create a new package: ```bash pnpm new:package ``` ### IDE Setup The project uses [Biome](https://biomejs.dev/) to format and lint the code. You can install the Biome extension for your IDE: https://biomejs.dev/guides/editors/first-party-extensions/ ### Publishing 1. Create a new release branch using the `release/X.Y.Z` naming convention. 2. Bumps up version number and updates the changelog. ```bash pnpm changeset version ``` 3. Commit the changes using `chore: bumps up version number` as the commit message. 4. Push the changes to the remote repository. 5. Open a pull request to the `main` branch. 6. Wait for all checks to pass and for the pull request to be approved. 7. Publish the package. ```bash pnpm changeset publish ``` 8. Push tags to the remote repository. ```bash git push --follow-tags ``` 9. Merge the pull request to the `main` branch. ## Troubleshooting ### Incompatible Types Across Packages Working within a monorepo can sometimes lead to type incompatibilities across packages. If you encounter an error like: ```bash Type 'import("[...]/packages/client/dist/index").PublicClient' is not assignable to type 'import("[...]/packages/client/src/clients").PublicClient'. ``` This usually indicates that TypeScript is picking up types from different versions of the same package. To resolve this, make sure you have configured the entry points correctly as aliases in the top level `tsconfig.json` file. ```json { "$schema": "https://json.schemastore.org/tsconfig", "compilerOptions": { "skipLibCheck": true, "types": ["node"], "paths": { "@lens-protocol/client": ["./packages/client/src"], "@lens-protocol/client/actions": ["./packages/client/src/actions"], "@lens-protocol/client/test-utils": ["./packages/client/src/test-utils"], "@lens-protocol/env": ["./packages/env/src"], "@lens-protocol/graphql": ["./packages/graphql/src"], "@lens-protocol/react": ["./packages/react/src"], "@lens-protocol/storage": ["./packages/storage/src"], "@lens-protocol/types": ["./packages/types/src"] } }, "include": ["**/*.ts"], "exclude": ["dist", "node_modules"] } ``` ## Contributing We are currently focused on launching Lens Network mainnet and Lens Protocol v3. We are not able to accept contributions at this time. We will update this section in due course. If you have a pressing issue or feature request, please open an issue on GitHub. ## License Lens SDK is [MIT licensed](./LICENSE). ================================================ FILE: biome.json ================================================ { "$schema": "https://biomejs.dev/schemas/2.0.6/schema.json", "vcs": { "enabled": true, "clientKind": "git", "useIgnoreFile": true }, "files": { "ignoreUnknown": false, "includes": ["**"] }, "formatter": { "enabled": true, "useEditorconfig": true }, "assist": { "actions": { "source": { "organizeImports": "on" } } }, "linter": { "enabled": true, "rules": { "recommended": true, "style": { "noParameterAssign": "error", "useAsConstAssertion": "error", "useDefaultParameterLast": "error", "useEnumInitializers": "error", "useSelfClosingElements": "error", "useSingleVarDeclarator": "error", "noUnusedTemplateLiteral": "error", "useNumberNamespace": "error", "noInferrableTypes": "error", "noUselessElse": "error" } } }, "javascript": { "formatter": { "quoteStyle": "single", "jsxQuoteStyle": "single" } }, "json": { "formatter": { "enabled": false }, "linter": { "enabled": false } }, "overrides": [ { "includes": ["**/*.tsx"], "linter": { "domains": { "react": "all" } } }, { "includes": ["templates/**/*"], "formatter": { "enabled": false }, "linter": { "enabled": false } }, { "includes": ["packages/**/*/dist/**"], "formatter": { "enabled": false }, "linter": { "enabled": false } }, { "includes": ["packages/**/*.e2e.ts","packages/**/*.test.ts"], "linter": { "rules": { "style": { "noNonNullAssertion": "off" } } } }, { "includes": ["packages/graphql/**/*.graphql"], "formatter": { "enabled": false }, "linter": { "enabled": false } }, { "includes": ["packages/graphql/src/graphql-*.d.ts"], "formatter": { "enabled": false }, "linter": { "enabled": false }, "assist": { "actions": { "source": { "organizeImports": "off" } } } }, { "includes": ["examples/**/*.ts", "examples/**/*.tsx"], "linter": { "rules": { "style": { "noNonNullAssertion": "off" } } } } ] } ================================================ FILE: examples/create-app/README.md ================================================ # Create an App [![Open in StackBlitz](https://developer.stackblitz.com/img/open_in_stackblitz.svg)](https://stackblitz.com/github/lens-protocol/lens-sdk/tree/main/examples/create-app) ================================================ FILE: examples/create-app/index.html ================================================

Create an App

Loading...
================================================ FILE: examples/create-app/index.ts ================================================ import 'viem/window'; import { chains } from '@lens-chain/sdk/viem'; import { immutable, StorageClient } from '@lens-chain/storage-client'; import { PublicClient, testnet, uri } from '@lens-protocol/client'; import { createApp, fetchApp } from '@lens-protocol/client/actions'; import { handleOperationWith } from '@lens-protocol/client/viem'; import { app, Platform } from '@lens-protocol/metadata'; import { type Address, createWalletClient, custom } from 'viem'; const chain = chains.testnet; // hoist account const [address] = (await window.ethereum!.request({ method: 'eth_requestAccounts', })) as [Address]; const walletClient = createWalletClient({ account: address, chain, transport: custom(window.ethereum!), }); const client = PublicClient.create({ environment: testnet, }); const sessionClient = await client .login({ builder: { address: walletClient.account.address, }, signMessage: async (message) => walletClient.signMessage({ message }), }) .match( (result) => result, (error) => { throw error; }, ); const storageClient = StorageClient.create(); const metadata = app({ name: 'My App', url: 'https://example.com', description: 'My app description', platforms: [Platform.WEB], developer: 'me@example.com', }); const resource = await storageClient.uploadAsJson(metadata, { acl: immutable(chain.id), }); const created = await createApp(sessionClient, { metadataUri: uri(resource.uri), defaultFeed: { globalFeed: true, }, graph: { globalGraph: true, }, namespace: { globalNamespace: true, }, }) .andThen(handleOperationWith(walletClient)) .andThen(sessionClient.waitForTransaction) .andThen((txHash) => fetchApp(sessionClient, { txHash })) .match( (result) => result, (error) => { throw error; }, ); export default [ `

${created?.metadata?.name}

`, `

Address: ${await created?.address}

`, ]; ================================================ FILE: examples/create-app/package.json ================================================ { "name": "example-create-app", "private": true, "type": "module", "scripts": { "dev": "vite" }, "dependencies": { "@lens-chain/sdk": "latest", "@lens-protocol/client": "canary", "@lens-protocol/metadata": "latest", "@lens-chain/storage-client": "latest", "viem": "^2.21.55" }, "devDependencies": { "typescript": "^5.6.3", "vite": "^5.4.11" } } ================================================ FILE: examples/create-app/tsconfig.json ================================================ { "compilerOptions": { "target": "ESNext", "useDefineForClassFields": true, "lib": ["ESNext", "DOM"], "module": "ESNext", "moduleResolution": "Bundler", "strict": true, "resolveJsonModule": true, "isolatedModules": true, "esModuleInterop": true, "noEmit": true, "noUnusedLocals": true, "noUnusedParameters": true, "noImplicitReturns": true, "skipLibCheck": true }, "include": ["./"] } ================================================ FILE: examples/custom-fragments/README.md ================================================ # Custom Fragments [![Open in StackBlitz](https://developer.stackblitz.com/img/open_in_stackblitz.svg)](https://stackblitz.com/github/lens-protocol/lens-sdk/tree/main/examples/custom-fragments) ================================================ FILE: examples/custom-fragments/index.html ================================================

Custom Fragments

Loading...
================================================ FILE: examples/custom-fragments/index.ts ================================================ import { type Account, ArticleMetadataFragment, AudioMetadataFragment, evmAddress, type FragmentOf, graphql, ImageMetadataFragment, PublicClient, TextOnlyMetadataFragment, testnet, UsernameFragment, VideoMetadataFragment, } from '@lens-protocol/client'; import { fetchAccount } from '@lens-protocol/client/actions'; const AccountFragment = graphql( `fragment Account on Account { __typename handle: username { ...Username } }`, [UsernameFragment], ); const PostMetadataFragment = graphql( `fragment PostMetadata on PostMetadata { __typename ... on ArticleMetadata { content } ... on AudioMetadata { content } ... on TextOnlyMetadata { content } ... on ImageMetadata { content } ... on VideoMetadata { content } }`, [ ArticleMetadataFragment, AudioMetadataFragment, TextOnlyMetadataFragment, ImageMetadataFragment, VideoMetadataFragment, ], ); const PostFieldsFragment = graphql( `fragment PostFields on Post { metadata { ...PostMetadata } }`, [PostMetadataFragment], ); declare module '@lens-protocol/client' { export interface Account extends FragmentOf {} export interface PostFields extends FragmentOf {} export type PostMetadata = FragmentOf; } const client = PublicClient.create({ environment: testnet, fragments: [AccountFragment, PostFieldsFragment], }); const account: Account | null = await fetchAccount(client, { address: evmAddress('0x57b62a1571F4F09CDB4C3d93dA542bfe142D9F81'), }).unwrapOr(null); export default [ `

${account?.handle?.value}

`, `
${JSON.stringify(account, null, 2)}
`, ]; ================================================ FILE: examples/custom-fragments/package.json ================================================ { "name": "example-custom-fragments", "private": true, "type": "module", "scripts": { "dev": "vite" }, "dependencies": { "@lens-protocol/client": "canary", "viem": "^2.21.55" }, "devDependencies": { "typescript": "^5.6.3", "vite": "^5.4.11" } } ================================================ FILE: examples/custom-fragments/tsconfig.json ================================================ { "compilerOptions": { "target": "ESNext", "useDefineForClassFields": true, "lib": ["ESNext", "DOM"], "module": "ESNext", "moduleResolution": "Bundler", "strict": true, "resolveJsonModule": true, "isolatedModules": true, "esModuleInterop": true, "noEmit": true, "noUnusedLocals": true, "noUnusedParameters": true, "noImplicitReturns": true, "skipLibCheck": true }, "include": ["./"] } ================================================ FILE: examples/nextjs-client/.gitignore ================================================ # See https://help.github.com/articles/ignoring-files/ for more about ignoring files. # dependencies /node_modules /.pnp .pnp.* .yarn/* !.yarn/patches !.yarn/plugins !.yarn/releases !.yarn/versions # testing /coverage # next.js /.next/ /out/ # production /build # misc .DS_Store *.pem # debug npm-debug.log* yarn-debug.log* yarn-error.log* .pnpm-debug.log* # env files (can opt-in for committing if needed) .env* # vercel .vercel # typescript *.tsbuildinfo next-env.d.ts ================================================ FILE: examples/nextjs-client/.stackblitzrc ================================================ { "startCommand": "npm run dev", "env": {} } ================================================ FILE: examples/nextjs-client/README.md ================================================ # Next.js - Lens Client Integration Example This is a [Next.js](https://nextjs.org) project bootstrapped with [`create-next-app`](https://nextjs.org/docs/app/api-reference/cli/create-next-app). [![Open in StackBlitz](https://developer.stackblitz.com/img/open_in_stackblitz.svg)](https://stackblitz.com/github/lens-protocol/lens-sdk/tree/main/examples/nextjs-client) ================================================ FILE: examples/nextjs-client/next.config.ts ================================================ import type { NextConfig } from 'next'; const nextConfig: NextConfig = { /* config options here */ }; export default nextConfig; ================================================ FILE: examples/nextjs-client/package.json ================================================ { "name": "nextjs-client", "version": "0.1.0", "private": true, "scripts": { "dev": "next dev", "build": "next build", "start": "next start", "lint": "next lint" }, "dependencies": { "@lens-protocol/react": "canary", "next": "15.4.2", "react": "^19.0.0", "react-dom": "^19.0.0", "simpledotcss": "^2.3.3" }, "devDependencies": { "@types/node": "^20", "@types/react": "^19", "@types/react-dom": "^19", "typescript": "^5" } } ================================================ FILE: examples/nextjs-client/src/app/Web3Providers.tsx ================================================ 'use client'; import { LensProvider } from '@lens-protocol/react'; import { client } from './client'; export function Web3Providers({ children }: { children: React.ReactNode }) { return {children}; } ================================================ FILE: examples/nextjs-client/src/app/client.ts ================================================ import { PublicClient, testnet } from '@lens-protocol/react'; export const client = PublicClient.create({ environment: testnet, }); ================================================ FILE: examples/nextjs-client/src/app/globals.css ================================================ :root { --background: #ffffff; --foreground: #171717; } @media (prefers-color-scheme: dark) { :root { --background: #0a0a0a; --foreground: #ededed; } } html, body { max-width: 100vw; overflow-x: hidden; } body { color: var(--foreground); background: var(--background); font-family: Arial, Helvetica, sans-serif; -webkit-font-smoothing: antialiased; -moz-osx-font-smoothing: grayscale; } * { box-sizing: border-box; padding: 0; margin: 0; } a { color: inherit; text-decoration: none; } @media (prefers-color-scheme: dark) { html { color-scheme: dark; } } ================================================ FILE: examples/nextjs-client/src/app/layout.tsx ================================================ import type { Metadata } from 'next'; import { Geist, Geist_Mono } from 'next/font/google'; import 'simpledotcss/simple.min.css'; import './globals.css'; import { Suspense } from 'react'; import { Web3Providers } from './Web3Providers'; const geistSans = Geist({ variable: '--font-geist-sans', subsets: ['latin'], }); const geistMono = Geist_Mono({ variable: '--font-geist-mono', subsets: ['latin'], }); export const metadata: Metadata = { title: 'Next.js - Lens Client Integration', description: 'Generated by create next app', }; export default function RootLayout({ children, }: Readonly<{ children: React.ReactNode; }>) { return ( Loading...}>{children} ); } ================================================ FILE: examples/nextjs-client/src/app/page.tsx ================================================ 'use client'; import { AccountsOrderBy, PageSize, useAccounts } from '@lens-protocol/react'; export default function Home() { const { data } = useAccounts({ orderBy: AccountsOrderBy.AccountScore, pageSize: PageSize.Ten, suspense: true, }); return (

Top 10 Accounts by Account Score:

    {data.items.map((account) => (
  • {account.username?.value}
  • ))}
); } ================================================ FILE: examples/nextjs-client/tsconfig.json ================================================ { "compilerOptions": { "target": "ES2017", "lib": ["dom", "dom.iterable", "esnext"], "allowJs": true, "skipLibCheck": true, "strict": true, "noEmit": true, "esModuleInterop": true, "module": "esnext", "moduleResolution": "bundler", "resolveJsonModule": true, "isolatedModules": true, "jsx": "preserve", "incremental": true, "plugins": [ { "name": "next" } ], "paths": { "@/*": ["./src/*"] } }, "include": ["next-env.d.ts", "**/*.ts", "**/*.tsx", ".next/types/**/*.ts"], "exclude": ["node_modules"] } ================================================ FILE: examples/react-follow/README.md ================================================ # Follow/Unfollow Accounts on Lens [![Open in StackBlitz](https://developer.stackblitz.com/img/open_in_stackblitz.svg)](https://stackblitz.com/github/lens-protocol/lens-sdk/tree/main/examples/react-follow) ================================================ FILE: examples/react-follow/index.html ================================================ Log in to Lens
================================================ FILE: examples/react-follow/package.json ================================================ { "name": "react-follow", "description": "Follow/Unfollow accounts on Lens", "private": true, "version": "0.0.0", "type": "module", "scripts": { "dev": "vite" }, "dependencies": { "@lens-chain/sdk": "latest", "@lens-protocol/react": "canary", "@tanstack/react-query": "^5.63.0", "connectkit": "^1.9.0", "react": "^18.3.1", "react-dom": "^18.3.1", "viem": "^2.22.4", "wagmi": "^2.14.6" }, "devDependencies": { "@types/react": "^18.3.12", "@types/react-dom": "^18.3.1", "@vitejs/plugin-react-swc": "^3.8.1", "typescript": "^5.6.3", "vite": "^5.4.9" } } ================================================ FILE: examples/react-follow/src/AccountToFollow.tsx ================================================ import { PageSize, useAccounts } from '@lens-protocol/react'; import { FollowButton } from './FollowButton'; export function AccountsToFollow() { const { data } = useAccounts({ filter: { searchBy: { localNameQuery: 'test' } }, pageSize: PageSize.Ten, suspense: true, }); return (

Accounts to Follow

    {data?.items.map((account) => (
  • {account.username?.localName ?? account.address} {account.operations?.isFollowedByMe ? 'Following' : 'Not Following'}

  • ))}
); } ================================================ FILE: examples/react-follow/src/App.tsx ================================================ import { AccountsToFollow } from './AccountToFollow'; export function App() { return (

Lens Follow Example


); } ================================================ FILE: examples/react-follow/src/FollowButton.tsx ================================================ import { type Account, useFollow, useUnfollow } from '@lens-protocol/react'; import { handleOperationWith } from '@lens-protocol/react/viem'; import { useWalletClient } from 'wagmi'; export function FollowButton({ account }: { account: Account }) { const { data: wallet } = useWalletClient(); const { execute: follow, loading: followLoading } = useFollow({ handler: handleOperationWith(wallet), }); const { execute: unfollow, loading: unfollowLoading } = useUnfollow({ handler: handleOperationWith(wallet), }); const loading = followLoading || unfollowLoading; const handleFollowToggle = async () => { const result = account.operations?.isFollowedByMe ? await unfollow({ account: account.address }) : await follow({ account: account.address }); if (result.isErr()) { alert(result.error.message); return; } }; return ( ); } ================================================ FILE: examples/react-follow/src/Web3Providers.tsx ================================================ import { LensProvider } from '@lens-protocol/react'; import { QueryClient, QueryClientProvider } from '@tanstack/react-query'; import { ConnectKitProvider } from 'connectkit'; import type React from 'react'; import { WagmiProvider } from 'wagmi'; import { client } from './client'; import { config } from './config'; const queryClient = new QueryClient(); export function Web3Providers({ children }: { children: React.ReactNode }) { return ( {children} ); } ================================================ FILE: examples/react-follow/src/client.ts ================================================ import { fetchAccountsAvailable } from '@lens-protocol/client/actions'; import { assertOk, cache, invariant, PublicClient, testnet, } from '@lens-protocol/react'; import { signMessageWith } from '@lens-protocol/react/viem'; import { walletClient } from './wallet'; export const client = PublicClient.create({ environment: testnet, cache: cache, storage: window.localStorage, }); const result = await client.resumeSession().orElse(() => fetchAccountsAvailable(client, { managedBy: walletClient.account.address, }).andThen(({ items }) => { invariant(items.length > 0, 'No available accounts found'); const loginAs = items[0].__typename === 'AccountOwned' ? { accountOwner: { owner: walletClient.account.address, account: items[0].account.address, }, } : { accountManager: { manager: walletClient.account.address, account: items[0].account.address, }, }; return client.login({ ...loginAs, signMessage: signMessageWith(walletClient), }); }), ); assertOk(result); ================================================ FILE: examples/react-follow/src/config.ts ================================================ import { chains } from '@lens-chain/sdk/viem'; import { getDefaultConfig } from 'connectkit'; import { createConfig, http } from 'wagmi'; export const config = createConfig( getDefaultConfig({ chains: [chains.testnet], transports: { // [chains.mainnet.id]: http(chains.mainnet.rpcUrls.default.http[0]!), [chains.testnet.id]: http(chains.testnet.rpcUrls.default.http[0]!), }, walletConnectProjectId: '', appName: 'Lens + ConnectKit Example', appDescription: 'A sample app integrating ConnectKit and Lens React SDK.', appUrl: `${import.meta.env.BASE_URL}`, appIcon: `${import.meta.env.BASE_URL}/lens.svg`, }), ); ================================================ FILE: examples/react-follow/src/main.tsx ================================================ import { Suspense } from 'react'; import { createRoot } from 'react-dom/client'; import { App } from './App'; import { Web3Providers } from './Web3Providers'; createRoot(document.getElementById('root')!).render( Loading...

}>
, ); ================================================ FILE: examples/react-follow/src/vite-env.d.ts ================================================ /// ================================================ FILE: examples/react-follow/src/wallet.ts ================================================ import { chains } from '@lens-chain/sdk/viem'; import { type Address, createWalletClient, custom } from 'viem'; const chain = chains.testnet; // hoist account const [address] = (await window.ethereum!.request({ method: 'eth_requestAccounts', })) as [Address]; export const walletClient = createWalletClient({ account: address, chain, transport: custom(window.ethereum!), }); const chainId = await walletClient.getChainId(); if (chainId !== chain.id) { try { await walletClient.switchChain({ id: chain.id }); } catch { await walletClient.addChain({ chain }); } } ================================================ FILE: examples/react-follow/tsconfig.json ================================================ { "compilerOptions": { "target": "ESNext", "useDefineForClassFields": true, "lib": ["ES2020", "DOM", "DOM.Iterable"], "jsx": "react-jsx", "module": "ESNext", "moduleResolution": "Bundler", "strict": true, "resolveJsonModule": true, "isolatedModules": true, "esModuleInterop": true, "noEmit": true, "noUnusedLocals": true, "noUnusedParameters": true, "noImplicitReturns": true, "skipLibCheck": true }, "include": ["src", "vite.config.ts"] } ================================================ FILE: examples/react-follow/vite.config.ts ================================================ import react from '@vitejs/plugin-react-swc'; import { defineConfig } from 'vite'; export default defineConfig({ plugins: [react()], }); ================================================ FILE: examples/react-login/README.md ================================================ # Log in to Lens [![Open in StackBlitz](https://developer.stackblitz.com/img/open_in_stackblitz.svg)](https://stackblitz.com/github/lens-protocol/lens-sdk/tree/main/examples/react-login) ================================================ FILE: examples/react-login/index.html ================================================ Log in to Lens
================================================ FILE: examples/react-login/package.json ================================================ { "name": "react-login", "description": "Log in to Lens", "private": true, "version": "0.0.0", "type": "module", "scripts": { "dev": "vite" }, "dependencies": { "@lens-chain/sdk": "latest", "@lens-protocol/react": "canary", "@tanstack/react-query": "^5.63.0", "connectkit": "^1.9.0", "react": "^18.3.1", "react-dom": "^18.3.1", "viem": "^2.22.4", "wagmi": "^2.14.6" }, "devDependencies": { "@types/react": "^18.3.12", "@types/react-dom": "^18.3.1", "@vitejs/plugin-react-swc": "^3.8.1", "typescript": "^5.6.3", "vite": "^5.4.9" } } ================================================ FILE: examples/react-login/src/App.tsx ================================================ import { useAuthenticatedUser } from '@lens-protocol/react'; import { LoginForm } from './LoginForm'; import { MyAccount } from './MyAccount'; export function App() { const { data } = useAuthenticatedUser({ suspense: true }); if (data) { return ; } return ; } ================================================ FILE: examples/react-login/src/LoginForm.tsx ================================================ import { type AccountAvailable, type EvmAddress, evmAddress, useAccountsAvailable, useLogin, } from '@lens-protocol/react'; import { signMessageWith } from '@lens-protocol/react/viem'; import { useModal } from 'connectkit'; import { useAccount, useWalletClient } from 'wagmi'; function LoginWith({ signer, value, }: { signer: EvmAddress; value: AccountAvailable; }) { const { execute } = useLogin(); const { data } = useWalletClient(); const loginAs = value.__typename === 'AccountManaged' ? { accountManager: { account: value.account.address, manager: signer, }, } : { accountOwner: { account: value.account.address, owner: signer, }, }; return ( ); } function LoginOptions({ address }: { address: string }) { const { data } = useAccountsAvailable({ managedBy: evmAddress(address), suspense: true, }); return ( <>

Select an account

    {data.items.map((item) => (
  • ))}
); } export function LoginForm() { const { address } = useAccount(); const { setOpen } = useModal(); if (!address) { return ( ); } return ; } ================================================ FILE: examples/react-login/src/LogoutButton.tsx ================================================ import { useLogout } from '@lens-protocol/react'; import { useDisconnect } from 'wagmi'; export function LogoutButton() { const { execute } = useLogout(); const { disconnectAsync } = useDisconnect(); const onClick = async () => { await execute(); await disconnectAsync(); }; return ( ); } ================================================ FILE: examples/react-login/src/MyAccount.tsx ================================================ import { type EvmAddress, useAccount } from '@lens-protocol/react'; import { LogoutButton } from './LogoutButton'; export function MyAccount({ address }: { address: EvmAddress }) { const { data } = useAccount({ address, suspense: true }); return (

Welcome,{' '} {data?.metadata?.name ?? data?.username?.value ?? data?.address}!

Created on: {data?.createdAt}

Account Score: {data?.score}

); } ================================================ FILE: examples/react-login/src/Web3Providers.tsx ================================================ import { LensProvider } from '@lens-protocol/react'; import { QueryClient, QueryClientProvider } from '@tanstack/react-query'; import { ConnectKitProvider } from 'connectkit'; import type React from 'react'; import { WagmiProvider } from 'wagmi'; import { client } from './client'; import { config } from './config'; const queryClient = new QueryClient(); export function Web3Providers({ children }: { children: React.ReactNode }) { return ( {children} ); } ================================================ FILE: examples/react-login/src/client.ts ================================================ import { mainnet, PublicClient } from '@lens-protocol/react'; export const client = PublicClient.create({ environment: mainnet, storage: window.localStorage, }); ================================================ FILE: examples/react-login/src/config.ts ================================================ import { chains } from '@lens-chain/sdk/viem'; import { getDefaultConfig } from 'connectkit'; import { createConfig, http } from 'wagmi'; export const config = createConfig( getDefaultConfig({ chains: [chains.mainnet, chains.testnet], transports: { [chains.mainnet.id]: http(chains.mainnet.rpcUrls.default.http[0]!), [chains.testnet.id]: http(chains.testnet.rpcUrls.default.http[0]!), }, walletConnectProjectId: '', appName: 'Lens + ConnectKit Example', appDescription: 'A sample app integrating ConnectKit and Lens React SDK.', appUrl: `${import.meta.env.BASE_URL}`, appIcon: `${import.meta.env.BASE_URL}/lens.svg`, }), ); ================================================ FILE: examples/react-login/src/main.tsx ================================================ import { Suspense } from 'react'; import { createRoot } from 'react-dom/client'; import { App } from './App'; import { Web3Providers } from './Web3Providers'; createRoot(document.getElementById('root')!).render( Loading...

}>
, ); ================================================ FILE: examples/react-login/src/vite-env.d.ts ================================================ /// ================================================ FILE: examples/react-login/tsconfig.json ================================================ { "compilerOptions": { "target": "ESNext", "useDefineForClassFields": true, "lib": ["ES2020", "DOM", "DOM.Iterable"], "jsx": "react-jsx", "module": "ESNext", "moduleResolution": "Bundler", "strict": true, "resolveJsonModule": true, "isolatedModules": true, "esModuleInterop": true, "noEmit": true, "noUnusedLocals": true, "noUnusedParameters": true, "noImplicitReturns": true, "skipLibCheck": true }, "include": ["src", "vite.config.ts"] } ================================================ FILE: examples/react-login/vite.config.ts ================================================ import react from '@vitejs/plugin-react-swc'; import { defineConfig } from 'vite'; export default defineConfig({ plugins: [react()], }); ================================================ FILE: examples/react-post/README.md ================================================ # Create a Lens Post with Lens React Hooks [![Open in StackBlitz](https://developer.stackblitz.com/img/open_in_stackblitz.svg)](https://stackblitz.com/github/lens-protocol/lens-sdk/tree/main/examples/react-post) ================================================ FILE: examples/react-post/index.html ================================================ Create a Lens Post with Lens React Hooks
================================================ FILE: examples/react-post/package.json ================================================ { "name": "react-post", "description": "Create a Lens Post with Lens React Hooks", "private": true, "version": "0.0.0", "type": "module", "scripts": { "dev": "vite" }, "dependencies": { "@lens-chain/sdk": "^1.0.3", "@lens-protocol/client": "canary", "@lens-protocol/metadata": "^2.0.0", "@lens-protocol/react": "canary", "@tanstack/react-query": "^5.74.3", "react": "^18.3.1", "react-dom": "^18.3.1", "viem": "2.x", "wagmi": "^2.14.16" }, "devDependencies": { "@types/react": "^18.3.12", "@types/react-dom": "^18.3.1", "@vitejs/plugin-react-swc": "^3.7.2", "typescript": "^5.6.3", "vite": "^5.4.9" } } ================================================ FILE: examples/react-post/src/App.tsx ================================================ import { textOnly } from '@lens-protocol/metadata'; import { useCreatePost } from '@lens-protocol/react'; import { handleOperationWith } from '@lens-protocol/react/viem'; import { useWalletClient } from 'wagmi'; export function App() { const { data: wallet } = useWalletClient(); const { execute, loading, data: post, } = useCreatePost({ handler: handleOperationWith(wallet) }); const onSubmit = async (event: React.FormEvent) => { event.preventDefault(); const formData = new FormData(event.currentTarget); const content = formData.get('content') as string; const metadata = textOnly({ content, }); const result = await execute({ contentUri: `data:application/json,${JSON.stringify(metadata)}`, }); if (result.isErr()) { alert(result.error.message); } }; return (

Post Example

{post && (

Post Created

Slug: {post.slug}

Created At: {post.timestamp.toString()}

Content:{' '} {post.metadata.__typename === 'TextOnlyMetadata' && post.metadata.content}

)}