@tgify/tgify 0.1.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 +23 -0
- package/README.md +356 -0
- package/filters.d.ts +1 -0
- package/filters.js +1 -0
- package/format.d.ts +1 -0
- package/format.js +1 -0
- package/future.d.ts +1 -0
- package/future.js +1 -0
- package/lib/button.js +100 -0
- package/lib/cli.mjs +105 -0
- package/lib/composer.js +582 -0
- package/lib/context.js +1219 -0
- package/lib/core/helpers/args.js +57 -0
- package/lib/core/helpers/check.js +55 -0
- package/lib/core/helpers/compact.js +16 -0
- package/lib/core/helpers/deunionize.js +12 -0
- package/lib/core/helpers/formatting.js +91 -0
- package/lib/core/helpers/util.js +50 -0
- package/lib/core/network/client.js +330 -0
- package/lib/core/network/error.js +21 -0
- package/lib/core/network/multipart-stream.js +71 -0
- package/lib/core/network/polling.js +87 -0
- package/lib/core/network/webhook.js +54 -0
- package/lib/core/types/typegram.js +27 -0
- package/lib/filters.js +69 -0
- package/lib/format.js +38 -0
- package/lib/future.js +149 -0
- package/lib/index.js +58 -0
- package/lib/input.js +61 -0
- package/lib/markup.js +121 -0
- package/lib/middleware.js +2 -0
- package/lib/reactions.js +84 -0
- package/lib/router.js +46 -0
- package/lib/scenes/base.js +39 -0
- package/lib/scenes/context.js +104 -0
- package/lib/scenes/index.js +21 -0
- package/lib/scenes/stage.js +49 -0
- package/lib/scenes/wizard/context.js +31 -0
- package/lib/scenes/wizard/index.js +45 -0
- package/lib/scenes.js +17 -0
- package/lib/session.js +166 -0
- package/lib/telegraf.js +256 -0
- package/lib/telegram-types.js +6 -0
- package/lib/telegram.js +1240 -0
- package/lib/types.js +2 -0
- package/lib/utils.js +5 -0
- package/markup.d.ts +1 -0
- package/markup.js +1 -0
- package/package.json +140 -0
- package/scenes.d.ts +1 -0
- package/scenes.js +1 -0
- package/session.d.ts +1 -0
- package/session.js +1 -0
- package/src/button.ts +182 -0
- package/src/composer.ts +1008 -0
- package/src/context.ts +1661 -0
- package/src/core/helpers/args.ts +63 -0
- package/src/core/helpers/check.ts +71 -0
- package/src/core/helpers/compact.ts +18 -0
- package/src/core/helpers/deunionize.ts +26 -0
- package/src/core/helpers/formatting.ts +119 -0
- package/src/core/helpers/util.ts +96 -0
- package/src/core/network/client.ts +396 -0
- package/src/core/network/error.ts +29 -0
- package/src/core/network/multipart-stream.ts +45 -0
- package/src/core/network/polling.ts +94 -0
- package/src/core/network/webhook.ts +58 -0
- package/src/core/types/typegram.ts +54 -0
- package/src/filters.ts +109 -0
- package/src/format.ts +110 -0
- package/src/future.ts +213 -0
- package/src/index.ts +17 -0
- package/src/input.ts +59 -0
- package/src/markup.ts +142 -0
- package/src/middleware.ts +24 -0
- package/src/reactions.ts +118 -0
- package/src/router.ts +55 -0
- package/src/scenes/base.ts +52 -0
- package/src/scenes/context.ts +136 -0
- package/src/scenes/index.ts +21 -0
- package/src/scenes/stage.ts +71 -0
- package/src/scenes/wizard/context.ts +58 -0
- package/src/scenes/wizard/index.ts +63 -0
- package/src/scenes.ts +1 -0
- package/src/session.ts +204 -0
- package/src/telegraf.ts +354 -0
- package/src/telegram-types.ts +219 -0
- package/src/telegram.ts +1635 -0
- package/src/types.ts +2 -0
- package/src/utils.ts +1 -0
- package/types.d.ts +1 -0
- package/types.js +1 -0
- package/typings/button.d.ts +36 -0
- package/typings/button.d.ts.map +1 -0
- package/typings/composer.d.ts +227 -0
- package/typings/composer.d.ts.map +1 -0
- package/typings/context.d.ts +655 -0
- package/typings/context.d.ts.map +1 -0
- package/typings/core/helpers/args.d.ts +11 -0
- package/typings/core/helpers/args.d.ts.map +1 -0
- package/typings/core/helpers/check.d.ts +56 -0
- package/typings/core/helpers/check.d.ts.map +1 -0
- package/typings/core/helpers/compact.d.ts +4 -0
- package/typings/core/helpers/compact.d.ts.map +1 -0
- package/typings/core/helpers/deunionize.d.ts +18 -0
- package/typings/core/helpers/deunionize.d.ts.map +1 -0
- package/typings/core/helpers/formatting.d.ts +30 -0
- package/typings/core/helpers/formatting.d.ts.map +1 -0
- package/typings/core/helpers/util.d.ts +26 -0
- package/typings/core/helpers/util.d.ts.map +1 -0
- package/typings/core/network/client.d.ts +53 -0
- package/typings/core/network/client.d.ts.map +1 -0
- package/typings/core/network/error.d.ts +16 -0
- package/typings/core/network/error.d.ts.map +1 -0
- package/typings/core/network/multipart-stream.d.ts +16 -0
- package/typings/core/network/multipart-stream.d.ts.map +1 -0
- package/typings/core/network/polling.d.ts +16 -0
- package/typings/core/network/polling.d.ts.map +1 -0
- package/typings/core/network/webhook.d.ts +6 -0
- package/typings/core/network/webhook.d.ts.map +1 -0
- package/typings/core/types/typegram.d.ts +42 -0
- package/typings/core/types/typegram.d.ts.map +1 -0
- package/typings/filters.d.ts +18 -0
- package/typings/filters.d.ts.map +1 -0
- package/typings/format.d.ts +22 -0
- package/typings/format.d.ts.map +1 -0
- package/typings/future.d.ts +12 -0
- package/typings/future.d.ts.map +1 -0
- package/typings/index.d.ts +15 -0
- package/typings/index.d.ts.map +1 -0
- package/typings/input.d.ts +50 -0
- package/typings/input.d.ts.map +1 -0
- package/typings/markup.d.ts +27 -0
- package/typings/markup.d.ts.map +1 -0
- package/typings/middleware.d.ts +8 -0
- package/typings/middleware.d.ts.map +1 -0
- package/typings/reactions.d.ts +32 -0
- package/typings/reactions.d.ts.map +1 -0
- package/typings/router.d.ts +21 -0
- package/typings/router.d.ts.map +1 -0
- package/typings/scenes/base.d.ts +22 -0
- package/typings/scenes/base.d.ts.map +1 -0
- package/typings/scenes/context.d.ts +36 -0
- package/typings/scenes/context.d.ts.map +1 -0
- package/typings/scenes/index.d.ts +11 -0
- package/typings/scenes/index.d.ts.map +1 -0
- package/typings/scenes/stage.d.ts +24 -0
- package/typings/scenes/stage.d.ts.map +1 -0
- package/typings/scenes/wizard/context.d.ts +29 -0
- package/typings/scenes/wizard/context.d.ts.map +1 -0
- package/typings/scenes/wizard/index.d.ts +16 -0
- package/typings/scenes/wizard/index.d.ts.map +1 -0
- package/typings/scenes.d.ts +2 -0
- package/typings/scenes.d.ts.map +1 -0
- package/typings/session.d.ts +55 -0
- package/typings/session.d.ts.map +1 -0
- package/typings/telegraf.d.ts +115 -0
- package/typings/telegraf.d.ts.map +1 -0
- package/typings/telegram-types.d.ts +117 -0
- package/typings/telegram-types.d.ts.map +1 -0
- package/typings/telegram.d.ts +675 -0
- package/typings/telegram.d.ts.map +1 -0
- package/typings/types.d.ts +3 -0
- package/typings/types.d.ts.map +1 -0
- package/typings/utils.d.ts +2 -0
- package/typings/utils.d.ts.map +1 -0
- package/utils.d.ts +1 -0
- package/utils.js +1 -0
|
@@ -0,0 +1,57 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
|
+
exports.argsParser = argsParser;
|
|
4
|
+
const SINGLE_QUOTE = "'";
|
|
5
|
+
const DOUBLE_QUOTE = '"';
|
|
6
|
+
function argsParser(str, entities = [], entityOffset = 0) {
|
|
7
|
+
const mentions = {};
|
|
8
|
+
for (const entity of entities) // extract all text_mentions into an { offset: length } map
|
|
9
|
+
if (entity.type === 'text_mention' || entity.type === 'text_link')
|
|
10
|
+
mentions[entity.offset - entityOffset] = entity.length;
|
|
11
|
+
const args = [];
|
|
12
|
+
let done = 0;
|
|
13
|
+
let inside = undefined;
|
|
14
|
+
let buf = '';
|
|
15
|
+
function flush(to) {
|
|
16
|
+
if (done !== to)
|
|
17
|
+
args.push(buf + str.slice(done, to)), (inside = undefined);
|
|
18
|
+
buf = '';
|
|
19
|
+
done = to + 1;
|
|
20
|
+
}
|
|
21
|
+
for (let i = 0; i < str.length; i++) {
|
|
22
|
+
const char = str[i];
|
|
23
|
+
// quick lookup length of mention starting at i
|
|
24
|
+
const mention = mentions[i];
|
|
25
|
+
if (mention) {
|
|
26
|
+
// if we're inside a quote, eagerly flush existing state
|
|
27
|
+
flush(i);
|
|
28
|
+
// this also consumes current index, so decrement
|
|
29
|
+
done--;
|
|
30
|
+
// fast forward to end of mention
|
|
31
|
+
i += mention;
|
|
32
|
+
flush(i);
|
|
33
|
+
}
|
|
34
|
+
else if (char === SINGLE_QUOTE || char === DOUBLE_QUOTE)
|
|
35
|
+
if (inside)
|
|
36
|
+
if (inside === char)
|
|
37
|
+
flush(i);
|
|
38
|
+
else
|
|
39
|
+
continue;
|
|
40
|
+
else
|
|
41
|
+
flush(i), (inside = char);
|
|
42
|
+
else if (char === ' ')
|
|
43
|
+
if (inside)
|
|
44
|
+
continue;
|
|
45
|
+
else
|
|
46
|
+
flush(i);
|
|
47
|
+
else if (char === '\n')
|
|
48
|
+
flush(i);
|
|
49
|
+
else if (char === '\\')
|
|
50
|
+
(buf += str.slice(done, i)), (done = ++i); // skip parsing the next char
|
|
51
|
+
else
|
|
52
|
+
continue;
|
|
53
|
+
}
|
|
54
|
+
if (done < str.length)
|
|
55
|
+
flush(str.length);
|
|
56
|
+
return args;
|
|
57
|
+
}
|
|
@@ -0,0 +1,55 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
|
+
exports.hasProp = hasProp;
|
|
4
|
+
exports.hasPropType = hasPropType;
|
|
5
|
+
exports.is2D = is2D;
|
|
6
|
+
/**
|
|
7
|
+
* Checks if a given object has a property with a given name.
|
|
8
|
+
*
|
|
9
|
+
* Example invocation:
|
|
10
|
+
* ```js
|
|
11
|
+
* let obj = { 'foo': 'bar', 'baz': () => {} }
|
|
12
|
+
* hasProp(obj, 'foo') // true
|
|
13
|
+
* hasProp(obj, 'baz') // true
|
|
14
|
+
* hasProp(obj, 'abc') // false
|
|
15
|
+
* ```
|
|
16
|
+
*
|
|
17
|
+
* @param obj An object to test
|
|
18
|
+
* @param prop The name of the property
|
|
19
|
+
*/
|
|
20
|
+
function hasProp(obj, prop) {
|
|
21
|
+
return obj !== undefined && prop in obj;
|
|
22
|
+
}
|
|
23
|
+
/**
|
|
24
|
+
* Checks if a given object has a property with a given name.
|
|
25
|
+
* Furthermore performs a `typeof` check on the property if it exists.
|
|
26
|
+
*
|
|
27
|
+
* Example invocation:
|
|
28
|
+
* ```js
|
|
29
|
+
* let obj = { 'foo': 'bar', 'baz': () => {} }
|
|
30
|
+
* hasPropType(obj, 'foo', 'string') // true
|
|
31
|
+
* hasPropType(obj, 'baz', 'function') // true
|
|
32
|
+
* hasPropType(obj, 'abc', 'number') // false
|
|
33
|
+
* ```
|
|
34
|
+
*
|
|
35
|
+
* @param obj An object to test
|
|
36
|
+
* @param prop The name of the property
|
|
37
|
+
* @param type The type the property is expected to have
|
|
38
|
+
*/
|
|
39
|
+
function hasPropType(obj, prop, type) {
|
|
40
|
+
return hasProp(obj, prop) && type === typeof obj[prop];
|
|
41
|
+
}
|
|
42
|
+
/**
|
|
43
|
+
* Checks if the supplied array has two dimensions or not.
|
|
44
|
+
*
|
|
45
|
+
* Example invocations:
|
|
46
|
+
* is2D([]) // false
|
|
47
|
+
* is2D([[]]) // true
|
|
48
|
+
* is2D([[], []]) // true
|
|
49
|
+
* is2D([42]) // false
|
|
50
|
+
*
|
|
51
|
+
* @param arr an array with one or two dimensions
|
|
52
|
+
*/
|
|
53
|
+
function is2D(arr) {
|
|
54
|
+
return Array.isArray(arr[0]);
|
|
55
|
+
}
|
|
@@ -0,0 +1,16 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
|
+
exports.compactOptions = compactOptions;
|
|
4
|
+
function compactOptions(options) {
|
|
5
|
+
if (!options) {
|
|
6
|
+
return options;
|
|
7
|
+
}
|
|
8
|
+
const compacted = {};
|
|
9
|
+
for (const key in options)
|
|
10
|
+
if (
|
|
11
|
+
// todo(mkr): replace with Object.hasOwn in v5 (Node 16+)
|
|
12
|
+
Object.prototype.hasOwnProperty.call(options, key) &&
|
|
13
|
+
options[key] !== undefined)
|
|
14
|
+
compacted[key] = options[key];
|
|
15
|
+
return compacted;
|
|
16
|
+
}
|
|
@@ -0,0 +1,12 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
|
+
exports.deunionize = deunionize;
|
|
4
|
+
/**
|
|
5
|
+
* Expose properties from all union variants.
|
|
6
|
+
* @deprectated
|
|
7
|
+
* @see https://github.com/telegraf/telegraf/issues/1388#issuecomment-791573609
|
|
8
|
+
* @see https://millsp.github.io/ts-toolbelt/modules/union_strict.html
|
|
9
|
+
*/
|
|
10
|
+
function deunionize(t) {
|
|
11
|
+
return t;
|
|
12
|
+
}
|
|
@@ -0,0 +1,91 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
|
+
exports.linkOrMention = exports.join = exports.FmtString = void 0;
|
|
4
|
+
exports.createFmt = createFmt;
|
|
5
|
+
const util_1 = require("./util");
|
|
6
|
+
class FmtString {
|
|
7
|
+
constructor(text, entities) {
|
|
8
|
+
this.text = text;
|
|
9
|
+
if (entities) {
|
|
10
|
+
this.entities = entities;
|
|
11
|
+
// force parse_mode to undefined if entities are present
|
|
12
|
+
this.parse_mode = undefined;
|
|
13
|
+
}
|
|
14
|
+
}
|
|
15
|
+
static normalise(content) {
|
|
16
|
+
if (content instanceof FmtString)
|
|
17
|
+
return content;
|
|
18
|
+
return new FmtString(String(content));
|
|
19
|
+
}
|
|
20
|
+
}
|
|
21
|
+
exports.FmtString = FmtString;
|
|
22
|
+
const isArray = Array.isArray;
|
|
23
|
+
/** Given a base FmtString and something to append to it, mutates the base */
|
|
24
|
+
const _add = (base, next) => {
|
|
25
|
+
var _a;
|
|
26
|
+
const len = base.text.length;
|
|
27
|
+
if (next instanceof FmtString) {
|
|
28
|
+
base.text = `${base.text}${next.text}`;
|
|
29
|
+
// next.entities could be undefined and condition will fail
|
|
30
|
+
for (let i = 0; i < (((_a = next.entities) === null || _a === void 0 ? void 0 : _a.length) || 0); i++) {
|
|
31
|
+
// because of the above condition, next.entities[i] cannot be undefined
|
|
32
|
+
// eslint-disable-next-line @typescript-eslint/no-non-null-assertion
|
|
33
|
+
const entity = next.entities[i];
|
|
34
|
+
// base.entities is ensured by caller
|
|
35
|
+
// eslint-disable-next-line @typescript-eslint/no-non-null-assertion
|
|
36
|
+
base.entities.push({ ...entity, offset: entity.offset + len });
|
|
37
|
+
}
|
|
38
|
+
}
|
|
39
|
+
else
|
|
40
|
+
base.text = `${base.text}${next}`;
|
|
41
|
+
};
|
|
42
|
+
/**
|
|
43
|
+
* Given an `Iterable<FmtString | string | Any>` and a separator, flattens the list into a single FmtString.
|
|
44
|
+
* Analogous to Array#join -> string, but for FmtString
|
|
45
|
+
*/
|
|
46
|
+
const join = (fragments, separator) => {
|
|
47
|
+
const result = new FmtString('');
|
|
48
|
+
// ensure entities array so loop doesn't need to check
|
|
49
|
+
result.entities = [];
|
|
50
|
+
const iter = fragments[Symbol.iterator]();
|
|
51
|
+
let curr = iter.next();
|
|
52
|
+
while (!curr.done) {
|
|
53
|
+
_add(result, curr.value);
|
|
54
|
+
curr = iter.next();
|
|
55
|
+
if (separator && !curr.done)
|
|
56
|
+
_add(result, separator);
|
|
57
|
+
}
|
|
58
|
+
// set parse_mode: undefined if entities are present
|
|
59
|
+
if (result.entities.length)
|
|
60
|
+
result.parse_mode = undefined;
|
|
61
|
+
// remove entities array if not relevant
|
|
62
|
+
else
|
|
63
|
+
delete result.entities;
|
|
64
|
+
return result;
|
|
65
|
+
};
|
|
66
|
+
exports.join = join;
|
|
67
|
+
/** Internal constructor for all fmt helpers */
|
|
68
|
+
function createFmt(kind, opts) {
|
|
69
|
+
return function fmt(parts, ...items) {
|
|
70
|
+
var _a;
|
|
71
|
+
parts = isArray(parts) ? parts : [parts];
|
|
72
|
+
const result = (0, exports.join)((0, util_1.zip)(parts, items));
|
|
73
|
+
if (kind) {
|
|
74
|
+
(_a = result.entities) !== null && _a !== void 0 ? _a : (result.entities = []);
|
|
75
|
+
result.entities.unshift({
|
|
76
|
+
type: kind,
|
|
77
|
+
offset: 0,
|
|
78
|
+
length: result.text.length,
|
|
79
|
+
...opts,
|
|
80
|
+
});
|
|
81
|
+
result.parse_mode = undefined;
|
|
82
|
+
}
|
|
83
|
+
return result;
|
|
84
|
+
};
|
|
85
|
+
}
|
|
86
|
+
const linkOrMention = (content, data) => {
|
|
87
|
+
const { text, entities = [] } = FmtString.normalise(content);
|
|
88
|
+
entities.unshift(Object.assign(data, { offset: 0, length: text.length }));
|
|
89
|
+
return new FmtString(text, entities);
|
|
90
|
+
};
|
|
91
|
+
exports.linkOrMention = linkOrMention;
|
|
@@ -0,0 +1,50 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
|
+
exports.env = void 0;
|
|
4
|
+
exports.fmtCaption = fmtCaption;
|
|
5
|
+
exports.zip = zip;
|
|
6
|
+
exports.indexed = indexed;
|
|
7
|
+
exports.env = process.env;
|
|
8
|
+
function fmtCaption(extra) {
|
|
9
|
+
if (!extra)
|
|
10
|
+
return;
|
|
11
|
+
const caption = extra.caption;
|
|
12
|
+
if (!caption || typeof caption === 'string')
|
|
13
|
+
return extra;
|
|
14
|
+
const { text, entities } = caption;
|
|
15
|
+
return {
|
|
16
|
+
...extra,
|
|
17
|
+
caption: text,
|
|
18
|
+
...(entities && {
|
|
19
|
+
caption_entities: entities,
|
|
20
|
+
parse_mode: undefined,
|
|
21
|
+
}),
|
|
22
|
+
};
|
|
23
|
+
}
|
|
24
|
+
function* zip(xs, ys) {
|
|
25
|
+
const x = xs[Symbol.iterator]();
|
|
26
|
+
const y = ys[Symbol.iterator]();
|
|
27
|
+
let x1 = x.next();
|
|
28
|
+
let y1 = y.next();
|
|
29
|
+
while (!x1.done) {
|
|
30
|
+
yield x1.value;
|
|
31
|
+
if (!y1.done)
|
|
32
|
+
yield y1.value;
|
|
33
|
+
x1 = x.next();
|
|
34
|
+
y1 = y.next();
|
|
35
|
+
}
|
|
36
|
+
while (!y1.done) {
|
|
37
|
+
yield y1.value;
|
|
38
|
+
y1 = y.next();
|
|
39
|
+
}
|
|
40
|
+
}
|
|
41
|
+
function indexed(target, indexer) {
|
|
42
|
+
return new Proxy(target, {
|
|
43
|
+
get: function (target, prop, receiver) {
|
|
44
|
+
if ((typeof prop === 'string' || typeof prop === 'number') &&
|
|
45
|
+
!isNaN(+prop))
|
|
46
|
+
return indexer.call(target, +prop);
|
|
47
|
+
return Reflect.get(target, prop, receiver);
|
|
48
|
+
},
|
|
49
|
+
});
|
|
50
|
+
}
|
|
@@ -0,0 +1,330 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
var __createBinding = (this && this.__createBinding) || (Object.create ? (function(o, m, k, k2) {
|
|
3
|
+
if (k2 === undefined) k2 = k;
|
|
4
|
+
var desc = Object.getOwnPropertyDescriptor(m, k);
|
|
5
|
+
if (!desc || ("get" in desc ? !m.__esModule : desc.writable || desc.configurable)) {
|
|
6
|
+
desc = { enumerable: true, get: function() { return m[k]; } };
|
|
7
|
+
}
|
|
8
|
+
Object.defineProperty(o, k2, desc);
|
|
9
|
+
}) : (function(o, m, k, k2) {
|
|
10
|
+
if (k2 === undefined) k2 = k;
|
|
11
|
+
o[k2] = m[k];
|
|
12
|
+
}));
|
|
13
|
+
var __setModuleDefault = (this && this.__setModuleDefault) || (Object.create ? (function(o, v) {
|
|
14
|
+
Object.defineProperty(o, "default", { enumerable: true, value: v });
|
|
15
|
+
}) : function(o, v) {
|
|
16
|
+
o["default"] = v;
|
|
17
|
+
});
|
|
18
|
+
var __importStar = (this && this.__importStar) || (function () {
|
|
19
|
+
var ownKeys = function(o) {
|
|
20
|
+
ownKeys = Object.getOwnPropertyNames || function (o) {
|
|
21
|
+
var ar = [];
|
|
22
|
+
for (var k in o) if (Object.prototype.hasOwnProperty.call(o, k)) ar[ar.length] = k;
|
|
23
|
+
return ar;
|
|
24
|
+
};
|
|
25
|
+
return ownKeys(o);
|
|
26
|
+
};
|
|
27
|
+
return function (mod) {
|
|
28
|
+
if (mod && mod.__esModule) return mod;
|
|
29
|
+
var result = {};
|
|
30
|
+
if (mod != null) for (var k = ownKeys(mod), i = 0; i < k.length; i++) if (k[i] !== "default") __createBinding(result, mod, k[i]);
|
|
31
|
+
__setModuleDefault(result, mod);
|
|
32
|
+
return result;
|
|
33
|
+
};
|
|
34
|
+
})();
|
|
35
|
+
var __importDefault = (this && this.__importDefault) || function (mod) {
|
|
36
|
+
return (mod && mod.__esModule) ? mod : { "default": mod };
|
|
37
|
+
};
|
|
38
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
39
|
+
/* eslint @typescript-eslint/restrict-template-expressions: [ "error", { "allowNumber": true, "allowBoolean": true } ] */
|
|
40
|
+
const crypto = __importStar(require("crypto"));
|
|
41
|
+
const fs = __importStar(require("fs"));
|
|
42
|
+
const promises_1 = require("fs/promises");
|
|
43
|
+
const https = __importStar(require("https"));
|
|
44
|
+
const path = __importStar(require("path"));
|
|
45
|
+
const node_fetch_1 = __importDefault(require("node-fetch"));
|
|
46
|
+
const check_1 = require("../helpers/check");
|
|
47
|
+
const compact_1 = require("../helpers/compact");
|
|
48
|
+
const multipart_stream_1 = __importDefault(require("./multipart-stream"));
|
|
49
|
+
const error_1 = __importDefault(require("./error"));
|
|
50
|
+
const url_1 = require("url");
|
|
51
|
+
// eslint-disable-next-line @typescript-eslint/no-var-requires
|
|
52
|
+
const debug = require('debug')('telegraf:client');
|
|
53
|
+
const { isStream } = multipart_stream_1.default;
|
|
54
|
+
const WEBHOOK_REPLY_METHOD_ALLOWLIST = new Set([
|
|
55
|
+
'answerCallbackQuery',
|
|
56
|
+
'answerInlineQuery',
|
|
57
|
+
'deleteMessage',
|
|
58
|
+
'leaveChat',
|
|
59
|
+
'sendChatAction',
|
|
60
|
+
]);
|
|
61
|
+
const DEFAULT_EXTENSIONS = {
|
|
62
|
+
audio: 'mp3',
|
|
63
|
+
photo: 'jpg',
|
|
64
|
+
sticker: 'webp',
|
|
65
|
+
video: 'mp4',
|
|
66
|
+
animation: 'mp4',
|
|
67
|
+
video_note: 'mp4',
|
|
68
|
+
voice: 'ogg',
|
|
69
|
+
};
|
|
70
|
+
const DEFAULT_OPTIONS = {
|
|
71
|
+
apiRoot: 'https://api.telegram.org',
|
|
72
|
+
apiMode: 'bot',
|
|
73
|
+
webhookReply: true,
|
|
74
|
+
agent: new https.Agent({
|
|
75
|
+
keepAlive: true,
|
|
76
|
+
keepAliveMsecs: 10000,
|
|
77
|
+
}),
|
|
78
|
+
attachmentAgent: undefined,
|
|
79
|
+
testEnv: false,
|
|
80
|
+
};
|
|
81
|
+
function includesMedia(payload) {
|
|
82
|
+
return Object.entries(payload).some(([key, value]) => {
|
|
83
|
+
if (key === 'link_preview_options')
|
|
84
|
+
return false;
|
|
85
|
+
if (Array.isArray(value)) {
|
|
86
|
+
return value.some(({ media }) => media && typeof media === 'object' && (media.source || media.url));
|
|
87
|
+
}
|
|
88
|
+
return (value &&
|
|
89
|
+
typeof value === 'object' &&
|
|
90
|
+
(((0, check_1.hasProp)(value, 'source') && value.source) ||
|
|
91
|
+
((0, check_1.hasProp)(value, 'url') && value.url) ||
|
|
92
|
+
((0, check_1.hasPropType)(value, 'media', 'object') &&
|
|
93
|
+
(((0, check_1.hasProp)(value.media, 'source') && value.media.source) ||
|
|
94
|
+
((0, check_1.hasProp)(value.media, 'url') && value.media.url)))));
|
|
95
|
+
});
|
|
96
|
+
}
|
|
97
|
+
function replacer(_, value) {
|
|
98
|
+
if (value == null)
|
|
99
|
+
return undefined;
|
|
100
|
+
return value;
|
|
101
|
+
}
|
|
102
|
+
function buildJSONConfig(payload) {
|
|
103
|
+
return Promise.resolve({
|
|
104
|
+
method: 'POST',
|
|
105
|
+
compress: true,
|
|
106
|
+
headers: { 'content-type': 'application/json', connection: 'keep-alive' },
|
|
107
|
+
body: JSON.stringify(payload, replacer),
|
|
108
|
+
});
|
|
109
|
+
}
|
|
110
|
+
const FORM_DATA_JSON_FIELDS = [
|
|
111
|
+
'results',
|
|
112
|
+
'reply_markup',
|
|
113
|
+
'mask_position',
|
|
114
|
+
'shipping_options',
|
|
115
|
+
'errors',
|
|
116
|
+
];
|
|
117
|
+
async function buildFormDataConfig(payload, agent) {
|
|
118
|
+
for (const field of FORM_DATA_JSON_FIELDS) {
|
|
119
|
+
if ((0, check_1.hasProp)(payload, field) && typeof payload[field] !== 'string') {
|
|
120
|
+
payload[field] = JSON.stringify(payload[field]);
|
|
121
|
+
}
|
|
122
|
+
}
|
|
123
|
+
const boundary = crypto.randomBytes(32).toString('hex');
|
|
124
|
+
const formData = new multipart_stream_1.default(boundary);
|
|
125
|
+
await Promise.all(Object.keys(payload).map((key) =>
|
|
126
|
+
// @ts-expect-error payload[key] can obviously index payload, but TS doesn't trust us
|
|
127
|
+
attachFormValue(formData, key, payload[key], agent)));
|
|
128
|
+
return {
|
|
129
|
+
method: 'POST',
|
|
130
|
+
compress: true,
|
|
131
|
+
headers: {
|
|
132
|
+
'content-type': `multipart/form-data; boundary=${boundary}`,
|
|
133
|
+
connection: 'keep-alive',
|
|
134
|
+
},
|
|
135
|
+
body: formData,
|
|
136
|
+
};
|
|
137
|
+
}
|
|
138
|
+
async function attachFormValue(form, id, value, agent) {
|
|
139
|
+
if (value == null) {
|
|
140
|
+
return;
|
|
141
|
+
}
|
|
142
|
+
if (typeof value === 'string' ||
|
|
143
|
+
typeof value === 'boolean' ||
|
|
144
|
+
typeof value === 'number') {
|
|
145
|
+
form.addPart({
|
|
146
|
+
headers: { 'content-disposition': `form-data; name="${id}"` },
|
|
147
|
+
body: `${value}`,
|
|
148
|
+
});
|
|
149
|
+
return;
|
|
150
|
+
}
|
|
151
|
+
if (id === 'thumb' || id === 'thumbnail') {
|
|
152
|
+
const attachmentId = crypto.randomBytes(16).toString('hex');
|
|
153
|
+
await attachFormMedia(form, value, attachmentId, agent);
|
|
154
|
+
return form.addPart({
|
|
155
|
+
headers: { 'content-disposition': `form-data; name="${id}"` },
|
|
156
|
+
body: `attach://${attachmentId}`,
|
|
157
|
+
});
|
|
158
|
+
}
|
|
159
|
+
if (Array.isArray(value)) {
|
|
160
|
+
const items = await Promise.all(value.map(async (item) => {
|
|
161
|
+
var _a;
|
|
162
|
+
if (typeof item.media !== 'object') {
|
|
163
|
+
return await Promise.resolve(item);
|
|
164
|
+
}
|
|
165
|
+
const attachmentId = crypto.randomBytes(16).toString('hex');
|
|
166
|
+
await attachFormMedia(form, item.media, attachmentId, agent);
|
|
167
|
+
const thumb = (_a = item.thumb) !== null && _a !== void 0 ? _a : item.thumbnail;
|
|
168
|
+
if (typeof thumb === 'object') {
|
|
169
|
+
const thumbAttachmentId = crypto.randomBytes(16).toString('hex');
|
|
170
|
+
await attachFormMedia(form, thumb, thumbAttachmentId, agent);
|
|
171
|
+
return {
|
|
172
|
+
...item,
|
|
173
|
+
media: `attach://${attachmentId}`,
|
|
174
|
+
thumbnail: `attach://${thumbAttachmentId}`,
|
|
175
|
+
};
|
|
176
|
+
}
|
|
177
|
+
return { ...item, media: `attach://${attachmentId}` };
|
|
178
|
+
}));
|
|
179
|
+
return form.addPart({
|
|
180
|
+
headers: { 'content-disposition': `form-data; name="${id}"` },
|
|
181
|
+
body: JSON.stringify(items),
|
|
182
|
+
});
|
|
183
|
+
}
|
|
184
|
+
if (value &&
|
|
185
|
+
typeof value === 'object' &&
|
|
186
|
+
(0, check_1.hasProp)(value, 'media') &&
|
|
187
|
+
(0, check_1.hasProp)(value, 'type') &&
|
|
188
|
+
typeof value.media !== 'undefined' &&
|
|
189
|
+
typeof value.type !== 'undefined') {
|
|
190
|
+
const attachmentId = crypto.randomBytes(16).toString('hex');
|
|
191
|
+
await attachFormMedia(form, value.media, attachmentId, agent);
|
|
192
|
+
return form.addPart({
|
|
193
|
+
headers: { 'content-disposition': `form-data; name="${id}"` },
|
|
194
|
+
body: JSON.stringify({
|
|
195
|
+
...value,
|
|
196
|
+
media: `attach://${attachmentId}`,
|
|
197
|
+
}),
|
|
198
|
+
});
|
|
199
|
+
}
|
|
200
|
+
return await attachFormMedia(form, value, id, agent);
|
|
201
|
+
}
|
|
202
|
+
async function attachFormMedia(form, media, id, agent) {
|
|
203
|
+
var _a, _b, _c;
|
|
204
|
+
let fileName = (_a = media.filename) !== null && _a !== void 0 ? _a : `${id}.${(_b = DEFAULT_EXTENSIONS[id]) !== null && _b !== void 0 ? _b : 'dat'}`;
|
|
205
|
+
if ('url' in media && media.url !== undefined) {
|
|
206
|
+
const timeout = 500000; // ms
|
|
207
|
+
const res = await (0, node_fetch_1.default)(media.url, { agent, timeout });
|
|
208
|
+
return form.addPart({
|
|
209
|
+
headers: {
|
|
210
|
+
'content-disposition': `form-data; name="${id}"; filename="${fileName}"`,
|
|
211
|
+
},
|
|
212
|
+
body: res.body,
|
|
213
|
+
});
|
|
214
|
+
}
|
|
215
|
+
if ('source' in media && media.source) {
|
|
216
|
+
let mediaSource = media.source;
|
|
217
|
+
if (typeof media.source === 'string') {
|
|
218
|
+
const source = await (0, promises_1.realpath)(media.source);
|
|
219
|
+
if ((await (0, promises_1.stat)(source)).isFile()) {
|
|
220
|
+
fileName = (_c = media.filename) !== null && _c !== void 0 ? _c : path.basename(media.source);
|
|
221
|
+
mediaSource = await fs.createReadStream(media.source);
|
|
222
|
+
}
|
|
223
|
+
else {
|
|
224
|
+
throw new TypeError(`Unable to upload '${media.source}', not a file`);
|
|
225
|
+
}
|
|
226
|
+
}
|
|
227
|
+
if (isStream(mediaSource) || Buffer.isBuffer(mediaSource)) {
|
|
228
|
+
form.addPart({
|
|
229
|
+
headers: {
|
|
230
|
+
'content-disposition': `form-data; name="${id}"; filename="${fileName}"`,
|
|
231
|
+
},
|
|
232
|
+
body: mediaSource,
|
|
233
|
+
});
|
|
234
|
+
}
|
|
235
|
+
}
|
|
236
|
+
}
|
|
237
|
+
async function answerToWebhook(response, payload, options) {
|
|
238
|
+
if (!includesMedia(payload)) {
|
|
239
|
+
if (!response.headersSent) {
|
|
240
|
+
response.setHeader('content-type', 'application/json');
|
|
241
|
+
}
|
|
242
|
+
response.end(JSON.stringify(payload), 'utf-8');
|
|
243
|
+
return true;
|
|
244
|
+
}
|
|
245
|
+
const { headers, body } = await buildFormDataConfig(payload, options.attachmentAgent);
|
|
246
|
+
if (!response.headersSent) {
|
|
247
|
+
for (const [key, value] of Object.entries(headers)) {
|
|
248
|
+
response.setHeader(key, value);
|
|
249
|
+
}
|
|
250
|
+
}
|
|
251
|
+
await new Promise((resolve) => {
|
|
252
|
+
response.on('finish', resolve);
|
|
253
|
+
body.pipe(response);
|
|
254
|
+
});
|
|
255
|
+
return true;
|
|
256
|
+
}
|
|
257
|
+
function redactToken(error) {
|
|
258
|
+
error.message = error.message.replace(/\/(bot|user)(\d+):[^/]+\//, '/$1$2:[REDACTED]/');
|
|
259
|
+
throw error;
|
|
260
|
+
}
|
|
261
|
+
class ApiClient {
|
|
262
|
+
constructor(token, options, response) {
|
|
263
|
+
this.token = token;
|
|
264
|
+
this.response = response;
|
|
265
|
+
this.options = {
|
|
266
|
+
...DEFAULT_OPTIONS,
|
|
267
|
+
...(0, compact_1.compactOptions)(options),
|
|
268
|
+
};
|
|
269
|
+
if (this.options.apiRoot.startsWith('http://')) {
|
|
270
|
+
this.options.agent = undefined;
|
|
271
|
+
}
|
|
272
|
+
}
|
|
273
|
+
/**
|
|
274
|
+
* If set to `true`, first _eligible_ call will avoid performing a POST request.
|
|
275
|
+
* Note that such a call:
|
|
276
|
+
* 1. cannot report errors or return meaningful values,
|
|
277
|
+
* 2. resolves before bot API has a chance to process it,
|
|
278
|
+
* 3. prematurely confirms the update as processed.
|
|
279
|
+
*
|
|
280
|
+
* https://core.telegram.org/bots/faq#how-can-i-make-requests-in-response-to-updates
|
|
281
|
+
* https://github.com/telegraf/telegraf/pull/1250
|
|
282
|
+
*/
|
|
283
|
+
set webhookReply(enable) {
|
|
284
|
+
this.options.webhookReply = enable;
|
|
285
|
+
}
|
|
286
|
+
get webhookReply() {
|
|
287
|
+
return this.options.webhookReply;
|
|
288
|
+
}
|
|
289
|
+
async callApi(method, payload, { signal } = {}) {
|
|
290
|
+
const { token, options, response } = this;
|
|
291
|
+
if (options.webhookReply &&
|
|
292
|
+
(response === null || response === void 0 ? void 0 : response.writableEnded) === false &&
|
|
293
|
+
WEBHOOK_REPLY_METHOD_ALLOWLIST.has(method)) {
|
|
294
|
+
debug('Call via webhook', method, payload);
|
|
295
|
+
// @ts-expect-error using webhookReply is an optimisation that doesn't respond with normal result
|
|
296
|
+
// up to the user to deal with this
|
|
297
|
+
return await answerToWebhook(response, { method, ...payload }, options);
|
|
298
|
+
}
|
|
299
|
+
if (!token) {
|
|
300
|
+
throw new error_1.default({
|
|
301
|
+
error_code: 401,
|
|
302
|
+
description: 'Bot Token is required',
|
|
303
|
+
});
|
|
304
|
+
}
|
|
305
|
+
debug('HTTP call', method, payload);
|
|
306
|
+
const config = includesMedia(payload)
|
|
307
|
+
? await buildFormDataConfig({ method, ...payload }, options.attachmentAgent)
|
|
308
|
+
: await buildJSONConfig(payload);
|
|
309
|
+
const apiUrl = new url_1.URL(`./${options.apiMode}${token}${options.testEnv ? '/test' : ''}/${method}`, options.apiRoot);
|
|
310
|
+
config.agent = options.agent;
|
|
311
|
+
// @ts-expect-error AbortSignal shim is missing some props from Request.AbortSignal
|
|
312
|
+
config.signal = signal;
|
|
313
|
+
config.timeout = 500000; // ms
|
|
314
|
+
const res = await (0, node_fetch_1.default)(apiUrl, config).catch(redactToken);
|
|
315
|
+
if (res.status >= 500) {
|
|
316
|
+
const errorPayload = {
|
|
317
|
+
error_code: res.status,
|
|
318
|
+
description: res.statusText,
|
|
319
|
+
};
|
|
320
|
+
throw new error_1.default(errorPayload, { method, payload });
|
|
321
|
+
}
|
|
322
|
+
const data = await res.json();
|
|
323
|
+
if (!data.ok) {
|
|
324
|
+
debug('API call failed', data);
|
|
325
|
+
throw new error_1.default(data, { method, payload });
|
|
326
|
+
}
|
|
327
|
+
return data.result;
|
|
328
|
+
}
|
|
329
|
+
}
|
|
330
|
+
exports.default = ApiClient;
|
|
@@ -0,0 +1,21 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
|
+
exports.TelegramError = void 0;
|
|
4
|
+
class TelegramError extends Error {
|
|
5
|
+
constructor(response, on = {}) {
|
|
6
|
+
super(`${response.error_code}: ${response.description}`);
|
|
7
|
+
this.response = response;
|
|
8
|
+
this.on = on;
|
|
9
|
+
}
|
|
10
|
+
get code() {
|
|
11
|
+
return this.response.error_code;
|
|
12
|
+
}
|
|
13
|
+
get description() {
|
|
14
|
+
return this.response.description;
|
|
15
|
+
}
|
|
16
|
+
get parameters() {
|
|
17
|
+
return this.response.parameters;
|
|
18
|
+
}
|
|
19
|
+
}
|
|
20
|
+
exports.TelegramError = TelegramError;
|
|
21
|
+
exports.default = TelegramError;
|