@patricktobias86/node-red-telegram-account 1.1.10 → 1.1.12

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/CHANGELOG.md CHANGED
@@ -19,3 +19,11 @@ All notable changes to this project will be documented in this file.
19
19
  ### Changed
20
20
  - `delete-message` now forwards the original message along with the Telegram API response.
21
21
 
22
+ ## [1.1.11] - 2025-08-04
23
+ ### Fixed
24
+ - All nodes now preserve properties on the incoming message outside of the payload.
25
+
26
+ ## [1.1.12] - 2025-08-06
27
+ ### Fixed
28
+ - Auth node now emits the generated `stringSession` so it can be used by other nodes.
29
+
package/README.md CHANGED
@@ -17,7 +17,7 @@ This package contains a collection of Node‑RED nodes built on top of [GramJS](
17
17
  See [docs/NODES.md](docs/NODES.md) for a detailed description of every node. Below is a quick summary:
18
18
 
19
19
  - **config** – stores your API credentials and caches sessions for reuse.
20
- - **auth** – interactive login that outputs a `stringSession`.
20
+ - **auth** – interactive login that outputs a `stringSession` (also set on `msg.stringSession`).
21
21
  - **receiver** – emits messages for every incoming update (with optional ignore list). Event listeners are cleaned up on node close so redeploys won't duplicate messages.
22
22
  - **command** – triggers when an incoming message matches a command or regex. Event listeners are removed on redeploy to prevent duplicates.
23
23
  - **send-message** – sends text or media messages with rich options.
@@ -29,6 +29,8 @@ See [docs/NODES.md](docs/NODES.md) for a detailed description of every node. Bel
29
29
  - **promote-admin** – promotes a user to admin with configurable rights.
30
30
  - **resolve-userid** – converts a username to a numeric user ID.
31
31
 
32
+ All nodes preserve any properties on the incoming message outside of <code>msg.payload</code>.
33
+
32
34
  All nodes include a <code>Debug</code> option that logs incoming and outgoing messages to the Node-RED log when enabled.
33
35
 
34
36
  ## Session management
package/docs/NODES.md CHANGED
@@ -7,7 +7,7 @@ Below is a short description of each node. For a full list of configuration opti
7
7
  | Node | Description |
8
8
  |------|-------------|
9
9
  | **config** | Configuration node storing API credentials and connection options. Other nodes reference this to share a Telegram client and reuse the session. Connections are tracked in a Map with a reference count so multiple nodes can wait for the same connection. |
10
- | **auth** | Starts an interactive login flow. Produces a `stringSession` that can be reused with the `config` node. |
10
+ | **auth** | Starts an interactive login flow. Produces a `stringSession` (available in both <code>msg.payload.stringSession</code> and <code>msg.stringSession</code>) that can be reused with the `config` node. |
11
11
  | **receiver** | Emits an output message for every incoming Telegram message. Can ignore specific user IDs. Event handlers are automatically removed when the node is closed. |
12
12
  | **command** | Listens for new messages and triggers when a message matches a configured command or regular expression. The event listener is cleaned up on node close to avoid duplicates. |
13
13
  | **send-message** | Sends text messages or media files to a chat. Supports parse mode, buttons, scheduling, and more. |
@@ -19,6 +19,7 @@ Below is a short description of each node. For a full list of configuration opti
19
19
  | **promote-admin** | Grants admin rights to a user in a group or channel with configurable permissions. |
20
20
  | **resolve-userid** | Converts a Telegram username to its numeric user ID. |
21
21
 
22
+ All nodes forward any properties on the incoming `msg` outside of `msg.payload` unchanged.
22
23
 
23
24
  All nodes provide a **Debug** checkbox. When enabled the node will log its input and output messages to aid troubleshooting.
24
25
 
package/nodes/auth.html CHANGED
@@ -130,6 +130,8 @@ if (typeof wait === "function") {
130
130
  <li><code>message</code> or <code>error</code>: Additional info.</li>
131
131
  </ul>
132
132
  </dd>
133
+ <dt>stringSession <span class="property-type">string</span></dt>
134
+ <dd>A copy of the session string for easier access.</dd>
133
135
  </dl>
134
136
 
135
137
  <h3>Example</h3>
package/nodes/auth.js CHANGED
@@ -49,6 +49,7 @@ module.exports = function (RED) {
49
49
  });
50
50
 
51
51
  const stringSession = client.session.save();
52
+ await client.disconnect();
52
53
 
53
54
  console.log("Sending result to output:", {
54
55
  stringSession,
@@ -57,12 +58,13 @@ module.exports = function (RED) {
57
58
  { type: "session_token", text: "Copy this stringSession to use in other nodes." }
58
59
  ]
59
60
  });
60
-
61
61
  const out = {
62
+ ...msg,
62
63
  topic: "auth_success",
64
+ stringSession,
63
65
  payload: {
64
66
  stringSession,
65
- message: "Authorization successful!"
67
+ message: "Authorization successful!",
66
68
  }
67
69
  };
68
70
  node.send(out);
@@ -73,12 +75,12 @@ module.exports = function (RED) {
73
75
  node.status({ fill: "green", shape: "dot", text: "Authenticated" });
74
76
 
75
77
  } catch (err) {
76
- node.error("Authentication failed: " + err.message);
77
- const out = { topic: "auth_error", payload: { error: err.message } };
78
- node.send(out);
79
- if (debug) {
80
- node.log('auth output: ' + JSON.stringify(out));
81
- }
78
+ node.error("Authentication failed: " + err.message);
79
+ const out = { ...msg, topic: "auth_error", payload: { error: err.message } };
80
+ node.send(out);
81
+ if (debug) {
82
+ node.log('auth output: ' + JSON.stringify(out));
83
+ }
82
84
  node.status({ fill: "red", shape: "ring", text: "Failed" });
83
85
  }
84
86
  });
