iobroker.script-restore 0.0.7 → 0.0.9

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/build/main.js.map CHANGED
@@ -1,7 +1,7 @@
1
1
  {
2
2
  "version": 3,
3
3
  "sources": ["../src/main.ts"],
4
- "sourcesContent": ["/*\n * ioBroker Script Restore Adapter\n * Restore ioBroker scripts from backup archives\n * Copyright (c) 2024 ipod86 <david@graef.email>\n * MIT License\n */\n\nimport type { Dirent } from \"node:fs\";\nimport * as utils from \"@iobroker/adapter-core\";\nimport * as fs from \"fs/promises\";\nimport * as path from \"node:path\";\nimport * as os from \"node:os\";\nimport { exec } from \"node:child_process\";\nimport { promisify } from \"node:util\";\nimport * as ftp from \"basic-ftp\";\nimport { Writable } from \"node:stream\";\nimport * as https from \"node:https\";\nimport * as http from \"node:http\";\nimport SftpClient from \"ssh2-sftp-client\";\n\n// eslint-disable-next-line @typescript-eslint/no-require-imports\nconst SMB2 = require(\"@marsaud/smb2\");\n\nconst execAsync = promisify(exec);\n\ninterface ScriptEntry {\n\tname: string;\n\tpath: string;\n\ttype: string;\n\tsource: string;\n}\n\nclass ScriptRestore extends utils.Adapter {\n\tpublic constructor(options: Partial<utils.AdapterOptions> = {}) {\n\t\tsuper({\n\t\t\t...options,\n\t\t\tname: \"script-restore\",\n\t\t});\n\t\tthis.on(\"ready\", this.onReady.bind(this));\n\t\tthis.on(\"message\", this.onMessage.bind(this));\n\t\tthis.on(\"unload\", this.onUnload.bind(this));\n\t}\n\n\tprivate onReady(): void {\n\t\tthis.log.info(`Script Restore ready. Backup path: ${this.config.backupPath || \"/opt/iobroker/backups\"}`);\n\t}\n\n\tprivate onUnload(callback: () => void): void {\n\t\tcallback();\n\t}\n\n\tprivate async onMessage(obj: ioBroker.Message): Promise<void> {\n\t\tif (!obj.callback) {\n\t\t\treturn;\n\t\t}\n\n\t\ttry {\n\t\t\tswitch (obj.command) {\n\t\t\t\tcase \"listLocalFiles\":\n\t\t\t\t\tawait this.handleListLocalFiles(obj);\n\t\t\t\t\tbreak;\n\t\t\t\tcase \"parseLocalFile\":\n\t\t\t\t\tawait this.handleParseLocalFile(obj);\n\t\t\t\t\tbreak;\n\t\t\t\tcase \"parseUploadedFile\":\n\t\t\t\t\tawait this.handleParseUploadedFile(obj);\n\t\t\t\t\tbreak;\n\t\t\t\tcase \"getSourceConfig\":\n\t\t\t\t\tthis.sendTo(\n\t\t\t\t\t\tobj.from,\n\t\t\t\t\t\tobj.command,\n\t\t\t\t\t\t{\n\t\t\t\t\t\t\tlocalEnabled: this.config.localEnabled !== false,\n\t\t\t\t\t\t\tftpEnabled: !!this.config.ftpEnabled,\n\t\t\t\t\t\t\tsmbEnabled: !!this.config.smbEnabled,\n\t\t\t\t\t\t\thttpEnabled: !!this.config.httpEnabled,\n\t\t\t\t\t\t\tsftpEnabled: !!this.config.sftpEnabled,\n\t\t\t\t\t\t\twebdavEnabled: !!this.config.webdavEnabled,\n\t\t\t\t\t\t},\n\t\t\t\t\t\tobj.callback,\n\t\t\t\t\t);\n\t\t\t\t\tbreak;\n\t\t\t\tcase \"suggestBackupPath\":\n\t\t\t\t\tawait this.handleSuggestBackupPath(obj);\n\t\t\t\t\tbreak;\n\t\t\t\tcase \"parseHttpUrl\":\n\t\t\t\t\tawait this.handleParseHttpUrl(obj);\n\t\t\t\t\tbreak;\n\t\t\t\tcase \"testSftp\":\n\t\t\t\t\tawait this.handleTestSftp(obj);\n\t\t\t\t\tbreak;\n\t\t\t\tcase \"listSftpFiles\":\n\t\t\t\t\tawait this.handleListSftpFiles(obj);\n\t\t\t\t\tbreak;\n\t\t\t\tcase \"parseSftpFile\":\n\t\t\t\t\tawait this.handleParseSftpFile(obj);\n\t\t\t\t\tbreak;\n\t\t\t\tcase \"testWebdav\":\n\t\t\t\t\tawait this.handleTestWebdav(obj);\n\t\t\t\t\tbreak;\n\t\t\t\tcase \"listWebdavFiles\":\n\t\t\t\t\tawait this.handleListWebdavFiles(obj);\n\t\t\t\t\tbreak;\n\t\t\t\tcase \"parseWebdavFile\":\n\t\t\t\t\tawait this.handleParseWebdavFile(obj);\n\t\t\t\t\tbreak;\n\t\t\t\tcase \"testFtp\":\n\t\t\t\t\tawait this.handleTestFtp(obj);\n\t\t\t\t\tbreak;\n\t\t\t\tcase \"testSmb\":\n\t\t\t\t\tawait this.handleTestSmb(obj);\n\t\t\t\t\tbreak;\n\t\t\t\tcase \"listFtpFiles\":\n\t\t\t\t\tawait this.handleListFtpFiles(obj);\n\t\t\t\t\tbreak;\n\t\t\t\tcase \"parseFtpFile\":\n\t\t\t\t\tawait this.handleParseFtpFile(obj);\n\t\t\t\t\tbreak;\n\t\t\t\tcase \"listSmbFiles\":\n\t\t\t\t\tawait this.handleListSmbFiles(obj);\n\t\t\t\t\tbreak;\n\t\t\t\tcase \"parseSmbFile\":\n\t\t\t\t\tawait this.handleParseSmbFile(obj);\n\t\t\t\t\tbreak;\n\t\t\t\tdefault:\n\t\t\t\t\tthis.sendTo(obj.from, obj.command, { error: \"Unknown command\" }, obj.callback);\n\t\t\t}\n\t\t} catch (e) {\n\t\t\tthis.log.error(`Error handling ${obj.command}: ${(e as Error).message}`);\n\t\t\tthis.sendTo(obj.from, obj.command, { error: (e as Error).message }, obj.callback);\n\t\t}\n\t}\n\n\t// \u2500\u2500\u2500 Local \u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\n\n\tprivate async handleListLocalFiles(obj: ioBroker.Message): Promise<void> {\n\t\tif (this.config.localEnabled === false) {\n\t\t\tthis.sendTo(obj.from, obj.command, { error: \"Local source not enabled\" }, obj.callback);\n\t\t\treturn;\n\t\t}\n\t\tconst backupPath = this.config.backupPath || \"/opt/iobroker/backups\";\n\t\ttry {\n\t\t\tconst rawEntries = await fs.readdir(backupPath, { withFileTypes: true, encoding: \"utf8\" });\n\t\t\tconst entries = rawEntries as unknown as Dirent[];\n\t\t\tconst files = entries\n\t\t\t\t.filter(e => {\n\t\t\t\t\tconst n = String(e.name);\n\t\t\t\t\treturn (\n\t\t\t\t\t\te.isFile() &&\n\t\t\t\t\t\t(n.startsWith(\"iobroker\") || n.startsWith(\"javascript\")) &&\n\t\t\t\t\t\t(n.endsWith(\".tar.gz\") || n.endsWith(\".tar\") || n.endsWith(\".json\") || n.endsWith(\".jsonl\"))\n\t\t\t\t\t);\n\t\t\t\t})\n\t\t\t\t.map(e => String(e.name))\n\t\t\t\t.sort()\n\t\t\t\t.reverse();\n\t\t\tthis.sendTo(obj.from, obj.command, { files, path: backupPath }, obj.callback);\n\t\t} catch (e) {\n\t\t\tthis.sendTo(\n\t\t\t\tobj.from,\n\t\t\t\tobj.command,\n\t\t\t\t{ error: `Verzeichnis nicht lesbar: ${(e as Error).message}` },\n\t\t\t\tobj.callback,\n\t\t\t);\n\t\t}\n\t}\n\n\tprivate async handleParseLocalFile(obj: ioBroker.Message): Promise<void> {\n\t\tif (this.config.localEnabled === false) {\n\t\t\tthis.sendTo(obj.from, obj.command, { error: \"Local source not enabled\" }, obj.callback);\n\t\t\treturn;\n\t\t}\n\t\tconst backupPath = this.config.backupPath || \"/opt/iobroker/backups\";\n\t\tconst msg = obj.message as { filename: string };\n\t\tconst filename = path.basename(msg.filename);\n\t\tconst filepath = path.join(backupPath, filename);\n\t\ttry {\n\t\t\tconst buf = await fs.readFile(filepath);\n\t\t\tconst scripts = await this.parseBuffer(buf, filename);\n\t\t\tthis.sendTo(obj.from, obj.command, { scripts }, obj.callback);\n\t\t} catch (e) {\n\t\t\tthis.sendTo(obj.from, obj.command, { error: (e as Error).message }, obj.callback);\n\t\t}\n\t}\n\n\tprivate async handleParseUploadedFile(obj: ioBroker.Message): Promise<void> {\n\t\tconst msg = obj.message as { name: string; data: string };\n\t\ttry {\n\t\t\tconst buf = Buffer.from(msg.data, \"base64\");\n\t\t\tconst scripts = await this.parseBuffer(buf, msg.name);\n\t\t\tthis.sendTo(obj.from, obj.command, { scripts }, obj.callback);\n\t\t} catch (e) {\n\t\t\tthis.sendTo(obj.from, obj.command, { error: (e as Error).message }, obj.callback);\n\t\t}\n\t}\n\n\t// \u2500\u2500\u2500 Tests \u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\n\n\tprivate async handleTestFtp(obj: ioBroker.Message): Promise<void> {\n\t\tconst msg = obj.message as {\n\t\t\thost: string;\n\t\t\tport: number;\n\t\t\tuser: string;\n\t\t\tpassword: string;\n\t\t\tpath: string;\n\t\t\tsecure: boolean;\n\t\t};\n\t\tconst client = new ftp.Client();\n\t\tclient.ftp.verbose = false;\n\t\ttry {\n\t\t\tawait client.access({\n\t\t\t\thost: msg.host,\n\t\t\t\tport: msg.port || 21,\n\t\t\t\tuser: msg.user || \"anonymous\",\n\t\t\t\tpassword: msg.password || \"\",\n\t\t\t\tsecure: msg.secure || false,\n\t\t\t});\n\t\t\tconst list = await client.list(msg.path || \"/\");\n\t\t\tconst count = list.filter(i => i.type === ftp.FileType.File).length;\n\t\t\tthis.sendTo(\n\t\t\t\tobj.from,\n\t\t\t\tobj.command,\n\t\t\t\t{ success: true, message: `Verbunden! ${count} Datei(en) gefunden in: ${msg.path || \"/\"}` },\n\t\t\t\tobj.callback,\n\t\t\t);\n\t\t} catch (e) {\n\t\t\tthis.sendTo(obj.from, obj.command, { success: false, message: (e as Error).message }, obj.callback);\n\t\t} finally {\n\t\t\tclient.close();\n\t\t}\n\t}\n\n\tprivate async handleTestSmb(obj: ioBroker.Message): Promise<void> {\n\t\tconst msg = obj.message as {\n\t\t\thost: string;\n\t\t\tshare: string;\n\t\t\tpath: string;\n\t\t\tuser: string;\n\t\t\tpassword: string;\n\t\t\tdomain: string;\n\t\t};\n\t\tconst smb = new SMB2({\n\t\t\tshare: `\\\\\\\\${msg.host}\\\\${msg.share}`,\n\t\t\tusername: msg.user || \"\",\n\t\t\tpassword: msg.password || \"\",\n\t\t\tdomain: msg.domain || \"\",\n\t\t});\n\t\ttry {\n\t\t\tconst files = await this.smbReaddir(smb, msg.path || \"\");\n\t\t\tthis.sendTo(\n\t\t\t\tobj.from,\n\t\t\t\tobj.command,\n\t\t\t\t{\n\t\t\t\t\tsuccess: true,\n\t\t\t\t\tmessage: `Verbunden! ${files.length} Eintr\u00E4ge in: \\\\\\\\${msg.host}\\\\${msg.share}${msg.path ? `\\\\${msg.path}` : \"\"}`,\n\t\t\t\t},\n\t\t\t\tobj.callback,\n\t\t\t);\n\t\t} catch (e) {\n\t\t\tthis.sendTo(obj.from, obj.command, { success: false, message: (e as Error).message }, obj.callback);\n\t\t} finally {\n\t\t\tsmb.disconnect();\n\t\t}\n\t}\n\n\t// \u2500\u2500\u2500 FTP \u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\n\n\tprivate createFtpClient(): ftp.Client {\n\t\tconst client = new ftp.Client();\n\t\tclient.ftp.verbose = false;\n\t\treturn client;\n\t}\n\n\tprivate async ftpConnect(client: ftp.Client): Promise<void> {\n\t\tawait client.access({\n\t\t\thost: this.config.ftpHost,\n\t\t\tport: this.config.ftpPort || 21,\n\t\t\tuser: this.config.ftpUser || \"anonymous\",\n\t\t\tpassword: this.config.ftpPassword || \"\",\n\t\t\tsecure: this.config.ftpSecure || false,\n\t\t});\n\t}\n\n\tprivate async handleListFtpFiles(obj: ioBroker.Message): Promise<void> {\n\t\tif (!this.config.ftpEnabled) {\n\t\t\tthis.sendTo(obj.from, obj.command, { error: \"FTP not enabled\" }, obj.callback);\n\t\t\treturn;\n\t\t}\n\t\tconst client = this.createFtpClient();\n\t\ttry {\n\t\t\tawait this.ftpConnect(client);\n\t\t\tconst remotePath = this.config.ftpPath || \"/\";\n\t\t\tconst list = await client.list(remotePath);\n\t\t\tconst files = list\n\t\t\t\t.filter(item => {\n\t\t\t\t\tconst n = item.name;\n\t\t\t\t\treturn (\n\t\t\t\t\t\titem.type === ftp.FileType.File &&\n\t\t\t\t\t\t(n.startsWith(\"iobroker\") || n.startsWith(\"javascript\")) &&\n\t\t\t\t\t\t(n.endsWith(\".tar.gz\") || n.endsWith(\".tar\") || n.endsWith(\".json\") || n.endsWith(\".jsonl\"))\n\t\t\t\t\t);\n\t\t\t\t})\n\t\t\t\t.map(item => item.name)\n\t\t\t\t.sort()\n\t\t\t\t.reverse();\n\t\t\tthis.sendTo(obj.from, obj.command, { files, path: remotePath }, obj.callback);\n\t\t} catch (e) {\n\t\t\tthis.sendTo(obj.from, obj.command, { error: (e as Error).message }, obj.callback);\n\t\t} finally {\n\t\t\tclient.close();\n\t\t}\n\t}\n\n\tprivate async handleParseFtpFile(obj: ioBroker.Message): Promise<void> {\n\t\tif (!this.config.ftpEnabled) {\n\t\t\tthis.sendTo(obj.from, obj.command, { error: \"FTP not enabled\" }, obj.callback);\n\t\t\treturn;\n\t\t}\n\t\tconst msg = obj.message as { filename: string };\n\t\tconst filename = path.basename(msg.filename);\n\t\tconst remotePath = path.posix.join(this.config.ftpPath || \"/\", filename);\n\t\tconst client = this.createFtpClient();\n\t\ttry {\n\t\t\tawait this.ftpConnect(client);\n\t\t\tconst chunks: Buffer[] = [];\n\t\t\tconst writable = new Writable({\n\t\t\t\twrite(chunk, _enc, cb) {\n\t\t\t\t\tchunks.push(Buffer.isBuffer(chunk) ? chunk : Buffer.from(chunk as string));\n\t\t\t\t\tcb();\n\t\t\t\t},\n\t\t\t});\n\t\t\tawait client.downloadTo(writable, remotePath);\n\t\t\tconst buf = Buffer.concat(chunks);\n\t\t\tconst scripts = await this.parseBuffer(buf, filename);\n\t\t\tthis.sendTo(obj.from, obj.command, { scripts }, obj.callback);\n\t\t} catch (e) {\n\t\t\tthis.sendTo(obj.from, obj.command, { error: (e as Error).message }, obj.callback);\n\t\t} finally {\n\t\t\tclient.close();\n\t\t}\n\t}\n\n\t// \u2500\u2500\u2500 SMB \u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\n\n\tprivate createSmbClient(): typeof SMB2 {\n\t\treturn new SMB2({\n\t\t\tshare: `\\\\\\\\${this.config.smbHost}\\\\${this.config.smbShare}`,\n\t\t\tusername: this.config.smbUser || \"\",\n\t\t\tpassword: this.config.smbPassword || \"\",\n\t\t\tdomain: this.config.smbDomain || \"\",\n\t\t});\n\t}\n\n\tprivate smbReaddir(smb: typeof SMB2, dirPath: string): Promise<string[]> {\n\t\treturn new Promise((resolve, reject) => {\n\t\t\tsmb.readdir(dirPath, (err: Error | null, files: string[]) => {\n\t\t\t\tif (err) {\n\t\t\t\t\treject(err);\n\t\t\t\t} else {\n\t\t\t\t\tresolve(files);\n\t\t\t\t}\n\t\t\t});\n\t\t});\n\t}\n\n\tprivate smbReadFile(smb: typeof SMB2, filePath: string): Promise<Buffer> {\n\t\treturn new Promise((resolve, reject) => {\n\t\t\tsmb.readFile(filePath, (err: Error | null, data: Buffer) => {\n\t\t\t\tif (err) {\n\t\t\t\t\treject(err);\n\t\t\t\t} else {\n\t\t\t\t\tresolve(data);\n\t\t\t\t}\n\t\t\t});\n\t\t});\n\t}\n\n\tprivate async handleListSmbFiles(obj: ioBroker.Message): Promise<void> {\n\t\tif (!this.config.smbEnabled) {\n\t\t\tthis.sendTo(obj.from, obj.command, { error: \"SMB not enabled\" }, obj.callback);\n\t\t\treturn;\n\t\t}\n\t\tconst smb = this.createSmbClient();\n\t\ttry {\n\t\t\tconst smbPath = this.config.smbPath || \"\";\n\t\t\tconst entries = await this.smbReaddir(smb, smbPath);\n\t\t\tconst files = entries\n\t\t\t\t.filter(n => {\n\t\t\t\t\treturn (\n\t\t\t\t\t\t(n.startsWith(\"iobroker\") || n.startsWith(\"javascript\")) &&\n\t\t\t\t\t\t(n.endsWith(\".tar.gz\") || n.endsWith(\".tar\") || n.endsWith(\".json\") || n.endsWith(\".jsonl\"))\n\t\t\t\t\t);\n\t\t\t\t})\n\t\t\t\t.sort()\n\t\t\t\t.reverse();\n\t\t\tthis.sendTo(obj.from, obj.command, { files, path: smbPath }, obj.callback);\n\t\t} catch (e) {\n\t\t\tthis.sendTo(obj.from, obj.command, { error: (e as Error).message }, obj.callback);\n\t\t} finally {\n\t\t\tsmb.disconnect();\n\t\t}\n\t}\n\n\tprivate async handleParseSmbFile(obj: ioBroker.Message): Promise<void> {\n\t\tif (!this.config.smbEnabled) {\n\t\t\tthis.sendTo(obj.from, obj.command, { error: \"SMB not enabled\" }, obj.callback);\n\t\t\treturn;\n\t\t}\n\t\tconst msg = obj.message as { filename: string };\n\t\tconst filename = path.basename(msg.filename);\n\t\tconst smbPath = this.config.smbPath || \"\";\n\t\tconst filePath = smbPath ? `${smbPath}\\\\${filename}` : filename;\n\t\tconst smb = this.createSmbClient();\n\t\ttry {\n\t\t\tconst buf = await this.smbReadFile(smb, filePath);\n\t\t\tconst scripts = await this.parseBuffer(buf, filename);\n\t\t\tthis.sendTo(obj.from, obj.command, { scripts }, obj.callback);\n\t\t} catch (e) {\n\t\t\tthis.sendTo(obj.from, obj.command, { error: (e as Error).message }, obj.callback);\n\t\t} finally {\n\t\t\tsmb.disconnect();\n\t\t}\n\t}\n\n\t// \u2500\u2500\u2500 Parsing \u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\n\n\tprivate async parseBuffer(buf: Buffer, filename: string): Promise<ScriptEntry[]> {\n\t\tconst name = filename.toLowerCase();\n\t\tif (name.endsWith(\".tar.gz\") || name.endsWith(\".tgz\") || name.endsWith(\".tar\")) {\n\t\t\treturn this.parseTarArchive(buf, name.endsWith(\".tar\") && !name.endsWith(\".tar.gz\"));\n\t\t}\n\t\treturn this.parseJsonContent(buf.toString(\"utf8\"), filename);\n\t}\n\n\tprivate async parseTarArchive(buf: Buffer, isPlainTar: boolean): Promise<ScriptEntry[]> {\n\t\tconst tmpDir = await fs.mkdtemp(path.join(os.tmpdir(), \"script-restore-\"));\n\t\tconst tmpFile = path.join(tmpDir, `archive.tar${isPlainTar ? \"\" : \".gz\"}`);\n\t\ttry {\n\t\t\tawait fs.writeFile(tmpFile, buf);\n\n\t\t\tconst extractFlag = isPlainTar ? \"-xf\" : \"-xzf\";\n\t\t\ttry {\n\t\t\t\tawait execAsync(\n\t\t\t\t\t`tar ${extractFlag} \"${tmpFile}\" -C \"${tmpDir}\" --wildcards` +\n\t\t\t\t\t\t` \"*/objects.jsonl\" \"*/objects.json\" \"*/scripts.json\" \"*/script.json\"` +\n\t\t\t\t\t\t` 2>/dev/null`,\n\t\t\t\t);\n\t\t\t} catch {\n\t\t\t\tawait execAsync(`tar ${extractFlag} \"${tmpFile}\" -C \"${tmpDir}\" 2>/dev/null`).catch(() => {});\n\t\t\t}\n\n\t\t\tconst targets = [\"objects.jsonl\", \"objects.json\", \"scripts.json\", \"script.json\"];\n\t\t\tconst found = await this.findFile(tmpDir, targets);\n\t\t\tif (!found) {\n\t\t\t\tthrow new Error(\n\t\t\t\t\t\"Keine passende Datei im Archiv gefunden (objects.json, objects.jsonl, scripts.json, script.json)\",\n\t\t\t\t);\n\t\t\t}\n\n\t\t\tconst content = await fs.readFile(found, \"utf8\");\n\t\t\treturn this.parseJsonContent(content, path.basename(found));\n\t\t} finally {\n\t\t\tawait fs.rm(tmpDir, { recursive: true, force: true }).catch(() => {});\n\t\t}\n\t}\n\n\tprivate async findFile(dir: string, names: string[]): Promise<string | null> {\n\t\tconst walk = async (d: string): Promise<string | null> => {\n\t\t\tlet entries: Dirent[];\n\t\t\ttry {\n\t\t\t\tentries = (await fs.readdir(d, { withFileTypes: true, encoding: \"utf8\" })) as unknown as Dirent[];\n\t\t\t} catch {\n\t\t\t\treturn null;\n\t\t\t}\n\t\t\tfor (const e of entries) {\n\t\t\t\tconst p = path.join(d, String(e.name));\n\t\t\t\tif (e.isDirectory()) {\n\t\t\t\t\tconst found = await walk(p);\n\t\t\t\t\tif (found) {\n\t\t\t\t\t\treturn found;\n\t\t\t\t\t}\n\t\t\t\t} else if (names.includes(String(e.name))) {\n\t\t\t\t\treturn p;\n\t\t\t\t}\n\t\t\t}\n\t\t\treturn null;\n\t\t};\n\t\treturn walk(dir);\n\t}\n\n\tprivate parseJsonContent(content: string, filename: string): ScriptEntry[] {\n\t\tconst scripts: ScriptEntry[] = [];\n\t\tconst trimmed = content.trimStart();\n\n\t\tconst isJsonl =\n\t\t\tfilename.endsWith(\".jsonl\") ||\n\t\t\t(trimmed.startsWith(\"{\") && !trimmed.startsWith('{\\n \"') && trimmed.includes(\"\\n{\"));\n\n\t\tif (isJsonl) {\n\t\t\tfor (const line of content.split(\"\\n\")) {\n\t\t\t\tconst l = line.trim();\n\t\t\t\tif (!l) {\n\t\t\t\t\tcontinue;\n\t\t\t\t}\n\t\t\t\ttry {\n\t\t\t\t\tconst item = JSON.parse(l) as Record<string, unknown>;\n\t\t\t\t\tthis.processItem(\n\t\t\t\t\t\t(item._id || item.id) as string,\n\t\t\t\t\t\t(item.value || item.doc || item) as Record<string, unknown>,\n\t\t\t\t\t\tscripts,\n\t\t\t\t\t);\n\t\t\t\t} catch {\n\t\t\t\t\t// skip invalid lines\n\t\t\t\t}\n\t\t\t}\n\t\t} else {\n\t\t\tconst data = JSON.parse(content) as Record<string, unknown>;\n\t\t\tfor (const [k, v] of Object.entries(data)) {\n\t\t\t\tthis.processItem(k, v as Record<string, unknown>, scripts);\n\t\t\t}\n\t\t}\n\n\t\treturn scripts.sort((a, b) => a.name.toLowerCase().localeCompare(b.name.toLowerCase()));\n\t}\n\n\tprivate processItem(key: string, val: unknown, scripts: ScriptEntry[]): void {\n\t\tif (!key || typeof val !== \"object\" || val === null) {\n\t\t\treturn;\n\t\t}\n\t\tconst v = val as Record<string, unknown>;\n\n\t\tif ([\"channel\", \"device\", \"folder\", \"meta\"].includes(v.type as string)) {\n\t\t\treturn;\n\t\t}\n\t\tif (v.type !== \"script\" && !key.startsWith(\"script.js.\")) {\n\t\t\treturn;\n\t\t}\n\n\t\tconst c = v.common as Record<string, unknown> | undefined;\n\t\tif (!c || (c.engineType === undefined && c.source === undefined)) {\n\t\t\treturn;\n\t\t}\n\n\t\tconst rawEngineType = typeof c.engineType === \"string\" ? c.engineType : \"JS\";\n\t\tconst engineType = rawEngineType.toLowerCase();\n\t\tlet stype: string;\n\t\tif (engineType.includes(\"ts\") || engineType.includes(\"typescript\")) {\n\t\t\tstype = \"TypeScript\";\n\t\t} else if (engineType.includes(\"blockly\")) {\n\t\t\tstype = \"Blockly\";\n\t\t} else if (engineType.includes(\"rules\")) {\n\t\t\tstype = \"Rules\";\n\t\t} else {\n\t\t\tstype = \"JS\";\n\t\t}\n\n\t\tlet name: string;\n\t\tconst nameObj = c.name;\n\t\tif (typeof nameObj === \"object\" && nameObj !== null) {\n\t\t\tconst n = nameObj as Record<string, string>;\n\t\t\tname = n.de || n.en || Object.values(n)[0] || key.split(\".\").pop() || key;\n\t\t} else {\n\t\t\tname = typeof nameObj === \"string\" && nameObj ? nameObj : (key.split(\".\").pop() ?? key);\n\t\t}\n\n\t\tconst scriptPath = key.startsWith(\"script.js.\") ? key.slice(10) : key;\n\n\t\tscripts.push({\n\t\t\tname,\n\t\t\tpath: scriptPath,\n\t\t\ttype: stype,\n\t\t\tsource: typeof c.source === \"string\" ? c.source : \"\",\n\t\t});\n\t}\n\n\t// \u2500\u2500\u2500 Suggest backup path \u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\n\n\tprivate async handleSuggestBackupPath(obj: ioBroker.Message): Promise<void> {\n\t\tconst candidates = [\"/opt/iobroker/backups\", \"/root/backups\"];\n\t\t// Check if backupPC or iobroker-backup adapter is configured\n\t\ttry {\n\t\t\tconst backupObj = (await this.getForeignObjectAsync(\"system.adapter.backitup.0\")) as ioBroker.Object | null;\n\t\t\tif (backupObj?.native?.defaultFolder) {\n\t\t\t\tcandidates.unshift(backupObj.native.defaultFolder as string);\n\t\t\t}\n\t\t} catch {\n\t\t\t// adapter not installed\n\t\t}\n\t\tfor (const p of candidates) {\n\t\t\ttry {\n\t\t\t\tawait fs.access(p);\n\t\t\t\tthis.sendTo(obj.from, obj.command, { path: p }, obj.callback);\n\t\t\t\treturn;\n\t\t\t} catch {\n\t\t\t\t// not accessible\n\t\t\t}\n\t\t}\n\t\tthis.sendTo(obj.from, obj.command, { path: null }, obj.callback);\n\t}\n\n\t// \u2500\u2500\u2500 HTTP \u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\n\n\tprivate downloadUrl(urlRaw: string): Promise<Buffer> {\n\t\tconst url = urlRaw.startsWith(\"http://\") || urlRaw.startsWith(\"https://\") ? urlRaw : `https://${urlRaw}`;\n\t\treturn new Promise((resolve, reject) => {\n\t\t\tconst mod = url.startsWith(\"https\") ? https : http;\n\t\t\tmod.get(url, res => {\n\t\t\t\tif (res.statusCode !== 200) {\n\t\t\t\t\treject(new Error(`HTTP ${res.statusCode}`));\n\t\t\t\t\treturn;\n\t\t\t\t}\n\t\t\t\tconst chunks: Buffer[] = [];\n\t\t\t\tres.on(\"data\", (c: Buffer) => chunks.push(c));\n\t\t\t\tres.on(\"end\", () => resolve(Buffer.concat(chunks)));\n\t\t\t\tres.on(\"error\", reject);\n\t\t\t}).on(\"error\", reject);\n\t\t});\n\t}\n\n\tprivate async handleParseHttpUrl(obj: ioBroker.Message): Promise<void> {\n\t\tif (!this.config.httpEnabled) {\n\t\t\tthis.sendTo(obj.from, obj.command, { error: \"HTTP not enabled\" }, obj.callback);\n\t\t\treturn;\n\t\t}\n\t\tconst msg = obj.message as { url: string };\n\t\tconst filename = msg.url.split(\"/\").pop() || \"backup\";\n\t\ttry {\n\t\t\tconst buf = await this.downloadUrl(msg.url);\n\t\t\tconst scripts = await this.parseBuffer(buf, filename);\n\t\t\tthis.sendTo(obj.from, obj.command, { scripts }, obj.callback);\n\t\t} catch (e) {\n\t\t\tthis.sendTo(obj.from, obj.command, { error: (e as Error).message }, obj.callback);\n\t\t}\n\t}\n\n\t// \u2500\u2500\u2500 SFTP \u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\n\n\tprivate async handleTestSftp(obj: ioBroker.Message): Promise<void> {\n\t\tconst msg = obj.message as { host: string; port: number; user: string; password: string; path: string };\n\t\tconst sftp = new SftpClient();\n\t\ttry {\n\t\t\tawait sftp.connect({ host: msg.host, port: msg.port || 22, username: msg.user, password: msg.password });\n\t\t\tconst list = await sftp.list(msg.path || \"/\");\n\t\t\tconst count = list.filter(i => i.type === \"-\").length;\n\t\t\tthis.sendTo(\n\t\t\t\tobj.from,\n\t\t\t\tobj.command,\n\t\t\t\t{ success: true, message: `Verbunden! ${count} Datei(en) in: ${msg.path || \"/\"}` },\n\t\t\t\tobj.callback,\n\t\t\t);\n\t\t} catch (e) {\n\t\t\tthis.sendTo(obj.from, obj.command, { success: false, message: (e as Error).message }, obj.callback);\n\t\t} finally {\n\t\t\tawait sftp.end();\n\t\t}\n\t}\n\n\tprivate async handleListSftpFiles(obj: ioBroker.Message): Promise<void> {\n\t\tif (!this.config.sftpEnabled) {\n\t\t\tthis.sendTo(obj.from, obj.command, { error: \"SFTP not enabled\" }, obj.callback);\n\t\t\treturn;\n\t\t}\n\t\tconst sftp = new SftpClient();\n\t\ttry {\n\t\t\tawait sftp.connect({\n\t\t\t\thost: this.config.sftpHost,\n\t\t\t\tport: this.config.sftpPort || 22,\n\t\t\t\tusername: this.config.sftpUser,\n\t\t\t\tpassword: this.config.sftpPassword,\n\t\t\t});\n\t\t\tconst remotePath = this.config.sftpPath || \"/\";\n\t\t\tconst list = await sftp.list(remotePath);\n\t\t\tconst files = list\n\t\t\t\t.filter(i => {\n\t\t\t\t\tconst n = i.name;\n\t\t\t\t\treturn (\n\t\t\t\t\t\ti.type === \"-\" &&\n\t\t\t\t\t\t(n.startsWith(\"iobroker\") || n.startsWith(\"javascript\")) &&\n\t\t\t\t\t\t(n.endsWith(\".tar.gz\") || n.endsWith(\".tar\") || n.endsWith(\".json\") || n.endsWith(\".jsonl\"))\n\t\t\t\t\t);\n\t\t\t\t})\n\t\t\t\t.map(i => i.name)\n\t\t\t\t.sort()\n\t\t\t\t.reverse();\n\t\t\tthis.sendTo(obj.from, obj.command, { files, path: remotePath }, obj.callback);\n\t\t} catch (e) {\n\t\t\tthis.sendTo(obj.from, obj.command, { error: (e as Error).message }, obj.callback);\n\t\t} finally {\n\t\t\tawait sftp.end();\n\t\t}\n\t}\n\n\tprivate async handleParseSftpFile(obj: ioBroker.Message): Promise<void> {\n\t\tif (!this.config.sftpEnabled) {\n\t\t\tthis.sendTo(obj.from, obj.command, { error: \"SFTP not enabled\" }, obj.callback);\n\t\t\treturn;\n\t\t}\n\t\tconst msg = obj.message as { filename: string };\n\t\tconst filename = path.basename(msg.filename);\n\t\tconst remotePath = path.posix.join(this.config.sftpPath || \"/\", filename);\n\t\tconst sftp = new SftpClient();\n\t\ttry {\n\t\t\tawait sftp.connect({\n\t\t\t\thost: this.config.sftpHost,\n\t\t\t\tport: this.config.sftpPort || 22,\n\t\t\t\tusername: this.config.sftpUser,\n\t\t\t\tpassword: this.config.sftpPassword,\n\t\t\t});\n\t\t\tconst buf = (await sftp.get(remotePath)) as Buffer;\n\t\t\tconst scripts = await this.parseBuffer(buf, filename);\n\t\t\tthis.sendTo(obj.from, obj.command, { scripts }, obj.callback);\n\t\t} catch (e) {\n\t\t\tthis.sendTo(obj.from, obj.command, { error: (e as Error).message }, obj.callback);\n\t\t} finally {\n\t\t\tawait sftp.end();\n\t\t}\n\t}\n\n\t// \u2500\u2500\u2500 WebDAV \u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\n\n\tprivate async handleTestWebdav(obj: ioBroker.Message): Promise<void> {\n\t\tconst msg = obj.message as { url: string; user: string; password: string; path: string };\n\t\ttry {\n\t\t\tconst { createClient: createWebdavClient } = await import(\"webdav\");\n\t\t\tconst client = createWebdavClient(msg.url, { username: msg.user, password: msg.password });\n\t\t\tconst list = await client.getDirectoryContents(msg.path || \"/\");\n\t\t\tconst arr = Array.isArray(list) ? list : (list as { data: unknown[] }).data;\n\t\t\tthis.sendTo(\n\t\t\t\tobj.from,\n\t\t\t\tobj.command,\n\t\t\t\t{ success: true, message: `Verbunden! ${arr.length} Eintr\u00E4ge in: ${msg.path || \"/\"}` },\n\t\t\t\tobj.callback,\n\t\t\t);\n\t\t} catch (e) {\n\t\t\tthis.sendTo(obj.from, obj.command, { success: false, message: (e as Error).message }, obj.callback);\n\t\t}\n\t}\n\n\tprivate async handleListWebdavFiles(obj: ioBroker.Message): Promise<void> {\n\t\tif (!this.config.webdavEnabled) {\n\t\t\tthis.sendTo(obj.from, obj.command, { error: \"WebDAV not enabled\" }, obj.callback);\n\t\t\treturn;\n\t\t}\n\t\ttry {\n\t\t\tconst { createClient: createWebdavClient } = await import(\"webdav\");\n\t\t\tconst client = createWebdavClient(this.config.webdavUrl, {\n\t\t\t\tusername: this.config.webdavUser,\n\t\t\t\tpassword: this.config.webdavPassword,\n\t\t\t});\n\t\t\tconst remotePath = this.config.webdavPath || \"/\";\n\t\t\tconst list = await client.getDirectoryContents(remotePath);\n\t\t\tconst arr = Array.isArray(list) ? list : (list as { data: { basename: string; type: string }[] }).data;\n\t\t\tconst files = arr\n\t\t\t\t.filter((i: { basename: string; type: string }) => {\n\t\t\t\t\tconst n = i.basename;\n\t\t\t\t\treturn (\n\t\t\t\t\t\ti.type === \"file\" &&\n\t\t\t\t\t\t(n.startsWith(\"iobroker\") || n.startsWith(\"javascript\")) &&\n\t\t\t\t\t\t(n.endsWith(\".tar.gz\") || n.endsWith(\".tar\") || n.endsWith(\".json\") || n.endsWith(\".jsonl\"))\n\t\t\t\t\t);\n\t\t\t\t})\n\t\t\t\t.map((i: { basename: string }) => i.basename)\n\t\t\t\t.sort()\n\t\t\t\t.reverse();\n\t\t\tthis.sendTo(obj.from, obj.command, { files, path: remotePath }, obj.callback);\n\t\t} catch (e) {\n\t\t\tthis.sendTo(obj.from, obj.command, { error: (e as Error).message }, obj.callback);\n\t\t}\n\t}\n\n\tprivate async handleParseWebdavFile(obj: ioBroker.Message): Promise<void> {\n\t\tif (!this.config.webdavEnabled) {\n\t\t\tthis.sendTo(obj.from, obj.command, { error: \"WebDAV not enabled\" }, obj.callback);\n\t\t\treturn;\n\t\t}\n\t\tconst msg = obj.message as { filename: string };\n\t\tconst filename = path.basename(msg.filename);\n\t\ttry {\n\t\t\tconst { createClient: createWebdavClient } = await import(\"webdav\");\n\t\t\tconst client = createWebdavClient(this.config.webdavUrl, {\n\t\t\t\tusername: this.config.webdavUser,\n\t\t\t\tpassword: this.config.webdavPassword,\n\t\t\t});\n\t\t\tconst remotePath = (this.config.webdavPath ? `${this.config.webdavPath}/` : \"/\") + filename;\n\t\t\tconst buf = Buffer.from((await client.getFileContents(remotePath)) as ArrayBuffer);\n\t\t\tconst scripts = await this.parseBuffer(buf, filename);\n\t\t\tthis.sendTo(obj.from, obj.command, { scripts }, obj.callback);\n\t\t} catch (e) {\n\t\t\tthis.sendTo(obj.from, obj.command, { error: (e as Error).message }, obj.callback);\n\t\t}\n\t}\n}\n\nif (require.main !== module) {\n\tmodule.exports = (options: Partial<utils.AdapterOptions> | undefined) => new ScriptRestore(options);\n} else {\n\t(() => new ScriptRestore())();\n}\n"],
5
- "mappings": "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",
4
+ "sourcesContent": ["/*\n * ioBroker Script Restore Adapter\n * Restore ioBroker scripts from backup archives\n * Copyright (c) 2024 ipod86 <david@graef.email>\n * MIT License\n */\n\nimport type { Dirent } from \"node:fs\";\nimport * as utils from \"@iobroker/adapter-core\";\nimport * as fs from \"node:fs/promises\";\nimport * as path from \"node:path\";\nimport * as os from \"node:os\";\nimport { exec } from \"node:child_process\";\nimport { promisify } from \"node:util\";\nimport * as ftp from \"basic-ftp\";\nimport { Writable } from \"node:stream\";\nimport * as https from \"node:https\";\nimport * as http from \"node:http\";\nimport SftpClient from \"ssh2-sftp-client\";\n\n// eslint-disable-next-line @typescript-eslint/no-require-imports\nconst SMB2 = require(\"@marsaud/smb2\");\n\nconst execAsync = promisify(exec);\n\ninterface ScriptEntry {\n\tname: string;\n\tpath: string;\n\ttype: string;\n\tsource: string;\n}\n\nclass ScriptRestore extends utils.Adapter {\n\tpublic constructor(options: Partial<utils.AdapterOptions> = {}) {\n\t\tsuper({\n\t\t\t...options,\n\t\t\tname: \"script-restore\",\n\t\t});\n\t\tthis.on(\"ready\", this.onReady.bind(this));\n\t\tthis.on(\"message\", this.onMessage.bind(this));\n\t\tthis.on(\"unload\", this.onUnload.bind(this));\n\t}\n\n\tprivate onReady(): void {\n\t\tthis.log.info(`Script Restore ready. Backup path: ${this.config.backupPath || \"/opt/iobroker/backups\"}`);\n\t}\n\n\tprivate onUnload(callback: () => void): void {\n\t\tcallback();\n\t}\n\n\tprivate async onMessage(obj: ioBroker.Message): Promise<void> {\n\t\tif (!obj.callback) {\n\t\t\treturn;\n\t\t}\n\n\t\ttry {\n\t\t\tswitch (obj.command) {\n\t\t\t\tcase \"listLocalFiles\":\n\t\t\t\t\tawait this.handleListLocalFiles(obj);\n\t\t\t\t\tbreak;\n\t\t\t\tcase \"parseLocalFile\":\n\t\t\t\t\tawait this.handleParseLocalFile(obj);\n\t\t\t\t\tbreak;\n\t\t\t\tcase \"parseUploadedFile\":\n\t\t\t\t\tawait this.handleParseUploadedFile(obj);\n\t\t\t\t\tbreak;\n\t\t\t\tcase \"getSourceConfig\":\n\t\t\t\t\tthis.sendTo(\n\t\t\t\t\t\tobj.from,\n\t\t\t\t\t\tobj.command,\n\t\t\t\t\t\t{\n\t\t\t\t\t\t\tlocalEnabled: this.config.localEnabled !== false,\n\t\t\t\t\t\t\tftpEnabled: !!this.config.ftpEnabled,\n\t\t\t\t\t\t\tsmbEnabled: !!this.config.smbEnabled,\n\t\t\t\t\t\t\thttpEnabled: !!this.config.httpEnabled,\n\t\t\t\t\t\t\tsftpEnabled: !!this.config.sftpEnabled,\n\t\t\t\t\t\t\twebdavEnabled: !!this.config.webdavEnabled,\n\t\t\t\t\t\t},\n\t\t\t\t\t\tobj.callback,\n\t\t\t\t\t);\n\t\t\t\t\tbreak;\n\t\t\t\tcase \"suggestBackupPath\":\n\t\t\t\t\tawait this.handleSuggestBackupPath(obj);\n\t\t\t\t\tbreak;\n\t\t\t\tcase \"parseHttpUrl\":\n\t\t\t\t\tawait this.handleParseHttpUrl(obj);\n\t\t\t\t\tbreak;\n\t\t\t\tcase \"testSftp\":\n\t\t\t\t\tawait this.handleTestSftp(obj);\n\t\t\t\t\tbreak;\n\t\t\t\tcase \"listSftpFiles\":\n\t\t\t\t\tawait this.handleListSftpFiles(obj);\n\t\t\t\t\tbreak;\n\t\t\t\tcase \"parseSftpFile\":\n\t\t\t\t\tawait this.handleParseSftpFile(obj);\n\t\t\t\t\tbreak;\n\t\t\t\tcase \"testWebdav\":\n\t\t\t\t\tawait this.handleTestWebdav(obj);\n\t\t\t\t\tbreak;\n\t\t\t\tcase \"listWebdavFiles\":\n\t\t\t\t\tawait this.handleListWebdavFiles(obj);\n\t\t\t\t\tbreak;\n\t\t\t\tcase \"parseWebdavFile\":\n\t\t\t\t\tawait this.handleParseWebdavFile(obj);\n\t\t\t\t\tbreak;\n\t\t\t\tcase \"testFtp\":\n\t\t\t\t\tawait this.handleTestFtp(obj);\n\t\t\t\t\tbreak;\n\t\t\t\tcase \"testSmb\":\n\t\t\t\t\tawait this.handleTestSmb(obj);\n\t\t\t\t\tbreak;\n\t\t\t\tcase \"listFtpFiles\":\n\t\t\t\t\tawait this.handleListFtpFiles(obj);\n\t\t\t\t\tbreak;\n\t\t\t\tcase \"parseFtpFile\":\n\t\t\t\t\tawait this.handleParseFtpFile(obj);\n\t\t\t\t\tbreak;\n\t\t\t\tcase \"listSmbFiles\":\n\t\t\t\t\tawait this.handleListSmbFiles(obj);\n\t\t\t\t\tbreak;\n\t\t\t\tcase \"parseSmbFile\":\n\t\t\t\t\tawait this.handleParseSmbFile(obj);\n\t\t\t\t\tbreak;\n\t\t\t\tdefault:\n\t\t\t\t\tthis.sendTo(obj.from, obj.command, { error: \"Unknown command\" }, obj.callback);\n\t\t\t}\n\t\t} catch (e) {\n\t\t\tthis.log.error(`Error handling ${obj.command}: ${(e as Error).message}`);\n\t\t\tthis.sendTo(obj.from, obj.command, { error: (e as Error).message }, obj.callback);\n\t\t}\n\t}\n\n\t// \u2500\u2500\u2500 Local \u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\n\n\tprivate async handleListLocalFiles(obj: ioBroker.Message): Promise<void> {\n\t\tif (this.config.localEnabled === false) {\n\t\t\tthis.sendTo(obj.from, obj.command, { error: \"Local source not enabled\" }, obj.callback);\n\t\t\treturn;\n\t\t}\n\t\tconst backupPath = this.config.backupPath || \"/opt/iobroker/backups\";\n\t\ttry {\n\t\t\tconst rawEntries = await fs.readdir(backupPath, { withFileTypes: true, encoding: \"utf8\" });\n\t\t\tconst entries = rawEntries as unknown as Dirent[];\n\t\t\tconst files = entries\n\t\t\t\t.filter(e => {\n\t\t\t\t\tconst n = String(e.name);\n\t\t\t\t\treturn (\n\t\t\t\t\t\te.isFile() &&\n\t\t\t\t\t\t(n.startsWith(\"iobroker\") || n.startsWith(\"javascript\")) &&\n\t\t\t\t\t\t(n.endsWith(\".tar.gz\") || n.endsWith(\".tar\") || n.endsWith(\".json\") || n.endsWith(\".jsonl\"))\n\t\t\t\t\t);\n\t\t\t\t})\n\t\t\t\t.map(e => String(e.name))\n\t\t\t\t.sort()\n\t\t\t\t.reverse();\n\t\t\tthis.sendTo(obj.from, obj.command, { files, path: backupPath }, obj.callback);\n\t\t} catch (e) {\n\t\t\tthis.sendTo(\n\t\t\t\tobj.from,\n\t\t\t\tobj.command,\n\t\t\t\t{ error: `Verzeichnis nicht lesbar: ${(e as Error).message}` },\n\t\t\t\tobj.callback,\n\t\t\t);\n\t\t}\n\t}\n\n\tprivate async handleParseLocalFile(obj: ioBroker.Message): Promise<void> {\n\t\tif (this.config.localEnabled === false) {\n\t\t\tthis.sendTo(obj.from, obj.command, { error: \"Local source not enabled\" }, obj.callback);\n\t\t\treturn;\n\t\t}\n\t\tconst backupPath = this.config.backupPath || \"/opt/iobroker/backups\";\n\t\tconst msg = obj.message as { filename: string };\n\t\tconst filename = path.basename(msg.filename);\n\t\tconst filepath = path.join(backupPath, filename);\n\t\ttry {\n\t\t\tconst buf = await fs.readFile(filepath);\n\t\t\tconst scripts = await this.parseBuffer(buf, filename);\n\t\t\tthis.sendTo(obj.from, obj.command, { scripts }, obj.callback);\n\t\t} catch (e) {\n\t\t\tthis.sendTo(obj.from, obj.command, { error: (e as Error).message }, obj.callback);\n\t\t}\n\t}\n\n\tprivate async handleParseUploadedFile(obj: ioBroker.Message): Promise<void> {\n\t\tconst msg = obj.message as { name: string; data: string };\n\t\ttry {\n\t\t\tconst buf = Buffer.from(msg.data, \"base64\");\n\t\t\tconst scripts = await this.parseBuffer(buf, msg.name);\n\t\t\tthis.sendTo(obj.from, obj.command, { scripts }, obj.callback);\n\t\t} catch (e) {\n\t\t\tthis.sendTo(obj.from, obj.command, { error: (e as Error).message }, obj.callback);\n\t\t}\n\t}\n\n\t// \u2500\u2500\u2500 Tests \u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\n\n\tprivate async handleTestFtp(obj: ioBroker.Message): Promise<void> {\n\t\tconst client = new ftp.Client();\n\t\tclient.ftp.verbose = false;\n\t\ttry {\n\t\t\tawait client.access({\n\t\t\t\thost: this.config.ftpHost,\n\t\t\t\tport: this.config.ftpPort || 21,\n\t\t\t\tuser: this.config.ftpUser || \"anonymous\",\n\t\t\t\tpassword: this.config.ftpPassword || \"\",\n\t\t\t\tsecure: this.config.ftpSecure || false,\n\t\t\t});\n\t\t\tconst list = await client.list(this.config.ftpPath || \"/\");\n\t\t\tconst count = list.filter(i => i.type === ftp.FileType.File).length;\n\t\t\tthis.sendTo(\n\t\t\t\tobj.from,\n\t\t\t\tobj.command,\n\t\t\t\t`\u2713 Verbunden! ${count} Datei(en) in: ${this.config.ftpPath || \"/\"}`,\n\t\t\t\tobj.callback,\n\t\t\t);\n\t\t} catch (e) {\n\t\t\tthis.sendTo(obj.from, obj.command, { error: (e as Error).message }, obj.callback);\n\t\t} finally {\n\t\t\tclient.close();\n\t\t}\n\t}\n\n\tprivate async handleTestSmb(obj: ioBroker.Message): Promise<void> {\n\t\tconst smb = new SMB2({\n\t\t\tshare: `\\\\\\\\${this.config.smbHost}\\\\${this.config.smbShare}`,\n\t\t\tusername: this.config.smbUser || \"\",\n\t\t\tpassword: this.config.smbPassword || \"\",\n\t\t\tdomain: this.config.smbDomain || \"\",\n\t\t});\n\t\ttry {\n\t\t\tconst files = await this.smbReaddir(smb, this.config.smbPath || \"\");\n\t\t\tthis.sendTo(\n\t\t\t\tobj.from,\n\t\t\t\tobj.command,\n\t\t\t\t`\u2713 Verbunden! ${files.length} Eintr\u00E4ge in: \\\\\\\\${this.config.smbHost}\\\\${this.config.smbShare}${this.config.smbPath ? `\\\\${this.config.smbPath}` : \"\"}`,\n\t\t\t\tobj.callback,\n\t\t\t);\n\t\t} catch (e) {\n\t\t\tthis.sendTo(obj.from, obj.command, { error: (e as Error).message }, obj.callback);\n\t\t} finally {\n\t\t\tsmb.disconnect();\n\t\t}\n\t}\n\n\t// \u2500\u2500\u2500 FTP \u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\n\n\tprivate createFtpClient(): ftp.Client {\n\t\tconst client = new ftp.Client();\n\t\tclient.ftp.verbose = false;\n\t\treturn client;\n\t}\n\n\tprivate async ftpConnect(client: ftp.Client): Promise<void> {\n\t\tawait client.access({\n\t\t\thost: this.config.ftpHost,\n\t\t\tport: this.config.ftpPort || 21,\n\t\t\tuser: this.config.ftpUser || \"anonymous\",\n\t\t\tpassword: this.config.ftpPassword || \"\",\n\t\t\tsecure: this.config.ftpSecure || false,\n\t\t});\n\t}\n\n\tprivate async handleListFtpFiles(obj: ioBroker.Message): Promise<void> {\n\t\tif (!this.config.ftpEnabled) {\n\t\t\tthis.sendTo(obj.from, obj.command, { error: \"FTP not enabled\" }, obj.callback);\n\t\t\treturn;\n\t\t}\n\t\tconst client = this.createFtpClient();\n\t\ttry {\n\t\t\tawait this.ftpConnect(client);\n\t\t\tconst remotePath = this.config.ftpPath || \"/\";\n\t\t\tconst list = await client.list(remotePath);\n\t\t\tconst files = list\n\t\t\t\t.filter(item => {\n\t\t\t\t\tconst n = item.name;\n\t\t\t\t\treturn (\n\t\t\t\t\t\titem.type === ftp.FileType.File &&\n\t\t\t\t\t\t(n.startsWith(\"iobroker\") || n.startsWith(\"javascript\")) &&\n\t\t\t\t\t\t(n.endsWith(\".tar.gz\") || n.endsWith(\".tar\") || n.endsWith(\".json\") || n.endsWith(\".jsonl\"))\n\t\t\t\t\t);\n\t\t\t\t})\n\t\t\t\t.map(item => item.name)\n\t\t\t\t.sort()\n\t\t\t\t.reverse();\n\t\t\tthis.sendTo(obj.from, obj.command, { files, path: remotePath }, obj.callback);\n\t\t} catch (e) {\n\t\t\tthis.sendTo(obj.from, obj.command, { error: (e as Error).message }, obj.callback);\n\t\t} finally {\n\t\t\tclient.close();\n\t\t}\n\t}\n\n\tprivate async handleParseFtpFile(obj: ioBroker.Message): Promise<void> {\n\t\tif (!this.config.ftpEnabled) {\n\t\t\tthis.sendTo(obj.from, obj.command, { error: \"FTP not enabled\" }, obj.callback);\n\t\t\treturn;\n\t\t}\n\t\tconst msg = obj.message as { filename: string };\n\t\tconst filename = path.basename(msg.filename);\n\t\tconst remotePath = path.posix.join(this.config.ftpPath || \"/\", filename);\n\t\tconst client = this.createFtpClient();\n\t\ttry {\n\t\t\tawait this.ftpConnect(client);\n\t\t\tconst chunks: Buffer[] = [];\n\t\t\tconst writable = new Writable({\n\t\t\t\twrite(chunk, _enc, cb) {\n\t\t\t\t\tchunks.push(Buffer.isBuffer(chunk) ? chunk : Buffer.from(chunk as string));\n\t\t\t\t\tcb();\n\t\t\t\t},\n\t\t\t});\n\t\t\tawait client.downloadTo(writable, remotePath);\n\t\t\tconst buf = Buffer.concat(chunks);\n\t\t\tconst scripts = await this.parseBuffer(buf, filename);\n\t\t\tthis.sendTo(obj.from, obj.command, { scripts }, obj.callback);\n\t\t} catch (e) {\n\t\t\tthis.sendTo(obj.from, obj.command, { error: (e as Error).message }, obj.callback);\n\t\t} finally {\n\t\t\tclient.close();\n\t\t}\n\t}\n\n\t// \u2500\u2500\u2500 SMB \u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\n\n\tprivate createSmbClient(): typeof SMB2 {\n\t\treturn new SMB2({\n\t\t\tshare: `\\\\\\\\${this.config.smbHost}\\\\${this.config.smbShare}`,\n\t\t\tusername: this.config.smbUser || \"\",\n\t\t\tpassword: this.config.smbPassword || \"\",\n\t\t\tdomain: this.config.smbDomain || \"\",\n\t\t});\n\t}\n\n\tprivate smbReaddir(smb: typeof SMB2, dirPath: string): Promise<string[]> {\n\t\treturn new Promise((resolve, reject) => {\n\t\t\tsmb.readdir(dirPath, (err: Error | null, files: string[]) => {\n\t\t\t\tif (err) {\n\t\t\t\t\treject(err);\n\t\t\t\t} else {\n\t\t\t\t\tresolve(files);\n\t\t\t\t}\n\t\t\t});\n\t\t});\n\t}\n\n\tprivate smbReadFile(smb: typeof SMB2, filePath: string): Promise<Buffer> {\n\t\treturn new Promise((resolve, reject) => {\n\t\t\tsmb.readFile(filePath, (err: Error | null, data: Buffer) => {\n\t\t\t\tif (err) {\n\t\t\t\t\treject(err);\n\t\t\t\t} else {\n\t\t\t\t\tresolve(data);\n\t\t\t\t}\n\t\t\t});\n\t\t});\n\t}\n\n\tprivate async handleListSmbFiles(obj: ioBroker.Message): Promise<void> {\n\t\tif (!this.config.smbEnabled) {\n\t\t\tthis.sendTo(obj.from, obj.command, { error: \"SMB not enabled\" }, obj.callback);\n\t\t\treturn;\n\t\t}\n\t\tconst smb = this.createSmbClient();\n\t\ttry {\n\t\t\tconst smbPath = this.config.smbPath || \"\";\n\t\t\tconst entries = await this.smbReaddir(smb, smbPath);\n\t\t\tconst files = entries\n\t\t\t\t.filter(n => {\n\t\t\t\t\treturn (\n\t\t\t\t\t\t(n.startsWith(\"iobroker\") || n.startsWith(\"javascript\")) &&\n\t\t\t\t\t\t(n.endsWith(\".tar.gz\") || n.endsWith(\".tar\") || n.endsWith(\".json\") || n.endsWith(\".jsonl\"))\n\t\t\t\t\t);\n\t\t\t\t})\n\t\t\t\t.sort()\n\t\t\t\t.reverse();\n\t\t\tthis.sendTo(obj.from, obj.command, { files, path: smbPath }, obj.callback);\n\t\t} catch (e) {\n\t\t\tthis.sendTo(obj.from, obj.command, { error: (e as Error).message }, obj.callback);\n\t\t} finally {\n\t\t\tsmb.disconnect();\n\t\t}\n\t}\n\n\tprivate async handleParseSmbFile(obj: ioBroker.Message): Promise<void> {\n\t\tif (!this.config.smbEnabled) {\n\t\t\tthis.sendTo(obj.from, obj.command, { error: \"SMB not enabled\" }, obj.callback);\n\t\t\treturn;\n\t\t}\n\t\tconst msg = obj.message as { filename: string };\n\t\tconst filename = path.basename(msg.filename);\n\t\tconst smbPath = this.config.smbPath || \"\";\n\t\tconst filePath = smbPath ? `${smbPath}\\\\${filename}` : filename;\n\t\tconst smb = this.createSmbClient();\n\t\ttry {\n\t\t\tconst buf = await this.smbReadFile(smb, filePath);\n\t\t\tconst scripts = await this.parseBuffer(buf, filename);\n\t\t\tthis.sendTo(obj.from, obj.command, { scripts }, obj.callback);\n\t\t} catch (e) {\n\t\t\tthis.sendTo(obj.from, obj.command, { error: (e as Error).message }, obj.callback);\n\t\t} finally {\n\t\t\tsmb.disconnect();\n\t\t}\n\t}\n\n\t// \u2500\u2500\u2500 Parsing \u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\n\n\tprivate async parseBuffer(buf: Buffer, filename: string): Promise<ScriptEntry[]> {\n\t\tconst name = filename.toLowerCase();\n\t\tif (name.endsWith(\".tar.gz\") || name.endsWith(\".tgz\") || name.endsWith(\".tar\")) {\n\t\t\treturn this.parseTarArchive(buf, name.endsWith(\".tar\") && !name.endsWith(\".tar.gz\"));\n\t\t}\n\t\treturn this.parseJsonContent(buf.toString(\"utf8\"), filename);\n\t}\n\n\tprivate async parseTarArchive(buf: Buffer, isPlainTar: boolean): Promise<ScriptEntry[]> {\n\t\tconst tmpDir = await fs.mkdtemp(path.join(os.tmpdir(), \"script-restore-\"));\n\t\tconst tmpFile = path.join(tmpDir, `archive.tar${isPlainTar ? \"\" : \".gz\"}`);\n\t\ttry {\n\t\t\tawait fs.writeFile(tmpFile, buf);\n\n\t\t\tconst extractFlag = isPlainTar ? \"-xf\" : \"-xzf\";\n\t\t\ttry {\n\t\t\t\tawait execAsync(\n\t\t\t\t\t`tar ${extractFlag} \"${tmpFile}\" -C \"${tmpDir}\" --wildcards` +\n\t\t\t\t\t\t` \"*/objects.jsonl\" \"*/objects.json\" \"*/scripts.json\" \"*/script.json\"` +\n\t\t\t\t\t\t` 2>/dev/null`,\n\t\t\t\t);\n\t\t\t} catch {\n\t\t\t\tawait execAsync(`tar ${extractFlag} \"${tmpFile}\" -C \"${tmpDir}\" 2>/dev/null`).catch(() => {});\n\t\t\t}\n\n\t\t\tconst targets = [\"objects.jsonl\", \"objects.json\", \"scripts.json\", \"script.json\"];\n\t\t\tconst found = await this.findFile(tmpDir, targets);\n\t\t\tif (!found) {\n\t\t\t\tthrow new Error(\n\t\t\t\t\t\"Keine passende Datei im Archiv gefunden (objects.json, objects.jsonl, scripts.json, script.json)\",\n\t\t\t\t);\n\t\t\t}\n\n\t\t\tconst content = await fs.readFile(found, \"utf8\");\n\t\t\treturn this.parseJsonContent(content, path.basename(found));\n\t\t} finally {\n\t\t\tawait fs.rm(tmpDir, { recursive: true, force: true }).catch(() => {});\n\t\t}\n\t}\n\n\tprivate async findFile(dir: string, names: string[]): Promise<string | null> {\n\t\tconst walk = async (d: string): Promise<string | null> => {\n\t\t\tlet entries: Dirent[];\n\t\t\ttry {\n\t\t\t\tentries = (await fs.readdir(d, { withFileTypes: true, encoding: \"utf8\" })) as unknown as Dirent[];\n\t\t\t} catch {\n\t\t\t\treturn null;\n\t\t\t}\n\t\t\tfor (const e of entries) {\n\t\t\t\tconst p = path.join(d, String(e.name));\n\t\t\t\tif (e.isDirectory()) {\n\t\t\t\t\tconst found = await walk(p);\n\t\t\t\t\tif (found) {\n\t\t\t\t\t\treturn found;\n\t\t\t\t\t}\n\t\t\t\t} else if (names.includes(String(e.name))) {\n\t\t\t\t\treturn p;\n\t\t\t\t}\n\t\t\t}\n\t\t\treturn null;\n\t\t};\n\t\treturn walk(dir);\n\t}\n\n\tprivate parseJsonContent(content: string, filename: string): ScriptEntry[] {\n\t\tconst scripts: ScriptEntry[] = [];\n\t\tconst trimmed = content.trimStart();\n\n\t\tconst isJsonl =\n\t\t\tfilename.endsWith(\".jsonl\") ||\n\t\t\t(trimmed.startsWith(\"{\") && !trimmed.startsWith('{\\n \"') && trimmed.includes(\"\\n{\"));\n\n\t\tif (isJsonl) {\n\t\t\tfor (const line of content.split(\"\\n\")) {\n\t\t\t\tconst l = line.trim();\n\t\t\t\tif (!l) {\n\t\t\t\t\tcontinue;\n\t\t\t\t}\n\t\t\t\ttry {\n\t\t\t\t\tconst item = JSON.parse(l) as Record<string, unknown>;\n\t\t\t\t\tthis.processItem(\n\t\t\t\t\t\t(item._id || item.id) as string,\n\t\t\t\t\t\t(item.value || item.doc || item) as Record<string, unknown>,\n\t\t\t\t\t\tscripts,\n\t\t\t\t\t);\n\t\t\t\t} catch {\n\t\t\t\t\t// skip invalid lines\n\t\t\t\t}\n\t\t\t}\n\t\t} else {\n\t\t\tconst data = JSON.parse(content) as Record<string, unknown>;\n\t\t\tfor (const [k, v] of Object.entries(data)) {\n\t\t\t\tthis.processItem(k, v as Record<string, unknown>, scripts);\n\t\t\t}\n\t\t}\n\n\t\treturn scripts.sort((a, b) => a.name.toLowerCase().localeCompare(b.name.toLowerCase()));\n\t}\n\n\tprivate processItem(key: string, val: unknown, scripts: ScriptEntry[]): void {\n\t\tif (!key || typeof val !== \"object\" || val === null) {\n\t\t\treturn;\n\t\t}\n\t\tconst v = val as Record<string, unknown>;\n\n\t\tif ([\"channel\", \"device\", \"folder\", \"meta\"].includes(v.type as string)) {\n\t\t\treturn;\n\t\t}\n\t\tif (v.type !== \"script\" && !key.startsWith(\"script.js.\")) {\n\t\t\treturn;\n\t\t}\n\n\t\tconst c = v.common as Record<string, unknown> | undefined;\n\t\tif (!c || (c.engineType === undefined && c.source === undefined)) {\n\t\t\treturn;\n\t\t}\n\n\t\tconst rawEngineType = typeof c.engineType === \"string\" ? c.engineType : \"JS\";\n\t\tconst engineType = rawEngineType.toLowerCase();\n\t\tlet stype: string;\n\t\tif (engineType.includes(\"ts\") || engineType.includes(\"typescript\")) {\n\t\t\tstype = \"TypeScript\";\n\t\t} else if (engineType.includes(\"blockly\")) {\n\t\t\tstype = \"Blockly\";\n\t\t} else if (engineType.includes(\"rules\")) {\n\t\t\tstype = \"Rules\";\n\t\t} else {\n\t\t\tstype = \"JS\";\n\t\t}\n\n\t\tlet name: string;\n\t\tconst nameObj = c.name;\n\t\tif (typeof nameObj === \"object\" && nameObj !== null) {\n\t\t\tconst n = nameObj as Record<string, string>;\n\t\t\tname = n.de || n.en || Object.values(n)[0] || key.split(\".\").pop() || key;\n\t\t} else {\n\t\t\tname = typeof nameObj === \"string\" && nameObj ? nameObj : (key.split(\".\").pop() ?? key);\n\t\t}\n\n\t\tconst scriptPath = key.startsWith(\"script.js.\") ? key.slice(10) : key;\n\n\t\tscripts.push({\n\t\t\tname,\n\t\t\tpath: scriptPath,\n\t\t\ttype: stype,\n\t\t\tsource: typeof c.source === \"string\" ? c.source : \"\",\n\t\t});\n\t}\n\n\t// \u2500\u2500\u2500 Suggest backup path \u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\n\n\tprivate async handleSuggestBackupPath(obj: ioBroker.Message): Promise<void> {\n\t\tconst candidates = [\"/opt/iobroker/backups\", \"/root/backups\"];\n\t\t// Check if backupPC or iobroker-backup adapter is configured\n\t\ttry {\n\t\t\tconst backupObj = (await this.getForeignObjectAsync(\"system.adapter.backitup.0\")) as ioBroker.Object | null;\n\t\t\tif (backupObj?.native?.defaultFolder) {\n\t\t\t\tcandidates.unshift(backupObj.native.defaultFolder as string);\n\t\t\t}\n\t\t} catch {\n\t\t\t// adapter not installed\n\t\t}\n\t\tfor (const p of candidates) {\n\t\t\ttry {\n\t\t\t\tawait fs.access(p);\n\t\t\t\tthis.sendTo(obj.from, obj.command, p, obj.callback);\n\t\t\t\treturn;\n\t\t\t} catch {\n\t\t\t\t// not accessible\n\t\t\t}\n\t\t}\n\t\tthis.sendTo(obj.from, obj.command, \"\", obj.callback);\n\t}\n\n\t// \u2500\u2500\u2500 HTTP \u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\n\n\tprivate downloadUrl(urlRaw: string): Promise<Buffer> {\n\t\tconst url = urlRaw.startsWith(\"http://\") || urlRaw.startsWith(\"https://\") ? urlRaw : `https://${urlRaw}`;\n\t\treturn new Promise((resolve, reject) => {\n\t\t\tconst mod = url.startsWith(\"https\") ? https : http;\n\t\t\tmod.get(url, res => {\n\t\t\t\tif (res.statusCode !== 200) {\n\t\t\t\t\treject(new Error(`HTTP ${res.statusCode}`));\n\t\t\t\t\treturn;\n\t\t\t\t}\n\t\t\t\tconst chunks: Buffer[] = [];\n\t\t\t\tres.on(\"data\", (c: Buffer) => chunks.push(c));\n\t\t\t\tres.on(\"end\", () => resolve(Buffer.concat(chunks)));\n\t\t\t\tres.on(\"error\", reject);\n\t\t\t}).on(\"error\", reject);\n\t\t});\n\t}\n\n\tprivate async handleParseHttpUrl(obj: ioBroker.Message): Promise<void> {\n\t\tif (!this.config.httpEnabled) {\n\t\t\tthis.sendTo(obj.from, obj.command, { error: \"HTTP not enabled\" }, obj.callback);\n\t\t\treturn;\n\t\t}\n\t\tconst msg = obj.message as { url: string };\n\t\tconst filename = msg.url.split(\"/\").pop() || \"backup\";\n\t\ttry {\n\t\t\tconst buf = await this.downloadUrl(msg.url);\n\t\t\tconst scripts = await this.parseBuffer(buf, filename);\n\t\t\tthis.sendTo(obj.from, obj.command, { scripts }, obj.callback);\n\t\t} catch (e) {\n\t\t\tthis.sendTo(obj.from, obj.command, { error: (e as Error).message }, obj.callback);\n\t\t}\n\t}\n\n\t// \u2500\u2500\u2500 SFTP \u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\n\n\tprivate async handleTestSftp(obj: ioBroker.Message): Promise<void> {\n\t\tconst sftp = new SftpClient();\n\t\ttry {\n\t\t\tawait sftp.connect({\n\t\t\t\thost: this.config.sftpHost,\n\t\t\t\tport: this.config.sftpPort || 22,\n\t\t\t\tusername: this.config.sftpUser,\n\t\t\t\tpassword: this.config.sftpPassword,\n\t\t\t});\n\t\t\tconst list = await sftp.list(this.config.sftpPath || \"/\");\n\t\t\tconst count = list.filter(i => i.type === \"-\").length;\n\t\t\tthis.sendTo(\n\t\t\t\tobj.from,\n\t\t\t\tobj.command,\n\t\t\t\t`\u2713 Verbunden! ${count} Datei(en) in: ${this.config.sftpPath || \"/\"}`,\n\t\t\t\tobj.callback,\n\t\t\t);\n\t\t} catch (e) {\n\t\t\tthis.sendTo(obj.from, obj.command, { error: (e as Error).message }, obj.callback);\n\t\t} finally {\n\t\t\tawait sftp.end();\n\t\t}\n\t}\n\n\tprivate async handleListSftpFiles(obj: ioBroker.Message): Promise<void> {\n\t\tif (!this.config.sftpEnabled) {\n\t\t\tthis.sendTo(obj.from, obj.command, { error: \"SFTP not enabled\" }, obj.callback);\n\t\t\treturn;\n\t\t}\n\t\tconst sftp = new SftpClient();\n\t\ttry {\n\t\t\tawait sftp.connect({\n\t\t\t\thost: this.config.sftpHost,\n\t\t\t\tport: this.config.sftpPort || 22,\n\t\t\t\tusername: this.config.sftpUser,\n\t\t\t\tpassword: this.config.sftpPassword,\n\t\t\t});\n\t\t\tconst remotePath = this.config.sftpPath || \"/\";\n\t\t\tconst list = await sftp.list(remotePath);\n\t\t\tconst files = list\n\t\t\t\t.filter(i => {\n\t\t\t\t\tconst n = i.name;\n\t\t\t\t\treturn (\n\t\t\t\t\t\ti.type === \"-\" &&\n\t\t\t\t\t\t(n.startsWith(\"iobroker\") || n.startsWith(\"javascript\")) &&\n\t\t\t\t\t\t(n.endsWith(\".tar.gz\") || n.endsWith(\".tar\") || n.endsWith(\".json\") || n.endsWith(\".jsonl\"))\n\t\t\t\t\t);\n\t\t\t\t})\n\t\t\t\t.map(i => i.name)\n\t\t\t\t.sort()\n\t\t\t\t.reverse();\n\t\t\tthis.sendTo(obj.from, obj.command, { files, path: remotePath }, obj.callback);\n\t\t} catch (e) {\n\t\t\tthis.sendTo(obj.from, obj.command, { error: (e as Error).message }, obj.callback);\n\t\t} finally {\n\t\t\tawait sftp.end();\n\t\t}\n\t}\n\n\tprivate async handleParseSftpFile(obj: ioBroker.Message): Promise<void> {\n\t\tif (!this.config.sftpEnabled) {\n\t\t\tthis.sendTo(obj.from, obj.command, { error: \"SFTP not enabled\" }, obj.callback);\n\t\t\treturn;\n\t\t}\n\t\tconst msg = obj.message as { filename: string };\n\t\tconst filename = path.basename(msg.filename);\n\t\tconst remotePath = path.posix.join(this.config.sftpPath || \"/\", filename);\n\t\tconst sftp = new SftpClient();\n\t\ttry {\n\t\t\tawait sftp.connect({\n\t\t\t\thost: this.config.sftpHost,\n\t\t\t\tport: this.config.sftpPort || 22,\n\t\t\t\tusername: this.config.sftpUser,\n\t\t\t\tpassword: this.config.sftpPassword,\n\t\t\t});\n\t\t\tconst buf = (await sftp.get(remotePath)) as Buffer;\n\t\t\tconst scripts = await this.parseBuffer(buf, filename);\n\t\t\tthis.sendTo(obj.from, obj.command, { scripts }, obj.callback);\n\t\t} catch (e) {\n\t\t\tthis.sendTo(obj.from, obj.command, { error: (e as Error).message }, obj.callback);\n\t\t} finally {\n\t\t\tawait sftp.end();\n\t\t}\n\t}\n\n\t// \u2500\u2500\u2500 WebDAV \u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\n\n\tprivate async handleTestWebdav(obj: ioBroker.Message): Promise<void> {\n\t\ttry {\n\t\t\tconst { createClient: createWebdavClient } = await import(\"webdav\");\n\t\t\tconst client = createWebdavClient(this.config.webdavUrl, {\n\t\t\t\tusername: this.config.webdavUser,\n\t\t\t\tpassword: this.config.webdavPassword,\n\t\t\t});\n\t\t\tconst list = await client.getDirectoryContents(this.config.webdavPath || \"/\");\n\t\t\tconst arr = Array.isArray(list) ? list : (list as { data: unknown[] }).data;\n\t\t\tthis.sendTo(\n\t\t\t\tobj.from,\n\t\t\t\tobj.command,\n\t\t\t\t`\u2713 Verbunden! ${arr.length} Eintr\u00E4ge in: ${this.config.webdavPath || \"/\"}`,\n\t\t\t\tobj.callback,\n\t\t\t);\n\t\t} catch (e) {\n\t\t\tthis.sendTo(obj.from, obj.command, { error: (e as Error).message }, obj.callback);\n\t\t}\n\t}\n\n\tprivate async handleListWebdavFiles(obj: ioBroker.Message): Promise<void> {\n\t\tif (!this.config.webdavEnabled) {\n\t\t\tthis.sendTo(obj.from, obj.command, { error: \"WebDAV not enabled\" }, obj.callback);\n\t\t\treturn;\n\t\t}\n\t\ttry {\n\t\t\tconst { createClient: createWebdavClient } = await import(\"webdav\");\n\t\t\tconst client = createWebdavClient(this.config.webdavUrl, {\n\t\t\t\tusername: this.config.webdavUser,\n\t\t\t\tpassword: this.config.webdavPassword,\n\t\t\t});\n\t\t\tconst remotePath = this.config.webdavPath || \"/\";\n\t\t\tconst list = await client.getDirectoryContents(remotePath);\n\t\t\tconst arr = Array.isArray(list) ? list : (list as { data: { basename: string; type: string }[] }).data;\n\t\t\tconst files = arr\n\t\t\t\t.filter((i: { basename: string; type: string }) => {\n\t\t\t\t\tconst n = i.basename;\n\t\t\t\t\treturn (\n\t\t\t\t\t\ti.type === \"file\" &&\n\t\t\t\t\t\t(n.startsWith(\"iobroker\") || n.startsWith(\"javascript\")) &&\n\t\t\t\t\t\t(n.endsWith(\".tar.gz\") || n.endsWith(\".tar\") || n.endsWith(\".json\") || n.endsWith(\".jsonl\"))\n\t\t\t\t\t);\n\t\t\t\t})\n\t\t\t\t.map((i: { basename: string }) => i.basename)\n\t\t\t\t.sort()\n\t\t\t\t.reverse();\n\t\t\tthis.sendTo(obj.from, obj.command, { files, path: remotePath }, obj.callback);\n\t\t} catch (e) {\n\t\t\tthis.sendTo(obj.from, obj.command, { error: (e as Error).message }, obj.callback);\n\t\t}\n\t}\n\n\tprivate async handleParseWebdavFile(obj: ioBroker.Message): Promise<void> {\n\t\tif (!this.config.webdavEnabled) {\n\t\t\tthis.sendTo(obj.from, obj.command, { error: \"WebDAV not enabled\" }, obj.callback);\n\t\t\treturn;\n\t\t}\n\t\tconst msg = obj.message as { filename: string };\n\t\tconst filename = path.basename(msg.filename);\n\t\ttry {\n\t\t\tconst { createClient: createWebdavClient } = await import(\"webdav\");\n\t\t\tconst client = createWebdavClient(this.config.webdavUrl, {\n\t\t\t\tusername: this.config.webdavUser,\n\t\t\t\tpassword: this.config.webdavPassword,\n\t\t\t});\n\t\t\tconst remotePath = (this.config.webdavPath ? `${this.config.webdavPath}/` : \"/\") + filename;\n\t\t\tconst buf = Buffer.from((await client.getFileContents(remotePath)) as ArrayBuffer);\n\t\t\tconst scripts = await this.parseBuffer(buf, filename);\n\t\t\tthis.sendTo(obj.from, obj.command, { scripts }, obj.callback);\n\t\t} catch (e) {\n\t\t\tthis.sendTo(obj.from, obj.command, { error: (e as Error).message }, obj.callback);\n\t\t}\n\t}\n}\n\nif (require.main !== module) {\n\tmodule.exports = (options: Partial<utils.AdapterOptions> | undefined) => new ScriptRestore(options);\n} else {\n\t(() => new ScriptRestore())();\n}\n"],
5
+ "mappings": "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",
6
6
  "names": ["SftpClient"]
7
7
  }
