Skip to content

Latest commit

 

History

History
393 lines (318 loc) · 13.2 KB

File metadata and controls

393 lines (318 loc) · 13.2 KB

CLAUDE.md — tweb (Telegram Web K)

Project Overview

tweb is a full-featured Telegram web client (https://web.telegram.org/k/) built with Solid.js and TypeScript. It implements Telegram's MTProto protocol directly in the browser (no third-party API wrappers). The codebase is large (~100k+ lines excluding vendor), mature, and highly performance-oriented.

Author: Eduard Kuzmenko. License: GPL v3.

Tech Stack

Layer Technology
UI Framework Solid.js (custom fork in src/vendor/solid/)
Language TypeScript 5.7
Build Vite 5
CSS SCSS (sass)
Testing Vitest
Package Manager pnpm 9
Protocol MTProto (custom implementation)
Storage IndexedDB + CacheStorage + localStorage
Workers SharedWorker + ServiceWorker

Development

pnpm install
pnpm start          # Dev server on :8080
pnpm build          # Production build → dist/
pnpm test           # Run tests (Vitest)
pnpm lint           # ESLint on src/**/*.ts

Debug query params: ?test=1 (test DCs), ?debug=1 (verbose logging), ?noSharedWorker=1 (disable shared worker).

Directory Structure

src/
├── components/       # Solid.js UI components (.tsx)
│   ├── chat/         # Chat bubbles, topbar, sidebars
│   ├── popups/       # Modal/popup components
│   ├── mediaEditor/  # Media editing UI
│   └── ...           # 200+ feature folders
├── lib/
│   ├── appManagers/  # 55+ domain managers (chats, users, messages, etc.)
│   ├── mtproto/      # MTProto protocol implementation
│   ├── storages/     # IndexedDB/localStorage wrappers
│   ├── rootScope.ts  # Global event emitter & app context
│   └── mainWorker/   # Background worker logic
├── stores/           # Solid.js reactive stores (13 stores)
├── helpers/          # 145+ utility functions
├── hooks/            # Solid.js hooks
├── pages/            # Auth pages (login, signup, etc.)
├── config/           # App constants, state schema, emoji, currencies
├── environment/      # Browser feature detection (39 modules)
├── scss/             # Global stylesheets
├── vendor/           # Third-party forks (solid, solid-transition-group)
├── scripts/          # Build & codegen scripts
└── tests/            # Test files

Path Aliases

Always use these aliases instead of relative paths:

@components/*    src/components/
@helpers/*       src/helpers/
@hooks/*         src/hooks/
@stores/*        src/stores/
@lib/*           src/lib/
@appManagers/*   src/lib/appManagers/
@environment/*   src/environment/
@config/*        src/config/
@vendor/*        src/vendor/
@layer           src/layer.d.ts    (MTProto API types)
@types           src/types.d.ts    (utility types)
@/*              src/

// Solid.js resolves to the custom fork:
solid-js         src/vendor/solid
solid-js/web     src/vendor/solid/web
solid-js/store   src/vendor/solid/store

Code Style (enforced by ESLint)

  • Indent: 2 spaces (no tabs)
  • Quotes: single quotes; template literals allowed
  • Line endings: Unix (LF); file must end with newline
  • No trailing spaces
  • Comma dangle: never ({a: 1, b: 2} not {a: 1, b: 2,})
  • Object/array spacing: no spaces inside braces/brackets
    • {a: 1} not { a: 1 }
    • [1, 2] not [ 1, 2 ]
  • Keyword spacing: no space after if, for, while, switch, catch
    • if(condition) not if (condition)
    • for(...) not for (...)
  • Function paren: no space before paren — function foo() not function foo ()
  • No return await: use return promise directly
  • Max 2 consecutive blank lines
  • prefer-const with destructuring: all

TypeScript Notes

  • strict: true but strictNullChecks: false and strictPropertyInitialization: false
  • useDefineForClassFields: false — important for class field behavior
  • jsxImportSource: solid-js — JSX is Solid.js, not React
  • MTProto types live in src/layer.d.ts (664KB, auto-generated); import from @layer
  • Utility types (AuthState, WorkerTask, etc.) live in src/types.d.ts; import from @types
  • Global types available everywhere: PeerId, UserId, ChatId, BotId, DocId, Long, Icon, ApiError, ErrorType, MaybePromise<T>. Defined in src/global.d.ts.

Key Patterns

Solid.js Components

Components are in .tsx files. Props typed inline. Use classNames() helper for class composition:

import {JSX} from 'solid-js';
import classNames from '@helpers/string/classNames';

export default function MyComponent(props: {
  class?: string,
  children: JSX.Element
}) {
  return (
    <div class={classNames('my-class', props.class)}>
      {props.children}
    </div>
  );
}

CSS Modules

Scoped styles use .module.scss files. Import as styles:

import styles from '@components/chat/bubbles/service.module.scss';
// Usage: <div class={styles.wrap}>

Solid.js Stores

Stores in src/stores/ use createRoot + createSignal and export a hook:

import {createRoot, createSignal} from 'solid-js';
import rootScope from '@lib/rootScope';

const [value, setValue] = createRoot(() => createSignal(initialValue));
rootScope.addEventListener('some_event', setValue);

export default function useValue() {
  return value;
}

App Managers

Business logic lives in AppManager subclasses in src/lib/appManagers/. They communicate via rootScope events and are accessed via rootScope.managers:

import {AppManager} from '@appManagers/manager';

export class AppSomethingManager extends AppManager {
  protected after() {
    // Initialization after state loaded
    this.apiUpdatesManager.addMultipleEventsListeners({...});
  }
}

Normally most of the interaction with MTProto should be done through the app managers, wrapping the raw APIs with a nicer interface, caching layer, etc. Managers are the source of truth.

Invoking MTProto methods is done via:

// invoke normally
await this.apiManager.invokeApi('payments.checkCanSendGift', {gift_id: gift.id})
// invoke with deduplication
await this.apiManager.invokeApiSingle('payments.checkCanSendGift', {gift_id: gift.id})
// invoke and do something with the result (only available inside managers)
return this.apiManager.invokeApiSingleProcess({
  method: 'some.method',
  params: {...},
  processResult: (result) => {
    // when the result type has {chats, users} fields, use this method to save them
    this.appUsersManager.saveApiPeers(result);
    // when the result is `Updates`, use this method to handle them
    this.apiUpdatesManager.processUpdateMessage(result);
  }
});

rootScope

Global event bus and context. Available everywhere:

import rootScope from '@lib/rootScope';

rootScope.addEventListener('premium_toggle', handler);
rootScope.managers.appChatsManager.getChat(chatId);

IMPORTANT: rootScope.managers.* are asynchronous proxies to a whared worker. Every manager method returns a Promise, even if the manager's own methods seem synchronous.

Imports from @layer

All MTProto types come from @layer:

import {Message, Chat, User, InputPeer} from '@layer';

CSS / SCSS

  • Global styles in src/scss/
  • Component-scoped styles in .module.scss next to component files
  • BEM-like class naming convention
  • CSS variables used for theming

Important Files

File Purpose
src/index.ts App entry point, account/auth init
src/lang.ts All i18n strings (232KB)
src/layer.d.ts MTProto API types (auto-generated, 664KB)
src/types.d.ts Utility/app types
src/global.d.ts Global interface augmentations
src/config/state.ts Application state schema
src/config/app.ts App constants
src/lib/rootScope.ts Global event emitter
vite.config.ts Build configuration
eslint.config.mjs ESLint flat config

What NOT to Do

  • Do not add eslint-disable without a reason
  • Do not use return await (rule enforced)
  • Do not use spaces inside {} for objects or [] for arrays
  • Do not use if ( with a space — use if(
  • Do not import from react or use React patterns — this is Solid.js
  • Do not use relative ../../ imports when an alias exists
  • Do not use var — use const/let
  • Do not add trailing commas in arrays/objects

Running Tests

pnpm test                  # all tests
pnpm test src/tests/foo    # specific test file

Vitest config: threads: false, globals: true, jsdom environment, setup in src/tests/setup.ts.

RTK (Rust Token Killer) - Token-Optimized Commands

Golden Rule

Always prefix commands with rtk. If RTK has a dedicated filter, it uses it. If not, it passes through unchanged. This means RTK is always safe to use.

Important: Even in command chains with &&, use rtk:

# ❌ Wrong
git add . && git commit -m "msg" && git push

# ✅ Correct
rtk git add . && rtk git commit -m "msg" && rtk git push

RTK Commands by Workflow

Build & Compile (80-90% savings)

rtk cargo build         # Cargo build output
rtk cargo check         # Cargo check output
rtk cargo clippy        # Clippy warnings grouped by file (80%)
rtk tsc                 # TypeScript errors grouped by file/code (83%)
rtk lint                # ESLint/Biome violations grouped (84%)
rtk prettier --check    # Files needing format only (70%)
rtk next build          # Next.js build with route metrics (87%)

Test (90-99% savings)

rtk cargo test          # Cargo test failures only (90%)
rtk vitest run          # Vitest failures only (99.5%)
rtk playwright test     # Playwright failures only (94%)
rtk test <cmd>          # Generic test wrapper - failures only

Git (59-80% savings)

rtk git status          # Compact status
rtk git log             # Compact log (works with all git flags)
rtk git diff            # Compact diff (80%)
rtk git show            # Compact show (80%)
rtk git add             # Ultra-compact confirmations (59%)
rtk git commit          # Ultra-compact confirmations (59%)
rtk git push            # Ultra-compact confirmations
rtk git pull            # Ultra-compact confirmations
rtk git branch          # Compact branch list
rtk git fetch           # Compact fetch
rtk git stash           # Compact stash
rtk git worktree        # Compact worktree

Note: Git passthrough works for ALL subcommands, even those not explicitly listed.

GitHub (26-87% savings)

rtk gh pr view <num>    # Compact PR view (87%)
rtk gh pr checks        # Compact PR checks (79%)
rtk gh run list         # Compact workflow runs (82%)
rtk gh issue list       # Compact issue list (80%)
rtk gh api              # Compact API responses (26%)

JavaScript/TypeScript Tooling (70-90% savings)

rtk pnpm list           # Compact dependency tree (70%)
rtk pnpm outdated       # Compact outdated packages (80%)
rtk pnpm install        # Compact install output (90%)
rtk npm run <script>    # Compact npm script output
rtk npx <cmd>           # Compact npx command output
rtk prisma              # Prisma without ASCII art (88%)

Files & Search (60-75% savings)

rtk ls <path>           # Tree format, compact (65%)
rtk read <file>         # Code reading with filtering (60%)
rtk grep <pattern>      # Search grouped by file (75%)
rtk find <pattern>      # Find grouped by directory (70%)

Analysis & Debug (70-90% savings)

rtk err <cmd>           # Filter errors only from any command
rtk log <file>          # Deduplicated logs with counts
rtk json <file>         # JSON structure without values
rtk deps                # Dependency overview
rtk env                 # Environment variables compact
rtk summary <cmd>       # Smart summary of command output
rtk diff                # Ultra-compact diffs

Infrastructure (85% savings)

rtk docker ps           # Compact container list
rtk docker images       # Compact image list
rtk docker logs <c>     # Deduplicated logs
rtk kubectl get         # Compact resource list
rtk kubectl logs        # Deduplicated pod logs

Network (65-70% savings)

rtk curl <url>          # Compact HTTP responses (70%)
rtk wget <url>          # Compact download output (65%)

Meta Commands

rtk gain                # View token savings statistics
rtk gain --history      # View command history with savings
rtk discover            # Analyze Claude Code sessions for missed RTK usage
rtk proxy <cmd>         # Run command without filtering (for debugging)
rtk init                # Add RTK instructions to CLAUDE.md
rtk init --global       # Add RTK to ~/.claude/CLAUDE.md

Token Savings Overview

Category Commands Typical Savings
Tests vitest, playwright, cargo test 90-99%
Build next, tsc, lint, prettier 70-87%
Git status, log, diff, add, commit 59-80%
GitHub gh pr, gh run, gh issue 26-87%
Package Managers pnpm, npm, npx 70-90%
Files ls, read, grep, find 60-75%
Infrastructure docker, kubectl 85%
Network curl, wget 65-70%

Overall average: 60-90% token reduction on common development operations.