Analytics package that collects installation statistics for npm packages to help open-source maintainers understand usage patterns.
npx @tessl/cli install tessl/npm-scarf--scarf@1.4.00
# Scarf Analytics
1
2
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.
3
4
## Package Information
5
6
- **Package Name**: @scarf/scarf
7
- **Package Type**: npm
8
- **Language**: JavaScript (Node.js)
9
- **Installation**: `npm install @scarf/scarf`
10
11
## Core Imports
12
13
```javascript
14
const scarf = require('@scarf/scarf');
15
```
16
17
For ES modules:
18
19
```javascript
20
import * as scarf from '@scarf/scarf';
21
```
22
23
## Basic Usage
24
25
Scarf is primarily designed to work automatically through npm postinstall hooks:
26
27
```json
28
{
29
"name": "your-package",
30
"scripts": {
31
"postinstall": "node ./node_modules/@scarf/scarf"
32
},
33
"dependencies": {
34
"@scarf/scarf": "^1.4.0"
35
}
36
}
37
```
38
39
The package automatically reports analytics when installed as a dependency. No additional code is required for basic functionality.
40
41
## Architecture
42
43
Scarf operates through several key components:
44
45
- **Automatic Execution**: Runs via npm postinstall hooks during package installation
46
- **Dependency Analysis**: Traverses npm dependency trees to understand package relationships
47
- **Privacy Protection**: Hashes sensitive package information before transmission
48
- **User Consent Management**: Respects user preferences and environment-based opt-out settings
49
- **Rate Limiting**: Prevents spam messaging to users across multiple installations
50
51
## Configuration
52
53
### Environment Variables
54
55
Control Scarf behavior through environment variables:
56
57
- `SCARF_ANALYTICS=false` - Disables analytics collection
58
- `SCARF_NO_ANALYTICS=true` - Legacy disable flag
59
- `DO_NOT_TRACK=1` - Respects Console Do Not Track standard
60
- `SCARF_VERBOSE=true` - Enables verbose logging output
61
- `SCARF_API_TOKEN` - API authentication token for custom endpoints
62
63
### Package.json Configuration
64
65
Configure Scarf behavior in your package.json:
66
67
```json
68
{
69
"scarfSettings": {
70
"enabled": true,
71
"defaultOptIn": true,
72
"allowTopLevel": false,
73
"skipTraversal": false
74
}
75
}
76
```
77
78
## Capabilities
79
80
### Analytics Reporting
81
82
Main function that collects and sends installation analytics to Scarf servers.
83
84
```javascript { .api }
85
/**
86
* Collect and report installation analytics
87
* @returns {Promise<void>} Promise that resolves when reporting completes
88
* @throws {Error} When analytics are disabled or reporting fails
89
*/
90
function reportPostInstall(): Promise<void>;
91
```
92
93
### Dependency Analysis
94
95
Analyzes npm dependency tree to understand package relationships and configuration.
96
97
```javascript { .api }
98
/**
99
* Analyze npm dependency tree to find package relationships
100
* @param {string} [packageJSONOverride] - Optional path to package.json for testing
101
* @returns {Promise<DependencyInfo>} Dependency information object
102
*/
103
function getDependencyInfo(packageJSONOverride?: string): Promise<DependencyInfo>;
104
105
/**
106
* Find all paths to @scarf/scarf in dependency tree
107
* @param {Object} tree - npm ls dependency tree object
108
* @returns {Array<Array<Object>>} Array of dependency chain arrays
109
*/
110
function findScarfInFullDependencyTree(tree: Object): Array<Array<Object>>;
111
```
112
113
### Privacy Protection
114
115
Functions that handle sensitive data redaction and hashing before transmission.
116
117
```javascript { .api }
118
/**
119
* Remove sensitive information from dependency data
120
* @param {DependencyInfo} dependencyInfo - Dependency information object
121
* @returns {DependencyInfo} Sanitized dependency info object
122
*/
123
function redactSensitivePackageInfo(dependencyInfo: DependencyInfo): DependencyInfo;
124
125
/**
126
* Create SHA256 hash of input string with fallback value
127
* @param {string} toHash - String to hash
128
* @param {string} defaultReturn - Fallback value if hashing fails
129
* @returns {string} Hash or default value
130
*/
131
function hashWithDefault(toHash: string, defaultReturn: string): string;
132
```
133
134
### Git Integration
135
136
Retrieves Git commit information for enhanced analytics when available.
137
138
```javascript { .api }
139
/**
140
* Retrieve Git commit SHA from current repository
141
* @returns {Promise<string|undefined>} Git SHA or undefined if unavailable
142
*/
143
function getGitShaFromRootPath(): Promise<string | undefined>;
144
```
145
146
### Rate Limiting
147
148
Prevents spam messaging to users during multiple package installations.
149
150
```javascript { .api }
151
/**
152
* Log messages to users with rate limiting
153
* @param {string} rateLimitKey - Unique key for rate limiting
154
* @param {string} toLog - Message to log
155
*/
156
function rateLimitedUserLog(rateLimitKey: string, toLog: string): void;
157
158
/**
159
* Check if rate limit has been exceeded for a given key
160
* @param {string} rateLimitKey - Rate limit key to check
161
* @param {Object} history - Rate limit history object
162
* @returns {boolean} True if rate limit has been hit
163
*/
164
function hasHitRateLimit(rateLimitKey: string, history: Object): boolean;
165
166
/**
167
* Retrieve rate limiting history from temporary file
168
* @returns {Object} Rate limit history data
169
*/
170
function getRateLimitedLogHistory(): Object;
171
```
172
173
### Environment Utilities
174
175
Utility functions for environment detection and path management.
176
177
```javascript { .api }
178
/**
179
* Generate temporary file name for rate limiting history
180
* @returns {string} Temporary file path
181
*/
182
function tmpFileName(): string;
183
184
/**
185
* Get current directory name (testable __dirname wrapper)
186
* @returns {string} Current directory path
187
*/
188
function dirName(): string;
189
190
/**
191
* Get npm executable path from environment
192
* @returns {string} npm executable path
193
*/
194
function npmExecPath(): string;
195
```
196
197
### Internal Processing
198
199
Callback factory functions for processing command output (primarily for testing).
200
201
```javascript { .api }
202
/**
203
* Create callback function for processing npm ls command output
204
* @param {Function} resolve - Promise resolve callback
205
* @param {Function} reject - Promise reject callback
206
* @returns {Function} Callback function for processing npm ls output
207
*/
208
function processDependencyTreeOutput(resolve: Function, reject: Function): Function;
209
210
/**
211
* Create callback function for processing git rev-parse command output
212
* @param {Function} resolve - Promise resolve callback
213
* @param {Function} reject - Promise reject callback
214
* @returns {Function} Callback function for processing git output
215
*/
216
function processGitRevParseOutput(resolve: Function, reject: Function): Function;
217
```
218
219
## Types
220
221
### DependencyInfo
222
223
Complete dependency relationship information for analytics reporting.
224
225
```javascript { .api }
226
interface DependencyInfo {
227
scarf: {
228
name: string;
229
version: string;
230
path?: string;
231
};
232
parent: {
233
name: string;
234
version: string;
235
scarfSettings?: ScarfSettings;
236
path?: string;
237
gitSha?: string;
238
};
239
grandparent?: {
240
name: string;
241
version: string;
242
path?: string;
243
nameHash?: string;
244
versionHash?: string;
245
};
246
rootPackage: {
247
name: string;
248
version: string;
249
packageJsonPath: string;
250
path?: string;
251
nameHash?: string;
252
versionHash?: string;
253
};
254
anyInChainDisabled: boolean;
255
skippedTraversal?: boolean;
256
}
257
```
258
259
### ScarfSettings
260
261
Configuration options for Scarf behavior in package.json.
262
263
```javascript { .api }
264
interface ScarfSettings {
265
/** Enable or disable Scarf for this package */
266
enabled?: boolean;
267
/** Whether users are opted into analytics by default */
268
defaultOptIn?: boolean;
269
/** Allow analytics when package is installed at root level */
270
allowTopLevel?: boolean;
271
/** Skip dependency tree traversal for large projects */
272
skipTraversal?: boolean;
273
}
274
```
275
276
### Analytics Payload
277
278
Data structure sent to Scarf analytics endpoint.
279
280
```javascript { .api }
281
interface AnalyticsPayload {
282
libraryType: 'npm';
283
rawPlatform: string;
284
rawArch: string;
285
nodeVersion: string;
286
dependencyInfo: DependencyInfo;
287
}
288
```
289
290
## Usage Examples
291
292
### Programmatic Usage
293
294
While primarily automatic, functions can be called programmatically for testing or advanced use cases:
295
296
```javascript
297
const scarf = require('@scarf/scarf');
298
299
// Manually trigger analytics reporting
300
try {
301
await scarf.reportPostInstall();
302
console.log('Analytics reported successfully');
303
} catch (error) {
304
console.log('Analytics disabled or failed:', error.message);
305
}
306
307
// Analyze dependency information
308
const depInfo = await scarf.getDependencyInfo();
309
console.log('Package relationships:', depInfo);
310
311
// Check rate limiting status
312
const history = scarf.getRateLimitedLogHistory();
313
const hitLimit = scarf.hasHitRateLimit('test-key', history);
314
console.log('Rate limit hit:', hitLimit);
315
```
316
317
### Configuration Examples
318
319
**Opt-out by default with manual opt-in:**
320
321
```json
322
{
323
"scarfSettings": {
324
"defaultOptIn": false
325
}
326
}
327
```
328
329
**Enable for top-level installations:**
330
331
```json
332
{
333
"scarfSettings": {
334
"allowTopLevel": true
335
}
336
}
337
```
338
339
**Skip dependency traversal for large projects:**
340
341
```json
342
{
343
"scarfSettings": {
344
"skipTraversal": true
345
}
346
}
347
```
348
349
**Complete configuration:**
350
351
```json
352
{
353
"scarfSettings": {
354
"enabled": true,
355
"defaultOptIn": true,
356
"allowTopLevel": true,
357
"skipTraversal": false
358
}
359
}
360
```