Telegram Serverless hukuruhusu kuendesha msimbo wa backend kwa ajili ya boti yako na Mini App moja kwa moja kwenye miundombinu ya Telegram — hakuna seva za kuweka, hakuna kontena za kuhakikisha zinaendelea kufanya kazi, na hakuna haja ya kufikiria kuhusu kuongeza uwezo (scaling). Unaandika moduli rahisi za JavaScript, unazipeleka kwa amri moja, na Telegram inaziendesha katika V8 sandbox ya haraka na iliyotengwa ambayo inakaa karibu na Bot API na hifadhidata iliyojengewa ndani.
Ikiwa umewahi kuunganisha boti kwenye VPS, cloud function, au hosting panel ili tu kujibu /start, hii ndiyo hatua ambayo huhitaji tena kuifanya.
Kwa nini serverless
Boti ya Telegram ni, katika msingi wake, programu inayokabiliana na masasisho (updates). Kijadi, ilibidi uweke programu hiyo mahali fulani ambapo inafanya kazi kila wakati, inayoweza kufikika, na salama — na kisha uweke hivyo kila wakati. Telegram Serverless huondoa safu hiyo kabisa:
- Hakuna miundombinu. Hakuna mashine ya kukodisha, kufanyia viraka, au kufuatilia. Msimbo wako unafanya kazi kulingana na mahitaji na hujiendesha yenyewe kwa kuongeza uwezo kulingana na boti yako.
- Vitambulisho vimejumuishwa. Telegram Bot API, hifadhidata inayotumia SQLite, na HTTP ya kutoka nje zinapatikana kwa kila moduli bila haja ya ziada — hakuna cha kusakinisha, hakuna vitambulisho vya kuunganisha.
- Utekelezaji wa haraka na uliotengwa. Kila ombi linafanya kazi katika V8 isolate nyepesi, karibu na mifumo ya Telegram yenyewe, kwa hivyo wito kwa Bot API na hifadhidata yako ni wa haraka na wa kuaminika.
- Utiririshaji halisi wa kazi wa msanidi programu. Mradi unaishi kwenye folda katika mashine yako chini ya udhibiti wa matoleo (version control). Unahariri faili, unaona hasa nini kimebadilika, unapeleka msimbo kikamilifu, na unasasisha muundo wa hifadhidata yako kwa mabadiliko yaliyokaguliwa — jinsi unavyofanya kazi na kila kitu kingine.
Mfano wa kimawazo: Jinsi mradi unavyofanya kazi
Unafanya kazi katika maeneo matatu, na yanalingana kikamilifu:
| Mahali | Nini kinaishi hapo |
|---|---|
| Folda ya mradi wako | Moduli za JavaScript — schema, msimbo wa pamoja, vishikilia masasisho, endpoints za Mini App — na, ikiwa unayo, front‑end ya Mini App |
| Cloud | Nakala iliyopelekwa ya moduli hizo, hifadhidata ya boti yako, na faili za Mini App |
tgcloud CLI |
Daraja — inakuonyesha tofauti na kuzisawazisha |
Huwezi ku-SSH kwenye kitu chochote. Unahariri faili ndani ya kompyuta yako, unaendesha npx tgcloud push, na jukwaa linashughulikia yaliyosalia. Trafiki ya boti yako inashughulikiwa na moduli zilizopelekwa; hifadhidata yako inadumu kati ya maombi.
Mradi una aina nne tu za msimbo, yote ndani ya folda moja ya tgcloud/:
tgcloud/
├─ endpoints/ # vitendaji vinavyoitwa na Mini App yako
├─ handlers/ # vitendaji vinavyoitikia aina za masasisho ya Telegram
├─ lib/ # msimbo wa pamoja unaoingiza kutoka popote
└─ schema.js # jedwali za hifadhidata yako
Wakati sasisho linapowasili — ujumbe, kubonyeza kitufe, inline query — Telegram inalipeleka kwa kishikilia kinacholingana (handlers/message.js, handlers/callback_query.js, …) na kuita export yake ya kawaida. Kitendaji hicho kinawasiliana na Bot API na hifadhidata kupitia SDK, na kisha kinamaliza. Huo ndio mzunguko mzima. Sasisho lisilo na kishikilia kinacholingana linapuuzwa tu, kwa hivyo unaongeza tu vishikilia unavyohitaji.
Mini App ni ya hiari. Ikiwa boti yako inayo moja, front‑end yake inaishi kwenye mradi huo huo, karibu na tgcloud/. Serverless inahifadhi matokeo ya build yake na kuendesha endpoints/ inayoziita. Tazama
Mini App front‑end
.
Onyesho la haraka
Hii hapa ni boti kamili ya onyesho inayofanya kazi. Inajibu kila ujumbe na kukumbuka ni ujumbe mingapi imeona kutoka kwa kila chat.
tgcloud/schema.js
import { table, integer } from 'sdk/db';
export const counters = table('counters', {
chatId: integer('chat_id').primaryKey() ,
seen: integer('seen').notNull().default(0) ,
});
tgcloud/handlers/message.js
import { api, db } from 'sdk';
import { sql } from 'sdk/db';
import { counters } from '../schema.js';
export default async function (message) {
const chatId = message.chat.id;
// Ingiza kaunta, au iongeze ikiwa chat hii tayari inayo — na urudishe
// mstari unaotokana katika taarifa hiyo hiyo kupitia .returning().
const [row] = await db.insert(counters)
.values({ chatId, seen: 1 })
.onConflictDoUpdate({
target: counters.chatId,
set: { seen: sql`${counters.seen} + 1` },
})
.returning()
.run();
await api.sendMessage({
chat_id: chatId,
text: `Hujambo! Nimeona ujumbe ${row.seen} kutoka kwako.`,
});
}
Ipeleke (Deploy):
npx tgcloud push # pakia moduli
npx tgcloud migrate # tengeneza jedwali la `counters`
Hiyo ni boti inayofanya kazi na hali endelevu na bila seva. Kila kitu ndani yake — api, db, table() DSL — kimeelezwa katika sehemu hapa chini.
Serverless ni backend ya jumla kwa boti za Telegram na Mini Apps, si kiolezo cha aina moja ya programu. Inafaa kwa:
- Boti za AI za Mazungumzo zinazohitaji kuhifadhi hali ya kila mtumiaji katika hifadhidata.
- Backend za Mini App zinazohifadhi data za watumiaji na kuhudumia maudhui yanayobadilika.
- Michezo na Zana — ikijumuisha ubao wa wanaoongoza, maswali na zaidi.
- Uendeshaji wa Kiotomatiki na Integrations zinazoita API za HTTP za watu wengine na kusukuma matokeo kwenye chats.
Kuanza
Mwongozo huu unakupeleka kutoka kwenye folda tupu hadi kwenye boti inayofanya kazi inayojibu ujumbe na kuhifadhi data. Inadhania kuwa umesakinisha
Node.js
18 au mpya zaidi na una boti iliyosajiliwa na
@BotFather
. Kufikia mwisho utakuwa umetumia kila amri unayohitaji kila siku: push, migrate, run, na status.
Kabla ya kitu kingine chochote, washa Serverless. Katika @BotFather , fungua boti yako → Serverless na uwashe. Hiyo inawasha kipengele hicho kwa boti hii na kufungua token yake ya ufikiaji ya CLI, vishikilia, maktaba, na hifadhidata.
1. Unda mradi
Njia ya haraka zaidi ya kuanza ni mtayarishaji wa mradi, ambayo inaunda kiolezo cha mradi na kusakinisha CLI ndani yake:
npm create @tgcloud/bot example_bot
cd example_bot
Hoja hiyo ni folda lengwa: pitisha . ili kuunda kwenye folda ya sasa, au njia yoyote. Inafanya kazi kwenye folda iliyopo pia na kamwe haifuti faili ulizokuwa nazo.
Hii inakupa mradi ulio tayari kuhaririwa:
example_bot/
├─ tgcloud/ # kila kitu kinachoendeshwa na jukwaa
│ ├─ handlers/
│ │ └─ message.js # kishikilia ujumbe cha kuanzia (hurudisha maandishi)
│ ├─ lib/ # moduli zako za pamoja zinaenda hapa (tupu kuanza)
│ └─ schema.js # jedwali za hifadhidata yako
├─ docs/
│ └─ tgcloud-sdk.md # marejeleo ya SDK (kwa ajili yako na zana zako za AI)
├─ AGENTS.md # mwongozo kwa wasaidizi wa uandishi wa msimbo wa AI
├─ package.json
└─ tgcloud.jsonc # usanidi wa mradi
Faili zilizoundwa zinaelezea wenyewe — kila moja ina mifano ya maoni ya kile unachoweza kufanya baadaye.
CLI inasakinisha kwenye mradi kama dev-dependency ya ndani, kwa hivyo unaiendesha na npx tgcloud <command> (npx inatafuta nakala katika node_modules ya mradi wako), au kupitia njia za mkato za npm run ambazo kiolezo kinaongeza kwenye package.json (npm run deploy, npm run status). Kwa chaguo-msingi hakuna tgcloud ya kimataifa kwenye PATH yako.
Unaweza pia kuisakinisha kimataifa — npm install -g @tgcloud/cli — ikiwa ungependelea kuandika tgcloud tu kutoka popote. Hiyo ni muhimu kwa kuendesha tgcloud init katika folda yoyote tupu, na ndivyo shell tab-completion inavyohitaji. Kwa namna yoyote unapata mradi uleule.
Unajenga Mini App? Anza kutoka front‑end yake badala yake. Iunde na zana yako ya kawaida, kisha uendeshe mtayarishaji wa mradi katika folda hiyo. Tazama Mini App front‑end .
2. Unganisha boti yako
Kila mradi umeunganishwa na boti moja. Ziunganishe na login, ambayo inauliza token yako ya ufikiaji ya CLI (
@BotFather
→ boti yako → Serverless → CLI Access → Token ya ufikiaji — token tofauti na
token ya API ya boti yako
) na kuihifadhi ndani:
npx tgcloud login
Token ina umbo la app<id>:<secret>. CLI inaiweka katika .tgcloud/, ambayo imepuuzwa na git, na kamwe haichapishi sehemu ya siri. Login ni mara pekee unayoulizwa hiyo — tazama
Authentication
kwa jinsi token zinavyotatuliwa katika CI.
3. Tazama kote
Amri mbili zinakuambia mahali mambo yalipo wakati wowote, zote zikiwa nje ya mtandao kikamilifu:
npx tgcloud status # nini kimebadilika ndani ya kompyuta dhidi ya nakala iliyopelekwa
npx tgcloud diff # mabadiliko ya mstari kwa mstari
Mara baada ya init kila kitu ni kipya na hakuna kitu kilichopelekwa bado. status inaonyesha faili za kuanzia zikisubiri kupandishwa.
4. Ipeleke (Deploy)
Tuma moduli zako kwenye cloud:
npx tgcloud push
push hupakia kila moduli iliyobadilika katika kundi moja na kusasisha rekodi yako ya ndani ya kile ambacho cloud inacho sasa. Boti yako iko hai: ifungue kwenye Telegram na uitumie ujumbe — kishikilia cha kuanzia kinakurudishia ujumbe huo.
Kupeleka msimbo kamwe hakugusi hifadhidata yako. Kusukuma msimbo na kubadilisha muundo wa hifadhidata yako ni hatua tofauti kwa makusudi, kwa hivyo kupeleka msimbo hakutakushangaza na mabadiliko ya data. Hiyo ndiyo hatua inayofuata.
5. Ongeza jedwali la hifadhidata
Hebu tuifanye boti ikumbuke kitu fulani. Fungua tgcloud/schema.js na utangaze jedwali:
import { table, integer, text, sql } from 'sdk/db';
export const messages = table('messages', {
id: integer('id').primaryKey({ autoIncrement: true }) ,
chatId: integer('chat_id').notNull() ,
text: text('text') ,
created: integer('created_at', { mode: 'timestamp' }).default(sql`(unixepoch())`) ,
});
Ipeleke schema, kisha uitumie kwenye hifadhidata:
npx tgcloud push # hupakia schema mpya
npx tgcloud migrate # hutengeneza jedwali la `messages`
push inaripoti kuwa schema haijasawazishwa na inakuonyesha mabadiliko yanayosubiri, lakini haitumii chochote. migrate inakuongoza kupitia mabadiliko na, baada ya uthibitisho wako, inatengeneza jedwali. Mfano huu wa hatua mbili — na nini kinatokea kwa mabadiliko ya hatari zaidi kama kufuta — umeelezwa katika
Migrations
.
6. Hifadhi na soma data
Sasa tumia jedwali kutoka kwa kishikilia chako. Hariri tgcloud/handlers/message.js:
import { api, db } from 'sdk';
import { eq } from 'sdk/db';
import { messages } from '../schema.js';
export default async function (message) {
// Hifadhi ujumbe huu.
await db.insert(messages)
.values({ chatId: message.chat.id, text: message.text })
.run();
// Hesabu ni mingapi tumehifadhi kwa chat hii.
const count = await db.$count(messages, eq(messages.chatId, message.chat.id));
await api.sendMessage({
chat_id: message.chat.id,
text: `Imehifadhiwa. Huo ni ujumbe ${count} kutoka kwenye chat hii hadi sasa.`,
});
}
Ipeleke kishikilia kilichosasishwa na npx tgcloud push, kisha itumie boti yako jumbe chache na utazame hesabu ikipanda. Hifadhidata inabaki kati ya maombi — hiyo ndiyo kumbukumbu ya boti yako.
7. Jaribu bila kupeleka
Huna haja ya kupeleka ili kujaribu mabadiliko. npx tgcloud run inatekeleza kishikilia kwenye jukwaa ikitumia faili zako za ndani, bila kuzichapisha:
npx tgcloud run handlers/message '{ chat: { id: 1 }, text: "hello" }'
Hoja hiyo ni payload ambayo kishikilia chako hupokea — kwa handlers/message,
Ujumbe
— iliyoandikwa katika
JSON5
(hivyo unaweza kuruka kuweka alama za kunukuu kwenye keys). Amri hiyo inachapisha chochote ambacho kishikilia kiliandika na console.*, thamani ya kurudishwa, na muda uliotumika. Hii ndiyo njia ya haraka zaidi ya kuboresha mantiki — hakuna kupeleka, hakuna kusubiri ujumbe halisi.
8. Kaa katika usawaziko
Unapofanya kazi, amri chache huweka mradi wako wa ndani na cloud katika usawaziko: npx tgcloud status inaonyesha nini kimebadilika, npx tgcloud push inapeleka, npx tgcloud pull inaleta mradi wako wa ndani sambamba na cloud, npx tgcloud fetch inakagua nini kimepelekwa bila kugusa faili zako, na npx tgcloud reset inafuta mabadiliko ya ndani.
Ikiwa watu wawili (au mashine mbili) watapeleka kwa boti moja, jukwaa linagundua mgogoro na
pushinasimama ili kukuacha u-pullkwanza — huwezi kamwe kubadilisha kazi ya mtu mwingine kimya kimya. Tazama Staying in sync .
Kujenga na AI
Unapendelea kujenga na msaidizi wa AI — au ni AI pekee ndiye anayeshughulika na msimbo kwenye timu yako? Bado unaweza kusafirisha boti. Tumechukua hatua ya kwanza kumfanya wakala wa AI ajisikie yuko nyumbani kwenye mradi: kila mradi mpya unaundwa na AGENTS.md na marejeleo ya docs/tgcloud-sdk.md ambayo zana za uandishi wa msimbo wa wakala husoma kiotomatiki.
Pamoja na muda mdogo wa utekelezaji (runtime) wa kujitegemea — SDK moja, hakuna vifurushi vya npm vya kusumbua — hiyo inampa msaidizi mwanzo mzuri kwenye mikataba ambayo uundaji wa msimbo wa kawaida huwa unakosa hapa: imports za jamaa na .js, hakuna funguo za kigeni (foreign keys), kila wito wa db ni async, kishikilia kimoja kwa kila aina ya sasisho, na mtiririko wa push/migrate wa hatua mbili.
Ijaribu:
npm create @tgcloud/bot my-bot
cd my-bot
opencode # au Claude Code, Cursor, … — wakala yeyote anayesoma AGENTS.md
Kisha uulize tu, kwa lugha rahisi:
Andika boti inayokumbuka orodha ya mambo ya kufanya ya kila mtu — ongeza kipengee wanapotuma maandishi, na uonyeshe orodha nzima wanapotuma /list.
Msaidizi anahariri schema.js na vishikilia vyako kwa ajili yako; unakagua, unajaribu mabadiliko papo hapo na npx tgcloud run, kisha unaenda mubashara na npx tgcloud push na npx tgcloud migrate. AGENTS.md ni sehemu ya mradi wako — ihariri boti inapokua ili mwongozo ubaki sahihi.
On the go na BotFather
Umebaki na simu yako tu? Mradi mzima unaishi katika @BotFather pia — fungua boti yako → Serverless na unapata kila kitu ambacho CLI inasimamia, kwenye skrini ya kugusa:
- Handlers — tengeneza, hariri, na jaribu vishikilia vya masasisho; BotFather huweka webhook katika usawaziko na vishikilia ulivyo navyo (sawa na In sync / Out of sync ambayo CLI inaripoti).
- Endpoints — vitendaji vinavyoitwa na Mini App yako.
- Library — moduli zako za pamoja za
lib/. - Database — hariri
schema.jskatika syntax ileile ya Drizzle, kagua mabadiliko yanayosubiri, na uyaapply; Save inapeleka (deploy). - Mini App Files — front‑end ambayo watumiaji wako wanaifungua kwenye Telegram.
- CLI Access — chukua token ya ufikiaji ya CLI hapa utakapokuwa umerejea kwenye kibodi.
Ni mradi mmoja uleule wa cloud, kwa hivyo unaweza kuanza kishikilia kwenye simu yako na kuki-pull na npx tgcloud pull kwenye laptop yako baadaye — hakuna kitu kinachofungwa na mteja mmoja. Kuendesha kishikilia kunaonyesha hata matokeo yake ya Console moja kwa moja kwenye chat, kama vile
npx tgcloud run
.
Miradi na moduli
Mradi wa serverless ni folda ya kawaida chini ya udhibiti wa matoleo. Kila kitu kinachoendeshwa na jukwaa kinakaa kwenye folda moja, tgcloud/; mradi wote uliobaki ni wako — front‑end ya mini-app, usanidi, docs. Hakuna hatua ya build kwa boti, hakuna node_modules wakati wa utekelezaji, na hakuna hatua ya kuingia ya seva.
Anatomia ya mradi
example_bot/
├─ tgcloud/ # sehemu iliyopelekwa — hakuna nyingine
│ ├─ handlers/ # vishikilia masasisho — bapa, ngazi moja tu
│ │ ├─ message.js
│ │ └─ callback_query.js
│ ├─ endpoints/ # vitendaji vinavyoitwa na Mini App yako — bapa, ngazi moja tu
│ │ └─ getProfile.js
│ ├─ lib/ # moduli za pamoja; ndogo-folda zinaruhusiwa
│ │ ├─ reply.js
│ │ └─ internal/util.js
│ └─ schema.js # schema ya hifadhidata — faili moja
└─ .tgcloud/ # hali ya CLI, imepuuzwa na git
Ni faili za .js ndani ya tgcloud/ — schema.js, lib/, handlers/, endpoints/ — ndizo zinazopelekwa. Kila kitu kingine — Markdown, faili za usanidi, folda ya .tgcloud/, chochote nje ya tgcloud/ — kinabaki kwenye mashine yako. Majina ya moduli ni ya jamaa na tgcloud/. Faili tgcloud/handlers/message.js ni moduli handlers/message, na hilo ndilo jina ambalo npx tgcloud run inatumia.
Unaboresha kutoka mradi wa zamani? Miradi iliyoundwa kabla ya CLI 0.2.0 iliweka
schema.js,lib/nahandlers/kwenye mzizi wa mradi. Endeshanpx tgcloud upgrademara moja ili kuzihamishia kwenyetgcloud/.
schema.js — hifadhidata yako. Inatangaza jedwali kama exports zilizopewa jina ikitumia schema DSL na kuishi katika tgcloud/ kama faili moja. Inapelekwa kama moduli nyingine yoyote, lakini kuipeleka hakubadilishi hifadhidata — mabadiliko ya schema yanatumika kando na npx tgcloud migrate. Tazama
The database
.
lib/ — msimbo wa pamoja, chochote unachotaka kutumia tena katika vishikilia: wasaidizi wa kawaida, safu za ufikiaji wa hifadhidata, uumbizaji, integrations na huduma za nje. lib/ ndiyo folda pekee inayoweza kuwa na ndogo-folda (lib/internal/util.js, lib/payments/stripe.js), ili uweze kupanga codebase kubwa jinsi unavyopenda. Moduli katika lib/ hazijawahi kuitwa moja kwa moja na jukwaa; zipo ili ziingizwe na vishikilia na kwa kila mmoja.
handlers/ — sehemu za kuingilia za boti yako. Kila faili inalingana na aina moja ya sasisho la Telegram, na jukwaa huelekeza kila sasisho linaloingia kwa kishikilia kinacholingana:
| Faili | Hushughulikia |
|---|---|
handlers/message.js |
Ujumbe mpya unaoingia |
handlers/inline_query.js |
Maswali mapya ya inline |
handlers/callback_query.js |
Maswali mapya ya callback |
| … | aina nyingine yoyote ya sasisho la Bot API |
handlers/ ni bapa — hakuna ndogo-folda. export default ya kishikilia ndicho kitendaji ambacho jukwaa huita (tazama
Handlers
).
Aina ya sasisho inashughulikiwa tu ikiwa faili ya kishikilia chake ipo na si tupu. Ikiwa hakuna handlers/<type>.js — au faili ni tupu — masasisho ya aina hiyo yanapuuzwa, na jukwaa halindeshi chochote kwa ajili yao. Kwa hivyo weka tu vishikilia unavyohitaji kweli: kila kimoja unachoongeza ni aina nyingine ya sasisho ambayo boti yako huamka kuishughulikia, na kuacha vingine inamaanisha Telegram haianzishi msimbo wako kwa masasisho ambayo ungeyapuuza tu.
Ili kuunda kishikilia kipya, endesha
npx tgcloud add handlers/<type>.
endpoints/ — upande wa seva wa Mini App yako. Kila faili ni kitendaji ambacho Mini App huita kwa jina, kwa hivyo endpoints/getProfile.js inajibu POST /api/getProfile. Jukwaa hukagua kuwa wito huo unatoka kwa mtumiaji wa Telegram ndani ya Mini App yako kabla msimbo wako haujaanza, na kukupa mtumiaji huyo. endpoints/ ni bapa, kama handlers/. Tazama
Endpoints
.
.tgcloud/ — hali ya mashine ya ndani inayodhibitiwa kikamilifu na CLI, ikijumuisha vitambulisho vyako vilivyohifadhiwa. Imepuuzwa na git, na hupaswi kamwe kusoma kutoka kwake au kuandika kwake kwa mkono — tumia amri za CLI badala yake.
Mfumo wa moduli
Wakati wa utekelezaji, moduli inaweza kuona vitu viwili tu: SDK ya jukwaa na moduli nyingine katika mradi wako. Hakuna vifurushi vya npm, hakuna mfumo wa faili, na hakuna mtandao isipokuwa kupitia fetch ya SDK.
Ingiza moduli zako mwenyewe jinsi ungefanya katika mradi wowote wa JavaScript — kwa njia ya jamaa, na kiendelezi cha .js — na SDK kwa jina lake:
// tgcloud/handlers/message.js
import { users } from '../schema.js'; // moduli ya schema
import { addItem } from '../lib/cart.js'; // moduli ya lib
import { format } from '../lib/internal/fmt.js'; // moduli ya lib iliyowekwa ndani
import { db, api, fetch } from 'sdk'; // SDK ya jukwaa
// tgcloud/lib/cart.js
import { format } from './internal/fmt.js'; // jirani
import { users } from '../schema.js';
Import ya jamaa lazima iishie katika .js na haiwezi kutoka nje ya tgcloud/:
import { users } from '../schema'; // ongeza .js
import config from '../../config.js'; // nje ya tgcloud/
import { z } from 'zod'; // hakuna vifurushi vya npm
Kila moduli pia ina jina — njia yake ndani ya tgcloud/ bila kiendelezi, kama schema, lib/cart au handlers/message. Jina hilo ndilo ambalo npx tgcloud run na matokeo ya CLI hutumia, na moduli inaweza kuingizwa kwa jina hilo pia (from 'lib/cart', hakuna kiendelezi). Pendelea imports za jamaa katika msimbo wako. Ndivyo mhariri wako anavyoelewa — jump‑to‑definition, autocomplete, rename.
Kinachopatikana wakati wa utekelezaji ni vitu viwili tu: sdk na moduli zake ndogo (sdk/db, sdk/api, sdk/fetch) — uso mzima wa jukwaa, tazama
The SDK
— na moduli zako mwenyewe katika tgcloud/. Hiyo ndiyo orodha kamili. Ikiwa msimbo wako una-import kitu kingine, haitafanya kazi. Kizuizi hiki ndicho kinachofanya moduli ziwe za haraka kupakia na salama kuendesha.
Handlers
Kishikilia ni moduli katika handlers/ ambayo default export yake inaitwa na jukwaa sasisho linapowasili.
// handlers/message.js
import { api } from 'sdk';
export default async function (message) {
await api.sendMessage({
chat_id: message.chat.id,
text: `Ulisema: ${message.text ?? '(hakuna maandishi)'}`,
});
}
Kishikilia hupokea payload ya sasisho kama hoja yake — jukwaa hufungua
Sasisho
la Telegram kwa ajili yako. handlers/message.js hupata
Ujumbe
(yaani update.message); handlers/callback_query.js hupata
CallbackQuery
; na kadhalika. Hoja ya pili ya kishikilia ni kitu cha muktadha wa kila ombi, ctx. Inachukua Update mbichi kama ctx.update — itumie unapohitaji kitu nje ya payload, kama update_id.
Kishikilia kinaweza kuwa async (kwa kawaida ndivyo kilivyo) na kinaweza kurudisha thamani. Hufikia Bot API, hifadhidata, na HTTP ya nje kupitia SDK.
Huna haja ya sasisho halisi ili kujaribu kishikilia. npx tgcloud run inakiendesha kwenye jukwaa na payload unayotoa na msimbo wako wa sasa wa ndani:
npx tgcloud run handlers/message '{ chat: { id: 1 }, text: "hi" }'
Hoja hiyo ni payload — kitu kilekile ambacho kishikilia chako hupokea — katika JSON5. Ili kutoa ctx ya kishikilia (hoja yake ya pili), ongeza --ctx, mfano --ctx '{ update: { update_id: 1 } }'. Hii inafanya kazi dhidi ya faili zako za ndani, kwa hivyo unaweza kujaribu mabadiliko kabla ya kuyapeleka. Tazama
run
.
Endpoints
Endpoint ni moduli katika endpoints/ ambayo Mini App yako inaita — mahali pa chochote ambacho front‑end haiwezi kufanya yenyewe, kama kusoma na kuandika hifadhidata, kuita Bot API, au kuzungumza na huduma za nje na siri zako.
// endpoints/getProfile.js
import { db, EndpointError } from 'sdk';
import { eq } from 'sdk/db';
import { profiles } from '../schema.js';
export default async function (input, ctx) {
const user = ctx.initData.user;
const profile = await db.select().from(profiles).where(eq(profiles.userId, user.id)).get();
if (!profile) throw new EndpointError('Profile not found', { userId: user.id });
return profile;
}
Hoja ya kwanza, input, ni kitu cha JSON ambacho Mini App ilituma. Ya pili, ctx, inachukua ctx.initData —
init data
ya Mini App (user, chat, start_param, auth_date, …), ambayo imethibitishwa na jukwaa. Ina umbo sawa na Telegram.WebApp.initDataUnsafe kwa mteja, lakini hapa unaweza kuiamini. Wito usio na init data sahihi unakataliwa na 401 kabla msimbo wako haujaanza, kwa hivyo ctx.initData.user ndiye mtu aliyefungua Mini App yako. Endpoints zinaweza kuitwa kwa njia hii tu — kutoka kwa Mini App ya boti yako, na mtumiaji wa Telegram — kwa hivyo hakuna API ya umma ya kulinda na hakuna login ya kujenga.
Chochote ambacho endpoint inarudisha kinatumwa tena kama JSON. Ili kukataa wito, throw new EndpointError(description, parameters?). Mini App inapata maelezo na kitu cha parameters kama vilivyo. Ikiwa unahitaji kuchanganua aina ya kosa katika front‑end, weka kodi kwenye parameters — { code: 'OUT_OF_STOCK' }. Ubaguzi wowote mwingine unaripotiwa kama kosa la jumla la ndani, na ujumbe halisi unaenda kwenye kumbukumbu zako tu, kwa hivyo mambo ya ndani hayavuji kwa mteja.
Kuita endpoint kutoka kwa Mini App
Mini App inaita endpoint kwa jina na Telegram.WebApp.Serverless.call kutoka kwa
Mini Apps SDK
rasmi, telegram-web-app.js — hati ambayo Mini App yako tayari inajumuisha. Inatuma init data kwa ajili yako na kurudisha kosa au matokeo ya endpoint:
Telegram.WebApp.Serverless.call('getProfile', { lang: 'en' }, function (err, profile) {
if (err) {
// err.message — maelezo; err.parameters — kile EndpointError ilichobeba
if (err.type === 'ENDPOINT_ERROR') showMessage(err.message);
return;
}
render(profile);
});
Input ni ya hiari na lazima iwe kitu rahisi. Bila hiyo wito ni Serverless.call('getProfile', callback).
err.type ni 'ENDPOINT_ERROR' wakati endpoint yako ilipotupa EndpointError. Thamani nyingine yoyote inamaanisha jukwaa lilikataliwa wito au endpoint ilishindwa bila kutarajiwa, kwa mfano 'UNAUTHORIZED' wakati init data haipo au si sahihi.
Majina ya Endpoint ni kama vitambulishi vya JavaScript — herufi, tarakimu na _, zisizoanza na tarakimu (getProfile, place_order). Iunde na
npx tgcloud add endpoints/<name>
, na ujaribu bila Mini App na
run
, ukitoa init data mwenyewe:
npx tgcloud run endpoints/getProfile '{}' --ctx '{ initData: { user: { id: 1, first_name: "Ann" } } }'
Nini kinachopelekwa
Wakati unapo-npx tgcloud push, CLI inakusanya kila faili ya .js chini ya schema.js, lib/, handlers/, na endpoints/, na kutuma seti hiyo kamili kama nafasi ya moduli ya mradi wako — pamoja na folda ya build ya Mini App, ikiwa tgcloud.jsonc inataja moja (tazama chini). Chochote kilichopo kwenye cloud lakini hakipo kwenye mradi wako kinafutwa, kwa hivyo hali iliyopelekwa daima huakisi folda yako — ikijumuisha ufutaji. Hakuna kitu nje ya tgcloud/ kinachopelekwa kama msimbo — mradi wote uliobaki ni wako. Ndani ya tgcloud/, faili ya .js ambayo haipo katika moja ya maeneo hayo (tgcloud/util.js, tgcloud/helpers/x.js) inawekwa alama, ili isisafirishwe bila kujulikana. Markdown, dotfiles, na .tgcloud/ hazijawahi kupelekwa.
Mini App front-end
Mzizi wa mradi ni wako, na ndio mahali pa asili kwa front‑end ya Mini App yako — iliyojengwa na React, Vue, Svelte au HTML rahisi, na Vite au bundler nyingine yoyote. Serverless inahifadhi matokeo ya build yake karibu na boti yako. push moja inapeleka msimbo na faili tuli pamoja, na programu inahudumiwa katika https://app<app_id>.tgcloud.ai/ (push inachapisha anwani kamili — itumie kama URL ya Mini App yako katika
@BotFather
).
Kuripoti unyanyasaji. Mini Apps kwenye tgcloud.ai zinachapishwa na wasanidi huru. Ili kuripoti maudhui haramu au unyanyasaji kwenye subdomain ya
app<app_id>.tgcloud.ai, tuma barua pepe kwa [email protected] .
Ili kuanza, tengeneza front‑end kwanza, na zana yoyote unayopenda, kisha ongeza Serverless juu yake:
npm create vite@latest example_app # au create-vue, …
cd example_app
npm create @tgcloud/bot .
Mtayarishaji wa mradi kamwe haifuti faili zako. Inaongeza folda ya tgcloud/ karibu na front‑end, inatambua folda ya build, na inaongeza hati ya npm run deploy ambayo inajenga programu na kuipeleka pamoja na boti.
Kinachohudumiwa kinawekwa katika tgcloud.jsonc, faili ya usanidi ya mradi kwenye mzizi wa mradi:
{
"$schema": "./node_modules/@tgcloud/cli/schema/tgcloud.json",
"static": {
"source": "dist",
"spa": true,
"immutable": ["/assets/*"],
"headers": [{ "path": "/*", "set": { "Referrer-Policy": "no-referrer" } }],
"redirects": [{ "from": "/old", "to": "/new", "status": 301 }]
}
}
"source" pekee ndiyo inayohitajika. Ni folda ya build, ya jamaa na mzizi wa mradi. Funguo zingine za "static" zinasanidi jinsi inavyohudumiwa (chini). init inatengeneza tgcloud.jsonc kwa ajili yako. Inapotambua front‑end, pia inajaza "source":
| Front‑end | init inaweka "source" kuwa |
|---|---|
| Vite — React, Vue, Svelte, Solid, … | dist |
| Next.js, Nuxt, SvelteKit, React Router, TanStack Start, Angular | hakuna — sanidi static export kwanza, kisha uweke "source" kwenye folda yake mwenyewe |
Kwa usanidi mwingine wowote, weka "source" kwenye folda yako ya build mwenyewe.
Mstari wa $schema unampa mhariri wako autocomplete na uthibitishaji kwa kila ufunguo. Faili ni JSON na maoni na koma za mwisho zinaruhusiwa. Ikiwa zana nyingine yako inahitaji kuisoma kama JSON rahisi, iite tgcloud.json badala yake — basi lazima iwe JSON kali.
Build kabla ya kusukuma. push hupakia folda kama ilivyo kwenye diski — isipokuwa faili na folda ambazo jina lake linaanza na nukta, ambazo hurukwa — na kamwe haifanyi build yako, kwa hivyo npx tgcloud push rahisi baada ya kuhariri front‑end ingepeleka build ya awali. Tumia npm run deploy (inaendesha hati yako ya build, kisha tgcloud push), au jenga mwenyewe kwanza.
Chaguzi za kuhudumia:
spa— hudumiaindex.htmlkwa njia ambazo hazipo na hazina kiendelezi cha faili, kwa hivyo kipanga njia cha upande wa mteja hufanya kazi kwenye reload. Njia zilizo na kiendelezi bado hupata404.immutable— ruwaza za faili zenye maelezo ya maudhui (Vite’s/assets/*) ambazo vivinjari vinaweza kuhifadhi kwa mwaka. Itumie tu kwa faili zenye maelezo ya maudhui. Faili nyingine yoyote inayolingana hapa ingekaa bila kusasishwa kwenye vivinjari kwa mwaka, na hakuna njia ya kuikumbuka.headers— vichwa vya majibu kwa njia ambazo sheria inalingana (njia kamili, au kiambishi kinachoishia katika/*). Thamani yanullhuondoa kichwa.redirects— sheria za kuelekeza, ambapo mechi ya kwanza inashinda. Faili iliyopo daima hushinda sheria.statusni301isipokuwa ukiweka nyingine."static": "dist"— njia ya mkato ya{ "source": "dist" }unapohitaji kitu kingine."static": false— ondoa tovuti iliyopelekwa kwenye push inayofuata. Kufuta ufunguo badala yake husitisha mradi huu kusimamia faili tuli, na chochote kilichopelekwa kinabaki.
Tovuti inahudumiwa kutoka mzizi wa mwenyeji wake, kwa hivyo base (/) ya msingi ya bundler yako ni sahihi. Telegram Web hufungua Mini Apps katika iframe, kwa hivyo usiongeze X-Frame-Options au sera kali ya frame-ancestors.
Mwenyeji uleule anajibu
endpoints
zako chini ya /api/ — hapo ndipo Telegram.WebApp.Serverless.call('getProfile', …) inapoenda. Usiweke faili zako mwenyewe chini ya /api/ kwenye folda ya build.
Hifadhidata
Kila boti inapata hifadhidata yake mwenyewe — hifadhi inayotumia SQLite inayodumu kati ya maombi na inapatikana kwa kila moduli kupitia db. Unaelezea jedwali zako katika schema.js na DSL ndogo, iliyochapwa; unazisoma na kuziandika na mjenzi wa wito wa maji; na unaziboresha na migrations zilizokaguliwa.
Unajua Drizzle ORM ? Basi tayari unajua jinsi ya kuzungumza na hifadhidata hapa. Schema DSL na mjenzi wa wito hufuata Drizzle — wajenzi wa safu,
select().from().where(), waendeshaji,onConflictDoUpdate,.returning(), nasqltag zote hufanya kazi jinsi unavyotarajia, kwa hivyo kusoma na kuandika data ni API inayojulikana unayotumia tayari. Unaiingiza tu kutokasdk/db, na mambo machache ya jukwaa (hasa bila funguo za kigeni ) yanaonyeshwa yanapotokea.
Kutangaza jedwali
Jedwali ni exports zilizopewa jina katika schema.js. Kuita table() hujenga maelezo wakati wa mzigo (haigusi hifadhidata); jukwaa hugundua jedwali zilizosafirishwa unapopeleka schema.js na kuhamisha hifadhidata ili ilingane.
import { table, integer, text, boolean, json, index, sql } from 'sdk/db';
export const users = table('users', {
id: integer('id').primaryKey({ autoIncrement: true }) ,
tgId: integer('tg_id').unique() ,
name: text('name').notNull() ,
lang: text('lang').default('en') ,
isAdmin: boolean('is_admin').default(false) ,
prefs: json('prefs') ,
created: integer('created_at', { mode: 'timestamp' }).default(sql`(unixepoch())`) ,
}, (t) => ({
createdIdx: index('idx_users_created').on(t.created) ,
}));
table(name, columns, extras?):
nameni jina la jedwali la SQL;columnsni ramani ya JS property → ufafanuzi wa safu;extrasni callback ya hiari(t) => ({ … })ambapotinafichua safu (t.createdni marejeleo ya safu hiyo) — tangaza faharisi na vikwazo vya kiwango cha jedwali hapa.
Aina za safu
| Kiwanda | Aina ya SQLite | Maelezo |
|---|---|---|
text() |
TEXT | |
integer() |
INTEGER | |
real() |
REAL | alias float() |
numeric() |
NUMERIC | |
blob() |
BLOB | inasoma/inaandika Uint8Array |
boolean() |
INTEGER | imehifadhiwa kama 0/1, inasomwa kama true/false |
json() |
TEXT | auto JSON.stringify / JSON.parse |
Hoja ya jina la safu ni ya hiari — iruke na key ya JS itatumika. Chaguo la
modelinadhibiti jinsi thamani hubadilika kati ya SQLite na JavaScript.
mode |
Imehifadhiwa kama | Thamani ya JS |
|---|---|---|
boolean |
INTEGER 0/1 | boolean |
json |
TEXT (JSON) | kitu chochote/safu |
timestamp |
INTEGER (unix seconds) | Date |
timestamp_ms |
INTEGER (unix ms) | Date |
bytes |
BLOB | Uint8Array |
boolean() na json() ni njia za mkato za integer(name, { mode: 'boolean' }) na text(name, { mode: 'json' }).
blob() inasoma na kuandika Uint8Array — utekelezaji hauna Node Buffer (na Buffer ni ndogo-darasa ya Uint8Array, kwa hivyo huu ndio aina ya msingi inayobebeka). mode hapo juu inadhibiti tu jinsi thamani inavyo-kodishwa, huru kutoka kwa aina ya uhifadhi wa safu: kwa hivyo blob('col', { mode: 'json' }) ni mwenzake wa BLOB wa json() — usimbaji huo huo wa JSON, uliowekwa kwenye safu ya BLOB badala ya TEXT.
TLDR:
blob()inatumiaUint8Array.modeinadhibiti usimbaji, si uhifadhi, kwa hivyoblob(..., { mode: 'json' })inahifadhi JSON kama BLOB, wakatijson()inahifadhi kama TEXT.
Vidhibiti vya safu
Vidhibiti vya safu hujiunga kwenye safu.
integer('id').primaryKey({ autoIncrement: true })
text('name').notNull()
text('tg').unique()
text('lang').default('en')
integer('created_at', { mode: 'timestamp' }).default(sql`(unixepoch())`)
text('slug').generatedAlwaysAs(sql`lower(name)`, { mode: 'stored' }) // au 'virtual'
text('email').deprecated('replaced by login') // inaweka alama ya safu kwa ajili ya kuondolewa
.default()kwenye safu yajson()inakukodisha thamani;sql`…`default inapitishwa kama ilivyo..deprecated()ni ya mwisho — tazama Migrations .
Faharisi na vikwazo
Faharisi na vikwazo vinatangazwa katika extras callback, ambapo safu ziko kwenye upeo.
table('t', { /* … */ }, (t) => ({
uq: unique('uq_email').on(t.email) ,
chk: check('chk_done', sql`${t.done} in (0, 1)`) ,
idx: index('idx_name').on(t.col) ,
uidx: uniqueIndex('uidx_email').on(t.email) ,
lower: index('idx_lower').on(sql`lower(${t.email})`) , // faharisi ya usemi
active: index('idx_active').on(t.userId).where(sql`done = 0`) , // faharisi ya sehemu
}));
Vidhibiti vya kiwango cha jedwali hujiunga baada ya table(...): .strict(), .withoutRowid(), .deprecated('reason').
Hakuna funguo za kigeni (Foreign keys)
Runtime inafanya kazi na PRAGMA foreign_keys ikiwa imezimwa. Ufunguo wa kigeni uliotangazwa ungekuwa bila nguvu kimya kimya — hakuna cascades, hakuna ulinzi wa yatima — ambayo ni mbaya kuliko kutokuwa na chochote, kwa hivyo DSL inafanya kuwa vigumu. Yaani, .references() na foreignKey() ya kiwango cha jedwali hutupa kosa inapotangazwa, na schema inayozitumia haitaweza kupelekwa.
Unapaswa kuweka mifano ya mahusiano na safu rahisi (userId: integer('user_id')) na kutekeleza uadilifu katika msimbo wa maombi yako: ingiza wazazi kabla ya watoto, futa watoto kabla ya wazazi, shughulikia makosa vizuri na futa yatima na LEFT JOIN … WHERE parent.id IS NULL unapohitaji.
Kutokuwepo kwa funguo za kigeni ni kizuizi cha makusudi, si kosa. Izingatie mapema unapopanga boti yako.
Kuhoji (Querying)
db ni mjenzi wa wito wa maji. Kila wito ni wa asynchronous — mbinu za mwisho (.all(), .get(), .values(), .run()) hurudisha Promises, kwa hivyo daima await.
import { db } from 'sdk';
import { eq, and, desc, asc, count, sql } from 'sdk/db';
import { users, todos } from '../schema.js';
await db.select().from(todos).all(); // safu zote
await db.select().from(todos).where(eq(todos.id, 1)).get(); // safu ya kwanza au null
await db.select().from(todos).values(); // safu kama safu za thamani
await db.select().from(todos)
.where(and(eq(todos.userId, uid) , eq(todos.done, false)))
.orderBy(desc(todos.priority) , asc(todos.id))
.limit(10).offset(20)
.all();
// makadirio ya kawaida: { alias: columnRef | sqlExpr | aggregate }
await db.select({ id: todos.id, title: todos.text, n: count() })
.from(todos).groupBy(todos.userId).having(sql`count(*) > ${1}`).all();
// hesabu ya safu — msaidizi, si mjenzi wa mwisho:
await db.$count(todos); // safu zote
await db.$count(todos, eq(todos.done, false)); // na kichujio
- Zinazoweza kuunganishwa:
.where(),.orderBy(),.limit(),.offset(),.groupBy(),.having(),.distinct(). - Mwisho:
.all(),.get(),.values(). - Hesabu safu na
db.$count(table, where?)(aucount()katika makadirio).
Ingiza, sasisha, futa:
await db.insert(todos).values({ userId: 1, text: 'Buy milk' }).run();
await db.insert(todos).values([{ text: 'A' }, { text: 'B' }]).run(); // kundi
await db.insert(todos).values({ text: 'X' }).returning().run(); // RETURNING *
await db.insert(users).values({ tgId: 42, name: 'Ann' })
.onConflictDoUpdate({ target: users.tgId, set: { name: 'Ann' } }).run();
await db.update(todos).set({ done: true }).where(eq(todos.id, 1)).run();
await db.delete(todos).where(eq(todos.id, 1)).run();
Kumbuka kuwa uingizaji wa kundi ni taarifa moja, kwa hivyo umepunguzwa na kikomo cha tofauti cha SQLite (
safu × safu wima); ukivuka, uingizaji unatoa kosa — igawanye mwenyewe.
Waendeshaji wanaingizwa kutoka sdk/db:
import {
eq, ne, gt, gte, lt, lte,
like, notLike,
isNull, isNotNull, and, or, not,
between, notBetween, inArray, notInArray,
count, sum, avg, min, max,
asc, desc,
} from 'sdk/db';
.where(a, b) na hoja nyingi ni sawa na and(a, b). Hoja ya pili ya ulinganisho ni thamani kwa chaguo-msingi, lakini inaweza kuwa safu nyingine au sql`…` — mfano eq(a.x, b.y). Aggregates (count/sum/avg/min/max) ni vipande vya sql kwa makadirio ya .select({ … }).
SQL mbichi — wakati mjenzi haitoshi, shuka kwenye SQL mbichi. Hali inachaguliwa na mbinu: db.run kwa uandishi, db.all kwa safu nyingi, db.get kwa safu moja, db.values kwa safu kama safu za msimamo.
await db.run('UPDATE todos SET done = 1 WHERE id = :id', { ':id': 5 });
// → { rowsAffected: 3, lastInsertRowid: 0, rows: [] }
await db.all(sql`SELECT * FROM todos WHERE done = ${false}`);
await db.get(sql`SELECT count(*) AS c FROM todos`);
await db.values(sql`SELECT id, text FROM todos`); // → [[1, 'buy milk']]
Uandishi unatatua kuwa matokeo ya uendeshaji — rowsAffected, lastInsertRowid, na rows, ambayo hubeba kifungu cha RETURNING ikiwa SQL ilikuwa na moja. Tumia db.values wakati wito unaonyesha safu mbili za jina moja (join kama SELECT u.id, o.id): db.all inaweka safu kwa jina la safu, kwa hivyo id ya pili ingeandika juu ya ya kwanza.
sql`…` tag inabadilisha ${value} kuwa kigezo kilichofungwa na ${table.column} kuwa kitambulishi, na kuunganisha vipande vya sql vilivyowekwa ndani. Tumia sql.raw('…') kwa herufi bila vigezo.
Wito mbichi hazijafungwa na jedwali, kwa hivyo safu zao hurudi bila ubadilishaji wa hali — boolean ni
0/1, safu ya JSON ni kamba, timestamp ni namba. Mjenzi aliyefungwa na jedwali pekee ndiye anayebadilisha thamani.
Migrations
Hifadhidata yako hubadilika boti yako inavyokua. Jukwaa huiweka salama kwa kutenganisha kupeleka msimbo kutoka kwa kubadilisha data, na kwa kuainisha kila mabadiliko ya schema kwa jinsi ya hatari ilivyo.
Kupeleka msimbo hakugusi hifadhidata. Unapopeleka npx tgcloud push schema.js iliyobadilika, jukwaa hurekodi schema mpya na kukuambia nini hifadhidata ingebadilisha — lakini haitumii chochote:
npx tgcloud push # peleka schema.js; inaripoti mabadiliko ya DB yanayosubiri
npx tgcloud migrate # kagua na uyaapply
npx tgcloud migrate huhesabu tofauti kati ya schema yako na hifadhidata hai na kukuongoza kupitia hiyo. Unaulizwa daima kabla ya chochote kutumika. Hii inamaanisha kupeleka msimbo wa kawaida hakuwezi kuanzisha mabadiliko ya data kwa bahati mbaya.
Kila mabadiliko yanayosubiri hubeba hali inayodhibiti jinsi migrate inavyoyatendea:
| Hali | Maana | Katika migrate |
|---|---|---|
| safe | Nyongeza na isiyozuia — jedwali jipya, safu, au faharisi | Zinatumiwa pamoja katika hatua moja, baada ya uthibitisho |
| warning | Inaweza kuharibu au polepole — kufuta kitu, au faharisi kwenye jedwali kubwa | Inawasilishwa moja kwa moja, kila moja ikithibitishwa kando |
| manual | Haiwezi kufanywa kiotomatiki — mfano kubadilisha aina ya safu | Inaonyeshwa na mwongozo; unaifanya kwa mkono |
| undocumented | Ipo kwenye hifadhidata lakini si kwenye schema yako | Inaonyeshwa kwa ufahamu; haitumiki |
Mabadiliko salama ni ya haraka na yanaweza kutenduliwa katika roho, kwa hivyo yanapita pamoja. Kila onyo ni uthibitisho wa makusudi, wa mtu binafsi — hakuna “apply all” kwa mabadiliko ya uharibifu.
Mabadiliko ya mwongozo huja na sababu na hatua iliyopendekezwa. migrate inaisha na muhtasari: mabadiliko mangapi yalitumiwa, kurukwa, kusubiri marekebisho ya mwongozo, au hayapo kwenye schema yako.
Tazama
migratekwa bendera (--dry-run,--safe,--yes,--local). Bila bendera,migrateinahitaji terminal na inatoa makosa katika mazingira yasiyo ya mwingiliano badala ya kubahatisha.
Kuondoa vitu
Kufuta jedwali au safu kutoka schema.js hakufuti — hiyo ingefanya ufutaji wa ajali kuwa mbaya sana. Ili kuondoa kitu, kiweke alama kuwa kimepitwa na wakati (deprecated):
// futa safu
text('email').deprecated('replaced by login')
// futa jedwali zima
export const oldSessions = table('old_sessions', { /* … */ }).deprecated('unused');
Katika migrate inayofuata, kitu kilichopitwa na wakati kinaonekana kama kushuka kwa hali ya onyo ambayo unathibitisha kando. Mara inapokuwa imekwenda, ondoa tangazo.
Kubadilisha aina ya safu
Mabadiliko ya aina ni ya mwongozo — SQLite haiwezi kuyafanya kila wakati mahali, na kulazimisha thamani zilizopo ni wito wa uamuzi. migrate itaonyesha mabadiliko na sababu yake; yafanye mwenyewe na SQL mbichi (db.run(...)), kwa kawaida kwa kutengeneza safu au jedwali mpya, kunakili data, na kubadilishana.
SDK
Wakati wa utekelezaji moduli ina maktaba moja: sdk. Inakusanya vitu vitatu ambavyo backend ya boti inahitaji — hifadhidata, Telegram Bot API, na HTTP ya nje — bila kitu cha kusakinisha na bila vitambulisho vya kusanidi. Hifadhidata (db) imeelezwa katika
The database
; sehemu hii inashughulikia api, fetch, na console ya kimataifa.
import { db, api, fetch, InputFile, BotApiError, EndpointError } from 'sdk'; // uso mzima
// au kutoka moduli ndogo:
import { table, integer, text, eq, sql } from 'sdk/db';
import { api } from 'sdk/api';
import { fetch } from 'sdk/fetch';
| Ingizo | Ni nini |
|---|---|
db |
Hifadhidata — mjenzi wa wito na schema DSL → The database |
api |
Telegram Bot API — api.sendMessage(...) →
chini
|
fetch |
HTTP ya nje → chini |
InputFile |
Faili (bytes + jina) ya kupakia — inafanya kazi na api na fetch →
Files
|
EndpointError |
Kataa wito wa Mini App na ujumbe inaoweza kuonyesha → Endpoints |
Ingiza moduli za mradi wako mwenyewe kwa njia ya jamaa na kiendelezi cha .js (from '../schema.js', from '../lib/cart.js'). Tazama
The module system
.
The Bot API
api inakupa
Telegram Bot API
nzima. Ita mbinu yoyote kama api.<method>(params). Kila mbinu ya sasa — na ya baadaye — ya Bot API inafanya kazi bila sasisho la SDK linalohitajika.
import { api } from 'sdk';
const me = await api.getMe(); // → matokeo yaliyofunguliwa
await api.sendMessage({ chat_id: id, text: 'Hujambo!' });
await api.editMessageText({ chat_id, message_id, text: 'Imesasishwa' });
await api.answerCallbackQuery({ callback_query_id, text: 'Imekamilika' });
Bahasha ya majibu imefunguliwa. Bot API kawaida hufunga matokeo katika { ok: true, result: … }. api inarudisha result moja kwa moja — getMe() inatatua kuwa kitu cha mtumiaji, si bahasha. Vigezo hutumia majina ya snake_case ya Bot API mwenyewe (chat_id, message_id, reply_markup, …).
Kushindwa hutupa BotApiError. Wakati Bot API inarudisha { ok: false }, wito hutupa BotApiError badala ya kurudisha thamani ya uwongo, kwa hivyo huwezi kuipuuza kwa bahati mbaya. Kosa linabeba .code (Bot API error_code), .description (ujumbe unaosomeka na binadamu), .method (ni mbinu gani ilishindwa), na .parameters (data ya ziada kama retry_after kwenye 429, au migrate_to_chat_id). Ikamate ili kushughulikia kushindwa kunakotarajiwa na kutupa tena vinginevyo:
import { api, BotApiError } from 'sdk';
try {
await api.deleteMessage({ chat_id, message_id });
} catch (e) {
if (e instanceof BotApiError && e.code === 400) {
// 400 = ujumbe umekwisha; ni sawa hapa.
} else {
throw e;
}
}
Faili
Fanya kazi na bytes za faili, si file_ids tu — pakia faili mpya na upakue zilizopo.
Pakia — InputFile. Funga bytes mbichi katika InputFile (kishikilia rahisi: bytes, jina la faili, na type ya hiari ya MIME) na upitishe popote mbinu ya Bot API inapotarajia faili:
import { api, InputFile } from 'sdk';
const doc = new InputFile(bytes, 'report.pdf', { type: 'application/pdf' });
await api.sendDocument({ chat_id, document: doc });
// faili zilizowekwa ndani ya params hufanya kazi pia — mfano albamu:
await api.sendMediaGroup({ chat_id, media: [
{ type: 'photo', media: new InputFile(a, 'a.jpg', { type: 'image/jpeg' }) },
{ type: 'photo', media: new InputFile(b, 'b.jpg', { type: 'image/jpeg' }) },
]});
Bytes zinatiririshwa kwenda Telegram kama upakiaji halisi wa multipart — faili haijahifadhiwa yote katika wito mmoja kwa jukwaa — lakini mipaka ya Bot API ya Telegram bado inatumika: boti kwa sasa inaweza kupakia hadi 50 MB kwa kila faili (na 10 MB kwa picha).
Pakua — na file_id. Wasaidizi wawili huvuta bytes za faili. Jukwaa hutatua file_id kwa ajili yako (inaendesha getFile na kuchota maudhui nyuma ya pazia), kwa hivyo huwezi kugusa token ya boti au URL ya kupakua:
const bytes = await api.getFileContent(file_id); // → Uint8Array (faili nzima)
const { file, body } = await api.getFileStream(file_id); // tiririsha badala yake
file.file_unique_id; // maelezo ya getFile
for await (const chunk of body) { /* Uint8Array */ } // au ihifadhi: await stream.bytes()
Bot API ya Telegram hufunga vipakuliwa vya
getFilekatika 20 MB, kwa hivyo huo ndio kikomo kwa wasaidizi wote wawili.
HTTP
fetch ni mteja anayefanana na fetch kwa kuita ulimwengu wa nje — API za watu wengine, webhooks, chochote kupitia HTTP.
import { fetch } from 'sdk';
const res = await fetch('https://api.example.com/users', {
method: 'POST',
headers: { 'Content-Type': 'application/json' },
body: JSON.stringify({ name: 'Pavel' }) ,
});
if (!res.ok) throw new Error(res.statusText);
const data = await res.json();
Majibu huakisi jukwaa la wavuti: res.status, res.statusText, res.ok (kweli kwa 200–299), res.url, res.headers (.get(), .has(), .keys(), .entries()), na wasomaji wa mwili await res.json() / await res.text().
Unaweza pia kusoma mwili kwa kuongezeka kama mkondo (stream) —
for await (const chunk of res.body) { … }— ambayo ndiyo jinsi unavyotumia matukio yaliyotumwa na seva au matokeo ya token-kwa-token kutoka AI APIs.
Wasaidizi wa mwili huweka Content-Type inayolingana kwa ajili yako:
await fetch(url, { method: 'POST', body: fetch.body.json({ a: 1 }) }); // application/json
await fetch(url, { method: 'POST', body: fetch.body.form({ a: 1 }) }); // x-www-form-urlencoded
await fetch(url, { method: 'POST', body: fetch.body.text('hi') }); // text/plain
Miili ya maombi inaweza pia kubeba faili na bytes mbichi: pitisha Uint8Array, InputFile, au FormData (kwa multipart/form-data) kama body, na bytes zinatiririshwa nje — kwa hivyo unaweza kupakia kwa API ya mtu wa tatu jinsi unavyotuma faili kwa Telegram:
import { fetch, FormData, InputFile } from 'sdk';
const form = new FormData();
form.append('file', new InputFile(bytes, 'photo.jpg', { type: 'image/jpeg' }));
form.append('caption', 'kutoka kwa boti yangu');
const res = await fetch('https://api.example.com/upload', { method: 'POST', body: form });
Vinginevyo inafanya kazi kama fetch ya kawaida unayoijua tayari, na vikwazo viwili:
- Majibu yanasomwa kama maandishi —
await res.json()/await res.text(), au kutiririshwa chunk-kwa-chunk nares.body. - Jumla ya majibu imefungwa katika 30 MB. Kikomo hicho kinashughulikia majibu yote — kutiririsha na
res.bodyhukuruhusu kuchakata mwili mkubwa kwa kuongezeka, lakini haiondoi kikomo.
Logging
console ya kimataifa ya kawaida inapatikana — hakuna cha kuingiza, ipo tu kama katika JavaScript yoyote. Matokeo yake yanakamatwa na kuonyeshwa na npx tgcloud run, ambayo inafanya kuwa zana yako kuu ya utatuzi wakati wa maendeleo.
console.log('inachakata', { chatId: id }); // log / debug — rahisi
console.info('imeanza'); // info — bluu
console.warn('kikomo cha kasi'); // warn — njano
console.error(err); // error — nyekundu, na stack trace
Kila mstari umewekwa alama na [file:line] ulikotoka. console.error na console.trace huongeza stack kamili, wakati console.warn haifanyi hivyo. Unapoi-npx tgcloud run moduli, mistari hii inachapishwa na kiambishi cha rangi kwa kila ngazi, muda tangu kuanza kwa uendeshaji, na asili — tazama
run
.
Command-line interface
tgcloud ni daraja kati ya folda ya mradi wako na cloud. Inaunda miradi, inakuonyesha nini kimebadilika, inapeleka, inaendesha moduli, na inatumia migrations za hifadhidata. Inahitaji
Node.js
18 au mpya zaidi. Njia mbili za kuipata:
# Inayopendekezwa — tengeneza mradi na CLI iliyosakinishwa ndani yake:
npm create @tgcloud/bot example_bot
# Au sakinisha CLI kimataifa na init folda tupu:
npm install -g @tgcloud/cli
tgcloud init
Kifurushi cha npm ni @tgcloud/cli, na amri inayosakinisha ni tgcloud. Kila amri inafanya kazi kutoka ndogo-folda yoyote ya mradi wako.
| Amri | Kusudi |
|---|---|
init
|
Unda mradi mpya katika folda ya sasa |
add
|
Unda moduli mpya (kishikilia, endpoint au moduli ya lib) |
login
|
Unganisha mradi na boti (huhifadhi token) |
status
|
Onyesha nini kimebadilika ndani ya kompyuta dhidi ya cloud |
diff
|
Onyesha mabadiliko ya mstari kwa mstari |
push
|
Peleka moduli zilizobadilika na build ya Mini App kwenye cloud |
migrate
|
Tumia mabadiliko ya schema kwenye hifadhidata |
run
|
Tekeleza moduli kwenye jukwaa bila kupeleka |
fetch
|
Kagua nini kimepelekwa, bila kubadilisha faili za ndani |
pull
|
Leta faili za ndani sambamba na cloud |
reset
|
Futa mabadiliko ya ndani; rejesha kutoka hali ya cloud |
webhook
|
Kagua na usawazishe webhook inayodhibitiwa na jukwaa |
completion
|
Chapisha hati ya kukamilisha shell (bash/zsh/fish) |
upgrade
|
Hamisha mpangilio wa mradi wa kabla ya 0.2.0 kwenye tgcloud/ |
Authentication
Mradi umeunganishwa na boti moja kwa token yake, ambayo ina umbo la app<id>:<secret>. Sehemu ya app<id> ni ya umma na inaweza kuchapishwa; siri haionekani kamwe kwenye kumbukumbu au makosa.
Token inatatuliwa kwa utaratibu huu:
TGCLOUD_TOKENtofauti ya mazingira — kwa CI; kamwe haiandikwi kwenye diski..tgcloud/credentials— iliandikwa nanpx tgcloud login.- Hakuna → kosa linalokuelekeza kwenye
npx tgcloud login.
CLI kamwe haiulizi token katikati ya amri. Kuingia daima ni hatua ya wazi ya login. Ikiwa token iliyohifadhiwa inakuwa batili, CLI huiondoa na kukuomba u-login tena.
init
npx tgcloud init
Inaunda mradi mpya katika saraka ya sasa: folda ya tgcloud/ na schema.js, lib/, handlers/ na kishikilia cha kuanzia, pamoja na tgcloud.jsonc, AGENTS.md, docs/, na folda ya hali ya .tgcloud/. Iendeshe kwenye mzizi wa mradi wa front‑end uliopo pia — inaongeza folda ya tgcloud/ na docs, na kamwe haifuti faili zako. Ikiwa inatambua front‑end, pia inaelekeza tgcloud.jsonc kwenye folda ya build na inaongeza hati ya deploy (jenga, kisha sukuma) kwenye package.json yako — tu ikiwa huna hati ya deploy tayari. Tazama
Mini App front‑end
.
init inakataa kuunda mradi ndani ya mradi mwingine. Kuiendesha tena kwenye mzizi wa mradi ni sawa na inaongeza tu chochote kinachokosekana.
add
npx tgcloud add <target>
Inaunda moduli moja mpya, iliyounganishwa na tayari kuhaririwa — kishikilia, endpoint au moduli ya lib/.
npx tgcloud add handlers/callback_query # kishikilia sasisho kipya
npx tgcloud add endpoints/getProfile # endpoint mpya kwa Mini App
npx tgcloud add lib/cart # moduli mpya ya pamoja
Kumbuka kuwa
addkamwe haifuti faili iliyopo.
<target> ni njia ya moduli (kiendelezi cha .js cha mwisho ni cha hiari). Kwa handlers/, jina lazima liwe aina ya sasisho la Telegram. Jukwaa hutangaza seti sahihi, kwa hivyo jina batili linakataliwa kwanza. handlers/ na endpoints/ ni bapa, wakati lib/ inaweza kuwekwa ndani (lib/payments/stripe).
Jina la moduli linahitajika. Kutoa folda tu ni kosa — lakini la kusaidia: kwa handlers/ inatoa orodha ya aina za masasisho ambazo huna bado, kwa hivyo unaweza kunakili moja.
$ npx tgcloud add handlers
Kosa: Taja jina, mfano "handlers/callback_query". Aina za handlers/ zinazopatikana: callback_query, inline_query, chat_member, …
<Tab>completion inatoa seti ileile — tazamacompletion.
Faili iliyoundwa ina export default hai, kwa hivyo kishikilia kinafanya kazi mara tu unapo-deploy — hakuna cha kuondoa maoni. Peleka moduli mpya na
push
.
login
npx tgcloud login
Inakuuliza token yako ya ufikiaji ya CLI — kutoka
@BotFather
→ boti yako → Serverless → CLI Access → Access token, token tofauti na
token ya API ya boti yako
— inathibitisha dhidi ya jukwaa, na kuihifadhi kwenye .tgcloud/credentials.
loginni amri pekee inayouliza token, na inahitaji terminal ya mwingiliano. Katika CI, wekaTGCLOUD_TOKENbadala yake.
status
npx tgcloud status
Inaonyesha, kwa kila faili, nini kimebadilika kati ya folda yako ya kazi na nakala iliyopelekwa: iliyorekebishwa, mpya, iliyofutwa, haijabadilika. Inafanya kazi nje ya mtandao, ikilinganisha dhidi ya hali ya cloud kama ya push, pull au fetch yako ya mwisho. Pia inaonya kuhusu faili za .js zilizopotea ndani ya tgcloud/ ambazo hazitapelekwa.
Kwa mradi wenye Mini App, status pia inaonyesha nini kimebadilika katika folda yake ya build tangu deploy ya mwisho.
diff
npx tgcloud diff
Kama status, lakini inaonyesha tofauti halisi ya mstari kwa mstari kwa moduli zilizobadilika. Pia nje ya mtandao.
push
npx tgcloud push [files...]
Inapeleka mradi wako kwenye cloud katika kundi moja.
Bila hoja yoyote, inapeleka mradi mzima, na hali iliyopelekwa inafanywa kuakisi folda yako kikamilifu — moduli ulizofuta ndani ya kompyuta zinaondolewa kwenye cloud.
Kwa hoja za faili au folda (npx tgcloud push tgcloud/handlers/message.js, npx tgcloud push handlers/), inapeleka tu mabadiliko katika faili hizo. Push inayolengwa kamwe haifuti moduli nyingine. Lengo linaweza kuandikwa kama njia ya faili (tgcloud/handlers/message.js), njia ndani ya tgcloud/ (handlers/message.js) au jina la moduli (handlers/message) — zote zinamaanisha moduli ileile.
Chaguo lake moja ni --force — kuruka ukaguzi wa usawaziko na kuandika juu ya chochote kilichopo kwenye cloud. Itumie tu unapokuwa na uhakika (tazama
Staying in sync
).
Ikiwa tgcloud.jsonc inataja folda tuli, push kamili inaipeleka katika kundi lileile — faili zilizobadilika tu ndizo zinazopakiwa — na inachapisha anwani ya tovuti. Jenga kwanza, kwa sababu push kamwe haifanyi build yako (npm run deploy hufanya yote). npx tgcloud push dist/ inapeleka faili tuli pekee, na push inayotaja moduli pekee inaziacha bila kuguswa.
Baada ya deploy, ikiwa schema.js ilibadilika na hifadhidata haijasawazishwa, push inachapisha muhtasari wa mabadiliko yanayosubiri na kupendekeza npx tgcloud migrate. Kamwe haitumii yenyewe.
migrate
npx tgcloud migrate
Inatumia mabadiliko yako ya schema kwenye hifadhidata. Inaunda tofauti kati ya schema.js na hifadhidata hai, kisha inakuongoza kupitia hiyo hatua kwa hatua na kaunta inayokimbia ya [N/M]:
- Muhtasari mfupi wa mabadiliko yote yanayosubiri.
- Mabadiliko salama, yaliyotumiwa pamoja katika hatua moja baada ya uthibitisho wako.
- Maonyo (kufuta, operesheni polepole), moja kwa moja, kila moja ikithibitishwa kando.
- Mabadiliko ya mwongozo, yaliyoonyeshwa na sababu na hatua iliyopendekezwa, hayatumiwi kiotomatiki.
- Vitu visivyothibitishwa (kwenye hifadhidata lakini si kwenye schema yako), yaliyoonyeshwa kwa ufahamu.
Inaisha na muhtasari: yaliyotumiwa, kurukwa, kusubiri marekebisho ya mwongozo, hayapo kwenye schema.
Tazama Migrations kwa mfano.
Chaguzi: --dry-run (chapisha kila kitu, usitumie chochote), --safe (auto‑apply mabadiliko salama, ruka maonyo), --yes (auto‑apply mabadiliko salama na kila onyo, ruka mwongozo — tumia kwa uangalifu), --local (linganisha dhidi ya schema.js ya ndani badala ya ile iliyopelekwa).
run
npx tgcloud run <module> [args] [--ctx <json5>]
Inatekeleza kishikilia au endpoint kwenye jukwaa bila kupeleka, ikitumia faili zako za sasa za ndani. Hii ndiyo mzunguko wa haraka wa ndani wa kujaribu mantiki.
<module>— jina wazi (lililotafutwa chini yahandlers/naendpoints/) au njia kamahandlers/message. Jina wazi lililopo katika folda zote mbili lazima liandikwe na folda yake.[args]— payload iliyopitishwa kwa kishikilia, iliyoandikwa katika JSON5 kwa hivyo unaweza kuruka kunukuu keys. Ni kitu cha aina ya sasisho ambacho kishikilia chako hupokea (mfano Ujumbe kwahandlers/message), auinputya endpoint, na lazima iwe kitu — si safu au kamba wazi.--ctx <json5>— kitu cha muktadha wa moduli (hoja yake ya pili), pia JSON5. Itumie kutoa kile msimbo wako unasoma kutokactx— sasisho mbichi kwa kishikilia,--ctx '{ update: { update_id: 1 } }', au init data kwa endpoint,--ctx '{ initData: { user: { id: 1 } } }'.runhaithibitishi, kwa kuwa unajaribu mantiki yako, si ukaguzi wa jukwaa.
npx tgcloud run handlers/message '{ chat: { id: 1 }, text: "hi" }'
Jukwaa linaendesha moduli dhidi ya nafasi ya moduli iliyokusanywa kutoka kwa mradi wako wa ndani (kwa hivyo msimbo wa lib/ uliobadilishwa ndani unatumika pia) na inarudisha thamani ya kurudishwa, chochote kilichoingizwa na console.*, na muda uliotumika. Soma hoja kubwa kutoka faili na npx tgcloud run handlers/message "$(cat message.json5)".
fetch
npx tgcloud fetch
Inakagua nini kimepelekwa sasa, bila kugusa faili zako za kazi. Baada ya hapo, status na diff hulinganisha dhidi ya hali ya hivi karibuni ya cloud. Ni muhimu kutazama mgogoro kabla ya kuamua jinsi ya kuutatua.
pull
npx tgcloud pull
Inaleta mradi wako wa ndani sambamba na cloud kwa kusasisha faili zako za kazi kwa hali iliyopelekwa.
pull kamwe haiandiki folda ya build ya Mini App yako.
reset
npx tgcloud reset
Inafuta mabadiliko yako ya ndani na kurejesha moduli kutoka hali ya mwisho inayojulikana ya cloud. Itumie kutupa majaribio. Folda ya build ya Mini App haiguswi.
webhook
npx tgcloud webhook
npx tgcloud webhook sync [--drop-pending]
Telegram huwasilisha masasisho kwa boti yako kupitia webhook, ambayo jukwaa inakusimamia — huwezi kuielekeza popote kwa mkono. npx tgcloud webhook inaonyesha hali yake ya sasa: URL, orodha ya allowed_updates, masasisho mangapi yanasubiri, kosa la mwisho la uwasilishaji (kama lipo), na kama iko katika usawaziko na vishikilia ulivyopeleka.
“Iko katika usawaziko” inamaanisha webhook inaelekeza kwenye jukwaa na allowed_updates zake zinalingana na vishikilia ulivyopeleka — kwa hivyo Telegram inawasilisha aina za masasisho unayoshughulikia, na si kitu kingine. Kupeleka kishikilia kipya (au kuondoa kimoja) kunaweza kuacha webhook nje ya usawaziko hadi ifufuliwe; npx tgcloud status inaweka alama hii pia.
npx tgcloud webhook sync inarekebisha — inaelekeza webhook kwenye jukwaa na kujenga upya allowed_updates kutoka kwa vishikilia ulivyopeleka. Ongeza --drop-pending ili kufuta masasisho ambayo Telegram ilikuwa imeyapanga kabla ya usawaziko (vinginevyo yatawasilishwa mara tu webhook itakapokuwa na afya tena).
completion
Kumbuka: tab‑completion inafanya kazi tu wakati
tgcloudwazi iko kwenyePATHyako — kwa hivyo isakinishe kimataifa (npm install -g @tgcloud/cli) au vinginevyo weka binary kwenyePATHyako. Haiwezi kuunganishwa kwenyenpx.
tgcloud completion <bash|zsh|fish>
Inachapisha hati ya kukamilisha shell kwenye stdout. Iwezeshe mara moja, kisha <Tab> inakamilisha amri, bendera, folda za moduli, aina za masasisho ya vishikilia ambayo huna bado, na moduli zako za ndani zinazoweza kuendeshwa.
# bash — inahitaji kifurushi cha bash-completion:
echo 'eval "$(tgcloud completion bash)"' >> ~/.bashrc
# zsh — hakikisha `autoload -U compinit && compinit` inaendeshwa katika ~/.zshrc yako:
echo 'eval "$(tgcloud completion zsh)"' >> ~/.zshrc
# fish:
tgcloud completion fish > ~/.config/fish/completions/tgcloud.fish
Anzisha tena shell yako (au re-source faili) baadaye. Kuendesha tgcloud completion bila shell kunachapisha maagizo haya tena.
upgrade
npx tgcloud upgrade [--dry-run]
Migration ya mara moja kwa miradi iliyoundwa kabla ya CLI 0.2.0, ambayo iliweka schema.js, lib/ na handlers/ kwenye mzizi wa mradi. Inazihamishia kwenye tgcloud/. Kiungo chako na boti kinahifadhiwa, na hakuna kinachohitaji kupelekwa tena. --dry-run inachapisha hatua zilizopangwa bila kugusa chochote. Amri nyingine hazifanyi kazi kwenye mpangilio wa zamani hadi utakapoboresha.
Staying in sync
Kila mradi una marekebisho (revision) yanayoongezeka kwa umoja katika cloud, yaliyoongezwa kwenye kila deploy. CLI inakumbuka marekebisho iliyosawazishwa nayo mara ya mwisho na inatuma kwenye kila push. Ikiwa cloud imesonga mbele — kwa sababu mashine nyingine au mfanyakazi mwenzako alipeleka — push inakataliwa badala ya kuandika juu ya kazi yao kimya kimya, na CLI inatoa njia tatu mbele:
npx tgcloud fetch # tazama nini kimebadilika kwenye cloud, kisha kagua tena
npx tgcloud pull # leta ya hivi karibuni kwenye faili zako za kazi
npx tgcloud push --force # andika juu ya hali ya cloud (hatari)
Ukaguzi huu wa usawaziko wa matumaini ndiyo sababu unaweza kushiriki boti kwenye timu bila mchakato wa deploy wa lockstep. Amri zinatoka zisizo-zero kwenye kushindwa — deploy iliyokataliwa, migration iliyoshindwa, kosa la uthibitishaji, moduli iliyotupa kosa wakati wa run — kwa hivyo zinajumuishwa vizuri katika hati na mabomba ya CI.