@www.hyperlinks.space/program-kit 1.2.3

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (87) hide show
  1. package/README.md +53 -0
  2. package/api/ai.ts +111 -0
  3. package/api/base.ts +117 -0
  4. package/api/blockchain.ts +58 -0
  5. package/api/bot.ts +19 -0
  6. package/api/ping.ts +41 -0
  7. package/api/releases.ts +162 -0
  8. package/api/telegram.ts +65 -0
  9. package/api/tsconfig.json +17 -0
  10. package/app/_layout.tsx +135 -0
  11. package/app/ai.tsx +39 -0
  12. package/app/components/GlobalBottomBar.tsx +447 -0
  13. package/app/components/GlobalBottomBarWeb.tsx +362 -0
  14. package/app/components/GlobalLogoBar.tsx +108 -0
  15. package/app/components/GlobalLogoBarFallback.tsx +66 -0
  16. package/app/components/GlobalLogoBarWithFallback.tsx +24 -0
  17. package/app/components/HyperlinksSpaceLogo.tsx +29 -0
  18. package/app/components/Telegram.tsx +648 -0
  19. package/app/components/telegramWebApp.ts +359 -0
  20. package/app/fonts.ts +12 -0
  21. package/app/index.tsx +102 -0
  22. package/app/theme.ts +117 -0
  23. package/app.json +60 -0
  24. package/assets/icon.ico +0 -0
  25. package/assets/images/favicon.png +0 -0
  26. package/blockchain/coffee.ts +217 -0
  27. package/blockchain/router.ts +44 -0
  28. package/bot/format.ts +143 -0
  29. package/bot/grammy.ts +52 -0
  30. package/bot/responder.ts +620 -0
  31. package/bot/webhook.ts +262 -0
  32. package/database/messages.ts +128 -0
  33. package/database/start.ts +133 -0
  34. package/database/users.ts +46 -0
  35. package/docs/ai_and_search_bar_input.md +94 -0
  36. package/docs/ai_bot_messages.md +124 -0
  37. package/docs/backlogs/medium_term_backlog.md +26 -0
  38. package/docs/backlogs/short_term_backlog.md +39 -0
  39. package/docs/blue_bar_tackling.md +143 -0
  40. package/docs/bot_async_streaming.md +174 -0
  41. package/docs/build_and_install.md +129 -0
  42. package/docs/database_messages.md +34 -0
  43. package/docs/fonts.md +18 -0
  44. package/docs/releases.md +201 -0
  45. package/docs/releases_github_actions.md +188 -0
  46. package/docs/scalability.md +34 -0
  47. package/docs/security_plan_raw.md +244 -0
  48. package/docs/security_raw.md +345 -0
  49. package/docs/timing_raw.md +63 -0
  50. package/docs/tma_logo_bar_jump_investigation.md +69 -0
  51. package/docs/update.md +205 -0
  52. package/docs/wallets_hosting_architecture.md +257 -0
  53. package/eas.json +47 -0
  54. package/eslint.config.js +10 -0
  55. package/fullREADME.md +159 -0
  56. package/global.css +67 -0
  57. package/npmReadMe.md +53 -0
  58. package/package.json +214 -0
  59. package/scripts/load-env.ts +17 -0
  60. package/scripts/migrate-db.ts +16 -0
  61. package/scripts/program-kit-init.cjs +58 -0
  62. package/scripts/run-bot-local.ts +30 -0
  63. package/scripts/set-webhook.ts +67 -0
  64. package/scripts/test-api-base.ts +12 -0
  65. package/telegram/post.ts +328 -0
  66. package/tsconfig.json +17 -0
  67. package/vercel.json +7 -0
  68. package/windows/after-sign-windows-icon.cjs +13 -0
  69. package/windows/build-layout.cjs +72 -0
  70. package/windows/build-with-progress.cjs +88 -0
  71. package/windows/build.cjs +2247 -0
  72. package/windows/cleanup-legacy-appdata-installs.ps1 +91 -0
  73. package/windows/cleanup-legacy-windows-shortcuts.ps1 +46 -0
  74. package/windows/cleanup.cjs +200 -0
  75. package/windows/embed-windows-exe-icon.cjs +55 -0
  76. package/windows/extractAppPackage.nsh +150 -0
  77. package/windows/forge/README.md +41 -0
  78. package/windows/forge/forge.config.js +138 -0
  79. package/windows/forge/make-with-stamp.cjs +65 -0
  80. package/windows/forge-cleanup.cjs +255 -0
  81. package/windows/hsp-app-process.ps1 +63 -0
  82. package/windows/installer-hooks.nsi +373 -0
  83. package/windows/product-brand.cjs +42 -0
  84. package/windows/remove-orphan-uninstall-registry.ps1 +67 -0
  85. package/windows/run-installed-with-icon-debug.cmd +20 -0
  86. package/windows/run-win-electron-builder.cjs +46 -0
  87. package/windows/updater-dialog.html +143 -0
