diff --git a/.github/workflows/e2e-dev.yml b/.github/workflows/e2e-dev.yml
index 9e6a99aa..6be7de1f 100644
--- a/.github/workflows/e2e-dev.yml
+++ b/.github/workflows/e2e-dev.yml
@@ -1,78 +1,78 @@
name: E2E — Dev
on:
- push:
- branches: [develop]
+ push:
+ branches: [develop]
concurrency:
- group: e2e-dev-${{ github.sha }}
- cancel-in-progress: true
+ group: e2e-dev-${{ github.sha }}
+ cancel-in-progress: true
jobs:
- install:
- name: Install dependencies
- runs-on: ubuntu-latest
- timeout-minutes: 10
- steps:
- - uses: actions/checkout@v4
+ install:
+ name: Install dependencies
+ runs-on: ubuntu-latest
+ timeout-minutes: 10
+ steps:
+ - uses: actions/checkout@v4
- - name: Set up Node.js
- uses: actions/setup-node@v4
- with:
- node-version: '24'
- cache: 'npm'
- cache-dependency-path: puppeteer-tests/package-lock.json
+ - name: Set up Node.js
+ uses: actions/setup-node@v4
+ with:
+ node-version: "24"
+ cache: "npm"
+ cache-dependency-path: puppeteer-tests/package-lock.json
- - name: Install test dependencies
- working-directory: puppeteer-tests
- run: npm ci
+ - name: Install test dependencies
+ working-directory: puppeteer-tests
+ run: npm ci
- - name: Cache node_modules and Puppeteer browsers
- uses: actions/cache/save@v4
- with:
- path: |
- puppeteer-tests/node_modules
- ~/.cache/puppeteer
- key: nm-puppeteer-${{ runner.os }}-${{ hashFiles('puppeteer-tests/package-lock.json') }}
+ - name: Cache node_modules and Puppeteer browsers
+ uses: actions/cache/save@v4
+ with:
+ path: |
+ puppeteer-tests/node_modules
+ ~/.cache/puppeteer
+ key: nm-puppeteer-${{ runner.os }}-${{ hashFiles('puppeteer-tests/package-lock.json') }}
- e2e:
- name: E2E dev — ${{ matrix.suite }}
- needs: install
- runs-on: ubuntu-latest
- timeout-minutes: 10
+ e2e:
+ name: E2E dev — ${{ matrix.suite }}
+ needs: install
+ runs-on: ubuntu-latest
+ timeout-minutes: 10
- strategy:
- fail-fast: false
- matrix:
- suite: [home, editor]
+ strategy:
+ fail-fast: false
+ matrix:
+ suite: [home, editor]
- steps:
- - uses: actions/checkout@v4
+ steps:
+ - uses: actions/checkout@v4
- - name: Set up Node.js
- uses: actions/setup-node@v4
- with:
- node-version: '24'
+ - name: Set up Node.js
+ uses: actions/setup-node@v4
+ with:
+ node-version: "24"
- - name: Restore node_modules and Puppeteer browsers
- uses: actions/cache/restore@v4
- with:
- path: |
- puppeteer-tests/node_modules
- ~/.cache/puppeteer
- key: nm-puppeteer-${{ runner.os }}-${{ hashFiles('puppeteer-tests/package-lock.json') }}
+ - name: Restore node_modules and Puppeteer browsers
+ uses: actions/cache/restore@v4
+ with:
+ path: |
+ puppeteer-tests/node_modules
+ ~/.cache/puppeteer
+ key: nm-puppeteer-${{ runner.os }}-${{ hashFiles('puppeteer-tests/package-lock.json') }}
- - name: Run ${{ matrix.suite }} tests
- working-directory: puppeteer-tests
- run: node --test tests/${{ matrix.suite }}.js
- env:
- TARGET: dev
+ - name: Run ${{ matrix.suite }} tests
+ working-directory: puppeteer-tests
+ run: node --test tests/${{ matrix.suite }}.js
+ env:
+ TARGET: dev
- - name: Upload debug artifacts
- if: failure()
- uses: actions/upload-artifact@v4
- with:
- name: e2e-debug-dev-${{ matrix.suite }}
- path: puppeteer-tests/screenshots/
- retention-days: 7
- if-no-files-found: ignore
+ - name: Upload debug artifacts
+ if: failure()
+ uses: actions/upload-artifact@v4
+ with:
+ name: e2e-debug-dev-${{ matrix.suite }}
+ path: puppeteer-tests/screenshots/
+ retention-days: 7
+ if-no-files-found: ignore
diff --git a/.github/workflows/e2e-local.yml b/.github/workflows/e2e-local.yml
index df358c79..a40d77e4 100644
--- a/.github/workflows/e2e-local.yml
+++ b/.github/workflows/e2e-local.yml
@@ -1,91 +1,91 @@
name: E2E — Local
on:
- pull_request:
- types: [opened, synchronize, reopened]
- workflow_dispatch:
+ pull_request:
+ types: [opened, synchronize, reopened]
+ workflow_dispatch:
concurrency:
- group: e2e-local-${{ github.ref }}
- cancel-in-progress: true
+ group: e2e-local-${{ github.ref }}
+ cancel-in-progress: true
jobs:
- install:
- name: Install dependencies
- runs-on: ubuntu-latest
- timeout-minutes: 10
- steps:
- - uses: actions/checkout@v4
-
- - name: Set up Node.js
- uses: actions/setup-node@v4
- with:
- node-version: '24'
- cache: 'npm'
-
- - name: Install project dependencies
- run: npm ci
-
- - name: Install test dependencies
- working-directory: puppeteer-tests
- run: npm ci
-
- - name: Cache node_modules and Puppeteer browsers
- uses: actions/cache/save@v4
- with:
- path: |
- node_modules
- puppeteer-tests/node_modules
- ~/.cache/puppeteer
- key: nm-${{ runner.os }}-${{ hashFiles('package-lock.json', 'puppeteer-tests/package-lock.json') }}
-
- e2e:
- name: E2E local — ${{ matrix.suite }}
- needs: install
- runs-on: ubuntu-latest
- timeout-minutes: 15
-
- strategy:
- fail-fast: false
- matrix:
- suite: [home, editor]
-
- steps:
- - uses: actions/checkout@v4
-
- - name: Set up Node.js
- uses: actions/setup-node@v4
- with:
- node-version: '24'
-
- - name: Restore node_modules and Puppeteer browsers
- uses: actions/cache/restore@v4
- with:
- path: |
- node_modules
- puppeteer-tests/node_modules
- ~/.cache/puppeteer
- key: nm-${{ runner.os }}-${{ hashFiles('package-lock.json', 'puppeteer-tests/package-lock.json') }}
-
- - name: Start dev server
- run: npm run start -- --open false &
- env:
- BROWSER: none
-
- - name: Wait for dev server
- run: npx wait-on http://localhost:3000 --timeout 120000
-
- - name: Run ${{ matrix.suite }} tests
- working-directory: puppeteer-tests
- run: node --test tests/${{ matrix.suite }}.js
- env:
- TARGET: local
-
- - name: Upload debug artifacts
- if: failure()
- uses: actions/upload-artifact@v4
- with:
- name: e2e-debug-${{ matrix.suite }}
- path: puppeteer-tests/screenshots/
- retention-days: 7
- if-no-files-found: ignore
+ install:
+ name: Install dependencies
+ runs-on: ubuntu-latest
+ timeout-minutes: 10
+ steps:
+ - uses: actions/checkout@v4
+
+ - name: Set up Node.js
+ uses: actions/setup-node@v4
+ with:
+ node-version: "24"
+ cache: "npm"
+
+ - name: Install project dependencies
+ run: npm ci
+
+ - name: Install test dependencies
+ working-directory: puppeteer-tests
+ run: npm ci
+
+ - name: Cache node_modules and Puppeteer browsers
+ uses: actions/cache/save@v4
+ with:
+ path: |
+ node_modules
+ puppeteer-tests/node_modules
+ ~/.cache/puppeteer
+ key: nm-${{ runner.os }}-${{ hashFiles('package-lock.json', 'puppeteer-tests/package-lock.json') }}
+
+ e2e:
+ name: E2E local — ${{ matrix.suite }}
+ needs: install
+ runs-on: ubuntu-latest
+ timeout-minutes: 15
+
+ strategy:
+ fail-fast: false
+ matrix:
+ suite: [home, editor]
+
+ steps:
+ - uses: actions/checkout@v4
+
+ - name: Set up Node.js
+ uses: actions/setup-node@v4
+ with:
+ node-version: "24"
+
+ - name: Restore node_modules and Puppeteer browsers
+ uses: actions/cache/restore@v4
+ with:
+ path: |
+ node_modules
+ puppeteer-tests/node_modules
+ ~/.cache/puppeteer
+ key: nm-${{ runner.os }}-${{ hashFiles('package-lock.json', 'puppeteer-tests/package-lock.json') }}
+
+ - name: Start dev server
+ run: npm run start -- --open false &
+ env:
+ BROWSER: none
+
+ - name: Wait for dev server
+ run: npx wait-on http://localhost:3000 --timeout 120000
+
+ - name: Run ${{ matrix.suite }} tests
+ working-directory: puppeteer-tests
+ run: node --test tests/${{ matrix.suite }}.js
+ env:
+ TARGET: local
+
+ - name: Upload debug artifacts
+ if: failure()
+ uses: actions/upload-artifact@v4
+ with:
+ name: e2e-debug-${{ matrix.suite }}
+ path: puppeteer-tests/screenshots/
+ retention-days: 7
+ if-no-files-found: ignore
diff --git a/.github/workflows/e2e-prod.yml b/.github/workflows/e2e-prod.yml
index ef16c0da..6dc54890 100644
--- a/.github/workflows/e2e-prod.yml
+++ b/.github/workflows/e2e-prod.yml
@@ -1,78 +1,78 @@
name: E2E — Prod
on:
- push:
- branches: [main]
+ push:
+ branches: [main]
concurrency:
- group: e2e-prod-${{ github.sha }}
- cancel-in-progress: true
+ group: e2e-prod-${{ github.sha }}
+ cancel-in-progress: true
jobs:
- install:
- name: Install dependencies
- runs-on: ubuntu-latest
- timeout-minutes: 10
- steps:
- - uses: actions/checkout@v4
+ install:
+ name: Install dependencies
+ runs-on: ubuntu-latest
+ timeout-minutes: 10
+ steps:
+ - uses: actions/checkout@v4
- - name: Set up Node.js
- uses: actions/setup-node@v4
- with:
- node-version: '24'
- cache: 'npm'
- cache-dependency-path: puppeteer-tests/package-lock.json
+ - name: Set up Node.js
+ uses: actions/setup-node@v4
+ with:
+ node-version: "24"
+ cache: "npm"
+ cache-dependency-path: puppeteer-tests/package-lock.json
- - name: Install test dependencies
- working-directory: puppeteer-tests
- run: npm ci
+ - name: Install test dependencies
+ working-directory: puppeteer-tests
+ run: npm ci
- - name: Cache node_modules and Puppeteer browsers
- uses: actions/cache/save@v4
- with:
- path: |
- puppeteer-tests/node_modules
- ~/.cache/puppeteer
- key: nm-puppeteer-${{ runner.os }}-${{ hashFiles('puppeteer-tests/package-lock.json') }}
+ - name: Cache node_modules and Puppeteer browsers
+ uses: actions/cache/save@v4
+ with:
+ path: |
+ puppeteer-tests/node_modules
+ ~/.cache/puppeteer
+ key: nm-puppeteer-${{ runner.os }}-${{ hashFiles('puppeteer-tests/package-lock.json') }}
- e2e:
- name: E2E prod — ${{ matrix.suite }}
- needs: install
- runs-on: ubuntu-latest
- timeout-minutes: 10
+ e2e:
+ name: E2E prod — ${{ matrix.suite }}
+ needs: install
+ runs-on: ubuntu-latest
+ timeout-minutes: 10
- strategy:
- fail-fast: false
- matrix:
- suite: [home, editor]
+ strategy:
+ fail-fast: false
+ matrix:
+ suite: [home, editor]
- steps:
- - uses: actions/checkout@v4
+ steps:
+ - uses: actions/checkout@v4
- - name: Set up Node.js
- uses: actions/setup-node@v4
- with:
- node-version: '24'
+ - name: Set up Node.js
+ uses: actions/setup-node@v4
+ with:
+ node-version: "24"
- - name: Restore node_modules and Puppeteer browsers
- uses: actions/cache/restore@v4
- with:
- path: |
- puppeteer-tests/node_modules
- ~/.cache/puppeteer
- key: nm-puppeteer-${{ runner.os }}-${{ hashFiles('puppeteer-tests/package-lock.json') }}
+ - name: Restore node_modules and Puppeteer browsers
+ uses: actions/cache/restore@v4
+ with:
+ path: |
+ puppeteer-tests/node_modules
+ ~/.cache/puppeteer
+ key: nm-puppeteer-${{ runner.os }}-${{ hashFiles('puppeteer-tests/package-lock.json') }}
- - name: Run ${{ matrix.suite }} tests
- working-directory: puppeteer-tests
- run: node --test tests/${{ matrix.suite }}.js
- env:
- TARGET: prod
+ - name: Run ${{ matrix.suite }} tests
+ working-directory: puppeteer-tests
+ run: node --test tests/${{ matrix.suite }}.js
+ env:
+ TARGET: prod
- - name: Upload debug artifacts
- if: failure()
- uses: actions/upload-artifact@v4
- with:
- name: e2e-debug-prod-${{ matrix.suite }}
- path: puppeteer-tests/screenshots/
- retention-days: 7
- if-no-files-found: ignore
+ - name: Upload debug artifacts
+ if: failure()
+ uses: actions/upload-artifact@v4
+ with:
+ name: e2e-debug-prod-${{ matrix.suite }}
+ path: puppeteer-tests/screenshots/
+ retention-days: 7
+ if-no-files-found: ignore
diff --git a/.husky/pre-commit b/.husky/pre-commit
index a5fd8d85..bbbc8677 100755
--- a/.husky/pre-commit
+++ b/.husky/pre-commit
@@ -1,2 +1 @@
npm run precommit-hook
-cd puppeteer-tests && npm run lint && npm run format -- --check
diff --git a/README.md b/README.md
index 80e74fde..2f7d1fe0 100644
--- a/README.md
+++ b/README.md
@@ -1,6 +1,7 @@
# Csound Web IDE

