@open-audio-stack/core 0.1.5 → 0.1.7

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/README.md CHANGED
@@ -5,7 +5,7 @@
5
5
  </h1>
6
6
  <p>Audio registry specification and API with searchable list of packages</p>
7
7
  <p>
8
- <a href="https://github.com/open-audio-stack/open-audio-stack-core/wiki/Open-Audio-Stack-%E2%80%90-Registry-%E2%80%90-Specification-1.0.0">Registry Specification</a>
8
+ <a href="https://github.com/open-audio-stack/open-audio-stack-core/wiki/Open-Audio-Stack-%E2%80%90-Manager-%E2%80%90-Specification-1.0.0">Manager Specification</a>
9
9
  ⦁︎
10
10
  <a href="https://open-audio-stack.github.io/open-audio-stack-registry">Registry API</a>
11
11
  ⦁︎
@@ -17,7 +17,7 @@
17
17
  ![Release](https://github.com/open-audio-stack/open-audio-stack-core/workflows/Release/badge.svg)
18
18
  <a href="https://discord.com/invite/9D94f98PxP" target="_blank"><img src="https://img.shields.io/badge/chat-on%20discord-7289DA.svg" alt="Join the chat at Discord"></a>
19
19
 
20
- ![Open Audio Stack - Registry - Specification 1.0.0](https://raw.githubusercontent.com/open-audio-stack/open-audio-stack-registry/refs/heads/main/src/assets/open-audio-stack-diagram.svg)
20
+ ![Open Audio Stack - Manager - Specification 1.0.0](https://raw.githubusercontent.com/open-audio-stack/open-audio-stack-registry/refs/heads/main/src/assets/open-audio-stack-diagram-manager.svg)
21
21
 
22
22
  </div>
23
23
 
@@ -3,7 +3,7 @@ import { Package } from './Package.js';
3
3
  import { Manager } from './Manager.js';
4
4
  import { archiveExtract, dirCreate, dirDelete, dirEmpty, dirRead, fileCreate, fileCreateJson, fileExists, fileHash, fileOpen, fileReadJson, filesMove, isAdmin, runCliAsAdmin, } from '../helpers/file.js';
5
5
  import { pathGetSlug, pathGetVersion } from '../helpers/utils.js';
6
- import { getArchitecture, getSystem, isTests } from '../helpers/utilsLocal.js';
6
+ import { commandExists, getArchitecture, getSystem, isTests } from '../helpers/utilsLocal.js';
7
7
  import { apiBuffer } from '../helpers/api.js';
8
8
  import { FileType } from '../types/FileType.js';
9
9
  import { RegistryType } from '../types/Registry.js';
@@ -12,6 +12,7 @@ import { ConfigLocal } from './ConfigLocal.js';
12
12
  import { packageCompatibleFiles } from '../helpers/package.js';
13
13
  import { presetFormatDir } from '../types/PresetFormat.js';
14
14
  import { projectFormatDir } from '../types/ProjectFormat.js';
15
+ import { FileFormat, SystemType } from '../index-browser.js';
15
16
  export class ManagerLocal extends Manager {
16
17
  typeDir;
17
18
  constructor(type, config) {
@@ -53,8 +54,17 @@ export class ManagerLocal extends Manager {
53
54
  // Create temporary directory to store downloaded files.
54
55
  const dirDownloads = path.join(this.config.get('appDir'), 'downloads', this.type, slug, versionNum);
55
56
  dirCreate(dirDownloads);
57
+ // Not all Linux distributions support all file formats.
58
+ const excludedFormats = [];
59
+ const system = getSystem();
60
+ if (system === SystemType.Linux) {
61
+ if (!(await commandExists('dpkg')))
62
+ excludedFormats.push(FileFormat.DebianPackage);
63
+ if (!(await commandExists('rpm')))
64
+ excludedFormats.push(FileFormat.RedHatPackage);
65
+ }
56
66
  // Filter for compatible files and download.
57
- const files = packageCompatibleFiles(pkgVersion, [getArchitecture()], [getSystem()]);
67
+ const files = packageCompatibleFiles(pkgVersion, [getArchitecture()], [getSystem()], excludedFormats);
58
68
  if (!files.length)
59
69
  return console.error(`Error: No compatible files found for ${slug}`);
60
70
  for (const key in files) {
@@ -200,9 +200,9 @@ export function fileOpen(filePath) {
200
200
  if (process.env.CI)
201
201
  return Buffer.from('');
202
202
  if (getSystem() === SystemType.Win)
203
- command = 'open';
204
- else if (getSystem() === SystemType.Mac)
205
203
  command = 'start ""';
204
+ else if (getSystem() === SystemType.Mac)
205
+ command = 'open';
206
206
  else
207
207
  command = 'xdg-open';
208
208
  console.log('⎋', `${command} "${filePath}"`);
@@ -10,8 +10,9 @@ import { PresetType } from '../types/PresetType.js';
10
10
  import { ProjectFile } from '../types/Project.js';
11
11
  import { ProjectType } from '../types/ProjectType.js';
12
12
  import { SystemType } from '../types/SystemType.js';
13
- import { PackageInterface, PackageValidationRec, PackageVersion } from '../types/Package.js';
14
- export declare function packageCompatibleFiles(pkg: PackageVersion, arch: Architecture[], sys: SystemType[]): (PluginFile | PresetFile | ProjectFile)[];
13
+ import { PackageFileMap, PackageInterface, PackageValidationRec, PackageVersion } from '../types/Package.js';
14
+ export declare function packageCompatibleFiles(pkg: PackageVersion, arch: Architecture[], sys: SystemType[], excludedFormats?: FileFormat[]): (PluginFile | PresetFile | ProjectFile)[];
15
+ export declare function packageFileMap(pkgVersion: PackageVersion): PackageFileMap;
15
16
  export declare function packageVersionLatest(pkg: PackageInterface): string;
16
17
  export declare const PackageSystemValidator: z.ZodObject<{
17
18
  max: z.ZodOptional<z.ZodNumber>;
@@ -8,7 +8,7 @@ import { PluginType } from '../types/PluginType.js';
8
8
  import { PresetType } from '../types/PresetType.js';
9
9
  import { ProjectType } from '../types/ProjectType.js';
10
10
  import { SystemType } from '../types/SystemType.js';
11
- export function packageCompatibleFiles(pkg, arch, sys) {
11
+ export function packageCompatibleFiles(pkg, arch, sys, excludedFormats) {
12
12
  return pkg.files.filter((file) => {
13
13
  const archMatches = file.architectures.filter(architecture => {
14
14
  return arch.includes(architecture);
@@ -16,9 +16,21 @@ export function packageCompatibleFiles(pkg, arch, sys) {
16
16
  const sysMatches = file.systems.filter(system => {
17
17
  return sys.includes(system.type);
18
18
  });
19
- return archMatches.length && sysMatches.length;
19
+ const formatAllowed = excludedFormats && excludedFormats.includes(file.format) ? false : true;
20
+ return archMatches.length && sysMatches.length && formatAllowed;
20
21
  });
21
22
  }
23
+ export function packageFileMap(pkgVersion) {
24
+ return pkgVersion.files.reduce((result, file) => {
25
+ file.systems.forEach(system => {
26
+ if (!result[system.type]) {
27
+ result[system.type] = [];
28
+ }
29
+ result[system.type].push(file);
30
+ });
31
+ return result;
32
+ }, {});
33
+ }
22
34
  export function packageVersionLatest(pkg) {
23
35
  return Array.from(Object.keys(pkg.versions)).sort(semver.rcompare)[0] || '0.0.0';
24
36
  }
@@ -85,6 +97,24 @@ export function packageRecommendations(pkgVersion) {
85
97
  });
86
98
  supportedFileFormats[file.format] = true;
87
99
  packageRecommendationsUrl(file, recs, 'url');
100
+ // Formats which do not support headless installation.
101
+ if (file.format === FileFormat.AppImage)
102
+ recs.push({ field: 'format', rec: 'requires manual installation steps, consider .deb and .rpm instead' });
103
+ if (file.format === FileFormat.AppleDiskImage)
104
+ recs.push({ field: 'format', rec: 'requires mounting step, consider .pkg instead' });
105
+ if (!file.url.includes(file.format))
106
+ recs.push({ field: 'format', rec: 'should match url field' });
107
+ // Validate format is a supported installer format
108
+ const installerFormats = [
109
+ FileFormat.AppleDiskImage,
110
+ FileFormat.ApplePackage,
111
+ FileFormat.DebianPackage,
112
+ FileFormat.ExecutableInstaller,
113
+ FileFormat.RedHatPackage,
114
+ FileFormat.WindowsInstaller,
115
+ ];
116
+ if (file.type === FileType.Installer && !installerFormats.includes(file.format))
117
+ recs.push({ field: 'type', rec: 'should match format field' });
88
118
  });
89
119
  // Architectures
90
120
  if (!supportedArchitectures.arm64)
@@ -98,17 +128,6 @@ export function packageRecommendations(pkgVersion) {
98
128
  recs.push({ field: 'systems', rec: 'should support Mac' });
99
129
  if (!supportedSystems.win)
100
130
  recs.push({ field: 'systems', rec: 'should support Windows' });
101
- // Formats
102
- if (supportedFileFormats.deb)
103
- recs.push({
104
- field: 'format',
105
- rec: 'should support all Linux distributions, consider using AppImage or Tarball instead',
106
- });
107
- if (supportedFileFormats.rpm)
108
- recs.push({
109
- field: 'format',
110
- rec: 'should support all Linux distributions, consider using AppImage or Tarball instead',
111
- });
112
131
  // Tags
113
132
  const pluginTags = pkgVersion.tags.map(tag => tag.trim().toLowerCase());
114
133
  if (pluginTags.length < 2)
@@ -3,3 +3,4 @@ import { Architecture } from '../types/Architecture.js';
3
3
  export declare function getArchitecture(): Architecture;
4
4
  export declare function getSystem(): SystemType;
5
5
  export declare function isTests(): boolean;
6
+ export declare function commandExists(cmd: string): Promise<boolean>;
@@ -1,3 +1,4 @@
1
+ import { exec } from 'child_process';
1
2
  import { SystemType } from '../types/SystemType.js';
2
3
  import { Architecture } from '../types/Architecture.js';
3
4
  export function getArchitecture() {
@@ -21,3 +22,10 @@ export function isTests() {
21
22
  const vitest = process.env.VITEST_WORKER_ID !== undefined;
22
23
  return jest || vitest;
23
24
  }
25
+ export function commandExists(cmd) {
26
+ return new Promise(resolve => {
27
+ exec(`command -v ${cmd}`, (error, stdout) => {
28
+ resolve(Boolean(stdout.trim()) && !error);
29
+ });
30
+ });
31
+ }
@@ -1,6 +1,6 @@
1
1
  export * from './classes/Config.js';
2
- export * from './classes/Package.js';
3
2
  export * from './classes/Manager.js';
3
+ export * from './classes/Package.js';
4
4
  export * from './classes/Registry.js';
5
5
  export * from './helpers/api.js';
6
6
  export * from './helpers/config.js';
@@ -5,10 +5,11 @@
5
5
  // Classes
6
6
  export * from './classes/Config.js';
7
7
  // export * from './classes/ConfigLocal.js';
8
- export * from './classes/Package.js';
9
8
  export * from './classes/Manager.js';
10
9
  // export * from './classes/ManagerLocal.js';
10
+ export * from './classes/Package.js';
11
11
  export * from './classes/Registry.js';
12
+ // export * from './classes/RegistryLocal.js';
12
13
  // Helpers
13
14
  // export * from './helpers/admin.js'; // Admin is an independent script which should not be imported here.
14
15
  export * from './helpers/api.js';
package/build/index.d.ts CHANGED
@@ -1,9 +1,10 @@
1
1
  export * from './classes/Config.js';
2
2
  export * from './classes/ConfigLocal.js';
3
- export * from './classes/Package.js';
4
3
  export * from './classes/Manager.js';
5
4
  export * from './classes/ManagerLocal.js';
5
+ export * from './classes/Package.js';
6
6
  export * from './classes/Registry.js';
7
+ export * from './classes/RegistryLocal.js';
7
8
  export * from './helpers/api.js';
8
9
  export * from './helpers/config.js';
9
10
  export * from './helpers/configLocal.js';
package/build/index.js CHANGED
@@ -5,10 +5,11 @@
5
5
  // Classes
6
6
  export * from './classes/Config.js';
7
7
  export * from './classes/ConfigLocal.js';
8
- export * from './classes/Package.js';
9
8
  export * from './classes/Manager.js';
10
9
  export * from './classes/ManagerLocal.js';
10
+ export * from './classes/Package.js';
11
11
  export * from './classes/Registry.js';
12
+ export * from './classes/RegistryLocal.js';
12
13
  // Helpers
13
14
  // export * from './helpers/admin.js'; // Admin is an independent script which should not be imported here.
14
15
  export * from './helpers/api.js';
@@ -1,14 +1,14 @@
1
1
  export declare enum FileFormat {
2
- AppImage = "appimage",
3
- AppleDiskImage = "dmg",
4
- ApplePackage = "pkg",
5
- DebianPackage = "deb",
6
- ExecutableInstaller = "exe",
7
- RedHatPackage = "rpm",
8
- Tarball = "tar.gz",
9
- TarballLegacy = "tgz",
10
- WindowsInstaller = "msi",
11
- Zip = "zip",
2
+ AppImage = "appimage",// No headless automatic installation, avoid using
3
+ AppleDiskImage = "dmg",// Has to be mounted to access installer inside
4
+ ApplePackage = "pkg",// Installer
5
+ DebianPackage = "deb",// Installer
6
+ ExecutableInstaller = "exe",// Installer
7
+ RedHatPackage = "rpm",// Installer
8
+ Tarball = "tar.gz",// Archive
9
+ TarballLegacy = "tgz",// Archive
10
+ WindowsInstaller = "msi",// Installer
11
+ Zip = "zip",// Archive
12
12
  Zip7 = "7z"
13
13
  }
14
14
  export interface FileFormatOption {
@@ -1,3 +1,6 @@
1
+ // File formats have different advantages for users
2
+ // but some do not support headless automated installation
3
+ // which is required for a fully automated package manager.
1
4
  export var FileFormat;
2
5
  (function (FileFormat) {
3
6
  FileFormat["AppImage"] = "appimage";
@@ -1,6 +1,6 @@
1
- import { PluginInterface } from './Plugin.js';
2
- import { PresetInterface } from './Preset.js';
3
- import { ProjectInterface } from './Project.js';
1
+ import { PluginFile, PluginFileMap, PluginInterface } from './Plugin.js';
2
+ import { PresetFile, PresetFileMap, PresetInterface } from './Preset.js';
3
+ import { ProjectFile, ProjectFileMap, ProjectInterface } from './Project.js';
4
4
  import { License } from './License.js';
5
5
  export interface PackageInterface {
6
6
  slug: string;
@@ -24,6 +24,8 @@ export interface PackageBase {
24
24
  url: string;
25
25
  }
26
26
  export type PackageVersion = PluginInterface | PresetInterface | ProjectInterface;
27
+ export type PackageFile = PluginFile | PresetFile | ProjectFile;
28
+ export type PackageFileMap = PluginFileMap | PresetFileMap | ProjectFileMap;
27
29
  export interface PackageValidationField {
28
30
  name: string;
29
31
  type: string;
@@ -9,3 +9,6 @@ export interface PluginInterface extends PackageBase {
9
9
  export interface PluginFile extends FileInterface {
10
10
  contains: PluginFormat[];
11
11
  }
12
+ export interface PluginFileMap {
13
+ [key: string]: PluginFile[];
14
+ }
@@ -10,6 +10,9 @@ export interface PresetInterface extends PackageBase {
10
10
  export interface PresetFile extends FileInterface {
11
11
  contains: PresetFormat[];
12
12
  }
13
+ export interface PresetFileMap {
14
+ [key: string]: PresetFile[];
15
+ }
13
16
  export interface PresetPlugins {
14
17
  [slug: string]: string;
15
18
  }
@@ -10,6 +10,9 @@ export interface ProjectInterface extends PackageBase {
10
10
  export interface ProjectFile extends FileInterface {
11
11
  contains: ProjectFormat[];
12
12
  }
13
+ export interface ProjectFileMap {
14
+ [key: string]: ProjectFile[];
15
+ }
13
16
  export interface ProjectPlugins {
14
17
  [slug: string]: string;
15
18
  }
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@open-audio-stack/core",
3
- "version": "0.1.5",
3
+ "version": "0.1.7",
4
4
  "description": "Open-source audio plugin management software",
5
5
  "type": "module",
6
6
  "main": "./build/index.js",