npm package discovery and stats viewer.

Discover Tips

  • General search

    [free text search, go nuts!]

  • Package details

    pkg:[package-name]

  • User packages

    @[username]

Sponsor

Optimize Toolset

I’ve always been into building performant and accessible sites, but lately I’ve been taking it extremely seriously. So much so that I’ve been building a tool to help me optimize and monitor the sites that I build to make sure that I’m making an attempt to offer the best experience to those who visit them. If you’re into performant, accessible and SEO friendly sites, you might like it too! You can check it out at Optimize Toolset.

About

Hi, 👋, I’m Ryan Hefner  and I built this site for me, and you! The goal of this site was to provide an easy way for me to check the stats on my npm packages, both for prioritizing issues and updates, and to give me a little kick in the pants to keep up on stuff.

As I was building it, I realized that I was actually using the tool to build the tool, and figured I might as well put this out there and hopefully others will find it to be a fast and useful way to search and browse npm packages as I have.

If you’re interested in other things I’m working on, follow me on Twitter or check out the open source projects I’ve been publishing on GitHub.

I am also working on a Twitter bot for this site to tweet the most popular, newest, random packages from npm. Please follow that account now and it will start sending out packages soon–ish.

Open Software & Tools

This site wouldn’t be possible without the immense generosity and tireless efforts from the people who make contributions to the world and share their work via open source initiatives. Thank you 🙏

© 2026 – Pkg Stats / Ryan Hefner

formulab

v0.10.1

Published

Manufacturing & Engineering calculation formulas library - 174 industrial calculations across 14 domains for OEE, Cpk, SPC, metal weight, CNC machining, GD&T, battery, environmental, pipe flow, logistics, and more

Readme

formulab

Industrial & manufacturing calculation library for engineers

npm version CI License: MIT TypeScript

A comprehensive collection of engineering formulas and calculations for manufacturing, quality control, logistics, and industrial applications. Zero dependencies, fully typed, tree-shakeable.

Features

  • 174 industrial calculations + 8 type guards — OEE, Cpk, SPC control charts, Gage R&R, Weibull, metal weight, CNC machining, GD&T, pipe flow, CBM, NIOSH lifting, PMV/PPD, arc flash, battery SOH, GHG emissions, PID tuning, and more
  • 14 specialized domains — Quality, Metal, Chemical, Electronics, Construction, Automotive, Logistics, Energy, Safety, Food, Utility, Battery, Environmental, Machining
  • Zero dependencies — Lightweight and fast
  • TypeScript first — Full type definitions included
  • Tree-shakeable — Import only what you need
  • 2,494 tests — Coverage thresholds: 90% lines, 95% functions, 85% branches (CI pipeline)
  • Research-based — Golden reference tests verified against NIOSH 94-110, AIAG/ASTM E2587, JIPM, ASME B16.5, ISO 22514-2, and more

Verification Status

| Domain | Functions | Golden Tests | Key References | |--------|-----------|-------------|----------------| | Quality | 18 | oee, cpk, controlChart, gageRR | ISO 22400-2, AIAG/ASTM E2587, JIPM, AIAG MSA | | Metal | 25 | metalWeight | Machinery's Handbook, ASME B36.10/B16.5 | | Logistics | 17 | cbm | Physical formula | | Safety | 14 | nioshLifting | NIOSH 94-110, ISO 7730, IEEE 1584, OSHA | | Chemical | 12 | — | Darcy-Weisbach, Fourier, API 520, ISA | | Electronics | 11 | — | IPC-2221 | | Construction | 12 | — | AISC, Timoshenko | | Automotive | 9 | — | AASHTO, SAE J1772 | | Energy | 15 | — | NREL PVWatts, ISO 50001 | | Food | 6 | — | HACCP, ICH Q1A | | Utility | 16 | — | — | | Battery | 10 | — | IEEE 1188, IEC 62620, Battery University | | Environmental | 10 | — | GHG Protocol, IPCC AR6, IEA 2023 | | Machining | 12 | — | Machinery's Handbook, ASME Y14.5, Sandvik Coromant |

Functions with golden reference tests have been verified against authoritative engineering sources. See each function's JSDoc for specific references.

Numerical Accuracy & Testing

Floating-Point Handling

All calculations use a sign-aware roundTo() utility with epsilon correction to avoid IEEE 754 rounding artifacts:

