@volter/twin-telegram 1.0.0
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/LICENSE +202 -0
- package/README.md +53 -0
- package/dist/generated/pack-facts.json +53 -0
- package/dist/journeys/coverage.json +138 -0
- package/dist/journeys/customer-life.json +1229 -0
- package/dist/journeys/customer-life.outline.md +99 -0
- package/dist/journeys/customer-life.outline.verdict.json +76 -0
- package/dist/journeys/customer-life.verdict.json +134 -0
- package/dist/journeys/decisions.json +95 -0
- package/dist/journeys/demand.json +152 -0
- package/dist/journeys/score.json +163 -0
- package/dist/journeys/unreachable.json +29 -0
- package/dist/journeys/vendor-examples.json +1554 -0
- package/dist/journeys/vendor-examples.verdict.json +14 -0
- package/dist/spec/SOURCE.md +51 -0
- package/dist/spec/bot-api.html.gz +0 -0
- package/dist/spec/doc-examples.json +344 -0
- package/dist/spec/grouping.json +1 -0
- package/dist/spec/openapi.json.gz +0 -0
- package/dist/spec/page-to-openapi.ts +258 -0
- package/dist/spec/patches.json +289 -0
- package/dist/spec/sources.json +416 -0
- package/dist/src/cli.d.ts +2 -0
- package/dist/src/cli.js +21 -0
- package/dist/src/engine/media.d.ts +17 -0
- package/dist/src/engine/media.js +75 -0
- package/dist/src/engine/text.d.ts +45 -0
- package/dist/src/engine/text.js +512 -0
- package/dist/src/fetch.d.ts +2 -0
- package/dist/src/fetch.js +17 -0
- package/dist/src/generated/surface.gen.json +1 -0
- package/dist/src/generated/ui.gen.json +1 -0
- package/dist/src/index.d.ts +5 -0
- package/dist/src/index.js +9 -0
- package/dist/src/manifest.d.ts +2 -0
- package/dist/src/manifest.js +104 -0
- package/dist/src/semantics/around.d.ts +2 -0
- package/dist/src/semantics/around.js +32 -0
- package/dist/src/semantics/available-methods.d.ts +12 -0
- package/dist/src/semantics/available-methods.js +266 -0
- package/dist/src/semantics/doors.d.ts +18 -0
- package/dist/src/semantics/doors.js +292 -0
- package/dist/src/semantics/getting-updates.d.ts +3 -0
- package/dist/src/semantics/getting-updates.js +68 -0
- package/dist/src/semantics/index.d.ts +2 -0
- package/dist/src/semantics/index.js +19 -0
- package/dist/src/semantics/shared.d.ts +112 -0
- package/dist/src/semantics/shared.js +424 -0
- package/dist/src/semantics/states.d.ts +18 -0
- package/dist/src/semantics/states.js +37 -0
- package/dist/src/semantics/updating-messages.d.ts +2 -0
- package/dist/src/semantics/updating-messages.js +48 -0
- package/dist/src/server.d.ts +7 -0
- package/dist/src/server.js +24 -0
- package/generated/pack-facts.json +53 -0
- package/journeys/coverage.json +138 -0
- package/journeys/customer-life.json +1229 -0
- package/journeys/customer-life.outline.md +99 -0
- package/journeys/customer-life.outline.verdict.json +76 -0
- package/journeys/customer-life.verdict.json +134 -0
- package/journeys/decisions.json +95 -0
- package/journeys/demand.json +152 -0
- package/journeys/score.json +163 -0
- package/journeys/unreachable.json +29 -0
- package/journeys/vendor-examples.json +1554 -0
- package/journeys/vendor-examples.verdict.json +14 -0
- package/package.json +37 -0
- package/spec/SOURCE.md +51 -0
- package/spec/bot-api.html.gz +0 -0
- package/spec/doc-examples.json +344 -0
- package/spec/grouping.json +1 -0
- package/spec/openapi.json.gz +0 -0
- package/spec/page-to-openapi.ts +258 -0
- package/spec/patches.json +289 -0
- package/spec/sources.json +416 -0
- package/src/cli.ts +22 -0
- package/src/engine/media.ts +67 -0
- package/src/engine/text.ts +409 -0
- package/src/fetch.ts +18 -0
- package/src/generated/surface.gen.json +1 -0
- package/src/generated/ui.gen.json +1 -0
- package/src/index.ts +11 -0
- package/src/manifest.ts +114 -0
- package/src/semantics/around.ts +33 -0
- package/src/semantics/available-methods.ts +253 -0
- package/src/semantics/doors.ts +277 -0
- package/src/semantics/getting-updates.ts +64 -0
- package/src/semantics/index.ts +23 -0
- package/src/semantics/shared.ts +428 -0
- package/src/semantics/states.ts +38 -0
- package/src/semantics/updating-messages.ts +41 -0
- package/src/server.ts +17 -0
|
@@ -0,0 +1,258 @@
|
|
|
1
|
+
// Writes an OpenAPI 3.1 document of the Telegram Bot API from its reference page (https://core.telegram.org/bots/api),
|
|
2
|
+
// read as HTML (SOURCE.md names the bytes it read). Usage: bun spec/page-to-openapi.ts <page.html> <out.json>, then
|
|
3
|
+
// `gzip -n -9` the output to spec/openapi.json.gz.
|
|
4
|
+
//
|
|
5
|
+
// Every method's parameters are declared twice: as its body (JSON, form or multipart) and in its query string, since
|
|
6
|
+
// the Bot API reads them from either (Making requests: "We support four ways of passing parameters in Bot API
|
|
7
|
+
// requests", the first "URL query string").
|
|
8
|
+
import { readFileSync, writeFileSync } from 'node:fs';
|
|
9
|
+
|
|
10
|
+
const [, , inPath, outPath] = process.argv;
|
|
11
|
+
const html = readFileSync(inPath!, 'utf8');
|
|
12
|
+
|
|
13
|
+
const decode = (s: string) =>
|
|
14
|
+
s.replace(/</g, '<').replace(/>/g, '>').replace(/"/g, '"').replace(/'/g, "'").replace(/&/g, '&');
|
|
15
|
+
const text = (s: string) => decode(s.replace(/<br\s*\/?>/g, ' ').replace(/<[^>]+>/g, '')).replace(/\s+/g, ' ').trim();
|
|
16
|
+
|
|
17
|
+
// the page in order: h3 sections and h4 items, each item's HTML up to the next heading
|
|
18
|
+
type Item = { section: string; name: string; anchor: string; body: string };
|
|
19
|
+
const items: Item[] = [];
|
|
20
|
+
const heads = [...html.matchAll(/<h([34])><a class="anchor" name="([^"]+)"[^>]*><i class="anchor-icon"><\/i><\/a>([\s\S]*?)<\/h\1>/g)];
|
|
21
|
+
let section = '';
|
|
22
|
+
for (let i = 0; i < heads.length; i++) {
|
|
23
|
+
const h = heads[i]!;
|
|
24
|
+
const end = i + 1 < heads.length ? heads[i + 1]!.index! : html.indexOf('</div>', h.index!) > 0 ? html.length : html.length;
|
|
25
|
+
const body = html.slice(h.index! + h[0].length, end);
|
|
26
|
+
if (h[1] === '3') { section = text(h[3]!); continue; }
|
|
27
|
+
items.push({ section, name: text(h[3]!), anchor: h[2]!, body });
|
|
28
|
+
}
|
|
29
|
+
const METHOD_SECTIONS = new Set(['Getting updates', 'Available methods', 'Updating messages', 'Stickers', 'Rich messages', 'Inline mode', 'Payments', 'Telegram Passport', 'Games']);
|
|
30
|
+
const isType = (it: Item) => /^[A-Z][A-Za-z0-9]+$/.test(it.name) && it.section !== 'Recent changes';
|
|
31
|
+
const isMethod = (it: Item) => /^[a-z][A-Za-z0-9]+$/.test(it.name) && METHOD_SECTIONS.has(it.section) && !/\s/.test(it.name);
|
|
32
|
+
const typeNames = new Set(items.filter(isType).map((t) => t.name));
|
|
33
|
+
|
|
34
|
+
function tableRows(body: string): string[][] | null {
|
|
35
|
+
const t = body.match(/<table class="table">([\s\S]*?)<\/table>/);
|
|
36
|
+
if (!t) return null;
|
|
37
|
+
const rows = [...t[1]!.matchAll(/<tr>([\s\S]*?)<\/tr>/g)].map((r) => [...r[1]!.matchAll(/<t[dh]>([\s\S]*?)<\/t[dh]>/g)].map((c) => c[1]!));
|
|
38
|
+
return rows;
|
|
39
|
+
}
|
|
40
|
+
function beforeTable(body: string): string {
|
|
41
|
+
const i = body.indexOf('<table');
|
|
42
|
+
return i < 0 ? body : body.slice(0, i);
|
|
43
|
+
}
|
|
44
|
+
|
|
45
|
+
// a Type cell: Integer, String, Boolean, True, Float, InputFile, a type, "Array of X", "X or Y", "X, Y and Z"
|
|
46
|
+
function schemaOf(cell: string): any {
|
|
47
|
+
const t = text(cell).replace(/\s+/g, ' ').trim();
|
|
48
|
+
return parseType(t);
|
|
49
|
+
}
|
|
50
|
+
function parseType(t: string): any {
|
|
51
|
+
t = t.trim();
|
|
52
|
+
const arr = t.match(/^Array of (.+)$/);
|
|
53
|
+
if (arr) return { type: 'array', items: parseType(arr[1]!) };
|
|
54
|
+
const parts = t.split(/\s*,\s*|\s+or\s+|\s+and\s+/).filter(Boolean);
|
|
55
|
+
if (parts.length > 1) return { oneOf: parts.map(parseType) };
|
|
56
|
+
switch (t) {
|
|
57
|
+
case 'Integer': case 'Int': return { type: 'integer' };
|
|
58
|
+
case 'String': return { type: 'string' };
|
|
59
|
+
case 'Boolean': return { type: 'boolean' };
|
|
60
|
+
case 'True': return { type: 'boolean', enum: [true] };
|
|
61
|
+
case 'False': return { type: 'boolean', enum: [false] };
|
|
62
|
+
case 'Float': case 'Float number': return { type: 'number' };
|
|
63
|
+
case 'InputFile': return { type: 'string', format: 'binary' };
|
|
64
|
+
}
|
|
65
|
+
if (typeNames.has(t)) return { $ref: `#/components/schemas/${t}` };
|
|
66
|
+
throw new Error(`unknown type: ${t}`);
|
|
67
|
+
}
|
|
68
|
+
|
|
69
|
+
// quoted values the description states a field can take (“private”, “group” …)
|
|
70
|
+
function enumOf(desc: string, schema: any): any {
|
|
71
|
+
if (schema.type !== 'string') return schema;
|
|
72
|
+
const d = text(desc);
|
|
73
|
+
const m = d.match(/(?:\balways\b|\bcan be\b|\bmust be\b|\bone of\b)/);
|
|
74
|
+
if (!m) return schema;
|
|
75
|
+
// the rest of the sentence the phrase opens (a sentence ends at ". " before a capital, outside quotes)
|
|
76
|
+
const rest = d.slice(m.index!);
|
|
77
|
+
const end = rest.search(/\.\s+[A-Z]/);
|
|
78
|
+
const sentence = end < 0 ? rest : rest.slice(0, end);
|
|
79
|
+
const values = [...sentence.matchAll(/“([^”]+)”/g)].map((x) => x[1]!);
|
|
80
|
+
return values.length ? { ...schema, enum: [...new Set(values)] } : schema;
|
|
81
|
+
}
|
|
82
|
+
|
|
83
|
+
const schemas: Record<string, any> = {};
|
|
84
|
+
for (const it of items.filter(isType)) {
|
|
85
|
+
const rows = tableRows(it.body);
|
|
86
|
+
const desc = text(beforeTable(it.body));
|
|
87
|
+
if (rows && rows[0]?.[0]?.trim() === 'Field') {
|
|
88
|
+
const properties: Record<string, any> = {};
|
|
89
|
+
const required: string[] = [];
|
|
90
|
+
for (const r of rows.slice(1)) {
|
|
91
|
+
const [f, ty, d] = r;
|
|
92
|
+
const name = text(f!);
|
|
93
|
+
const s = enumOf(d!, schemaOf(ty!));
|
|
94
|
+
properties[name] = { ...s, description: text(d!) };
|
|
95
|
+
if (!/^Optional\./.test(text(d!))) required.push(name);
|
|
96
|
+
}
|
|
97
|
+
schemas[it.name] = { type: 'object', description: desc, properties, ...(required.length ? { required } : {}) };
|
|
98
|
+
continue;
|
|
99
|
+
}
|
|
100
|
+
const list = it.body.match(/<ul>([\s\S]*?)<\/ul>/);
|
|
101
|
+
if (list && !rows) {
|
|
102
|
+
const lis = [...list[1]!.matchAll(/<li>([\s\S]*?)<\/li>/g)].map((m) => m[1]!.trim());
|
|
103
|
+
const refs = lis.map((li) => li.match(/^<a href="#[a-z0-9]+">([A-Za-z0-9]+)<\/a>$/)?.[1]).filter((n): n is string => Boolean(n && typeNames.has(n)));
|
|
104
|
+
if (refs.length && refs.length === lis.length) { schemas[it.name] = { description: desc, oneOf: refs.map((n) => ({ $ref: `#/components/schemas/${n}` })) }; continue; }
|
|
105
|
+
}
|
|
106
|
+
// a type that holds no information yet ("Currently holds no information"), or one described in prose only
|
|
107
|
+
schemas[it.name] = { type: 'object', description: desc };
|
|
108
|
+
}
|
|
109
|
+
// InputFile is the multipart upload itself, not a JSON object
|
|
110
|
+
schemas.InputFile = { type: 'string', format: 'binary', description: schemas.InputFile?.description ?? 'This object represents the contents of a file to be uploaded.' };
|
|
111
|
+
|
|
112
|
+
// the result an operation's description says is returned
|
|
113
|
+
const RETURN_OVERRIDES: Record<string, any> = {};
|
|
114
|
+
function resultOf(it: Item): any {
|
|
115
|
+
if (RETURN_OVERRIDES[it.name]) return RETURN_OVERRIDES[it.name];
|
|
116
|
+
const descHtml = beforeTable(it.body);
|
|
117
|
+
const sentences = descHtml.split(/(?<=\.)\s+(?=[A-Z<])/).filter((s) => /return/i.test(text(s)));
|
|
118
|
+
const found: any[] = [];
|
|
119
|
+
const seen = new Set<string>();
|
|
120
|
+
const add = (key: string, s: any) => { if (!seen.has(key)) { seen.add(key); found.push(s); } };
|
|
121
|
+
for (const s of sentences) {
|
|
122
|
+
const tx = s;
|
|
123
|
+
for (const m of tx.matchAll(/(Array of |array of |an array of )?<a href="#([a-z0-9]+)">([A-Za-z0-9]+)<\/a>(s?)/g)) {
|
|
124
|
+
const name = m[3]!;
|
|
125
|
+
if (!typeNames.has(name)) continue;
|
|
126
|
+
const isArr = Boolean(m[1]) || (m[4] === 's' && /array of/i.test(tx.slice(Math.max(0, m.index! - 40), m.index!)));
|
|
127
|
+
add(`${isArr ? '[]' : ''}${name}`, isArr ? { type: 'array', items: { $ref: `#/components/schemas/${name}` } } : { $ref: `#/components/schemas/${name}` });
|
|
128
|
+
}
|
|
129
|
+
const plain = text(tx);
|
|
130
|
+
if (/\bTrue\b/.test(plain)) add('true', { type: 'boolean', enum: [true] });
|
|
131
|
+
if (/\bas String\b|\bString on success\b|\bin form of a String\b|new invite link as String/.test(plain)) add('string', { type: 'string' });
|
|
132
|
+
if (/\bReturns Int(eger)?\b|\bas Int(eger)?\b|\bInt(eger)? on success\b/.test(plain)) add('integer', { type: 'integer' });
|
|
133
|
+
if (/\bReturns String\b/.test(plain)) add('string', { type: 'string' });
|
|
134
|
+
}
|
|
135
|
+
if (!found.length) { console.error(`NO RESULT ${it.name}: ${text(descHtml)}`); return {}; }
|
|
136
|
+
return found.length === 1 ? found[0] : { oneOf: found };
|
|
137
|
+
}
|
|
138
|
+
|
|
139
|
+
// the types a method's result names (by itself, as an array's items, or as one of several): each is what the Bot API
|
|
140
|
+
// answers under `result` ("If 'ok' equals True, the request was successful and the result of the query can be found
|
|
141
|
+
// in the 'result' field", Making requests), so each is declared a resource under its own name (`x-resourceId`, the
|
|
142
|
+
// declaration the spec IR reads), and the IR reads every such answer under its envelope key, `answers.key: result`.
|
|
143
|
+
// The page has no GET read to infer them from: every method is written as a POST.
|
|
144
|
+
const answered = new Set<string>();
|
|
145
|
+
const namedIn = (s: any): void => {
|
|
146
|
+
if (!s || typeof s !== 'object') return;
|
|
147
|
+
if (typeof s.$ref === 'string') answered.add(s.$ref.split('/').pop());
|
|
148
|
+
if (s.items) namedIn(s.items);
|
|
149
|
+
for (const alt of s.oneOf ?? []) namedIn(alt);
|
|
150
|
+
};
|
|
151
|
+
|
|
152
|
+
const TAG: Record<string, string> = {};
|
|
153
|
+
const paths: Record<string, any> = {};
|
|
154
|
+
const methods = items.filter(isMethod);
|
|
155
|
+
for (const it of methods) {
|
|
156
|
+
const rows = tableRows(it.body);
|
|
157
|
+
const properties: Record<string, any> = {};
|
|
158
|
+
const required: string[] = [];
|
|
159
|
+
let hasFile = false;
|
|
160
|
+
if (rows && rows[0]?.[0]?.trim() === 'Parameter') {
|
|
161
|
+
for (const r of rows.slice(1)) {
|
|
162
|
+
const [p, ty, req, d] = r;
|
|
163
|
+
const name = text(p!);
|
|
164
|
+
const s = enumOf(d!, schemaOf(ty!));
|
|
165
|
+
if (/InputFile/.test(text(ty!))) hasFile = true;
|
|
166
|
+
properties[name] = { ...s, description: text(d!) };
|
|
167
|
+
if (text(req!) === 'Yes') required.push(name);
|
|
168
|
+
}
|
|
169
|
+
}
|
|
170
|
+
const body = { type: 'object', properties, ...(required.length ? { required } : {}) };
|
|
171
|
+
// the same parameters in the query string, none required there (a request carries each in one place or the other)
|
|
172
|
+
const query = Object.entries(properties).map(([name, schema]) => ({ name, in: 'query', required: false, description: schema.description, schema: Object.fromEntries(Object.entries(schema).filter(([k]) => k !== 'description')) }));
|
|
173
|
+
const result = resultOf(it);
|
|
174
|
+
namedIn(result);
|
|
175
|
+
paths[`/bot{token}/${it.name}`] = {
|
|
176
|
+
post: {
|
|
177
|
+
operationId: it.name,
|
|
178
|
+
tags: [it.section],
|
|
179
|
+
summary: it.name,
|
|
180
|
+
description: text(beforeTable(it.body)),
|
|
181
|
+
externalDocs: { url: `https://core.telegram.org/bots/api#${it.anchor}` },
|
|
182
|
+
parameters: [{ $ref: '#/components/parameters/token' }, ...query],
|
|
183
|
+
...(Object.keys(properties).length
|
|
184
|
+
? {
|
|
185
|
+
requestBody: {
|
|
186
|
+
required: required.length > 0,
|
|
187
|
+
content: {
|
|
188
|
+
'application/json': { schema: body },
|
|
189
|
+
'application/x-www-form-urlencoded': { schema: body },
|
|
190
|
+
'multipart/form-data': { schema: body },
|
|
191
|
+
},
|
|
192
|
+
},
|
|
193
|
+
}
|
|
194
|
+
: {}),
|
|
195
|
+
responses: {
|
|
196
|
+
'200': {
|
|
197
|
+
description: 'The request was successful: the result of the query is in the result field.',
|
|
198
|
+
content: { 'application/json': { schema: { type: 'object', required: ['ok', 'result'], properties: { ok: { type: 'boolean', enum: [true] }, result, description: { type: 'string' } } } } },
|
|
199
|
+
},
|
|
200
|
+
default: { $ref: '#/components/responses/Error' },
|
|
201
|
+
},
|
|
202
|
+
},
|
|
203
|
+
};
|
|
204
|
+
TAG[it.section] = it.section;
|
|
205
|
+
}
|
|
206
|
+
// the file download path getFile names ("https://api.telegram.org/file/bot<token>/<file_path>")
|
|
207
|
+
paths['/file/bot{token}/{file_path}'] = {
|
|
208
|
+
get: {
|
|
209
|
+
operationId: 'downloadFile',
|
|
210
|
+
tags: ['Available methods'],
|
|
211
|
+
summary: 'Download a file',
|
|
212
|
+
description: text(beforeTable(items.find((i) => i.name === 'getFile')!.body)),
|
|
213
|
+
externalDocs: { url: 'https://core.telegram.org/bots/api#getfile' },
|
|
214
|
+
parameters: [{ $ref: '#/components/parameters/token' }, { name: 'file_path', in: 'path', required: true, schema: { type: 'string' } }],
|
|
215
|
+
responses: { '200': { description: 'The file', content: { 'application/octet-stream': { schema: { type: 'string', format: 'binary' } } } }, default: { $ref: '#/components/responses/Error' } },
|
|
216
|
+
},
|
|
217
|
+
};
|
|
218
|
+
|
|
219
|
+
for (const name of answered) if (schemas[name]) schemas[name]['x-resourceId'] = name;
|
|
220
|
+
|
|
221
|
+
const ver = text(html.match(/<strong>Bot API ([0-9.]+)<\/strong>/)?.[0] ?? html.match(/Bot API ([0-9.]+)/)?.[0] ?? '');
|
|
222
|
+
const doc = {
|
|
223
|
+
openapi: '3.1.0',
|
|
224
|
+
info: {
|
|
225
|
+
title: 'Telegram Bot API',
|
|
226
|
+
version: ver.replace(/^Bot API /, ''),
|
|
227
|
+
description: 'Written from https://core.telegram.org/bots/api (spec/SOURCE.md): every method and type the page documents.',
|
|
228
|
+
},
|
|
229
|
+
servers: [{ url: 'https://api.telegram.org' }],
|
|
230
|
+
tags: [...new Set(methods.map((m) => m.section))].map((name) => ({ name })),
|
|
231
|
+
paths,
|
|
232
|
+
components: {
|
|
233
|
+
parameters: {
|
|
234
|
+
token: { name: 'token', in: 'path', required: true, description: "The bot's authentication token, as BotFather gives it (123456:ABC-DEF1234ghIkl-zyx57W2v1u123ew11).", schema: { type: 'string' } },
|
|
235
|
+
},
|
|
236
|
+
responses: {
|
|
237
|
+
Error: {
|
|
238
|
+
description: "The request was unsuccessful: 'ok' equals False and the error is explained in the 'description'.",
|
|
239
|
+
content: { 'application/json': { schema: { $ref: '#/components/schemas/Error' } } },
|
|
240
|
+
},
|
|
241
|
+
},
|
|
242
|
+
schemas: {
|
|
243
|
+
Error: {
|
|
244
|
+
type: 'object',
|
|
245
|
+
required: ['ok', 'error_code', 'description'],
|
|
246
|
+
properties: {
|
|
247
|
+
ok: { type: 'boolean', enum: [false] },
|
|
248
|
+
error_code: { type: 'integer' },
|
|
249
|
+
description: { type: 'string' },
|
|
250
|
+
parameters: { $ref: '#/components/schemas/ResponseParameters' },
|
|
251
|
+
},
|
|
252
|
+
},
|
|
253
|
+
...schemas,
|
|
254
|
+
},
|
|
255
|
+
},
|
|
256
|
+
};
|
|
257
|
+
writeFileSync(outPath!, JSON.stringify(doc, null, 1) + '\n');
|
|
258
|
+
console.log(`methods ${methods.length}, types ${Object.keys(schemas).length}, version ${doc.info.version}`);
|
|
@@ -0,0 +1,289 @@
|
|
|
1
|
+
{
|
|
2
|
+
"patches": [
|
|
3
|
+
{
|
|
4
|
+
"op": "add",
|
|
5
|
+
"path": "/paths/~1bot{token}~1sendMessage/post/requestBody/content/application~1json/schema/properties/reply_to_message_id",
|
|
6
|
+
"value": {
|
|
7
|
+
"type": "integer",
|
|
8
|
+
"description": "If the message is a reply, ID of the original message (read when reply_parameters is absent)"
|
|
9
|
+
},
|
|
10
|
+
"why": "The page lists only reply_parameters, but the Bot API server still reads reply_to_message_id (and allow_sending_without_reply) when a request carries no reply_parameters, and node-telegram-bot-api 0.66.0 as Postiz calls it sends reply_to_message_id (sendMessage).",
|
|
11
|
+
"source": {
|
|
12
|
+
"url": "https://raw.githubusercontent.com/tdlib/telegram-bot-api/e3e9dd8e5b3d7ab8537cd5a10dc31d5ffa8f82d1/telegram-bot-api/Client.cpp",
|
|
13
|
+
"quote": "result.reply_to_message_id = get_message_id(query, \"reply_to_message_id\");"
|
|
14
|
+
}
|
|
15
|
+
},
|
|
16
|
+
{
|
|
17
|
+
"op": "add",
|
|
18
|
+
"path": "/paths/~1bot{token}~1sendMessage/post/requestBody/content/application~1x-www-form-urlencoded/schema/properties/reply_to_message_id",
|
|
19
|
+
"value": {
|
|
20
|
+
"type": "integer",
|
|
21
|
+
"description": "If the message is a reply, ID of the original message (read when reply_parameters is absent)"
|
|
22
|
+
},
|
|
23
|
+
"why": "The page lists only reply_parameters, but the Bot API server still reads reply_to_message_id (and allow_sending_without_reply) when a request carries no reply_parameters, and node-telegram-bot-api 0.66.0 as Postiz calls it sends reply_to_message_id (sendMessage).",
|
|
24
|
+
"source": {
|
|
25
|
+
"url": "https://raw.githubusercontent.com/tdlib/telegram-bot-api/e3e9dd8e5b3d7ab8537cd5a10dc31d5ffa8f82d1/telegram-bot-api/Client.cpp",
|
|
26
|
+
"quote": "result.reply_to_message_id = get_message_id(query, \"reply_to_message_id\");"
|
|
27
|
+
}
|
|
28
|
+
},
|
|
29
|
+
{
|
|
30
|
+
"op": "add",
|
|
31
|
+
"path": "/paths/~1bot{token}~1sendMessage/post/requestBody/content/multipart~1form-data/schema/properties/reply_to_message_id",
|
|
32
|
+
"value": {
|
|
33
|
+
"type": "integer",
|
|
34
|
+
"description": "If the message is a reply, ID of the original message (read when reply_parameters is absent)"
|
|
35
|
+
},
|
|
36
|
+
"why": "The page lists only reply_parameters, but the Bot API server still reads reply_to_message_id (and allow_sending_without_reply) when a request carries no reply_parameters, and node-telegram-bot-api 0.66.0 as Postiz calls it sends reply_to_message_id (sendMessage).",
|
|
37
|
+
"source": {
|
|
38
|
+
"url": "https://raw.githubusercontent.com/tdlib/telegram-bot-api/e3e9dd8e5b3d7ab8537cd5a10dc31d5ffa8f82d1/telegram-bot-api/Client.cpp",
|
|
39
|
+
"quote": "result.reply_to_message_id = get_message_id(query, \"reply_to_message_id\");"
|
|
40
|
+
}
|
|
41
|
+
},
|
|
42
|
+
{
|
|
43
|
+
"op": "add",
|
|
44
|
+
"path": "/paths/~1bot{token}~1sendPhoto/post/requestBody/content/application~1json/schema/properties/reply_to_message_id",
|
|
45
|
+
"value": {
|
|
46
|
+
"type": "integer",
|
|
47
|
+
"description": "If the message is a reply, ID of the original message (read when reply_parameters is absent)"
|
|
48
|
+
},
|
|
49
|
+
"why": "The page lists only reply_parameters, but the Bot API server still reads reply_to_message_id (and allow_sending_without_reply) when a request carries no reply_parameters, and node-telegram-bot-api 0.66.0 as Postiz calls it sends reply_to_message_id (sendPhoto).",
|
|
50
|
+
"source": {
|
|
51
|
+
"url": "https://raw.githubusercontent.com/tdlib/telegram-bot-api/e3e9dd8e5b3d7ab8537cd5a10dc31d5ffa8f82d1/telegram-bot-api/Client.cpp",
|
|
52
|
+
"quote": "result.reply_to_message_id = get_message_id(query, \"reply_to_message_id\");"
|
|
53
|
+
}
|
|
54
|
+
},
|
|
55
|
+
{
|
|
56
|
+
"op": "add",
|
|
57
|
+
"path": "/paths/~1bot{token}~1sendPhoto/post/requestBody/content/application~1x-www-form-urlencoded/schema/properties/reply_to_message_id",
|
|
58
|
+
"value": {
|
|
59
|
+
"type": "integer",
|
|
60
|
+
"description": "If the message is a reply, ID of the original message (read when reply_parameters is absent)"
|
|
61
|
+
},
|
|
62
|
+
"why": "The page lists only reply_parameters, but the Bot API server still reads reply_to_message_id (and allow_sending_without_reply) when a request carries no reply_parameters, and node-telegram-bot-api 0.66.0 as Postiz calls it sends reply_to_message_id (sendPhoto).",
|
|
63
|
+
"source": {
|
|
64
|
+
"url": "https://raw.githubusercontent.com/tdlib/telegram-bot-api/e3e9dd8e5b3d7ab8537cd5a10dc31d5ffa8f82d1/telegram-bot-api/Client.cpp",
|
|
65
|
+
"quote": "result.reply_to_message_id = get_message_id(query, \"reply_to_message_id\");"
|
|
66
|
+
}
|
|
67
|
+
},
|
|
68
|
+
{
|
|
69
|
+
"op": "add",
|
|
70
|
+
"path": "/paths/~1bot{token}~1sendPhoto/post/requestBody/content/multipart~1form-data/schema/properties/reply_to_message_id",
|
|
71
|
+
"value": {
|
|
72
|
+
"type": "integer",
|
|
73
|
+
"description": "If the message is a reply, ID of the original message (read when reply_parameters is absent)"
|
|
74
|
+
},
|
|
75
|
+
"why": "The page lists only reply_parameters, but the Bot API server still reads reply_to_message_id (and allow_sending_without_reply) when a request carries no reply_parameters, and node-telegram-bot-api 0.66.0 as Postiz calls it sends reply_to_message_id (sendPhoto).",
|
|
76
|
+
"source": {
|
|
77
|
+
"url": "https://raw.githubusercontent.com/tdlib/telegram-bot-api/e3e9dd8e5b3d7ab8537cd5a10dc31d5ffa8f82d1/telegram-bot-api/Client.cpp",
|
|
78
|
+
"quote": "result.reply_to_message_id = get_message_id(query, \"reply_to_message_id\");"
|
|
79
|
+
}
|
|
80
|
+
},
|
|
81
|
+
{
|
|
82
|
+
"op": "add",
|
|
83
|
+
"path": "/paths/~1bot{token}~1sendVideo/post/requestBody/content/application~1json/schema/properties/reply_to_message_id",
|
|
84
|
+
"value": {
|
|
85
|
+
"type": "integer",
|
|
86
|
+
"description": "If the message is a reply, ID of the original message (read when reply_parameters is absent)"
|
|
87
|
+
},
|
|
88
|
+
"why": "The page lists only reply_parameters, but the Bot API server still reads reply_to_message_id (and allow_sending_without_reply) when a request carries no reply_parameters, and node-telegram-bot-api 0.66.0 as Postiz calls it sends reply_to_message_id (sendVideo).",
|
|
89
|
+
"source": {
|
|
90
|
+
"url": "https://raw.githubusercontent.com/tdlib/telegram-bot-api/e3e9dd8e5b3d7ab8537cd5a10dc31d5ffa8f82d1/telegram-bot-api/Client.cpp",
|
|
91
|
+
"quote": "result.reply_to_message_id = get_message_id(query, \"reply_to_message_id\");"
|
|
92
|
+
}
|
|
93
|
+
},
|
|
94
|
+
{
|
|
95
|
+
"op": "add",
|
|
96
|
+
"path": "/paths/~1bot{token}~1sendVideo/post/requestBody/content/application~1x-www-form-urlencoded/schema/properties/reply_to_message_id",
|
|
97
|
+
"value": {
|
|
98
|
+
"type": "integer",
|
|
99
|
+
"description": "If the message is a reply, ID of the original message (read when reply_parameters is absent)"
|
|
100
|
+
},
|
|
101
|
+
"why": "The page lists only reply_parameters, but the Bot API server still reads reply_to_message_id (and allow_sending_without_reply) when a request carries no reply_parameters, and node-telegram-bot-api 0.66.0 as Postiz calls it sends reply_to_message_id (sendVideo).",
|
|
102
|
+
"source": {
|
|
103
|
+
"url": "https://raw.githubusercontent.com/tdlib/telegram-bot-api/e3e9dd8e5b3d7ab8537cd5a10dc31d5ffa8f82d1/telegram-bot-api/Client.cpp",
|
|
104
|
+
"quote": "result.reply_to_message_id = get_message_id(query, \"reply_to_message_id\");"
|
|
105
|
+
}
|
|
106
|
+
},
|
|
107
|
+
{
|
|
108
|
+
"op": "add",
|
|
109
|
+
"path": "/paths/~1bot{token}~1sendVideo/post/requestBody/content/multipart~1form-data/schema/properties/reply_to_message_id",
|
|
110
|
+
"value": {
|
|
111
|
+
"type": "integer",
|
|
112
|
+
"description": "If the message is a reply, ID of the original message (read when reply_parameters is absent)"
|
|
113
|
+
},
|
|
114
|
+
"why": "The page lists only reply_parameters, but the Bot API server still reads reply_to_message_id (and allow_sending_without_reply) when a request carries no reply_parameters, and node-telegram-bot-api 0.66.0 as Postiz calls it sends reply_to_message_id (sendVideo).",
|
|
115
|
+
"source": {
|
|
116
|
+
"url": "https://raw.githubusercontent.com/tdlib/telegram-bot-api/e3e9dd8e5b3d7ab8537cd5a10dc31d5ffa8f82d1/telegram-bot-api/Client.cpp",
|
|
117
|
+
"quote": "result.reply_to_message_id = get_message_id(query, \"reply_to_message_id\");"
|
|
118
|
+
}
|
|
119
|
+
},
|
|
120
|
+
{
|
|
121
|
+
"op": "add",
|
|
122
|
+
"path": "/paths/~1bot{token}~1sendDocument/post/requestBody/content/application~1json/schema/properties/reply_to_message_id",
|
|
123
|
+
"value": {
|
|
124
|
+
"type": "integer",
|
|
125
|
+
"description": "If the message is a reply, ID of the original message (read when reply_parameters is absent)"
|
|
126
|
+
},
|
|
127
|
+
"why": "The page lists only reply_parameters, but the Bot API server still reads reply_to_message_id (and allow_sending_without_reply) when a request carries no reply_parameters, and node-telegram-bot-api 0.66.0 as Postiz calls it sends reply_to_message_id (sendDocument).",
|
|
128
|
+
"source": {
|
|
129
|
+
"url": "https://raw.githubusercontent.com/tdlib/telegram-bot-api/e3e9dd8e5b3d7ab8537cd5a10dc31d5ffa8f82d1/telegram-bot-api/Client.cpp",
|
|
130
|
+
"quote": "result.reply_to_message_id = get_message_id(query, \"reply_to_message_id\");"
|
|
131
|
+
}
|
|
132
|
+
},
|
|
133
|
+
{
|
|
134
|
+
"op": "add",
|
|
135
|
+
"path": "/paths/~1bot{token}~1sendDocument/post/requestBody/content/application~1x-www-form-urlencoded/schema/properties/reply_to_message_id",
|
|
136
|
+
"value": {
|
|
137
|
+
"type": "integer",
|
|
138
|
+
"description": "If the message is a reply, ID of the original message (read when reply_parameters is absent)"
|
|
139
|
+
},
|
|
140
|
+
"why": "The page lists only reply_parameters, but the Bot API server still reads reply_to_message_id (and allow_sending_without_reply) when a request carries no reply_parameters, and node-telegram-bot-api 0.66.0 as Postiz calls it sends reply_to_message_id (sendDocument).",
|
|
141
|
+
"source": {
|
|
142
|
+
"url": "https://raw.githubusercontent.com/tdlib/telegram-bot-api/e3e9dd8e5b3d7ab8537cd5a10dc31d5ffa8f82d1/telegram-bot-api/Client.cpp",
|
|
143
|
+
"quote": "result.reply_to_message_id = get_message_id(query, \"reply_to_message_id\");"
|
|
144
|
+
}
|
|
145
|
+
},
|
|
146
|
+
{
|
|
147
|
+
"op": "add",
|
|
148
|
+
"path": "/paths/~1bot{token}~1sendDocument/post/requestBody/content/multipart~1form-data/schema/properties/reply_to_message_id",
|
|
149
|
+
"value": {
|
|
150
|
+
"type": "integer",
|
|
151
|
+
"description": "If the message is a reply, ID of the original message (read when reply_parameters is absent)"
|
|
152
|
+
},
|
|
153
|
+
"why": "The page lists only reply_parameters, but the Bot API server still reads reply_to_message_id (and allow_sending_without_reply) when a request carries no reply_parameters, and node-telegram-bot-api 0.66.0 as Postiz calls it sends reply_to_message_id (sendDocument).",
|
|
154
|
+
"source": {
|
|
155
|
+
"url": "https://raw.githubusercontent.com/tdlib/telegram-bot-api/e3e9dd8e5b3d7ab8537cd5a10dc31d5ffa8f82d1/telegram-bot-api/Client.cpp",
|
|
156
|
+
"quote": "result.reply_to_message_id = get_message_id(query, \"reply_to_message_id\");"
|
|
157
|
+
}
|
|
158
|
+
},
|
|
159
|
+
{
|
|
160
|
+
"op": "add",
|
|
161
|
+
"path": "/paths/~1bot{token}~1sendMediaGroup/post/requestBody/content/application~1json/schema/properties/reply_to_message_id",
|
|
162
|
+
"value": {
|
|
163
|
+
"type": "integer",
|
|
164
|
+
"description": "If the message is a reply, ID of the original message (read when reply_parameters is absent)"
|
|
165
|
+
},
|
|
166
|
+
"why": "The page lists only reply_parameters, but the Bot API server still reads reply_to_message_id (and allow_sending_without_reply) when a request carries no reply_parameters, and node-telegram-bot-api 0.66.0 as Postiz calls it sends reply_to_message_id (sendMediaGroup).",
|
|
167
|
+
"source": {
|
|
168
|
+
"url": "https://raw.githubusercontent.com/tdlib/telegram-bot-api/e3e9dd8e5b3d7ab8537cd5a10dc31d5ffa8f82d1/telegram-bot-api/Client.cpp",
|
|
169
|
+
"quote": "result.reply_to_message_id = get_message_id(query, \"reply_to_message_id\");"
|
|
170
|
+
}
|
|
171
|
+
},
|
|
172
|
+
{
|
|
173
|
+
"op": "add",
|
|
174
|
+
"path": "/paths/~1bot{token}~1sendMediaGroup/post/requestBody/content/application~1x-www-form-urlencoded/schema/properties/reply_to_message_id",
|
|
175
|
+
"value": {
|
|
176
|
+
"type": "integer",
|
|
177
|
+
"description": "If the message is a reply, ID of the original message (read when reply_parameters is absent)"
|
|
178
|
+
},
|
|
179
|
+
"why": "The page lists only reply_parameters, but the Bot API server still reads reply_to_message_id (and allow_sending_without_reply) when a request carries no reply_parameters, and node-telegram-bot-api 0.66.0 as Postiz calls it sends reply_to_message_id (sendMediaGroup).",
|
|
180
|
+
"source": {
|
|
181
|
+
"url": "https://raw.githubusercontent.com/tdlib/telegram-bot-api/e3e9dd8e5b3d7ab8537cd5a10dc31d5ffa8f82d1/telegram-bot-api/Client.cpp",
|
|
182
|
+
"quote": "result.reply_to_message_id = get_message_id(query, \"reply_to_message_id\");"
|
|
183
|
+
}
|
|
184
|
+
},
|
|
185
|
+
{
|
|
186
|
+
"op": "add",
|
|
187
|
+
"path": "/paths/~1bot{token}~1sendMediaGroup/post/requestBody/content/multipart~1form-data/schema/properties/reply_to_message_id",
|
|
188
|
+
"value": {
|
|
189
|
+
"type": "integer",
|
|
190
|
+
"description": "If the message is a reply, ID of the original message (read when reply_parameters is absent)"
|
|
191
|
+
},
|
|
192
|
+
"why": "The page lists only reply_parameters, but the Bot API server still reads reply_to_message_id (and allow_sending_without_reply) when a request carries no reply_parameters, and node-telegram-bot-api 0.66.0 as Postiz calls it sends reply_to_message_id (sendMediaGroup).",
|
|
193
|
+
"source": {
|
|
194
|
+
"url": "https://raw.githubusercontent.com/tdlib/telegram-bot-api/e3e9dd8e5b3d7ab8537cd5a10dc31d5ffa8f82d1/telegram-bot-api/Client.cpp",
|
|
195
|
+
"quote": "result.reply_to_message_id = get_message_id(query, \"reply_to_message_id\");"
|
|
196
|
+
}
|
|
197
|
+
},
|
|
198
|
+
{
|
|
199
|
+
"op": "add",
|
|
200
|
+
"path": "/paths/~1bot{token}~1sendMessage/post/parameters/-",
|
|
201
|
+
"value": {
|
|
202
|
+
"name": "reply_to_message_id",
|
|
203
|
+
"in": "query",
|
|
204
|
+
"required": false,
|
|
205
|
+
"description": "If the message is a reply, ID of the original message (read when reply_parameters is absent)",
|
|
206
|
+
"schema": {
|
|
207
|
+
"type": "integer"
|
|
208
|
+
}
|
|
209
|
+
},
|
|
210
|
+
"why": "The page lists only reply_parameters, but the Bot API server still reads reply_to_message_id (and allow_sending_without_reply) when a request carries no reply_parameters, in the query string as in the body, and node-telegram-bot-api 0.66.0 as Postiz calls it sends reply_to_message_id (sendMessage).",
|
|
211
|
+
"source": {
|
|
212
|
+
"url": "https://raw.githubusercontent.com/tdlib/telegram-bot-api/e3e9dd8e5b3d7ab8537cd5a10dc31d5ffa8f82d1/telegram-bot-api/Client.cpp",
|
|
213
|
+
"quote": "result.reply_to_message_id = get_message_id(query, \"reply_to_message_id\");"
|
|
214
|
+
}
|
|
215
|
+
},
|
|
216
|
+
{
|
|
217
|
+
"op": "add",
|
|
218
|
+
"path": "/paths/~1bot{token}~1sendPhoto/post/parameters/-",
|
|
219
|
+
"value": {
|
|
220
|
+
"name": "reply_to_message_id",
|
|
221
|
+
"in": "query",
|
|
222
|
+
"required": false,
|
|
223
|
+
"description": "If the message is a reply, ID of the original message (read when reply_parameters is absent)",
|
|
224
|
+
"schema": {
|
|
225
|
+
"type": "integer"
|
|
226
|
+
}
|
|
227
|
+
},
|
|
228
|
+
"why": "The page lists only reply_parameters, but the Bot API server still reads reply_to_message_id (and allow_sending_without_reply) when a request carries no reply_parameters, in the query string as in the body, and node-telegram-bot-api 0.66.0 as Postiz calls it sends reply_to_message_id (sendPhoto).",
|
|
229
|
+
"source": {
|
|
230
|
+
"url": "https://raw.githubusercontent.com/tdlib/telegram-bot-api/e3e9dd8e5b3d7ab8537cd5a10dc31d5ffa8f82d1/telegram-bot-api/Client.cpp",
|
|
231
|
+
"quote": "result.reply_to_message_id = get_message_id(query, \"reply_to_message_id\");"
|
|
232
|
+
}
|
|
233
|
+
},
|
|
234
|
+
{
|
|
235
|
+
"op": "add",
|
|
236
|
+
"path": "/paths/~1bot{token}~1sendVideo/post/parameters/-",
|
|
237
|
+
"value": {
|
|
238
|
+
"name": "reply_to_message_id",
|
|
239
|
+
"in": "query",
|
|
240
|
+
"required": false,
|
|
241
|
+
"description": "If the message is a reply, ID of the original message (read when reply_parameters is absent)",
|
|
242
|
+
"schema": {
|
|
243
|
+
"type": "integer"
|
|
244
|
+
}
|
|
245
|
+
},
|
|
246
|
+
"why": "The page lists only reply_parameters, but the Bot API server still reads reply_to_message_id (and allow_sending_without_reply) when a request carries no reply_parameters, in the query string as in the body, and node-telegram-bot-api 0.66.0 as Postiz calls it sends reply_to_message_id (sendVideo).",
|
|
247
|
+
"source": {
|
|
248
|
+
"url": "https://raw.githubusercontent.com/tdlib/telegram-bot-api/e3e9dd8e5b3d7ab8537cd5a10dc31d5ffa8f82d1/telegram-bot-api/Client.cpp",
|
|
249
|
+
"quote": "result.reply_to_message_id = get_message_id(query, \"reply_to_message_id\");"
|
|
250
|
+
}
|
|
251
|
+
},
|
|
252
|
+
{
|
|
253
|
+
"op": "add",
|
|
254
|
+
"path": "/paths/~1bot{token}~1sendDocument/post/parameters/-",
|
|
255
|
+
"value": {
|
|
256
|
+
"name": "reply_to_message_id",
|
|
257
|
+
"in": "query",
|
|
258
|
+
"required": false,
|
|
259
|
+
"description": "If the message is a reply, ID of the original message (read when reply_parameters is absent)",
|
|
260
|
+
"schema": {
|
|
261
|
+
"type": "integer"
|
|
262
|
+
}
|
|
263
|
+
},
|
|
264
|
+
"why": "The page lists only reply_parameters, but the Bot API server still reads reply_to_message_id (and allow_sending_without_reply) when a request carries no reply_parameters, in the query string as in the body, and node-telegram-bot-api 0.66.0 as Postiz calls it sends reply_to_message_id (sendDocument).",
|
|
265
|
+
"source": {
|
|
266
|
+
"url": "https://raw.githubusercontent.com/tdlib/telegram-bot-api/e3e9dd8e5b3d7ab8537cd5a10dc31d5ffa8f82d1/telegram-bot-api/Client.cpp",
|
|
267
|
+
"quote": "result.reply_to_message_id = get_message_id(query, \"reply_to_message_id\");"
|
|
268
|
+
}
|
|
269
|
+
},
|
|
270
|
+
{
|
|
271
|
+
"op": "add",
|
|
272
|
+
"path": "/paths/~1bot{token}~1sendMediaGroup/post/parameters/-",
|
|
273
|
+
"value": {
|
|
274
|
+
"name": "reply_to_message_id",
|
|
275
|
+
"in": "query",
|
|
276
|
+
"required": false,
|
|
277
|
+
"description": "If the message is a reply, ID of the original message (read when reply_parameters is absent)",
|
|
278
|
+
"schema": {
|
|
279
|
+
"type": "integer"
|
|
280
|
+
}
|
|
281
|
+
},
|
|
282
|
+
"why": "The page lists only reply_parameters, but the Bot API server still reads reply_to_message_id (and allow_sending_without_reply) when a request carries no reply_parameters, in the query string as in the body, and node-telegram-bot-api 0.66.0 as Postiz calls it sends reply_to_message_id (sendMediaGroup).",
|
|
283
|
+
"source": {
|
|
284
|
+
"url": "https://raw.githubusercontent.com/tdlib/telegram-bot-api/e3e9dd8e5b3d7ab8537cd5a10dc31d5ffa8f82d1/telegram-bot-api/Client.cpp",
|
|
285
|
+
"quote": "result.reply_to_message_id = get_message_id(query, \"reply_to_message_id\");"
|
|
286
|
+
}
|
|
287
|
+
}
|
|
288
|
+
]
|
|
289
|
+
}
|