
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.
@eschatons/edu-tools
Advanced tools
A comprehensive collection of educational tools and utilities as reusable React components with zero-config auto-discovery
A zero-config, auto-discovery system for creating and publishing educational React components.
npm install @your-org/edu-tools
import { Calculator, Ruler } from "@your-org/edu-tools";
import "@your-org/edu-tools/styles";
function App() {
return (
<div>
<Calculator />
<Ruler lengthPx={800} />
</div>
);
}
# Step 1: Create your component
# Create: app/components/mytool/MyTool.tsx
# Step 2: Auto-generate library files
npm run generate:lib
# Step 3: Build and publish
npm run build:lib
npm version patch
npm publish
That's it! Zero configuration needed! 🎉
This library includes 14 educational tools:
Create a new directory and component file:
app/components/timer/Timer.tsx
"use client";
import { useState, useEffect } from "react";
export default function Timer() {
const [seconds, setSeconds] = useState(0);
const [isRunning, setIsRunning] = useState(false);
useEffect(() => {
let interval: NodeJS.Timeout | null = null;
if (isRunning) {
interval = setInterval(() => {
setSeconds((s) => s + 1);
}, 1000);
}
return () => {
if (interval) clearInterval(interval);
};
}, [isRunning]);
const reset = () => {
setSeconds(0);
setIsRunning(false);
};
return (
<div className="p-4 rounded-lg border border-border bg-card">
<div className="text-4xl font-mono mb-4">
{Math.floor(seconds / 60)}:{(seconds % 60).toString().padStart(2, "0")}
</div>
<div className="flex gap-2">
<button
onClick={() => setIsRunning(!isRunning)}
className="px-4 py-2 bg-accent text-white rounded"
>
{isRunning ? "Pause" : "Start"}
</button>
<button onClick={reset} className="px-4 py-2 bg-surface rounded">
Reset
</button>
</div>
</div>
);
}
Run the auto-discovery script:
npm run generate:lib
Output:
✓ Found tool: timer (Timer)
✓ Generated lib/index.ts with 15 tools
✓ Generated 15 individual tool entries
✅ All library files generated successfully!
What just happened?
lib/index.ts was updated with your exportlib/tools/timer.ts was created for tree-shakingTest your tool in the Next.js app:
// app/page.tsx
import Timer from "./components/timer/Timer";
export default function Page() {
return <Timer />;
}
npm run dev
# Visit http://localhost:3000
npm run build:lib
Output:
✓ Found 15 tools
✓ Generated library files
📦 Building library with 16 entries
✓ built in 417ms
dist/timer.js 0.12 kB │ gzip: 0.12 kB
dist/timer.cjs 0.19 kB │ gzip: 0.17 kB
Before publishing, test in a separate project:
# In your library directory
npm pack
# Creates: your-org-edu-tools-1.0.0.tgz
# In a test project
npm install /path/to/your-org-edu-tools-1.0.0.tgz
# Test it
import { Timer } from "@your-org/edu-tools";
Create NPM Account (if you don't have one)
Login to NPM
npm login
Choose Your Package Name
Update package.json:
{
"name": "@your-username/edu-tools",
"version": "1.0.0",
"description": "Educational tools as React components"
}
# Build the library
npm run build:lib
# Version bump (choose one)
npm version patch # 1.0.0 -> 1.0.1 (bug fixes)
npm version minor # 1.0.0 -> 1.1.0 (new features)
npm version major # 1.0.0 -> 2.0.0 (breaking changes)
# Publish to NPM
npm publish --access public
Success! Your package is now on NPM! 🎊
When you add new tools or make changes:
# 1. Make your changes (add tools, fix bugs, etc.)
# 2. Regenerate library files
npm run generate:lib
# 3. Build
npm run build:lib
# 4. Bump version
npm version patch # or minor/major
# 5. Publish
npm publish
import { Calculator, Timer, Ruler } from "@your-org/edu-tools";
import "@your-org/edu-tools/styles";
function App() {
return (
<div>
<Calculator />
<Timer />
<Ruler lengthPx={600} />
</div>
);
}
import { Calculator } from "@your-org/edu-tools/calculator";
import { Timer } from "@your-org/edu-tools/timer";
import "@your-org/edu-tools/styles";
// Only Calculator and Timer code is bundled! (~3 KB total)
import { lazy, Suspense } from "react";
const Timer = lazy(() =>
import("@your-org/edu-tools/timer").then((m) => ({ default: m.Timer }))
);
function App() {
return (
<Suspense fallback={<div>Loading...</div>}>
<Timer />
</Suspense>
);
}
import { Timer, WindowLayer, useWindowStore } from "@your-org/edu-tools";
function App() {
const createWindow = useWindowStore((s) => s.createWindow);
const openTimer = () => {
createWindow({
type: "timer",
title: "Timer",
initialBounds: { width: 300, height: 200 },
});
};
return (
<div>
<button onClick={openTimer}>Open Timer</button>
<WindowLayer />
</div>
);
}
The system automatically discovers tools based on file structure:
app/components/
├── calculator/
│ └── Calculator.tsx ← Auto-discovered!
├── timer/
│ └── Timer.tsx ← Auto-discovered!
└── mytool/
└── MyTool.tsx ← Auto-discovered!
The system is smart and supports multiple naming patterns:
| Directory | Component File | Export Name |
|---|---|---|
calculator/ | Calculator.tsx | Calculator |
equation/ | EquationEditor.tsx | EquationEditor |
periodic/ | PeriodicTable.tsx | PeriodicTable |
timer/ | Timer.tsx | Timer |
Priority:
calculator/Calculator.tsx[Name]Editor, [Name]Table, [Name]Reader.tsx file alphabeticallyThese directories are automatically excluded:
hooks/ - Utility hooksui/ - UI componentswindows/ - Window managementtools/ - Tool definitionsdocks/ - Dock componentsWhen you run npm run generate:lib:
Main Entry (lib/index.ts)
export { default as Calculator } from "../app/components/calculator/Calculator";
export { default as Timer } from "../app/components/timer/Timer";
// ... all tools
Individual Entries (lib/tools/timer.ts)
export { default as Timer } from "../../app/components/timer/Timer";
export * from "../../app/components/timer/Timer";
Build Configuration
equation-editor/
│
├── app/
│ ├── components/ # Your tools (add new tools here!)
│ │ ├── calculator/
│ │ │ └── Calculator.tsx
│ │ ├── timer/
│ │ │ └── Timer.tsx
│ │ └── [your-new-tool]/
│ │ └── [YourNewTool].tsx
│ └── ...
│
├── lib/ # Library utilities
│ ├── calculator.ts ✅ Keep (utility library)
│ ├── calculator.test.ts ✅ Keep (tests)
│ │
│ # Auto-generated (gitignored):
│ ├── index.ts ⚠️ Generated by npm run generate:lib
│ └── tools/ ⚠️ Generated by npm run generate:lib
│
├── scripts/
│ └── generate-lib-entries.mjs # Auto-discovery magic
│
├── docs/ # Documentation
│
├── vite.lib.config.ts # Library build config
├── package.json # NPM configuration
└── README.md # This file
npm run dev # Start Next.js dev server
npm test # Run tests
npm run lint # Run linter
npm run generate:lib # Auto-discover tools and generate exports
npm run build:lib # Build library (includes generate:lib)
npm run build:types # Generate TypeScript definitions
npm version patch # Bump version (bug fixes)
npm version minor # Bump version (new features)
npm version major # Bump version (breaking changes)
npm publish # Publish to NPM
npm pack # Create .tgz for local testing
npm run build:lib # Verify build works
npm test # Verify tests pass
Edit scripts/generate-lib-entries.mjs to customize:
// Add custom suffixes
const mainVariants = [
`${componentNameFromDir}Editor`,
`${componentNameFromDir}Table`,
`${componentNameFromDir}Widget`, // Your custom suffix
];
// Add exclusions
const EXCLUDED_DIRS = [
"hooks",
"ui",
"your-excluded-dir", // Add here
];
Edit vite.lib.config.ts for custom build settings:
export default defineConfig({
build: {
lib: {
name: "EduTools",
formats: ["es", "cjs"], // Add "umd" if needed
},
},
});
Edit package.json for metadata:
{
"name": "@your-org/edu-tools",
"version": "1.0.0",
"description": "Your description",
"keywords": ["react", "education", "components"],
"repository": "https://github.com/your-org/edu-tools"
}
Problem: Your tool doesn't appear after running npm run generate:lib
Solutions:
.tsx or .jsxEXCLUDED_DIRS✅ app/components/mytool/MyTool.tsx
❌ app/components/mytool/sub/MyTool.tsx
✅ timer/ -> Timer.tsx
❌ timer/ -> MyTimer.tsx (won't match)
Problem: Build fails with module errors
Solutions:
# Clean and rebuild
rm -rf dist/ lib/index.ts lib/tools/
npm run build:lib
# Check for import errors
npm run lint
Problem: Script exports wrong file from directory
Solutions:
Editor, Table, ReaderProblem: npm publish fails
Solutions:
Not logged in:
npm login
Package name taken:
{
"name": "@your-username/edu-tools"
}
Access denied (scoped package):
npm publish --access public
Missing build:
npm run build:lib
Problem: Styles not working for users
Solution: Tell users to import styles:
import "@your-org/edu-tools/styles";
Keep tools small and focused:
// Good - Single responsibility
export default function Calculator() { ... }
// Avoid - Multiple tools in one file
export function Calculator() { ... }
export function ScientificCalculator() { ... }
Use individual imports for better tree-shaking:
// Larger bundle (~200 KB)
import { Calculator, Timer, Ruler } from "@your-org/edu-tools";
// Smaller bundle (~10 KB)
import { Calculator } from "@your-org/edu-tools/calculator";
import { Timer } from "@your-org/edu-tools/timer";
The library uses Tailwind CSS. Import the bundled styles:
import "@your-org/edu-tools/styles";
Override CSS variables:
:root {
--color-accent: #your-color;
--color-card: #your-color;
--color-foreground: #your-color;
}
// tailwind.config.js
module.exports = {
content: [
"./src/**/*.{js,ts,jsx,tsx}",
"./node_modules/@your-org/edu-tools/**/*.js",
],
theme: {
extend: {
// Your customizations
},
},
};
generate:lib before buildingnpm pack before publishingimport "@your-org/edu-tools/styles"✅ app/components/[toolname]/[ComponentName].tsx # Your tools
✅ lib/calculator.ts # Utility libraries
⚠️ lib/index.ts # Auto-generated
⚠️ lib/tools/*.ts # Auto-generated
npm run generate:lib # Discover tools
npm run build:lib # Build library
npm version patch # Bump version
npm publish # Publish to NPM
1. Create component → 2. generate:lib → 3. build:lib → 4. publish
app/components/[toolname]/npm run generate:libnpm run devnpm run build:libMIT © Your Name
Made with ❤️ for educators and learners
⭐ Star us on GitHub | 📦 Install from NPM
FAQs
A comprehensive collection of educational tools and utilities as reusable React components with zero-config auto-discovery
We found that @eschatons/edu-tools demonstrated a healthy version release cadence and project activity because the last version was released less than a year ago. It has 1 open source maintainer 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.