package/io-package.json CHANGED
@@ -1,8 +1,34 @@
1
1
  {
2
2
  "common": {
3
3
  "name": "script-restore",
4
- "version": "0.0.7",
4
+ "version": "0.0.9",
5
5
  "news": {
6
+ "0.0.9": {
7
+ "en": "Fix jsonConfig: add responsive size attributes, i18n support, remove outdated admin files",
8
+ "de": "jsonConfig: Responsive Size-Attribute ergänzt, i18n-Unterstützung, veraltete Admin-Dateien entfernt",
9
+ "ru": "jsonConfig: добавлены атрибуты размера, поддержка i18n, удалены устаревшие файлы admin",
10
+ "pt": "jsonConfig: atributos de tamanho responsivos, suporte i18n, remoção de ficheiros admin obsoletos",
11
+ "nl": "jsonConfig: responsieve grootteattributen, i18n-ondersteuning, verouderde adminbestanden verwijderd",
12
+ "fr": "jsonConfig: attributs de taille responsifs, support i18n, suppression fichiers admin obsolètes",
13
+ "it": "jsonConfig: attributi dimensione responsivi, supporto i18n, rimozione file admin obsoleti",
14
+ "es": "jsonConfig: atributos de tamaño responsivos, soporte i18n, eliminación de archivos admin obsoletos",
15
+ "pl": "jsonConfig: atrybuty rozmiaru responsywnego, wsparcie i18n, usunięcie przestarzałych plików admin",
16
+ "uk": "jsonConfig: атрибути розміру, підтримка i18n, видалення застарілих файлів admin",
17
+ "zh-cn": "jsonConfig:添加响应式尺寸属性、i18n 支持,删除过时的 admin 文件"
18
+ },
19
+ "0.0.8": {
20
+ "en": "Migrate settings UI to jsonConfig (admin 5+); fix node:fs import; update Dependabot schedule; migrate automerge workflow",
21
+ "de": "Einstellungen auf jsonConfig (Admin 5+) migriert; node:fs-Import korrigiert; Dependabot-Schedule aktualisiert; Automerge-Workflow migriert",
22
+ "ru": "Миграция UI настроек на jsonConfig (admin 5+); исправлен импорт node:fs; обновлён Dependabot; миграция automerge workflow",
23
+ "pt": "Migrar UI de configurações para jsonConfig (admin 5+); corrigir importação node:fs; atualizar Dependabot; migrar workflow automerge",
24
+ "nl": "Instellingen UI migreren naar jsonConfig (admin 5+); node:fs import gecorrigeerd; Dependabot schedule bijgewerkt; automerge workflow gemigreerd",
25
+ "fr": "Migration de l'UI des paramètres vers jsonConfig (admin 5+); correction de l'import node:fs; mise à jour Dependabot; migration du workflow automerge",
26
+ "it": "Migrazione UI impostazioni a jsonConfig (admin 5+); corretto import node:fs; aggiornato Dependabot; migrato workflow automerge",
27
+ "es": "Migrar UI de configuración a jsonConfig (admin 5+); corregir importación node:fs; actualizar Dependabot; migrar workflow automerge",
28
+ "pl": "Migracja UI ustawień do jsonConfig (admin 5+); poprawka importu node:fs; aktualizacja Dependabot; migracja workflow automerge",
29
+ "uk": "Міграція UI налаштувань на jsonConfig (admin 5+); виправлено імпорт node:fs; оновлено Dependabot; міграція automerge workflow",
30
+ "zh-cn": "将设置 UI 迁移至 jsonConfig(admin 5+);修复 node:fs 导入;更新 Dependabot 计划;迁移 automerge 工作流"
31
+ },
6
32
  "0.0.7": {
7
33
  "en": "Fix HTTP URL loading without protocol prefix; remove localStorage backup persistence",
8
34
  "de": "HTTP-URL-Laden ohne Protokoll-Präfix behoben; localStorage-Backup-Persistenz entfernt",
@@ -135,7 +161,7 @@
135
161
  "connectionType": "local",
136
162
  "dataSource": "push",
137
163
  "adminUI": {
138
- "config": "materialize",
164
+ "config": "json",
139
165
  "tab": "materialize"
140
166
  },
141
167
  "adminTab": {
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "iobroker.script-restore",
3
- "version": "0.0.7",
3
+ "version": "0.0.9",
4
4
  "description": "Restore ioBroker scripts from backup archives",
5
5
  "author": {
6
6
  "name": "ipod86",