roundTo(0.615, 2)   // → 0.62  (not 0.61)
roundTo(-2.555, 2)  // → -2.56 (sign-aware)

Non-finite values (NaN, Infinity) pass through unchanged. All validation errors throw RangeError — no function returns NaN or Infinity for invalid inputs. Each function's JSDoc specifies output precision (typically 2-4 decimal places) and @throws conditions.

Golden Reference Tests

The following functions include tests verified against published reference values:

| Function | Standard / Source | What is verified | |----------|-------------------|------------------| | nioshLifting() | NIOSH Publication 94-110 | LC=23kg ideal, FM/CM table values, RWL calculation | | oee() | JIPM TPM Handbook | World-class OEE (A≥90%, P≥95%, Q≥99.9%), perfect 100% | | cpk() | ISO 22514-2 | Six Sigma Cpk=2.0, minimum capable Cpk≈1.33, off-center penalty | | controlChart() | AIAG/ASTM E2587-16 | A2, D3, D4, d2 constants for n=2, 3, 5 | | cbm() | Physical formula | 20ft container 33.2m³, 1m³ cube reference | | metalWeight() | Machinery's Handbook | Steel plate density 7.85 g/cm³ | | flangeSpec() | ASME B16.5 | Class 150/300/600 flange dimensions | | pipeSpec() | ASME B36.10 | SCH40/80/160 wall thickness | | awgProperties() | ANSI/AWG | AWG 0-40 diameter, resistance |

Edge Case Handling

Functions validate or handle these boundary conditions:

  • Division by zero: cpk() with zero standard deviation, oee() with zero planned time
  • Out-of-range inputs: tolerance() rejects invalid IT grades, aql() validates lot sizes
  • Physical impossibility: pressFit() rejects negative interference, nioshLifting() clamps multipliers to [0, 1]
  • Extreme values: aql() handles 1M-unit lots, awgProperties() covers AWG 0-40

Optimization Functions — Algorithms & Limitations

Three functions solve NP-hard combinatorial problems using heuristic algorithms. They provide good practical results but do not guarantee optimal solutions:

| Function | Algorithm | Complexity | Optimality | |----------|-----------|-----------|-----------| | tsp() | Nearest Neighbor + 2-Opt local search; brute force for n ≤ 10 | O(n²) per NN start, O(n!) exact for n ≤ 10 | Heuristic — no approximation ratio guarantee; exact only for n ≤ 10 | | pallet3d() | Bottom-Left-Fill + First Fit Decreasing with AABB collision & stability checks | O(m² × n) where m = placed boxes | Heuristic — greedy placement; enforces physical constraints (80% support, weight limit) | | cuttingStock() | First Fit Decreasing (FFD) or Best Fit Decreasing (BFD), user-selectable | O(q²) worst case | FFD: ≤ 11/9 × OPT + 1 (proven bound); not optimal |

For mission-critical optimization requiring proven-optimal solutions, use dedicated solvers (e.g., OR-Tools, Gurobi). These functions are designed for quick shop-floor estimates.

CI Pipeline

GitHub Actions runs on every push to main and every pull request:

  • Matrix: Node.js 18, 20
  • Steps: pnpm installtsc (type check) → vitest run --coverage
  • Coverage enforcement: Fails if below thresholds (lines 90%, functions 95%, branches 85%, statements 90%)
# Run tests locally
pnpm test

# Run with coverage report
pnpm test:coverage

Installation

npm install formulab
pnpm add formulab

Quick Start

import { oee, metalWeight, cbm } from 'formulab';

// Calculate OEE (Overall Equipment Effectiveness)
const result = oee({
  rawData: {
    plannedTime: 480,      // minutes (8 hours)
    runTime: 432,          // minutes (90% availability)
    totalCount: 1000,
    goodCount: 990,        // 99% quality
    idealCycleTime: 0.456, // minutes per piece (95% performance)
  },
});
console.log(result.percentages.oee); // 84.6%

// Calculate metal weight
const weight = metalWeight({
  shape: 'plate',
  materialName: 'steel',
  length: 1000,    // mm
  width: 500,      // mm
  thickness: 10,   // mm
});
console.log(weight.weight); // 39.25 kg