+
> A browser-based IDE for the Csound audio programming language — write, run, and share Csound
> projects entirely in the browser, or install it as a native desktop app via Electron.
diff --git a/config/cors.json b/config/cors.json
index bd9d0dfb..f4521b13 100644
--- a/config/cors.json
+++ b/config/cors.json
@@ -1,7 +1,7 @@
[
- {
- "origin": ["*"],
- "method": ["GET"],
- "maxAgeSeconds": 3600
- }
-]
\ No newline at end of file
+ {
+ "origin": ["*"],
+ "method": ["GET"],
+ "maxAgeSeconds": 3600
+ }
+]
diff --git a/config/env.js b/config/env.js
index 09ec03c5..f1a703e5 100644
--- a/config/env.js
+++ b/config/env.js
@@ -1,28 +1,28 @@
-'use strict';
+"use strict";
-const fs = require('fs');
-const path = require('path');
-const paths = require('./paths');
+const fs = require("fs");
+const path = require("path");
+const paths = require("./paths");
// Make sure that including paths.js after env.js will read .env variables.
-delete require.cache[require.resolve('./paths')];
+delete require.cache[require.resolve("./paths")];
const NODE_ENV = process.env.NODE_ENV;
if (!NODE_ENV) {
- throw new Error(
- 'The NODE_ENV environment variable is required but was not specified.'
- );
+ throw new Error(
+ "The NODE_ENV environment variable is required but was not specified."
+ );
}
// https://github.com/bkeepers/dotenv#what-other-env-files-can-i-use
const dotenvFiles = [
- `${paths.dotenv}.${NODE_ENV}.local`,
- `${paths.dotenv}.${NODE_ENV}`,
- // Don't include `.env.local` for `test` environment
- // since normally you expect tests to produce the same
- // results for everyone
- NODE_ENV !== 'test' && `${paths.dotenv}.local`,
- paths.dotenv,
+ `${paths.dotenv}.${NODE_ENV}.local`,
+ `${paths.dotenv}.${NODE_ENV}`,
+ // Don't include `.env.local` for `test` environment
+ // since normally you expect tests to produce the same
+ // results for everyone
+ NODE_ENV !== "test" && `${paths.dotenv}.local`,
+ paths.dotenv
].filter(Boolean);
// Load environment variables from .env* files. Suppress warnings using silent
@@ -30,14 +30,14 @@ const dotenvFiles = [
// that have already been set. Variable expansion is supported in .env files.
// https://github.com/motdotla/dotenv
// https://github.com/motdotla/dotenv-expand
-dotenvFiles.forEach(dotenvFile => {
- if (fs.existsSync(dotenvFile)) {
- require('dotenv-expand')(
- require('dotenv').config({
- path: dotenvFile,
- })
- );
- }
+dotenvFiles.forEach((dotenvFile) => {
+ if (fs.existsSync(dotenvFile)) {
+ require("dotenv-expand")(
+ require("dotenv").config({
+ path: dotenvFile
+ })
+ );
+ }
});
// We support resolving modules according to `NODE_PATH`.
@@ -50,52 +50,52 @@ dotenvFiles.forEach(dotenvFile => {
// https://github.com/facebook/create-react-app/issues/1023#issuecomment-265344421
// We also resolve them to make sure all tools using them work consistently.
const appDirectory = fs.realpathSync(process.cwd());
-process.env.NODE_PATH = (process.env.NODE_PATH || '')
- .split(path.delimiter)
- .filter(folder => folder && !path.isAbsolute(folder))
- .map(folder => path.resolve(appDirectory, folder))
- .join(path.delimiter);
+process.env.NODE_PATH = (process.env.NODE_PATH || "")
+ .split(path.delimiter)
+ .filter((folder) => folder && !path.isAbsolute(folder))
+ .map((folder) => path.resolve(appDirectory, folder))
+ .join(path.delimiter);
// Grab NODE_ENV and REACT_APP_* environment variables and prepare them to be
// injected into the application via DefinePlugin in webpack configuration.
const REACT_APP = /^REACT_APP_/i;
function getClientEnvironment(publicUrl) {
- const raw = Object.keys(process.env)
- .filter(key => REACT_APP.test(key))
- .reduce(
- (env, key) => {
- env[key] = process.env[key];
- return env;
- },
- {
- // Useful for determining whether we’re running in production mode.
- // Most importantly, it switches React into the correct mode.
- NODE_ENV: process.env.NODE_ENV || 'development',
- // Useful for resolving the correct path to static assets in `public`.
- // For example,
.
- // This should only be used as an escape hatch. Normally you would put
- // images into the `src` and `import` them in code to get their paths.
- PUBLIC_URL: publicUrl,
- // We support configuring the sockjs pathname during development.
- // These settings let a developer run multiple simultaneous projects.
- // They are used as the connection `hostname`, `pathname` and `port`
- // in webpackHotDevClient. They are used as the `sockHost`, `sockPath`
- // and `sockPort` options in webpack-dev-server.
- WDS_SOCKET_HOST: process.env.WDS_SOCKET_HOST,
- WDS_SOCKET_PATH: process.env.WDS_SOCKET_PATH,
- WDS_SOCKET_PORT: process.env.WDS_SOCKET_PORT,
- }
- );
- // Stringify all values so we can feed into webpack DefinePlugin
- const stringified = {
- 'process.env': Object.keys(raw).reduce((env, key) => {
- env[key] = JSON.stringify(raw[key]);
- return env;
- }, {}),
- };
+ const raw = Object.keys(process.env)
+ .filter((key) => REACT_APP.test(key))
+ .reduce(
+ (env, key) => {
+ env[key] = process.env[key];
+ return env;
+ },
+ {
+ // Useful for determining whether we’re running in production mode.
+ // Most importantly, it switches React into the correct mode.
+ NODE_ENV: process.env.NODE_ENV || "development",
+ // Useful for resolving the correct path to static assets in `public`.
+ // For example,
.
+ // This should only be used as an escape hatch. Normally you would put
+ // images into the `src` and `import` them in code to get their paths.
+ PUBLIC_URL: publicUrl,
+ // We support configuring the sockjs pathname during development.
+ // These settings let a developer run multiple simultaneous projects.
+ // They are used as the connection `hostname`, `pathname` and `port`
+ // in webpackHotDevClient. They are used as the `sockHost`, `sockPath`
+ // and `sockPort` options in webpack-dev-server.
+ WDS_SOCKET_HOST: process.env.WDS_SOCKET_HOST,
+ WDS_SOCKET_PATH: process.env.WDS_SOCKET_PATH,
+ WDS_SOCKET_PORT: process.env.WDS_SOCKET_PORT
+ }
+ );
+ // Stringify all values so we can feed into webpack DefinePlugin
+ const stringified = {
+ "process.env": Object.keys(raw).reduce((env, key) => {
+ env[key] = JSON.stringify(raw[key]);
+ return env;
+ }, {})
+ };
- return { raw, stringified };
+ return { raw, stringified };
}
module.exports = getClientEnvironment;
diff --git a/config/getHttpsConfig.js b/config/getHttpsConfig.js
index 013d493c..5d744d86 100644
--- a/config/getHttpsConfig.js
+++ b/config/getHttpsConfig.js
@@ -1,66 +1,66 @@
-'use strict';
+"use strict";
-const fs = require('fs');
-const path = require('path');
-const crypto = require('crypto');
-const chalk = require('react-dev-utils/chalk');
-const paths = require('./paths');
+const fs = require("fs");
+const path = require("path");
+const crypto = require("crypto");
+const chalk = require("react-dev-utils/chalk");
+const paths = require("./paths");
// Ensure the certificate and key provided are valid and if not
// throw an easy to debug error
function validateKeyAndCerts({ cert, key, keyFile, crtFile }) {
- let encrypted;
- try {
- // publicEncrypt will throw an error with an invalid cert
- encrypted = crypto.publicEncrypt(cert, Buffer.from('test'));
- } catch (err) {
- throw new Error(
- `The certificate "${chalk.yellow(crtFile)}" is invalid.\n${err.message}`
- );
- }
+ let encrypted;
+ try {
+ // publicEncrypt will throw an error with an invalid cert
+ encrypted = crypto.publicEncrypt(cert, Buffer.from("test"));
+ } catch (err) {
+ throw new Error(
+ `The certificate "${chalk.yellow(crtFile)}" is invalid.\n${err.message}`
+ );
+ }
- try {
- // privateDecrypt will throw an error with an invalid key
- crypto.privateDecrypt(key, encrypted);
- } catch (err) {
- throw new Error(
- `The certificate key "${chalk.yellow(keyFile)}" is invalid.\n${
- err.message
- }`
- );
- }
+ try {
+ // privateDecrypt will throw an error with an invalid key
+ crypto.privateDecrypt(key, encrypted);
+ } catch (err) {
+ throw new Error(
+ `The certificate key "${chalk.yellow(keyFile)}" is invalid.\n${
+ err.message
+ }`
+ );
+ }
}
// Read file and throw an error if it doesn't exist
function readEnvFile(file, type) {
- if (!fs.existsSync(file)) {
- throw new Error(
- `You specified ${chalk.cyan(
- type
- )} in your env, but the file "${chalk.yellow(file)}" can't be found.`
- );
- }
- return fs.readFileSync(file);
+ if (!fs.existsSync(file)) {
+ throw new Error(
+ `You specified ${chalk.cyan(
+ type
+ )} in your env, but the file "${chalk.yellow(file)}" can't be found.`
+ );
+ }
+ return fs.readFileSync(file);
}
// Get the https config
// Return cert files if provided in env, otherwise just true or false
function getHttpsConfig() {
- const { SSL_CRT_FILE, SSL_KEY_FILE, HTTPS } = process.env;
- const isHttps = HTTPS === 'true';
+ const { SSL_CRT_FILE, SSL_KEY_FILE, HTTPS } = process.env;
+ const isHttps = HTTPS === "true";
- if (isHttps && SSL_CRT_FILE && SSL_KEY_FILE) {
- const crtFile = path.resolve(paths.appPath, SSL_CRT_FILE);
- const keyFile = path.resolve(paths.appPath, SSL_KEY_FILE);
- const config = {
- cert: readEnvFile(crtFile, 'SSL_CRT_FILE'),
- key: readEnvFile(keyFile, 'SSL_KEY_FILE'),
- };
+ if (isHttps && SSL_CRT_FILE && SSL_KEY_FILE) {
+ const crtFile = path.resolve(paths.appPath, SSL_CRT_FILE);
+ const keyFile = path.resolve(paths.appPath, SSL_KEY_FILE);
+ const config = {
+ cert: readEnvFile(crtFile, "SSL_CRT_FILE"),
+ key: readEnvFile(keyFile, "SSL_KEY_FILE")
+ };
- validateKeyAndCerts({ ...config, keyFile, crtFile });
- return config;
- }
- return isHttps;
+ validateKeyAndCerts({ ...config, keyFile, crtFile });
+ return config;
+ }
+ return isHttps;
}
module.exports = getHttpsConfig;
diff --git a/config/paths.js b/config/paths.js
index 4a337982..1292a45d 100644
--- a/config/paths.js
+++ b/config/paths.js
@@ -1,13 +1,13 @@
-'use strict';
+"use strict";
-const path = require('path');
-const fs = require('fs');
-const getPublicUrlOrPath = require('react-dev-utils/getPublicUrlOrPath');
+const path = require("path");
+const fs = require("fs");
+const getPublicUrlOrPath = require("react-dev-utils/getPublicUrlOrPath");
// Make sure any symlinks in the project folder are resolved:
// https://github.com/facebook/create-react-app/issues/637
const appDirectory = fs.realpathSync(process.cwd());
-const resolveApp = relativePath => path.resolve(appDirectory, relativePath);
+const resolveApp = (relativePath) => path.resolve(appDirectory, relativePath);
// We use `PUBLIC_URL` environment variable or "homepage" field to infer
// "public path" at which the app is served.
@@ -16,57 +16,55 @@ const resolveApp = relativePath => path.resolve(appDirectory, relativePath);
// We can't use a relative path in HTML because we don't want to load something
// like /todos/42/static/js/bundle.7289d.js. We have to know the root.
const publicUrlOrPath = getPublicUrlOrPath(
- process.env.NODE_ENV === 'development',
- require(resolveApp('package.json')).homepage,
- process.env.PUBLIC_URL
+ process.env.NODE_ENV === "development",
+ require(resolveApp("package.json")).homepage,
+ process.env.PUBLIC_URL
);
const moduleFileExtensions = [
- 'web.mjs',
- 'mjs',
- 'web.js',
- 'js',
- 'web.ts',
- 'ts',
- 'web.tsx',
- 'tsx',
- 'json',
- 'web.jsx',
- 'jsx',
+ "web.mjs",
+ "mjs",
+ "web.js",
+ "js",
+ "web.ts",
+ "ts",
+ "web.tsx",
+ "tsx",
+ "json",
+ "web.jsx",
+ "jsx"
];
// Resolve file paths in the same order as webpack
const resolveModule = (resolveFn, filePath) => {
- const extension = moduleFileExtensions.find(extension =>
- fs.existsSync(resolveFn(`${filePath}.${extension}`))
- );
+ const extension = moduleFileExtensions.find((extension) =>
+ fs.existsSync(resolveFn(`${filePath}.${extension}`))
+ );
- if (extension) {
- return resolveFn(`${filePath}.${extension}`);
- }
+ if (extension) {
+ return resolveFn(`${filePath}.${extension}`);
+ }
- return resolveFn(`${filePath}.js`);
+ return resolveFn(`${filePath}.js`);
};
// config after eject: we're in ./config/
module.exports = {
- dotenv: resolveApp('.env'),
- appPath: resolveApp('.'),
- appBuild: resolveApp('dist'),
- appPublic: resolveApp('public'),
- appHtml: resolveApp('public/index.html'),
- appIndexJs: resolveModule(resolveApp, 'src/index'),
- appPackageJson: resolveApp('package.json'),
- appSrc: resolveApp('src'),
- appTsConfig: resolveApp('tsconfig.json'),
- appJsConfig: resolveApp('jsconfig.json'),
- yarnLockFile: resolveApp('yarn.lock'),
- testsSetup: resolveModule(resolveApp, 'src/setupTests'),
- proxySetup: resolveApp('src/setupProxy.js'),
- appNodeModules: resolveApp('node_modules'),
- publicUrlOrPath,
+ dotenv: resolveApp(".env"),
+ appPath: resolveApp("."),
+ appBuild: resolveApp("dist"),
+ appPublic: resolveApp("public"),
+ appHtml: resolveApp("public/index.html"),
+ appIndexJs: resolveModule(resolveApp, "src/index"),
+ appPackageJson: resolveApp("package.json"),
+ appSrc: resolveApp("src"),
+ appTsConfig: resolveApp("tsconfig.json"),
+ appJsConfig: resolveApp("jsconfig.json"),
+ yarnLockFile: resolveApp("yarn.lock"),
+ testsSetup: resolveModule(resolveApp, "src/setupTests"),
+ proxySetup: resolveApp("src/setupProxy.js"),
+ appNodeModules: resolveApp("node_modules"),
+ publicUrlOrPath
};
-
-
module.exports.moduleFileExtensions = moduleFileExtensions;
diff --git a/config/pnpTs.js b/config/pnpTs.js
index d1b0539f..938d9a54 100644
--- a/config/pnpTs.js
+++ b/config/pnpTs.js
@@ -1,35 +1,35 @@
-'use strict';
+"use strict";
-const { resolveModuleName } = require('ts-pnp');
+const { resolveModuleName } = require("ts-pnp");
exports.resolveModuleName = (
- typescript,
- moduleName,
- containingFile,
- compilerOptions,
- resolutionHost
-) => {
- return resolveModuleName(
+ typescript,
moduleName,
containingFile,
compilerOptions,
- resolutionHost,
- typescript.resolveModuleName
- );
+ resolutionHost
+) => {
+ return resolveModuleName(
+ moduleName,
+ containingFile,
+ compilerOptions,
+ resolutionHost,
+ typescript.resolveModuleName
+ );
};
exports.resolveTypeReferenceDirective = (
- typescript,
- moduleName,
- containingFile,
- compilerOptions,
- resolutionHost
-) => {
- return resolveModuleName(
+ typescript,
moduleName,
containingFile,
compilerOptions,
- resolutionHost,
- typescript.resolveTypeReferenceDirective
- );
+ resolutionHost
+) => {
+ return resolveModuleName(
+ moduleName,
+ containingFile,
+ compilerOptions,
+ resolutionHost,
+ typescript.resolveTypeReferenceDirective
+ );
};
diff --git a/docs/developer.md b/docs/developer.md
index 42f2279c..429c6f20 100644
--- a/docs/developer.md
+++ b/docs/developer.md
@@ -6,35 +6,32 @@
### Overview
-* Firebase Authentication: user identity
-* Firebase Database: Cloud Firestore or Realtime Database?
-* Firebase Storage: for storage of binaries (ogg, wav, mp3)
-* Firebase Hosting: for hosting the site
+- Firebase Authentication: user identity
+- Firebase Database: Cloud Firestore or Realtime Database?
+- Firebase Storage: for storage of binaries (ogg, wav, mp3)
+- Firebase Hosting: for hosting the site
### Data
-* Projects have files and directories
-* Files may be textual: CSD, ORC, TXT, MD (, HTML, JS)
-* Resources: OGG, MP3, WAV
+- Projects have files and directories
+- Files may be textual: CSD, ORC, TXT, MD (, HTML, JS)
+- Resources: OGG, MP3, WAV
Firestore DB layout
/users/username
/projects/projectname -- collection file refs which have name and URI (FirebaseStorage URI)
-/collections/collectionname
+/collections/collectionname
project files as binary - stored in Firebase Storage
-
### URL Structure
-* /[user-name]
-* /[user-name]/[project-name]
-* /[user-name]/[project-name]/edit
-* /[user-name]/[project-name]/[file-name]
-* /[user-name]/[collections]
-
-
+- /[user-name]
+- /[user-name]/[project-name]
+- /[user-name]/[project-name]/edit
+- /[user-name]/[project-name]/[file-name]
+- /[user-name]/[collections]
@@ -42,52 +39,48 @@ project files as binary - stored in Firebase Storage
### Technologies
-* npm/yarn
-* React
-* Redux
-* Firebase
-* Csound
-
+- npm/yarn
+- React
+- Redux
+- Firebase
+- Csound
### Coding Practice
-### Features
-
-* IDE-like with project file tree on left (see Codepen.io Projects)
-* Client-side code: user selects a file in file tree, we have mime-type like system to identify type, open editor for type (text editor with different hilighting, playback interface for auditioning audio files)
-* Project can have "main" CSD file set
-* Project can have multiple CSD files (maybe one for realtime, one for disk, etc.). See csound-live-code project for example.
-* User can render to "disk" which will render to local filesystem. This will need to render to Emscripten FS, which is also where we will be mapping our project files to in memory. We should consider having a local area mapped to a separate peer folder to the project folder that user can render to so that and output render doesn't get added to project and synced back to firebase.
+### Features
+- IDE-like with project file tree on left (see Codepen.io Projects)
+- Client-side code: user selects a file in file tree, we have mime-type like system to identify type, open editor for type (text editor with different hilighting, playback interface for auditioning audio files)
+- Project can have "main" CSD file set
+- Project can have multiple CSD files (maybe one for realtime, one for disk, etc.). See csound-live-code project for example.
+- User can render to "disk" which will render to local filesystem. This will need to render to Emscripten FS, which is also where we will be mapping our project files to in memory. We should consider having a local area mapped to a separate peer folder to the project folder that user can render to so that and output render doesn't get added to project and synced back to firebase.
### Milestone 1
-* User can start a new project
-* User can name project (must be unique)
-* User can add .orc file
-* User can add .sco file
-* User can add .csd file
-* User can use \#include and files include correctly
-* User can start rendering with CSD
-* User can eval to live code
-* User can save project (or just have auto-save)
-* User can mark project public/private
+- User can start a new project
+- User can name project (must be unique)
+- User can add .orc file
+- User can add .sco file
+- User can add .csd file
+- User can use \#include and files include correctly
+- User can start rendering with CSD
+- User can eval to live code
+- User can save project (or just have auto-save)
+- User can mark project public/private
### Milestone 2
-* User can clone project
-* User can fork project (with history)
-
+- User can clone project
+- User can fork project (with history)
### Desktop
-* Electron application
-* Look at NPM packaging for WebCsound? (is this necessary?)
-* Another option is Progressive Web App (PWA)
-
+- Electron application
+- Look at NPM packaging for WebCsound? (is this necessary?)
+- Another option is Progressive Web App (PWA)
## Brainstorming
-* Loading .orc from external URL would be very handy (see Codepen, jsfiddle, etc.)
+- Loading .orc from external URL would be very handy (see Codepen, jsfiddle, etc.)
diff --git a/functions/README.md b/functions/README.md
index a4a29382..71297765 100644
--- a/functions/README.md
+++ b/functions/README.md
@@ -1,10 +1,12 @@
## Installation
+
1. `npm install -g firebase-tools` (provides firebase-cli)
2. Login via google OAuth by typing `firebase login`
3. confirm that you're logged in by typing `firebase list`
4. Activate a default project from your google-appengine projects by typing `firebase use --add`.
## Useage
+
### Scope
```
@@ -21,14 +23,16 @@ When developing run `firebase serve --only functions`
When deploying run `firebase deploy --only functions`
Watch the logs from the command line with firebase functions:log
-
## Understanding the firebase-cli
+
Firebase is pretty strict on the directory structure. All cloud functions must be uploaded from one .js file from the functions directory.
## Troubleshoot
+
- Read the firebase-debug.log file when something crashes
- Common tip is to try `npm install -g @google-cloud/functions-emulator` for strange errors
## Online resources
+
- https://github.com/firebase/functions-samples
- https://firebase.google.com/docs/functions/firestore-events
diff --git a/functions/backup/migrate.js b/functions/backup/migrate.js
index c62c5801..f7426d6e 100644
--- a/functions/backup/migrate.js
+++ b/functions/backup/migrate.js
@@ -4,8 +4,9 @@ const R = require("ramda");
const newTimestamp = admin.firestore.FieldValue.serverTimestamp;
-const serviceAccountCredentials = require(process.env
- .GOOGLE_APPLICATION_CREDENTIALS);
+const serviceAccountCredentials = require(
+ process.env.GOOGLE_APPLICATION_CREDENTIALS
+);
async function asyncForEach(array, callback) {
for (let index = 0; index < array.length; index++) {
@@ -21,13 +22,10 @@ const defaultApp = admin.initializeApp({
// projectsCount
const migration2020_1 = async () => {
const batch = admin.firestore().batch();
- const allUsers = await admin
- .firestore()
- .collection("usernames")
- .get();
- const allUserIds = await allUsers.docs.map(x => x.data().userUid);
+ const allUsers = await admin.firestore().collection("usernames").get();
+ const allUserIds = await allUsers.docs.map((x) => x.data().userUid);
- await asyncForEach(allUserIds, async userUid => {
+ await asyncForEach(allUserIds, async (userUid) => {
const countRef = await admin
.firestore()
.collection("projectsCount")
@@ -58,13 +56,10 @@ const migration2020_1 = async () => {
// followersCount and followingCount
const migration2020_2 = async () => {
const batch = admin.firestore().batch();
- const allUsers = await admin
- .firestore()
- .collection("usernames")
- .get();
- const allUserIds = await allUsers.docs.map(x => x.data().userUid);
+ const allUsers = await admin.firestore().collection("usernames").get();
+ const allUserIds = await allUsers.docs.map((x) => x.data().userUid);
- await asyncForEach(allUserIds, async userUid => {
+ await asyncForEach(allUserIds, async (userUid) => {
const followersCountRef = await admin
.firestore()
.collection("followersCount")
@@ -102,12 +97,9 @@ const migration2020_2 = async () => {
// projectCreated timestamp
const migration2020_3 = async () => {
const batch = admin.firestore().batch();
- const allProjectsRef = await admin
- .firestore()
- .collection("projects")
- .get();
+ const allProjectsRef = await admin.firestore().collection("projects").get();
- await asyncForEach(allProjectsRef.docs, async projectSnap => {
+ await asyncForEach(allProjectsRef.docs, async (projectSnap) => {
const projectUid = projectSnap.id;
const data = projectSnap.data();
@@ -138,10 +130,7 @@ const migration2020_3 = async () => {
// profileStars
const migration2020_4 = async () => {
const batch = admin.firestore().batch();
- const allStarsRef = await admin
- .firestore()
- .collection("stars")
- .get();
+ const allStarsRef = await admin.firestore().collection("stars").get();
const allStars = allStarsRef.docs.reduce((a, doc) => {
const data = doc.data();
@@ -158,7 +147,7 @@ const migration2020_4 = async () => {
allUserIds
);
}, {});
- await asyncForEach(R.keys(allStars), async userID => {
+ await asyncForEach(R.keys(allStars), async (userID) => {
const starsMap = allStars[userID];
const profileStarsRef = await admin
.firestore()
diff --git a/functions/src/popular_artists.ts b/functions/src/popular_artists.ts
index 457d2c59..5ea7ad0b 100644
--- a/functions/src/popular_artists.ts
+++ b/functions/src/popular_artists.ts
@@ -21,10 +21,7 @@ const countStars = (value: unknown): number => {
export const popularArtists = onCall<{ count: number }>(async ({ data }) => {
const requestedCount = Math.max(1, Math.min(50, data?.count || 8));
- if (
- cachedArtists.length === 0 ||
- Date.now() - lastUpdate > CACHE_TTL
- ) {
+ if (cachedArtists.length === 0 || Date.now() - lastUpdate > CACHE_TTL) {
const db = admin.firestore();
const [projectsSnapshot, starsSnapshot] = await Promise.all([
diff --git a/package.json b/package.json
index b64698eb..8aefbc72 100644
--- a/package.json
+++ b/package.json
@@ -20,7 +20,8 @@
"electron:dev": "concurrently \"BROWSER=none npm run start\" \"npx wait-on http-get://127.0.0.1:3000 && ELECTRON_IS_DEV=1 npx electron .\"",
"deploy": "./node_modules/.bin/firebase deploy -P default --token=$FIREBASE_TOKEN",
"deploy:dev": "./node_modules/.bin/firebase deploy -P develop --token=$FIREBASE_TOKEN",
- "precommit-hook": "npm run lint && npm run typecheck && npm run format:check",
+ "precommit-hook:puppeteer": "cd puppeteer-tests && npm run lint && npm run format -- --check",
+ "precommit-hook": "npm run lint && npm run typecheck && npm run format:check && npm run precommit-hook:puppeteer",
"prepare": "husky"
},
"dependencies": {
diff --git a/public/csound-no-audio.js b/public/csound-no-audio.js
index 946d1447..a827e8db 100644
--- a/public/csound-no-audio.js
+++ b/public/csound-no-audio.js
@@ -3,689 +3,12529 @@
Copyright The Closure Library Authors.
SPDX-License-Identifier: Apache-2.0
*/
-var $jscomp=$jscomp||{};$jscomp.scope={};var COMPILED=!0,goog=goog||{};goog.global=this||self;goog.exportPath_=function(a,b,c,d){a=a.split(".");d=d||goog.global;a[0]in d||"undefined"==typeof d.execScript||d.execScript("var "+a[0]);for(var e;a.length&&(e=a.shift());)if(a.length||void 0===b)d=d[e]&&d[e]!==Object.prototype[e]?d[e]:d[e]={};else if(!c&&goog.isObject(b)&&goog.isObject(d[e]))for(var f in b)b.hasOwnProperty(f)&&(d[e][f]=b[f]);else d[e]=b};
-goog.define=function(a,b){if(!COMPILED){var c=goog.global.CLOSURE_UNCOMPILED_DEFINES,d=goog.global.CLOSURE_DEFINES;c&&void 0===c.nodeType&&Object.prototype.hasOwnProperty.call(c,a)?b=c[a]:d&&void 0===d.nodeType&&Object.prototype.hasOwnProperty.call(d,a)&&(b=d[a])}return b};goog.FEATURESET_YEAR=2020;goog.DEBUG=!0;goog.LOCALE="en";goog.getLocale=function(){return goog.LOCALE};goog.TRUSTED_SITE=!0;goog.DISALLOW_TEST_ONLY_CODE=COMPILED&&!goog.DEBUG;goog.ENABLE_CHROME_APP_SAFE_SCRIPT_LOADING=!1;
-goog.provide=function(a){if(goog.isInModuleLoader_())throw Error("goog.provide cannot be used within a module.");if(!COMPILED&&goog.isProvided_(a))throw Error('Namespace "'+a+'" already declared.');goog.constructNamespace_(a)};goog.constructNamespace_=function(a,b,c){if(!COMPILED){delete goog.implicitNamespaces_[a];for(var d=a;(d=d.substring(0,d.lastIndexOf(".")))&&!goog.getObjectByName(d);)goog.implicitNamespaces_[d]=!0}goog.exportPath_(a,b,c)};goog.NONCE_PATTERN_=/^[\w+/_-]+[=]{0,2}$/;
-goog.getScriptNonce_=function(a){a=(a||goog.global).document;return(a=a.querySelector&&a.querySelector("script[nonce]"))&&(a=a.nonce||a.getAttribute("nonce"))&&goog.NONCE_PATTERN_.test(a)?a:""};goog.VALID_MODULE_RE_=/^[a-zA-Z_$][a-zA-Z0-9._$]*$/;
-goog.module=function(a){if("string"!==typeof a||!a||-1==a.search(goog.VALID_MODULE_RE_))throw Error("Invalid module identifier");if(!goog.isInGoogModuleLoader_())throw Error("Module "+a+" has been loaded incorrectly. Note, modules cannot be loaded as normal scripts. They require some kind of pre-processing step. You're likely trying to load a module via a script tag or as a part of a concatenated bundle without rewriting the module. For more info see: https://github.com/google/closure-library/wiki/goog.module:-an-ES6-module-like-alternative-to-goog.provide.");if(goog.moduleLoaderState_.moduleName)throw Error("goog.module may only be called once per module.");
-goog.moduleLoaderState_.moduleName=a;if(!COMPILED){if(goog.isProvided_(a))throw Error('Namespace "'+a+'" already declared.');delete goog.implicitNamespaces_[a]}};goog.module.get=function(a){return goog.module.getInternal_(a)};goog.module.getInternal_=function(a){if(!COMPILED){if(a in goog.loadedModules_)return goog.loadedModules_[a].exports;if(!goog.implicitNamespaces_[a])return a=goog.getObjectByName(a),null!=a?a:null}return null};goog.ModuleType={ES6:"es6",GOOG:"goog"};goog.moduleLoaderState_=null;
-goog.isInModuleLoader_=function(){return goog.isInGoogModuleLoader_()||goog.isInEs6ModuleLoader_()};goog.isInGoogModuleLoader_=function(){return!!goog.moduleLoaderState_&&goog.moduleLoaderState_.type==goog.ModuleType.GOOG};goog.isInEs6ModuleLoader_=function(){if(goog.moduleLoaderState_&&goog.moduleLoaderState_.type==goog.ModuleType.ES6)return!0;var a=goog.global.$jscomp;return a?"function"!=typeof a.getCurrentModulePath?!1:!!a.getCurrentModulePath():!1};
-goog.module.declareLegacyNamespace=function(){if(!COMPILED&&!goog.isInGoogModuleLoader_())throw Error("goog.module.declareLegacyNamespace must be called from within a goog.module");if(!COMPILED&&!goog.moduleLoaderState_.moduleName)throw Error("goog.module must be called prior to goog.module.declareLegacyNamespace.");goog.moduleLoaderState_.declareLegacyNamespace=!0};
-goog.declareModuleId=function(a){if(!COMPILED){if(!goog.isInEs6ModuleLoader_())throw Error("goog.declareModuleId may only be called from within an ES6 module");if(goog.moduleLoaderState_&&goog.moduleLoaderState_.moduleName)throw Error("goog.declareModuleId may only be called once per module.");if(a in goog.loadedModules_)throw Error('Module with namespace "'+a+'" already exists.');}if(goog.moduleLoaderState_)goog.moduleLoaderState_.moduleName=a;else{var b=goog.global.$jscomp;if(!b||"function"!=typeof b.getCurrentModulePath)throw Error('Module with namespace "'+
-a+'" has been loaded incorrectly.');b=b.require(b.getCurrentModulePath());goog.loadedModules_[a]={exports:b,type:goog.ModuleType.ES6,moduleId:a}}};goog.setTestOnly=function(a){if(goog.DISALLOW_TEST_ONLY_CODE)throw a=a||"",Error("Importing test-only code into non-debug environment"+(a?": "+a:"."));};goog.forwardDeclare=function(a){};COMPILED||(goog.isProvided_=function(a){return a in goog.loadedModules_||!goog.implicitNamespaces_[a]&&null!=goog.getObjectByName(a)},goog.implicitNamespaces_={"goog.module":!0});
-goog.getObjectByName=function(a,b){a=a.split(".");b=b||goog.global;for(var c=0;c>>0);goog.uidCounter_=0;goog.cloneObject=function(a){var b=goog.typeOf(a);if("object"==b||"array"==b){if("function"===typeof a.clone)return a.clone();if("undefined"!==typeof Map&&a instanceof Map)return new Map(a);if("undefined"!==typeof Set&&a instanceof Set)return new Set(a);b="array"==b?[]:{};for(var c in a)b[c]=goog.cloneObject(a[c]);return b}return a};goog.bindNative_=function(a,b,c){return a.call.apply(a.bind,arguments)};
-goog.bindJs_=function(a,b,c){if(!a)throw Error();if(2").replace(/'/g,"'").replace(/"/g,'"').replace(/&/g,"&"));b&&(a=a.replace(/\{\$([^}]+)}/g,function(d,e){return null!=b&&e in b?b[e]:d}));return a};goog.getMsgWithFallback=function(a,b){return a};goog.exportSymbol=function(a,b,c){goog.exportPath_(a,b,!0,c)};goog.exportProperty=function(a,b,c){a[b]=c};
-goog.inherits=function(a,b){function c(){}c.prototype=b.prototype;a.superClass_=b.prototype;a.prototype=new c;a.prototype.constructor=a;a.base=function(d,e,f){for(var g=Array(arguments.length-2),h=2;h\x3c/script>';f+="