iris-relay 1.0.0 → 1.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/README.md +178 -32
- package/dist/builder.d.ts +50 -0
- package/dist/builder.d.ts.map +1 -0
- package/dist/builder.js +94 -0
- package/dist/builder.js.map +1 -0
- package/dist/channels.d.ts +28 -0
- package/dist/channels.d.ts.map +1 -0
- package/dist/channels.js +56 -0
- package/dist/channels.js.map +1 -0
- package/dist/cli.d.ts +3 -0
- package/dist/cli.d.ts.map +1 -0
- package/dist/cli.js +84 -0
- package/dist/cli.js.map +1 -0
- package/dist/file.d.ts +12 -0
- package/dist/file.d.ts.map +1 -0
- package/dist/file.js +60 -0
- package/dist/file.js.map +1 -0
- package/dist/format.d.ts +30 -0
- package/dist/format.d.ts.map +1 -0
- package/dist/format.js +86 -0
- package/dist/format.js.map +1 -0
- package/dist/index.d.ts +8 -2
- package/dist/index.d.ts.map +1 -1
- package/dist/index.js +14 -1
- package/dist/index.js.map +1 -1
- package/dist/middleware.d.ts +25 -0
- package/dist/middleware.d.ts.map +1 -0
- package/dist/middleware.js +74 -0
- package/dist/middleware.js.map +1 -0
- package/dist/relay.d.ts +13 -18
- package/dist/relay.d.ts.map +1 -1
- package/dist/relay.js +50 -35
- package/dist/relay.js.map +1 -1
- package/dist/types.d.ts +54 -1
- package/dist/types.d.ts.map +1 -1
- package/dist/watch.d.ts +26 -0
- package/dist/watch.d.ts.map +1 -0
- package/dist/watch.js +70 -0
- package/dist/watch.js.map +1 -0
- package/package.json +14 -6
package/README.md
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
# iris-relay
|
|
2
2
|
|
|
3
|
-
Lightweight,
|
|
3
|
+
Lightweight Telegram relay dev tool — crash alerts, deploy notifications, heartbeats, and more. Zero-config, tree-shakeable, built-in `.env` loading.
|
|
4
4
|
|
|
5
5
|
## Install
|
|
6
6
|
|
|
@@ -15,17 +15,16 @@ Create a `.env` file in your project root:
|
|
|
15
15
|
```env
|
|
16
16
|
XERO_BOT_TOKEN=your_bot_token_from_botfather
|
|
17
17
|
XERO_CHAT_ID=your_telegram_chat_id
|
|
18
|
+
XERO_DRY_RUN=false
|
|
18
19
|
```
|
|
19
20
|
|
|
20
|
-
> **
|
|
21
|
-
> - **Bot Token** — message [@BotFather](https://t.me/BotFather) on Telegram to create a bot
|
|
22
|
-
> - **Chat ID** — message [@userinfobot](https://t.me/userinfobot) on Telegram to get your chat ID
|
|
21
|
+
> **Bot Token** → [@BotFather](https://t.me/BotFather) · **Chat ID** → [@userinfobot](https://t.me/userinfobot)
|
|
23
22
|
|
|
24
|
-
|
|
23
|
+
No dotenv import needed — `iris-relay` auto-loads your `.env`.
|
|
25
24
|
|
|
26
|
-
|
|
25
|
+
---
|
|
27
26
|
|
|
28
|
-
|
|
27
|
+
## Quick Start
|
|
29
28
|
|
|
30
29
|
```ts
|
|
31
30
|
import { relay } from "iris-relay";
|
|
@@ -33,52 +32,199 @@ import { relay } from "iris-relay";
|
|
|
33
32
|
await relay("Hello from my server! 🚀");
|
|
34
33
|
```
|
|
35
34
|
|
|
36
|
-
|
|
35
|
+
---
|
|
36
|
+
|
|
37
|
+
## Features
|
|
38
|
+
|
|
39
|
+
### 📨 Core Relay
|
|
37
40
|
|
|
38
41
|
```ts
|
|
39
|
-
import { createRelay } from "iris-relay";
|
|
42
|
+
import { relay, createRelay } from "iris-relay";
|
|
40
43
|
|
|
41
|
-
|
|
42
|
-
|
|
43
|
-
|
|
44
|
+
// One-off message
|
|
45
|
+
await relay("Server started");
|
|
46
|
+
|
|
47
|
+
// With options
|
|
48
|
+
await relay("Check this out", {
|
|
49
|
+
parseMode: "HTML",
|
|
50
|
+
disablePreview: true,
|
|
51
|
+
silent: true,
|
|
52
|
+
retries: 3, // retry with exponential backoff
|
|
53
|
+
retryDelay: 1000, // base delay in ms
|
|
44
54
|
});
|
|
45
55
|
|
|
56
|
+
// Pre-configured sender
|
|
57
|
+
const send = createRelay({ botToken: "...", chatId: "..." });
|
|
46
58
|
await send("Deploy successful ✅");
|
|
47
|
-
await send("Build failed ❌");
|
|
48
59
|
```
|
|
49
60
|
|
|
50
|
-
###
|
|
61
|
+
### 🚨 Error Relay
|
|
51
62
|
|
|
52
63
|
```ts
|
|
53
|
-
|
|
54
|
-
|
|
55
|
-
|
|
56
|
-
|
|
64
|
+
import { relayError } from "iris-relay";
|
|
65
|
+
|
|
66
|
+
try {
|
|
67
|
+
dangerousOperation();
|
|
68
|
+
} catch (err) {
|
|
69
|
+
await relayError(err); // sends formatted stack trace
|
|
70
|
+
}
|
|
71
|
+
```
|
|
72
|
+
|
|
73
|
+
### 📋 JSON Relay
|
|
74
|
+
|
|
75
|
+
```ts
|
|
76
|
+
import { relayJSON } from "iris-relay";
|
|
77
|
+
|
|
78
|
+
await relayJSON({ users: 42, status: "healthy" }, "Server Stats");
|
|
79
|
+
```
|
|
80
|
+
|
|
81
|
+
### 🚀 Deploy Notifications
|
|
82
|
+
|
|
83
|
+
```ts
|
|
84
|
+
import { relayDeploy } from "iris-relay";
|
|
85
|
+
|
|
86
|
+
// Auto-reads git branch, commit, and message
|
|
87
|
+
await relayDeploy({ app: "my-api", env: "production", version: "1.2.3" });
|
|
88
|
+
```
|
|
89
|
+
|
|
90
|
+
### ✍️ Message Builder
|
|
91
|
+
|
|
92
|
+
```ts
|
|
93
|
+
import { message } from "iris-relay";
|
|
94
|
+
|
|
95
|
+
await message()
|
|
96
|
+
.bold("Deploy")
|
|
97
|
+
.text(" ")
|
|
98
|
+
.code("v1.2.3")
|
|
99
|
+
.text(" to ")
|
|
100
|
+
.italic("production")
|
|
101
|
+
.br()
|
|
102
|
+
.separator()
|
|
103
|
+
.link("View Dashboard", "https://example.com")
|
|
104
|
+
.send();
|
|
105
|
+
```
|
|
106
|
+
|
|
107
|
+
Builder methods: `.bold()` `.italic()` `.code()` `.codeBlock()` `.strike()` `.underline()` `.link()` `.text()` `.br()` `.separator()`
|
|
108
|
+
|
|
109
|
+
### 📎 File Relay
|
|
110
|
+
|
|
111
|
+
```ts
|
|
112
|
+
import { relayFile } from "iris-relay";
|
|
113
|
+
|
|
114
|
+
await relayFile("./logs/error.log", "Latest error log");
|
|
115
|
+
```
|
|
116
|
+
|
|
117
|
+
### 💀 Process Crash Watcher
|
|
118
|
+
|
|
119
|
+
```ts
|
|
120
|
+
import { watchProcess } from "iris-relay";
|
|
121
|
+
|
|
122
|
+
watchProcess(); // done — uncaught exceptions & rejections get reported
|
|
123
|
+
```
|
|
124
|
+
|
|
125
|
+
### 💓 Heartbeat
|
|
126
|
+
|
|
127
|
+
```ts
|
|
128
|
+
import { startHeartbeat } from "iris-relay";
|
|
129
|
+
|
|
130
|
+
const stop = startHeartbeat({
|
|
131
|
+
interval: 60_000, // every minute
|
|
132
|
+
app: "my-api",
|
|
57
133
|
});
|
|
134
|
+
|
|
135
|
+
// Later: stop();
|
|
136
|
+
```
|
|
137
|
+
|
|
138
|
+
### 🔌 Express Middleware
|
|
139
|
+
|
|
140
|
+
```ts
|
|
141
|
+
import express from "express";
|
|
142
|
+
import { irisMiddleware, irisErrorHandler } from "iris-relay";
|
|
143
|
+
|
|
144
|
+
const app = express();
|
|
145
|
+
|
|
146
|
+
// Reports slow requests (>3s) and 5xx errors
|
|
147
|
+
app.use(irisMiddleware({ slowThreshold: 3000 }));
|
|
148
|
+
|
|
149
|
+
// Your routes...
|
|
150
|
+
|
|
151
|
+
// Catches unhandled errors and sends to Telegram
|
|
152
|
+
app.use(irisErrorHandler());
|
|
153
|
+
```
|
|
154
|
+
|
|
155
|
+
### 📡 Multi-Channel
|
|
156
|
+
|
|
157
|
+
```ts
|
|
158
|
+
import { createChannels } from "iris-relay";
|
|
159
|
+
|
|
160
|
+
const channels = createChannels([
|
|
161
|
+
{ name: "alerts", chatId: "-100123456" },
|
|
162
|
+
{ name: "deploys", chatId: "-100789012", silent: true },
|
|
163
|
+
{ name: "logs", chatId: "-100345678" },
|
|
164
|
+
]);
|
|
165
|
+
|
|
166
|
+
await channels.send("alerts", "🚨 Server is down!");
|
|
167
|
+
await channels.send("deploys", "🚀 v1.2.3 deployed");
|
|
168
|
+
await channels.broadcast("System maintenance in 5 minutes");
|
|
58
169
|
```
|
|
59
170
|
|
|
60
|
-
|
|
171
|
+
### 🧪 Dry Run Mode
|
|
61
172
|
|
|
62
|
-
|
|
173
|
+
Set `XERO_DRY_RUN=true` in `.env` to log messages to console instead of sending to Telegram. Perfect for local development.
|
|
63
174
|
|
|
64
|
-
|
|
175
|
+
---
|
|
65
176
|
|
|
66
|
-
|
|
67
|
-
|
|
68
|
-
|
|
69
|
-
|
|
70
|
-
|
|
71
|
-
| `config.parseMode` | `"HTML" \| "Markdown" \| "MarkdownV2"` | Message formatting |
|
|
72
|
-
| `config.disablePreview` | `boolean?` | Disable link previews |
|
|
73
|
-
| `config.silent` | `boolean?` | Send without notification sound |
|
|
177
|
+
## CLI
|
|
178
|
+
|
|
179
|
+
```bash
|
|
180
|
+
# Send a message
|
|
181
|
+
npx iris-relay "Deploy complete ✅"
|
|
74
182
|
|
|
75
|
-
|
|
183
|
+
# Send with HTML
|
|
184
|
+
npx iris-relay --html "<b>Bold</b> message"
|
|
185
|
+
|
|
186
|
+
# Send a file
|
|
187
|
+
npx iris-relay --file ./logs/error.log "Error log attached"
|
|
188
|
+
|
|
189
|
+
# Silent (no notification sound)
|
|
190
|
+
npx iris-relay --silent "Background update"
|
|
191
|
+
```
|
|
76
192
|
|
|
77
|
-
|
|
193
|
+
---
|
|
194
|
+
|
|
195
|
+
## API Reference
|
|
196
|
+
|
|
197
|
+
| Export | Description |
|
|
198
|
+
|--------|-------------|
|
|
199
|
+
| `relay(msg, config?)` | Send a text message |
|
|
200
|
+
| `createRelay(config)` | Create a pre-configured sender |
|
|
201
|
+
| `relayError(err, config?)` | Send formatted error + stack trace |
|
|
202
|
+
| `relayJSON(obj, label?, config?)` | Send pretty-printed JSON |
|
|
203
|
+
| `relayDeploy(meta?, config?)` | Send deploy notification with git info |
|
|
204
|
+
| `relayFile(path, caption?, config?)` | Send a file |
|
|
205
|
+
| `message()` | Create a fluent message builder |
|
|
206
|
+
| `watchProcess(config?)` | Auto-report crashes |
|
|
207
|
+
| `startHeartbeat(opts?, config?)` | Periodic alive pings |
|
|
208
|
+
| `irisMiddleware(opts?)` | Express middleware for slow/error reporting |
|
|
209
|
+
| `irisErrorHandler(config?)` | Express error handler |
|
|
210
|
+
| `createChannels(channels, config?)` | Multi-channel manager |
|
|
211
|
+
| `isDryRun()` | Check if dry run mode is active |
|
|
212
|
+
|
|
213
|
+
## Config
|
|
214
|
+
|
|
215
|
+
| Option | Type | Default | Description |
|
|
216
|
+
|--------|------|---------|-------------|
|
|
217
|
+
| `botToken` | `string` | `XERO_BOT_TOKEN` | Bot token |
|
|
218
|
+
| `chatId` | `string` | `XERO_CHAT_ID` | Chat ID |
|
|
219
|
+
| `parseMode` | `"HTML" \| "Markdown" \| "MarkdownV2"` | — | Message format |
|
|
220
|
+
| `disablePreview` | `boolean` | `false` | Disable link previews |
|
|
221
|
+
| `silent` | `boolean` | `false` | No notification sound |
|
|
222
|
+
| `retries` | `number` | `0` | Retry count |
|
|
223
|
+
| `retryDelay` | `number` | `1000` | Base retry delay (ms) |
|
|
78
224
|
|
|
79
225
|
## Requirements
|
|
80
226
|
|
|
81
|
-
- Node.js ≥ 18
|
|
227
|
+
- Node.js ≥ 18
|
|
82
228
|
|
|
83
229
|
## License
|
|
84
230
|
|
|
@@ -0,0 +1,50 @@
|
|
|
1
|
+
import type { RelayConfig, RelayResult } from "./types.js";
|
|
2
|
+
/**
|
|
3
|
+
* Fluent message builder for composing formatted Telegram messages.
|
|
4
|
+
*
|
|
5
|
+
* @example
|
|
6
|
+
* ```ts
|
|
7
|
+
* import { message } from "iris-relay";
|
|
8
|
+
*
|
|
9
|
+
* await message()
|
|
10
|
+
* .bold("Deploy")
|
|
11
|
+
* .text(" ")
|
|
12
|
+
* .code("v1.2.3")
|
|
13
|
+
* .text(" to ")
|
|
14
|
+
* .italic("production")
|
|
15
|
+
* .send();
|
|
16
|
+
* ```
|
|
17
|
+
*/
|
|
18
|
+
export declare class MessageBuilder {
|
|
19
|
+
private parts;
|
|
20
|
+
private config;
|
|
21
|
+
/** Add plain text */
|
|
22
|
+
text(content: string): this;
|
|
23
|
+
/** Add bold text */
|
|
24
|
+
bold(content: string): this;
|
|
25
|
+
/** Add italic text */
|
|
26
|
+
italic(content: string): this;
|
|
27
|
+
/** Add inline code */
|
|
28
|
+
code(content: string): this;
|
|
29
|
+
/** Add a code block with optional language */
|
|
30
|
+
codeBlock(content: string, lang?: string): this;
|
|
31
|
+
/** Add a strikethrough text */
|
|
32
|
+
strike(content: string): this;
|
|
33
|
+
/** Add underlined text */
|
|
34
|
+
underline(content: string): this;
|
|
35
|
+
/** Add a link */
|
|
36
|
+
link(text: string, url: string): this;
|
|
37
|
+
/** Add a newline */
|
|
38
|
+
br(): this;
|
|
39
|
+
/** Add a horizontal separator */
|
|
40
|
+
separator(): this;
|
|
41
|
+
/** Override relay config for this message */
|
|
42
|
+
withConfig(config: RelayConfig): this;
|
|
43
|
+
/** Build the message string without sending */
|
|
44
|
+
build(): string;
|
|
45
|
+
/** Send the composed message */
|
|
46
|
+
send(config?: RelayConfig): Promise<RelayResult>;
|
|
47
|
+
}
|
|
48
|
+
/** Create a new message builder */
|
|
49
|
+
export declare function message(): MessageBuilder;
|
|
50
|
+
//# sourceMappingURL=builder.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"builder.d.ts","sourceRoot":"","sources":["../src/builder.ts"],"names":[],"mappings":"AACA,OAAO,KAAK,EAAE,WAAW,EAAE,WAAW,EAAE,MAAM,YAAY,CAAC;AAO3D;;;;;;;;;;;;;;;GAeG;AACH,qBAAa,cAAc;IACvB,OAAO,CAAC,KAAK,CAAgB;IAC7B,OAAO,CAAC,MAAM,CAAsC;IAEpD,qBAAqB;IACrB,IAAI,CAAC,OAAO,EAAE,MAAM,GAAG,IAAI;IAK3B,oBAAoB;IACpB,IAAI,CAAC,OAAO,EAAE,MAAM,GAAG,IAAI;IAK3B,sBAAsB;IACtB,MAAM,CAAC,OAAO,EAAE,MAAM,GAAG,IAAI;IAK7B,sBAAsB;IACtB,IAAI,CAAC,OAAO,EAAE,MAAM,GAAG,IAAI;IAK3B,8CAA8C;IAC9C,SAAS,CAAC,OAAO,EAAE,MAAM,EAAE,IAAI,CAAC,EAAE,MAAM,GAAG,IAAI;IAM/C,+BAA+B;IAC/B,MAAM,CAAC,OAAO,EAAE,MAAM,GAAG,IAAI;IAK7B,0BAA0B;IAC1B,SAAS,CAAC,OAAO,EAAE,MAAM,GAAG,IAAI;IAKhC,iBAAiB;IACjB,IAAI,CAAC,IAAI,EAAE,MAAM,EAAE,GAAG,EAAE,MAAM,GAAG,IAAI;IAKrC,oBAAoB;IACpB,EAAE,IAAI,IAAI;IAKV,iCAAiC;IACjC,SAAS,IAAI,IAAI;IAKjB,6CAA6C;IAC7C,UAAU,CAAC,MAAM,EAAE,WAAW,GAAG,IAAI;IAKrC,+CAA+C;IAC/C,KAAK,IAAI,MAAM;IAIf,gCAAgC;IAC1B,IAAI,CAAC,MAAM,CAAC,EAAE,WAAW,GAAG,OAAO,CAAC,WAAW,CAAC;CAGzD;AAED,mCAAmC;AACnC,wBAAgB,OAAO,IAAI,cAAc,CAExC"}
|
package/dist/builder.js
ADDED
|
@@ -0,0 +1,94 @@
|
|
|
1
|
+
import { relay } from "./relay.js";
|
|
2
|
+
/** Escape HTML special characters */
|
|
3
|
+
function esc(text) {
|
|
4
|
+
return text.replace(/&/g, "&").replace(/</g, "<").replace(/>/g, ">");
|
|
5
|
+
}
|
|
6
|
+
/**
|
|
7
|
+
* Fluent message builder for composing formatted Telegram messages.
|
|
8
|
+
*
|
|
9
|
+
* @example
|
|
10
|
+
* ```ts
|
|
11
|
+
* import { message } from "iris-relay";
|
|
12
|
+
*
|
|
13
|
+
* await message()
|
|
14
|
+
* .bold("Deploy")
|
|
15
|
+
* .text(" ")
|
|
16
|
+
* .code("v1.2.3")
|
|
17
|
+
* .text(" to ")
|
|
18
|
+
* .italic("production")
|
|
19
|
+
* .send();
|
|
20
|
+
* ```
|
|
21
|
+
*/
|
|
22
|
+
export class MessageBuilder {
|
|
23
|
+
parts = [];
|
|
24
|
+
config = { parseMode: "HTML" };
|
|
25
|
+
/** Add plain text */
|
|
26
|
+
text(content) {
|
|
27
|
+
this.parts.push(esc(content));
|
|
28
|
+
return this;
|
|
29
|
+
}
|
|
30
|
+
/** Add bold text */
|
|
31
|
+
bold(content) {
|
|
32
|
+
this.parts.push(`<b>${esc(content)}</b>`);
|
|
33
|
+
return this;
|
|
34
|
+
}
|
|
35
|
+
/** Add italic text */
|
|
36
|
+
italic(content) {
|
|
37
|
+
this.parts.push(`<i>${esc(content)}</i>`);
|
|
38
|
+
return this;
|
|
39
|
+
}
|
|
40
|
+
/** Add inline code */
|
|
41
|
+
code(content) {
|
|
42
|
+
this.parts.push(`<code>${esc(content)}</code>`);
|
|
43
|
+
return this;
|
|
44
|
+
}
|
|
45
|
+
/** Add a code block with optional language */
|
|
46
|
+
codeBlock(content, lang) {
|
|
47
|
+
const langAttr = lang ? ` class="language-${esc(lang)}"` : "";
|
|
48
|
+
this.parts.push(`<pre${langAttr}>${esc(content)}</pre>`);
|
|
49
|
+
return this;
|
|
50
|
+
}
|
|
51
|
+
/** Add a strikethrough text */
|
|
52
|
+
strike(content) {
|
|
53
|
+
this.parts.push(`<s>${esc(content)}</s>`);
|
|
54
|
+
return this;
|
|
55
|
+
}
|
|
56
|
+
/** Add underlined text */
|
|
57
|
+
underline(content) {
|
|
58
|
+
this.parts.push(`<u>${esc(content)}</u>`);
|
|
59
|
+
return this;
|
|
60
|
+
}
|
|
61
|
+
/** Add a link */
|
|
62
|
+
link(text, url) {
|
|
63
|
+
this.parts.push(`<a href="${esc(url)}">${esc(text)}</a>`);
|
|
64
|
+
return this;
|
|
65
|
+
}
|
|
66
|
+
/** Add a newline */
|
|
67
|
+
br() {
|
|
68
|
+
this.parts.push("\n");
|
|
69
|
+
return this;
|
|
70
|
+
}
|
|
71
|
+
/** Add a horizontal separator */
|
|
72
|
+
separator() {
|
|
73
|
+
this.parts.push("\n———————————\n");
|
|
74
|
+
return this;
|
|
75
|
+
}
|
|
76
|
+
/** Override relay config for this message */
|
|
77
|
+
withConfig(config) {
|
|
78
|
+
this.config = { ...this.config, ...config };
|
|
79
|
+
return this;
|
|
80
|
+
}
|
|
81
|
+
/** Build the message string without sending */
|
|
82
|
+
build() {
|
|
83
|
+
return this.parts.join("");
|
|
84
|
+
}
|
|
85
|
+
/** Send the composed message */
|
|
86
|
+
async send(config) {
|
|
87
|
+
return relay(this.build(), { ...this.config, ...config });
|
|
88
|
+
}
|
|
89
|
+
}
|
|
90
|
+
/** Create a new message builder */
|
|
91
|
+
export function message() {
|
|
92
|
+
return new MessageBuilder();
|
|
93
|
+
}
|
|
94
|
+
//# sourceMappingURL=builder.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"builder.js","sourceRoot":"","sources":["../src/builder.ts"],"names":[],"mappings":"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"}
|
|
@@ -0,0 +1,28 @@
|
|
|
1
|
+
import type { Channel, RelayConfig, RelayResult } from "./types.js";
|
|
2
|
+
/**
|
|
3
|
+
* Multi-channel manager for sending to different Telegram chats.
|
|
4
|
+
*
|
|
5
|
+
* @example
|
|
6
|
+
* ```ts
|
|
7
|
+
* import { createChannels } from "iris-relay";
|
|
8
|
+
*
|
|
9
|
+
* const channels = createChannels([
|
|
10
|
+
* { name: "alerts", chatId: "-100123456" },
|
|
11
|
+
* { name: "deploys", chatId: "-100789012", silent: true },
|
|
12
|
+
* { name: "logs", chatId: "-100345678" },
|
|
13
|
+
* ]);
|
|
14
|
+
*
|
|
15
|
+
* await channels.send("alerts", "🚨 Server is down!");
|
|
16
|
+
* await channels.send("deploys", "🚀 v1.2.3 deployed");
|
|
17
|
+
* await channels.broadcast("System maintenance in 5 minutes");
|
|
18
|
+
* ```
|
|
19
|
+
*/
|
|
20
|
+
export declare function createChannels(channels: Channel[], defaultConfig?: RelayConfig): {
|
|
21
|
+
/** Send a message to a specific channel */
|
|
22
|
+
send(channelName: string, message: string, config?: RelayConfig): Promise<RelayResult>;
|
|
23
|
+
/** Broadcast a message to all channels */
|
|
24
|
+
broadcast(message: string, config?: RelayConfig): Promise<Map<string, RelayResult>>;
|
|
25
|
+
/** Get list of registered channel names */
|
|
26
|
+
list(): string[];
|
|
27
|
+
};
|
|
28
|
+
//# sourceMappingURL=channels.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"channels.d.ts","sourceRoot":"","sources":["../src/channels.ts"],"names":[],"mappings":"AACA,OAAO,KAAK,EAAE,OAAO,EAAE,WAAW,EAAE,WAAW,EAAE,MAAM,YAAY,CAAC;AAEpE;;;;;;;;;;;;;;;;;GAiBG;AACH,wBAAgB,cAAc,CAAC,QAAQ,EAAE,OAAO,EAAE,EAAE,aAAa,CAAC,EAAE,WAAW;IASvE,2CAA2C;sBACnB,MAAM,WAAW,MAAM,WAAW,WAAW,GAAG,OAAO,CAAC,WAAW,CAAC;IAgB5F,0CAA0C;uBACjB,MAAM,WAAW,WAAW,GAAG,OAAO,CAAC,GAAG,CAAC,MAAM,EAAE,WAAW,CAAC,CAAC;IAUzF,2CAA2C;YACnC,MAAM,EAAE;EAIvB"}
|
package/dist/channels.js
ADDED
|
@@ -0,0 +1,56 @@
|
|
|
1
|
+
import { relay, resolveConfig } from "./relay.js";
|
|
2
|
+
/**
|
|
3
|
+
* Multi-channel manager for sending to different Telegram chats.
|
|
4
|
+
*
|
|
5
|
+
* @example
|
|
6
|
+
* ```ts
|
|
7
|
+
* import { createChannels } from "iris-relay";
|
|
8
|
+
*
|
|
9
|
+
* const channels = createChannels([
|
|
10
|
+
* { name: "alerts", chatId: "-100123456" },
|
|
11
|
+
* { name: "deploys", chatId: "-100789012", silent: true },
|
|
12
|
+
* { name: "logs", chatId: "-100345678" },
|
|
13
|
+
* ]);
|
|
14
|
+
*
|
|
15
|
+
* await channels.send("alerts", "🚨 Server is down!");
|
|
16
|
+
* await channels.send("deploys", "🚀 v1.2.3 deployed");
|
|
17
|
+
* await channels.broadcast("System maintenance in 5 minutes");
|
|
18
|
+
* ```
|
|
19
|
+
*/
|
|
20
|
+
export function createChannels(channels, defaultConfig) {
|
|
21
|
+
const resolved = resolveConfig(defaultConfig);
|
|
22
|
+
const channelMap = new Map();
|
|
23
|
+
for (const ch of channels) {
|
|
24
|
+
channelMap.set(ch.name, ch);
|
|
25
|
+
}
|
|
26
|
+
return {
|
|
27
|
+
/** Send a message to a specific channel */
|
|
28
|
+
async send(channelName, message, config) {
|
|
29
|
+
const channel = channelMap.get(channelName);
|
|
30
|
+
if (!channel) {
|
|
31
|
+
return { success: false, error: `Channel "${channelName}" not found` };
|
|
32
|
+
}
|
|
33
|
+
return relay(message, {
|
|
34
|
+
...resolved,
|
|
35
|
+
botToken: channel.botToken ?? resolved.botToken,
|
|
36
|
+
chatId: channel.chatId,
|
|
37
|
+
parseMode: channel.parseMode ?? resolved.parseMode,
|
|
38
|
+
silent: channel.silent ?? resolved.silent,
|
|
39
|
+
...config,
|
|
40
|
+
});
|
|
41
|
+
},
|
|
42
|
+
/** Broadcast a message to all channels */
|
|
43
|
+
async broadcast(message, config) {
|
|
44
|
+
const results = new Map();
|
|
45
|
+
for (const [name] of channelMap) {
|
|
46
|
+
results.set(name, await this.send(name, message, config));
|
|
47
|
+
}
|
|
48
|
+
return results;
|
|
49
|
+
},
|
|
50
|
+
/** Get list of registered channel names */
|
|
51
|
+
list() {
|
|
52
|
+
return Array.from(channelMap.keys());
|
|
53
|
+
},
|
|
54
|
+
};
|
|
55
|
+
}
|
|
56
|
+
//# sourceMappingURL=channels.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"channels.js","sourceRoot":"","sources":["../src/channels.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,KAAK,EAAE,aAAa,EAAE,MAAM,YAAY,CAAC;AAGlD;;;;;;;;;;;;;;;;;GAiBG;AACH,MAAM,UAAU,cAAc,CAAC,QAAmB,EAAE,aAA2B;IAC3E,MAAM,QAAQ,GAAG,aAAa,CAAC,aAAa,CAAC,CAAC;IAC9C,MAAM,UAAU,GAAG,IAAI,GAAG,EAAmB,CAAC;IAE9C,KAAK,MAAM,EAAE,IAAI,QAAQ,EAAE,CAAC;QACxB,UAAU,CAAC,GAAG,CAAC,EAAE,CAAC,IAAI,EAAE,EAAE,CAAC,CAAC;IAChC,CAAC;IAED,OAAO;QACH,2CAA2C;QAC3C,KAAK,CAAC,IAAI,CAAC,WAAmB,EAAE,OAAe,EAAE,MAAoB;YACjE,MAAM,OAAO,GAAG,UAAU,CAAC,GAAG,CAAC,WAAW,CAAC,CAAC;YAC5C,IAAI,CAAC,OAAO,EAAE,CAAC;gBACX,OAAO,EAAE,OAAO,EAAE,KAAK,EAAE,KAAK,EAAE,YAAY,WAAW,aAAa,EAAE,CAAC;YAC3E,CAAC;YAED,OAAO,KAAK,CAAC,OAAO,EAAE;gBAClB,GAAG,QAAQ;gBACX,QAAQ,EAAE,OAAO,CAAC,QAAQ,IAAI,QAAQ,CAAC,QAAQ;gBAC/C,MAAM,EAAE,OAAO,CAAC,MAAM;gBACtB,SAAS,EAAE,OAAO,CAAC,SAAS,IAAI,QAAQ,CAAC,SAAS;gBAClD,MAAM,EAAE,OAAO,CAAC,MAAM,IAAI,QAAQ,CAAC,MAAM;gBACzC,GAAG,MAAM;aACZ,CAAC,CAAC;QACP,CAAC;QAED,0CAA0C;QAC1C,KAAK,CAAC,SAAS,CAAC,OAAe,EAAE,MAAoB;YACjD,MAAM,OAAO,GAAG,IAAI,GAAG,EAAuB,CAAC;YAE/C,KAAK,MAAM,CAAC,IAAI,CAAC,IAAI,UAAU,EAAE,CAAC;gBAC9B,OAAO,CAAC,GAAG,CAAC,IAAI,EAAE,MAAM,IAAI,CAAC,IAAI,CAAC,IAAI,EAAE,OAAO,EAAE,MAAM,CAAC,CAAC,CAAC;YAC9D,CAAC;YAED,OAAO,OAAO,CAAC;QACnB,CAAC;QAED,2CAA2C;QAC3C,IAAI;YACA,OAAO,KAAK,CAAC,IAAI,CAAC,UAAU,CAAC,IAAI,EAAE,CAAC,CAAC;QACzC,CAAC;KACJ,CAAC;AACN,CAAC"}
|
package/dist/cli.d.ts
ADDED
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"cli.d.ts","sourceRoot":"","sources":["../src/cli.ts"],"names":[],"mappings":""}
|
package/dist/cli.js
ADDED
|
@@ -0,0 +1,84 @@
|
|
|
1
|
+
#!/usr/bin/env node
|
|
2
|
+
import { config } from "dotenv";
|
|
3
|
+
import { relay } from "./relay.js";
|
|
4
|
+
import { relayFile } from "./file.js";
|
|
5
|
+
config();
|
|
6
|
+
const args = process.argv.slice(2);
|
|
7
|
+
function printHelp() {
|
|
8
|
+
console.log(`
|
|
9
|
+
iris-relay — Send messages to Telegram from the CLI
|
|
10
|
+
|
|
11
|
+
Usage:
|
|
12
|
+
iris-relay "Your message here"
|
|
13
|
+
iris-relay --file ./path/to/file.log "Optional caption"
|
|
14
|
+
iris-relay --silent "No notification sound"
|
|
15
|
+
iris-relay --html "<b>Bold</b> message"
|
|
16
|
+
|
|
17
|
+
Options:
|
|
18
|
+
--file <path> Send a file instead of a text message
|
|
19
|
+
--silent Send without notification sound
|
|
20
|
+
--html Parse message as HTML
|
|
21
|
+
--markdown Parse message as Markdown
|
|
22
|
+
--help, -h Show this help message
|
|
23
|
+
|
|
24
|
+
Environment:
|
|
25
|
+
XERO_BOT_TOKEN Your Telegram bot token
|
|
26
|
+
XERO_CHAT_ID Your Telegram chat ID
|
|
27
|
+
`);
|
|
28
|
+
}
|
|
29
|
+
async function main() {
|
|
30
|
+
if (args.length === 0 || args.includes("--help") || args.includes("-h")) {
|
|
31
|
+
printHelp();
|
|
32
|
+
process.exit(0);
|
|
33
|
+
}
|
|
34
|
+
const silent = args.includes("--silent");
|
|
35
|
+
const html = args.includes("--html");
|
|
36
|
+
const markdown = args.includes("--markdown");
|
|
37
|
+
const fileIdx = args.indexOf("--file");
|
|
38
|
+
// Filter out flags to get the message
|
|
39
|
+
const messageArgs = args.filter((a, i) => !a.startsWith("--") && !(i === fileIdx + 1 && fileIdx >= 0));
|
|
40
|
+
const message = messageArgs.join(" ");
|
|
41
|
+
const parseMode = html ? "HTML" : markdown ? "Markdown" : undefined;
|
|
42
|
+
try {
|
|
43
|
+
// File mode
|
|
44
|
+
if (fileIdx >= 0) {
|
|
45
|
+
const filePath = args[fileIdx + 1];
|
|
46
|
+
if (!filePath) {
|
|
47
|
+
console.error("Error: --file requires a path argument");
|
|
48
|
+
process.exit(1);
|
|
49
|
+
}
|
|
50
|
+
const result = await relayFile(filePath, message || undefined, {
|
|
51
|
+
silent,
|
|
52
|
+
parseMode,
|
|
53
|
+
});
|
|
54
|
+
if (result.success) {
|
|
55
|
+
console.log(`✅ File sent: ${filePath}`);
|
|
56
|
+
}
|
|
57
|
+
else {
|
|
58
|
+
console.error(`❌ Failed: ${result.error}`);
|
|
59
|
+
process.exit(1);
|
|
60
|
+
}
|
|
61
|
+
return;
|
|
62
|
+
}
|
|
63
|
+
// Message mode
|
|
64
|
+
if (!message) {
|
|
65
|
+
console.error("Error: No message provided");
|
|
66
|
+
printHelp();
|
|
67
|
+
process.exit(1);
|
|
68
|
+
}
|
|
69
|
+
const result = await relay(message, { silent, parseMode });
|
|
70
|
+
if (result.success) {
|
|
71
|
+
console.log(`✅ Message sent (ID: ${result.messageId})`);
|
|
72
|
+
}
|
|
73
|
+
else {
|
|
74
|
+
console.error(`❌ Failed: ${result.error}`);
|
|
75
|
+
process.exit(1);
|
|
76
|
+
}
|
|
77
|
+
}
|
|
78
|
+
catch (err) {
|
|
79
|
+
console.error(`💥 ${err instanceof Error ? err.message : String(err)}`);
|
|
80
|
+
process.exit(1);
|
|
81
|
+
}
|
|
82
|
+
}
|
|
83
|
+
main();
|
|
84
|
+
//# sourceMappingURL=cli.js.map
|
package/dist/cli.js.map
ADDED
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"cli.js","sourceRoot":"","sources":["../src/cli.ts"],"names":[],"mappings":"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"}
|
package/dist/file.d.ts
ADDED
|
@@ -0,0 +1,12 @@
|
|
|
1
|
+
import type { RelayConfig, RelayResult } from "./types.js";
|
|
2
|
+
/**
|
|
3
|
+
* Send a file to your Telegram chat via sendDocument API.
|
|
4
|
+
*
|
|
5
|
+
* @example
|
|
6
|
+
* ```ts
|
|
7
|
+
* import { relayFile } from "iris-relay";
|
|
8
|
+
* await relayFile("./logs/error.log", "Latest error log");
|
|
9
|
+
* ```
|
|
10
|
+
*/
|
|
11
|
+
export declare function relayFile(filePath: string, caption?: string, config?: RelayConfig): Promise<RelayResult>;
|
|
12
|
+
//# sourceMappingURL=file.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"file.d.ts","sourceRoot":"","sources":["../src/file.ts"],"names":[],"mappings":"AACA,OAAO,KAAK,EAAE,WAAW,EAAE,WAAW,EAAoB,MAAM,YAAY,CAAC;AAO7E;;;;;;;;GAQG;AACH,wBAAsB,SAAS,CAC3B,QAAQ,EAAE,MAAM,EAChB,OAAO,CAAC,EAAE,MAAM,EAChB,MAAM,CAAC,EAAE,WAAW,GACrB,OAAO,CAAC,WAAW,CAAC,CAgDtB"}
|