package/fullREADME.md ADDED
@@ -0,0 +1,159 @@
1
+ # Welcome to your Expo app 👋
2
+ This is an [Expo](https://expo.dev) project created with [`create-expo-app`](https://www.npmjs.com/package/create-expo-app).
3
+
4
+ ## Get started
5
+
6
+ To start the app (and the Telegram bot in polling mode), run:
7
+
8
+ ```bash
9
+ npm run start
10
+ ```
11
+
12
+ This runs both the Expo dev server and the bot. For Expo only (no bot), use `npm run start:expo`.
13
+
14
+ ## Milestone snapshot package (npm)
15
+
16
+ This repository includes a publishable snapshot package for fast developer bootstrap:
17
+
18
+ - package source: `app/` (published directly, no duplicate snapshot folder)
19
+ - **npmjs (public):** `@www.hyperlinks.space/program-kit` — manage org and tokens: [www.hyperlinks.space on npm](https://www.npmjs.com/settings/www.hyperlinks.space/packages)
20
+ - **GitHub Packages:** `@hyperlinksspace/program-kit` (same version; GitHub requires the package scope to match this repo’s owner)
21
+
22
+ **npm ownership:** your token must be allowed to publish under scope `@www.hyperlinks.space` (org members or automation token with access to that org).
23
+
24
+ ### Verify publish payload locally
25
+
26
+ The npm package page uses `README.md` from the published tarball, not `npmReadMe.md`. The published package also includes **`fullREADME.md`**, a copy of this developer readme (saved before the npm readme replaces `README.md`). Match CI before `npm pack`, then restore:
27
+
28
+ ```bash
29
+ cp README.md fullREADME.md
30
+ cp npmReadMe.md README.md
31
+ npm pack --dry-run
32
+ git checkout -- README.md
33
+ rm -f fullREADME.md
34
+ ```
35
+
36
+ ### Install snapshot as a developer
37
+
38
+ ```bash
39
+ npx @www.hyperlinks.space/program-kit ./my-hsp-app
40
+ ```
41
+
42
+ The CLI materializes the bundled package payload into your target folder, then you run:
43
+
44
+ ```bash
45
+ cd my-hsp-app
46
+ npm install
47
+ ```
48
+
49
+ ### Release channels
50
+
51
+ - `latest`: immutable stable snapshots (tag workflow `snapshot-vX.Y.Z`)
52
+ - `next`: rolling snapshots from manual workflow dispatch
53
+
54
+ In the output, you'll find options to open the app in:
55
+
56
+ - [a development build](https://docs.expo.dev/develop/development-builds/introduction/)
57
+ - [an Android emulator](https://docs.expo.dev/workflow/android-studio-emulator/)
58
+ - [an iOS simulator](https://docs.expo.dev/workflow/ios-simulator/)
59
+ - [Expo Go](https://expo.dev/go), a limited sandbox for trying out app development with Expo
60
+
61
+ You can start developing by editing the files inside the **app** directory. This project uses [file-based routing](https://docs.expo.dev/router/introduction).
62
+
63
+ ### Local env setup
64
+
65
+ 1. **Copy the example file** (from the `app/` directory):
66
+ ```bash
67
+ cp .env.example .env
68
+ ```
69
+ 2. **Edit `.env`** and set at least:
70
+ - **`BOT_TOKEN`** – if you run the Telegram bot locally (`npm run bot:local`).
71
+ 3. **Expo app** – `npx expo start` reads env from the environment; for app-only env vars you can also put them in `.env` and use an Expo-compatible loader if you add one, or set them in the shell before running:
72
+ ```bash
73
+ export BOT_TOKEN=your_token
74
+ npx expo start
75
+ ```
76
+ 4. **Bot local** – `npm run bot:local` loads `.env` from the project root (optional; you can also set `BOT_TOKEN` in the shell).
77
+
78
+ The `.env` file is gitignored; do not commit it.
79
+
80
+ ## Workflows
81
+
82
+ This project is configured to use [EAS Workflows](https://docs.expo.dev/eas/workflows/get-started/) to automate some development and release processes. These commands are set up in [`package.json`](./package.json) and can be run using NPM scripts in your terminal.
83
+
84
+ ### Previews
85
+
86
+ Run `npm run draft` to [publish a preview update](https://docs.expo.dev/eas/workflows/examples/publish-preview-update/) of your project, which can be viewed in Expo Go or in a development build.
87
+
88
+ ### Development Builds
89
+
90
+ Run `npm run development-builds` to [create a development build](https://docs.expo.dev/eas/workflows/examples/create-development-builds/). Note - you'll need to follow the [Prerequisites](https://docs.expo.dev/eas/workflows/examples/create-development-builds/#prerequisites) to ensure you have the correct emulator setup on your machine.
91
+
92
+ ### Production Deployments
93
+
94
+ Run `npm run deploy` to [deploy to production](https://docs.expo.dev/eas/workflows/examples/deploy-to-production/). Note - you'll need to follow the [Prerequisites](https://docs.expo.dev/eas/workflows/examples/deploy-to-production/#prerequisites) to ensure you're set up to submit to the Apple and Google stores.
95
+
96
+ ## Hosting
97
+
98
+ Expo offers hosting for websites and API functions via EAS Hosting. See the [Getting Started](https://docs.expo.dev/eas/hosting/get-started/) guide to learn more.
99
+
100
+ ### Deploy web build to Vercel
101
+
102
+ From this directory (`app/`), deploy the static web build to Vercel production:
103
+
104
+ ```bash
105
+ vercel --prod
106
+ ```
107
+
108
+ Deploying from `app/` makes this folder the project root, so `api/bot` is deployed and no Root Directory setting is needed. The project is configured so Vercel runs `npx expo export -p web` and serves the `dist/` output. Link the project first with `vercel` if needed.
109
+
110
+ ### Telegram bot (Grammy)
111
+
112
+ A minimal bot that replies "Hello" is included. It is deployable on Vercel via webhook and runnable locally with getUpdates.
113
+
114
+ **Vercel (webhook)**
115
+ - **Env for deploy:** In Vercel → **Settings → Environment Variables** add **`BOT_TOKEN`** (or `TELEGRAM_BOT_TOKEN`). Assign to **Production** (and to **Build** if your dashboard has that option) so the deploy-step webhook script can run. The webhook URL is built from Vercel’s `VERCEL_PROJECT_PRODUCTION_URL` or `VERCEL_URL`.
116
+ - **Webhook on deploy:** Each build runs `scripts/set-webhook.ts` and calls Telegram `setWebhook` with the base URL + `/api/bot`. If the script fails (e.g. missing URL or Telegram error), the build fails so you see the error in the deploy log.
117
+ - Telegram sends updates to **POST** `/api/bot`; the bot replies "Hello".
118
+
119
+ **Bot works locally but not on Vercel**
120
+ 1. Open **GET** `https://<your-app>.vercel.app/api/bot` in a browser. The JSON shows:
121
+ - `bot: true` → BOT_TOKEN is set; `bot: false` → add BOT_TOKEN in Vercel → Settings → Environment Variables (Production), then redeploy.
122
+ - `expected_url` → URL we use for the webhook (from VERCEL_PROJECT_PRODUCTION_URL or VERCEL_URL).
123
+ - `telegram_has` → URL Telegram actually has. It must match your production URL (e.g. `https://hsbexpo.vercel.app/api/bot`). If it’s `(none)` or different, ensure the project’s production domain is set in Vercel and redeploy so set-webhook.ts runs with the correct URL.
124
+ - `webhook_set: true` → last setWebhook call succeeded.
125
+ 2. **Root directory:** Only needed if you deploy via Git (auto-deploy from the repo). Then set **Root Directory** to **`app`** in Vercel → Project Settings → General. If you always run `vercel --prod` from inside `app/`, the CLI uses this folder as the project root and you don’t need to set it.
126
+ 3. **Logs:** After sending /start, check **Logs** for `[webhook] POST update` and any `[bot]` errors (e.g. handler_error, timeout).
127
+ 4. Don’t run the same bot in polling locally while testing the webhook (or Telegram may deliver updates to the wrong place).
128
+
129
+ **Local (getUpdates, no webhook)**
130
+ - Only `BOT_TOKEN` is required (in env or `.env`).
131
+ - Run the bot in polling mode (do not use the same token with webhook set elsewhere):
132
+ ```bash
133
+ npx tsx scripts/run-bot-local.ts
134
+ ```
135
+ - `npm run start` runs both Expo and the bot; or run the bot alone with `npm run bot:local`.
136
+
137
+ ## Get a fresh project
138
+
139
+ When you're ready, run:
140
+
141
+ ```bash
142
+ npm run reset-project
143
+ ```
144
+
145
+ This command will move the starter code to the **app-example** directory and create a blank **app** directory where you can start developing.
146
+
147
+ ## Learn more
148
+
149
+ To learn more about developing your project with Expo, look at the following resources:
150
+
151
+ - [Expo documentation](https://docs.expo.dev/): Learn fundamentals, or go into advanced topics with our [guides](https://docs.expo.dev/guides).
152
+ - [Learn Expo tutorial](https://docs.expo.dev/tutorial/introduction/): Follow a step-by-step tutorial where you'll create a project that runs on Android, iOS, and the web.
153
+
154
+ ## Join the community
155
+
156
+ Join our community of developers creating universal apps.
157
+
158
+ - [Expo on GitHub](https://github.com/expo/expo): View our open source platform and contribute.
159
+ - [Discord community](https://chat.expo.dev): Chat with Expo users and ask questions.
package/global.css ADDED
@@ -0,0 +1,67 @@
1
+ /* Global web-only overrides */
2
+
3
+ /* Lock the app column to the viewport so the whole block is not scrollable (avoids logo bar jump in TMA when keyboard opens). */
4
+ html {
5
+ height: 100%;
6
+ overflow: hidden;
7
+ overscroll-behavior: none;
8
+ background-color: var(--tg-theme-bg-color, transparent);
9
+ }
10
+ body {
11
+ height: var(--tg-viewport-height, 100%);
12
+ min-height: var(--tg-viewport-height, 100%);
13
+ overflow: hidden;
14
+ overscroll-behavior: none;
15
+ /* TMA: Telegram sets --tg-theme-bg-color early; fills gap before React shows the app (no dark flash). */
16
+ background-color: var(--tg-theme-bg-color, transparent);
17
+ }
18
+
19
+ /* TMA: --tg-viewport-height is set and updated by TMA SDK viewport.bindCssVars() on viewport_changed only. */
20
+ #root,
21
+ [data-expo-root] {
22
+ height: var(--tg-viewport-height, 100%);
23
+ min-height: var(--tg-viewport-height, 100%);
24
+ overflow: hidden;
25
+ background-color: var(--tg-theme-bg-color, transparent);
26
+ }
27
+
28
+ /* Hide native textarea scrollbars (React Native Web TextInput) while keeping scroll behaviour. */
29
+ textarea {
30
+ -ms-overflow-style: none; /* IE and Edge */
31
+ scrollbar-width: none; /* Firefox */
32
+ }
33
+
34
+ textarea::-webkit-scrollbar {
35
+ display: none; /* Chrome, Safari, Opera */
36
+ }
37
+
38
+ /* Make the AI & Search textarea truly 20px tall for one line */
39
+ textarea[data-ai-input="true"] {
40
+ min-height: 20px !important;
41
+ height: 20px !important;
42
+ line-height: 20px !important;
43
+ padding-top: 0 !important;
44
+ padding-bottom: 0 !important;
45
+ border: none !important;
46
+ box-sizing: content-box;
47
+ }
48
+
49
+ /* GlobalBottomBarWeb: placeholder + same font stack as inline (see app/fonts.ts). */
50
+ [data-global-bottom-bar-web] {
51
+ -ms-overflow-style: none;
52
+ scrollbar-width: none;
53
+ background-color: transparent !important;
54
+ font-family: Aeroport, ui-sans-serif, system-ui, -apple-system, BlinkMacSystemFont, "Segoe UI",
55
+ Roboto, "Helvetica Neue", Arial, sans-serif !important;
56
+ }
57
+
58
+ [data-global-bottom-bar-web]::-webkit-scrollbar {
59
+ width: 0;
60
+ height: 0;
61
+ }
62
+
63
+ [data-global-bottom-bar-web]::placeholder {
64
+ color: var(--ai-placeholder-color, #fafafa);
65
+ opacity: 1;
66
+ }
67
+
package/npmReadMe.md ADDED
@@ -0,0 +1,53 @@
1
+ # Program Kit
2
+
3
+ Program Kit is a production-ready cross-platform starter published from `app/`.
4
+ It is built around React Native + Expo and is designed to be quickly tested, scaled,
5
+ and deployed across popular platforms.
6
+
7
+ ## What You Get
8
+
9
+ - Expo + React Native app foundation
10
+ - Telegram bot support (webhook + local bot scripts)
11
+ - Telegram Mini App-ready client structure
12
+ - Android and iOS workflow scripts
13
+ - Windows desktop packaging (`.exe`) with Electron Builder
14
+ - CI-oriented release workflow and deployment helpers
15
+
16
+ ## Install
17
+
18
+ ### npmjs (public)
19
+
20
+ ```bash
21
+ npx @www.hyperlinks.space/program-kit ./my-new-program
22
+ ```
23
+
24
+ ### GitHub Packages
25
+
26
+ ```bash
27
+ npx @hyperlinksspace/program-kit ./my-new-program
28
+ ```
29
+
30
+ If you install from GitHub Packages, configure `.npmrc` with the `@hyperlinksspace`
31
+ registry and token.
32
+
33
+ ## After Scaffold
34
+
35
+ ```bash
36
+ cd my-new-program
37
+ npm install
38
+ npm run start
39
+ ```
40
+
41
+ Then open the project `README.md` for full setup details (env vars, bot setup, build
42
+ and release commands).
43
+
44
+ ## Release Channels
45
+
46
+ - `latest` for stable milestone snapshots
47
+ - `next` for rolling preview snapshots
48
+
49
+ ## Notes
50
+
51
+ - Published directly from the `app/` folder.
52
+ - Package tarball is filtered to include only required project files.
53
+ - **`fullREADME.md`** in the package is the full in-repo developer guide (Expo setup, scripts, and the rest of the project readme).
package/package.json ADDED
@@ -0,0 +1,214 @@
1
+ {
2
+ "name": "@www.hyperlinks.space/program-kit",
3
+ "productName": "Hyperlinks Space Program",
4
+ "description": "Hyperlinks Space Program",
5
+ "author": "sraibaby",
6
+ "license": "0BSD",
7
+ "private": false,
8
+ "bin": {
9
+ "program-kit": "scripts/program-kit-init.cjs"
10
+ },
11
+ "files": [
12
+ "README.md",
13
+ "fullREADME.md",
14
+ "npmReadMe.md",
15
+ "app",
16
+ "api",
17
+ "app.json",
18
+ "assets",
19
+ "blockchain",
20
+ "bot",
21
+ "database",
22
+ "docs",
23
+ "!docs/debug.log",
24
+ "!docs/issue.md",
25
+ "eas.json",
26
+ "eslint.config.js",
27
+ "global.css",
28
+ "package-lock.json",
29
+ "scripts",
30
+ "telegram",
31
+ "tsconfig.json",
32
+ "vercel.json",
33
+ "windows"
34
+ ],
35
+ "publishConfig": {
36
+ "access": "public"
37
+ },
38
+ "repository": {
39
+ "type": "git",
40
+ "url": "https://github.com/HyperlinksSpace/HyperlinksSpaceBot.git"
41
+ },
42
+ "main": "expo-router/entry",
43
+ "version": "1.2.3",
44
+ "type": "module",
45
+ "engines": {
46
+ "node": ">=18 <=22"
47
+ },
48
+ "config": {
49
+ "forge": "./windows/forge/forge.config.js"
50
+ },
51
+ "scripts": {
52
+ "prestart": "npm run db:migrate",
53
+ "build": "expo export -p web",
54
+ "start": "npx concurrently -n expo,bot,vercel \"expo start\" \"npx tsx scripts/run-bot-local.ts\" \"npm run dev:vercel\"",
55
+ "start:expo": "expo start",
56
+ "reset-project": "node ./scripts/reset-project.js",
57
+ "android": "expo start --android",
58
+ "ios": "expo start --ios",
59
+ "web": "expo start --web",
60
+ "dev:vercel": "cross-env TS_NODE_PROJECT=api/tsconfig.json npx vercel dev",
61
+ "lint": "expo lint",
62
+ "draft": "npx eas-cli@latest workflow:run create-draft.yml",
63
+ "development-builds": "npx eas-cli@latest workflow:run create-development-builds.yml",
64
+ "deploy": "npx eas-cli@latest workflow:run deploy-to-production.yml",
65
+ "deploy:vercel": "npx vercel --prod",
66
+ "bot:local": "npx tsx scripts/run-bot-local.ts",
67
+ "set-webhook": "npx tsx scripts/set-webhook.ts",
68
+ "db:migrate": "npx tsx scripts/migrate-db.ts",
69
+ "build:win": "node windows/build-with-progress.cjs",
70
+ "build:win:raw": "npm run build && node windows/run-win-electron-builder.cjs",
71
+ "pack:win": "node windows/build-with-progress.cjs --pack",
72
+ "pack:win:raw": "node windows/run-win-electron-builder.cjs",
73
+ "build:win:dir": "npm run build && electron-builder --win --publish never --config.win.target=dir",
74
+ "build:win:verbose": "node windows/build-with-progress.cjs --verbose",
75
+ "make:win:forge": "npm run build && node windows/forge/make-with-stamp.cjs",
76
+ "make:win:forge:verbose": "npm run build && node windows/forge/make-with-stamp.cjs --verbose",
77
+ "run:win:installed-icon-debug": "windows/run-installed-with-icon-debug.cmd",
78
+ "version:bump": "npm version patch --no-git-tag-version",
79
+ "version:bump-minor": "npm version minor --no-git-tag-version",
80
+ "version:bump-major": "npm version major --no-git-tag-version"
81
+ },
82
+ "build": {
83
+ "appId": "com.sraibaby.app",
84
+ "productName": "Hyperlinks Space Program",
85
+ "icon": "assets/icon.ico",
86
+ "asar": {
87
+ "smartUnpack": true
88
+ },
89
+ "asarUnpack": [
90
+ "**/*.node",
91
+ "**/*.dll",
92
+ "**/*.exe",
93
+ "assets/icon.ico"
94
+ ],
95
+ "extraResources": [
96
+ {
97
+ "from": "assets/icon.ico",
98
+ "to": "."
99
+ }
100
+ ],
101
+ "extraMetadata": {
102
+ "main": "windows/build.cjs"
103
+ },
104
+ "files": [
105
+ "dist/**/*",
106
+ "windows/**",
107
+ "assets/icon.ico"
108
+ ],
109
+ "afterSign": "windows/after-sign-windows-icon.cjs",
110
+ "win": {
111
+ "icon": "assets/icon.ico",
112
+ "signAndEditExecutable": true,
113
+ "artifactName": "HyperlinksSpaceProgram_${version}.${ext}",
114
+ "target": [
115
+ {
116
+ "target": "nsis",
117
+ "arch": [
118
+ "x64"
119
+ ]
120
+ },
121
+ {
122
+ "target": "zip",
123
+ "arch": [
124
+ "x64"
125
+ ]
126
+ }
127
+ ]
128
+ },
129
+ "nsis": {
130
+ "artifactName": "HyperlinksSpaceProgramInstaller_${env.BUILD_STAMP}.${ext}",
131
+ "include": "installer-hooks.nsi",
132
+ "installerIcon": "assets/icon.ico",
133
+ "uninstallerIcon": "assets/icon.ico",
134
+ "installerHeaderIcon": "assets/icon.ico",
135
+ "guid": "5e1f4a8d-9c64-4e6a-a7d1-2a2fd2f01b0f",
136
+ "oneClick": false,
137
+ "runAfterFinish": true,
138
+ "perMachine": true,
139
+ "allowElevation": true,
140
+ "allowToChangeInstallationDirectory": false,
141
+ "warningsAsErrors": false,
142
+ "deleteAppDataOnUninstall": true
143
+ },
144
+ "directories": {
145
+ "output": "releases/artifacts",
146
+ "buildResources": "windows"
147
+ },
148
+ "publish": {
149
+ "provider": "github",
150
+ "owner": "HyperlinksSpace",
151
+ "repo": "HyperlinksSpaceProgram"
152
+ }
153
+ },
154
+ "dependencies": {
155
+ "@expo/metro-runtime": "~6.1.2",
156
+ "@expo/vector-icons": "^15.0.2",
157
+ "@neondatabase/api-client": "^2.7.0",
158
+ "@neondatabase/serverless": "^1.0.2",
159
+ "@react-navigation/bottom-tabs": "^7.3.10",
160
+ "@react-navigation/elements": "^2.3.8",
161
+ "@react-navigation/native": "^7.1.6",
162
+ "@swap-coffee/sdk": "^1.5.4",
163
+ "@tma.js/sdk-react": "^3.0.16",
164
+ "electron-updater": "^6.8.3",
165
+ "expo": "~54.0.0",
166
+ "expo-blur": "~15.0.8",
167
+ "expo-constants": "~18.0.13",
168
+ "expo-font": "~14.0.11",
169
+ "expo-haptics": "~15.0.8",
170
+ "expo-image": "~3.0.11",
171
+ "expo-linking": "~8.0.11",
172
+ "expo-router": "~6.0.23",
173
+ "expo-splash-screen": "~31.0.13",
174
+ "expo-status-bar": "~3.0.9",
175
+ "expo-symbols": "~1.0.8",
176
+ "expo-system-ui": "~6.0.9",
177
+ "expo-updates": "~29.0.16",
178
+ "expo-web-browser": "~15.0.10",
179
+ "extract-zip": "^2.0.1",
180
+ "grammy": "^1.34.0",
181
+ "openai": "^6.25.0",
182
+ "react": "19.1.0",
183
+ "react-dom": "19.1.0",
184
+ "react-native": "0.81.5",
185
+ "react-native-gesture-handler": "~2.28.0",
186
+ "react-native-reanimated": "~4.1.1",
187
+ "react-native-safe-area-context": "~5.6.2",
188
+ "react-native-screens": "~4.16.0",
189
+ "react-native-svg": "^15.15.3",
190
+ "react-native-web": "^0.21.0",
191
+ "react-native-webview": "13.15.0",
192
+ "react-native-worklets": "0.5.1"
193
+ },
194
+ "devDependencies": {
195
+ "@babel/core": "^7.25.2",
196
+ "@electron-forge/cli": "^7.11.1",
197
+ "@electron-forge/maker-zip": "^7.11.1",
198
+ "@felixrieseberg/electron-forge-maker-nsis": "^7.2.0",
199
+ "@types/react": "~19.1.0",
200
+ "@vercel/functions": "^3.4.3",
201
+ "concurrently": "^9.1.0",
202
+ "cross-env": "^7.0.3",
203
+ "dotenv": "^16.4.5",
204
+ "electron": "^41.0.4",
205
+ "electron-builder": "^26.8.1",
206
+ "electron-forge": "^5.2.4",
207
+ "electron-prebuilt-compile": "8.2.0",
208
+ "eslint": "^9.25.0",
209
+ "eslint-config-expo": "~10.0.0",
210
+ "tsx": "^4.19.2",
211
+ "typescript": "~5.9.2",
212
+ "vercel": "^38.0.0"
213
+ }
214
+ }
@@ -0,0 +1,17 @@
1
+ import dotenv from "dotenv";
2
+ import path from "path";
3
+
4
+ /**
5
+ * Unified env loader for local Node contexts.
6
+ *
7
+ * Loads .env and .env.local from repo root and app/.
8
+ * On Vercel, these files normally aren't present, so this is effectively a no-op.
9
+ */
10
+ export function loadEnv() {
11
+ const cwd = process.cwd();
12
+ dotenv.config({ path: path.join(cwd, ".env") });
13
+ dotenv.config({ path: path.join(cwd, "app", ".env") });
14
+ dotenv.config({ path: path.join(cwd, ".env.local") });
15
+ dotenv.config({ path: path.join(cwd, "app", ".env.local") });
16
+ }
17
+
@@ -0,0 +1,16 @@
1
+ import { ensureSchema } from '../database/start.js';
2
+
3
+ async function main() {
4
+ try {
5
+ console.log('[db] Running schema migrations against DATABASE_URL...');
6
+ await ensureSchema();
7
+ console.log('[db] Schema is up to date.');
8
+ } catch (err) {
9
+ console.error('[db] Migration failed', err);
10
+ process.exitCode = 1;
11
+ }
12
+ }
13
+
14
+ // eslint-disable-next-line @typescript-eslint/no-floating-promises
15
+ main();
16
+
@@ -0,0 +1,58 @@
1
+ #!/usr/bin/env node
2
+
3
+ const fs = require("fs");
4
+ const path = require("path");
5
+
6
+ const SKIP = new Set(["node_modules", ".git", ".DS_Store"]);
7
+
8
+ function copyRecursive(src, dst) {
9
+ fs.mkdirSync(dst, { recursive: true });
10
+ for (const entry of fs.readdirSync(src, { withFileTypes: true })) {
11
+ if (SKIP.has(entry.name)) continue;
12
+ const from = path.join(src, entry.name);
13
+ const to = path.join(dst, entry.name);
14
+ if (entry.isDirectory()) {
15
+ copyRecursive(from, to);
16
+ } else if (entry.isSymbolicLink()) {
17
+ const real = fs.realpathSync(from);
18
+ const st = fs.statSync(real);
19
+ if (st.isDirectory()) {
20
+ copyRecursive(real, to);
21
+ } else {
22
+ fs.mkdirSync(path.dirname(to), { recursive: true });
23
+ fs.copyFileSync(real, to);
24
+ }
25
+ } else {
26
+ fs.mkdirSync(path.dirname(to), { recursive: true });
27
+ fs.copyFileSync(from, to);
28
+ }
29
+ }
30
+ }
31
+
32
+ function isEmptyDir(dir) {
33
+ try {
34
+ return fs.readdirSync(dir).length === 0;
35
+ } catch (_) {
36
+ return true;
37
+ }
38
+ }
39
+
40
+ const args = process.argv.slice(2);
41
+ const force = args.includes("--force");
42
+ const targetArg = args.find((a) => !a.startsWith("-")) || ".";
43
+ const target = path.resolve(process.cwd(), targetArg);
44
+ const packageRoot = path.resolve(__dirname, "..");
45
+
46
+ if (fs.existsSync(target) && !isEmptyDir(target) && !force) {
47
+ console.error(`Target is not empty: ${target}`);
48
+ console.error("Re-run with --force to overwrite.");
49
+ process.exit(1);
50
+ }
51
+
52
+ fs.mkdirSync(target, { recursive: true });
53
+ copyRecursive(packageRoot, target);
54
+
55
+ console.log(`Program kit scaffold created at ${target}`);
56
+ console.log("Next steps:");
57
+ console.log(` cd ${targetArg}`);
58
+ console.log(" npm install");
@@ -0,0 +1,30 @@
1
+ /**
2
+ * Local run: polling (getUpdates). Only BOT_TOKEN needed.
3
+ * Run: npx tsx scripts/run-bot-local.ts (or npm run bot:local)
4
+ * Do not run with the same token while webhook is set in production.
5
+ */
6
+ import { createBot } from '../bot/grammy';
7
+ import { loadEnv } from './load-env';
8
+
9
+ loadEnv();
10
+
11
+ const token = (process.env.BOT_TOKEN || process.env.TELEGRAM_BOT_TOKEN || '').trim();
12
+ if (!token) {
13
+ console.error('Missing BOT_TOKEN (or TELEGRAM_BOT_TOKEN)');
14
+ process.exit(1);
15
+ }
16
+
17
+ async function main() {
18
+ const bot = createBot(token);
19
+ await bot.api.deleteWebhook();
20
+ await bot.start();
21
+ console.log('Bot running locally (getUpdates). Press Ctrl+C to stop.');
22
+ }
23
+
24
+ main().catch((err) => {
25
+ console.error(err);
26
+ if (err?.error_code === 401) {
27
+ console.error('[bot] 401 Unauthorized: check BOT_TOKEN in .env (valid token from @BotFather, no extra spaces).');
28
+ }
29
+ process.exit(1);
30
+ });
@@ -0,0 +1,67 @@
1
+ /**
2
+ * Set Telegram webhook on deploy. Run during Vercel build.
3
+ * Requires BOT_TOKEN and a base URL. Base URL is VERCEL_PROJECT_PRODUCTION_URL
4
+ * (Vercel's production alias, e.g. hsbexpo.vercel.app) or VERCEL_URL (deployment-specific).
5
+ */
6
+
7
+ const BOT_TOKEN = process.env.BOT_TOKEN || process.env.TELEGRAM_BOT_TOKEN;
8
+ const VERCEL_PROJECT_PRODUCTION_URL = process.env.VERCEL_PROJECT_PRODUCTION_URL;
9
+ const VERCEL_URL = process.env.VERCEL_URL;
10
+ const baseUrl =
11
+ VERCEL_PROJECT_PRODUCTION_URL
12
+ ? `https://${VERCEL_PROJECT_PRODUCTION_URL}`
13
+ : VERCEL_URL
14
+ ? `https://${VERCEL_URL}`
15
+ : '';
16
+
17
+ const WEBHOOK_PATH = '/api/bot';
18
+ const FETCH_TIMEOUT_MS = 15_000;
19
+
20
+ async function setWebhook(): Promise<void> {
21
+ console.log(
22
+ '[set-webhook] env: VERCEL_ENV=%s VERCEL_URL=%s VERCEL_PROJECT_PRODUCTION_URL=%s',
23
+ process.env.VERCEL_ENV ?? '',
24
+ VERCEL_URL ?? '(none)',
25
+ VERCEL_PROJECT_PRODUCTION_URL ?? '(none)',
26
+ );
27
+
28
+ if (!BOT_TOKEN) {
29
+ console.log('[set-webhook] Skip: BOT_TOKEN not set. Add BOT_TOKEN in Vercel → Settings → Environment Variables (Production, include in Build).');
30
+ return;
31
+ }
32
+
33
+ if (!baseUrl) {
34
+ console.log('[set-webhook] Skip: no webhook URL (VERCEL_URL / VERCEL_PROJECT_PRODUCTION_URL).');
35
+ return;
36
+ }
37
+
38
+ const url = `${baseUrl}${WEBHOOK_PATH}`;
39
+ console.log('[set-webhook] Setting webhook to:', url);
40
+
41
+ const controller = new AbortController();
42
+ const timeout = setTimeout(() => controller.abort(), FETCH_TIMEOUT_MS);
43
+
44
+ const res = await fetch(`https://api.telegram.org/bot${BOT_TOKEN}/setWebhook`, {
45
+ method: 'POST',
46
+ headers: { 'Content-Type': 'application/json' },
47
+ body: JSON.stringify({ url }),
48
+ signal: controller.signal,
49
+ });
50
+ clearTimeout(timeout);
51
+
52
+ const data = (await res.json()) as { ok?: boolean; description?: string };
53
+ if (data.ok) {
54
+ console.log('[set-webhook] OK:', url);
55
+ return;
56
+ }
57
+
58
+ console.error('[set-webhook] Telegram setWebhook failed:', data.description ?? data);
59
+ process.exit(1);
60
+ }
61
+
62
+ setWebhook()
63
+ .then(() => process.exit(0))
64
+ .catch((err: Error) => {
65
+ console.error('[set-webhook] Error:', err.message);
66
+ process.exit(1);
67
+ });