iobroker.beszel 0.2.0 → 0.2.2

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 CHANGED
@@ -122,6 +122,12 @@ beszel.0.
122
122
 
123
123
  ## Changelog
124
124
 
125
+ ### 0.2.2 (2026-04-03)
126
+ - Modernize dev tooling (esbuild, TypeScript 5.9 pin, testing-action-check v2)
127
+
128
+ ### 0.2.1 (2026-03-28)
129
+ - Error deduplication, auth backoff, protect against empty system list deletion
130
+
125
131
  ### 0.2.0 (2026-03-28)
126
132
  - Adapter timer methods, synchronous onUnload, merge About tab, Windows/macOS CI, full MIT license
127
133
 
@@ -137,12 +143,6 @@ beszel.0.
137
143
  ### 0.1.6 (2026-03-18)
138
144
  - Code cleanup: remove dead code, fix duplicate container filter, extract load avg helper
139
145
 
140
- ### 0.1.5 (2026-03-17)
141
- - Migrate to @alcalzone/release-script, enable npm Trusted Publishing
142
-
143
- ### 0.1.4 (2026-03-17)
144
- - Fix all repochecker issues; rename repo to ioBroker.beszel; add responsive grid sizes
145
-
146
146
  Older changelog: [CHANGELOG.md](CHANGELOG.md)
147
147
 
148
148
  ---
