Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Pure ES modules, vitest and TypeScript upgrade #18

Merged
merged 2 commits into from
Aug 12, 2024
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
12 changes: 6 additions & 6 deletions .github/workflows/release.yml
Original file line number Diff line number Diff line change
Expand Up @@ -3,7 +3,7 @@ name: Release
on:
push:
tags:
- "v*"
- 'v*'

jobs:
create_release:
Expand Down Expand Up @@ -66,8 +66,8 @@ jobs:
needs: [create_release, build_release]
runs-on: ubuntu-latest
steps:
- uses: eregon/publish-release@v1
env:
GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }}
with:
release_id: ${{ needs.create_release.outputs.upload_id }}
- uses: eregon/publish-release@v1
env:
GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }}
with:
release_id: ${{ needs.create_release.outputs.upload_id }}
1 change: 1 addition & 0 deletions .github/workflows/test.yml
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,7 @@ name: Test

on:
push:
pull_request:

jobs:
test_code:
Expand Down
55 changes: 25 additions & 30 deletions .gitignore
Original file line number Diff line number Diff line change
@@ -1,38 +1,33 @@
# See https://help.github.com/articles/ignoring-files/ for more about ignoring files.
# Logs
logs
*.log
npm-debug.log*

# dependencies
/node_modules
/.pnp
.pnp.js
# Dependencies
node_modules/

# testing
/coverage
# Coverage
coverage

# next.js
/.next/
/out/
/renderer/.next/
/renderer/out/
/main/
/dist/
# Transpiled files
build/
main/
out/
.next/
test/tool

# production
/build
# VS Code
.vscode
!.vscode/tasks.js

# misc
.DS_Store
*.pem
# JetBrains IDEs
.idea/

# debug
npm-debug.log*
yarn-debug.log*
yarn-error.log*
# Optional npm cache directory
.npm

# local env files
.env.local
.env.development.local
.env.test.local
.env.production.local
# Optional eslint cache
.eslintcache

# vercel
.vercel
# Misc
.DS_Store
5 changes: 0 additions & 5 deletions .prettierrc

This file was deleted.

15 changes: 15 additions & 0 deletions .prettierrc.json
Original file line number Diff line number Diff line change
@@ -0,0 +1,15 @@
{
"arrowParens": "avoid",
"bracketSpacing": true,
"endOfLine": "lf",
"bracketSameLine": false,
"jsxSingleQuote": false,
"printWidth": 120,
"proseWrap": "preserve",
"quoteProps": "as-needed",
"semi": true,
"singleQuote": true,
"tabWidth": 2,
"trailingComma": "all",
"useTabs": false
}
21 changes: 12 additions & 9 deletions README.md
Original file line number Diff line number Diff line change
@@ -1,4 +1,5 @@
# studiorack-app

