mikrotik-telegram 0.1.0 → 0.2.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/CHANGELOG.md +12 -0
- package/README.md +4 -0
- package/dist/alerts.d.ts +1 -1
- package/dist/automation.d.ts +1 -1
- package/dist/index.d.ts +13 -13
- package/dist/index.js +13 -13
- package/dist/mikrotik-service.d.ts +2 -2
- package/dist/rest-client.d.ts +1 -1
- package/dist/rest-client.js +1 -1
- package/dist/runtime-adapters.d.ts +1 -1
- package/dist/runtime.d.ts +4 -4
- package/dist/runtime.js +5 -5
- package/dist/telegram-client.d.ts +1 -1
- package/dist/telegram-commands.d.ts +1 -1
- package/dist/telegram-commands.js +1 -1
- package/examples/production-bot/.env.example +16 -0
- package/examples/production-bot/README.md +48 -0
- package/examples/production-bot/package-lock.json +590 -0
- package/examples/production-bot/package.json +22 -0
- package/examples/production-bot/src/index.ts +194 -0
- package/examples/production-bot/tsconfig.json +16 -0
- package/package.json +3 -2
package/CHANGELOG.md
CHANGED
|
@@ -4,6 +4,18 @@ All notable changes to `mikrotik-telegram` are documented here.
|
|
|
4
4
|
|
|
5
5
|
The project follows [Semantic Versioning](https://semver.org/).
|
|
6
6
|
|
|
7
|
+
## [0.2.0] - 2026-09-12
|
|
8
|
+
|
|
9
|
+
### Added
|
|
10
|
+
|
|
11
|
+
- Complete `examples/production-bot` Node.js production example.
|
|
12
|
+
- Webhook server, operational command catalogue, alert loop, automation rules, and audit commands.
|
|
13
|
+
|
|
14
|
+
### Fixed
|
|
15
|
+
|
|
16
|
+
- Published ESM declarations now use Node.js-compatible `.js` import specifiers.
|
|
17
|
+
- Package builds with a standalone NodeNext configuration for external consumers.
|
|
18
|
+
|
|
7
19
|
## [0.1.0] - 2026-09-12
|
|
8
20
|
|
|
9
21
|
### Added
|
package/README.md
CHANGED
|
@@ -168,6 +168,10 @@ The library owns RouterOS and Telegram behavior but does not own your web framew
|
|
|
168
168
|
|
|
169
169
|
The public entry point exports configuration, REST transport, services, command registry, runtime adapters, alerting, automation, protected actions, types, and audit helpers from `src/index.ts`.
|
|
170
170
|
|
|
171
|
+
## Complete example
|
|
172
|
+
|
|
173
|
+
See [`examples/production-bot`](./examples/production-bot) for a complete Node.js 20 bot with webhook handling, role-based commands, vouchers, CRUD operations, protected mutations, alerts, automation, and audit export.
|
|
174
|
+
|
|
171
175
|
## Versioning
|
|
172
176
|
|
|
173
177
|
This package follows [Semantic Versioning](https://semver.org/):
|
package/dist/alerts.d.ts
CHANGED
|
@@ -1,5 +1,5 @@
|
|
|
1
1
|
import { z } from 'zod';
|
|
2
|
-
import type { HotspotProfile, SystemHealth, TrafficMetrics } from './types';
|
|
2
|
+
import type { HotspotProfile, SystemHealth, TrafficMetrics } from './types.js';
|
|
3
3
|
export declare const AlertSeveritySchema: z.ZodEnum<{
|
|
4
4
|
info: "info";
|
|
5
5
|
warning: "warning";
|
package/dist/automation.d.ts
CHANGED
package/dist/index.d.ts
CHANGED
|
@@ -1,13 +1,13 @@
|
|
|
1
|
-
export * from './config';
|
|
2
|
-
export * from './errors';
|
|
3
|
-
export * from './rest-client';
|
|
4
|
-
export * from './mikrotik-service';
|
|
5
|
-
export * from './telegram-client';
|
|
6
|
-
export * from './telegram-commands';
|
|
7
|
-
export * from './runtime';
|
|
8
|
-
export * from './runtime-adapters';
|
|
9
|
-
export * from './alerts';
|
|
10
|
-
export * from './automation';
|
|
11
|
-
export * from './actions';
|
|
12
|
-
export * from './types';
|
|
13
|
-
export * from './audit';
|
|
1
|
+
export * from './config.js';
|
|
2
|
+
export * from './errors.js';
|
|
3
|
+
export * from './rest-client.js';
|
|
4
|
+
export * from './mikrotik-service.js';
|
|
5
|
+
export * from './telegram-client.js';
|
|
6
|
+
export * from './telegram-commands.js';
|
|
7
|
+
export * from './runtime.js';
|
|
8
|
+
export * from './runtime-adapters.js';
|
|
9
|
+
export * from './alerts.js';
|
|
10
|
+
export * from './automation.js';
|
|
11
|
+
export * from './actions.js';
|
|
12
|
+
export * from './types.js';
|
|
13
|
+
export * from './audit.js';
|
package/dist/index.js
CHANGED
|
@@ -1,13 +1,13 @@
|
|
|
1
|
-
export * from './config';
|
|
2
|
-
export * from './errors';
|
|
3
|
-
export * from './rest-client';
|
|
4
|
-
export * from './mikrotik-service';
|
|
5
|
-
export * from './telegram-client';
|
|
6
|
-
export * from './telegram-commands';
|
|
7
|
-
export * from './runtime';
|
|
8
|
-
export * from './runtime-adapters';
|
|
9
|
-
export * from './alerts';
|
|
10
|
-
export * from './automation';
|
|
11
|
-
export * from './actions';
|
|
12
|
-
export * from './types';
|
|
13
|
-
export * from './audit';
|
|
1
|
+
export * from './config.js';
|
|
2
|
+
export * from './errors.js';
|
|
3
|
+
export * from './rest-client.js';
|
|
4
|
+
export * from './mikrotik-service.js';
|
|
5
|
+
export * from './telegram-client.js';
|
|
6
|
+
export * from './telegram-commands.js';
|
|
7
|
+
export * from './runtime.js';
|
|
8
|
+
export * from './runtime-adapters.js';
|
|
9
|
+
export * from './alerts.js';
|
|
10
|
+
export * from './automation.js';
|
|
11
|
+
export * from './actions.js';
|
|
12
|
+
export * from './types.js';
|
|
13
|
+
export * from './audit.js';
|
|
@@ -1,5 +1,5 @@
|
|
|
1
|
-
import { RouterOsRestClient } from './rest-client';
|
|
2
|
-
import type { ActiveSession, CreateHotspotUserInput, CreateProfileInput, CreateSchedulerInput, CreateScriptInput, HotspotProfile, HotspotUser, MutationResult, RouterId, RouterScheduler, RouterScript, SystemHealth, UpdateHotspotUserInput, UpdateProfileInput, UpdateSchedulerInput, UserQuery, GenerateVouchersInput, GenerateVouchersResult, BanUserInput, BanResult, UnbanUserInput, DeleteUserInput, DisconnectUserInput } from './types';
|
|
1
|
+
import { RouterOsRestClient } from './rest-client.js';
|
|
2
|
+
import type { ActiveSession, CreateHotspotUserInput, CreateProfileInput, CreateSchedulerInput, CreateScriptInput, HotspotProfile, HotspotUser, MutationResult, RouterId, RouterScheduler, RouterScript, SystemHealth, UpdateHotspotUserInput, UpdateProfileInput, UpdateSchedulerInput, UserQuery, GenerateVouchersInput, GenerateVouchersResult, BanUserInput, BanResult, UnbanUserInput, DeleteUserInput, DisconnectUserInput } from './types.js';
|
|
3
3
|
export declare class MikroTikService {
|
|
4
4
|
private readonly client;
|
|
5
5
|
constructor(client: RouterOsRestClient);
|
package/dist/rest-client.d.ts
CHANGED
package/dist/rest-client.js
CHANGED
package/dist/runtime.d.ts
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
|
-
import type { PackageConfig } from './config';
|
|
2
|
-
import { MikroTikService } from './mikrotik-service';
|
|
3
|
-
import { TelegramCommandRegistry } from './telegram-commands';
|
|
4
|
-
import type { CommandResponse, TelegramUpdate } from './types';
|
|
1
|
+
import type { PackageConfig } from './config.js';
|
|
2
|
+
import { MikroTikService } from './mikrotik-service.js';
|
|
3
|
+
import { TelegramCommandRegistry } from './telegram-commands.js';
|
|
4
|
+
import type { CommandResponse, TelegramUpdate } from './types.js';
|
|
5
5
|
export interface NetPulseRuntime {
|
|
6
6
|
readonly registry: TelegramCommandRegistry;
|
|
7
7
|
readonly mikrotik: MikroTikService;
|
package/dist/runtime.js
CHANGED
|
@@ -1,8 +1,8 @@
|
|
|
1
|
-
import { AuthorizationError } from './errors';
|
|
2
|
-
import { RouterOsRestClient } from './rest-client';
|
|
3
|
-
import { MikroTikService } from './mikrotik-service';
|
|
4
|
-
import { TelegramClient } from './telegram-client';
|
|
5
|
-
import { TelegramCommandRegistry } from './telegram-commands';
|
|
1
|
+
import { AuthorizationError } from './errors.js';
|
|
2
|
+
import { RouterOsRestClient } from './rest-client.js';
|
|
3
|
+
import { MikroTikService } from './mikrotik-service.js';
|
|
4
|
+
import { TelegramClient } from './telegram-client.js';
|
|
5
|
+
import { TelegramCommandRegistry } from './telegram-commands.js';
|
|
6
6
|
function roleFor(config, chatId) {
|
|
7
7
|
if (config.security.adminChatIds.includes(chatId))
|
|
8
8
|
return 'admin';
|
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
import type { CommandContext, CommandDefinition, CommandResponse } from './types';
|
|
1
|
+
import type { CommandContext, CommandDefinition, CommandResponse } from './types.js';
|
|
2
2
|
export interface CommandRegistryOptions {
|
|
3
3
|
readonly confirmationTtlMs?: number;
|
|
4
4
|
readonly now?: () => number;
|
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
import { AuthorizationError, ConfirmationRequiredError } from './errors';
|
|
1
|
+
import { AuthorizationError, ConfirmationRequiredError } from './errors.js';
|
|
2
2
|
const ROLE_WEIGHT = { viewer: 1, operator: 2, admin: 3 };
|
|
3
3
|
export function parseCommand(text) {
|
|
4
4
|
const tokens = text.trim().split(/\s+/).filter(Boolean);
|
|
@@ -0,0 +1,16 @@
|
|
|
1
|
+
MIKROTIK_HOST=192.168.1.64
|
|
2
|
+
MIKROTIK_USER=netpulse-bot
|
|
3
|
+
MIKROTIK_PASSWORD=replace-me
|
|
4
|
+
MIKROTIK_HTTP_PORT=443
|
|
5
|
+
MIKROTIK_HTTPS=true
|
|
6
|
+
MIKROTIK_TIMEOUT_MS=10000
|
|
7
|
+
|
|
8
|
+
TELEGRAM_BOT_TOKEN=replace-me
|
|
9
|
+
TELEGRAM_ALLOWED_CHAT_IDS=123456789
|
|
10
|
+
TELEGRAM_ADMIN_CHAT_IDS=123456789
|
|
11
|
+
TELEGRAM_OPERATOR_CHAT_IDS=123456789
|
|
12
|
+
TELEGRAM_WEBHOOK_SECRET=use-at-least-16-characters
|
|
13
|
+
TELEGRAM_CONFIRMATION_TTL_SECONDS=60
|
|
14
|
+
|
|
15
|
+
BOT_PORT=8787
|
|
16
|
+
ALERT_INTERVAL_MS=300000
|
|
@@ -0,0 +1,48 @@
|
|
|
1
|
+
# Production bot example
|
|
2
|
+
|
|
3
|
+
A complete Node.js 20 example using the published `mikrotik-telegram` package.
|
|
4
|
+
It is deliberately independent from Next.js, the parent application database, and the legacy Telegram bot.
|
|
5
|
+
|
|
6
|
+
## Features exercised
|
|
7
|
+
|
|
8
|
+
- Environment validation with `createConfigFromEnv()`.
|
|
9
|
+
- RouterOS REST health, users, profiles, sessions, vouchers, scripts, and schedulers.
|
|
10
|
+
- Telegram commands with viewer/operator/admin roles.
|
|
11
|
+
- Expiring confirmation flow for `/ban` and `/disconnect`.
|
|
12
|
+
- Protected action catalog and batch guardrails.
|
|
13
|
+
- Router, traffic, and profile-stock alert evaluation.
|
|
14
|
+
- Scheduled automation with health, stock, cleanup, and report rules.
|
|
15
|
+
- Audit logging with JSON and CSV export commands.
|
|
16
|
+
- Node HTTP webhook adapter with Telegram secret validation.
|
|
17
|
+
|
|
18
|
+
## Run
|
|
19
|
+
|
|
20
|
+
```bash
|
|
21
|
+
cp .env.example .env
|
|
22
|
+
# Fill in .env, then:
|
|
23
|
+
npm install
|
|
24
|
+
npm run build
|
|
25
|
+
npm start
|
|
26
|
+
```
|
|
27
|
+
|
|
28
|
+
The webhook endpoint is `POST http://localhost:${BOT_PORT:-8787}/telegram/webhook`.
|
|
29
|
+
Configure Telegram with `setWebhook` and the same `TELEGRAM_WEBHOOK_SECRET`.
|
|
30
|
+
|
|
31
|
+
## Command catalogue
|
|
32
|
+
|
|
33
|
+
- `/start` or `/help`: command list
|
|
34
|
+
- `/health`: RouterOS health
|
|
35
|
+
- `/users profile=guest-2h limit=20`: hotspot users
|
|
36
|
+
- `/profiles`: hotspot profiles
|
|
37
|
+
- `/sessions`: active sessions
|
|
38
|
+
- `/vouchers count=10 profile=guest-2h dryRun=true`: preview or create vouchers
|
|
39
|
+
- `/create-user name=alice password=secret profile=guest-2h`: create a user
|
|
40
|
+
- `/ban address=192.0.2.10`: protected ban confirmation
|
|
41
|
+
- `/disconnect session=*1`: protected session disconnect
|
|
42
|
+
- `/create-script name=backup source=/system backup save name=nightly`: create script
|
|
43
|
+
- `/create-scheduler name=nightly interval=1d onEvent=/system backup save name=nightly`: create scheduler
|
|
44
|
+
- `/alerts`: run anomaly checks immediately
|
|
45
|
+
- `/automation`: list configured rules
|
|
46
|
+
- `/audit format=csv`: export the in-memory audit log
|
|
47
|
+
|
|
48
|
+
The example intentionally keeps destructive actions explicit. In production, persist audit entries and automation state in your own durable store.
|
|
@@ -0,0 +1,590 @@
|
|
|
1
|
+
{
|
|
2
|
+
"name": "mikrotik-telegram-production-example",
|
|
3
|
+
"version": "0.1.0",
|
|
4
|
+
"lockfileVersion": 3,
|
|
5
|
+
"requires": true,
|
|
6
|
+
"packages": {
|
|
7
|
+
"": {
|
|
8
|
+
"name": "mikrotik-telegram-production-example",
|
|
9
|
+
"version": "0.1.0",
|
|
10
|
+
"dependencies": {
|
|
11
|
+
"mikrotik-telegram": "file:../.."
|
|
12
|
+
},
|
|
13
|
+
"devDependencies": {
|
|
14
|
+
"@types/node": "^22.0.0",
|
|
15
|
+
"tsx": "^4.19.0",
|
|
16
|
+
"typescript": "^5.9.3"
|
|
17
|
+
},
|
|
18
|
+
"engines": {
|
|
19
|
+
"node": ">=20"
|
|
20
|
+
}
|
|
21
|
+
},
|
|
22
|
+
"../..": {
|
|
23
|
+
"name": "mikrotik-telegram",
|
|
24
|
+
"version": "0.2.0",
|
|
25
|
+
"license": "MIT",
|
|
26
|
+
"dependencies": {
|
|
27
|
+
"zod": "^4.6.1"
|
|
28
|
+
},
|
|
29
|
+
"devDependencies": {
|
|
30
|
+
"typescript": "^5.9.3"
|
|
31
|
+
},
|
|
32
|
+
"engines": {
|
|
33
|
+
"node": ">=20"
|
|
34
|
+
}
|
|
35
|
+
},
|
|
36
|
+
"node_modules/@esbuild/aix-ppc64": {
|
|
37
|
+
"version": "0.28.2",
|
|
38
|
+
"resolved": "https://registry.npmjs.org/@esbuild/aix-ppc64/-/aix-ppc64-0.28.2.tgz",
|
|
39
|
+
"integrity": "sha512-XExcO+dvLKvVtNTibSTBej1NCAbaGhWn9Ww1ZPx80qsahhPFe/8jgWP0IchNe0F3HwkU7n8ejhH8bjonqht8mQ==",
|
|
40
|
+
"cpu": [
|
|
41
|
+
"ppc64"
|
|
42
|
+
],
|
|
43
|
+
"dev": true,
|
|
44
|
+
"license": "MIT",
|
|
45
|
+
"optional": true,
|
|
46
|
+
"os": [
|
|
47
|
+
"aix"
|
|
48
|
+
],
|
|
49
|
+
"engines": {
|
|
50
|
+
"node": ">=18"
|
|
51
|
+
}
|
|
52
|
+
},
|
|
53
|
+
"node_modules/@esbuild/android-arm": {
|
|
54
|
+
"version": "0.28.2",
|
|
55
|
+
"resolved": "https://registry.npmjs.org/@esbuild/android-arm/-/android-arm-0.28.2.tgz",
|
|
56
|
+
"integrity": "sha512-kXXoiPVVGQcnIYGOeaovwOURpniDBpSq4A03qkQ+BMQqtGG6HYap3xne9C1O1yo4TR3qxlCX5IqqmX6fFo2Lqg==",
|
|
57
|
+
"cpu": [
|
|
58
|
+
"arm"
|
|
59
|
+
],
|
|
60
|
+
"dev": true,
|
|
61
|
+
"license": "MIT",
|
|
62
|
+
"optional": true,
|
|
63
|
+
"os": [
|
|
64
|
+
"android"
|
|
65
|
+
],
|
|
66
|
+
"engines": {
|
|
67
|
+
"node": ">=18"
|
|
68
|
+
}
|
|
69
|
+
},
|
|
70
|
+
"node_modules/@esbuild/android-arm64": {
|
|
71
|
+
"version": "0.28.2",
|
|
72
|
+
"resolved": "https://registry.npmjs.org/@esbuild/android-arm64/-/android-arm64-0.28.2.tgz",
|
|
73
|
+
"integrity": "sha512-5YfKeeI8qWfBZIX+u2xZC3Zlb3Os/gLS2sbEKM+I4ZOcsWmHS2WLysCcQZDAFRslDUU5Oiq44gf6PYN1vGwG5A==",
|
|
74
|
+
"cpu": [
|
|
75
|
+
"arm64"
|
|
76
|
+
],
|
|
77
|
+
"dev": true,
|
|
78
|
+
"license": "MIT",
|
|
79
|
+
"optional": true,
|
|
80
|
+
"os": [
|
|
81
|
+
"android"
|
|
82
|
+
],
|
|
83
|
+
"engines": {
|
|
84
|
+
"node": ">=18"
|
|
85
|
+
}
|
|
86
|
+
},
|
|
87
|
+
"node_modules/@esbuild/android-x64": {
|
|
88
|
+
"version": "0.28.2",
|
|
89
|
+
"resolved": "https://registry.npmjs.org/@esbuild/android-x64/-/android-x64-0.28.2.tgz",
|
|
90
|
+
"integrity": "sha512-O387ite7SzUyCcy3JQX4P4bLtEA7bLLkx+esve5JHnyYfNTxcVpXZo9jhdB0lTKN44gztELTdU7nS8Nr16Fs1Q==",
|
|
91
|
+
"cpu": [
|
|
92
|
+
"x64"
|
|
93
|
+
],
|
|
94
|
+
"dev": true,
|
|
95
|
+
"license": "MIT",
|
|
96
|
+
"optional": true,
|
|
97
|
+
"os": [
|
|
98
|
+
"android"
|
|
99
|
+
],
|
|
100
|
+
"engines": {
|
|
101
|
+
"node": ">=18"
|
|
102
|
+
}
|
|
103
|
+
},
|
|
104
|
+
"node_modules/@esbuild/darwin-arm64": {
|
|
105
|
+
"version": "0.28.2",
|
|
106
|
+
"resolved": "https://registry.npmjs.org/@esbuild/darwin-arm64/-/darwin-arm64-0.28.2.tgz",
|
|
107
|
+
"integrity": "sha512-n4KqkOQrraxHJcgjM1RvwbigfQKIKJVpM7xp+KsxiyUSrRdIXnt73VhrPAx0fV44hgfmIVKjxMN9J1t5jySVkw==",
|
|
108
|
+
"cpu": [
|
|
109
|
+
"arm64"
|
|
110
|
+
],
|
|
111
|
+
"dev": true,
|
|
112
|
+
"license": "MIT",
|
|
113
|
+
"optional": true,
|
|
114
|
+
"os": [
|
|
115
|
+
"darwin"
|
|
116
|
+
],
|
|
117
|
+
"engines": {
|
|
118
|
+
"node": ">=18"
|
|
119
|
+
}
|
|
120
|
+
},
|
|
121
|
+
"node_modules/@esbuild/darwin-x64": {
|
|
122
|
+
"version": "0.28.2",
|
|
123
|
+
"resolved": "https://registry.npmjs.org/@esbuild/darwin-x64/-/darwin-x64-0.28.2.tgz",
|
|
124
|
+
"integrity": "sha512-uq6suIWYP37qzGddBKPw5QEQPi6HiLGsO7UmkpfyaYNQ3D+rN6w6WfwH+nuqcGXWvawGwxOEroO4YGnFh95azw==",
|
|
125
|
+
"cpu": [
|
|
126
|
+
"x64"
|
|
127
|
+
],
|
|
128
|
+
"dev": true,
|
|
129
|
+
"license": "MIT",
|
|
130
|
+
"optional": true,
|
|
131
|
+
"os": [
|
|
132
|
+
"darwin"
|
|
133
|
+
],
|
|
134
|
+
"engines": {
|
|
135
|
+
"node": ">=18"
|
|
136
|
+
}
|
|
137
|
+
},
|
|
138
|
+
"node_modules/@esbuild/freebsd-arm64": {
|
|
139
|
+
"version": "0.28.2",
|
|
140
|
+
"resolved": "https://registry.npmjs.org/@esbuild/freebsd-arm64/-/freebsd-arm64-0.28.2.tgz",
|
|
141
|
+
"integrity": "sha512-n+I0BTSRIoy+d6RPKnEVwql5UwBJolytvY4mAOIEJorKlqgPII8ix6slVVrfZ5Tnj7glIZvloylbB/EJPMWEXw==",
|
|
142
|
+
"cpu": [
|
|
143
|
+
"arm64"
|
|
144
|
+
],
|
|
145
|
+
"dev": true,
|
|
146
|
+
"license": "MIT",
|
|
147
|
+
"optional": true,
|
|
148
|
+
"os": [
|
|
149
|
+
"freebsd"
|
|
150
|
+
],
|
|
151
|
+
"engines": {
|
|
152
|
+
"node": ">=18"
|
|
153
|
+
}
|
|
154
|
+
},
|
|
155
|
+
"node_modules/@esbuild/freebsd-x64": {
|
|
156
|
+
"version": "0.28.2",
|
|
157
|
+
"resolved": "https://registry.npmjs.org/@esbuild/freebsd-x64/-/freebsd-x64-0.28.2.tgz",
|
|
158
|
+
"integrity": "sha512-78XJTJkvPs0kz2w61301PJjXl4g7q3JqiYMZ/M/yVI73EHBrCRTgkhu9oqG7vPqq+a/yadEW8aD+agKlk5xrmg==",
|
|
159
|
+
"cpu": [
|
|
160
|
+
"x64"
|
|
161
|
+
],
|
|
162
|
+
"dev": true,
|
|
163
|
+
"license": "MIT",
|
|
164
|
+
"optional": true,
|
|
165
|
+
"os": [
|
|
166
|
+
"freebsd"
|
|
167
|
+
],
|
|
168
|
+
"engines": {
|
|
169
|
+
"node": ">=18"
|
|
170
|
+
}
|
|
171
|
+
},
|
|
172
|
+
"node_modules/@esbuild/linux-arm": {
|
|
173
|
+
"version": "0.28.2",
|
|
174
|
+
"resolved": "https://registry.npmjs.org/@esbuild/linux-arm/-/linux-arm-0.28.2.tgz",
|
|
175
|
+
"integrity": "sha512-XlDnu2q5yoqems+xay6wSAcg9DDD7K9RLKZEBOMZm3ckNpJBvOX20tSfby8KfrrhINDyv9V2YVZKY/SpoGJI8w==",
|
|
176
|
+
"cpu": [
|
|
177
|
+
"arm"
|
|
178
|
+
],
|
|
179
|
+
"dev": true,
|
|
180
|
+
"license": "MIT",
|
|
181
|
+
"optional": true,
|
|
182
|
+
"os": [
|
|
183
|
+
"linux"
|
|
184
|
+
],
|
|
185
|
+
"engines": {
|
|
186
|
+
"node": ">=18"
|
|
187
|
+
}
|
|
188
|
+
},
|
|
189
|
+
"node_modules/@esbuild/linux-arm64": {
|
|
190
|
+
"version": "0.28.2",
|
|
191
|
+
"resolved": "https://registry.npmjs.org/@esbuild/linux-arm64/-/linux-arm64-0.28.2.tgz",
|
|
192
|
+
"integrity": "sha512-pW4AC0P3it8c7do9MVM4p51FzHzdM/TZrerurgRcHJ2WTa1VQ1CIq18xncfpBJw4ojkiZZrKW2yIBWBP92j6Ug==",
|
|
193
|
+
"cpu": [
|
|
194
|
+
"arm64"
|
|
195
|
+
],
|
|
196
|
+
"dev": true,
|
|
197
|
+
"license": "MIT",
|
|
198
|
+
"optional": true,
|
|
199
|
+
"os": [
|
|
200
|
+
"linux"
|
|
201
|
+
],
|
|
202
|
+
"engines": {
|
|
203
|
+
"node": ">=18"
|
|
204
|
+
}
|
|
205
|
+
},
|
|
206
|
+
"node_modules/@esbuild/linux-ia32": {
|
|
207
|
+
"version": "0.28.2",
|
|
208
|
+
"resolved": "https://registry.npmjs.org/@esbuild/linux-ia32/-/linux-ia32-0.28.2.tgz",
|
|
209
|
+
"integrity": "sha512-CYbnj78HsIeA+DhgUKgFCfvNsTHFhMMrinUrMZpDXJXKN8T3XViTZ/+wtHeVxEWY8ewSzTFN+nRmSwO2tZaLUQ==",
|
|
210
|
+
"cpu": [
|
|
211
|
+
"ia32"
|
|
212
|
+
],
|
|
213
|
+
"dev": true,
|
|
214
|
+
"license": "MIT",
|
|
215
|
+
"optional": true,
|
|
216
|
+
"os": [
|
|
217
|
+
"linux"
|
|
218
|
+
],
|
|
219
|
+
"engines": {
|
|
220
|
+
"node": ">=18"
|
|
221
|
+
}
|
|
222
|
+
},
|
|
223
|
+
"node_modules/@esbuild/linux-loong64": {
|
|
224
|
+
"version": "0.28.2",
|
|
225
|
+
"resolved": "https://registry.npmjs.org/@esbuild/linux-loong64/-/linux-loong64-0.28.2.tgz",
|
|
226
|
+
"integrity": "sha512-buwkd8nsph4R+ajRvw0qM5Hja/TXQow3ptzWO2EbG/cqcIkHloRrdlBtQlshyYGTNFvfkfJ5tpPLVkY4DtsPfQ==",
|
|
227
|
+
"cpu": [
|
|
228
|
+
"loong64"
|
|
229
|
+
],
|
|
230
|
+
"dev": true,
|
|
231
|
+
"license": "MIT",
|
|
232
|
+
"optional": true,
|
|
233
|
+
"os": [
|
|
234
|
+
"linux"
|
|
235
|
+
],
|
|
236
|
+
"engines": {
|
|
237
|
+
"node": ">=18"
|
|
238
|
+
}
|
|
239
|
+
},
|
|
240
|
+
"node_modules/@esbuild/linux-mips64el": {
|
|
241
|
+
"version": "0.28.2",
|
|
242
|
+
"resolved": "https://registry.npmjs.org/@esbuild/linux-mips64el/-/linux-mips64el-0.28.2.tgz",
|
|
243
|
+
"integrity": "sha512-ZVykbDyk7519VwiNb9Lcj9m8XM6v5V9uKPvrEMkkEedVewf+0itkhahp4HDpgERXhwLRpWFypsGbG/J8s0QjJA==",
|
|
244
|
+
"cpu": [
|
|
245
|
+
"mips64el"
|
|
246
|
+
],
|
|
247
|
+
"dev": true,
|
|
248
|
+
"license": "MIT",
|
|
249
|
+
"optional": true,
|
|
250
|
+
"os": [
|
|
251
|
+
"linux"
|
|
252
|
+
],
|
|
253
|
+
"engines": {
|
|
254
|
+
"node": ">=18"
|
|
255
|
+
}
|
|
256
|
+
},
|
|
257
|
+
"node_modules/@esbuild/linux-ppc64": {
|
|
258
|
+
"version": "0.28.2",
|
|
259
|
+
"resolved": "https://registry.npmjs.org/@esbuild/linux-ppc64/-/linux-ppc64-0.28.2.tgz",
|
|
260
|
+
"integrity": "sha512-CAXl+Dtd9UUuJd8pKKdwh6MLm3MUMiqMPmhZ3tTSXPqfyQ3vDl6R5hZdZ/kYojK4ofXtdfSv1tFq8XzWx3heNQ==",
|
|
261
|
+
"cpu": [
|
|
262
|
+
"ppc64"
|
|
263
|
+
],
|
|
264
|
+
"dev": true,
|
|
265
|
+
"license": "MIT",
|
|
266
|
+
"optional": true,
|
|
267
|
+
"os": [
|
|
268
|
+
"linux"
|
|
269
|
+
],
|
|
270
|
+
"engines": {
|
|
271
|
+
"node": ">=18"
|
|
272
|
+
}
|
|
273
|
+
},
|
|
274
|
+
"node_modules/@esbuild/linux-riscv64": {
|
|
275
|
+
"version": "0.28.2",
|
|
276
|
+
"resolved": "https://registry.npmjs.org/@esbuild/linux-riscv64/-/linux-riscv64-0.28.2.tgz",
|
|
277
|
+
"integrity": "sha512-GeXCej4IQtU1B+QlDV8W/RRvbzI3O/Stss+/bCXv4lZls5WGRtu2a+3JkA3i4qIUlMXpcHebWpF8AkJhATowuA==",
|
|
278
|
+
"cpu": [
|
|
279
|
+
"riscv64"
|
|
280
|
+
],
|
|
281
|
+
"dev": true,
|
|
282
|
+
"license": "MIT",
|
|
283
|
+
"optional": true,
|
|
284
|
+
"os": [
|
|
285
|
+
"linux"
|
|
286
|
+
],
|
|
287
|
+
"engines": {
|
|
288
|
+
"node": ">=18"
|
|
289
|
+
}
|
|
290
|
+
},
|
|
291
|
+
"node_modules/@esbuild/linux-s390x": {
|
|
292
|
+
"version": "0.28.2",
|
|
293
|
+
"resolved": "https://registry.npmjs.org/@esbuild/linux-s390x/-/linux-s390x-0.28.2.tgz",
|
|
294
|
+
"integrity": "sha512-3H1weTYZPxt/WOhByszQZybS9w5lKzUn1FDMsgEChbHWQwHYQQRfBxgCcZvPhjHfKyJjIievvMmEUawJrdY9Dg==",
|
|
295
|
+
"cpu": [
|
|
296
|
+
"s390x"
|
|
297
|
+
],
|
|
298
|
+
"dev": true,
|
|
299
|
+
"license": "MIT",
|
|
300
|
+
"optional": true,
|
|
301
|
+
"os": [
|
|
302
|
+
"linux"
|
|
303
|
+
],
|
|
304
|
+
"engines": {
|
|
305
|
+
"node": ">=18"
|
|
306
|
+
}
|
|
307
|
+
},
|
|
308
|
+
"node_modules/@esbuild/linux-x64": {
|
|
309
|
+
"version": "0.28.2",
|
|
310
|
+
"resolved": "https://registry.npmjs.org/@esbuild/linux-x64/-/linux-x64-0.28.2.tgz",
|
|
311
|
+
"integrity": "sha512-4xTZr1FUmSoQW4XIWmit3tzQrUTZM+N3P0XV8xROKYF50XfI7xeO90+1bZvNwxIufQ9hDQVRJH5YhgPVF8A/HQ==",
|
|
312
|
+
"cpu": [
|
|
313
|
+
"x64"
|
|
314
|
+
],
|
|
315
|
+
"dev": true,
|
|
316
|
+
"license": "MIT",
|
|
317
|
+
"optional": true,
|
|
318
|
+
"os": [
|
|
319
|
+
"linux"
|
|
320
|
+
],
|
|
321
|
+
"engines": {
|
|
322
|
+
"node": ">=18"
|
|
323
|
+
}
|
|
324
|
+
},
|
|
325
|
+
"node_modules/@esbuild/netbsd-arm64": {
|
|
326
|
+
"version": "0.28.2",
|
|
327
|
+
"resolved": "https://registry.npmjs.org/@esbuild/netbsd-arm64/-/netbsd-arm64-0.28.2.tgz",
|
|
328
|
+
"integrity": "sha512-sSATRjPeDBg3pdgHoQfoYBob11Kk1FGa9lui5RIHZCoCkJa9QKlvl3/vKz2usCmYYjs7ymJR/2Nnsqe+Hjt5nw==",
|
|
329
|
+
"cpu": [
|
|
330
|
+
"arm64"
|
|
331
|
+
],
|
|
332
|
+
"dev": true,
|
|
333
|
+
"license": "MIT",
|
|
334
|
+
"optional": true,
|
|
335
|
+
"os": [
|
|
336
|
+
"netbsd"
|
|
337
|
+
],
|
|
338
|
+
"engines": {
|
|
339
|
+
"node": ">=18"
|
|
340
|
+
}
|
|
341
|
+
},
|
|
342
|
+
"node_modules/@esbuild/netbsd-x64": {
|
|
343
|
+
"version": "0.28.2",
|
|
344
|
+
"resolved": "https://registry.npmjs.org/@esbuild/netbsd-x64/-/netbsd-x64-0.28.2.tgz",
|
|
345
|
+
"integrity": "sha512-lqnzCV+mM0gIADaKihiCg6ifgfU2L3h5E33rNQBN1Y4MaVGnzryzmvvf7UHxprpQdE8hpqLolJ9Rl+SkIRDpyw==",
|
|
346
|
+
"cpu": [
|
|
347
|
+
"x64"
|
|
348
|
+
],
|
|
349
|
+
"dev": true,
|
|
350
|
+
"license": "MIT",
|
|
351
|
+
"optional": true,
|
|
352
|
+
"os": [
|
|
353
|
+
"netbsd"
|
|
354
|
+
],
|
|
355
|
+
"engines": {
|
|
356
|
+
"node": ">=18"
|
|
357
|
+
}
|
|
358
|
+
},
|
|
359
|
+
"node_modules/@esbuild/openbsd-arm64": {
|
|
360
|
+
"version": "0.28.2",
|
|
361
|
+
"resolved": "https://registry.npmjs.org/@esbuild/openbsd-arm64/-/openbsd-arm64-0.28.2.tgz",
|
|
362
|
+
"integrity": "sha512-AL2qJILH7lNjrDmCQDvdxMfAUIv8KMNZOvrwAQ8i8//ntL9FflhOyMJ8OZSMBb8/AWXe3/5v5S20y3zCoZWKoQ==",
|
|
363
|
+
"cpu": [
|
|
364
|
+
"arm64"
|
|
365
|
+
],
|
|
366
|
+
"dev": true,
|
|
367
|
+
"license": "MIT",
|
|
368
|
+
"optional": true,
|
|
369
|
+
"os": [
|
|
370
|
+
"openbsd"
|
|
371
|
+
],
|
|
372
|
+
"engines": {
|
|
373
|
+
"node": ">=18"
|
|
374
|
+
}
|
|
375
|
+
},
|
|
376
|
+
"node_modules/@esbuild/openbsd-x64": {
|
|
377
|
+
"version": "0.28.2",
|
|
378
|
+
"resolved": "https://registry.npmjs.org/@esbuild/openbsd-x64/-/openbsd-x64-0.28.2.tgz",
|
|
379
|
+
"integrity": "sha512-QtiuPytchRyC4rwUKhexJdQKvDuZ6hWloi3igqPQNUJCS1/v9EiO3UTOXR6A3FoMo4fnAKbWJdqaIwhOzh8qEw==",
|
|
380
|
+
"cpu": [
|
|
381
|
+
"x64"
|
|
382
|
+
],
|
|
383
|
+
"dev": true,
|
|
384
|
+
"license": "MIT",
|
|
385
|
+
"optional": true,
|
|
386
|
+
"os": [
|
|
387
|
+
"openbsd"
|
|
388
|
+
],
|
|
389
|
+
"engines": {
|
|
390
|
+
"node": ">=18"
|
|
391
|
+
}
|
|
392
|
+
},
|
|
393
|
+
"node_modules/@esbuild/openharmony-arm64": {
|
|
394
|
+
"version": "0.28.2",
|
|
395
|
+
"resolved": "https://registry.npmjs.org/@esbuild/openharmony-arm64/-/openharmony-arm64-0.28.2.tgz",
|
|
396
|
+
"integrity": "sha512-WkhYDmpTjLvGlScA1rwjRUmhl4k8oXR3cIbtqWmELgU/dFeHHlEllxDvdWcNJV9rbzCexB5vz8gtNewWLgCT7Q==",
|
|
397
|
+
"cpu": [
|
|
398
|
+
"arm64"
|
|
399
|
+
],
|
|
400
|
+
"dev": true,
|
|
401
|
+
"license": "MIT",
|
|
402
|
+
"optional": true,
|
|
403
|
+
"os": [
|
|
404
|
+
"openharmony"
|
|
405
|
+
],
|
|
406
|
+
"engines": {
|
|
407
|
+
"node": ">=18"
|
|
408
|
+
}
|
|
409
|
+
},
|
|
410
|
+
"node_modules/@esbuild/sunos-x64": {
|
|
411
|
+
"version": "0.28.2",
|
|
412
|
+
"resolved": "https://registry.npmjs.org/@esbuild/sunos-x64/-/sunos-x64-0.28.2.tgz",
|
|
413
|
+
"integrity": "sha512-GPMSkTOtMnv2U2F8gxe4Io6qmVs+YKyp832Etqqxr0hFngmXQ3rzwytelm3GIn7T4VviRUlf3sOgBOiTdvaf7g==",
|
|
414
|
+
"cpu": [
|
|
415
|
+
"x64"
|
|
416
|
+
],
|
|
417
|
+
"dev": true,
|
|
418
|
+
"license": "MIT",
|
|
419
|
+
"optional": true,
|
|
420
|
+
"os": [
|
|
421
|
+
"sunos"
|
|
422
|
+
],
|
|
423
|
+
"engines": {
|
|
424
|
+
"node": ">=18"
|
|
425
|
+
}
|
|
426
|
+
},
|
|
427
|
+
"node_modules/@esbuild/win32-arm64": {
|
|
428
|
+
"version": "0.28.2",
|
|
429
|
+
"resolved": "https://registry.npmjs.org/@esbuild/win32-arm64/-/win32-arm64-0.28.2.tgz",
|
|
430
|
+
"integrity": "sha512-PIhhEkE9uPBleRBrQEJpUn7MBnibZzbGzYWPmY3x+YoVg/95zbjB4CxPPOQ8l5tYYM4mMaCthF8/1DIfBQQyWQ==",
|
|
431
|
+
"cpu": [
|
|
432
|
+
"arm64"
|
|
433
|
+
],
|
|
434
|
+
"dev": true,
|
|
435
|
+
"license": "MIT",
|
|
436
|
+
"optional": true,
|
|
437
|
+
"os": [
|
|
438
|
+
"win32"
|
|
439
|
+
],
|
|
440
|
+
"engines": {
|
|
441
|
+
"node": ">=18"
|
|
442
|
+
}
|
|
443
|
+
},
|
|
444
|
+
"node_modules/@esbuild/win32-ia32": {
|
|
445
|
+
"version": "0.28.2",
|
|
446
|
+
"resolved": "https://registry.npmjs.org/@esbuild/win32-ia32/-/win32-ia32-0.28.2.tgz",
|
|
447
|
+
"integrity": "sha512-YmJbfTlvU7Sdn9BB+4PRES4oB6pxgS37MAONj+hBr/cpXS1aBPKXxNnDbu+QCWPj0o9dgyxeq79g6c5P8KeuYA==",
|
|
448
|
+
"cpu": [
|
|
449
|
+
"ia32"
|
|
450
|
+
],
|
|
451
|
+
"dev": true,
|
|
452
|
+
"license": "MIT",
|
|
453
|
+
"optional": true,
|
|
454
|
+
"os": [
|
|
455
|
+
"win32"
|
|
456
|
+
],
|
|
457
|
+
"engines": {
|
|
458
|
+
"node": ">=18"
|
|
459
|
+
}
|
|
460
|
+
},
|
|
461
|
+
"node_modules/@esbuild/win32-x64": {
|
|
462
|
+
"version": "0.28.2",
|
|
463
|
+
"resolved": "https://registry.npmjs.org/@esbuild/win32-x64/-/win32-x64-0.28.2.tgz",
|
|
464
|
+
"integrity": "sha512-5ebpxr3nWMzrL/rnUI755Jkuee0bHL/Gq0WTF9lvcpv73wAp5eu8MfBUgWK9bhWvZjj7yX8etf/8tI8Ney695g==",
|
|
465
|
+
"cpu": [
|
|
466
|
+
"x64"
|
|
467
|
+
],
|
|
468
|
+
"dev": true,
|
|
469
|
+
"license": "MIT",
|
|
470
|
+
"optional": true,
|
|
471
|
+
"os": [
|
|
472
|
+
"win32"
|
|
473
|
+
],
|
|
474
|
+
"engines": {
|
|
475
|
+
"node": ">=18"
|
|
476
|
+
}
|
|
477
|
+
},
|
|
478
|
+
"node_modules/@types/node": {
|
|
479
|
+
"version": "22.20.2",
|
|
480
|
+
"resolved": "https://registry.npmjs.org/@types/node/-/node-22.20.2.tgz",
|
|
481
|
+
"integrity": "sha512-xlvWf4Vs9n1PEVYwP1n4vvG07M6y8WgvJ2t0vbrWTmijsIHp1cS+uJ2kMIRdY3nHZK0nCYKrPeD171+SzF4/zw==",
|
|
482
|
+
"dev": true,
|
|
483
|
+
"license": "MIT",
|
|
484
|
+
"dependencies": {
|
|
485
|
+
"undici-types": "~6.21.0"
|
|
486
|
+
}
|
|
487
|
+
},
|
|
488
|
+
"node_modules/esbuild": {
|
|
489
|
+
"version": "0.28.2",
|
|
490
|
+
"resolved": "https://registry.npmjs.org/esbuild/-/esbuild-0.28.2.tgz",
|
|
491
|
+
"integrity": "sha512-HKVLS8dvII+xoKW9kmqxbRKrnWEXfJJr/FZhhJmiqIB0e053QNYFqOBouTMO/k5sID4MvCiUCvv8b9M4h32wIA==",
|
|
492
|
+
"dev": true,
|
|
493
|
+
"hasInstallScript": true,
|
|
494
|
+
"license": "MIT",
|
|
495
|
+
"bin": {
|
|
496
|
+
"esbuild": "bin/esbuild"
|
|
497
|
+
},
|
|
498
|
+
"engines": {
|
|
499
|
+
"node": ">=18"
|
|
500
|
+
},
|
|
501
|
+
"optionalDependencies": {
|
|
502
|
+
"@esbuild/aix-ppc64": "0.28.2",
|
|
503
|
+
"@esbuild/android-arm": "0.28.2",
|
|
504
|
+
"@esbuild/android-arm64": "0.28.2",
|
|
505
|
+
"@esbuild/android-x64": "0.28.2",
|
|
506
|
+
"@esbuild/darwin-arm64": "0.28.2",
|
|
507
|
+
"@esbuild/darwin-x64": "0.28.2",
|
|
508
|
+
"@esbuild/freebsd-arm64": "0.28.2",
|
|
509
|
+
"@esbuild/freebsd-x64": "0.28.2",
|
|
510
|
+
"@esbuild/linux-arm": "0.28.2",
|
|
511
|
+
"@esbuild/linux-arm64": "0.28.2",
|
|
512
|
+
"@esbuild/linux-ia32": "0.28.2",
|
|
513
|
+
"@esbuild/linux-loong64": "0.28.2",
|
|
514
|
+
"@esbuild/linux-mips64el": "0.28.2",
|
|
515
|
+
"@esbuild/linux-ppc64": "0.28.2",
|
|
516
|
+
"@esbuild/linux-riscv64": "0.28.2",
|
|
517
|
+
"@esbuild/linux-s390x": "0.28.2",
|
|
518
|
+
"@esbuild/linux-x64": "0.28.2",
|
|
519
|
+
"@esbuild/netbsd-arm64": "0.28.2",
|
|
520
|
+
"@esbuild/netbsd-x64": "0.28.2",
|
|
521
|
+
"@esbuild/openbsd-arm64": "0.28.2",
|
|
522
|
+
"@esbuild/openbsd-x64": "0.28.2",
|
|
523
|
+
"@esbuild/openharmony-arm64": "0.28.2",
|
|
524
|
+
"@esbuild/sunos-x64": "0.28.2",
|
|
525
|
+
"@esbuild/win32-arm64": "0.28.2",
|
|
526
|
+
"@esbuild/win32-ia32": "0.28.2",
|
|
527
|
+
"@esbuild/win32-x64": "0.28.2"
|
|
528
|
+
}
|
|
529
|
+
},
|
|
530
|
+
"node_modules/fsevents": {
|
|
531
|
+
"version": "2.3.3",
|
|
532
|
+
"resolved": "https://registry.npmjs.org/fsevents/-/fsevents-2.3.3.tgz",
|
|
533
|
+
"integrity": "sha512-5xoDfX+fL7faATnagmWPpbFtwh/R77WmMMqqHGS65C3vvB0YHrgF+B1YmZ3441tMj5n63k0212XNoJwzlhffQw==",
|
|
534
|
+
"dev": true,
|
|
535
|
+
"hasInstallScript": true,
|
|
536
|
+
"license": "MIT",
|
|
537
|
+
"optional": true,
|
|
538
|
+
"os": [
|
|
539
|
+
"darwin"
|
|
540
|
+
],
|
|
541
|
+
"engines": {
|
|
542
|
+
"node": "^8.16.0 || ^10.6.0 || >=11.0.0"
|
|
543
|
+
}
|
|
544
|
+
},
|
|
545
|
+
"node_modules/mikrotik-telegram": {
|
|
546
|
+
"resolved": "../..",
|
|
547
|
+
"link": true
|
|
548
|
+
},
|
|
549
|
+
"node_modules/tsx": {
|
|
550
|
+
"version": "4.23.13",
|
|
551
|
+
"resolved": "https://registry.npmjs.org/tsx/-/tsx-4.23.13.tgz",
|
|
552
|
+
"integrity": "sha512-BL5MGkRln6aDYhb0xbQlEAGw743BaZYWdbWtdJOBriYJboKgUUYCadFp2/FpBBZquBC/ezNBn7wMMPx7FDZUDw==",
|
|
553
|
+
"dev": true,
|
|
554
|
+
"license": "MIT",
|
|
555
|
+
"dependencies": {
|
|
556
|
+
"esbuild": "~0.28.0"
|
|
557
|
+
},
|
|
558
|
+
"bin": {
|
|
559
|
+
"tsx": "dist/cli.mjs"
|
|
560
|
+
},
|
|
561
|
+
"engines": {
|
|
562
|
+
"node": ">=18.0.0"
|
|
563
|
+
},
|
|
564
|
+
"optionalDependencies": {
|
|
565
|
+
"fsevents": "~2.3.3"
|
|
566
|
+
}
|
|
567
|
+
},
|
|
568
|
+
"node_modules/typescript": {
|
|
569
|
+
"version": "5.9.3",
|
|
570
|
+
"resolved": "https://registry.npmjs.org/typescript/-/typescript-5.9.3.tgz",
|
|
571
|
+
"integrity": "sha512-jl1vZzPDinLr9eUt3J/t7V6FgNEw9QjvBPdysz9KfQDD41fQrC2Y4vKQdiaUpFT4bXlb1RHhLpp8wtm6M5TgSw==",
|
|
572
|
+
"dev": true,
|
|
573
|
+
"license": "Apache-2.0",
|
|
574
|
+
"bin": {
|
|
575
|
+
"tsc": "bin/tsc",
|
|
576
|
+
"tsserver": "bin/tsserver"
|
|
577
|
+
},
|
|
578
|
+
"engines": {
|
|
579
|
+
"node": ">=14.17"
|
|
580
|
+
}
|
|
581
|
+
},
|
|
582
|
+
"node_modules/undici-types": {
|
|
583
|
+
"version": "6.21.0",
|
|
584
|
+
"resolved": "https://registry.npmjs.org/undici-types/-/undici-types-6.21.0.tgz",
|
|
585
|
+
"integrity": "sha512-iwDZqg0QAGrg9Rav5H4n0M64c3mkR59cJ6wQp+7C4nI0gsmExaedaYLNO44eT4AtBBwjbTiGPMlt2Md0T9H9JQ==",
|
|
586
|
+
"dev": true,
|
|
587
|
+
"license": "MIT"
|
|
588
|
+
}
|
|
589
|
+
}
|
|
590
|
+
}
|
|
@@ -0,0 +1,22 @@
|
|
|
1
|
+
{
|
|
2
|
+
"name": "mikrotik-telegram-production-example",
|
|
3
|
+
"private": true,
|
|
4
|
+
"version": "0.1.0",
|
|
5
|
+
"type": "module",
|
|
6
|
+
"engines": {
|
|
7
|
+
"node": ">=20"
|
|
8
|
+
},
|
|
9
|
+
"scripts": {
|
|
10
|
+
"build": "tsc -p tsconfig.json",
|
|
11
|
+
"start": "node dist/index.js",
|
|
12
|
+
"dev": "tsx src/index.ts"
|
|
13
|
+
},
|
|
14
|
+
"dependencies": {
|
|
15
|
+
"mikrotik-telegram": "file:../.."
|
|
16
|
+
},
|
|
17
|
+
"devDependencies": {
|
|
18
|
+
"@types/node": "^22.0.0",
|
|
19
|
+
"tsx": "^4.19.0",
|
|
20
|
+
"typescript": "^5.9.3"
|
|
21
|
+
}
|
|
22
|
+
}
|
|
@@ -0,0 +1,194 @@
|
|
|
1
|
+
import { createServer, type IncomingMessage } from 'node:http';
|
|
2
|
+
import {
|
|
3
|
+
AlertEngine,
|
|
4
|
+
AutomationEngine,
|
|
5
|
+
createAuditLogger,
|
|
6
|
+
createConfigFromEnv,
|
|
7
|
+
createProtectedAction,
|
|
8
|
+
createRouterActionCatalog,
|
|
9
|
+
createRuntime,
|
|
10
|
+
createWebhookHandler,
|
|
11
|
+
evaluateRouterAnomalies,
|
|
12
|
+
evaluateStockAnomalies,
|
|
13
|
+
evaluateTrafficAnomalies,
|
|
14
|
+
exportAuditLog,
|
|
15
|
+
TelegramClient,
|
|
16
|
+
type ActionContext,
|
|
17
|
+
type Alert,
|
|
18
|
+
type AutomationAction,
|
|
19
|
+
type CommandContext,
|
|
20
|
+
type CommandResponse,
|
|
21
|
+
type TelegramUpdate,
|
|
22
|
+
} from 'mikrotik-telegram';
|
|
23
|
+
|
|
24
|
+
const config = createConfigFromEnv(process.env);
|
|
25
|
+
const runtime = createRuntime(config);
|
|
26
|
+
const telegram = new TelegramClient({ token: config.telegram.token });
|
|
27
|
+
const audit = createAuditLogger('production-bot');
|
|
28
|
+
const alertEngine = new AlertEngine(15 * 60_000);
|
|
29
|
+
const automation = new AutomationEngine();
|
|
30
|
+
|
|
31
|
+
function response(text: string): CommandResponse {
|
|
32
|
+
return { text };
|
|
33
|
+
}
|
|
34
|
+
|
|
35
|
+
function formatAlerts(alerts: readonly Alert[]): string {
|
|
36
|
+
return alerts.length
|
|
37
|
+
? alerts.map((alert) => `${alert.severity.toUpperCase()}: ${alert.title}\n${alert.message}`).join('\n\n')
|
|
38
|
+
: 'Aucune anomalie détectée.';
|
|
39
|
+
}
|
|
40
|
+
|
|
41
|
+
async function notifyOperators(alerts: readonly Alert[]): Promise<void> {
|
|
42
|
+
if (!alerts.length) return;
|
|
43
|
+
const message = formatAlerts(alerts);
|
|
44
|
+
for (const chatId of config.security.operatorChatIds) {
|
|
45
|
+
await telegram.sendMessage(chatId, response(`🚨 NetPulse alertes\n\n${message}`));
|
|
46
|
+
}
|
|
47
|
+
}
|
|
48
|
+
|
|
49
|
+
function actionContext(context: CommandContext): ActionContext {
|
|
50
|
+
return { chatId: context.chatId, userId: context.userId, role: context.role };
|
|
51
|
+
}
|
|
52
|
+
|
|
53
|
+
const actions = createRouterActionCatalog({
|
|
54
|
+
async health() {
|
|
55
|
+
return { ok: true, data: await runtime.mikrotik.getSystemHealth() };
|
|
56
|
+
},
|
|
57
|
+
async disconnectUser(input) {
|
|
58
|
+
return { ok: true, data: await runtime.mikrotik.disconnectUser(input) };
|
|
59
|
+
},
|
|
60
|
+
async banUser(input) {
|
|
61
|
+
return { ok: true, data: await runtime.mikrotik.banUser(input) };
|
|
62
|
+
},
|
|
63
|
+
});
|
|
64
|
+
|
|
65
|
+
const disconnectAction = createProtectedAction(
|
|
66
|
+
'disconnect-session',
|
|
67
|
+
async (input: { sessionId: string }, context) => {
|
|
68
|
+
const result = await actions.disconnectUser(input);
|
|
69
|
+
audit.log({ action: 'session.disconnect', actor: context.userId, resource: input.sessionId, status: result.ok ? 'success' : 'failure', metadata: { result: result.data } });
|
|
70
|
+
return result;
|
|
71
|
+
},
|
|
72
|
+
{ requiredRole: 'operator', requiresConfirmation: true, maxBatchSize: 1, confirm: async () => ({ ok: true }) },
|
|
73
|
+
);
|
|
74
|
+
|
|
75
|
+
const banAction = createProtectedAction(
|
|
76
|
+
'ban-user',
|
|
77
|
+
async (input: { address: string; timeout?: string }, context) => {
|
|
78
|
+
const result = await actions.banUser(input);
|
|
79
|
+
audit.log({ action: 'user.ban', actor: context.userId, resource: input.address, status: result.ok ? 'success' : 'failure', metadata: { result: result.data } });
|
|
80
|
+
return result;
|
|
81
|
+
},
|
|
82
|
+
{ requiredRole: 'admin', requiresConfirmation: true, confirm: async () => ({ ok: true }) },
|
|
83
|
+
);
|
|
84
|
+
|
|
85
|
+
async function runHealthCheck(): Promise<{ alerts: readonly Alert[] }> {
|
|
86
|
+
try {
|
|
87
|
+
const health = await runtime.mikrotik.getSystemHealth();
|
|
88
|
+
const evaluation = evaluateRouterAnomalies({ online: true, health });
|
|
89
|
+
const filtered = alertEngine.filter(evaluation.alerts);
|
|
90
|
+
audit.log({ action: 'automation.health-check', resource: health.identity, status: 'success', metadata: { alerts: filtered.alerts.length } });
|
|
91
|
+
await notifyOperators(filtered.alerts);
|
|
92
|
+
return filtered;
|
|
93
|
+
} catch (error) {
|
|
94
|
+
const evaluation = evaluateRouterAnomalies({ online: false });
|
|
95
|
+
const filtered = alertEngine.filter(evaluation.alerts);
|
|
96
|
+
audit.log({ action: 'automation.health-check', status: 'failure', metadata: { error: String(error) } });
|
|
97
|
+
await notifyOperators(filtered.alerts);
|
|
98
|
+
return filtered;
|
|
99
|
+
}
|
|
100
|
+
}
|
|
101
|
+
|
|
102
|
+
async function runStockCheck(): Promise<{ alerts: readonly Alert[] }> {
|
|
103
|
+
const profiles = await runtime.mikrotik.listProfiles();
|
|
104
|
+
const filtered = alertEngine.filter(evaluateStockAnomalies(profiles).alerts);
|
|
105
|
+
audit.log({ action: 'automation.stock-check', status: 'success', metadata: { profiles: profiles.length, alerts: filtered.alerts.length } });
|
|
106
|
+
await notifyOperators(filtered.alerts);
|
|
107
|
+
return filtered;
|
|
108
|
+
}
|
|
109
|
+
|
|
110
|
+
async function executeAutomation(action: AutomationAction, rule: { id: string }) {
|
|
111
|
+
const startedAt = new Date().toISOString();
|
|
112
|
+
if (action === 'health-check') {
|
|
113
|
+
const result = await runHealthCheck();
|
|
114
|
+
return { ruleId: rule.id, action, success: true, startedAt, finishedAt: new Date().toISOString(), alerts: result.alerts };
|
|
115
|
+
}
|
|
116
|
+
if (action === 'stock-check') {
|
|
117
|
+
const result = await runStockCheck();
|
|
118
|
+
return { ruleId: rule.id, action, success: true, startedAt, finishedAt: new Date().toISOString(), alerts: result.alerts };
|
|
119
|
+
}
|
|
120
|
+
if (action === 'cleanup-sessions') {
|
|
121
|
+
const sessions = await runtime.mikrotik.listActiveSessions();
|
|
122
|
+
audit.log({ action: 'automation.cleanup-sessions', status: 'success', metadata: { activeSessions: sessions.length } });
|
|
123
|
+
return { ruleId: rule.id, action, success: true, startedAt, finishedAt: new Date().toISOString() };
|
|
124
|
+
}
|
|
125
|
+
audit.log({ action: `automation.${action}`, status: 'success' });
|
|
126
|
+
return { ruleId: rule.id, action, success: true, startedAt, finishedAt: new Date().toISOString() };
|
|
127
|
+
}
|
|
128
|
+
|
|
129
|
+
automation.register({ id: 'health', name: 'Router health', action: 'health-check', intervalMs: Number(process.env.ALERT_INTERVAL_MS || 300_000), enabled: true, runImmediately: true });
|
|
130
|
+
automation.register({ id: 'stock', name: 'Profile capacity', action: 'stock-check', intervalMs: 900_000, enabled: true, runImmediately: false });
|
|
131
|
+
automation.register({ id: 'sessions', name: 'Session inventory', action: 'cleanup-sessions', intervalMs: 600_000, enabled: true, runImmediately: false });
|
|
132
|
+
|
|
133
|
+
runtime.registry.registerMany([
|
|
134
|
+
{ name: 'automation', description: 'Lister les automatisations', minimumRole: 'viewer', execute: async () => response(automation.list().map((rule) => `• ${rule.id}: ${rule.action} (${rule.enabled ? 'active' : 'pause'})`).join('\n')) },
|
|
135
|
+
{ name: 'health', aliases: ['status'], description: 'État du routeur', minimumRole: 'viewer', execute: async () => { const health = await runtime.mikrotik.getSystemHealth(); return response(`🟢 ${health.identity} · ${health.model}\nCPU: ${health.cpuLoadPercent}%\nRAM libre: ${Math.round(health.freeMemoryBytes / 1048576)} MB\nREST: ${health.latencyMs} ms`); } },
|
|
136
|
+
{ name: 'users', description: 'Lister les utilisateurs hotspot', minimumRole: 'viewer', execute: async (context) => { const users = await runtime.mikrotik.listHotspotUsers({ profile: context.args.profile, limit: Number(context.args.limit || 20) }); return response(users.length ? users.map((user) => `• ${user.name} · ${user.profile || 'default'} · ${user.id}`).join('\n') : 'Aucun utilisateur.'); } },
|
|
137
|
+
{ name: 'profiles', description: 'Lister les profils', minimumRole: 'viewer', execute: async () => { const profiles = await runtime.mikrotik.listProfiles(); return response(profiles.map((profile) => `• ${profile.name} · ${profile.rateLimit || 'illimité'} · shared=${profile.sharedUsers ?? 0}`).join('\n') || 'Aucun profil.'); } },
|
|
138
|
+
{ name: 'sessions', description: 'Lister les sessions', minimumRole: 'viewer', execute: async () => { const sessions = await runtime.mikrotik.listActiveSessions(); return response(sessions.map((session) => `• ${session.user} · ${session.address || '?'} · ${session.id}`).join('\n') || 'Aucune session.'); } },
|
|
139
|
+
{ name: 'vouchers', aliases: ['generate'], description: 'Générer des vouchers', minimumRole: 'operator', execute: async (context) => { const result = await runtime.mikrotik.generateVouchers({ count: Number(context.args.count || context.positional[0] || 1), profile: context.args.profile || 'default', prefix: context.args.prefix || 'NET', limitUptime: context.args.duration, comment: context.args.comment, dryRun: context.args.dryRun === 'true' }); audit.log({ action: 'voucher.generate', actor: context.userId, status: 'success', metadata: { requested: result.requested, created: result.created, dryRun: result.dryRun } }); return response(`${result.dryRun ? 'Aperçu' : 'Créés'}: ${result.created || result.requested}\n${result.vouchers.map((voucher) => `${voucher.name} · ${voucher.password}`).join('\n')}`); } },
|
|
140
|
+
{ name: 'create-user', description: 'Créer un utilisateur', minimumRole: 'operator', execute: async (context) => { const name = context.args.name || context.positional[0]; const password = context.args.password; const profile = context.args.profile || 'default'; if (!name || !password) return response('Usage: /create-user name=alice password=secret profile=guest-2h'); const user = await runtime.mikrotik.createHotspotUser({ name, password, profile, comment: context.args.comment }); audit.log({ action: 'user.create', actor: context.userId, resource: user.id, status: 'success', metadata: { name, profile } }); return response(`Utilisateur créé: ${user.name} · ${user.id}`); } },
|
|
141
|
+
{ name: 'ban', description: 'Bannir une adresse', minimumRole: 'admin', execute: async (context) => { const address = context.args.address || context.positional[0]; if (!address) return response('Usage: /ban address=192.0.2.10'); if (context.args.confirm !== 'yes') return runtime.registry.requestConfirmation(context, `/ban address=${address} confirm=yes`); const result = await banAction({ address, timeout: context.args.timeout }, actionContext(context)); return response(result.ok ? `Adresse bannie: ${address}` : result.error || 'Échec du bannissement.'); } },
|
|
142
|
+
{ name: 'disconnect', description: 'Déconnecter une session', minimumRole: 'operator', execute: async (context) => { const sessionId = context.args.session || context.positional[0]; if (!sessionId) return response('Usage: /disconnect session=*1'); if (context.args.confirm !== 'yes') return runtime.registry.requestConfirmation(context, `/disconnect session=${sessionId} confirm=yes`); const result = await disconnectAction({ sessionId }, actionContext(context)); return response(result.ok ? `Session déconnectée: ${sessionId}` : result.error || 'Échec de la déconnexion.'); } },
|
|
143
|
+
{ name: 'create-script', description: 'Créer un script RouterOS', minimumRole: 'admin', execute: async (context) => { const name = context.args.name; const source = context.args.source || context.positional.slice(1).join(' '); if (!name || !source) return response('Usage: /create-script name=backup source=/system backup save'); const script = await runtime.mikrotik.createScript({ name, source }); audit.log({ action: 'script.create', actor: context.userId, resource: script.id, status: 'success' }); return response(`Script créé: ${script.name} · ${script.id}`); } },
|
|
144
|
+
{ name: 'create-scheduler', description: 'Créer un scheduler RouterOS', minimumRole: 'admin', execute: async (context) => { const name = context.args.name; const interval = context.args.interval; const onEvent = context.args.onEvent; if (!name || !interval || !onEvent) return response('Usage: /create-scheduler name=nightly interval=1d onEvent=/system backup save'); const scheduler = await runtime.mikrotik.createScheduler({ name, interval, onEvent }); audit.log({ action: 'scheduler.create', actor: context.userId, resource: scheduler.id, status: 'success' }); return response(`Scheduler créé: ${scheduler.name} · ${scheduler.id}`); } },
|
|
145
|
+
{ name: 'alerts', description: 'Lancer les contrôles', minimumRole: 'operator', execute: async () => { const health = await runHealthCheck(); const stock = await runStockCheck(); const traffic = evaluateTrafficAnomalies({ online: true, totalSessions: (await runtime.mikrotik.listActiveSessions()).length, peakSessions: 100 }); const filtered = alertEngine.filter(traffic.alerts); await notifyOperators(filtered.alerts); return response(formatAlerts([...health.alerts, ...stock.alerts, ...filtered.alerts])); } },
|
|
146
|
+
{ name: 'audit', description: 'Exporter les audits', minimumRole: 'admin', execute: async (context) => { const format = context.args.format === 'csv' ? 'csv' : 'json'; return response(exportAuditLog(audit.snapshot(), format)); } },
|
|
147
|
+
]);
|
|
148
|
+
|
|
149
|
+
async function handleUpdate(update: TelegramUpdate): Promise<unknown> {
|
|
150
|
+
if (update.callback_query?.data && update.callback_query.message) {
|
|
151
|
+
const chatId = String(update.callback_query.message.chat.id);
|
|
152
|
+
const callbackResponse = await runtime.registry.executeCallback(update.callback_query.data, chatId);
|
|
153
|
+
await telegram.answerCallbackQuery(update.callback_query.id, callbackResponse.text);
|
|
154
|
+
const confirmedCommand = callbackResponse.text.match(/^Action confirmée: (.+)$/)?.[1];
|
|
155
|
+
if (confirmedCommand) return runtime.handleUpdate({ update_id: update.update_id, message: { message_id: update.update_id, text: confirmedCommand, chat: { id: chatId, type: 'private' }, from: { id: update.callback_query.from.id } } });
|
|
156
|
+
return telegram.sendMessage(chatId, callbackResponse);
|
|
157
|
+
}
|
|
158
|
+
return runtime.handleUpdate(update);
|
|
159
|
+
}
|
|
160
|
+
|
|
161
|
+
function toRequest(request: IncomingMessage, body: string): Request {
|
|
162
|
+
const protocol = 'http';
|
|
163
|
+
const host = request.headers.host || 'localhost';
|
|
164
|
+
return new Request(`${protocol}://${host}${request.url || '/'}`, { method: request.method, headers: request.headers as Record<string, string>, body: request.method === 'POST' ? body : undefined });
|
|
165
|
+
}
|
|
166
|
+
|
|
167
|
+
const webhook = createWebhookHandler(handleUpdate, { secret: config.telegram.webhookSecret });
|
|
168
|
+
const server = createServer(async (request, response) => {
|
|
169
|
+
const chunks: Buffer[] = [];
|
|
170
|
+
request.on('data', (chunk: Buffer) => chunks.push(chunk));
|
|
171
|
+
request.on('end', async () => {
|
|
172
|
+
if (request.url !== '/telegram/webhook') { response.writeHead(404).end('Not Found'); return; }
|
|
173
|
+
const result = await webhook(toRequest(request, Buffer.concat(chunks).toString('utf8')));
|
|
174
|
+
response.writeHead(result.status, Object.fromEntries(result.headers.entries())).end(await result.text());
|
|
175
|
+
});
|
|
176
|
+
});
|
|
177
|
+
|
|
178
|
+
const port = Number(process.env.BOT_PORT || 8787);
|
|
179
|
+
server.listen(port, () => console.log(`Production bot listening on http://localhost:${port}/telegram/webhook`));
|
|
180
|
+
|
|
181
|
+
const automationTimer = setInterval(async () => {
|
|
182
|
+
const results = await automation.runDue({ now: new Date(), execute: executeAutomation });
|
|
183
|
+
for (const result of results) if (!result.success) audit.log({ action: `automation.${result.action}`, status: 'failure', metadata: { result } });
|
|
184
|
+
}, 30_000);
|
|
185
|
+
|
|
186
|
+
automationTimer.unref();
|
|
187
|
+
|
|
188
|
+
function shutdown(signal: string): void {
|
|
189
|
+
clearInterval(automationTimer);
|
|
190
|
+
server.close(() => { console.log(`Stopped on ${signal}`); process.exit(0); });
|
|
191
|
+
}
|
|
192
|
+
|
|
193
|
+
process.once('SIGINT', () => shutdown('SIGINT'));
|
|
194
|
+
process.once('SIGTERM', () => shutdown('SIGTERM'));
|
|
@@ -0,0 +1,16 @@
|
|
|
1
|
+
{
|
|
2
|
+
"compilerOptions": {
|
|
3
|
+
"target": "ES2022",
|
|
4
|
+
"lib": ["ES2022", "DOM", "DOM.Iterable"],
|
|
5
|
+
"module": "NodeNext",
|
|
6
|
+
"moduleResolution": "NodeNext",
|
|
7
|
+
"strict": true,
|
|
8
|
+
"skipLibCheck": true,
|
|
9
|
+
"esModuleInterop": true,
|
|
10
|
+
"forceConsistentCasingInFileNames": true,
|
|
11
|
+
"outDir": "dist",
|
|
12
|
+
"rootDir": "src",
|
|
13
|
+
"types": ["node"]
|
|
14
|
+
},
|
|
15
|
+
"include": ["src/**/*.ts"]
|
|
16
|
+
}
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "mikrotik-telegram",
|
|
3
|
-
"version": "0.
|
|
3
|
+
"version": "0.2.0",
|
|
4
4
|
"description": "Type-safe RouterOS REST automation and Telegram bot package for modern MikroTik operations.",
|
|
5
5
|
"license": "MIT",
|
|
6
6
|
"private": false,
|
|
@@ -23,7 +23,8 @@
|
|
|
23
23
|
"dist",
|
|
24
24
|
"README.md",
|
|
25
25
|
"LICENSE",
|
|
26
|
-
"CHANGELOG.md"
|
|
26
|
+
"CHANGELOG.md",
|
|
27
|
+
"examples"
|
|
27
28
|
],
|
|
28
29
|
"publishConfig": {
|
|
29
30
|
"access": "public"
|