Addons Scanner Utilities
raw JSON →The `addons-scanner-utils` library provides a collection of helper functions specifically designed for building command-line interfaces (CLIs) and backend services within the Mozilla add-ons scanning ecosystem. Currently at version `15.0.0`, it maintains a rapid release cadence, with several major versions released in quick succession, indicating active and continuous development. Key functionalities include robust error handling through the `AppError` class, secure JSON Web Token (JWT) generation for authenticating with platforms like Add-ons for Mozilla (AMO), and versatile file operations such as downloading remote resources. The library is often integrated with `express` for API development, supporting specific authentication patterns like `HMAC-SHA256` and handling `X-Forwarded-Authorization` headers. Its core differentiator is its specialized focus on the Mozilla add-ons context, offering tailored solutions for common operational tasks in that domain. It ships with comprehensive TypeScript types, ensuring type-safe development.
Common errors
error ReferenceError: ApiError is not defined ↓
ApiError with AppError in your code, including import statements. error Error: This module requires Node.js version 22 or higher. ↓
error TypeError: (0 , addons_scanner_utils_1.makeJWT) is not a function ↓
import { makeJWT } from 'addons-scanner-utils'; and ensure your project supports ESM. error Unauthorized: Bearer token missing or malformed ↓
Authorization: Bearer YOUR_TOKEN header. If using the library's internal auth (pre-v15), verify configuration. For v15+, implement custom Bearer token validation logic. Warnings
breaking The `ApiError` class was renamed to `AppError`. Direct references to `ApiError` will cause runtime errors. ↓
gotcha This library now requires Node.js version 22 or higher to run. Older Node.js versions are no longer supported. ↓
breaking The internal authentication layer, if used, now strictly requires credentials to be passed via an `Authorization` HTTP header instead of a request body parameter. ↓
breaking Support for `Bearer` token based authentication within the library's built-in utilities has been dropped. If your application relied on the library's direct handling of Bearer tokens, this functionality must now be implemented manually. ↓
breaking The built-in Express handler for automatically downloading XPI (Mozilla addon) files has been removed. Applications previously relying on this functionality will need to implement custom file download logic. ↓
Install
npm install addons-scanner-utils yarn add addons-scanner-utils pnpm add addons-scanner-utils Imports
- AppError wrong
import { ApiError } from 'addons-scanner-utils'; const { AppError } = require('addons-scanner-utils');correctimport { AppError } from 'addons-scanner-utils'; - makeJWT wrong
const { makeJWT } = require('addons-scanner-utils');correctimport { makeJWT } from 'addons-scanner-utils'; - downloadFile wrong
const { downloadFile } = require('addons-scanner-utils');correctimport { downloadFile } from 'addons-scanner-utils';
Quickstart
import express, { Request, Response, NextFunction } from 'express';
import { AppError, makeJWT, downloadFile } from 'addons-scanner-utils';
import safeCompare from 'safe-compare'; // from peer dependency
const app = express();
const port = 3000;
// A placeholder for a secret key for HMAC-SHA256 or JWT signing
const JWT_SECRET = process.env.JWT_SECRET ?? 'super_secret_jwt_key_please_change';
const STATIC_AUTH_TOKEN = process.env.STATIC_AUTH_TOKEN ?? 'my-secure-token-123_please_change';
// Middleware to simulate an authentication check (e.g., Bearer token)
function authMiddleware(req: Request, res: Response, next: NextFunction) {
const authHeader = req.headers.authorization;
if (!authHeader || !authHeader.startsWith('Bearer ')) {
return next(new AppError('Unauthorized: Bearer token missing or malformed', 401));
}
const token = authHeader.split(' ')[1];
// In a real application, validate JWT or compare with a stored secret securely.
// Using safeCompare for demonstration with a static token.
if (!safeCompare(token, STATIC_AUTH_TOKEN)) {
return next(new AppError('Unauthorized: Invalid token', 401));
}
next();
}
app.get('/', (req: Request, res: Response) => {
res.send('Addons Scanner Utils Example API');
});
app.get('/protected', authMiddleware, (req: Request, res: Response) => {
res.json({ message: 'Access granted to protected resource.' });
});
app.get('/jwt', (req: Request, res: Response, next: NextFunction) => {
try {
const issuer = 'your-service';
const expiresInMinutes = 5;
// In a production environment, ensure JWT_SECRET is a strong, securely stored key.
const jwtToken = makeJWT(issuer, JWT_SECRET, expiresInMinutes);
res.json({ jwt: jwtToken, message: `JWT created for ${issuer}, valid for ${expiresInMinutes} minutes.` });
} catch (error) {
next(new AppError('Failed to create JWT', 500, error as Error));
}
});
app.get('/download-example', async (req: Request, res: Response, next: NextFunction) => {
const fileUrl = 'https://www.google.com/images/branding/googlelogo/1x/googlelogo_color_272x92dp.png'; // Example URL
const destinationPath = '/tmp/downloaded-image.png'; // Ensure /tmp is writable or change path
try {
await downloadFile(fileUrl, destinationPath);
res.json({ message: `File downloaded successfully to ${destinationPath}` });
} catch (error) {
next(new AppError('Failed to download file', 500, error as Error));
}
});
// Error handling middleware
app.use((err: Error, req: Request, res: Response, next: NextFunction) => {
if (err instanceof AppError) {
console.error(`AppError: ${err.message}`, err.originalError);
res.status(err.statusCode).json({
error: err.name,
message: err.message
});
} else {
console.error('Unhandled error:', err);
res.status(500).json({
error: 'InternalServerError',
message: 'An unexpected error occurred.'
});
}
});
app.listen(port, () => {
console.log(`Server listening at http://localhost:${port}`);
});