Analytics package that collects installation statistics for npm packages to help open-source maintainers understand usage patterns.
—
Pending
Does it follow best practices?
Impact
Pending
No eval scenarios have been run
Pending
The risk profile of this skill
Scarf is an analytics package that automatically collects installation statistics for npm packages, helping open-source maintainers understand how their packages are used and by which organizations. It operates transparently during package installation via postinstall hooks and provides configurable opt-in/opt-out mechanisms.
npm install @scarf/scarfconst scarf = require('@scarf/scarf');For ES modules:
import * as scarf from '@scarf/scarf';Scarf is primarily designed to work automatically through npm postinstall hooks:
{
"name": "your-package",
"scripts": {
"postinstall": "node ./node_modules/@scarf/scarf"
},
"dependencies": {
"@scarf/scarf": "^1.4.0"
}
}The package automatically reports analytics when installed as a dependency. No additional code is required for basic functionality.
Scarf operates through several key components:
Control Scarf behavior through environment variables:
SCARF_ANALYTICS=false - Disables analytics collectionSCARF_NO_ANALYTICS=true - Legacy disable flagDO_NOT_TRACK=1 - Respects Console Do Not Track standardSCARF_VERBOSE=true - Enables verbose logging outputSCARF_API_TOKEN - API authentication token for custom endpointsConfigure Scarf behavior in your package.json:
{
"scarfSettings": {
"enabled": true,
"defaultOptIn": true,
"allowTopLevel": false,
"skipTraversal": false
}
}Main function that collects and sends installation analytics to Scarf servers.
/**
* Collect and report installation analytics
* @returns {Promise<void>} Promise that resolves when reporting completes
* @throws {Error} When analytics are disabled or reporting fails
*/
function reportPostInstall(): Promise<void>;Analyzes npm dependency tree to understand package relationships and configuration.
/**
* Analyze npm dependency tree to find package relationships
* @param {string} [packageJSONOverride] - Optional path to package.json for testing
* @returns {Promise<DependencyInfo>} Dependency information object
*/
function getDependencyInfo(packageJSONOverride?: string): Promise<DependencyInfo>;
/**
* Find all paths to @scarf/scarf in dependency tree
* @param {Object} tree - npm ls dependency tree object
* @returns {Array<Array<Object>>} Array of dependency chain arrays
*/
function findScarfInFullDependencyTree(tree: Object): Array<Array<Object>>;Functions that handle sensitive data redaction and hashing before transmission.
/**
* Remove sensitive information from dependency data
* @param {DependencyInfo} dependencyInfo - Dependency information object
* @returns {DependencyInfo} Sanitized dependency info object
*/
function redactSensitivePackageInfo(dependencyInfo: DependencyInfo): DependencyInfo;
/**
* Create SHA256 hash of input string with fallback value
* @param {string} toHash - String to hash
* @param {string} defaultReturn - Fallback value if hashing fails
* @returns {string} Hash or default value
*/
function hashWithDefault(toHash: string, defaultReturn: string): string;Retrieves Git commit information for enhanced analytics when available.
/**
* Retrieve Git commit SHA from current repository
* @returns {Promise<string|undefined>} Git SHA or undefined if unavailable
*/
function getGitShaFromRootPath(): Promise<string | undefined>;Prevents spam messaging to users during multiple package installations.
/**
* Log messages to users with rate limiting
* @param {string} rateLimitKey - Unique key for rate limiting
* @param {string} toLog - Message to log
*/
function rateLimitedUserLog(rateLimitKey: string, toLog: string): void;
/**
* Check if rate limit has been exceeded for a given key
* @param {string} rateLimitKey - Rate limit key to check
* @param {Object} history - Rate limit history object
* @returns {boolean} True if rate limit has been hit
*/
function hasHitRateLimit(rateLimitKey: string, history: Object): boolean;
/**
* Retrieve rate limiting history from temporary file
* @returns {Object} Rate limit history data
*/
function getRateLimitedLogHistory(): Object;Utility functions for environment detection and path management.
/**
* Generate temporary file name for rate limiting history
* @returns {string} Temporary file path
*/
function tmpFileName(): string;
/**
* Get current directory name (testable __dirname wrapper)
* @returns {string} Current directory path
*/
function dirName(): string;
/**
* Get npm executable path from environment
* @returns {string} npm executable path
*/
function npmExecPath(): string;Callback factory functions for processing command output (primarily for testing).
/**
* Create callback function for processing npm ls command output
* @param {Function} resolve - Promise resolve callback
* @param {Function} reject - Promise reject callback
* @returns {Function} Callback function for processing npm ls output
*/
function processDependencyTreeOutput(resolve: Function, reject: Function): Function;
/**
* Create callback function for processing git rev-parse command output
* @param {Function} resolve - Promise resolve callback
* @param {Function} reject - Promise reject callback
* @returns {Function} Callback function for processing git output
*/
function processGitRevParseOutput(resolve: Function, reject: Function): Function;Complete dependency relationship information for analytics reporting.
interface DependencyInfo {
scarf: {
name: string;
version: string;
path?: string;
};
parent: {
name: string;
version: string;
scarfSettings?: ScarfSettings;
path?: string;
gitSha?: string;
};
grandparent?: {
name: string;
version: string;
path?: string;
nameHash?: string;
versionHash?: string;
};
rootPackage: {
name: string;
version: string;
packageJsonPath: string;
path?: string;
nameHash?: string;
versionHash?: string;
};
anyInChainDisabled: boolean;
skippedTraversal?: boolean;
}Configuration options for Scarf behavior in package.json.
interface ScarfSettings {
/** Enable or disable Scarf for this package */
enabled?: boolean;
/** Whether users are opted into analytics by default */
defaultOptIn?: boolean;
/** Allow analytics when package is installed at root level */
allowTopLevel?: boolean;
/** Skip dependency tree traversal for large projects */
skipTraversal?: boolean;
}Data structure sent to Scarf analytics endpoint.
interface AnalyticsPayload {
libraryType: 'npm';
rawPlatform: string;
rawArch: string;
nodeVersion: string;
dependencyInfo: DependencyInfo;
}While primarily automatic, functions can be called programmatically for testing or advanced use cases:
const scarf = require('@scarf/scarf');
// Manually trigger analytics reporting
try {
await scarf.reportPostInstall();
console.log('Analytics reported successfully');
} catch (error) {
console.log('Analytics disabled or failed:', error.message);
}
// Analyze dependency information
const depInfo = await scarf.getDependencyInfo();
console.log('Package relationships:', depInfo);
// Check rate limiting status
const history = scarf.getRateLimitedLogHistory();
const hitLimit = scarf.hasHitRateLimit('test-key', history);
console.log('Rate limit hit:', hitLimit);Opt-out by default with manual opt-in:
{
"scarfSettings": {
"defaultOptIn": false
}
}Enable for top-level installations:
{
"scarfSettings": {
"allowTopLevel": true
}
}Skip dependency traversal for large projects:
{
"scarfSettings": {
"skipTraversal": true
}
}Complete configuration:
{
"scarfSettings": {
"enabled": true,
"defaultOptIn": true,
"allowTopLevel": true,
"skipTraversal": false
}
}