@@ -1,204 +1,207 @@
1
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;
2
+ var __create = Object.create;
3
+ var __defProp = Object.defineProperty;
4
+ var __getOwnPropDesc = Object.getOwnPropertyDescriptor;
5
+ var __getOwnPropNames = Object.getOwnPropertyNames;
6
+ var __getProtoOf = Object.getPrototypeOf;
7
+ var __hasOwnProp = Object.prototype.hasOwnProperty;
8
+ var __export = (target, all) => {
9
+ for (var name in all)
10
+ __defProp(target, name, { get: all[name], enumerable: true });
11
+ };
12
+ var __copyProps = (to, from, except, desc) => {
13
+ if (from && typeof from === "object" || typeof from === "function") {
14
+ for (let key of __getOwnPropNames(from))
15
+ if (!__hasOwnProp.call(to, key) && key !== except)
16
+ __defProp(to, key, { get: () => from[key], enumerable: !(desc = __getOwnPropDesc(from, key)) || desc.enumerable });
17
+ }
18
+ return to;
19
+ };
20
+ var __toESM = (mod, isNodeMode, target) => (target = mod != null ? __create(__getProtoOf(mod)) : {}, __copyProps(
21
+ // If the importer is in node compatibility mode or this is not an ESM
22
+ // file that has been converted to a CommonJS file using a Babel-
23
+ // compatible transform (i.e. "__esModule" has not been set), then set
24
+ // "default" to the CommonJS "module.exports" for node compatibility.
25
+ isNodeMode || !mod || !mod.__esModule ? __defProp(target, "default", { value: mod, enumerable: true }) : target,
26
+ mod
27
+ ));
28
+ var __toCommonJS = (mod) => __copyProps(__defProp({}, "__esModule", { value: true }), mod);
29
+ var beszel_client_exports = {};
30
+ __export(beszel_client_exports, {
31
+ BeszelClient: () => BeszelClient
17
32
  });
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
- Object.defineProperty(exports, "__esModule", { value: true });
36
- exports.BeszelClient = void 0;
37
- const http = __importStar(require("http"));
38
- const https = __importStar(require("https"));
39
- const url_1 = require("url");
40
- const TOKEN_REFRESH_MS = 23 * 60 * 60 * 1000; // 23 hours
41
- /**
42
- * HTTP client for the Beszel PocketBase REST API.
43
- * Uses only Node.js built-in http/https — no extra dependencies.
44
- */
33
+ module.exports = __toCommonJS(beszel_client_exports);
34
+ var http = __toESM(require("http"));
35
+ var https = __toESM(require("https"));
36
+ var import_url = require("url");
37
+ const TOKEN_REFRESH_MS = 23 * 60 * 60 * 1e3;
45
38
  class BeszelClient {
46
- baseUrl;
47
- username;
48
- password;
49
- token = null;
50
- tokenTime = 0;
51
- /**
52
- * @param url Beszel Hub base URL, e.g. http://192.168.1.100:8090
53
- * @param username Login username
54
- * @param password Login password
55
- */
56
- constructor(url, username, password) {
57
- // Strip trailing slash
58
- this.baseUrl = url.replace(/\/+$/, "");
59
- this.username = username;
60
- this.password = password;
61
- }
62
- /** Force token re-authentication on the next request */
63
- invalidateToken() {
64
- this.token = null;
65
- this.tokenTime = 0;
66
- }
67
- /**
68
- * Test the connection to Beszel.
69
- * Returns { success: true } or { success: false, message: reason }.
70
- */
71
- async checkConnection() {
72
- try {
73
- this.invalidateToken();
74
- await this.authenticate();
75
- return { success: true, message: "Connected successfully" };
76
- }
77
- catch (err) {
78
- return {
79
- success: false,
80
- message: err instanceof Error ? err.message : String(err),
81
- };
82
- }
39
+ baseUrl;
40
+ username;
41
+ password;
42
+ token = null;
43
+ tokenTime = 0;
44
+ /**
45
+ * @param url Beszel Hub base URL, e.g. http://192.168.1.100:8090
46
+ * @param username Login username
47
+ * @param password Login password
48
+ */
49
+ constructor(url, username, password) {
50
+ this.baseUrl = url.replace(/\/+$/, "");
51
+ this.username = username;
52
+ this.password = password;
53
+ }
54
+ /** Force token re-authentication on the next request */
55
+ invalidateToken() {
56
+ this.token = null;
57
+ this.tokenTime = 0;
58
+ }
59
+ /**
60
+ * Test the connection to Beszel.
61
+ * Returns { success: true } or { success: false, message: reason }.
62
+ */
63
+ async checkConnection() {
64
+ try {
65
+ this.invalidateToken();
66
+ await this.authenticate();
67
+ return { success: true, message: "Connected successfully" };
68
+ } catch (err) {
69
+ return {
70
+ success: false,
71
+ message: err instanceof Error ? err.message : String(err)
72
+ };
83
73
  }
84
- /** Fetch all systems */
85
- async getSystems() {
86
- await this.ensureToken();
87
- const data = await this.fetchJson("/api/collections/systems/records?perPage=200&sort=name");
88
- return data.items;
74
+ }
75
+ /** Fetch all systems */
76
+ async getSystems() {
77
+ await this.ensureToken();
78
+ const data = await this.fetchJson(
79
+ "/api/collections/systems/records?perPage=200&sort=name"
80
+ );
81
+ return data.items;
82
+ }
83
+ /**
84
+ * Fetch the latest 1m stats per system.
85
+ * Returns a Map<systemId, SystemStats>.
86
+ *
87
+ * @param systemIds List of system IDs to fetch stats for
88
+ */
89
+ async getLatestStats(systemIds) {
90
+ if (systemIds.length === 0) {
91
+ return /* @__PURE__ */ new Map();
89
92
  }
90
- /**
91
- * Fetch the latest 1m stats per system.
92
- * Returns a Map<systemId, SystemStats>.
93
- *
94
- * @param systemIds List of system IDs to fetch stats for
95
- */
96
- async getLatestStats(systemIds) {
97
- if (systemIds.length === 0) {
98
- return new Map();
99
- }
100
- await this.ensureToken();
101
- const data = await this.fetchJson("/api/collections/system_stats/records?sort=-updated&perPage=200&filter=type%3D'1m'");
102
- // Deduplicate: keep the newest record per system
103
- const result = new Map();
104
- for (const record of data.items) {
105
- if (!result.has(record.system)) {
106
- result.set(record.system, record.stats);
107
- }
108
- }
109
- return result;
93
+ await this.ensureToken();
94
+ const data = await this.fetchJson(
95
+ "/api/collections/system_stats/records?sort=-updated&perPage=200&filter=type%3D'1m'"
96
+ );
97
+ const result = /* @__PURE__ */ new Map();
98
+ for (const record of data.items) {
99
+ if (!result.has(record.system)) {
100
+ result.set(record.system, record.stats);
101
+ }
110
102
  }
111
- /** Fetch all containers */
112
- async getContainers() {
113
- await this.ensureToken();
114
- const data = await this.fetchJson("/api/collections/containers/records?perPage=500&sort=system%2Cname");
115
- return data.items;
103
+ return result;
104
+ }
105
+ /** Fetch all containers */
106
+ async getContainers() {
107
+ await this.ensureToken();
108
+ const data = await this.fetchJson(
109
+ "/api/collections/containers/records?perPage=500&sort=system%2Cname"
110
+ );
111
+ return data.items;
112
+ }
113
+ // -------------------------------------------------------------------------
114
+ // Private helpers
115
+ // -------------------------------------------------------------------------
116
+ async ensureToken() {
117
+ const now = Date.now();
118
+ if (this.token && now - this.tokenTime < TOKEN_REFRESH_MS) {
119
+ return;
116
120
  }
117
- // -------------------------------------------------------------------------
118
- // Private helpers
119
- // -------------------------------------------------------------------------
120
- async ensureToken() {
121
- const now = Date.now();
122
- if (this.token && now - this.tokenTime < TOKEN_REFRESH_MS) {
121
+ await this.authenticate();
122
+ }
123
+ async authenticate() {
124
+ const body = JSON.stringify({
125
+ identity: this.username,
126
+ password: this.password
127
+ });
128
+ const data = await this.request(
129
+ "POST",
130
+ "/api/collections/users/auth-with-password",
131
+ body,
132
+ null
133
+ // no auth token yet
134
+ );
135
+ this.token = data.token;
136
+ this.tokenTime = Date.now();
137
+ }
138
+ async fetchJson(path) {
139
+ return this.request("GET", path, null, this.token);
140
+ }
141
+ request(method, path, body, token) {
142
+ return new Promise((resolve, reject) => {
143
+ let parsedUrl;
144
+ try {
145
+ parsedUrl = new import_url.URL(this.baseUrl + path);
146
+ } catch {
147
+ reject(new Error(`Invalid URL: ${this.baseUrl + path}`));
148
+ return;
149
+ }
150
+ const isHttps = parsedUrl.protocol === "https:";
151
+ const transport = isHttps ? https : http;
152
+ const headers = {
153
+ "Content-Type": "application/json",
154
+ Accept: "application/json"
155
+ };
156
+ if (token) {
157
+ headers.Authorization = token;
158
+ }
159
+ if (body !== null) {
160
+ headers["Content-Length"] = Buffer.byteLength(body).toString();
161
+ }
162
+ const options = {
163
+ hostname: parsedUrl.hostname,
164
+ port: parsedUrl.port || (isHttps ? 443 : 80),
165
+ path: parsedUrl.pathname + parsedUrl.search,
166
+ method,
167
+ headers,
168
+ timeout: 15e3
169
+ };
170
+ const req = transport.request(options, (res) => {
171
+ const chunks = [];
172
+ res.on("data", (chunk) => chunks.push(chunk));
173
+ res.on("end", () => {
174
+ var _a;
175
+ const raw = Buffer.concat(chunks).toString("utf8");
176
+ if (!res.statusCode || res.statusCode < 200 || res.statusCode >= 300) {
177
+ const err = new Error(
178
+ `HTTP ${(_a = res.statusCode) != null ? _a : "?"}: ${raw.slice(0, 200)}`
179
+ );
180
+ err.code = res.statusCode === 401 ? "UNAUTHORIZED" : "HTTP_ERROR";
181
+ reject(err);
123
182
  return;
124
- }
125
- await this.authenticate();
126
- }
127
- async authenticate() {
128
- const body = JSON.stringify({
129
- identity: this.username,
130
- password: this.password,
183
+ }
184
+ try {
185
+ resolve(JSON.parse(raw));
186
+ } catch {
187
+ reject(new Error(`Invalid JSON response from ${path}`));
188
+ }
131
189
  });
132
- const data = await this.request("POST", "/api/collections/users/auth-with-password", body, null);
133
- this.token = data.token;
134
- this.tokenTime = Date.now();
135
- }
136
- async fetchJson(path) {
137
- return this.request("GET", path, null, this.token);
138
- }
139
- request(method, path, body, token) {
140
- return new Promise((resolve, reject) => {
141
- let parsedUrl;
142
- try {
143
- parsedUrl = new url_1.URL(this.baseUrl + path);
144
- }
145
- catch {
146
- reject(new Error(`Invalid URL: ${this.baseUrl + path}`));
147
- return;
148
- }
149
- const isHttps = parsedUrl.protocol === "https:";
150
- const transport = isHttps ? https : http;
151
- const headers = {
152
- "Content-Type": "application/json",
153
- Accept: "application/json",
154
- };
155
- if (token) {
156
- headers.Authorization = token;
157
- }
158
- if (body !== null) {
159
- headers["Content-Length"] = Buffer.byteLength(body).toString();
160
- }
161
- const options = {
162
- hostname: parsedUrl.hostname,
163
- port: parsedUrl.port || (isHttps ? 443 : 80),
164
- path: parsedUrl.pathname + parsedUrl.search,
165
- method,
166
- headers,
167
- timeout: 15000,
168
- };
169
- const req = transport.request(options, (res) => {
170
- const chunks = [];
171
- res.on("data", (chunk) => chunks.push(chunk));
172
- res.on("end", () => {
173
- const raw = Buffer.concat(chunks).toString("utf8");
174
- if (!res.statusCode ||
175
- res.statusCode < 200 ||
176
- res.statusCode >= 300) {
177
- // Propagate 401 specifically so caller can re-auth
178
- const err = new Error(`HTTP ${res.statusCode ?? "?"}: ${raw.slice(0, 200)}`);
179
- err.code =
180
- res.statusCode === 401 ? "UNAUTHORIZED" : "HTTP_ERROR";
181
- reject(err);
182
- return;
183
- }
184
- try {
185
- resolve(JSON.parse(raw));
186
- }
187
- catch {
188
- reject(new Error(`Invalid JSON response from ${path}`));
189
- }
190
- });
191
- });
192
- req.on("timeout", () => {
193
- req.destroy();
194
- reject(new Error(`Request to ${path} timed out`));
195
- });
196
- req.on("error", (err) => reject(err));
197
- if (body !== null) {
198
- req.write(body);
199
- }
200
- req.end();
201
- });
202
- }
190
+ });
191
+ req.on("timeout", () => {
192
+ req.destroy();
193
+ reject(new Error(`Request to ${path} timed out`));
194
+ });
195
+ req.on("error", (err) => reject(err));
196
+ if (body !== null) {
197
+ req.write(body);
198
+ }
199
+ req.end();
200
+ });
201
+ }
203
202
  }
204
- exports.BeszelClient = BeszelClient;
203
+ // Annotate the CommonJS export names for ESM import in node:
204
+ 0 && (module.exports = {
205
+ BeszelClient
206
+ });
207
+ //# sourceMappingURL=beszel-client.js.map
@@ -0,0 +1,7 @@
1
+ {
2
+ "version": 3,
3
+ "sources": ["../../src/lib/beszel-client.ts"],
4
+ "sourcesContent": ["import * as http from \"http\";\nimport * as https from \"https\";\nimport { URL } from \"url\";\nimport type {\n AuthResponse,\n BeszelContainer,\n BeszelSystem,\n BeszelSystemStats,\n PocketBaseList,\n SystemStats,\n} from \"./types.js\";\n\nconst TOKEN_REFRESH_MS = 23 * 60 * 60 * 1000; // 23 hours\n\n/**\n * HTTP client for the Beszel PocketBase REST API.\n * Uses only Node.js built-in http/https \u2014 no extra dependencies.\n */\nexport class BeszelClient {\n private readonly baseUrl: string;\n private readonly username: string;\n private readonly password: string;\n\n private token: string | null = null;\n private tokenTime = 0;\n\n /**\n * @param url Beszel Hub base URL, e.g. http://192.168.1.100:8090\n * @param username Login username\n * @param password Login password\n */\n constructor(url: string, username: string, password: string) {\n // Strip trailing slash\n this.baseUrl = url.replace(/\\/+$/, \"\");\n this.username = username;\n this.password = password;\n }\n\n /** Force token re-authentication on the next request */\n public invalidateToken(): void {\n this.token = null;\n this.tokenTime = 0;\n }\n\n /**\n * Test the connection to Beszel.\n * Returns { success: true } or { success: false, message: reason }.\n */\n public async checkConnection(): Promise<{\n success: boolean;\n message: string;\n }> {\n try {\n this.invalidateToken();\n await this.authenticate();\n return { success: true, message: \"Connected successfully\" };\n } catch (err) {\n return {\n success: false,\n message: err instanceof Error ? err.message : String(err),\n };\n }\n }\n\n /** Fetch all systems */\n public async getSystems(): Promise<BeszelSystem[]> {\n await this.ensureToken();\n const data = await this.fetchJson<PocketBaseList<BeszelSystem>>(\n \"/api/collections/systems/records?perPage=200&sort=name\",\n );\n return data.items;\n }\n\n /**\n * Fetch the latest 1m stats per system.\n * Returns a Map<systemId, SystemStats>.\n *\n * @param systemIds List of system IDs to fetch stats for\n */\n public async getLatestStats(\n systemIds: string[],\n ): Promise<Map<string, SystemStats>> {\n if (systemIds.length === 0) {\n return new Map();\n }\n await this.ensureToken();\n const data = await this.fetchJson<PocketBaseList<BeszelSystemStats>>(\n \"/api/collections/system_stats/records?sort=-updated&perPage=200&filter=type%3D'1m'\",\n );\n\n // Deduplicate: keep the newest record per system\n const result = new Map<string, SystemStats>();\n for (const record of data.items) {\n if (!result.has(record.system)) {\n result.set(record.system, record.stats);\n }\n }\n return result;\n }\n\n /** Fetch all containers */\n public async getContainers(): Promise<BeszelContainer[]> {\n await this.ensureToken();\n const data = await this.fetchJson<PocketBaseList<BeszelContainer>>(\n \"/api/collections/containers/records?perPage=500&sort=system%2Cname\",\n );\n return data.items;\n }\n\n // -------------------------------------------------------------------------\n // Private helpers\n // -------------------------------------------------------------------------\n\n private async ensureToken(): Promise<void> {\n const now = Date.now();\n if (this.token && now - this.tokenTime < TOKEN_REFRESH_MS) {\n return;\n }\n await this.authenticate();\n }\n\n private async authenticate(): Promise<void> {\n const body = JSON.stringify({\n identity: this.username,\n password: this.password,\n });\n\n const data = await this.request<AuthResponse>(\n \"POST\",\n \"/api/collections/users/auth-with-password\",\n body,\n null, // no auth token yet\n );\n\n this.token = data.token;\n this.tokenTime = Date.now();\n }\n\n private async fetchJson<T>(path: string): Promise<T> {\n return this.request<T>(\"GET\", path, null, this.token);\n }\n\n private request<T>(\n method: string,\n path: string,\n body: string | null,\n token: string | null,\n ): Promise<T> {\n return new Promise((resolve, reject) => {\n let parsedUrl: URL;\n try {\n parsedUrl = new URL(this.baseUrl + path);\n } catch {\n reject(new Error(`Invalid URL: ${this.baseUrl + path}`));\n return;\n }\n\n const isHttps = parsedUrl.protocol === \"https:\";\n const transport = isHttps ? https : http;\n\n const headers: Record<string, string> = {\n \"Content-Type\": \"application/json\",\n Accept: \"application/json\",\n };\n if (token) {\n headers.Authorization = token;\n }\n if (body !== null) {\n headers[\"Content-Length\"] = Buffer.byteLength(body).toString();\n }\n\n const options: http.RequestOptions = {\n hostname: parsedUrl.hostname,\n port: parsedUrl.port || (isHttps ? 443 : 80),\n path: parsedUrl.pathname + parsedUrl.search,\n method,\n headers,\n timeout: 15000,\n };\n\n const req = transport.request(options, (res) => {\n const chunks: Buffer[] = [];\n res.on(\"data\", (chunk: Buffer) => chunks.push(chunk));\n res.on(\"end\", () => {\n const raw = Buffer.concat(chunks).toString(\"utf8\");\n if (\n !res.statusCode ||\n res.statusCode < 200 ||\n res.statusCode >= 300\n ) {\n // Propagate 401 specifically so caller can re-auth\n const err = new Error(\n `HTTP ${res.statusCode ?? \"?\"}: ${raw.slice(0, 200)}`,\n );\n (err as NodeJS.ErrnoException).code =\n res.statusCode === 401 ? \"UNAUTHORIZED\" : \"HTTP_ERROR\";\n reject(err);\n return;\n }\n try {\n resolve(JSON.parse(raw) as T);\n } catch {\n reject(new Error(`Invalid JSON response from ${path}`));\n }\n });\n });\n\n req.on(\"timeout\", () => {\n req.destroy();\n reject(new Error(`Request to ${path} timed out`));\n });\n\n req.on(\"error\", (err) => reject(err));\n\n if (body !== null) {\n req.write(body);\n }\n req.end();\n });\n }\n}\n"],
5
+ "mappings": "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",
6
+ "names": []
7
+ }