@@ -25,14 +25,14 @@ module.exports = function (RED) {
25
25
  entity = await client.getEntity(input);
26
26
  }
27
27
 
28
- const out = { payload: { input: entity } };
28
+ const out = { ...msg, payload: { input: entity } };
29
29
  node.send(out);
30
30
  if (debug) {
31
31
  node.log('get-entity output: ' + JSON.stringify(out));
32
32
  }
33
33
  } catch (err) {
34
34
  node.error('Error getting entity: ' + err.message);
35
- const out = { payload: { input: null } };
35
+ const out = { ...msg, payload: { input: null } };
36
36
  node.send(out);
37
37
  if (debug) {
38
38
  node.log('get-entity output: ' + JSON.stringify(out));
@@ -45,7 +45,7 @@ module.exports = function (RED) {
45
45
  dialogs[dialog.id] = dialog;
46
46
  console.log(`${dialog.id}: ${dialog.title}`);
47
47
  }
48
- const out = { payload: { dialogs } };
48
+ const out = { ...msg, payload: { dialogs } };
49
49
  node.send(out);
50
50
  if (debug) {
51
51
  node.log('iter-dialogs output: ' + JSON.stringify(out));
@@ -84,8 +84,8 @@ module.exports = function (RED) {
84
84
  console.log(message.id, message.text);
85
85
  }
86
86
  }
87
-
88
- const out = { payload: { messages } };
87
+
88
+ const out = { ...msg, payload: { messages } };
89
89
  node.send(out);
90
90
  if (debug) {
91
91
  node.log('iter-messages output: ' + JSON.stringify(out));
@@ -44,7 +44,7 @@ module.exports = function (RED) {
44
44
  rank: rank,
45
45
  }));
46
46
 
47
- const out = { payload: { response: result } };
47
+ const out = { ...msg, payload: { response: result } };
48
48
  node.send(out);
49
49
  if (debug) {
50
50
  node.log('promote-admin output: ' + JSON.stringify(out));
@@ -30,14 +30,14 @@ module.exports = function(RED) {
30
30
  } else if (entity?.userId) {
31
31
  userId = entity.userId;
32
32
  }
33
- const out = { payload: { userId } };
33
+ const out = { ...msg, payload: { userId } };
34
34
  node.send(out);
35
35
  if (debug) {
36
36
  node.log('resolve-userid output: ' + JSON.stringify(out));
37
37
  }
38
38
  } catch (err) {
39
39
  node.error('Error resolving username: ' + err.message);
40
- const out = { payload: { userId: null } };
40
+ const out = { ...msg, payload: { userId: null } };
41
41
  node.send(out);
42
42
  if (debug) {
43
43
  node.log('resolve-userid output: ' + JSON.stringify(out));
@@ -64,7 +64,7 @@ module.exports = function (RED) {
64
64
 
65
65
  // Send files
66
66
  const response = await client.sendFile(chatId, params);
67
- const out = { payload: response };
67
+ const out = { ...msg, payload: response };
68
68
  node.send(out);
69
69
  if (debug) {
70
70
  node.log('send-files output: ' + JSON.stringify(out));
@@ -73,7 +73,7 @@ module.exports = function (RED) {
73
73
  await client.sendMessage(entity, params);
74
74
  }
75
75
 
76
- const out = { payload: { response } };
76
+ const out = { ...msg, payload: { response } };
77
77
  node.send(out);
78
78
  if (debug) {
79
79
  node.log('send-message output: ' + JSON.stringify(out));
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@patricktobias86/node-red-telegram-account",
3
- "version": "1.1.10",
3
+ "version": "1.1.12",
4
4
  "description": "Node-RED nodes to communicate with GramJS.",
5
5
  "main": "nodes/config.js",
6
6
  "keywords": [
@@ -0,0 +1,48 @@
1
+ const assert = require('assert');
2
+ const proxyquire = require('proxyquire').noPreserveCache();
3
+
4
+ function setup() {
5
+ let NodeCtor;
6
+ let sent;
7
+ class TelegramClientStub {
8
+ constructor(session, id, hash, opts) {
9
+ this.session = { save: () => 'sess-string' };
10
+ }
11
+ start() { return Promise.resolve(); }
12
+ disconnect() { return Promise.resolve(); }
13
+ }
14
+ class StringSessionStub { constructor(str) {} }
15
+
16
+ const RED = {
17
+ nodes: {
18
+ createNode(node) {
19
+ node._events = {};
20
+ node.on = (e, fn) => { node._events[e] = fn; };
21
+ node.send = (msg) => { sent = msg; };
22
+ node.status = () => {};
23
+ node.log = () => {};
24
+ node.error = () => {};
25
+ node.context = () => ({ flow: { set() {}, get() {} } });
26
+ },
27
+ registerType(name, ctor) { NodeCtor = ctor; }
28
+ }
29
+ };
30
+
31
+ proxyquire('../nodes/auth.js', {
32
+ telegram: { TelegramClient: TelegramClientStub },
33
+ 'telegram/sessions': { StringSession: StringSessionStub }
34
+ })(RED);
35
+
36
+ return { NodeCtor, getSent: () => sent };
37
+ }
38
+
39
+ describe('auth node', function() {
40
+ it('emits stringSession on successful auth', async function() {
41
+ const { NodeCtor, getSent } = setup();
42
+ const node = new NodeCtor({ api_id: 1, api_hash: 'hash', phoneNumber: '123' });
43
+ await node._events['input']({ payload: {} });
44
+ const out = getSent();
45
+ assert.strictEqual(out.stringSession, 'sess-string');
46
+ assert.strictEqual(out.payload.stringSession, 'sess-string');
47
+ });
48
+ });
@@ -0,0 +1,41 @@
1
+ const assert = require('assert');
2
+ const proxyquire = require('proxyquire').noPreserveCache();
3
+
4
+ function setup() {
5
+ let NodeCtor;
6
+ let sent;
7
+ const configNode = { client: {} };
8
+ const RED = {
9
+ nodes: {
10
+ createNode(node) {
11
+ node._events = {};
12
+ node.on = (e, fn) => { node._events[e] = fn; };
13
+ node.send = (msg) => { sent = msg; };
14
+ node.log = () => {};
15
+ node.error = () => {};
16
+ },
17
+ registerType(name, ctor) { NodeCtor = ctor; },
18
+ getNode() { return configNode; }
19
+ }
20
+ };
21
+
22
+ proxyquire('../nodes/send-message.js', {
23
+ telegram: { TelegramClient: function() {} },
24
+ 'telegram/Utils': { parseID: () => ({}) }
25
+ })(RED);
26
+
27
+ return { NodeCtor, getSent: () => sent };
28
+ }
29
+
30
+ describe('message property relay', function() {
31
+ it('keeps non-payload properties on send-message output', async function() {
32
+ const { NodeCtor, getSent } = setup();
33
+ const node = new NodeCtor({ config: 'c', file: "" });
34
+ const client = { sendMessage: async () => 'ok' };
35
+ const msg = { foo: 'bar', payload: { client, chatId: 'me', message: 'hi' } };
36
+ await node._events['input'](msg);
37
+ const out = getSent();
38
+ assert.strictEqual(out.foo, 'bar');
39
+ assert.deepStrictEqual(out.payload.response, 'ok');
40
+ });
41
+ });