@open-audio-stack/core 0.1.42 → 0.1.44

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.
@@ -14,7 +14,7 @@ export declare class Manager extends Base {
14
14
  getPackage(slug: string): Package | undefined;
15
15
  getReport(): ManagerReport;
16
16
  outputReport(): void;
17
- listPackages(installed?: boolean): Package[];
17
+ listPackages(installed?: boolean, showAll?: boolean): Package[];
18
18
  removePackage(slug: string): void;
19
19
  reset(): void;
20
20
  search(query: string): Package[];
@@ -2,6 +2,8 @@ import { apiJson } from '../helpers/api.js';
2
2
  import { Config } from './Config.js';
3
3
  import { Package } from './Package.js';
4
4
  import { Base } from './Base.js';
5
+ import { packageCompatibleFiles } from '../helpers/package.js';
6
+ import { getArchitecture, getSystem } from '../helpers/utilsLocal.js';
5
7
  export class Manager extends Base {
6
8
  config;
7
9
  packages;
@@ -52,19 +54,21 @@ export class Manager extends Base {
52
54
  }
53
55
  }
54
56
  }
55
- listPackages(installed) {
57
+ listPackages(installed, showAll = false) {
58
+ let packages = Array.from(this.packages.values());
56
59
  if (installed !== undefined) {
57
- const packagesFiltered = [];
58
- Array.from(this.packages.values()).forEach(pkg => {
59
- Array.from(pkg.versions.values()).forEach(pkgVersion => {
60
- if ((installed === true && pkgVersion.installed) || (installed === false && !pkgVersion.installed)) {
61
- packagesFiltered.push(pkg);
62
- }
63
- });
60
+ packages = packages.filter(pkg => Array.from(pkg.versions.values()).some(pkgVersion => (installed === true && pkgVersion.installed) || (installed === false && !pkgVersion.installed)));
61
+ }
62
+ if (!showAll) {
63
+ packages = packages.filter(pkg => {
64
+ const pkgVersion = pkg.getVersionLatest();
65
+ if (!pkgVersion)
66
+ return false;
67
+ const files = packageCompatibleFiles(pkgVersion, [getArchitecture()], [getSystem()], []);
68
+ return files.length > 0;
64
69
  });
65
- return packagesFiltered;
66
70
  }
67
- return Array.from(this.packages.values());
71
+ return packages.sort((a, b) => a.slug.localeCompare(b.slug));
68
72
  }
69
73
  removePackage(slug) {
70
74
  if (!this.packages.has(slug))
@@ -10,12 +10,12 @@ export declare class ManagerLocal extends Manager {
10
10
  create(): Promise<void>;
11
11
  scan(ext?: string, installable?: boolean): void;
12
12
  export(dir: string, ext?: string): boolean;
13
- install(slug: string, version?: string): Promise<void | PackageVersion>;
13
+ install(slug: string, version?: string): Promise<PackageVersion>;
14
14
  installAll(): Promise<Package[]>;
15
15
  installDependency(slug: string, version?: string, filePath?: string, type?: RegistryType): Promise<any>;
16
16
  installDependencies(filePath: string, type?: RegistryType): Promise<any>;
17
17
  open(slug: string, version?: string, options?: string[]): boolean;
18
- uninstall(slug: string, version?: string): Promise<void | PackageVersion>;
18
+ uninstall(slug: string, version?: string): Promise<PackageVersion>;
19
19
  uninstallDependency(slug: string, version?: string, filePath?: string, type?: RegistryType): Promise<any>;
20
20
  uninstallDependencies(filePath?: string, type?: RegistryType): Promise<any>;
21
21
  }
@@ -164,16 +164,36 @@ export class ManagerLocal extends Manager {
164
164
  // Get package information from registry.
165
165
  const pkg = this.getPackage(slug);
166
166
  if (!pkg)
167
- return this.log(`Package ${slug} not found in registry`);
167
+ throw new Error(`Package ${slug} not found in registry`);
168
168
  const versionNum = version || pkg.latestVersion();
169
169
  const pkgVersion = pkg?.getVersion(versionNum);
170
170
  if (!pkgVersion)
171
- return this.log(`Package ${slug} version ${versionNum} not found in registry`);
171
+ throw new Error(`Package ${slug} version ${versionNum} not found in registry`);
172
172
  if (this.isPackageInstalled(slug, versionNum)) {
173
173
  this.log(`Package ${slug} version ${versionNum} already installed`);
174
174
  pkgVersion.installed = true;
175
175
  return pkgVersion;
176
176
  }
177
+ // Check for compatible files before running admin command
178
+ const excludedFormats = [];
179
+ const system = getSystem();
180
+ if (system === SystemType.Linux) {
181
+ const hasDpkg = await commandExists('dpkg');
182
+ const hasRpm = await commandExists('rpm');
183
+ // If both exist, prefer DEB over RPM
184
+ if (hasDpkg && hasRpm) {
185
+ excludedFormats.push(FileFormat.RedHatPackage);
186
+ }
187
+ else if (!hasDpkg) {
188
+ excludedFormats.push(FileFormat.DebianPackage);
189
+ }
190
+ else if (!hasRpm) {
191
+ excludedFormats.push(FileFormat.RedHatPackage);
192
+ }
193
+ }
194
+ const files = packageCompatibleFiles(pkgVersion, [getArchitecture()], [getSystem()], excludedFormats);
195
+ if (!files.length)
196
+ throw new Error(`No compatible files found for ${slug}`);
177
197
  // Elevate permissions if not running as admin.
178
198
  if (!isAdmin() && !isTests()) {
179
199
  let command = `--appDir "${this.config.get('appDir')}" --operation "install" --type "${this.type}" --id "${slug}"`;
@@ -194,19 +214,6 @@ export class ManagerLocal extends Manager {
194
214
  // Create temporary directory to store downloaded files.
195
215
  const dirDownloads = path.join(this.config.get('appDir'), 'downloads', this.type, slug, versionNum);
196
216
  dirCreate(dirDownloads);
197
- // Not all Linux distributions support all file formats.
198
- const excludedFormats = [];
199
- const system = getSystem();
200
- if (system === SystemType.Linux) {
201
- if (!(await commandExists('dpkg')))
202
- excludedFormats.push(FileFormat.DebianPackage);
203
- if (!(await commandExists('rpm')))
204
- excludedFormats.push(FileFormat.RedHatPackage);
205
- }
206
- // Filter for compatible files and download.
207
- const files = packageCompatibleFiles(pkgVersion, [getArchitecture()], [getSystem()], excludedFormats);
208
- if (!files.length)
209
- return this.log(`Error: No compatible files found for ${slug}`);
210
217
  for (const key in files) {
211
218
  // Download file to temporary directory if not already downloaded.
212
219
  const file = files[key];
@@ -218,9 +225,10 @@ export class ManagerLocal extends Manager {
218
225
  // Check file hash matches expected hash.
219
226
  const hash = await fileHash(filePath);
220
227
  if (hash !== file.sha256)
221
- return this.log(`Error: ${filePath} hash mismatch`);
228
+ throw new Error(`${filePath} hash mismatch`);
222
229
  // If installer, run the installer headless (without the user interface).
223
230
  if (file.type === FileType.Installer) {
231
+ // Test time out if installing during tests.
224
232
  if (isTests())
225
233
  fileOpen(filePath);
226
234
  else
@@ -324,26 +332,22 @@ export class ManagerLocal extends Manager {
324
332
  // Get package information
325
333
  const pkg = this.getPackage(slug);
326
334
  if (!pkg) {
327
- this.log(`Package ${slug} not found`);
328
- return false;
335
+ throw new Error(`Package ${slug} not found`);
329
336
  }
330
337
  const versionNum = version || pkg.latestVersion();
331
338
  const pkgVersion = pkg.getVersion(versionNum);
332
339
  if (!pkgVersion) {
333
- this.log(`Package ${slug} version ${versionNum} not found`);
334
- return false;
340
+ throw new Error(`Package ${slug} version ${versionNum} not found`);
335
341
  }
336
342
  // Check if package is installed
337
343
  if (!this.isPackageInstalled(slug, versionNum)) {
338
- this.log(`Package ${slug} version ${versionNum} not installed`);
339
- return false;
344
+ throw new Error(`Package ${slug} version ${versionNum} not installed`);
340
345
  }
341
346
  // Filter compatible files and find one with open field
342
347
  const files = packageCompatibleFiles(pkgVersion, [getArchitecture()], [getSystem()], []);
343
348
  const openableFile = files.find(file => file.open);
344
349
  if (!openableFile) {
345
- this.log(`Package ${slug} has no compatible file with open command defined`);
346
- return false;
350
+ throw new Error(`Package ${slug} has no compatible file with open command defined`);
347
351
  }
348
352
  try {
349
353
  const openPath = openableFile.open;
@@ -370,12 +374,7 @@ export class ManagerLocal extends Manager {
370
374
  }
371
375
  const command = `"${fullPath}" ${options.join(' ')}`;
372
376
  this.log(`Running: ${command}`);
373
- if (isTests()) {
374
- this.log(`Would run: ${command}`);
375
- }
376
- else {
377
- fileOpen(fullPath);
378
- }
377
+ fileOpen(fullPath, options);
379
378
  return true;
380
379
  }
381
380
  catch (error) {
@@ -387,13 +386,13 @@ export class ManagerLocal extends Manager {
387
386
  // Get package information from registry.
388
387
  const pkg = this.getPackage(slug);
389
388
  if (!pkg)
390
- return this.log(`Package ${slug} not found in registry`);
389
+ throw new Error(`Package ${slug} not found in registry`);
391
390
  const versionNum = version || pkg.latestVersion();
392
391
  const pkgVersion = pkg?.getVersion(versionNum);
393
392
  if (!pkgVersion)
394
- return this.log(`Package ${slug} version ${versionNum} not found in registry`);
393
+ throw new Error(`Package ${slug} version ${versionNum} not found in registry`);
395
394
  if (!this.isPackageInstalled(slug, versionNum))
396
- return this.log(`Package ${slug} version ${versionNum} not installed`);
395
+ throw new Error(`Package ${slug} version ${versionNum} not installed`);
397
396
  // Elevate permissions if not running as admin.
398
397
  if (!isAdmin() && !isTests()) {
399
398
  let command = `--appDir "${this.config.get('appDir')}" --operation "uninstall" --type "${this.type}" --id "${slug}"`;
@@ -33,7 +33,7 @@ export declare function fileHash(filePath: string, algorithm?: string): Promise<
33
33
  export declare function fileInstall(filePath: string): Buffer<ArrayBufferLike>;
34
34
  export declare function fileMove(filePath: string, newPath: string): void | boolean;
35
35
  export declare function filesMove(dirSource: string, dirTarget: string, dirSub: string, formatDir: Record<string, string>): string[];
36
- export declare function fileOpen(filePath: string): Buffer<ArrayBufferLike>;
36
+ export declare function fileOpen(filePath: string, options?: string[]): import("child_process").ChildProcess | Buffer<ArrayBufferLike>;
37
37
  export declare function fileRead(filePath: string): string;
38
38
  export declare function fileReadJson(filePath: string): any;
39
39
  export declare function fileReadString(filePath: string): string;
@@ -247,8 +247,9 @@ export function fileMove(filePath, newPath) {
247
247
  return false;
248
248
  }
249
249
  export function filesMove(dirSource, dirTarget, dirSub, formatDir) {
250
- // Read files from source directory, ignoring Mac Contents files.
251
- const files = dirRead(`${dirSource}/**/*.*`);
250
+ // Read all files from source directory, ignoring Mac Contents files.
251
+ const allFiles = dirRead(`${dirSource}/**/*`);
252
+ const files = allFiles.filter(f => !dirIs(f));
252
253
  const filesMoved = [];
253
254
  // For each file, move to correct folder based on type
254
255
  files.forEach((fileSource) => {
@@ -256,7 +257,7 @@ export function filesMove(dirSource, dirTarget, dirSub, formatDir) {
256
257
  const fileExtTarget = formatDir[fileExt];
257
258
  // If this is not a supported file format, then ignore.
258
259
  if (fileExtTarget === undefined)
259
- return log(`${fileSource} - ${fileExt} not mapped to a installation folder, skipping.`);
260
+ return log(`${fileSource} - ${fileExt || 'no extension'} not mapped to a installation folder, skipping.`);
260
261
  const fileTarget = path.join(dirTarget, fileExtTarget, dirSub, path.basename(fileSource));
261
262
  if (fileExists(fileTarget))
262
263
  return log(`${fileSource} - ${fileTarget} already exists, skipping.`);
@@ -270,21 +271,32 @@ export function filesMove(dirSource, dirTarget, dirSub, formatDir) {
270
271
  fileExec(executablePath);
271
272
  }
272
273
  }
273
- else if (['elf', 'exe'].includes(fileExt)) {
274
+ else if (['elf', 'exe', ''].includes(fileExt)) {
274
275
  fileExec(fileTarget);
275
276
  }
276
277
  filesMoved.push(fileTarget);
277
278
  });
278
279
  return filesMoved;
279
280
  }
280
- export function fileOpen(filePath) {
281
- let command = '';
281
+ export function fileOpen(filePath, options = []) {
282
282
  if (process.env.CI)
283
283
  return Buffer.from('');
284
+ if (getSystem() === SystemType.Mac) {
285
+ const isExecutable = !path.extname(filePath);
286
+ if (isExecutable) {
287
+ // Use spawn for executables with stdio inherit to show output
288
+ log('⎋', `spawn "${filePath}" ${options.join(' ')}`);
289
+ const child = spawn(filePath, options, { stdio: 'inherit' });
290
+ return child;
291
+ }
292
+ else {
293
+ log('⎋', `open "${filePath}"`);
294
+ return execSync(`open "${filePath}"`);
295
+ }
296
+ }
297
+ let command = '';
284
298
  if (getSystem() === SystemType.Win)
285
299
  command = 'start ""';
286
- else if (getSystem() === SystemType.Mac)
287
- command = 'open';
288
300
  else
289
301
  command = 'xdg-open';
290
302
  log('⎋', `${command} "${filePath}"`);
@@ -19,7 +19,9 @@ export declare enum PluginFormat {
19
19
  export type PluginFormatDir = {
20
20
  [format in PluginFormat]: string;
21
21
  };
22
- export declare const pluginFormatDir: PluginFormatDir;
22
+ export declare const pluginFormatDir: PluginFormatDir & {
23
+ '': string;
24
+ };
23
25
  export interface PluginFormatOption {
24
26
  description: string;
25
27
  value: PluginFormat;
@@ -34,6 +34,7 @@ export const pluginFormatDir = {
34
34
  [PluginFormat.VSTMac]: 'VST',
35
35
  [PluginFormat.VSTWin]: 'VST',
36
36
  [PluginFormat.WinStandalone]: 'Exe',
37
+ '': 'App',
37
38
  };
38
39
  export const pluginFormats = [
39
40
  {
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@open-audio-stack/core",
3
- "version": "0.1.42",
3
+ "version": "0.1.44",
4
4
  "description": "Open-source audio plugin management software",
5
5
  "type": "module",
6
6
  "main": "./build/index.js",