@matterbridge/thread 3.6.1-dev-20260311-7da5ff8 → 3.6.1-dev-20260312-a699c0e

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.
@@ -17,6 +17,7 @@ export declare class ThreadsManager {
17
17
  private msgHandler;
18
18
  private intervalHandler;
19
19
  runThread(name: string, workerData?: WorkerData, argv?: string[], env?: NodeJS.ProcessEnv, execArgv?: string[], pipedOutput?: boolean): Worker;
20
+ runInMainThread(name: string, workerData?: WorkerData | null): Promise<boolean>;
20
21
  resolvePath(fileName: string): string;
21
22
  createESMWorker(name: string, relativePath: string, workerData?: Record<string, boolean | number | string | object>, argv?: string[], env?: NodeJS.ProcessEnv, execArgv?: string[], pipedOutput?: boolean): Worker;
22
23
  }
@@ -69,7 +69,7 @@ export class ThreadsManager {
69
69
  this.server.respond({ ...msg, result: { success: true } });
70
70
  }
71
71
  catch (err) {
72
- this.log.error(`Failed to run thread ${CYAN}${msg.params.name}${db}: ${err.message}`);
72
+ this.log.warn(`Failed to run thread ${CYAN}${msg.params.name}${db}: ${err.message}`);
73
73
  this.server.respond({ ...msg, result: { success: false } });
74
74
  }
75
75
  break;
@@ -143,6 +143,22 @@ export class ThreadsManager {
143
143
  this.log.debug(`Started thread ${threadInfo.name} from path ${path} type ${threadInfo.type} with thread id ${worker.threadId}`);
144
144
  return threadInfo.worker;
145
145
  }