![Release](https://github.com/studiorack/studiorack-app/workflows/Release/badge.svg)

Audio plugin app, searchable list of plugins to install and share.
Expand All @@ -17,28 +18,31 @@ Download the file and open to install the app on to your machine. Follow instruc

StudioRack App was built using:

* NodeJS 17.x
* TypeScript 4.x
* NextJS 12.x
* React 17.x
* Electron 15.x

- NodeJS 20.x
- TypeScript 5.x
- NextJS 14.x
- React 18.x
- Electron

## Installation

Install dependencies using:

npm install


## Usage

Run the development server using:

npm run dev

View the app in the application window opened automatically
View the site at:

http://localhost:3000

Get the api at:

http://localhost:3000/api/plugins

## Deployment

Expand All @@ -51,7 +55,6 @@ This will run an automated build and deploy process on GitHub Actions:

.github/workflows/release.yml


## Contact

For more information please contact kmturley
26 changes: 13 additions & 13 deletions electron-src/api.ts
Original file line number Diff line number Diff line change
@@ -1,52 +1,52 @@
import { ipcRenderer } from 'electron';
import { PluginInterface } from '@studiorack/core';
import { PluginVersion, PluginVersionLocal, ProjectVersionLocal, ProjectVersionPlugins } from '@studiorack/core';

function message(val: any) {
function message(val: string | object) {
return ipcRenderer.send('message', val);
}

async function pluginsGetLocal(): Promise<any> {
async function pluginsGetLocal(): Promise<PluginVersionLocal[]> {
return ipcRenderer.invoke('pluginsGetLocal');
}

async function pluginGetLocal(id: string): Promise<any> {
async function pluginGetLocal(id: string): Promise<PluginVersionLocal> {
return ipcRenderer.invoke('pluginGetLocal', id);
}

async function pluginInstall(plugin: PluginInterface): Promise<any> {
async function pluginInstall(plugin: PluginVersion): Promise<PluginVersionLocal> {
console.log('pluginInstall api', plugin);
return ipcRenderer.invoke('pluginInstall', plugin);
}

async function pluginsInstall(plugins: any): Promise<any> {
async function pluginsInstall(plugins: ProjectVersionPlugins): Promise<PluginVersionLocal[]> {
return ipcRenderer.invoke('pluginsInstall', plugins);
}

async function pluginUninstall(plugin: PluginInterface): Promise<any> {
async function pluginUninstall(plugin: PluginVersion): Promise<PluginVersionLocal> {
return ipcRenderer.invoke('pluginUninstall', plugin);
}

async function projectsGetLocal(): Promise<any> {
async function projectsGetLocal(): Promise<ProjectVersionLocal[]> {
return ipcRenderer.invoke('projectsGetLocal');
}

async function projectGetLocal(id: string): Promise<any> {
async function projectGetLocal(id: string): Promise<ProjectVersionLocal> {
return ipcRenderer.invoke('projectGetLocal', id);
}

async function projectOpen(path: string): Promise<any> {
async function projectOpen(path: string): Promise<ProjectVersionLocal> {
return ipcRenderer.invoke('projectOpen', path);
}

async function folderSelect(path: string): Promise<any> {
async function folderSelect(path: string): Promise<Electron.OpenDialogReturnValue> {
return ipcRenderer.invoke('folderSelect', path);
}

async function storeGet(key: string): Promise<any> {
async function storeGet(key: string): Promise<string> {
return ipcRenderer.invoke('storeGet', key);
}

async function storeSet(key: string, val: any): Promise<any> {
async function storeSet(key: string, val: string | object): Promise<string> {
return ipcRenderer.invoke('storeSet', key, val);
}

Expand Down
42 changes: 22 additions & 20 deletions electron-src/index.ts
Original file line number Diff line number Diff line change
Expand Up @@ -6,16 +6,16 @@ import { parse } from 'url';
import { BrowserWindow, app, dialog, session, ipcMain, IpcMainEvent, protocol } from 'electron';
import fixPath from 'fix-path';
import isDev from 'electron-is-dev';
import { createServer } from 'http';
import next from 'next';
import { createServer as createServerHttp, IncomingMessage, ServerResponse } from 'http';
import createServer from 'next/dist/server/next.js';

// Ensure Electron apps subprocess on macOS and Linux inherit system $PATH
fixPath();

// custom code
import {
fileOpen,
PluginInterface,
PluginVersion,
pluginGetLocal,
pluginInstall,
pluginsGetLocal,
Expand All @@ -25,14 +25,16 @@ import {
configGet,
ConfigInterface,
configSet,
ProjectVersionPlugins,
} from '@studiorack/core';

const DEFAULT_PAGE = 'projects';

// Prepare the renderer once the app is ready
app.on('ready', async () => {
// Use server-side rendering for both dev and production builds
const nextApp = next({
// @ts-expect-error incorrect types returned
const nextApp = createServer({
dev: isDev,
dir: join(app.getAppPath(), 'renderer'),
});
Expand All @@ -42,8 +44,8 @@ app.on('ready', async () => {
await nextApp.prepare();

// Create a new native HTTP server (which supports hot code reloading)
createServer((req: any, res: any) => {
const parsedUrl = parse(req.url, true);
createServerHttp((req: IncomingMessage, res: ServerResponse) => {
const parsedUrl = parse(req.url ? req.url : '', true);
requestHandler(req, res, parsedUrl);
}).listen(3000, () => {
console.log('> Ready on http://localhost:3000');
Expand All @@ -68,13 +70,13 @@ app.on('ready', async () => {
'Content-Security-Policy': [
`
default-src 'self' *.youtube.com;
connect-src 'self' *.github.io data: *.google-analytics.com;
connect-src 'self' github.com *.github.com *.github.io *.githubusercontent.com *.google-analytics.com *.doubleclick.net *.google.com *.googleapis.com data:;
font-src 'self' fonts.gstatic.com;
img-src 'self' github.com *.githubusercontent.com *.s3.amazonaws.com *.youtube.com data: media:;
media-src 'self' github.com *.githubusercontent.com *.s3.amazonaws.com *.youtube.com media:;
img-src 'self' github.com *.github.com *.github.io *.githubusercontent.com *.s3.amazonaws.com *.youtube.com *.ytimg.com data: media:;
media-src 'self' github.com *.github.com *.github.io *.githubusercontent.com *.s3.amazonaws.com *.youtube.com media:;
object-src 'none';
script-src 'self' 'unsafe-inline' 'unsafe-eval' *.doubleclick.net *.google.com *.gstatic.com *.googletagmanager.com *.google-analytics.com;
style-src 'self' 'unsafe-inline' fonts.googleapis.com
script-src 'self' 'unsafe-inline' 'unsafe-eval' github.com *.github.com *.github.io *.githubusercontent.com *.doubleclick.net *.google.com *.gstatic.com *.googletagmanager.com *.google-analytics.com;
style-src 'self' 'unsafe-inline' github.com *.github.com *.github.io *.githubusercontent.com fonts.googleapis.com
`,
],
},
Expand All @@ -85,7 +87,8 @@ app.on('ready', async () => {
width: isDev ? 1024 + 445 : 1024,
height: 768,
webPreferences: {
preload: join(app.getAppPath(), 'main', 'preload.js'),
sandbox: false,
preload: join(app.getAppPath(), 'main', 'preload.mjs'),
},
});

Expand All @@ -101,7 +104,7 @@ app.on('ready', async () => {
app.on('window-all-closed', app.quit);

// Listen the channel `message` and resend the received message to the renderer process
ipcMain.on('message', (event: IpcMainEvent, message: any) => {
ipcMain.on('message', (event: IpcMainEvent, message: string | object) => {
event.sender.send('message', message);
});

Expand All @@ -118,25 +121,24 @@ ipcMain.handle('pluginGetLocal', async (_event, id: string) => {
});

// Install plugin into root plugin folder locally
ipcMain.handle('pluginInstall', async (_event, plugin: PluginInterface) => {
ipcMain.handle('pluginInstall', async (_event, plugin: PluginVersion) => {
console.log('pluginInstall index', plugin);
return await pluginInstall(`${plugin.repo}/${plugin.id}`, plugin.version);
return await pluginInstall(plugin.id || '', plugin.version);
});

// Install plugin into root plugin folder locally
ipcMain.handle('pluginsInstall', async (_event, plugins: any) => {
ipcMain.handle('pluginsInstall', async (_event, plugins: ProjectVersionPlugins) => {
console.log('pluginsInstall', plugins);
const promises = Object.keys(plugins).map((pluginId: string) => {
const plugin = plugins[pluginId];
return pluginInstall(`${plugin.repo}/${plugin.id}`, plugin.version);
return pluginInstall(pluginId, plugins[pluginId]);
});
return Promise.all(promises);
});

// Uninstall plugin from root plugin folder locally
ipcMain.handle('pluginUninstall', async (_event, plugin) => {
console.log('pluginUninstall', plugin);
return await pluginUninstall(`${plugin.repo}/${plugin.id}`, plugin.version);
return await pluginUninstall(plugin.id || '', plugin.version);
});

// Get projects installed locally
Expand Down Expand Up @@ -178,7 +180,7 @@ ipcMain.handle('storeGet', async (_event, key: keyof ConfigInterface) => {
});

// Set user-specific setting
ipcMain.handle('storeSet', async (_event, key: keyof ConfigInterface, val: any) => {
ipcMain.handle('storeSet', async (_event, key: keyof ConfigInterface, val: string | object) => {
console.log('storeSet', key, val);
if (!key || !val) return;
return configSet(key, val);
Expand Down
6 changes: 6 additions & 0 deletions electron-src/preload.mjs
Original file line number Diff line number Diff line change
@@ -0,0 +1,6 @@
// This file is intentionally .mjs to ensure Electron treats it as an ES module.
// https://www.electronjs.org/docs/latest/tutorial/esm
import { contextBridge } from 'electron';
import api from './api.js';

contextBridge.exposeInMainWorld('electronAPI', api);
4 changes: 0 additions & 4 deletions electron-src/preload.ts

This file was deleted.

Loading
Loading