diff --git a/CLAUDE.local.md b/CLAUDE.local.md new file mode 100644 index 0000000..ce04bf2 --- /dev/null +++ b/CLAUDE.local.md @@ -0,0 +1,86 @@ +# Orchestrator Mode + +For tasks that require code changes, act as an orchestrator. Break down requests, delegate to agents, coordinate results. + +## Agents + +- `researcher` (Opus) - investigation, architecture analysis, web lookups +- `developer` (Sonnet) - implementation, bug fixes, tests +- `reviewer` (Sonnet) - code review after implementation + +## Workflow + +1. Clarify which project(s) are affected and the expected behavior if not obvious from the request +2. Dispatch `researcher` when the task touches unfamiliar code or multiple systems interact +3. Dispatch `developer` with research findings and the target project name(s) +4. Dispatch `reviewer` after implementation +5. Summarize results to the user + +Skip the researcher for tasks confined to a single file or component with obvious patterns. + +## Clarification Loops + +Agents cannot spawn other agents. When an agent reports questions or blockers during implementation: + +1. Save the agent's `agentId` from its return value +2. Dispatch `researcher` with the open question +3. **Resume** the blocked agent using `resume: ` with the researcher's findings — this continues the agent with its full prior context preserved + +## After Review + +When the reviewer requests changes: + +1. **Resume the developer** with the reviewer's blocking issues and ask it to summarize only what's relevant to those issues — changed files, design decisions, and approaches that were tried but didn't work +2. **Dispatch a fresh developer** with: the summary + the reviewer's issues list. The clean context lets it focus on fixes without carrying the full implementation history + +When the reviewer approves — done, no further action needed. + +## Rules + +- Never implement code yourself for non-trivial tasks. +- Always dispatch `reviewer` after implementation. +- Always specify the target project(s) when dispatching any agent. +- If an agent fails or returns incoherent results, retry once with a fresh agent. If it fails again, report to the user. +- Keep the user informed at each stage. + +## Project Context + +**honey-fe** — Telegram games project frontend (single SPA, no sub-projects). + +### Tech Stack + +- React 19 + TypeScript 5.9 (strict mode, `erasableSyntaxOnly`) +- Vite 7 + SWC (via `@vitejs/plugin-react-swc`) +- TanStack Router (file-based, auto code-splitting) + React Query +- Tailwind CSS v4 (via `@tailwindcss/vite` plugin) +- i18next + react-i18next (HTTP backend, locales in `public/locales/`, EN + RU) +- arktype for runtime validation +- motion (Framer Motion) for animations +- pnpm package manager + +### Path Aliases + +- `@/*` → `src/*` +- `@components/*` → `src/components/*` + +### Directory Layout + +``` +src/ + components/ — shared UI (atoms/, form/, icons/, modal/, modals/, surface/) + routes/ — TanStack file-based routes (game, apiary, cashdesk, earnings, roulette, shop, tasks) + styles/ — global CSS + fonts + i18next.ts — i18n runtime setup + main.tsx — app entry point +public/ + locales/ — translation JSON files (en.json, ru.json) + fonts/ +``` + +### Key Commands + +- `pnpm dev` — start dev server +- `pnpm build` — typecheck + production build +- `pnpm build:staging` — staging build +- `pnpm lint` / `pnpm lint:fix` — oxlint +- `pnpm fmt` / `pnpm fmt:check` — oxfmt diff --git a/package.json b/package.json index 3b148c8..e45b4a9 100644 --- a/package.json +++ b/package.json @@ -21,7 +21,7 @@ "@tanstack/react-query-devtools": "^5.91.3", "@tanstack/react-router": "^1.166.3", "@tanstack/react-router-devtools": "^1.166.3", - "@telegram-apps/sdk-react": "^3.3.9", + "@tma.js/sdk-react": "^3.0.16", "arktype": "^2.2.0", "axios": "^1.13.6", "clsx": "^2.1.1", diff --git a/pnpm-lock.yaml b/pnpm-lock.yaml index e8b4c7b..be0bced 100644 --- a/pnpm-lock.yaml +++ b/pnpm-lock.yaml @@ -29,9 +29,9 @@ importers: '@tanstack/react-router-devtools': specifier: ^1.166.3 version: 1.166.3(@tanstack/react-router@1.166.3(react-dom@19.2.4(react@19.2.4))(react@19.2.4))(@tanstack/router-core@1.166.2)(csstype@3.2.3)(react-dom@19.2.4(react@19.2.4))(react@19.2.4) - '@telegram-apps/sdk-react': - specifier: ^3.3.9 - version: 3.3.9(@types/react@19.2.14)(react@19.2.4)(typescript@5.9.3) + '@tma.js/sdk-react': + specifier: ^3.0.16 + version: 3.0.16(@types/react@19.2.14)(react@19.2.4)(typescript@5.9.3) arktype: specifier: ^2.2.0 version: 2.2.0 @@ -1192,15 +1192,11 @@ packages: resolution: {integrity: sha512-42WoRePf8v690qG8yGRe/YOh+oHni9vUaUUfoqlS91U2scd3a5rkLtVsc6b7z60w3RogH0I00vdrC5AaeiZ18w==} engines: {node: '>=20.19'} - '@telegram-apps/bridge@2.11.0': - resolution: {integrity: sha512-kBZjWRRp/lxKeQ8r8cDWUY9EjxUtyeh/9xTQjsjuGRsCR5XTO1cyVbvcvqzHn53csGx3aBs+fOR3Pk3b6w2JHg==} - deprecated: This package is not supported anymore. Use @tma.js/bridge instead + '@tma.js/bridge@2.2.3': + resolution: {integrity: sha512-R+FQTxaFbQVBgtegfCvOU4SH1TcXhgGvFotNzrtsaRmiuPlvsMNSbtslfsysg0Yv3d6svAPAWJ1PJjimAopfag==} - '@telegram-apps/navigation@1.0.14': - resolution: {integrity: sha512-bqNgF/J8Po7ZtsELm3E1a6aPr7awwxO3sIqD8J6u12urOlGoW5+1KxKKbkPa58mgXuQdsltd8apI+OVy0IYiUA==} - - '@telegram-apps/sdk-react@3.3.9': - resolution: {integrity: sha512-85jF1ICT8sYCNzXu19SqJrfrS8XslsvV14KUcToiyL7H5ZMXHt0JQKM+QJgULjnLjEswweQ4/7Bd7mNULf/BIg==} + '@tma.js/sdk-react@3.0.16': + resolution: {integrity: sha512-/DhMV6jwLh2Yja/gGrZu4CTWt0enC1tbG6Bp0lfUUHK0x+9q90z+zCN0XuytNKk1gedZfmzpeTyR/4sroW2CLA==} peerDependencies: '@types/react': ^17.0.0 || ^18.0.0 || ^19.0.0 react: ^17.0.0 || ^18.0.0 || ^19.0.0 @@ -1208,22 +1204,20 @@ packages: '@types/react': optional: true - '@telegram-apps/sdk@3.11.8': - resolution: {integrity: sha512-vlpkYzMJCV9Cadsn9Q+/hbHNR39j5o96N9z4CjZ6AFHkkxOeOqVRrq9zRBw0gmffROkF2bU0WQxhRj8KZ/bPhw==} + '@tma.js/sdk@3.1.7': + resolution: {integrity: sha512-yHYqr+Gwj2wptmkceYAZ+ZPOV1Tv3f/UpJTkpngUt7shZg2vJQnZINnHC93iqznLo/Vqr15TO8UGzOdBQ7rhNA==} - '@telegram-apps/signals@1.1.2': - resolution: {integrity: sha512-1P1kdCLX7MfETGPxH7f3UZKIsdE7Tz5S7QmN4Km1sbYQMakD5Bi1NecSMR7/wnHp50gWMI1JzENcMtCEmouhSg==} + '@tma.js/signals@1.0.1': + resolution: {integrity: sha512-i2HUuwGqL4BmM5KAklAUhMhlEgUOF+F4nMHHS/zxrmD0upHE/0CiXCEdQxVeeOGN6e2RrKlonA40sDtR6OUDCw==} - '@telegram-apps/toolkit@2.1.3': - resolution: {integrity: sha512-LPUBL7hxQTOr+Dowyk9a1O82nQS4ja4+OYiYWtvqq5nNUHC6Gbbus0zGWCbFcj9CLnIzaeb5HWOg5iSnhoRcyg==} + '@tma.js/toolkit@1.0.4': + resolution: {integrity: sha512-6CDlkgc+43WD2jy6jog3B50yt9t+/wRwrN25zOa4iSw4IzfqoFjaQcJzTupBYaRxz19C3Rrir7p0/qStS/Z8vw==} - '@telegram-apps/transformers@2.2.6': - resolution: {integrity: sha512-MMBRs3demeBT9Cd614KKZmak7eEyNdEbfu99a0SwEEJe2oIODjJLrUxrhUcAOc5wvTRfrKka27VXVgruauLhdg==} - deprecated: This package is not supported anymore. Use @tma.js/transfomers instead + '@tma.js/transformers@1.1.3': + resolution: {integrity: sha512-zRL+fdo/NBpGqCJfl8ItAvcJIFT5Zy6UOYJwQPmUV5/gTHgmSvmGlrP43PeVi9XZ7Ggf4xbO6LUa4ehxozhMTA==} - '@telegram-apps/types@2.0.3': - resolution: {integrity: sha512-pXh9BdnLZF3e2BGc4WL+RTRMAUpqKpaSP3Rs8rB4WyRwIoRSGWFKE4gtT/9m42LGixB8YVwdo/pJ+9XO765XEA==} - deprecated: This package is not supported anymore. Use @tma.js/types instead + '@tma.js/types@1.0.2': + resolution: {integrity: sha512-qs4mi+U1xZmMQBdMhWAo1X4YqUJ/ae0y28s+GNCpQq58bsJo0h8rvyVOB1RwPvXogIY9+yribbZe6z3AIJmsAQ==} '@traversable/json@0.0.26': resolution: {integrity: sha512-oXKX0eNxbbHGLjLV27nTuV0uyR6uSoWi0BF+FYJu4jXRcSsWqCHOqNjIb2x/0usKd70rnKLGyHxurlTBTpQVOw==} @@ -1309,8 +1303,8 @@ packages: engines: {node: '>=6.0.0'} hasBin: true - better-promises@0.4.1: - resolution: {integrity: sha512-cDW7eMvhvCoWzSih5o/OxsAgTUfP05yGMq77xNZUTmcZoNU9vEeFZJ+yJJi4lnocvxFrVFKsG0Yxt7ZnuYJEig==} + better-promises@1.0.0: + resolution: {integrity: sha512-gPgL2nRgeSbMIe3QpsYdKR3K0S9OZuphVuos60Eqsw8d/6GivOkyJ5D/zmnolJ6hzh7upnnflBUWUlQh4qpU2A==} binary-extensions@2.3.0: resolution: {integrity: sha512-Ceh+7ox5qe7LJuLHoY0feh3pHuUDHAcRUeyL2VYghZwfpkNIy/+8Ocg0a3UuSoYzavmylwuLWQOf3hl0jjMMIw==} @@ -1424,8 +1418,8 @@ packages: resolution: {integrity: sha512-xUtoPkMggbz0MPyPiIWr1Kp4aeWJjDZ6SMvURhimjdZgsRuDplF5/s9hcgGhyXMhs+6vpnuoiZ2kFiu3FMnS8Q==} engines: {node: '>=18'} - error-kid@0.0.7: - resolution: {integrity: sha512-8mFs7ZaDWlBFgjOy4lHLMCe2+KZfZXGx5GOgh2VQ/M1CCIvSWzbl2OMl+5fdZgrgoUfhTeF+NPhmqfEvUhN8yw==} + error-kid@1.0.2: + resolution: {integrity: sha512-Xvq0ZrY/azCbREWKt9E/3mXDF0MkuEVVvHnOKutUhtq2O8pyneEixQ4nSFkA19Xfn+/OVSg//iVG0dxIDj7DIA==} es-define-property@1.0.1: resolution: {integrity: sha512-e3nRfgfUZ4rNGL232gUgX06QNyyez04KdjFrF+LTRoOXmrOgFKDg4BCdsjW8EnT69eqdYGmRpJwiPVYNrCaW3g==} @@ -1486,6 +1480,9 @@ packages: resolution: {integrity: sha512-8RipRLol37bNs2bhoV67fiTEvdTrbMUYcFTiy3+wuuOnUog2QBHCZWXDRijWQfAkhBj2Uf5UnVaiWwA5vdd82w==} engines: {node: '>= 6'} + fp-ts@2.16.11: + resolution: {integrity: sha512-LaI+KaX2NFkfn1ZGHoKCmcfv7yrZsC3b8NtWsTVQeHkq4F27vI5igUuO53sxqDEa2gNQMHFPmpojDw/1zmUK7w==} + framer-motion@12.35.1: resolution: {integrity: sha512-rL8cLrjYZNShZqKV3U0Qj6Y5WDiZXYEM5giiTLfEqsIZxtspzMDCkKmrO5po76jWfvOg04+Vk+sfBvTD0iMmLw==} peerDependencies: @@ -2157,16 +2154,8 @@ packages: peerDependencies: react: ^16.8.0 || ^17.0.0 || ^18.0.0 || ^19.0.0 - valibot@1.0.0: - resolution: {integrity: sha512-1Hc0ihzWxBar6NGeZv7fPLY0QuxFMyxwYR2sF1Blu7Wq7EnremwY2W02tit2ij2VJT8HcSkHAQqmFfl77f73Yw==} - peerDependencies: - typescript: '>=5' - peerDependenciesMeta: - typescript: - optional: true - - valibot@1.0.0-beta.14: - resolution: {integrity: sha512-tLyV2rE5QL6U29MFy3xt4AqMrn+/HErcp2ZThASnQvPMwfSozjV1uBGKIGiegtZIGjinJqn0SlBdannf18wENA==} + valibot@1.3.0: + resolution: {integrity: sha512-SItIaOFnWYho/AcRU5gOtyfkTsuDTC3tRv+jy4/py8xERPnvHdM+ybD1iIqWTATVWG1nZetOfwZKq5upBjSqzw==} peerDependencies: typescript: '>=5' peerDependenciesMeta: @@ -3079,57 +3068,60 @@ snapshots: '@tanstack/virtual-file-routes@1.161.4': {} - '@telegram-apps/bridge@2.11.0(typescript@5.9.3)': + '@tma.js/bridge@2.2.3(typescript@5.9.3)': dependencies: - '@telegram-apps/signals': 1.1.2 - '@telegram-apps/toolkit': 2.1.3 - '@telegram-apps/transformers': 2.2.6(typescript@5.9.3) - '@telegram-apps/types': 2.0.3 - better-promises: 0.4.1 - error-kid: 0.0.7 + '@tma.js/signals': 1.0.1 + '@tma.js/toolkit': 1.0.4 + '@tma.js/transformers': 1.1.3(typescript@5.9.3) + '@tma.js/types': 1.0.2 + better-promises: 1.0.0 + error-kid: 1.0.2 + fp-ts: 2.16.11 mitt: 3.0.1 - valibot: 1.0.0(typescript@5.9.3) + valibot: 1.3.0(typescript@5.9.3) transitivePeerDependencies: - typescript - '@telegram-apps/navigation@1.0.14': {} - - '@telegram-apps/sdk-react@3.3.9(@types/react@19.2.14)(react@19.2.4)(typescript@5.9.3)': + '@tma.js/sdk-react@3.0.16(@types/react@19.2.14)(react@19.2.4)(typescript@5.9.3)': dependencies: - '@telegram-apps/sdk': 3.11.8(typescript@5.9.3) + '@tma.js/sdk': 3.1.7(typescript@5.9.3) react: 19.2.4 optionalDependencies: '@types/react': 19.2.14 transitivePeerDependencies: - typescript - '@telegram-apps/sdk@3.11.8(typescript@5.9.3)': + '@tma.js/sdk@3.1.7(typescript@5.9.3)': dependencies: - '@telegram-apps/bridge': 2.11.0(typescript@5.9.3) - '@telegram-apps/navigation': 1.0.14 - '@telegram-apps/signals': 1.1.2 - '@telegram-apps/toolkit': 2.1.3 - '@telegram-apps/transformers': 2.2.6(typescript@5.9.3) - '@telegram-apps/types': 2.0.3 - better-promises: 0.4.1 - error-kid: 0.0.7 - valibot: 1.0.0(typescript@5.9.3) + '@tma.js/bridge': 2.2.3(typescript@5.9.3) + '@tma.js/signals': 1.0.1 + '@tma.js/toolkit': 1.0.4 + '@tma.js/transformers': 1.1.3(typescript@5.9.3) + '@tma.js/types': 1.0.2 + better-promises: 1.0.0 + error-kid: 1.0.2 + fp-ts: 2.16.11 + valibot: 1.3.0(typescript@5.9.3) transitivePeerDependencies: - typescript - '@telegram-apps/signals@1.1.2': {} + '@tma.js/signals@1.0.1': {} - '@telegram-apps/toolkit@2.1.3': {} - - '@telegram-apps/transformers@2.2.6(typescript@5.9.3)': + '@tma.js/toolkit@1.0.4': dependencies: - '@telegram-apps/toolkit': 2.1.3 - '@telegram-apps/types': 2.0.3 - valibot: 1.0.0-beta.14(typescript@5.9.3) + better-promises: 1.0.0 + fp-ts: 2.16.11 + + '@tma.js/transformers@1.1.3(typescript@5.9.3)': + dependencies: + '@tma.js/toolkit': 1.0.4 + '@tma.js/types': 1.0.2 + fp-ts: 2.16.11 + valibot: 1.3.0(typescript@5.9.3) transitivePeerDependencies: - typescript - '@telegram-apps/types@2.0.3': {} + '@tma.js/types@1.0.2': {} '@traversable/json@0.0.26(@traversable/registry@0.0.25)': dependencies: @@ -3213,9 +3205,9 @@ snapshots: baseline-browser-mapping@2.10.0: {} - better-promises@0.4.1: + better-promises@1.0.0: dependencies: - error-kid: 0.0.7 + error-kid: 1.0.2 binary-extensions@2.3.0: {} @@ -3320,7 +3312,7 @@ snapshots: environment@1.1.0: {} - error-kid@0.0.7: {} + error-kid@1.0.2: {} es-define-property@1.0.1: {} @@ -3390,6 +3382,8 @@ snapshots: hasown: 2.0.2 mime-types: 2.1.35 + fp-ts@2.16.11: {} + framer-motion@12.35.1(react-dom@19.2.4(react@19.2.4))(react@19.2.4): dependencies: motion-dom: 12.35.1 @@ -4004,11 +3998,7 @@ snapshots: dependencies: react: 19.2.4 - valibot@1.0.0(typescript@5.9.3): - optionalDependencies: - typescript: 5.9.3 - - valibot@1.0.0-beta.14(typescript@5.9.3): + valibot@1.3.0(typescript@5.9.3): optionalDependencies: typescript: 5.9.3 diff --git a/src/tg/index.ts b/src/tg/index.ts index 8c1b790..960afa0 100644 --- a/src/tg/index.ts +++ b/src/tg/index.ts @@ -1,22 +1,87 @@ -import * as tg from "@telegram-apps/sdk-react"; +import * as tg from "@tma.js/sdk-react"; export const STORAGE_KEYS = { authToken: "authToken", } as const; export type StorageKey = (typeof STORAGE_KEYS)[keyof typeof STORAGE_KEYS]; +const MOCKED_START_PARAM = `debug+${Math.random().toString(36).substring(2, 15)}`; + +tg.mockTelegramEnv({ + launchParams: { + tgWebAppData: new URLSearchParams({ + user: JSON.stringify({ + id: 1, + first_name: "Pavel", + is_bot: false, + last_name: "Durov", + username: "durov", + language_code: "en", + is_premium: true, + photo_url: + "https://media4.giphy.com/media/v1.Y2lkPTZjMDliOTUyeXF1MzYyY2pwMjR2YWFhNDhqdXBsc216MWo2aW9pczNnNXM2ZmZmbCZlcD12MV9pbnRlcm5hbF9naWZfYnlfaWQmY3Q9Zw/xUPGcHc4I3wICqp8bu/giphy.gif", + added_to_attachment_menu: false, + allows_write_to_pm: true, + } satisfies tg.User), + hash: "", + signature: "", + auth_date: Date.now().toString(), + }), + tgWebAppStartParam: MOCKED_START_PARAM, + tgWebAppThemeParams: {}, + tgWebAppVersion: "8", + tgWebAppPlatform: "android", + }, +}); + +type WithChecks = { + ifAvailable: (...args: any[]) => { ok: true; data: Result } | { ok: false }; +}; + +const isPromise = (value: T | Promise): value is Promise => + value && typeof value === "object" && "then" in value && typeof value.then === "function"; + +const promisify = (value: T | Promise): Promise => + isPromise(value) ? value : Promise.resolve(value); + +const isTMA = () => tg.retrieveLaunchParams().tgWebAppStartParam !== MOCKED_START_PARAM; + +const fallbackImplementation = < + T extends ((...args: any) => any) & WithChecks, + Async extends boolean, + Params extends Parameters, + Result extends T extends WithChecks ? Result : never, + F extends (...args: Params) => Async extends true ? Result | Awaited : Result, +>( + async: Async, + args: Params, + cb: T, + onErr: F, +): Async extends true ? Promise : Awaited => { + if (isTMA()) { + const res = cb.ifAvailable.apply(null, args); + const returnValue = (res.ok ? res.data : onErr.apply(null, args)) as Result; + if (!async) return returnValue as Async extends true ? Promise : Awaited; + return promisify(returnValue).catch(() => onErr.apply(null, args)) as Async extends true + ? Promise + : Awaited; + } else { + const result = onErr.apply(null, args); + return (async ? promisify(result) : result) as Async extends true + ? Promise + : Awaited; + } +}; + export default { init: () => { - try { - tg.setDebug(import.meta.env.DEV); - tg.init({ acceptCustomStyles: true }); - tg.requestFullscreen(); - tg.disableVerticalSwipes(); - tg.expandViewport(); - tg.setMiniAppHeaderColor("#000000"); - } catch { - console.warn("Telegram SDK not available in browser."); - } + tg.setDebug(import.meta.env.DEV); + tg.init({ acceptCustomStyles: true }); + tg.viewport.requestFullscreen.ifAvailable(); + tg.swipeBehavior.disableVertical.ifAvailable(); + tg.viewport.expand.ifAvailable(); + tg.miniApp.setHeaderColor.ifAvailable("#000000"); + console.log(isTMA() ? "Telegram Mini App initialized" : "TMA Debug mode in Web initialized"); }, openLink(url: string | URL, options?: tg.OpenLinkOptions) { tg.openLink.ifAvailable(url, options); @@ -28,25 +93,32 @@ export default { }, initData: tg.initData, storage: { - clear() { - localStorage.clear(); - tg.cloudStorage.clear.ifAvailable(); + async clear() { + return fallbackImplementation(true, [], tg.cloudStorage.clear, localStorage.clear); }, - getItem(key: StorageKey, options?: tg.InvokeCustomMethodOptions) { - return tg.cloudStorage - .getItem(key, options) - .catch( - () => - localStorage.getItem(key) ?? tg.AbortablePromise.reject(new Error("Item not found")), - ); + async getItem(key: StorageKey, options?: tg.InvokeCustomMethodFpOptions) { + return fallbackImplementation( + true, + [key, options], + tg.cloudStorage.getItem, + (key) => localStorage.getItem(key) ?? "", + ); }, - setItem(key: StorageKey, value: string, options?: tg.InvokeCustomMethodOptions) { - localStorage.setItem(key, value); - tg.cloudStorage.setItem.ifAvailable(key, value, options); + async setItem(key: StorageKey, value: string, options?: tg.InvokeCustomMethodFpOptions) { + return fallbackImplementation( + true, + [key, value, options], + tg.cloudStorage.setItem, + localStorage.setItem, + ); }, - deleteItem(key: StorageKey, options?: tg.InvokeCustomMethodOptions) { - tg.cloudStorage.deleteItem.ifAvailable(key, options); - localStorage.removeItem(key); + async deleteItem(key: StorageKey, options?: tg.InvokeCustomMethodFpOptions) { + return fallbackImplementation( + true, + [key, options], + tg.cloudStorage.deleteItem, + localStorage.removeItem as typeof tg.cloudStorage.deleteItem, + ); }, }, }; diff --git a/vite.config.ts b/vite.config.ts index 6f32be0..403cf95 100644 --- a/vite.config.ts +++ b/vite.config.ts @@ -19,22 +19,6 @@ export default defineConfig({ }), tanstackDevtools({ removeDevtoolsOnBuild: true, - logging: true, - injectSource: { - enabled: true, - }, - editor: { - name: "WebStorm", - open: async (path, lineNumber, columnNumber) => { - const { exec } = await import("node:child_process"); - exec( - `webstorm -g "${path.replaceAll("$", "\\$")}${lineNumber ? `:${lineNumber}` : ""}${columnNumber ? `:${columnNumber}` : ""}"`, - ); - }, - }, - enhancedLogs: { - enabled: true, - }, }), tanstackRouter({ target: "react",