// Calculate CBM (Cubic Meter)
const volume = cbm({
  length: 120,
  width: 80,
  height: 100,
  quantity: 1,
  unit: 'cm',
});
console.log(volume.totalCbm); // 0.96 m³

Domains

Quality & Production (18 functions)

import { oee, cpk, taktTime, dpmo, controlChart, gageRR, weibull } from 'formulab/quality';

| Function | Description | |----------|-------------| | oee() | Overall Equipment Effectiveness | | cpk() | Process Capability Index | | controlChart() | SPC X-bar/R and X-bar/S charts | | cycleTime() | Cycle Time analysis | | taktTime() | Takt Time calculation | | aql() | AQL sampling inspection | | downtime() | Downtime analysis | | dpmo() | Defects Per Million Opportunities | | lineBalancing() | Line balancing optimization | | mtbf() | Mean Time Between Failures | | ppk() | Process Performance Index | | ppm() | Parts Per Million conversion | | rpn() | Risk Priority Number (FMEA) | | yieldCalc() | First Pass Yield / RTY | | gageRR() | Gage R&R (AIAG MSA Average & Range) | | cmk() | Machine capability index Cm/Cmk | | weibull() | Weibull reliability analysis | | paretoAnalysis() | Pareto 80/20 ABC classification |

Metal & Machining (25 functions)

import { metalWeight, bendAllowance, cutting, bearing } from 'formulab/metal';

| Function | Description | |----------|-------------| | metalWeight() | Weight calculation for various shapes | | bendAllowance() | Sheet metal bend allowance | | flatPattern() | Flat pattern length calculation | | kFactorReverse() | K-factor reverse engineering | | pressTonnage() | Press brake tonnage | | bearing() | L10 bearing life calculation | | bolt() | Bolt torque and preload | | cutting() | Cutting speed, feed rate, RPM | | cuttingStock() | 1D cutting stock heuristic (FFD/BFD) | | gear() | Gear module calculation | | hardness() | Hardness conversion (HRC, HB, HV) | | material() | Material properties lookup | | pressFit() | Press fit interference | | roughness() | Surface roughness conversion | | screw() | Screw specification | | spring() | Spring design calculation | | tap() | Tap drill size | | thread() | Thread dimensions | | tolerance() | ISO tolerance (IT grades) | | vibration() | Natural frequency analysis | | weldHeat() | Weld heat input calculation | | welding() | Welding parameters | | materialGradeConverter() | ASTM/EN/JIS/GB/KS grade cross-reference | | pipeSpec() | ANSI/ASME pipe dimensions lookup | | flangeSpec() | ASME B16.5 flange dimensions lookup |

Chemical & Process (12 functions)

import { dilution, concentration, ph, reactor, pipeFlow, heatTransfer, flowControl, pid } from 'formulab/chemical';

| Function | Description | |----------|-------------| | batch() | Batch scaling calculation | | concentration() | Concentration conversion | | dilution() | Dilution (C1V1 = C2V2) | | heatTransfer() | Conduction/convection/radiation heat transfer | | ph() | pH and buffer calculations | | pipeFlow() | Darcy-Weisbach pipe flow pressure drop | | reactor() | Reactor sizing | | shelfLife() | Shelf life prediction (Arrhenius) | | injectionCycle() | Injection molding cycle time | | flowControl() | Control valve Cv/Kv sizing (ISA/IEC 60534) | | reliefValve() | Safety relief valve sizing (API 520/526) | | pid() | PID controller tuning (Z-N / Cohen-Coon) |

Electronics & SMT (11 functions)

import { traceWidth, solderPaste, resistorDecode, ohmsLaw } from 'formulab/electronics';

| Function | Description | |----------|-------------| | ohmsLaw() | Ohm's Law V/I/R/P calculator | | reflowProfile() | Reflow temperature profile | | resistorDecode() | Resistor color code decoder | | smtTakt() | SMT line takt time | | solderPaste() | Solder paste volume calculation | | traceWidth() | PCB trace width (IPC-2221) | | awgProperties() | AWG wire properties | | capacitorDecode() | Capacitor code decoder | | ledResistor() | LED resistor calculation | | stencilAperture() | Stencil aperture design | | viaCurrent() | Via current capacity |

Construction (12 functions)

import { concreteMix, rebarWeight, slope, stair, momentOfInertia } from 'formulab/construction';

