@iobroker/db-states-jsonl 7.2.3 → 8.0.0-alpha.1-20260921-e5941ca8a

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.
@@ -3,6 +3,7 @@ var __defProp = Object.defineProperty;
3
3
  var __getOwnPropDesc = Object.getOwnPropertyDescriptor;
4
4
  var __getOwnPropNames = Object.getOwnPropertyNames;
5
5
  var __hasOwnProp = Object.prototype.hasOwnProperty;
6
+ var __name = (target, value) => __defProp(target, "name", { value, configurable: true });
6
7
  var __export = (target, all) => {
7
8
  for (var name in all)
8
9
  __defProp(target, name, { get: all[name], enumerable: true });
@@ -16,18 +17,19 @@ var __copyProps = (to, from, except, desc) => {
16
17
  return to;
17
18
  };
18
19
  var __toCommonJS = (mod) => __copyProps(__defProp({}, "__esModule", { value: true }), mod);
19
- var esm_exports = {};
20
- __export(esm_exports, {
20
+ var index_exports = {};
21
+ __export(index_exports, {
21
22
  Client: () => import_db_states_redis.Client,
22
23
  Server: () => import_statesInMemServerClass.StatesInMemoryServerClass,
23
24
  getDefaultPort: () => getDefaultPort
24
25
  });
25
- module.exports = __toCommonJS(esm_exports);
26
+ module.exports = __toCommonJS(index_exports);
26
27
  var import_db_states_redis = require("@iobroker/db-states-redis");
27
28
  var import_statesInMemServerClass = require("./lib/states/statesInMemServerClass.js");
28
29
  function getDefaultPort() {
29
30
  return 9e3;
30
31
  }
32
+ __name(getDefaultPort, "getDefaultPort");
31
33
  // Annotate the CommonJS export names for ESM import in node:
32
34
  0 && (module.exports = {
33
35
  Client,
@@ -2,6 +2,6 @@
2
2
  "version": 3,
3
3
  "sources": ["../../src/index.ts"],
4
4
  "sourcesContent": ["export { Client } from '@iobroker/db-states-redis';\nexport { StatesInMemoryServerClass as Server } from './lib/states/statesInMemServerClass.js';\n\n/**\n * Get the default port of the objects db\n */\nexport function getDefaultPort(): number {\n return 9000;\n}\n"],
5
- "mappings": ";;;;;;;;;;;;;;;;;;AAAA;;;;;;;AAAA,6BAAuB;AACvB,oCAAoD;AAK9C,SAAU,iBAAc;AAC1B,SAAO;AACX;",
5
+ "mappings": ";;;;;;;;;;;;;;;;;;;AAAA;;;;;;;AAAA,6BAAuB;AACvB,oCAAoD;AAK9C,SAAU,iBAAc;AAC1B,SAAO;AACX;AAFgB;",
6
6
  "names": []
7
7
  }
@@ -1,11 +1,33 @@
1
1
  /**
2
- * This class inherits InMemoryFileDB class and adds all relevant logic for states
2
+ * States DB in memory - Server
3
+ *
4
+ * Copyright 2013-2026 bluefox <dogafox@gmail.com>
5
+ *
6
+ * MIT License
7
+ *
8
+ */
9
+ import { StatesInMemoryFileDB } from '@iobroker/db-states-file';
10
+ import type { FileDbSettings } from '@iobroker/db-base';
11
+ /**
12
+ * This class inherits the InMemoryFileDB class and adds all relevant logic for states
3
13
  * including the available methods for use by js-controller directly
4
14
  */
5
- export class StatesInMemoryJsonlDB extends StatesInMemoryFileDB {
6
- constructor(settings: any);
7
- _db: JsonlDB<unknown>;
8
- _backupInterval: NodeJS.Timeout | undefined;
15
+ export declare class StatesInMemoryJsonlDB<THandler extends {
16
+ _subscribe?: Record<string, {
17
+ pattern: string;
18
+ regex: RegExp;
19
+ }[]>;
20
+ }> extends StatesInMemoryFileDB<THandler> {
21
+ private readonly _db;
22
+ private _backupInterval;
23
+ /**
24
+ * @param settings Settings for the states database
25
+ */
26
+ constructor(settings: FileDbSettings<ioBroker.State | Record<string, string>>);
27
+ /**
28
+ * Open the JSONL database, migrating from the legacy file DB if necessary
29
+ */
30
+ open(): Promise<void>;
9
31
  /**
10
32
  * Checks if an existing file DB should be migrated to JSONL
11
33
  *
@@ -13,8 +35,17 @@ export class StatesInMemoryJsonlDB extends StatesInMemoryFileDB {
13
35
  * If this returns true, the jsonl DB was opened and doesn't need to be opened again.
14
36
  */
15
37
  _maybeMigrateFileDB(): Promise<boolean>;
38
+ /**
39
+ * Persist the state. Nothing to do here as the JSONL DB saves behind the scenes.
40
+ */
41
+ saveState(): Promise<void>;
42
+ /**
43
+ * Regularly called to store a compressed backup of the DB
44
+ */
16
45
  saveBackup(): Promise<void>;
46
+ /**
47
+ * Stop the backup interval, close the DB and clean up
48
+ */
49
+ destroy(): Promise<void>;
17
50
  }
18
- import { StatesInMemoryFileDB } from '@iobroker/db-states-file';
19
- import { JsonlDB } from '@alcalzone/jsonl-db';
20
51
  //# sourceMappingURL=statesInMemJsonlDB.d.ts.map
@@ -5,6 +5,7 @@ var __getOwnPropDesc = Object.getOwnPropertyDescriptor;
5
5
  var __getOwnPropNames = Object.getOwnPropertyNames;
6
6
  var __getProtoOf = Object.getPrototypeOf;
7
7
  var __hasOwnProp = Object.prototype.hasOwnProperty;
8
+ var __name = (target, value) => __defProp(target, "name", { value, configurable: true });
8
9
  var __export = (target, all) => {
9
10
  for (var name in all)
10
11
  __defProp(target, name, { get: all[name], enumerable: true });
@@ -31,11 +32,11 @@ __export(statesInMemJsonlDB_exports, {
31
32
  StatesInMemoryJsonlDB: () => StatesInMemoryJsonlDB
32
33
  });
33
34
  module.exports = __toCommonJS(statesInMemJsonlDB_exports);
34
- var import_db_states_file = require("@iobroker/db-states-file");
35
- var import_jsonl_db = require("@alcalzone/jsonl-db");
36
35
  var import_node_path = __toESM(require("node:path"), 1);
37
36
  var import_node_fs = __toESM(require("node:fs"), 1);
38
37
  var import_node_os = __toESM(require("node:os"), 1);
38
+ var import_db_states_file = require("@iobroker/db-states-file");
39
+ var import_jsonl_db = require("@alcalzone/jsonl-db");
39
40
  var import_js_controller_common_db = require("@iobroker/js-controller-common-db");
40
41
  function normalizeJsonlOptions(conf = {}) {
41
42
  const ret = {
@@ -43,7 +44,7 @@ function normalizeJsonlOptions(conf = {}) {
43
44
  // Compress when the number of uncompressed entries has grown a lot
44
45
  sizeFactor: 10,
45
46
  sizeFactorMinimumSize: 5e4,
46
- // Compress at least daily to avoid a huge file when DBs have few objects
47
+ // Compress at least daily to avoid a huge file when DBs have few objects,
47
48
  // but big binary states are updated regularly
48
49
  intervalMs: 1e3 * 60 * 60 * 23
49
50
  },
@@ -61,8 +62,11 @@ function normalizeJsonlOptions(conf = {}) {
61
62
  staleMs: 2e3
62
63
  }
63
64
  };
64
- if (import_js_controller_common_db.tools.isObject(conf.autoCompress)) {
65
+ if (conf.autoCompress && typeof conf.autoCompress === "object") {
65
66
  const ac = conf.autoCompress;
67
+ if (!ret.autoCompress) {
68
+ throw new Error("Unexpected autoCompress");
69
+ }
66
70
  if (typeof ac.sizeFactor === "number" && ac.sizeFactor >= 2 && ac.sizeFactor <= 100) {
67
71
  ret.autoCompress.sizeFactor = ac.sizeFactor;
68
72
  }
@@ -70,8 +74,11 @@ function normalizeJsonlOptions(conf = {}) {
70
74
  ret.autoCompress.sizeFactorMinimumSize = ac.sizeFactorMinimumSize;
71
75
  }
72
76
  }
73
- if (import_js_controller_common_db.tools.isObject(conf.throttleFS)) {
77
+ if (conf.throttleFS && typeof conf.throttleFS === "object") {
74
78
  const thr = conf.throttleFS;
79
+ if (!ret.throttleFS) {
80
+ throw new Error("Unexpected throttle fs");
81
+ }
75
82
  if (typeof thr.intervalMs === "number" && thr.intervalMs >= 1e3 && thr.intervalMs <= 36e5) {
76
83
  ret.throttleFS.intervalMs = thr.intervalMs;
77
84
  }
@@ -81,51 +88,63 @@ function normalizeJsonlOptions(conf = {}) {
81
88
  }
82
89
  return ret;
83
90
  }
91
+ __name(normalizeJsonlOptions, "normalizeJsonlOptions");
84
92
  class StatesInMemoryJsonlDB extends import_db_states_file.StatesInMemoryFileDB {
93
+ static {
94
+ __name(this, "StatesInMemoryJsonlDB");
95
+ }
96
+ _db;
97
+ _backupInterval;
98
+ /**
99
+ * @param settings Settings for the states database
100
+ */
85
101
  constructor(settings) {
86
- settings = settings || {};
87
102
  settings.fileDB = {
88
103
  fileName: "states.json",
89
104
  backupDirName: "backup-objects"
90
105
  };
91
106
  const jsonlOptions = normalizeJsonlOptions(settings.connection.jsonlOptions);
107
+ const jsonlFileName = "states.jsonl";
92
108
  settings.jsonlDB = {
93
- fileName: "states.jsonl"
109
+ fileName: jsonlFileName
94
110
  };
95
111
  super(settings);
96
- this._db = new import_jsonl_db.JsonlDB(import_node_path.default.join(this.dataDir, settings.jsonlDB.fileName), jsonlOptions);
112
+ this._db = new import_jsonl_db.JsonlDB(import_node_path.default.join(this.dataDir, jsonlFileName), jsonlOptions);
97
113
  }
114
+ /**
115
+ * Open the JSONL database, migrating from the legacy file DB if necessary
116
+ */
98
117
  async open() {
99
118
  if (!await this._maybeMigrateFileDB()) {
100
119
  await this._db.open();
101
120
  }
102
121
  this.dataset = new Proxy(this._db, {
103
122
  /**
104
- * @param target
105
- * @param prop
123
+ * @param target The proxied JsonlDB instance
124
+ * @param prop The property key being read
106
125
  */
107
126
  get(target, prop) {
108
127
  return target.get(prop);
109
128
  },
110
129
  /**
111
- * @param target
112
- * @param prop
130
+ * @param target The proxied JsonlDB instance
131
+ * @param prop The property key being checked
113
132
  */
114
133
  has(target, prop) {
115
134
  return target.has(prop);
116
135
  },
117
136
  /**
118
- * @param target
119
- * @param prop
120
- * @param value
137
+ * @param target The proxied JsonlDB instance
138
+ * @param prop The property key being written
139
+ * @param value The value to store
121
140
  */
122
141
  set(target, prop, value) {
123
142
  target.set(prop, value);
124
143
  return true;
125
144
  },
126
145
  /**
127
- * @param target
128
- * @param prop
146
+ * @param target The proxied JsonlDB instance
147
+ * @param prop The property key being deleted
129
148
  */
130
149
  deleteProperty(target, prop) {
131
150
  return target.delete(prop);
@@ -134,8 +153,8 @@ class StatesInMemoryJsonlDB extends import_db_states_file.StatesInMemoryFileDB {
134
153
  return [...target.keys()];
135
154
  },
136
155
  /**
137
- * @param target
138
- * @param prop
156
+ * @param target The proxied JsonlDB instance
157
+ * @param prop The property key to describe
139
158
  */
140
159
  getOwnPropertyDescriptor(target, prop) {
141
160
  if (!target.has(prop)) {
@@ -149,9 +168,9 @@ class StatesInMemoryJsonlDB extends import_db_states_file.StatesInMemoryFileDB {
149
168
  };
150
169
  }
151
170
  });
152
- if (this.settings.backup && this.settings.backup.period && !this.settings.backup.disabled) {
171
+ if (this.settings.backup?.period && !this.settings.backup.disabled) {
153
172
  this._backupInterval = setInterval(() => {
154
- this.saveBackup();
173
+ this.saveBackup().catch((e) => this.log.error(`${this.namespace} Cannot save backup: ${e.message}`));
155
174
  }, this.settings.backup.period);
156
175
  }
157
176
  }
@@ -162,30 +181,35 @@ class StatesInMemoryJsonlDB extends import_db_states_file.StatesInMemoryFileDB {
162
181
  * If this returns true, the jsonl DB was opened and doesn't need to be opened again.
163
182
  */
164
183
  async _maybeMigrateFileDB() {
165
- const jsonlFileName = import_node_path.default.join(this.dataDir, this.settings.jsonlDB.fileName);
166
- const jsonFileName = import_node_path.default.join(this.dataDir, this.settings.fileDB.fileName);
167
- const bakFileName = import_node_path.default.join(this.dataDir, `${this.settings.fileDB.fileName}.bak`);
184
+ const jsonlName = this.settings.jsonlDB?.fileName;
185
+ const jsonName = this.settings.fileDB?.fileName;
186
+ if (!jsonlName || !jsonName) {
187
+ return false;
188
+ }
189
+ const jsonlFileName = import_node_path.default.join(this.dataDir, jsonlName);
190
+ const jsonFileName = import_node_path.default.join(this.dataDir, jsonName);
191
+ const bakFileName = import_node_path.default.join(this.dataDir, `${jsonName}.bak`);
168
192
  let jsonlTimeStamp = 0;
169
193
  let jsonTimeStamp = 0;
170
194
  let bakTimeStamp = 0;
171
195
  try {
172
196
  const stat = import_node_fs.default.statSync(jsonlFileName);
173
197
  if (stat.isFile()) {
174
- jsonlTimeStamp = stat.mtime;
198
+ jsonlTimeStamp = stat.mtimeMs;
175
199
  }
176
200
  } catch {
177
201
  }
178
202
  try {
179
203
  const stat = import_node_fs.default.statSync(jsonFileName);
180
204
  if (stat.isFile()) {
181
- jsonTimeStamp = stat.mtime;
205
+ jsonTimeStamp = stat.mtimeMs;
182
206
  }
183
207
  } catch {
184
208
  }
185
209
  try {
186
210
  const stat = import_node_fs.default.statSync(bakFileName);
187
211
  if (stat.isFile()) {
188
- bakTimeStamp = stat.mtime;
212
+ bakTimeStamp = stat.mtimeMs;
189
213
  }
190
214
  } catch {
191
215
  }
@@ -199,7 +223,7 @@ class StatesInMemoryJsonlDB extends import_db_states_file.StatesInMemoryFileDB {
199
223
  }
200
224
  await this._db.open();
201
225
  this._db.clear();
202
- await this._db.importJson(importFilename);
226
+ this._db.importJSON(JSON.parse(import_node_fs.default.readFileSync(importFilename, "utf8")));
203
227
  if (import_node_fs.default.existsSync(jsonFileName)) {
204
228
  try {
205
229
  import_node_fs.default.renameSync(jsonFileName, `${jsonFileName}.migrated`);
@@ -214,13 +238,22 @@ class StatesInMemoryJsonlDB extends import_db_states_file.StatesInMemoryFileDB {
214
238
  }
215
239
  return true;
216
240
  }
241
+ /**
242
+ * Persist the state. Nothing to do here as the JSONL DB saves behind the scenes.
243
+ */
217
244
  async saveState() {
218
245
  }
219
- // Is regularly called and stores a compressed backup of the DB
246
+ /**
247
+ * Regularly called to store a compressed backup of the DB
248
+ */
220
249
  async saveBackup() {
250
+ const jsonlFileName = this.settings.jsonlDB?.fileName;
251
+ if (!jsonlFileName) {
252
+ return;
253
+ }
221
254
  const now = Date.now();
222
- const tmpBackupFileName = import_node_path.default.join(import_node_os.default.tmpdir(), `${this.getTimeStr(now)}_${this.settings.jsonlDB.fileName}`);
223
- const backupFileName = import_node_path.default.join(this.backupDir, `${this.getTimeStr(now)}_${this.settings.jsonlDB.fileName}.gz`);
255
+ const tmpBackupFileName = import_node_path.default.join(import_node_os.default.tmpdir(), `${this.getTimeStr(now)}_${jsonlFileName}`);
256
+ const backupFileName = import_node_path.default.join(this.backupDir, `${this.getTimeStr(now)}_${jsonlFileName}.gz`);
224
257
  if (!this._db.isOpen) {
225
258
  this.log.warn(`${this.namespace} Cannot save backup ${backupFileName}: DB is closed`);
226
259
  return;
@@ -231,11 +264,14 @@ class StatesInMemoryJsonlDB extends import_db_states_file.StatesInMemoryFileDB {
231
264
  }
232
265
  await this._db.dump(tmpBackupFileName);
233
266
  await import_js_controller_common_db.tools.compressFileGZip(tmpBackupFileName, backupFileName, { deleteInput: true });
234
- this.deleteOldBackupFiles(this.settings.jsonlDB.fileName);
267
+ this.deleteOldBackupFiles(jsonlFileName);
235
268
  } catch (e) {
236
269
  this.log.error(`${this.namespace} Cannot save backup ${backupFileName}: ${e.message}`);
237
270
  }
238
271
  }
272
+ /**
273
+ * Stop the backup interval, close the DB and clean up
274
+ */
239
275
  async destroy() {
240
276
  await super.destroy();
241
277
  if (this._backupInterval) {
@@ -1,7 +1,7 @@
1
1
  {
2
2
  "version": 3,
3
- "sources": ["../../../../src/lib/states/statesInMemJsonlDB.js"],
4
- "sourcesContent": ["/**\n * States DB in memory - Server\n *\n * Copyright 2013-2024 bluefox <dogafox@gmail.com>\n *\n * MIT License\n *\n */\n\nimport { StatesInMemoryFileDB } from '@iobroker/db-states-file';\nimport { JsonlDB } from '@alcalzone/jsonl-db';\nimport path from 'node:path';\nimport fs from 'node:fs';\nimport os from 'node:os';\nimport { tools } from '@iobroker/js-controller-common-db';\n\n// settings = {\n// change: function (id, state) {},\n// connected: function (nameOfServer) {},\n// logger: {\n// silly: function (msg) {},\n// debug: function (msg) {},\n// info: function (msg) {},\n// warn: function (msg) {},\n// error: function (msg) {}\n// },\n// connection: {\n// dataDir: 'relative path'\n// },\n// auth: null, //unused\n// secure: true/false,\n// certificates: as required by createServer\n// port: 9000,\n// host: localhost\n// };\n//\n\n/**\n * Normalizes options for the JsonlDB\n *\n * @param conf The jsonlOptions options from iobroker.json\n * @returns\n */\nfunction normalizeJsonlOptions(conf = {}) {\n const ret = {\n autoCompress: {\n // Compress when the number of uncompressed entries has grown a lot\n sizeFactor: 10,\n sizeFactorMinimumSize: 50000,\n // Compress at least daily to avoid a huge file when DBs have few objects\n // but big binary states are updated regularly\n intervalMs: 1000 * 60 * 60 * 23,\n },\n ignoreReadErrors: true,\n throttleFS: {\n intervalMs: 60000,\n maxBufferedCommands: 2000,\n },\n lockfile: {\n // 5 retries starting at 250ms add up to just above 2s,\n // so the DB has 3 more seconds to load all data if it wants to stay within the 5s connectionTimeout\n retries: 5,\n retryMinTimeoutMs: 250,\n // This makes sure the DB stays locked for maximum 2s even if the process crashes\n staleMs: 2000,\n },\n };\n\n // Be really careful what we allow here. Incorrect settings may cause problems in production.\n if (tools.isObject(conf.autoCompress)) {\n const ac = conf.autoCompress;\n // Letting the DB grow more than 100x is risky\n if (typeof ac.sizeFactor === 'number' && ac.sizeFactor >= 2 && ac.sizeFactor <= 100) {\n ret.autoCompress.sizeFactor = ac.sizeFactor;\n }\n // Also we should definitely compress once the DB has reached 200k lines or it might grow too big\n if (\n typeof ac.sizeFactorMinimumSize === 'number' &&\n ac.sizeFactorMinimumSize >= 0 &&\n ac.sizeFactorMinimumSize <= 200000\n ) {\n ret.autoCompress.sizeFactorMinimumSize = ac.sizeFactorMinimumSize;\n }\n }\n if (tools.isObject(conf.throttleFS)) {\n const thr = conf.throttleFS;\n // Don't write more often than every second and write at least once every hour\n if (typeof thr.intervalMs === 'number' && thr.intervalMs >= 1000 && thr.intervalMs <= 3600000) {\n ret.throttleFS.intervalMs = thr.intervalMs;\n }\n // Don't keep too much in memory - 100k changes are more than enough\n if (\n typeof thr.maxBufferedCommands === 'number' &&\n thr.maxBufferedCommands >= 0 &&\n thr.maxBufferedCommands <= 100000\n ) {\n ret.throttleFS.maxBufferedCommands = thr.maxBufferedCommands;\n }\n }\n\n return ret;\n}\n\n/**\n * This class inherits InMemoryFileDB class and adds all relevant logic for states\n * including the available methods for use by js-controller directly\n */\nexport class StatesInMemoryJsonlDB extends StatesInMemoryFileDB {\n constructor(settings) {\n settings = settings || {};\n // Not really used\n settings.fileDB = {\n fileName: 'states.json',\n backupDirName: 'backup-objects',\n };\n\n const jsonlOptions = normalizeJsonlOptions(settings.connection.jsonlOptions);\n settings.jsonlDB = {\n fileName: 'states.jsonl',\n };\n super(settings);\n\n this._db = new JsonlDB(path.join(this.dataDir, settings.jsonlDB.fileName), jsonlOptions);\n }\n\n async open() {\n if (!(await this._maybeMigrateFileDB())) {\n await this._db.open();\n }\n\n // Create an object-like wrapper around the internal Map\n this.dataset = new Proxy(this._db, {\n /**\n * @param target\n * @param prop\n */\n get(target, prop) {\n return target.get(prop);\n },\n /**\n * @param target\n * @param prop\n */\n has(target, prop) {\n return target.has(prop);\n },\n /**\n * @param target\n * @param prop\n * @param value\n */\n set(target, prop, value) {\n target.set(prop, value);\n return true;\n },\n /**\n * @param target\n * @param prop\n */\n deleteProperty(target, prop) {\n return target.delete(prop);\n },\n ownKeys(target) {\n return [...target.keys()];\n },\n /**\n * @param target\n * @param prop\n */\n getOwnPropertyDescriptor(target, prop) {\n if (!target.has(prop)) {\n return undefined;\n }\n return {\n configurable: true,\n enumerable: true,\n writable: true,\n value: target.get(prop),\n };\n },\n });\n\n if (this.settings.backup && this.settings.backup.period && !this.settings.backup.disabled) {\n this._backupInterval = setInterval(() => {\n this.saveBackup();\n }, this.settings.backup.period);\n }\n }\n\n /**\n * Checks if an existing file DB should be migrated to JSONL\n *\n * @returns true if the file DB was migrated. false if not.\n * If this returns true, the jsonl DB was opened and doesn't need to be opened again.\n */\n async _maybeMigrateFileDB() {\n const jsonlFileName = path.join(this.dataDir, this.settings.jsonlDB.fileName);\n const jsonFileName = path.join(this.dataDir, this.settings.fileDB.fileName);\n const bakFileName = path.join(this.dataDir, `${this.settings.fileDB.fileName}.bak`);\n\n // Check the timestamps of each file, defaulting to 0 if they don't exist\n let jsonlTimeStamp = 0;\n let jsonTimeStamp = 0;\n let bakTimeStamp = 0;\n try {\n const stat = fs.statSync(jsonlFileName);\n if (stat.isFile()) {\n jsonlTimeStamp = stat.mtime;\n }\n } catch {\n // ignore\n }\n try {\n const stat = fs.statSync(jsonFileName);\n if (stat.isFile()) {\n jsonTimeStamp = stat.mtime;\n }\n } catch {\n // ignore\n }\n try {\n const stat = fs.statSync(bakFileName);\n if (stat.isFile()) {\n bakTimeStamp = stat.mtime;\n }\n } catch {\n // ignore\n }\n\n // Figure out which file needs to be imported\n let importFilename;\n if (jsonTimeStamp > 0 && jsonTimeStamp >= bakTimeStamp && jsonTimeStamp >= jsonlTimeStamp) {\n importFilename = jsonFileName;\n } else if (bakTimeStamp > 0 && bakTimeStamp >= jsonTimeStamp && bakTimeStamp >= jsonlTimeStamp) {\n importFilename = bakFileName;\n } else {\n // None of the File DB files are newer than the JSONL file\n // There is nothing to restore, we're done\n return false;\n }\n\n await this._db.open();\n this._db.clear();\n await this._db.importJson(importFilename);\n\n // And rename the existing files to avoid redoing the work next time\n if (fs.existsSync(jsonFileName)) {\n try {\n fs.renameSync(jsonFileName, `${jsonFileName}.migrated`);\n } catch {\n // ignore\n }\n }\n if (fs.existsSync(bakFileName)) {\n try {\n fs.renameSync(bakFileName, `${bakFileName}.migrated`);\n } catch {\n // ignore\n }\n }\n\n // Signal to the caller that the DB is already open\n return true;\n }\n\n async saveState() {\n // Nothing to do, the DB saves behind the scenes\n }\n\n // Is regularly called and stores a compressed backup of the DB\n async saveBackup() {\n const now = Date.now();\n const tmpBackupFileName = path.join(os.tmpdir(), `${this.getTimeStr(now)}_${this.settings.jsonlDB.fileName}`);\n const backupFileName = path.join(\n this.backupDir,\n `${this.getTimeStr(now)}_${this.settings.jsonlDB.fileName}.gz`,\n );\n\n if (!this._db.isOpen) {\n this.log.warn(`${this.namespace} Cannot save backup ${backupFileName}: DB is closed`);\n return;\n }\n\n try {\n if (fs.existsSync(backupFileName)) {\n return;\n }\n\n // Create a DB dump\n await this._db.dump(tmpBackupFileName);\n // and zip it\n await tools.compressFileGZip(tmpBackupFileName, backupFileName, { deleteInput: true });\n // figure out if older files need to be deleted\n this.deleteOldBackupFiles(this.settings.jsonlDB.fileName);\n } catch (e) {\n this.log.error(`${this.namespace} Cannot save backup ${backupFileName}: ${e.message}`);\n }\n }\n\n async destroy() {\n await super.destroy();\n\n if (this._backupInterval) {\n clearInterval(this._backupInterval);\n }\n if (this._db) {\n await this._db.close();\n }\n }\n}\n"],
5
- "mappings": "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",
3
+ "sources": ["../../../../src/lib/states/statesInMemJsonlDB.ts"],
4
+ "sourcesContent": ["/**\n * States DB in memory - Server\n *\n * Copyright 2013-2026 bluefox <dogafox@gmail.com>\n *\n * MIT License\n *\n */\n/// <reference types=\"@iobroker/types-dev\" />\n\nimport path from 'node:path';\nimport fs from 'node:fs';\nimport os from 'node:os';\n\nimport { StatesInMemoryFileDB } from '@iobroker/db-states-file';\nimport type { FileDbSettings } from '@iobroker/db-base';\nimport { JsonlDB, type JsonlDBOptions } from '@alcalzone/jsonl-db';\nimport { tools } from '@iobroker/js-controller-common-db';\n\n/**\n * Normalizes options for the JsonlDB\n *\n * @param conf The jsonlOptions options from iobroker.json\n * @returns the normalized and validated JsonlDB options\n */\nfunction normalizeJsonlOptions(\n conf: Partial<JsonlDBOptions<ioBroker.State | Record<string, string>>> = {},\n): JsonlDBOptions<ioBroker.State | Record<string, string>> {\n const ret: JsonlDBOptions<ioBroker.State | Record<string, string>> = {\n autoCompress: {\n // Compress when the number of uncompressed entries has grown a lot\n sizeFactor: 10,\n sizeFactorMinimumSize: 50000,\n // Compress at least daily to avoid a huge file when DBs have few objects,\n // but big binary states are updated regularly\n intervalMs: 1000 * 60 * 60 * 23,\n },\n ignoreReadErrors: true,\n throttleFS: {\n intervalMs: 60000,\n maxBufferedCommands: 2000,\n },\n lockfile: {\n // 5 retries starting at 250ms add up to just above 2s,\n // so the DB has 3 more seconds to load all data if it wants to stay within the 5s connectionTimeout\n retries: 5,\n retryMinTimeoutMs: 250,\n // This makes sure the DB stays locked for maximum 2s even if the process crashes\n staleMs: 2000,\n },\n };\n\n // Be really careful what we allow here. Incorrect settings may cause problems in production.\n if (conf.autoCompress && typeof conf.autoCompress === 'object') {\n const ac = conf.autoCompress;\n if (!ret.autoCompress) {\n throw new Error('Unexpected autoCompress');\n }\n // Letting the DB grow more than 100x is risky\n if (typeof ac.sizeFactor === 'number' && ac.sizeFactor >= 2 && ac.sizeFactor <= 100) {\n ret.autoCompress.sizeFactor = ac.sizeFactor;\n }\n // Also, we should definitely compress once the DB has reached 200k lines, or it might grow too big\n if (\n typeof ac.sizeFactorMinimumSize === 'number' &&\n ac.sizeFactorMinimumSize >= 0 &&\n ac.sizeFactorMinimumSize <= 200000\n ) {\n ret.autoCompress.sizeFactorMinimumSize = ac.sizeFactorMinimumSize;\n }\n }\n if (conf.throttleFS && typeof conf.throttleFS === 'object') {\n const thr = conf.throttleFS;\n if (!ret.throttleFS) {\n throw new Error('Unexpected throttle fs');\n }\n // Don't write more often than every second and write at least once every hour\n if (typeof thr.intervalMs === 'number' && thr.intervalMs >= 1000 && thr.intervalMs <= 3600000) {\n ret.throttleFS.intervalMs = thr.intervalMs;\n }\n // Don't keep too much in memory - 100k changes are more than enough\n if (\n typeof thr.maxBufferedCommands === 'number' &&\n thr.maxBufferedCommands >= 0 &&\n thr.maxBufferedCommands <= 100000\n ) {\n ret.throttleFS.maxBufferedCommands = thr.maxBufferedCommands;\n }\n }\n\n return ret;\n}\n\n/**\n * This class inherits the InMemoryFileDB class and adds all relevant logic for states\n * including the available methods for use by js-controller directly\n */\nexport class StatesInMemoryJsonlDB<\n THandler extends {\n _subscribe?: Record<\n string,\n {\n pattern: string;\n regex: RegExp;\n }[]\n >;\n },\n> extends StatesInMemoryFileDB<THandler> {\n private readonly _db: JsonlDB<ioBroker.State | Record<string, string>>;\n private _backupInterval: NodeJS.Timeout | undefined;\n\n /**\n * @param settings Settings for the states database\n */\n constructor(settings: FileDbSettings<ioBroker.State | Record<string, string>>) {\n // Not really used\n settings.fileDB = {\n fileName: 'states.json',\n backupDirName: 'backup-objects',\n };\n\n const jsonlOptions = normalizeJsonlOptions(settings.connection.jsonlOptions);\n const jsonlFileName = 'states.jsonl';\n settings.jsonlDB = {\n fileName: jsonlFileName,\n };\n super(settings);\n\n this._db = new JsonlDB(path.join(this.dataDir, jsonlFileName), jsonlOptions);\n }\n\n /**\n * Open the JSONL database, migrating from the legacy file DB if necessary\n */\n async open(): Promise<void> {\n if (!(await this._maybeMigrateFileDB())) {\n await this._db.open();\n }\n\n // Create an object-like wrapper around the internal Map\n this.dataset = new Proxy(this._db, {\n /**\n * @param target The proxied JsonlDB instance\n * @param prop The property key being read\n */\n get(target: JsonlDB<ioBroker.State | Record<string, string>>, prop: string) {\n return target.get(prop);\n },\n /**\n * @param target The proxied JsonlDB instance\n * @param prop The property key being checked\n */\n has(target: JsonlDB<ioBroker.State | Record<string, string>>, prop: string) {\n return target.has(prop);\n },\n /**\n * @param target The proxied JsonlDB instance\n * @param prop The property key being written\n * @param value The value to store\n */\n set(\n target: JsonlDB<ioBroker.State | Record<string, string>>,\n prop: string,\n value: ioBroker.State | Record<string, string>,\n ) {\n target.set(prop, value);\n return true;\n },\n /**\n * @param target The proxied JsonlDB instance\n * @param prop The property key being deleted\n */\n deleteProperty(target: JsonlDB<ioBroker.State | Record<string, string>>, prop: string) {\n return target.delete(prop);\n },\n ownKeys(target: JsonlDB<ioBroker.State | Record<string, string>>) {\n return [...target.keys()];\n },\n /**\n * @param target The proxied JsonlDB instance\n * @param prop The property key to describe\n */\n getOwnPropertyDescriptor(target: JsonlDB<ioBroker.State | Record<string, string>>, prop: string) {\n if (!target.has(prop)) {\n return undefined;\n }\n return {\n configurable: true,\n enumerable: true,\n writable: true,\n value: target.get(prop),\n };\n },\n }) as unknown as Record<string, ioBroker.State | Record<string, string>>;\n\n if (this.settings.backup?.period && !this.settings.backup.disabled) {\n this._backupInterval = setInterval(() => {\n this.saveBackup().catch(e => this.log.error(`${this.namespace} Cannot save backup: ${e.message}`));\n }, this.settings.backup.period);\n }\n }\n\n /**\n * Checks if an existing file DB should be migrated to JSONL\n *\n * @returns true if the file DB was migrated. false if not.\n * If this returns true, the jsonl DB was opened and doesn't need to be opened again.\n */\n async _maybeMigrateFileDB(): Promise<boolean> {\n const jsonlName = this.settings.jsonlDB?.fileName;\n const jsonName = this.settings.fileDB?.fileName;\n if (!jsonlName || !jsonName) {\n return false;\n }\n const jsonlFileName = path.join(this.dataDir, jsonlName);\n const jsonFileName = path.join(this.dataDir, jsonName);\n const bakFileName = path.join(this.dataDir, `${jsonName}.bak`);\n\n // Check the timestamps of each file, defaulting to 0 if they don't exist\n let jsonlTimeStamp = 0;\n let jsonTimeStamp = 0;\n let bakTimeStamp = 0;\n try {\n const stat = fs.statSync(jsonlFileName);\n if (stat.isFile()) {\n jsonlTimeStamp = stat.mtimeMs;\n }\n } catch {\n // ignore\n }\n try {\n const stat = fs.statSync(jsonFileName);\n if (stat.isFile()) {\n jsonTimeStamp = stat.mtimeMs;\n }\n } catch {\n // ignore\n }\n try {\n const stat = fs.statSync(bakFileName);\n if (stat.isFile()) {\n bakTimeStamp = stat.mtimeMs;\n }\n } catch {\n // ignore\n }\n\n // Figure out which file needs to be imported\n let importFilename: string;\n if (jsonTimeStamp > 0 && jsonTimeStamp >= bakTimeStamp && jsonTimeStamp >= jsonlTimeStamp) {\n importFilename = jsonFileName;\n } else if (bakTimeStamp > 0 && bakTimeStamp >= jsonTimeStamp && bakTimeStamp >= jsonlTimeStamp) {\n importFilename = bakFileName;\n } else {\n // None of the File DB files are newer than the JSONL file\n // There is nothing to restore, we're done\n return false;\n }\n\n await this._db.open();\n this._db.clear();\n this._db.importJSON(JSON.parse(fs.readFileSync(importFilename, 'utf8')));\n\n // And rename the existing files to avoid redoing the work next time\n if (fs.existsSync(jsonFileName)) {\n try {\n fs.renameSync(jsonFileName, `${jsonFileName}.migrated`);\n } catch {\n // ignore\n }\n }\n if (fs.existsSync(bakFileName)) {\n try {\n fs.renameSync(bakFileName, `${bakFileName}.migrated`);\n } catch {\n // ignore\n }\n }\n\n // Signal to the caller that the DB is already open\n return true;\n }\n\n /**\n * Persist the state. Nothing to do here as the JSONL DB saves behind the scenes.\n */\n async saveState(): Promise<void> {\n // Nothing to do, the DB saves behind the scenes\n }\n\n /**\n * Regularly called to store a compressed backup of the DB\n */\n async saveBackup(): Promise<void> {\n const jsonlFileName = this.settings.jsonlDB?.fileName;\n if (!jsonlFileName) {\n return;\n }\n const now = Date.now();\n const tmpBackupFileName = path.join(os.tmpdir(), `${this.getTimeStr(now)}_${jsonlFileName}`);\n const backupFileName = path.join(this.backupDir, `${this.getTimeStr(now)}_${jsonlFileName}.gz`);\n\n if (!this._db.isOpen) {\n this.log.warn(`${this.namespace} Cannot save backup ${backupFileName}: DB is closed`);\n return;\n }\n\n try {\n if (fs.existsSync(backupFileName)) {\n return;\n }\n\n // Create a DB dump\n await this._db.dump(tmpBackupFileName);\n // and zip it\n await tools.compressFileGZip(tmpBackupFileName, backupFileName, { deleteInput: true });\n // figure out if older files need to be deleted\n this.deleteOldBackupFiles(jsonlFileName);\n } catch (e) {\n this.log.error(`${this.namespace} Cannot save backup ${backupFileName}: ${e.message}`);\n }\n }\n\n /**\n * Stop the backup interval, close the DB and clean up\n */\n async destroy(): Promise<void> {\n await super.destroy();\n\n if (this._backupInterval) {\n clearInterval(this._backupInterval);\n }\n if (this._db) {\n await this._db.close();\n }\n }\n}\n"],
5
+ "mappings": "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",
6
6
  "names": ["path", "fs", "os"]
7
7
  }
@@ -1,7 +1,29 @@
1
- export class StatesInMemoryServerClass extends StatesInRedisClient {
2
- constructor(settings: any);
3
- statesServer: StatesInMemoryServer;
1
+ /**
2
+ * States DB in memory - Server with Redis protocol
3
+ *
4
+ * Copyright 2013-2026 bluefox <dogafox@gmail.com>
5
+ *
6
+ * MIT License
7
+ *
8
+ */
9
+ import { Client as StatesInRedisClient, type StatesSettings } from '@iobroker/db-states-redis';
10
+ import { type DbStatus } from '@iobroker/db-base';
11
+ /**
12
+ * States database client that also starts an in-memory server speaking the Redis protocol
13
+ */
14
+ export declare class StatesInMemoryServerClass extends StatesInRedisClient {
15
+ private readonly statesServer;
16
+ /**
17
+ * @param settings Settings for the states client and the in-memory server
18
+ */
19
+ constructor(settings: StatesSettings);
20
+ /**
21
+ * Destroy the client first and the in-memory server afterwards
22
+ */
23
+ destroy(): Promise<void>;
24
+ /**
25
+ * Get the status as reported by the in-memory server
26
+ */
27
+ getStatus(): DbStatus;
4
28
  }
5
- import { Client as StatesInRedisClient } from '@iobroker/db-states-redis';
6
- import { StatesInMemoryServer } from './statesInMemServerRedis.js';
7
29
  //# sourceMappingURL=statesInMemServerClass.d.ts.map
@@ -3,6 +3,7 @@ var __defProp = Object.defineProperty;
3
3
  var __getOwnPropDesc = Object.getOwnPropertyDescriptor;
4
4
  var __getOwnPropNames = Object.getOwnPropertyNames;
5
5
  var __hasOwnProp = Object.prototype.hasOwnProperty;
6
+ var __name = (target, value) => __defProp(target, "name", { value, configurable: true });
6
7
  var __export = (target, all) => {
7
8
  for (var name in all)
8
9
  __defProp(target, name, { get: all[name], enumerable: true });
@@ -24,6 +25,13 @@ module.exports = __toCommonJS(statesInMemServerClass_exports);
24
25
  var import_db_states_redis = require("@iobroker/db-states-redis");
25
26
  var import_statesInMemServerRedis = require("./statesInMemServerRedis.js");
26
27
  class StatesInMemoryServerClass extends import_db_states_redis.Client {
28
+ static {
29
+ __name(this, "StatesInMemoryServerClass");
30
+ }
31
+ statesServer;
32
+ /**
33
+ * @param settings Settings for the states client and the in-memory server
34
+ */
27
35
  constructor(settings) {
28
36
  settings.autoConnect = false;
29
37
  super(settings);
@@ -32,16 +40,22 @@ class StatesInMemoryServerClass extends import_db_states_redis.Client {
32
40
  connection: settings.connection,
33
41
  logger: settings.logger,
34
42
  hostname: settings.hostname,
35
- connected: () => {
43
+ connected: /* @__PURE__ */ __name(() => {
36
44
  this.connectDb();
37
- }
45
+ }, "connected")
38
46
  };
39
47
  this.statesServer = new import_statesInMemServerRedis.StatesInMemoryServer(serverSettings);
40
48
  }
49
+ /**
50
+ * Destroy the client first and the in-memory server afterwards
51
+ */
41
52
  async destroy() {
42
53
  await super.destroy();
43
54
  await this.statesServer.destroy();
44
55
  }
56
+ /**
57
+ * Get the status as reported by the in-memory server
58
+ */
45
59
  getStatus() {
46
60
  return this.statesServer.getStatus();
47
61
  }
@@ -1,7 +1,7 @@
1
1
  {
2
2
  "version": 3,
3
- "sources": ["../../../../src/lib/states/statesInMemServerClass.js"],
4
- "sourcesContent": ["/**\n * States DB in memory - Server with Redis protocol\n *\n * Copyright 2013-2024 bluefox <dogafox@gmail.com>\n *\n * MIT License\n *\n */\n\nimport { Client as StatesInRedisClient } from '@iobroker/db-states-redis';\nimport { StatesInMemoryServer } from './statesInMemServerRedis.js';\n\nexport class StatesInMemoryServerClass extends StatesInRedisClient {\n constructor(settings) {\n settings.autoConnect = false; // delay Client connection to when we need it\n super(settings);\n\n const serverSettings = {\n namespace: settings.namespace ? `${settings.namespace}-Server` : 'Server',\n connection: settings.connection,\n logger: settings.logger,\n hostname: settings.hostname,\n connected: () => {\n this.connectDb(); // now that server is connected also connect client\n },\n };\n this.statesServer = new StatesInMemoryServer(serverSettings);\n }\n\n async destroy() {\n await super.destroy(); // destroy client first\n await this.statesServer.destroy(); // server afterwards too\n }\n\n getStatus() {\n return this.statesServer.getStatus(); // return Status as Server\n }\n}\n"],
5
- "mappings": ";;;;;;;;;;;;;;;;;;AAAA;;;;;AASA,6BAA8C;AAC9C,oCAAqC;AAE/B,MAAO,kCAAkC,uBAAAA,OAAmB;EAC9D,YAAY,UAAQ;AAChB,aAAS,cAAc;AACvB,UAAM,QAAQ;AAEd,UAAM,iBAAiB;MACnB,WAAW,SAAS,YAAY,GAAG,SAAS,SAAS,YAAY;MACjE,YAAY,SAAS;MACrB,QAAQ,SAAS;MACjB,UAAU,SAAS;MACnB,WAAW,MAAK;AACZ,aAAK,UAAS;MAClB;;AAEJ,SAAK,eAAe,IAAI,mDAAqB,cAAc;EAC/D;EAEA,MAAM,UAAO;AACT,UAAM,MAAM,QAAO;AACnB,UAAM,KAAK,aAAa,QAAO;EACnC;EAEA,YAAS;AACL,WAAO,KAAK,aAAa,UAAS;EACtC;;",
3
+ "sources": ["../../../../src/lib/states/statesInMemServerClass.ts"],
4
+ "sourcesContent": ["/**\n * States DB in memory - Server with Redis protocol\n *\n * Copyright 2013-2026 bluefox <dogafox@gmail.com>\n *\n * MIT License\n *\n */\n\nimport { Client as StatesInRedisClient, type StatesSettings } from '@iobroker/db-states-redis';\nimport { StatesInMemoryServer } from './statesInMemServerRedis.js';\nimport { type DbStatus } from '@iobroker/db-base';\n\n/**\n * States database client that also starts an in-memory server speaking the Redis protocol\n */\nexport class StatesInMemoryServerClass extends StatesInRedisClient {\n private readonly statesServer: StatesInMemoryServer;\n\n /**\n * @param settings Settings for the states client and the in-memory server\n */\n constructor(settings: StatesSettings) {\n settings.autoConnect = false; // delay Client connection to when we need it\n super(settings);\n\n const serverSettings = {\n namespace: settings.namespace ? `${settings.namespace}-Server` : 'Server',\n connection: settings.connection,\n logger: settings.logger,\n hostname: settings.hostname,\n connected: () => {\n this.connectDb(); // now that server is connected also connect client\n },\n };\n this.statesServer = new StatesInMemoryServer(serverSettings);\n }\n\n /**\n * Destroy the client first and the in-memory server afterwards\n */\n async destroy(): Promise<void> {\n await super.destroy(); // destroy client first\n await this.statesServer.destroy(); // server afterwards too\n }\n\n /**\n * Get the status as reported by the in-memory server\n */\n getStatus(): DbStatus {\n return this.statesServer.getStatus(); // return Status as Server\n }\n}\n"],
5
+ "mappings": ";;;;;;;;;;;;;;;;;;;AAAA;;;;;AASA,6BAAmE;AACnE,oCAAqC;AAM/B,MAAO,kCAAkC,uBAAAA,OAAmB;EAhBlE,OAgBkE;;;EAC7C;;;;EAKjB,YAAY,UAAwB;AAChC,aAAS,cAAc;AACvB,UAAM,QAAQ;AAEd,UAAM,iBAAiB;MACnB,WAAW,SAAS,YAAY,GAAG,SAAS,SAAS,YAAY;MACjE,YAAY,SAAS;MACrB,QAAQ,SAAS;MACjB,UAAU,SAAS;MACnB,WAAW,6BAAK;AACZ,aAAK,UAAS;MAClB,GAFW;;AAIf,SAAK,eAAe,IAAI,mDAAqB,cAAc;EAC/D;;;;EAKA,MAAM,UAAO;AACT,UAAM,MAAM,QAAO;AACnB,UAAM,KAAK,aAAa,QAAO;EACnC;;;;EAKA,YAAS;AACL,WAAO,KAAK,aAAa,UAAS;EACtC;;",
6
6
  "names": ["StatesInRedisClient"]
7
7
  }
@@ -1,32 +1,58 @@
1
+ /**
2
+ * States DB in memory - Server with Redis protocol
3
+ *
4
+ * Copyright 2013-2024 bluefox <dogafox@gmail.com>
5
+ *
6
+ * MIT License
7
+ *
8
+ */
9
+ import net from 'node:net';
10
+ import { RedisHandler, type ConnectionOptions, type FileDbSettings } from '@iobroker/db-base';
11
+ import { StatesInMemoryJsonlDB } from './statesInMemJsonlDB.js';
12
+ type RedisHandlerInternal = RedisHandler & {
13
+ _subscribe?: Record<string, {
14
+ pattern: string;
15
+ regex: RegExp;
16
+ }[]>;
17
+ };
1
18
  /**
2
19
  * This class inherits statesInMemoryFileDB class and adds socket.io communication layer
3
20
  * to access the methods via socket.io
4
21
  */
5
- export class StatesInMemoryServer extends StatesInMemoryJsonlDB {
22
+ export declare class StatesInMemoryServer extends StatesInMemoryJsonlDB<RedisHandlerInternal> {
23
+ private readonly serverConnections;
24
+ private readonly namespaceStates;
25
+ private readonly namespaceMsg;
26
+ private readonly namespaceLog;
27
+ private readonly namespaceSession;
28
+ private readonly namespaceMsgLen;
29
+ private readonly namespaceLogLen;
30
+ private readonly metaNamespace;
31
+ private server;
6
32
  /**
7
33
  * Constructor
8
34
  *
9
35
  * @param settings State and InMem-DB settings
10
36
  */
11
- constructor(settings: any);
12
- serverConnections: {};
13
- namespaceStates: string;
14
- namespaceMsg: string;
15
- namespaceLog: string;
16
- namespaceSession: string;
17
- namespaceMsgLen: number;
18
- namespaceLogLen: number;
19
- metaNamespace: string;
20
- metaNamespaceLen: number;
37
+ constructor(settings: FileDbSettings<ioBroker.State | Record<string, string>>);
21
38
  /**
22
39
  * Separate Namespace from ID and return both
23
40
  *
24
41
  * @param idWithNamespace ID or Array of IDs containing a redis namespace and the real ID
25
- * @returns Object with namespace and the
26
- * ID/Array of IDs without the namespace
42
+ * @returns Object with namespace and the Array of IDs without the namespace
27
43
  */
28
- _normalizeId(idWithNamespace: any): {
29
- id: any;
44
+ _normalizeIds(idWithNamespace: string[]): {
45
+ ids: string[];
46
+ namespace: string;
47
+ };
48
+ /**
49
+ * Separate Namespace from ID and return both
50
+ *
51
+ * @param idWithNamespace ID or Array of IDs containing a redis namespace and the real ID
52
+ * @returns Object with namespace and the ID without the namespace
53
+ */
54
+ _normalizeId(idWithNamespace: string): {
55
+ id: string;
30
56
  namespace: string;
31
57
  };
32
58
  /**
@@ -36,36 +62,38 @@ export class StatesInMemoryServer extends StatesInMemoryJsonlDB {
36
62
  * @param type Type of subscribed key
37
63
  * @param id Subscribed ID
38
64
  * @param obj Object to publish
39
- * @returns Publish counter 0 or 1 depending if send out or not
65
+ * @returns Publish counter 0 or 1 depending on if send out or not
40
66
  */
41
- publishToClients(client: any, type: any, id: any, obj: any): 0 | 1;
67
+ publishToClients(client: RedisHandlerInternal, type: string, id: string, obj: ioBroker.State | Record<string, string>): number;
42
68
  /**
43
69
  * Register all event listeners for Handler and implement the relevant logic
44
70
  *
45
71
  * @param handler RedisHandler instance
46
72
  */
47
- _socketEvents(handler: any): void;
73
+ _socketEvents(handler: RedisHandler): void;
48
74
  /**
49
75
  * Return connected RedisHandlers/Connections
50
76
  *
51
- * @returns
77
+ * @returns the currently connected RedisHandlers/Connections
52
78
  */
53
- getClients(): {};
79
+ getClients(): Record<string, RedisHandler>;
80
+ /**
81
+ * Destructor of the class. Called by shutting down.
82
+ */
83
+ destroy(): Promise<void>;
54
84
  /**
55
85
  * Initialize RedisHandler for a new network connection
56
86
  *
57
87
  * @param socket Network socket
58
88
  */
59
- _initSocket(socket: any): void;
89
+ _initSocket(socket: net.Socket): void;
60
90
  /**
61
91
  * Initialize Redis Server
62
92
  *
63
93
  * @param settings Settings object
64
- * @returns
94
+ * @returns a promise that resolves once the Redis server is listening
65
95
  */
66
- _initRedisServer(settings: any): Promise<any>;
67
- server: net.Server | undefined;
96
+ _initRedisServer(settings: ConnectionOptions): Promise<void>;
68
97
  }
69
- import { StatesInMemoryJsonlDB } from './statesInMemJsonlDB.js';
70
- import net from 'node:net';
98
+ export {};
71
99
  //# sourceMappingURL=statesInMemServerRedis.d.ts.map