146
+ async runInMainThread(name, workerData = null) {
147
+ const threadInfo = this.threads.find((t) => t.name === name);
148
+ if (!threadInfo) {
149
+ throw new Error(`Thread ${name} not found`);
150
+ }
151
+ this.log.debug(`Running thread ${threadInfo.name} in the main thread...`);
152
+ let success = false;
153
+ const workerWrapper = (await import(this.resolvePath(threadInfo.path))).default;
154
+ if (workerWrapper && typeof workerWrapper === 'object' && workerWrapper.name === name && workerWrapper.callback && typeof workerWrapper.callback === 'function') {
155
+ workerWrapper.workerData = workerData;
156
+ success = await workerWrapper.callback(workerWrapper);
157
+ workerWrapper.destroy(success);
158
+ }
159
+ this.log.debug(`Finished running thread ${threadInfo.name} in the main thread.`);
160
+ return success;
161
+ }
146
162
  resolvePath(fileName) {
147
163
  const currentModuleDirectory = path.dirname(fileURLToPath(import.meta.url));
148
164
  const candidates = [
@@ -1 +1,3 @@
1
- export {};
1
+ import { WorkerWrapper } from './workerWrapper.js';
2
+ declare const _default: WorkerWrapper;
3
+ export default _default;
@@ -1,7 +1,7 @@
1
1
  import { inspectError } from '@matterbridge/utils/error';
2
2
  import { checkUpdates } from './checkUpdates.js';
3
3
  import { WorkerWrapper } from './workerWrapper.js';
4
- new WorkerWrapper('CheckUpdates', async (worker) => {
4
+ export default new WorkerWrapper('CheckUpdates', async (worker) => {
5
5
  worker.logger("info", `Starting check updates...`);
6
6
  let success = false;
7
7
  try {
@@ -1 +1,3 @@
1
- export {};
1
+ import { WorkerWrapper } from './workerWrapper.js';
2
+ declare const _default: WorkerWrapper;
3
+ export default _default;
@@ -1,7 +1,7 @@
1
1
  import { inspectError } from '@matterbridge/utils/error';
2
2
  import { getGlobalNodeModules } from '@matterbridge/utils/npm-prefix';
3
3
  import { WorkerWrapper } from './workerWrapper.js';
4
- new WorkerWrapper('GlobalPrefix', async (worker) => {
4
+ export default new WorkerWrapper('GlobalPrefix', async (worker) => {
5
5
  let prefix;
6
6
  worker.logger("info", `Starting global prefix check...`);
7
7
  let success = false;
@@ -1 +1,3 @@
1
- export {};
1
+ import { WorkerWrapper } from './workerWrapper.js';
2
+ declare const _default: WorkerWrapper;
3
+ export default _default;
@@ -1,7 +1,7 @@
1
1
  import { isSpawnWorkerData } from '@matterbridge/types';
2
2
  import { spawnCommand } from './spawnCommand.js';
3
3
  import { WorkerWrapper } from './workerWrapper.js';
4
- new WorkerWrapper('SpawnCommand', async (worker) => {
4
+ export default new WorkerWrapper('SpawnCommand', async (worker) => {
5
5
  if (!isSpawnWorkerData(worker.workerData)) {
6
6
  worker.logger("error", `SpawnCommand invalid parameters`);
7
7
  return false;
@@ -1 +1,3 @@
1
- export {};
1
+ import { WorkerWrapper } from './workerWrapper.js';
2
+ declare const _default: WorkerWrapper;
3
+ export default _default;
@@ -2,7 +2,7 @@ import os from 'node:os';
2
2
  import { inspectError } from '@matterbridge/utils/error';
3
3
  import { excludedInterfaceNamePattern } from '@matterbridge/utils/network';
4
4
  import { WorkerWrapper } from './workerWrapper.js';
5
- new WorkerWrapper('SystemCheck', async (worker) => {
5
+ export default new WorkerWrapper('SystemCheck', async (worker) => {
6
6
  worker.logger("info", `Starting system check...`);
7
7
  let success = false;
8
8
  try {
@@ -4,6 +4,7 @@ import { AnsiLogger, LogLevel } from 'node-ansi-logger';
4
4
  import { BroadcastServer } from './broadcastServer.js';
5
5
  export declare class WorkerWrapper {
6
6
  name: ThreadNames;
7
+ callback: (worker: WorkerWrapper) => Promise<boolean>;
7
8
  debug: boolean;
8
9
  verbose: boolean;
9
10
  useTracker: boolean;
@@ -8,6 +8,7 @@ import { BroadcastServer } from './broadcastServer.js';
8
8
  import { ThreadsManager } from './threadsManager.js';
9
9
  export class WorkerWrapper {
10
10
  name;
11
+ callback;
11
12
  debug = hasParameter('debug') || hasParameter('verbose') || hasParameter('debug-threads') || hasParameter('verbose-threads');
12
13
  verbose = hasParameter('verbose') || hasParameter('verbose-threads');
13
14
  useTracker = hasParameter('tracker') || hasParameter('tracker-threads');
@@ -17,6 +18,7 @@ export class WorkerWrapper {
17
18
  tracker;
18
19
  constructor(name, callback) {
19
20
  this.name = name;
21
+ this.callback = callback;
20
22
  if (this.workerData) {
21
23
  this.debug = this.workerData.debug || this.debug;
22
24
  this.verbose = this.workerData.verbose || this.verbose;
@@ -65,12 +67,18 @@ export class WorkerWrapper {
65
67
  if (this.debug)
66
68
  this.parentLog(this.name, "info", `Worker ${this.name}:${threadId} initialized.`);
67
69
  }
70
+ else {
71
+ if (this.debug)
72
+ this.log.debug(`Worker ${this.name}:${threadId} initialized in main thread.`);
73
+ }
68
74
  if (this.verbose)
69
75
  this.logWorkerInfo(this.log, false);
70
- setImmediate(async () => {
71
- const success = await callback(this);
72
- this.destroy(success);
73
- });
76
+ if (!isMainThread) {
77
+ setImmediate(async () => {
78
+ const success = await callback(this);
79
+ this.destroy(success);
80
+ });
81
+ }
74
82
  }
75
83
  destroy(success) {
76
84
  if (this.tracker)
@@ -82,6 +90,10 @@ export class WorkerWrapper {
82
90
  this.parentPost({ type: 'exit', threadId, threadName: this.name, memoryUsage: process.memoryUsage(), success });
83
91
  parentPort.close();
84
92
  }
93
+ else {
94
+ if (this.debug)
95
+ this.log.debug(`Worker ${this.name}:${threadId} exiting with success in main thread: ${success}.`);
96
+ }
85
97
  }
86
98
  parentPost(message) {
87
99
  if (!parentPort)
@@ -0,0 +1,10 @@
1
+ export interface ZipContentEntry {
2
+ filename: string;
3
+ directory: boolean;
4
+ compressedSize: number;
5
+ uncompressedSize: number;
6
+ lastModDate: Date;
7
+ }
8
+ export declare function createZip(zipPath: string, sourcePaths: string[]): Promise<number>;
9
+ export declare function readZip(zipPath: string): Promise<ZipContentEntry[]>;
10
+ export declare function unZip(zipPath: string, destinationPath?: string): Promise<string>;
package/dist/zipjs.js ADDED
@@ -0,0 +1,114 @@
1
+ import { mkdir, readdir, readFile, stat, writeFile } from 'node:fs/promises';
2
+ import { basename, dirname, extname, isAbsolute, join, relative, resolve } from 'node:path';
3
+ import { Uint8ArrayReader, Uint8ArrayWriter, ZipReader, ZipWriter } from '@zip.js/zip.js';
4
+ import { AnsiLogger } from 'node-ansi-logger';
5
+ export async function createZip(zipPath, sourcePaths) {
6
+ if (sourcePaths.length === 0)
7
+ throw new Error('No files or directories provided to createZip.');
8
+ const log = createLogger();
9
+ const writer = new ZipWriter(new Uint8ArrayWriter());
10
+ let entryCount = 0;
11
+ for (const sourcePath of sourcePaths) {
12
+ const resolvedSourcePath = resolve(sourcePath);
13
+ entryCount += await addZipEntry(writer, resolvedSourcePath, basename(resolvedSourcePath), log);
14
+ }
15
+ const zipData = await writer.close();
16
+ await mkdir(dirname(zipPath), { recursive: true });
17
+ await writeFile(zipPath, zipData);
18
+ log.info(`Created zip ${zipPath} with ${entryCount} entries (${zipData.byteLength} bytes).`);
19
+ return zipData.byteLength;
20
+ }
21
+ export async function readZip(zipPath) {
22
+ const log = createLogger();
23
+ const reader = new ZipReader(new Uint8ArrayReader(await readFile(zipPath)));
24
+ try {
25
+ const entries = await reader.getEntries();
26
+ const content = entries.map((entry) => ({
27
+ filename: entry.filename,
28
+ directory: entry.directory,
29
+ compressedSize: entry.compressedSize,
30
+ uncompressedSize: entry.uncompressedSize,
31
+ lastModDate: entry.lastModDate,
32
+ }));
33
+ if (content.length === 0) {
34
+ log.info(`Zip ${zipPath} is empty.`);
35
+ }
36
+ else {
37
+ for (const entry of content) {
38
+ log.info(`${entry.directory ? 'dir ' : 'file'} ${entry.filename} (${entry.uncompressedSize} bytes)`);
39
+ }
40
+ }
41
+ return content;
42
+ }
43
+ finally {
44
+ await reader.close();
45
+ }
46
+ }
47
+ export async function unZip(zipPath, destinationPath = getDefaultDestinationPath(zipPath)) {
48
+ const log = createLogger();
49
+ const reader = new ZipReader(new Uint8ArrayReader(await readFile(zipPath)));
50
+ let extractedEntries = 0;
51
+ await mkdir(destinationPath, { recursive: true });
52
+ try {
53
+ const entries = await reader.getEntries();
54
+ for (const entry of entries) {
55
+ const entryPath = resolveEntryPath(destinationPath, entry.filename);
56
+ if (entry.directory) {
57
+ await mkdir(entryPath, { recursive: true });
58
+ extractedEntries++;
59
+ continue;
60
+ }
61
+ await mkdir(dirname(entryPath), { recursive: true });
62
+ const fileData = await entry.getData(new Uint8ArrayWriter());
63
+ await writeFile(entryPath, fileData);
64
+ extractedEntries++;
65
+ }
66
+ }
67
+ finally {
68
+ await reader.close();
69
+ }
70
+ log.info(`Extracted ${extractedEntries} entries from ${zipPath} to ${destinationPath}.`);
71
+ return destinationPath;
72
+ }
73
+ function createLogger() {
74
+ return new AnsiLogger({ logName: 'ZipJs', logTimestampFormat: 4, logLevel: "info" });
75
+ }
76
+ async function addZipEntry(writer, sourcePath, entryName, log) {
77
+ const sourceStats = await stat(sourcePath);
78
+ const normalizedEntryName = normalizeEntryName(entryName);
79
+ if (sourceStats.isDirectory()) {
80
+ const directoryEntryName = normalizedEntryName.replace(/\/?$/, '/');
81
+ await writer.add(directoryEntryName, undefined, { directory: true, lastModDate: sourceStats.mtime, level: 9 });
82
+ const children = await readdir(sourcePath, { withFileTypes: true });
83
+ children.sort((left, right) => left.name.localeCompare(right.name));
84
+ let childEntries = 1;
85
+ for (const child of children) {
86
+ childEntries += await addZipEntry(writer, join(sourcePath, child.name), `${directoryEntryName}${child.name}`, log);
87
+ }
88
+ log.debug(`Added directory ${directoryEntryName}`);
89
+ return childEntries;
90
+ }
91
+ if (sourceStats.isFile()) {
92
+ await writer.add(normalizedEntryName, new Uint8ArrayReader(await readFile(sourcePath)), { lastModDate: sourceStats.mtime, level: 9 });
93
+ log.debug(`Added file ${normalizedEntryName}`);
94
+ return 1;
95
+ }
96
+ throw new Error(`Unsupported source path type: ${sourcePath}`);
97
+ }
98
+ function getDefaultDestinationPath(zipPath) {
99
+ const zipExtension = extname(zipPath);
100
+ const zipName = basename(zipPath, zipExtension);
101
+ return join(dirname(zipPath), zipName);
102
+ }
103
+ function normalizeEntryName(entryName) {
104
+ return entryName.replace(/\\/g, '/');
105
+ }
106
+ function resolveEntryPath(destinationPath, entryName) {
107
+ const resolvedDestinationPath = resolve(destinationPath);
108
+ const resolvedEntryPath = resolve(resolvedDestinationPath, normalizeEntryName(entryName));
109
+ const relativeEntryPath = relative(resolvedDestinationPath, resolvedEntryPath);
110
+ if (isAbsolute(relativeEntryPath) || relativeEntryPath.startsWith('..')) {
111
+ throw new Error(`Refusing to extract zip entry outside destination: ${entryName}`);
112
+ }
113
+ return resolvedEntryPath;
114
+ }
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@matterbridge/thread",
3
- "version": "3.6.1-dev-20260311-7da5ff8",
3
+ "version": "3.6.1-dev-20260312-a699c0e",
4
4
  "description": "Matterbridge thread library",
5
5
  "author": "https://github.com/Luligu",
6
6
  "homepage": "https://matterbridge.io/",
@@ -69,8 +69,9 @@
69
69
  "CHANGELOG.md"
70
70
  ],
71
71
  "dependencies": {
72
- "@matterbridge/types": "3.6.1-dev-20260311-7da5ff8",
73
- "@matterbridge/utils": "3.6.1-dev-20260311-7da5ff8",
72
+ "@matterbridge/types": "3.6.1-dev-20260312-a699c0e",
73
+ "@matterbridge/utils": "3.6.1-dev-20260312-a699c0e",
74
+ "@zip.js/zip.js": "2.8.23",
74
75
  "node-ansi-logger": "3.2.0"
75
76
  }
76
77
  }