| Function | Description | |----------|-------------| | momentOfInertia() | Section properties (Ix, Sx, rx) for 7 shapes | | beamLoad() | Beam load calculation | | concreteMix() | Concrete mix ratio | | earthwork() | Earthwork volume | | formwork() | Formwork area calculation | | rebarWeight() | Rebar weight by size | | slope() | Slope conversion (%, degree, ratio) | | aggregate() | Aggregate volume calculation | | brick() | Brick quantity estimation | | pert() | PERT schedule analysis | | roof() | Roof calculation | | stair() | Stair dimension calculation |

Automotive (9 functions)

import { batteryRuntime, evCharging, torque, brakingDistance, chargingLoss } from 'formulab/automotive';

| Function | Description | |----------|-------------| | brakingDistance() | Stopping distance (AASHTO method) | | batteryRuntime() | Battery capacity/runtime | | evCharging() | EV charging time estimation | | fuelEconomy() | Fuel economy conversion | | gearRatio() | Gear ratio calculation | | tireCompare() | Tire size comparison | | torque() | Torque conversion | | power() | Power conversion (HP, kW) | | chargingLoss() | EV charging loss/efficiency |

Logistics & Inventory (17 functions)

import { cbm, eoq, safetyStock, kanban, inventoryTurnover, abcAnalysis } from 'formulab/logistics';

| Function | Description | |----------|-------------| | abcAnalysis() | ABC inventory classification by annual value | | cbm() | Cubic meter calculation | | containerFit() | Container capacity estimation | | dimWeight() | Dimensional weight | | eoq() | Economic Order Quantity | | fillRate() | Fill rate calculation | | freightClass() | NMFC freight class | | inventoryTurnover() | Inventory turnover ratio & days of supply | | kanban() | Kanban quantity | | loadCapacity() | Forklift load capacity derating | | pallet3d() | 3D pallet loading heuristic (BLF + FFD) | | palletStack() | Pallet stacking calculation | | pickTime() | Picking time estimation | | safetyStock() | Safety stock calculation | | serviceLevel() | Service level calculation | | shipping() | Shipping cost estimation | | tsp() | TSP heuristic (NN + 2-Opt; exact for n ≤ 10) |

Energy & Utilities (15 functions)

import { powerCost, motorEfficiency, carbonFootprint, solarOutput, boilerEfficiency, heatPump, cusum } from 'formulab/energy';

| Function | Description | |----------|-------------| | boilerEfficiency() | Boiler thermal efficiency (direct method) | | carbonFootprint() | Scope 2 emissions | | compressedAirCost() | Compressed air cost | | cusum() | CUSUM energy anomaly detection | | degreeDay() | Heating/Cooling degree days (HDD/CDD) | | heatPump() | Heat pump COP & Carnot efficiency | | insulationRoi() | Insulation ROI & payback | | ledRoi() | LED lighting retrofit ROI | | motorEfficiency() | Motor upgrade ROI | | pfCorrection() | Power factor correction | | powerCost() | Electricity cost with demand | | solarOutput() | Solar panel output estimation (PVWatts-based) | | transformerLoss() | Transformer loss & efficiency | | vfdSavings() | VFD energy savings | | windOutput() | Wind turbine output with Rayleigh CF |

Safety & Ergonomics (14 functions)

import { nioshLifting, noiseExposure, wbgtCalculate, ventilationRate, thermalComfort, arcFlash, lel } from 'formulab/safety';

