create-gramstax 0.5.13 → 0.5.15
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.
- package/dist/src/templates/.env.example +3 -3
- package/dist/src/templates/README.md +6 -69
- package/dist/src/templates/package.json +2 -3
- package/dist/src/templates/src/blocks/keyboard.ts +2 -2
- package/dist/src/templates/src/core/bot.ts +1 -1
- package/dist/src/templates/src/guards/user.ts +3 -3
- package/dist/src/templates/src/index.ts +3 -3
- package/dist/src/templates/src/pages/general-status.ts +13 -7
- package/dist/src/templates/src/pages/help.ts +0 -1
- package/dist/src/templates/src/pages/start.ts +0 -10
- package/dist/src/templates/src/pages/username-notfound.ts +0 -1
- package/dist/src/templates/src/utils/log.ts +1 -1
- package/package.json +1 -1
- package/dist/src/templates/src/guards/session.ts +0 -15
- package/dist/src/templates/src/pages/input-text.ts +0 -69
|
@@ -1,15 +1,15 @@
|
|
|
1
1
|
# Telegram Bot Token
|
|
2
|
-
|
|
2
|
+
TELEGRAM_BOT_TOKEN=your_bot_token_here
|
|
3
3
|
|
|
4
4
|
# Bot Deployment Mode
|
|
5
5
|
# Options:
|
|
6
6
|
# - polling
|
|
7
7
|
# - webhook:<full-public-url> | example: webhook:https://yourdomain.com/telegram-webhook
|
|
8
8
|
# - serverless:<adapter> | example: serverless:std/http
|
|
9
|
-
|
|
9
|
+
TELEGRAM_BOT_DEPLOY=polling
|
|
10
10
|
|
|
11
11
|
# Cache configuration for session
|
|
12
12
|
# Options:
|
|
13
13
|
# - memory
|
|
14
14
|
# - redis:<url> | example: redis://127.0.0.1:6379
|
|
15
|
-
|
|
15
|
+
TELEGRAM_CACHE_SESSION=memory
|
|
@@ -17,7 +17,7 @@ A Telegram bot built with Gramstax framework.
|
|
|
17
17
|
Copy `.env.example` to `.env` and add your Telegram bot token:
|
|
18
18
|
|
|
19
19
|
```bash
|
|
20
|
-
|
|
20
|
+
TELEGRAM_BOT_TOKEN="<...your_bot_token_here...>"
|
|
21
21
|
```
|
|
22
22
|
|
|
23
23
|
3. Run the development server:
|
|
@@ -26,57 +26,6 @@ BOT_TOKEN=your_bot_token_here
|
|
|
26
26
|
{{runDevCmd}}
|
|
27
27
|
```
|
|
28
28
|
|
|
29
|
-
### Production
|
|
30
|
-
|
|
31
|
-
#### Using PM2 (Recommended)
|
|
32
|
-
|
|
33
|
-
PM2 is a production process manager for Node.js applications with built-in load balancer.
|
|
34
|
-
|
|
35
|
-
1. Install dependencies:
|
|
36
|
-
|
|
37
|
-
```bash
|
|
38
|
-
{{installCmd}}
|
|
39
|
-
```
|
|
40
|
-
|
|
41
|
-
2. Set up production environment:
|
|
42
|
-
|
|
43
|
-
```bash
|
|
44
|
-
cp .env.example .env
|
|
45
|
-
# Edit .env with your production BOT_TOKEN
|
|
46
|
-
```
|
|
47
|
-
|
|
48
|
-
3. Start with PM2:
|
|
49
|
-
|
|
50
|
-
```bash
|
|
51
|
-
{{runPm2StartCmd}}
|
|
52
|
-
```
|
|
53
|
-
|
|
54
|
-
4. PM2 Management Commands:
|
|
55
|
-
|
|
56
|
-
```bash
|
|
57
|
-
# View logs
|
|
58
|
-
{{runPm2LogsCmd}}
|
|
59
|
-
|
|
60
|
-
# Monitor processes
|
|
61
|
-
{{runPm2MonitCmd}}
|
|
62
|
-
|
|
63
|
-
# Restart bot
|
|
64
|
-
{{runPm2RestartCmd}}
|
|
65
|
-
|
|
66
|
-
# Stop bot
|
|
67
|
-
{{runPm2StopCmd}}
|
|
68
|
-
|
|
69
|
-
# Delete from PM2
|
|
70
|
-
{{runPm2DeleteCmd}}
|
|
71
|
-
```
|
|
72
|
-
|
|
73
|
-
5. Setup PM2 to start on system boot:
|
|
74
|
-
|
|
75
|
-
```bash
|
|
76
|
-
pm2 startup
|
|
77
|
-
pm2 save
|
|
78
|
-
```
|
|
79
|
-
|
|
80
29
|
#### Using Bun directly
|
|
81
30
|
|
|
82
31
|
```bash
|
|
@@ -86,12 +35,10 @@ pm2 save
|
|
|
86
35
|
## Project Structure
|
|
87
36
|
|
|
88
37
|
- `src/base/` - Base classes for your bot components
|
|
38
|
+
- `src/blocks/` - Block data builder classes
|
|
89
39
|
- `src/core/` - Core bot configuration and hooks
|
|
90
|
-
- `src/pages/` - Bot pages/screens
|
|
91
40
|
- `src/guards/` - Route guards and middleware
|
|
92
|
-
- `src/
|
|
93
|
-
- `src/repositories/` - Data access layer
|
|
94
|
-
- `src/templates/` - Message templates
|
|
41
|
+
- `src/pages/` - Bot pages/screens
|
|
95
42
|
- `src/utils/` - Utility functions
|
|
96
43
|
- `logs/` - Application logs (created automatically)
|
|
97
44
|
|
|
@@ -99,22 +46,12 @@ pm2 save
|
|
|
99
46
|
|
|
100
47
|
### Environment Variables
|
|
101
48
|
|
|
102
|
-
- `
|
|
103
|
-
- `
|
|
104
|
-
|
|
105
|
-
### PM2 Configuration
|
|
106
|
-
|
|
107
|
-
The `ecosystem.config.js` file contains PM2 configuration:
|
|
108
|
-
|
|
109
|
-
- **instances**: Number of instances (default: 1)
|
|
110
|
-
- **exec_mode**: Execution mode (cluster/fork)
|
|
111
|
-
- **max_memory_restart**: Auto-restart if memory exceeds limit
|
|
112
|
-
- **autorestart**: Auto-restart on crash
|
|
113
|
-
- **error_file/out_file**: Log file locations
|
|
49
|
+
- `TELEGRAM_BOT_TOKEN` - Your Telegram bot token (required)
|
|
50
|
+
- `TELEGRAM_BOT_DEPLOY` - Your Telegram bot deploy (required)
|
|
51
|
+
- `TELEGRAM_CACHE_SESSION` - Cache type configuration (optional)
|
|
114
52
|
|
|
115
53
|
## Learn More
|
|
116
54
|
|
|
117
55
|
- [Gramstax Documentation](https://github.com/gramstax/gramstax)
|
|
118
56
|
- [Grammy Documentation](https://grammy.dev/)
|
|
119
57
|
- [Telegram Bot API](https://core.telegram.org/bots/api)
|
|
120
|
-
- [PM2 Documentation](https://pm2.keymetrics.io/)
|
|
@@ -36,13 +36,12 @@
|
|
|
36
36
|
},
|
|
37
37
|
"dependencies": {
|
|
38
38
|
"logging-pretty": "^3.0.0",
|
|
39
|
-
"gramstax": "^0.5.
|
|
39
|
+
"gramstax": "^0.5.14"
|
|
40
40
|
},
|
|
41
41
|
"peerDependencies": {
|
|
42
42
|
"typescript": "5.9.3"
|
|
43
43
|
},
|
|
44
44
|
"devDependencies": {
|
|
45
|
-
"@types/bun": "latest"
|
|
46
|
-
"pm2": "^5.3.0"
|
|
45
|
+
"@types/bun": "latest"
|
|
47
46
|
}
|
|
48
47
|
}
|
|
@@ -2,8 +2,8 @@ import {BlockKeyboard, LabelKeyboard} from "gramstax"
|
|
|
2
2
|
|
|
3
3
|
export class KeyboardBlock extends BlockKeyboard {
|
|
4
4
|
static label = class extends LabelKeyboard {
|
|
5
|
-
static home = {default: `Home`,
|
|
6
|
-
static back = {default:
|
|
5
|
+
static home = {default: `Home`, id: `Beranda`}
|
|
6
|
+
static back = {default: `<< Back`, id: `<< Kembali`}
|
|
7
7
|
}
|
|
8
8
|
static home = (lang?: string, type?: string) => this._build(`home`, lang, type)
|
|
9
9
|
static back = (lang?: string, type?: string) => this._build(`back`, lang, type)
|
|
@@ -5,7 +5,7 @@ import type {CtxCore} from "./ctx"
|
|
|
5
5
|
|
|
6
6
|
export class BotCore extends Gramstax {
|
|
7
7
|
async hookBeforeRoute(ctx: CtxCore) {
|
|
8
|
-
const result = await new UserGuard(ctx).
|
|
8
|
+
const result = await new UserGuard(ctx).ensureUsername(true)
|
|
9
9
|
if (result === null) {
|
|
10
10
|
return false
|
|
11
11
|
}
|
|
@@ -8,15 +8,15 @@ export class UserGuard extends GuardBase {
|
|
|
8
8
|
return null
|
|
9
9
|
}
|
|
10
10
|
|
|
11
|
-
async
|
|
11
|
+
async ensureUsername(edit: boolean) {
|
|
12
12
|
try {
|
|
13
13
|
if (!this.userName || this.userName.length == 0) {
|
|
14
|
-
await new UserNameNotFoundPage(this).transition(
|
|
14
|
+
await new UserNameNotFoundPage(this).transition(edit)
|
|
15
15
|
return null
|
|
16
16
|
}
|
|
17
17
|
return {status: true}
|
|
18
18
|
} catch (err) {
|
|
19
|
-
return await this._catch(err, `ensureValid`,
|
|
19
|
+
return await this._catch(err, `ensureValid`, edit)
|
|
20
20
|
}
|
|
21
21
|
}
|
|
22
22
|
}
|
|
@@ -1,14 +1,14 @@
|
|
|
1
1
|
import {env} from "./env"
|
|
2
|
-
import {
|
|
2
|
+
import {log} from "./utils/log"
|
|
3
3
|
import {BotCore} from "./core/bot"
|
|
4
4
|
import {CacheExternal} from "gramstax"
|
|
5
5
|
|
|
6
|
-
|
|
6
|
+
log.success(`Bot started..`)
|
|
7
7
|
|
|
8
8
|
new BotCore({
|
|
9
9
|
token: env.TELEGRAM_BOT_TOKEN,
|
|
10
10
|
deploy: env.TELEGRAM_BOT_DEPLOY,
|
|
11
|
-
cacheSession: new CacheExternal(env.TELEGRAM_CACHE_SESSION,
|
|
11
|
+
cacheSession: new CacheExternal(env.TELEGRAM_CACHE_SESSION, 4 * 60 * 60 * 1000, `s`), // 4 hours
|
|
12
12
|
optionsPage: {
|
|
13
13
|
shortCallbackData: true
|
|
14
14
|
}
|
|
@@ -1,9 +1,11 @@
|
|
|
1
|
-
import {log} from "
|
|
1
|
+
import {log} from "~/utils/log"
|
|
2
2
|
import {PageBase} from "~/base/page"
|
|
3
3
|
import {StartPage} from "./start"
|
|
4
4
|
|
|
5
5
|
export class GeneralStatusPage extends PageBase {
|
|
6
|
+
static BASE = {error: `error`, notFound: `not-found`}
|
|
6
7
|
constructorName?: string
|
|
8
|
+
|
|
7
9
|
constructor(p: any) {
|
|
8
10
|
super(p)
|
|
9
11
|
this.constructorName = p?.constructor?.name
|
|
@@ -18,13 +20,13 @@ export class GeneralStatusPage extends PageBase {
|
|
|
18
20
|
|
|
19
21
|
await this.sessionClear()
|
|
20
22
|
const kb = this.kb()
|
|
21
|
-
const
|
|
22
|
-
if (edit) await this.edit(kb, {},
|
|
23
|
-
else await this.reply(kb, {},
|
|
23
|
+
const bi = GeneralStatusPage.BASE.error
|
|
24
|
+
if (edit) await this.edit(kb, {}, bi)
|
|
25
|
+
else await this.reply(kb, {}, bi)
|
|
24
26
|
}
|
|
25
27
|
|
|
26
28
|
async toErrorInputNotFound() {
|
|
27
|
-
await this.reply(this.kb(), {},
|
|
29
|
+
await this.reply(this.kb(), {}, GeneralStatusPage.BASE.notFound)
|
|
28
30
|
}
|
|
29
31
|
|
|
30
32
|
static template = `
|
|
@@ -32,7 +34,7 @@ export class GeneralStatusPage extends PageBase {
|
|
|
32
34
|
${this.kbk.home()}
|
|
33
35
|
</base>
|
|
34
36
|
|
|
35
|
-
<base id="error">
|
|
37
|
+
<base id="${this.BASE.error}">
|
|
36
38
|
<message>
|
|
37
39
|
<b>❌ Error</b>
|
|
38
40
|
|
|
@@ -47,12 +49,16 @@ export class GeneralStatusPage extends PageBase {
|
|
|
47
49
|
</message>
|
|
48
50
|
</base>
|
|
49
51
|
|
|
50
|
-
<base id="
|
|
52
|
+
<base id="${this.BASE.notFound}">
|
|
51
53
|
<message>
|
|
52
54
|
<b>❌ Not Found</b>
|
|
55
|
+
|
|
56
|
+
Not maching route.
|
|
53
57
|
</message>
|
|
54
58
|
<message lang="id">
|
|
55
59
|
<b>❌ Tidak Ditemukan</b>
|
|
60
|
+
|
|
61
|
+
Tidak ada route terdeteksi.
|
|
56
62
|
</message>
|
|
57
63
|
</base>
|
|
58
64
|
`
|
|
@@ -18,11 +18,6 @@ export class StartPage extends PageBase {
|
|
|
18
18
|
}
|
|
19
19
|
|
|
20
20
|
static template = `
|
|
21
|
-
<base id="with-import-and-you-can-use-components">
|
|
22
|
-
<keyboard>❓ Help</keyboard>
|
|
23
|
-
<keyboard lang="it">❓ Aiuto</keyboard>
|
|
24
|
-
<keyboard lang="id">❓ Bantuan</keyboard>
|
|
25
|
-
</base>
|
|
26
21
|
<base>
|
|
27
22
|
<import src="start" base="with-import-and-you-can-use-components" />
|
|
28
23
|
<message>
|
|
@@ -30,11 +25,6 @@ export class StartPage extends PageBase {
|
|
|
30
25
|
|
|
31
26
|
<b>❓ Help</b> - View help
|
|
32
27
|
</message>
|
|
33
|
-
<message lang="it">
|
|
34
|
-
<b>Benvenuto nel Bot di {{userName}}</b>
|
|
35
|
-
|
|
36
|
-
<b>❓ Aiuto</b> - Ottieni assistenza e informazioni
|
|
37
|
-
</message>
|
|
38
28
|
<message lang="id">
|
|
39
29
|
<b>Selamat datang di bot {{userName}}</b>
|
|
40
30
|
|
|
@@ -12,7 +12,6 @@ export class UserNameNotFoundPage extends PageBase {
|
|
|
12
12
|
<base>
|
|
13
13
|
${this.kbk.home()}
|
|
14
14
|
<message>Please set the username first before using the bot.</message>
|
|
15
|
-
<message lang="it">Prima di utilizzare il bot, imposta prima il nome utente.</message>
|
|
16
15
|
<message lang="id">Tolong set username dulu sebelum memakai bot</message>
|
|
17
16
|
</base>
|
|
18
17
|
`
|
|
@@ -1,2 +1,2 @@
|
|
|
1
1
|
import {log} from "gramstax"
|
|
2
|
-
export {log
|
|
2
|
+
export {log}
|
package/package.json
CHANGED
|
@@ -1,15 +0,0 @@
|
|
|
1
|
-
import {GuardBase} from "~/base/guard"
|
|
2
|
-
|
|
3
|
-
export class SessionGuard extends GuardBase {
|
|
4
|
-
async ensureTextFree() {
|
|
5
|
-
try {
|
|
6
|
-
const {method, params} = this.session
|
|
7
|
-
if (this.validateSessionTextFree(method, this.temp.data.name) === false) {
|
|
8
|
-
return null
|
|
9
|
-
}
|
|
10
|
-
return params
|
|
11
|
-
} catch {
|
|
12
|
-
return null
|
|
13
|
-
}
|
|
14
|
-
}
|
|
15
|
-
}
|
|
@@ -1,69 +0,0 @@
|
|
|
1
|
-
import {PageBase} from "~/base/page"
|
|
2
|
-
import {StartPage} from "./start"
|
|
3
|
-
import {SessionGuard} from "~/guards/session"
|
|
4
|
-
|
|
5
|
-
export class InputTextPage extends PageBase {
|
|
6
|
-
static data = this.buildData({
|
|
7
|
-
intentTextCommand: `input_text`
|
|
8
|
-
})
|
|
9
|
-
|
|
10
|
-
kb(baseId?: string) {
|
|
11
|
-
return this.inlineKeyboardT([StartPage], `1`, baseId)
|
|
12
|
-
}
|
|
13
|
-
|
|
14
|
-
async callback() {
|
|
15
|
-
await this.sessionToTextFree()
|
|
16
|
-
await this.edit(this.kb())
|
|
17
|
-
}
|
|
18
|
-
|
|
19
|
-
async textCommand() {
|
|
20
|
-
await this.sessionToTextFree()
|
|
21
|
-
await this.reply(this.kb())
|
|
22
|
-
}
|
|
23
|
-
|
|
24
|
-
async textFree() {
|
|
25
|
-
const params = await new SessionGuard(this).ensureTextFree()
|
|
26
|
-
if (params === null) {
|
|
27
|
-
/**
|
|
28
|
-
* Return "null" if you want the bot to continue to check for suitable route for the
|
|
29
|
-
* "dynamicSpecific" and "dynamic" type with the route suffix "Free" or "free" (without session), for example: textFree, animationFree, free.
|
|
30
|
-
*
|
|
31
|
-
* Return "undefined"/void if you want the bot to stop checking for "dynamicSpecific" and "dynamic" route types.
|
|
32
|
-
*
|
|
33
|
-
* Returning undefined/void indicates the success of this rule. There are only two returns allowed for all routes: null and undefined / void.
|
|
34
|
-
*/
|
|
35
|
-
return null
|
|
36
|
-
}
|
|
37
|
-
|
|
38
|
-
const baseId = `result`
|
|
39
|
-
const data = {res: this.msgText}
|
|
40
|
-
await this.reply(this.kb(baseId), data, baseId)
|
|
41
|
-
}
|
|
42
|
-
|
|
43
|
-
static template = `
|
|
44
|
-
<base>
|
|
45
|
-
${this.kbk.cancel()}
|
|
46
|
-
<message>Please input text you want view</message>
|
|
47
|
-
<message lang="it">Inserisci il testo che vuoi vedere</message>
|
|
48
|
-
<message lang="id">Tolong masukan text yang ingin anda liat</message>
|
|
49
|
-
</base>
|
|
50
|
-
<base id="result">
|
|
51
|
-
${this.kbk.home()}
|
|
52
|
-
<message>
|
|
53
|
-
Result: {{res}}
|
|
54
|
-
|
|
55
|
-
Please input other text to see difference result
|
|
56
|
-
</message>
|
|
57
|
-
<message lang="it">
|
|
58
|
-
Risultato: {{res}}
|
|
59
|
-
|
|
60
|
-
Inserisci un altro testo per vedere il risultato diverso
|
|
61
|
-
</message>
|
|
62
|
-
<message lang="id">
|
|
63
|
-
Hasil: {{res}}
|
|
64
|
-
|
|
65
|
-
Tolong masukan text lain untuk lihat hasil yang berbeda
|
|
66
|
-
</message>
|
|
67
|
-
</base>
|
|
68
|
-
`
|
|
69
|
-
}
|