feat: update tg integration
All checks were successful
Deploy to VPS (dist) / deploy (push) Successful in 1m35s
All checks were successful
Deploy to VPS (dist) / deploy (push) Successful in 1m35s
This commit is contained in:
86
CLAUDE.local.md
Normal file
86
CLAUDE.local.md
Normal file
@@ -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: <agentId>` 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
|
||||||
@@ -21,7 +21,7 @@
|
|||||||
"@tanstack/react-query-devtools": "^5.91.3",
|
"@tanstack/react-query-devtools": "^5.91.3",
|
||||||
"@tanstack/react-router": "^1.166.3",
|
"@tanstack/react-router": "^1.166.3",
|
||||||
"@tanstack/react-router-devtools": "^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",
|
"arktype": "^2.2.0",
|
||||||
"axios": "^1.13.6",
|
"axios": "^1.13.6",
|
||||||
"clsx": "^2.1.1",
|
"clsx": "^2.1.1",
|
||||||
|
|||||||
140
pnpm-lock.yaml
generated
140
pnpm-lock.yaml
generated
@@ -29,9 +29,9 @@ importers:
|
|||||||
'@tanstack/react-router-devtools':
|
'@tanstack/react-router-devtools':
|
||||||
specifier: ^1.166.3
|
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)
|
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':
|
'@tma.js/sdk-react':
|
||||||
specifier: ^3.3.9
|
specifier: ^3.0.16
|
||||||
version: 3.3.9(@types/react@19.2.14)(react@19.2.4)(typescript@5.9.3)
|
version: 3.0.16(@types/react@19.2.14)(react@19.2.4)(typescript@5.9.3)
|
||||||
arktype:
|
arktype:
|
||||||
specifier: ^2.2.0
|
specifier: ^2.2.0
|
||||||
version: 2.2.0
|
version: 2.2.0
|
||||||
@@ -1192,15 +1192,11 @@ packages:
|
|||||||
resolution: {integrity: sha512-42WoRePf8v690qG8yGRe/YOh+oHni9vUaUUfoqlS91U2scd3a5rkLtVsc6b7z60w3RogH0I00vdrC5AaeiZ18w==}
|
resolution: {integrity: sha512-42WoRePf8v690qG8yGRe/YOh+oHni9vUaUUfoqlS91U2scd3a5rkLtVsc6b7z60w3RogH0I00vdrC5AaeiZ18w==}
|
||||||
engines: {node: '>=20.19'}
|
engines: {node: '>=20.19'}
|
||||||
|
|
||||||
'@telegram-apps/bridge@2.11.0':
|
'@tma.js/bridge@2.2.3':
|
||||||
resolution: {integrity: sha512-kBZjWRRp/lxKeQ8r8cDWUY9EjxUtyeh/9xTQjsjuGRsCR5XTO1cyVbvcvqzHn53csGx3aBs+fOR3Pk3b6w2JHg==}
|
resolution: {integrity: sha512-R+FQTxaFbQVBgtegfCvOU4SH1TcXhgGvFotNzrtsaRmiuPlvsMNSbtslfsysg0Yv3d6svAPAWJ1PJjimAopfag==}
|
||||||
deprecated: This package is not supported anymore. Use @tma.js/bridge instead
|
|
||||||
|
|
||||||
'@telegram-apps/navigation@1.0.14':
|
'@tma.js/sdk-react@3.0.16':
|
||||||
resolution: {integrity: sha512-bqNgF/J8Po7ZtsELm3E1a6aPr7awwxO3sIqD8J6u12urOlGoW5+1KxKKbkPa58mgXuQdsltd8apI+OVy0IYiUA==}
|
resolution: {integrity: sha512-/DhMV6jwLh2Yja/gGrZu4CTWt0enC1tbG6Bp0lfUUHK0x+9q90z+zCN0XuytNKk1gedZfmzpeTyR/4sroW2CLA==}
|
||||||
|
|
||||||
'@telegram-apps/sdk-react@3.3.9':
|
|
||||||
resolution: {integrity: sha512-85jF1ICT8sYCNzXu19SqJrfrS8XslsvV14KUcToiyL7H5ZMXHt0JQKM+QJgULjnLjEswweQ4/7Bd7mNULf/BIg==}
|
|
||||||
peerDependencies:
|
peerDependencies:
|
||||||
'@types/react': ^17.0.0 || ^18.0.0 || ^19.0.0
|
'@types/react': ^17.0.0 || ^18.0.0 || ^19.0.0
|
||||||
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':
|
'@types/react':
|
||||||
optional: true
|
optional: true
|
||||||
|
|
||||||
'@telegram-apps/sdk@3.11.8':
|
'@tma.js/sdk@3.1.7':
|
||||||
resolution: {integrity: sha512-vlpkYzMJCV9Cadsn9Q+/hbHNR39j5o96N9z4CjZ6AFHkkxOeOqVRrq9zRBw0gmffROkF2bU0WQxhRj8KZ/bPhw==}
|
resolution: {integrity: sha512-yHYqr+Gwj2wptmkceYAZ+ZPOV1Tv3f/UpJTkpngUt7shZg2vJQnZINnHC93iqznLo/Vqr15TO8UGzOdBQ7rhNA==}
|
||||||
|
|
||||||
'@telegram-apps/signals@1.1.2':
|
'@tma.js/signals@1.0.1':
|
||||||
resolution: {integrity: sha512-1P1kdCLX7MfETGPxH7f3UZKIsdE7Tz5S7QmN4Km1sbYQMakD5Bi1NecSMR7/wnHp50gWMI1JzENcMtCEmouhSg==}
|
resolution: {integrity: sha512-i2HUuwGqL4BmM5KAklAUhMhlEgUOF+F4nMHHS/zxrmD0upHE/0CiXCEdQxVeeOGN6e2RrKlonA40sDtR6OUDCw==}
|
||||||
|
|
||||||
'@telegram-apps/toolkit@2.1.3':
|
'@tma.js/toolkit@1.0.4':
|
||||||
resolution: {integrity: sha512-LPUBL7hxQTOr+Dowyk9a1O82nQS4ja4+OYiYWtvqq5nNUHC6Gbbus0zGWCbFcj9CLnIzaeb5HWOg5iSnhoRcyg==}
|
resolution: {integrity: sha512-6CDlkgc+43WD2jy6jog3B50yt9t+/wRwrN25zOa4iSw4IzfqoFjaQcJzTupBYaRxz19C3Rrir7p0/qStS/Z8vw==}
|
||||||
|
|
||||||
'@telegram-apps/transformers@2.2.6':
|
'@tma.js/transformers@1.1.3':
|
||||||
resolution: {integrity: sha512-MMBRs3demeBT9Cd614KKZmak7eEyNdEbfu99a0SwEEJe2oIODjJLrUxrhUcAOc5wvTRfrKka27VXVgruauLhdg==}
|
resolution: {integrity: sha512-zRL+fdo/NBpGqCJfl8ItAvcJIFT5Zy6UOYJwQPmUV5/gTHgmSvmGlrP43PeVi9XZ7Ggf4xbO6LUa4ehxozhMTA==}
|
||||||
deprecated: This package is not supported anymore. Use @tma.js/transfomers instead
|
|
||||||
|
|
||||||
'@telegram-apps/types@2.0.3':
|
'@tma.js/types@1.0.2':
|
||||||
resolution: {integrity: sha512-pXh9BdnLZF3e2BGc4WL+RTRMAUpqKpaSP3Rs8rB4WyRwIoRSGWFKE4gtT/9m42LGixB8YVwdo/pJ+9XO765XEA==}
|
resolution: {integrity: sha512-qs4mi+U1xZmMQBdMhWAo1X4YqUJ/ae0y28s+GNCpQq58bsJo0h8rvyVOB1RwPvXogIY9+yribbZe6z3AIJmsAQ==}
|
||||||
deprecated: This package is not supported anymore. Use @tma.js/types instead
|
|
||||||
|
|
||||||
'@traversable/json@0.0.26':
|
'@traversable/json@0.0.26':
|
||||||
resolution: {integrity: sha512-oXKX0eNxbbHGLjLV27nTuV0uyR6uSoWi0BF+FYJu4jXRcSsWqCHOqNjIb2x/0usKd70rnKLGyHxurlTBTpQVOw==}
|
resolution: {integrity: sha512-oXKX0eNxbbHGLjLV27nTuV0uyR6uSoWi0BF+FYJu4jXRcSsWqCHOqNjIb2x/0usKd70rnKLGyHxurlTBTpQVOw==}
|
||||||
@@ -1309,8 +1303,8 @@ packages:
|
|||||||
engines: {node: '>=6.0.0'}
|
engines: {node: '>=6.0.0'}
|
||||||
hasBin: true
|
hasBin: true
|
||||||
|
|
||||||
better-promises@0.4.1:
|
better-promises@1.0.0:
|
||||||
resolution: {integrity: sha512-cDW7eMvhvCoWzSih5o/OxsAgTUfP05yGMq77xNZUTmcZoNU9vEeFZJ+yJJi4lnocvxFrVFKsG0Yxt7ZnuYJEig==}
|
resolution: {integrity: sha512-gPgL2nRgeSbMIe3QpsYdKR3K0S9OZuphVuos60Eqsw8d/6GivOkyJ5D/zmnolJ6hzh7upnnflBUWUlQh4qpU2A==}
|
||||||
|
|
||||||
binary-extensions@2.3.0:
|
binary-extensions@2.3.0:
|
||||||
resolution: {integrity: sha512-Ceh+7ox5qe7LJuLHoY0feh3pHuUDHAcRUeyL2VYghZwfpkNIy/+8Ocg0a3UuSoYzavmylwuLWQOf3hl0jjMMIw==}
|
resolution: {integrity: sha512-Ceh+7ox5qe7LJuLHoY0feh3pHuUDHAcRUeyL2VYghZwfpkNIy/+8Ocg0a3UuSoYzavmylwuLWQOf3hl0jjMMIw==}
|
||||||
@@ -1424,8 +1418,8 @@ packages:
|
|||||||
resolution: {integrity: sha512-xUtoPkMggbz0MPyPiIWr1Kp4aeWJjDZ6SMvURhimjdZgsRuDplF5/s9hcgGhyXMhs+6vpnuoiZ2kFiu3FMnS8Q==}
|
resolution: {integrity: sha512-xUtoPkMggbz0MPyPiIWr1Kp4aeWJjDZ6SMvURhimjdZgsRuDplF5/s9hcgGhyXMhs+6vpnuoiZ2kFiu3FMnS8Q==}
|
||||||
engines: {node: '>=18'}
|
engines: {node: '>=18'}
|
||||||
|
|
||||||
error-kid@0.0.7:
|
error-kid@1.0.2:
|
||||||
resolution: {integrity: sha512-8mFs7ZaDWlBFgjOy4lHLMCe2+KZfZXGx5GOgh2VQ/M1CCIvSWzbl2OMl+5fdZgrgoUfhTeF+NPhmqfEvUhN8yw==}
|
resolution: {integrity: sha512-Xvq0ZrY/azCbREWKt9E/3mXDF0MkuEVVvHnOKutUhtq2O8pyneEixQ4nSFkA19Xfn+/OVSg//iVG0dxIDj7DIA==}
|
||||||
|
|
||||||
es-define-property@1.0.1:
|
es-define-property@1.0.1:
|
||||||
resolution: {integrity: sha512-e3nRfgfUZ4rNGL232gUgX06QNyyez04KdjFrF+LTRoOXmrOgFKDg4BCdsjW8EnT69eqdYGmRpJwiPVYNrCaW3g==}
|
resolution: {integrity: sha512-e3nRfgfUZ4rNGL232gUgX06QNyyez04KdjFrF+LTRoOXmrOgFKDg4BCdsjW8EnT69eqdYGmRpJwiPVYNrCaW3g==}
|
||||||
@@ -1486,6 +1480,9 @@ packages:
|
|||||||
resolution: {integrity: sha512-8RipRLol37bNs2bhoV67fiTEvdTrbMUYcFTiy3+wuuOnUog2QBHCZWXDRijWQfAkhBj2Uf5UnVaiWwA5vdd82w==}
|
resolution: {integrity: sha512-8RipRLol37bNs2bhoV67fiTEvdTrbMUYcFTiy3+wuuOnUog2QBHCZWXDRijWQfAkhBj2Uf5UnVaiWwA5vdd82w==}
|
||||||
engines: {node: '>= 6'}
|
engines: {node: '>= 6'}
|
||||||
|
|
||||||
|
fp-ts@2.16.11:
|
||||||
|
resolution: {integrity: sha512-LaI+KaX2NFkfn1ZGHoKCmcfv7yrZsC3b8NtWsTVQeHkq4F27vI5igUuO53sxqDEa2gNQMHFPmpojDw/1zmUK7w==}
|
||||||
|
|
||||||
framer-motion@12.35.1:
|
framer-motion@12.35.1:
|
||||||
resolution: {integrity: sha512-rL8cLrjYZNShZqKV3U0Qj6Y5WDiZXYEM5giiTLfEqsIZxtspzMDCkKmrO5po76jWfvOg04+Vk+sfBvTD0iMmLw==}
|
resolution: {integrity: sha512-rL8cLrjYZNShZqKV3U0Qj6Y5WDiZXYEM5giiTLfEqsIZxtspzMDCkKmrO5po76jWfvOg04+Vk+sfBvTD0iMmLw==}
|
||||||
peerDependencies:
|
peerDependencies:
|
||||||
@@ -2157,16 +2154,8 @@ packages:
|
|||||||
peerDependencies:
|
peerDependencies:
|
||||||
react: ^16.8.0 || ^17.0.0 || ^18.0.0 || ^19.0.0
|
react: ^16.8.0 || ^17.0.0 || ^18.0.0 || ^19.0.0
|
||||||
|
|
||||||
valibot@1.0.0:
|
valibot@1.3.0:
|
||||||
resolution: {integrity: sha512-1Hc0ihzWxBar6NGeZv7fPLY0QuxFMyxwYR2sF1Blu7Wq7EnremwY2W02tit2ij2VJT8HcSkHAQqmFfl77f73Yw==}
|
resolution: {integrity: sha512-SItIaOFnWYho/AcRU5gOtyfkTsuDTC3tRv+jy4/py8xERPnvHdM+ybD1iIqWTATVWG1nZetOfwZKq5upBjSqzw==}
|
||||||
peerDependencies:
|
|
||||||
typescript: '>=5'
|
|
||||||
peerDependenciesMeta:
|
|
||||||
typescript:
|
|
||||||
optional: true
|
|
||||||
|
|
||||||
valibot@1.0.0-beta.14:
|
|
||||||
resolution: {integrity: sha512-tLyV2rE5QL6U29MFy3xt4AqMrn+/HErcp2ZThASnQvPMwfSozjV1uBGKIGiegtZIGjinJqn0SlBdannf18wENA==}
|
|
||||||
peerDependencies:
|
peerDependencies:
|
||||||
typescript: '>=5'
|
typescript: '>=5'
|
||||||
peerDependenciesMeta:
|
peerDependenciesMeta:
|
||||||
@@ -3079,57 +3068,60 @@ snapshots:
|
|||||||
|
|
||||||
'@tanstack/virtual-file-routes@1.161.4': {}
|
'@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:
|
dependencies:
|
||||||
'@telegram-apps/signals': 1.1.2
|
'@tma.js/signals': 1.0.1
|
||||||
'@telegram-apps/toolkit': 2.1.3
|
'@tma.js/toolkit': 1.0.4
|
||||||
'@telegram-apps/transformers': 2.2.6(typescript@5.9.3)
|
'@tma.js/transformers': 1.1.3(typescript@5.9.3)
|
||||||
'@telegram-apps/types': 2.0.3
|
'@tma.js/types': 1.0.2
|
||||||
better-promises: 0.4.1
|
better-promises: 1.0.0
|
||||||
error-kid: 0.0.7
|
error-kid: 1.0.2
|
||||||
|
fp-ts: 2.16.11
|
||||||
mitt: 3.0.1
|
mitt: 3.0.1
|
||||||
valibot: 1.0.0(typescript@5.9.3)
|
valibot: 1.3.0(typescript@5.9.3)
|
||||||
transitivePeerDependencies:
|
transitivePeerDependencies:
|
||||||
- typescript
|
- typescript
|
||||||
|
|
||||||
'@telegram-apps/navigation@1.0.14': {}
|
'@tma.js/sdk-react@3.0.16(@types/react@19.2.14)(react@19.2.4)(typescript@5.9.3)':
|
||||||
|
|
||||||
'@telegram-apps/sdk-react@3.3.9(@types/react@19.2.14)(react@19.2.4)(typescript@5.9.3)':
|
|
||||||
dependencies:
|
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
|
react: 19.2.4
|
||||||
optionalDependencies:
|
optionalDependencies:
|
||||||
'@types/react': 19.2.14
|
'@types/react': 19.2.14
|
||||||
transitivePeerDependencies:
|
transitivePeerDependencies:
|
||||||
- typescript
|
- typescript
|
||||||
|
|
||||||
'@telegram-apps/sdk@3.11.8(typescript@5.9.3)':
|
'@tma.js/sdk@3.1.7(typescript@5.9.3)':
|
||||||
dependencies:
|
dependencies:
|
||||||
'@telegram-apps/bridge': 2.11.0(typescript@5.9.3)
|
'@tma.js/bridge': 2.2.3(typescript@5.9.3)
|
||||||
'@telegram-apps/navigation': 1.0.14
|
'@tma.js/signals': 1.0.1
|
||||||
'@telegram-apps/signals': 1.1.2
|
'@tma.js/toolkit': 1.0.4
|
||||||
'@telegram-apps/toolkit': 2.1.3
|
'@tma.js/transformers': 1.1.3(typescript@5.9.3)
|
||||||
'@telegram-apps/transformers': 2.2.6(typescript@5.9.3)
|
'@tma.js/types': 1.0.2
|
||||||
'@telegram-apps/types': 2.0.3
|
better-promises: 1.0.0
|
||||||
better-promises: 0.4.1
|
error-kid: 1.0.2
|
||||||
error-kid: 0.0.7
|
fp-ts: 2.16.11
|
||||||
valibot: 1.0.0(typescript@5.9.3)
|
valibot: 1.3.0(typescript@5.9.3)
|
||||||
transitivePeerDependencies:
|
transitivePeerDependencies:
|
||||||
- typescript
|
- typescript
|
||||||
|
|
||||||
'@telegram-apps/signals@1.1.2': {}
|
'@tma.js/signals@1.0.1': {}
|
||||||
|
|
||||||
'@telegram-apps/toolkit@2.1.3': {}
|
'@tma.js/toolkit@1.0.4':
|
||||||
|
|
||||||
'@telegram-apps/transformers@2.2.6(typescript@5.9.3)':
|
|
||||||
dependencies:
|
dependencies:
|
||||||
'@telegram-apps/toolkit': 2.1.3
|
better-promises: 1.0.0
|
||||||
'@telegram-apps/types': 2.0.3
|
fp-ts: 2.16.11
|
||||||
valibot: 1.0.0-beta.14(typescript@5.9.3)
|
|
||||||
|
'@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:
|
transitivePeerDependencies:
|
||||||
- typescript
|
- typescript
|
||||||
|
|
||||||
'@telegram-apps/types@2.0.3': {}
|
'@tma.js/types@1.0.2': {}
|
||||||
|
|
||||||
'@traversable/json@0.0.26(@traversable/registry@0.0.25)':
|
'@traversable/json@0.0.26(@traversable/registry@0.0.25)':
|
||||||
dependencies:
|
dependencies:
|
||||||
@@ -3213,9 +3205,9 @@ snapshots:
|
|||||||
|
|
||||||
baseline-browser-mapping@2.10.0: {}
|
baseline-browser-mapping@2.10.0: {}
|
||||||
|
|
||||||
better-promises@0.4.1:
|
better-promises@1.0.0:
|
||||||
dependencies:
|
dependencies:
|
||||||
error-kid: 0.0.7
|
error-kid: 1.0.2
|
||||||
|
|
||||||
binary-extensions@2.3.0: {}
|
binary-extensions@2.3.0: {}
|
||||||
|
|
||||||
@@ -3320,7 +3312,7 @@ snapshots:
|
|||||||
|
|
||||||
environment@1.1.0: {}
|
environment@1.1.0: {}
|
||||||
|
|
||||||
error-kid@0.0.7: {}
|
error-kid@1.0.2: {}
|
||||||
|
|
||||||
es-define-property@1.0.1: {}
|
es-define-property@1.0.1: {}
|
||||||
|
|
||||||
@@ -3390,6 +3382,8 @@ snapshots:
|
|||||||
hasown: 2.0.2
|
hasown: 2.0.2
|
||||||
mime-types: 2.1.35
|
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):
|
framer-motion@12.35.1(react-dom@19.2.4(react@19.2.4))(react@19.2.4):
|
||||||
dependencies:
|
dependencies:
|
||||||
motion-dom: 12.35.1
|
motion-dom: 12.35.1
|
||||||
@@ -4004,11 +3998,7 @@ snapshots:
|
|||||||
dependencies:
|
dependencies:
|
||||||
react: 19.2.4
|
react: 19.2.4
|
||||||
|
|
||||||
valibot@1.0.0(typescript@5.9.3):
|
valibot@1.3.0(typescript@5.9.3):
|
||||||
optionalDependencies:
|
|
||||||
typescript: 5.9.3
|
|
||||||
|
|
||||||
valibot@1.0.0-beta.14(typescript@5.9.3):
|
|
||||||
optionalDependencies:
|
optionalDependencies:
|
||||||
typescript: 5.9.3
|
typescript: 5.9.3
|
||||||
|
|
||||||
|
|||||||
120
src/tg/index.ts
120
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 = {
|
export const STORAGE_KEYS = {
|
||||||
authToken: "authToken",
|
authToken: "authToken",
|
||||||
} as const;
|
} as const;
|
||||||
export type StorageKey = (typeof STORAGE_KEYS)[keyof typeof STORAGE_KEYS];
|
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<Result> = {
|
||||||
|
ifAvailable: (...args: any[]) => { ok: true; data: Result } | { ok: false };
|
||||||
|
};
|
||||||
|
|
||||||
|
const isPromise = <T>(value: T | Promise<T>): value is Promise<T> =>
|
||||||
|
value && typeof value === "object" && "then" in value && typeof value.then === "function";
|
||||||
|
|
||||||
|
const promisify = <T>(value: T | Promise<T>): Promise<T> =>
|
||||||
|
isPromise(value) ? value : Promise.resolve(value);
|
||||||
|
|
||||||
|
const isTMA = () => tg.retrieveLaunchParams().tgWebAppStartParam !== MOCKED_START_PARAM;
|
||||||
|
|
||||||
|
const fallbackImplementation = <
|
||||||
|
T extends ((...args: any) => any) & WithChecks<any>,
|
||||||
|
Async extends boolean,
|
||||||
|
Params extends Parameters<T>,
|
||||||
|
Result extends T extends WithChecks<infer Result> ? Result : never,
|
||||||
|
F extends (...args: Params) => Async extends true ? Result | Awaited<Result> : Result,
|
||||||
|
>(
|
||||||
|
async: Async,
|
||||||
|
args: Params,
|
||||||
|
cb: T,
|
||||||
|
onErr: F,
|
||||||
|
): Async extends true ? Promise<Result> : Awaited<Result> => {
|
||||||
|
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<Result> : Awaited<Result>;
|
||||||
|
return promisify(returnValue).catch(() => onErr.apply(null, args)) as Async extends true
|
||||||
|
? Promise<Result>
|
||||||
|
: Awaited<Result>;
|
||||||
|
} else {
|
||||||
|
const result = onErr.apply(null, args);
|
||||||
|
return (async ? promisify(result) : result) as Async extends true
|
||||||
|
? Promise<Result>
|
||||||
|
: Awaited<Result>;
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
export default {
|
export default {
|
||||||
init: () => {
|
init: () => {
|
||||||
try {
|
|
||||||
tg.setDebug(import.meta.env.DEV);
|
tg.setDebug(import.meta.env.DEV);
|
||||||
tg.init({ acceptCustomStyles: true });
|
tg.init({ acceptCustomStyles: true });
|
||||||
tg.requestFullscreen();
|
tg.viewport.requestFullscreen.ifAvailable();
|
||||||
tg.disableVerticalSwipes();
|
tg.swipeBehavior.disableVertical.ifAvailable();
|
||||||
tg.expandViewport();
|
tg.viewport.expand.ifAvailable();
|
||||||
tg.setMiniAppHeaderColor("#000000");
|
tg.miniApp.setHeaderColor.ifAvailable("#000000");
|
||||||
} catch {
|
console.log(isTMA() ? "Telegram Mini App initialized" : "TMA Debug mode in Web initialized");
|
||||||
console.warn("Telegram SDK not available in browser.");
|
|
||||||
}
|
|
||||||
},
|
},
|
||||||
openLink(url: string | URL, options?: tg.OpenLinkOptions) {
|
openLink(url: string | URL, options?: tg.OpenLinkOptions) {
|
||||||
tg.openLink.ifAvailable(url, options);
|
tg.openLink.ifAvailable(url, options);
|
||||||
@@ -28,25 +93,32 @@ export default {
|
|||||||
},
|
},
|
||||||
initData: tg.initData,
|
initData: tg.initData,
|
||||||
storage: {
|
storage: {
|
||||||
clear() {
|
async clear() {
|
||||||
localStorage.clear();
|
return fallbackImplementation(true, [], tg.cloudStorage.clear, localStorage.clear);
|
||||||
tg.cloudStorage.clear.ifAvailable();
|
|
||||||
},
|
},
|
||||||
getItem(key: StorageKey, options?: tg.InvokeCustomMethodOptions) {
|
async getItem(key: StorageKey, options?: tg.InvokeCustomMethodFpOptions) {
|
||||||
return tg.cloudStorage
|
return fallbackImplementation(
|
||||||
.getItem(key, options)
|
true,
|
||||||
.catch(
|
[key, options],
|
||||||
() =>
|
tg.cloudStorage.getItem,
|
||||||
localStorage.getItem(key) ?? tg.AbortablePromise.reject(new Error("Item not found")),
|
(key) => localStorage.getItem(key) ?? "",
|
||||||
);
|
);
|
||||||
},
|
},
|
||||||
setItem(key: StorageKey, value: string, options?: tg.InvokeCustomMethodOptions) {
|
async setItem(key: StorageKey, value: string, options?: tg.InvokeCustomMethodFpOptions) {
|
||||||
localStorage.setItem(key, value);
|
return fallbackImplementation(
|
||||||
tg.cloudStorage.setItem.ifAvailable(key, value, options);
|
true,
|
||||||
|
[key, value, options],
|
||||||
|
tg.cloudStorage.setItem,
|
||||||
|
localStorage.setItem,
|
||||||
|
);
|
||||||
},
|
},
|
||||||
deleteItem(key: StorageKey, options?: tg.InvokeCustomMethodOptions) {
|
async deleteItem(key: StorageKey, options?: tg.InvokeCustomMethodFpOptions) {
|
||||||
tg.cloudStorage.deleteItem.ifAvailable(key, options);
|
return fallbackImplementation(
|
||||||
localStorage.removeItem(key);
|
true,
|
||||||
|
[key, options],
|
||||||
|
tg.cloudStorage.deleteItem,
|
||||||
|
localStorage.removeItem as typeof tg.cloudStorage.deleteItem,
|
||||||
|
);
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
};
|
};
|
||||||
|
|||||||
@@ -19,22 +19,6 @@ export default defineConfig({
|
|||||||
}),
|
}),
|
||||||
tanstackDevtools({
|
tanstackDevtools({
|
||||||
removeDevtoolsOnBuild: true,
|
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({
|
tanstackRouter({
|
||||||
target: "react",
|
target: "react",
|
||||||
|
|||||||
Reference in New Issue
Block a user