| Function | Description | |----------|-------------| | arcFlash() | Arc flash incident energy & PPE (IEEE 1584) | | confinedSpace() | Confined space atmospheric assessment (OSHA) | | ergonomicRisk() | REBA ergonomic risk scoring | | fallClearance() | Fall protection clearance | | havsCalculate() | Hand-arm vibration exposure | | illuminance() | Workplace illuminance (Lumen Method) | | ladderAngle() | Ladder safety angle (OSHA 4:1) | | lel() | Mixed gas LEL (Le Chatelier's rule) | | nioshLifting() | NIOSH lifting equation | | noiseExposure() | TWA/Dose calculation | | respiratorCalculate() | Respirator MUC calculation | | thermalComfort() | PMV/PPD thermal comfort (ISO 7730) | | ventilationRate() | Required ventilation ACH/CFM (ASHRAE/OSHA) | | wbgtCalculate() | WBGT heat stress index |

Food & HACCP (6 functions)

import { calorie, nutrition, haccp, waterActivity, stabilityStudy } from 'formulab/food';

| Function | Description | |----------|-------------| | calorie() | Calorie requirement (BMR/TDEE) | | expiry() | Expiry date calculation | | nutrition() | Nutrition facts calculation | | haccp() | HACCP checklist generation | | waterActivity() | Water activity microbial risk (HACCP) | | stabilityStudy() | Accelerated stability (Arrhenius, ICH Q1A) |

Utility (16 functions)

import { solveAssignment, calculateUnit, statistics, regression, npv } from 'formulab/utility';

| Function | Description | |----------|-------------| | solveAssignment() | Hungarian algorithm optimization | | calculateUnit() | Unit conversion (7 categories) | | getUnitCategories() | Get unit categories | | statistics() | Descriptive statistics (mean, median, stdDev, etc.) | | percentile() | Percentile/quantile calculation | | correlation() | Pearson correlation coefficient | | regression() | Simple linear regression | | movingAverage() | SMA/EMA/WMA moving average | | linearInterpolation() | 1D linear interpolation | | bilinearInterpolation() | 2D bilinear interpolation | | roi() | Return on Investment | | npv() | Net Present Value | | depreciation() | Asset depreciation (SL/DDB/SYD) | | lcc() | Life Cycle Cost analysis | | normalize() | Data normalization (min-max/z-score) | | histogram() | Frequency distribution histogram | | weightedScore() | Weighted scoring model |

Battery (10 functions)

import { energyDensity, cRate, stateOfHealth, cycleLife } from 'formulab/battery';

| Function | Description | |----------|-------------| | energyDensity() | Wh/kg and Wh/L energy density | | cRate() | C-rate ↔ current/time conversion | | stateOfHealth() | SOH % with degradation status | | batteryPackConfig() | Series/parallel cell configuration | | cycleLife() | Cycle life estimation (chemistry/DOD/temp) | | internalResistance() | DCIR from OCV and load voltage | | selfDischarge() | Self-discharge rate calculation | | thermalRunaway() | Thermal safety margin analysis | | bmsBalancing() | BMS cell balancing time estimation | | chargingProfile() | CC-CV charging profile timing |

Environmental (10 functions)

import { scope1Emissions, scope2Emissions, gwpCalculator, esgSummary } from 'formulab/environmental';

| Function | Description | |----------|-------------| | scope1Emissions() | Fuel combustion direct emissions (6 fuels) | | scope2Emissions() | Purchased electricity emissions (12 regions) | | scope3Emissions() | Supply chain spend-based emissions (8 categories) | | vocEmissions() | VOC emissions with capture/destruction | | productCarbonFootprint() | Product lifecycle carbon footprint | | gwpCalculator() | GWP conversion (8 gases × 3 time horizons) | | energyIntensity() | Energy intensity (MJ/unit, kWh/unit) | | waterFootprint() | Water footprint (blue/green/grey) | | emissionsIntensity() | Emissions intensity per unit/revenue/employee | | esgSummary() | ESG reduction tracking and projections |

Machining & CNC (12 functions)

import { truePosition, boltCircle, toolDeflection, threadOverWires } from 'formulab/machining';

| Function | Description | |----------|-------------| | truePosition() | GD&T True Position (diametral, MMC bonus) | | boltCircle() | Bolt hole pattern coordinates | | sineBarHeight() | Sine bar gauge block height | | radialChipThinning() | Chip load compensation for light radial cuts | | toolDeflection() | End mill cantilever deflection | | cuspHeight() | Ball mill scallop height | | effectiveDiameter() | Ball mill effective cutting diameter | | boringBarDeflection() | Boring bar deflection with L/D guidance | | threadOverWires() | 3-wire thread measurement | | gaugeBlockStack() | Gauge block combination (47/88/81-pc sets) | | triangleSolver() | Triangle solver (SSS/SAS/ASA/SSA) | | cycleTimeEstimator() | CNC cycle time estimation |

API Examples

OEE Calculation

import { oee } from 'formulab/quality';

const result = oee({
  rawData: {
    plannedTime: 480,      // minutes
    runTime: 420,          // actual running time
    totalCount: 1000,      // total pieces produced
    goodCount: 990,        // good pieces
    idealCycleTime: 0.4,   // minutes per piece
  },
});

console.log(result);
// {
//   factors: { availability: 0.875, performance: 0.952, quality: 0.99, oee: 0.825 },
//   percentages: { availability: 87.5, performance: 95.2, quality: 99, oee: 82.5 }
// }

NIOSH Lifting Equation

import { nioshLifting } from 'formulab/safety';

const result = nioshLifting({
  loadWeight: 23,           // kg
  horizontalDistance: 25,   // cm
  verticalDistance: 75,     // cm (height at lift origin)
  verticalTravel: 25,       // cm (vertical travel distance)
  asymmetryAngle: 0,        // degrees
  coupling: 'good',         // 'good' | 'fair' | 'poor'
  frequency: 1,             // lifts per minute
  duration: 'short',        // 'short' | 'medium' | 'long'
});

console.log(result);
// {
//   rwl: 21.62,             // Recommended Weight Limit (kg)
//   liftingIndex: 1.06,     // LI = Load / RWL
//   riskLevel: 'moderate',
//   hm: 1.0, vm: 1.0, dm: 1.0, am: 1.0, fm: 0.94, cm: 1.0
// }

Dimensional Weight

import { dimWeight } from 'formulab/logistics';

const result = dimWeight({
  length: 60,
  width: 40,
  height: 30,
  unit: 'cm',
  carrier: 'international',
});

console.log(result);
// {
//   dimWeight: 14.4,
//   actualVolume: 0.072,
//   cbm: 0.072,
// }

Type Guards for Discriminated Unions

formulab provides runtime type guard functions for all discriminated union input types. These enable type-safe integration when working with dynamic data (e.g., form inputs, API responses):

import { isCRateInput, cRate } from 'formulab/battery';

// Form data from user input (Record<string, unknown>)
const formData: unknown = { mode: 'currentToRate', capacityAh: 100, currentA: 50 };

if (isCRateInput(formData)) {
  const result = cRate(formData); // Type-safe, no 'as any' needed
}

Available Type Guards

| Guard | Domain | Discriminant | Variants | |-------|--------|-------------|----------| | isCRateInput() | battery | mode | currentToRate, rateToCurrent | | isDilutionInput() | chemical | solveFor | c1, v1, c2, v2 | | isReactorInput() | chemical | shape | cylindrical, spherical | | isHeatTransferInput() | chemical | mode | conduction, convection, radiation | | isMomentOfInertiaInput() | construction | shape | rectangle, circle, hollowRectangle, hollowCircle, iBeam, tSection, cChannel | | isOhmsLawInput() | electronics | solveFor | voltage, current, resistance, power | | isMetalWeightInput() | metal | shape | plate, round, pipe, angle | | isBoltInput() | metal | mode | torqueToPreload, preloadToTorque |

Error Handling

See ERRORS.md for the complete error behavior specification. Key points:

  • All validation failures throw RangeError with descriptive messages
  • No silent NaN/Infinity — every function guarantees finite outputs for valid inputs
  • Every @throws condition is documented in each function's JSDoc
import { metalWeight } from 'formulab/metal';

try {
  const result = metalWeight({ shape: 'plate', materialName: 'steel', length: 0, width: 100, thickness: 10 });
} catch (e) {
  if (e instanceof RangeError) {
    console.log(e.message); // "length must be positive"
  }
}

Tree Shaking

Import only what you need to minimize bundle size:

// Recommended - domain-specific import
import { oee } from 'formulab/quality';
import { metalWeight } from 'formulab/metal';

// Also works - main entry point (tree-shakeable)
import { oee, metalWeight } from 'formulab';

// Avoid - imports entire module
import * as formulab from 'formulab';

TypeScript Support

Full TypeScript support with detailed type definitions:

import type {
  OeeInput,
  OeeResult,
  CpkInput,
  CpkResult,
  MetalWeightInput,
  MetalWeightResult,
} from 'formulab';

Browser Support

formulab works in all modern browsers and Node.js:

  • Node.js 18+
  • Chrome 80+
  • Firefox 75+
  • Safari 13+
  • Edge 80+

Contributing

Contributions are welcome! Please see our GitHub repository.

# Clone the repository
git clone https://github.com/iyulab/formulab.git

# Install dependencies
pnpm install

# Run tests
pnpm test

# Build
pnpm build

License

MIT © iyulab