
Security News
Axios Maintainer Confirms Social Engineering Attack Behind npm Compromise
Axios compromise traced to social engineering, showing how attacks on maintainers can bypass controls and expose the broader software supply chain.
@educandu/dev-tools
Advanced tools
Development tools for educandu based systems and ESLint configuration shared between educandu projects.
npm i -g gulp-cliThe output of this repository is an npm package (@educandu/dev-tools).
$ yarn add @educandu/dev-tools --dev
$ yarn add eslint eslint-plugin-import eslint-plugin-react eslint-plugin-react-hooks vitest @vitest/coverage-v8 --dev
Create a file .eslint-config.cjs containing:
module.exports = require('@educandu/dev-tools/eslint-config');
Extend this file in your local .eslintrc.js, for example:
module.exports = {
extends: ['./.eslint-config.cjs'],
overrides: [...]
};
Use the dev tools in code as follows:
import {
buildTranslationsJson,
cliArgs,
createGithubRelease,
createLabelInJiraIssues,
createReleaseNotesFromCurrentTag,
downloadJson,
ensureIsValidSemverTag,
esbuild,
eslint,
getEnvAsString,
jest,
less,
LoadBalancedNodeProcessGroup,
MaildevContainer,
MinioContainer,
MongoContainer,
NodeProcess,
runInteractiveMigrations,
TunnelProxyContainer
} from '@educandu/dev-tools';
await buildTranslationsJson({
pattern: './**/*.yml',
outputFile: './translations.json'
});
const { currentTag, releaseNotes, jiraIssueKeys } = await createReleaseNotesFromCurrentTag({
jiraBaseUrl: cliArgs.jiraBaseUrl,
jiraProjectKeys: cliArgs.jiraProjectKeys.split(',')
});
await createGithubRelease({
githubToken: cliArgs.githubToken,
currentTag,
releaseNotes,
files: []
});
await createLabelInJiraIssues({
jiraBaseUrl: cliArgs.jiraBaseUrl,
jiraUser: cliArgs.jiraUser,
jiraApiKey: cliArgs.jiraApiKey,
jiraIssueKeys,
label: currentTag
});
await downloadJson('https://mydomain/my.json', './target.json');
ensureIsValidSemverTag('1.0.0');
await esbuild.transpileDir({
inputDir: 'src',
outputDir: 'dist',
ignore: '**/*.spec.js'
});
// Note: `context` is only defined if `incremental` is set to `true`!
const context = await esbuild.bundle({
entryPoints: ['./src/main.js'],
outdir: './dist/dist',
minify: true,
incremental: true,
inject: ['./src/polyfills.js'],
metaFilePath: './reports/meta.json'
});
await context.rebuild();
await context.dispose();
await eslint.lint(['src/**/*.js'], { failOnError: true });
await eslint.fix(['src/**/*.js']);
const domain = getEnvAsString('DOMAIN');
await jest.coverage();
await jest.changed();
await jest.watch();
await less.compile({
inputFile: 'src/main.less',
outputFile: 'dist/main.css',
optimize: true
});
const nodeApp = new NodeProcess({
script: 'src/index.js',
env: {
...process.env,
PORT: 3000
}
});
await nodeApp.start();
await nodeApp.restart();
await nodeApp.waitForExit();
const lbNodeApp = new LoadBalancedNodeProcessGroup({
script: 'src/index.js',
jsx: true,
loadBalancerPort: 3000,
getNodeProcessPort: index => 4000 + index,
instanceCount: 3,
getInstanceEnv: index => ({
...process.env,
PORT: (4000 + index).toString()
})
});
await lbNodeApp.start();
await lbNodeApp.restart();
await lbNodeApp.waitForExit();
const mongoContainer = new MongoContainer({
port: 27017,
rootUser: 'root',
rootPassword: 'pw',
replicaSetName: 'rsname'
});
await mongoContainer.ensureIsRunning();
await mongoContainer.ensureIsRemoved();
const minioContainer = new MinioContainer({
port: 9000,
accessKey: '435ZJV9F243DZ400KD',
secretKey: '4837VZNC27NTZ24KTZU0X2ZTZ01TX',
initialBuckets: ['my-bucket']
});
await minioContainer.ensureIsRunning();
await minioContainer.ensureIsRemoved();
const maildevContainer = new MaildevContainer({
smtpPort: 8025,
frontendPort: 8000
});
await maildevContainer.ensureIsRunning();
await maildevContainer.ensureIsRemoved();
const tunnelProxyContainer = new TunnelProxyContainer({
name: 'tunnel',
tunnelToken: ''0z543mh897h3j4rtxh,
tunnelDomain: 'https://tunnel.com',
localPort: 3000
});
await tunnelProxyContainer.ensureIsRunning();
await tunnelProxyContainer.ensureIsRemoved();
await runInteractiveMigrations({
migrationsDirectory: 'migrations',
migrationFileNamePattern: /^\d{4}-\d{2}-\d{2}-.*(?<!\.spec)(?<!\.specs)(?<!\.test)\.js$/
});
Funded by 'Stiftung Innovation in der Hochschullehre'
A Project of the 'Hochschule für Musik und Theater München' (University for Music and Performing Arts)
Project owner: Hochschule für Musik und Theater München
Project management: Ulrich Kaiser
FAQs
Development tools for educandu based systems
We found that @educandu/dev-tools demonstrated a healthy version release cadence and project activity because the last version was released less than a year ago. It has 3 open source maintainers collaborating on the project.
Did you know?

Socket for GitHub automatically highlights issues in each pull request and monitors the health of all your open source dependencies. Discover the contents of your packages and block harmful activity before you install or update your dependencies.

Security News
Axios compromise traced to social engineering, showing how attacks on maintainers can bypass controls and expose the broader software supply chain.

Security News
Node.js has paused its bug bounty program after funding ended, removing payouts for vulnerability reports but keeping its security process unchanged.

Security News
The Axios compromise shows how time-dependent dependency resolution makes exposure harder to detect and contain.