{"id":12795,"library":"addons-scanner-utils","title":"Addons Scanner Utilities","description":"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.","status":"active","version":"15.0.0","language":"javascript","source_language":"en","source_url":"git://github.com/mozilla/addons-scanner-utils","tags":["javascript","typescript"],"install":[{"cmd":"npm install addons-scanner-utils","lang":"bash","label":"npm"},{"cmd":"yarn add addons-scanner-utils","lang":"bash","label":"yarn"},{"cmd":"pnpm add addons-scanner-utils","lang":"bash","label":"pnpm"}],"dependencies":[{"reason":"Peer dependency for building web APIs and integrating with middleware, crucial for handling requests and responses, especially for authentication layers. Used for HTTP server functionality.","package":"express","optional":false},{"reason":"Peer dependency used for constant-time string comparison, important for mitigating timing attacks in authentication and security-sensitive operations.","package":"safe-compare","optional":false}],"imports":[{"note":"The error class was renamed from `ApiError` to `AppError` in version 14.0.0. This package is primarily ESM-first since Node.js 22+ is a requirement.","wrong":"import { ApiError } from 'addons-scanner-utils';\nconst { AppError } = require('addons-scanner-utils');","symbol":"AppError","correct":"import { AppError } from 'addons-scanner-utils';"},{"note":"Introduced in version 13.1.0 to facilitate JWT generation for AMO. Ensure your project environment is configured for ES modules.","wrong":"const { makeJWT } = require('addons-scanner-utils');","symbol":"makeJWT","correct":"import { makeJWT } from 'addons-scanner-utils';"},{"note":"A utility function for downloading files, introduced in version 13.1.0. For older Express handler functionality for XPIs, see breaking change warnings.","wrong":"const { downloadFile } = require('addons-scanner-utils');","symbol":"downloadFile","correct":"import { downloadFile } from 'addons-scanner-utils';"}],"quickstart":{"code":"import express, { Request, Response, NextFunction } from 'express';\nimport { AppError, makeJWT, downloadFile } from 'addons-scanner-utils';\nimport safeCompare from 'safe-compare'; // from peer dependency\n\nconst app = express();\nconst port = 3000;\n\n// A placeholder for a secret key for HMAC-SHA256 or JWT signing\nconst JWT_SECRET = process.env.JWT_SECRET ?? 'super_secret_jwt_key_please_change';\nconst STATIC_AUTH_TOKEN = process.env.STATIC_AUTH_TOKEN ?? 'my-secure-token-123_please_change';\n\n// Middleware to simulate an authentication check (e.g., Bearer token)\nfunction authMiddleware(req: Request, res: Response, next: NextFunction) {\n  const authHeader = req.headers.authorization;\n  if (!authHeader || !authHeader.startsWith('Bearer ')) {\n    return next(new AppError('Unauthorized: Bearer token missing or malformed', 401));\n  }\n  const token = authHeader.split(' ')[1];\n  // In a real application, validate JWT or compare with a stored secret securely.\n  // Using safeCompare for demonstration with a static token.\n  if (!safeCompare(token, STATIC_AUTH_TOKEN)) {\n    return next(new AppError('Unauthorized: Invalid token', 401));\n  }\n  next();\n}\n\napp.get('/', (req: Request, res: Response) => {\n  res.send('Addons Scanner Utils Example API');\n});\n\napp.get('/protected', authMiddleware, (req: Request, res: Response) => {\n  res.json({ message: 'Access granted to protected resource.' });\n});\n\napp.get('/jwt', (req: Request, res: Response, next: NextFunction) => {\n  try {\n    const issuer = 'your-service';\n    const expiresInMinutes = 5;\n    // In a production environment, ensure JWT_SECRET is a strong, securely stored key.\n    const jwtToken = makeJWT(issuer, JWT_SECRET, expiresInMinutes);\n    res.json({ jwt: jwtToken, message: `JWT created for ${issuer}, valid for ${expiresInMinutes} minutes.` });\n  } catch (error) {\n    next(new AppError('Failed to create JWT', 500, error as Error));\n  }\n});\n\napp.get('/download-example', async (req: Request, res: Response, next: NextFunction) => {\n  const fileUrl = 'https://www.google.com/images/branding/googlelogo/1x/googlelogo_color_272x92dp.png'; // Example URL\n  const destinationPath = '/tmp/downloaded-image.png'; // Ensure /tmp is writable or change path\n\n  try {\n    await downloadFile(fileUrl, destinationPath);\n    res.json({ message: `File downloaded successfully to ${destinationPath}` });\n  } catch (error) {\n    next(new AppError('Failed to download file', 500, error as Error));\n  }\n});\n\n// Error handling middleware\napp.use((err: Error, req: Request, res: Response, next: NextFunction) => {\n  if (err instanceof AppError) {\n    console.error(`AppError: ${err.message}`, err.originalError);\n    res.status(err.statusCode).json({\n      error: err.name,\n      message: err.message\n    });\n  } else {\n    console.error('Unhandled error:', err);\n    res.status(500).json({\n      error: 'InternalServerError',\n      message: 'An unexpected error occurred.'\n    });\n  }\n});\n\napp.listen(port, () => {\n  console.log(`Server listening at http://localhost:${port}`);\n});","lang":"typescript","description":"This quickstart demonstrates a basic Express.js application integrating `addons-scanner-utils` for error handling (`AppError`), JWT generation (`makeJWT`), file downloading (`downloadFile`), and custom authentication logic using `safe-compare`."},"warnings":[{"fix":"Update all import statements and class instantiations from `ApiError` to `AppError`.","message":"The `ApiError` class was renamed to `AppError`. Direct references to `ApiError` will cause runtime errors.","severity":"breaking","affected_versions":">=14.0.0"},{"fix":"Upgrade your Node.js runtime environment to version 22 or newer to ensure compatibility.","message":"This library now requires Node.js version 22 or higher to run. Older Node.js versions are no longer supported.","severity":"gotcha","affected_versions":">=13.0.0"},{"fix":"Modify client-side applications to send authentication tokens exclusively within the `Authorization` HTTP header.","message":"The internal authentication layer, if used, now strictly requires credentials to be passed via an `Authorization` HTTP header instead of a request body parameter.","severity":"breaking","affected_versions":">=10.0.0"},{"fix":"Review and update any existing authentication logic that utilized the library's `Bearer` token utilities. Implement custom authentication middleware or handlers for processing Bearer tokens if necessary.","message":"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.","severity":"breaking","affected_versions":">=15.0.0"},{"fix":"Manually implement XPI file download logic using a custom Express route and potentially the `downloadFile` utility function provided by the library (introduced in v13.1.0).","message":"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.","severity":"breaking","affected_versions":">=11.0.0"}],"env_vars":null,"last_verified":"2026-04-19T00:00:00.000Z","next_check":"2026-07-18T00:00:00.000Z","problems":[{"fix":"Replace all occurrences of `ApiError` with `AppError` in your code, including import statements.","cause":"The `ApiError` class was renamed to `AppError` in version 14.0.0.","error":"ReferenceError: ApiError is not defined"},{"fix":"Update your Node.js runtime to version 22 or a later compatible version.","cause":"The application is running in an environment with an outdated Node.js version.","error":"Error: This module requires Node.js version 22 or higher."},{"fix":"Refactor your import statements to use ES module syntax: `import { makeJWT } from 'addons-scanner-utils';` and ensure your project supports ESM.","cause":"Attempting to use CommonJS `require()` syntax to import ES module named exports.","error":"TypeError: (0 , addons_scanner_utils_1.makeJWT) is not a function"},{"fix":"Ensure the client sends a correctly formatted `Authorization: Bearer YOUR_TOKEN` header. If using the library's internal auth (pre-v15), verify configuration. For v15+, implement custom Bearer token validation logic.","cause":"The incoming request is missing the `Authorization` header, or its `Bearer` token format is incorrect, or the library's internal auth logic no longer supports this method (v15).","error":"Unauthorized: Bearer token missing or malformed"}],"ecosystem":"npm","meta_description":null,"install_score":null,"install_tag":null,"quickstart_score":null,"quickstart_tag":null,"pypi_latest":null}