5 Years Later: sequelize-guard Goes Full TypeScript (with AI as Co-Pilot)
The journey of rewriting a 5-year-old JavaScript authorization library in TypeScript, and how AI helped modernize an open-source project while preserving its battle-tested architecture.
5 Years Later: sequelize-guard Goes Full TypeScript (with AI as Co-Pilot)
Back in 2019, I open-sourced sequelize-guard—a lightweight authorization library that brings Laravel-style permissions to Sequelize.js in Node.js. It was born out of a real need: managing role-based access control without drowning in complexity.
Today, I'm proud to ship v6: fully rewritten in TypeScript with a modern documentation site!
This post is about the journey, the lessons learned about system design, and how AI became an invaluable co-pilot in modernizing open-source software.
The Genesis: Why sequelize-guard Exists
Authorization is one of those problems that seems simple until you actually implement it. You need roles, permissions, caching, audit trails, and a clean API that doesn't make developers want to tear their hair out.
I wanted something that felt as intuitive as Laravel's authorization system but worked seamlessly with Sequelize in Node.js. The result was sequelize-guard:
await user.can('edit:post'); // Simple, readable, powerful
Clean separation of roles, permissions, and caching. Event-driven hooks for auditing. A fluent API that reads like natural language.
System Design That Stands the Test of Time
Here's the thing about good architecture: it ages well.
The original JavaScript codebase was built with longevity in mind. Even after 5 years, multiple Sequelize major versions (v5 → v6), and the entire JavaScript ecosystem evolving around it, the core logic ported to TypeScript almost unchanged.
What Made It Last?
1. Strong Abstractions
The library was built around clear concepts:
- Roles as containers for permissions
- Permissions as action-resource pairs
- Caching layer as a separate concern
- Event system for extensibility
These abstractions didn't leak. They didn't depend on Sequelize internals more than necessary. They just... worked.
2. Fluent, Readable API
// This API design from 2019 still feels modern in 2024
user.can('edit:post')
user.isA('admin')
user.isAnyOf(['admin', 'editor'])
When your API reads like natural language, it doesn't age. It doesn't need "modernizing" because it was already intuitive.
3. Event-Driven Architecture
guard.on('permission:checked', (event) => {
// Audit logging, analytics, whatever you need
});
By emitting events at key points, the library became extensible without modification. Users could hook into the authorization flow without touching the core.
The Lesson: Invest in strong abstractions early. They make migrations painless and keep your code relevant for years.
Maintainability in Open Source
JavaScript moves quickly. What felt state-of-the-art in 2019 looked a bit dated by 2024.
The v6 rewrite wasn't just about adding types—it was about setting the project up for the next several years.
The Modernization Checklist
- ✅ TypeScript with strict generics for models & permissions
- ✅ Dual ESM + CommonJS support for maximum compatibility
- ✅ Vitest for testing (goodbye Jest config hell)
- ✅ Vite for blazing-fast builds
- ✅ Typedoc for auto-generated API documentation
- ✅ 99% backward compatible (breaking changes only where absolutely necessary)
Why This Matters
Open source projects thrive when they keep evolving at a sustainable pace. A modern toolchain makes it easier for maintainers and contributors to keep improving things without constant friction.
By modernizing the toolchain, I aimed to make sure that:
- New contributors can jump in with familiar tools
- The library works smoothly with modern Node.js projects (ESM)
- TypeScript users get first-class support
- The documentation stays fresh and accurate
The Lesson: A little ongoing maintenance goes a long way. Investing in your tooling and architecture makes it much easier for your project to keep growing over time.
LLMs as Open-Source Superchargers
Here's where it gets interesting.
I approached this massive rewrite by treating Claude and GPT-4 as my co-pilots. I gave them the old JavaScript codebase and a clear task:
"Migrate to strict TypeScript. Keep 100% behavior. Add generics. Update tests."
What AI Crushed
The Repetitive Work:
- Type definitions across hundreds of lines of code
- Converting modules from CommonJS to ESM
- Migrating test suites from Jest to Vitest
- Generating boilerplate for generic types
- Updating configuration files for modern tooling
This is the kind of work that's tedious, error-prone, soul-crushing and easy to get wrong when you're tired. AI handled it with remarkable consistency.
What I Still Owned
The High-Value Work:
- Core architecture decisions
- Handling complex edge cases specific to Sequelize
- Designing the generic type system for models
- Setting up CI/CD pipelines
- Building and deploying the documentation site
- Reviewing and validating AI-generated code
The Truth About AI-Assisted Development
AI didn't replace me. It removed the noise so I could focus purely on quality, correctness, and architecture.
Think of it like this:
- Before AI: 70% grunt work, 30% creative problem-solving
- With AI: 20% grunt work, 80% creative problem-solving
The work became more intellectually engaging. I spent less time typing boilerplate and more time thinking about design.
The Lesson: AI is a helpful force multiplier for maintainers. It doesn't replace expertise—it gives you more space to use it.
The Result: Battle-Tested, Type-Safe, Future-Proof
sequelize-guard v6 is everything the original was, but better:
// Now with compile-time type checking!
await user.can('delete:user'); // TypeScript knows this is valid
// Generic support for your models
const guard = new SequelizeGuard<MyUserModel>(sequelize);
// Full IntelliSense support
user.assignRole('admin'); // Autocomplete works perfectly
What Users Get
- Type Safety: Catch permission errors at compile time
- Better DX: IntelliSense, autocomplete, inline documentation
- Modern Tooling: Works with ESM, Vite, and modern Node.js
- Same Great API: If you used v5, v6 feels familiar
- Comprehensive Docs: sequelize-guard.js.org
A Message to Open-Source Maintainers
If you have an open-source gem sitting quietly in your GitHub repos, it's never too late to modernize.
The tools are better than ever:
- TypeScript makes refactoring safer
- AI can help carry the grunt work
- Modern build tools (Vite, Vitest) are faster and simpler
- Documentation generators (Typedoc, VitePress) are incredible
The community is here. People still care about well-designed libraries that solve real problems.
If your project feels a bit behind on tooling, that's okay—it happens to every codebase. A small round of improvements can give it new life.
Try It Out
If you use Sequelize + Node.js, I'd love for you to try sequelize-guard v6:
I'd especially love to hear your thoughts on the new type system and developer experience.
About the Author: Pankaj Vaghela is a software engineer passionate about system design, open source, and building tools that make developers' lives easier. With over a decade of experience in full-stack development, he specializes in creating scalable solutions and contributing to the open-source community. Learn more at pankajvaghela.in or connect on GitHub.