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-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",
|
||||
|
||||
140
pnpm-lock.yaml
generated
140
pnpm-lock.yaml
generated
@@ -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
|
||||
|
||||
|
||||
126
src/tg/index.ts
126
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<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 {
|
||||
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,
|
||||
);
|
||||
},
|
||||
},
|
||||
};
|
||||
|
||||
@@ -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",
|
||||
|
||||
Reference in New Issue
Block a user