Last commit july 5th

This commit is contained in:
2024-07-05 13:46:23 +02:00
parent dad0d86e8c
commit b0e4dfbb76
24982 changed files with 2621219 additions and 413 deletions

186
spa/node_modules/insight/lib/index.js generated vendored Normal file
View File

@@ -0,0 +1,186 @@
'use strict';
const path = require('path');
const childProcess = require('child_process');
const osName = require('os-name');
const Conf = require('conf');
const chalk = require('chalk');
const debounce = require('lodash.debounce');
const inquirer = require('inquirer');
const uuid = require('uuid');
const providers = require('./providers.js');
const DEBOUNCE_MS = 100;
class Insight {
constructor(options) {
options = options || {};
options.pkg = options.pkg || {};
// Deprecated options
// TODO: Remove these at some point in the future
if (options.packageName) {
options.pkg.name = options.packageName;
}
if (options.packageVersion) {
options.pkg.version = options.packageVersion;
}
if (!options.trackingCode || !options.pkg.name) {
throw new Error('trackingCode and pkg.name required');
}
this.trackingCode = options.trackingCode;
this.trackingProvider = options.trackingProvider || 'google';
this.packageName = options.pkg.name;
this.packageVersion = options.pkg.version || 'undefined';
this.os = osName();
this.nodeVersion = process.version;
this.appVersion = this.packageVersion;
this.config = options.config || new Conf({
configName: `insight-${this.packageName}`,
defaults: {
clientId: options.clientId || Math.floor(Date.now() * Math.random()),
},
});
this._queue = {};
this._permissionTimeout = 30;
this._debouncedSend = debounce(this._send, DEBOUNCE_MS, {leading: true});
}
get optOut() {
return this.config.get('optOut');
}
set optOut(value) {
this.config.set('optOut', value);
}
get clientId() {
return this.config.get('clientId');
}
set clientId(value) {
this.config.set('clientId', value);
}
_save() {
setImmediate(() => {
this._debouncedSend();
});
}
_send() {
const pending = Object.keys(this._queue).length;
if (pending === 0) {
return;
}
this._fork(this._getPayload());
this._queue = {};
}
_fork(payload) {
// Extracted to a method so it can be easily mocked
const cp = childProcess.fork(path.join(__dirname, 'push.js'), {silent: true});
cp.send(payload);
cp.unref();
cp.disconnect();
}
_getPayload() {
return {
queue: {...this._queue},
packageName: this.packageName,
packageVersion: this.packageVersion,
trackingCode: this.trackingCode,
trackingProvider: this.trackingProvider,
};
}
_getRequestObj(...args) {
return providers[this.trackingProvider].apply(this, args);
}
track(...args) {
if (this.optOut) {
return;
}
const path = '/' + args.map(element => String(element).trim().replace(/ /, '-')).join('/');
// Timestamp isn't unique enough since it can end up with duplicate entries
this._queue[`${Date.now()} ${uuid.v4()}`] = {
path,
type: 'pageview',
};
this._save();
}
trackEvent(options) {
if (this.optOut) {
return;
}
if (this.trackingProvider !== 'google') {
throw new Error('Event tracking is supported only for Google Analytics');
}
if (!options || !options.category || !options.action) {
throw new Error('`category` and `action` required');
}
// Timestamp isn't unique enough since it can end up with duplicate entries
this._queue[`${Date.now()} ${uuid.v4()}`] = {
category: options.category,
action: options.action,
label: options.label,
value: options.value,
type: 'event',
};
this._save();
}
askPermission(message) {
const defaultMessage = `May ${chalk.cyan(this.packageName)} anonymously report usage statistics to improve the tool over time?`;
if (!process.stdout.isTTY || process.argv.includes('--no-insight') || process.env.CI) {
return Promise.resolve();
}
const prompt = inquirer.prompt({
type: 'confirm',
name: 'optIn',
message: message || defaultMessage,
default: true,
});
// Set a 30 sec timeout before giving up on getting an answer
let permissionTimeout;
const timeoutPromise = new Promise(resolve => {
permissionTimeout = setTimeout(() => {
// Stop listening for stdin
prompt.ui.close();
// Automatically opt out
this.optOut = true;
resolve(false);
}, this._permissionTimeout * 1000);
});
const promise = (async () => {
const {optIn} = await prompt;
// Clear the permission timeout upon getting an answer
clearTimeout(permissionTimeout);
this.optOut = !optIn;
return optIn;
})();
// Return the result of the prompt if it finishes first otherwise default to the timeout's value.
return Promise.race([promise, timeoutPromise]);
}
}
module.exports = Insight;

104
spa/node_modules/insight/lib/providers.js generated vendored Normal file
View File

@@ -0,0 +1,104 @@
'use strict';
const qs = require('querystring');
/**
* Tracking providers
*
* Each provider is a function(id, path) that should return
* options object for request() call. It will be called bound
* to Insight instance object.
*/
module.exports = {
// Google Analytics — https://www.google.com/analytics/
google(id, payload) {
const now = Date.now();
const _qs = {
// GA Measurement Protocol API version
v: 1,
// Hit type
t: payload.type,
// Anonymize IP
aip: 1,
tid: this.trackingCode,
// Random UUID
cid: this.clientId,
cd1: this.os,
// GA custom dimension 2 = Node Version, scope = Session
cd2: this.nodeVersion,
// GA custom dimension 3 = App Version, scope = Session (temp solution until refactored to work w/ GA app tracking)
cd3: this.appVersion,
// Queue time - delta (ms) between now and track time
qt: now - Number.parseInt(id, 10),
// Cache busting, need to be last param sent
z: now,
};
// Set payload data based on the tracking type
if (payload.type === 'event') {
_qs.ec = payload.category;
_qs.ea = payload.action;
if (payload.label) {
_qs.el = payload.label;
}
if (payload.value) {
_qs.ev = payload.value;
}
} else {
_qs.dp = payload.path;
}
return {
url: 'https://ssl.google-analytics.com/collect',
method: 'POST',
// GA docs recommends body payload via POST instead of querystring via GET
body: qs.stringify(_qs),
};
},
// Yandex.Metrica - https://metrica.yandex.com
yandex(id, payload) {
const request = require('request');
const ts = new Date(Number.parseInt(id, 10))
.toISOString()
.replace(/[-:T]/g, '')
.replace(/\..*$/, '');
const {path} = payload;
const qs = {
wmode: 3,
ut: 'noindex',
'page-url': `http://${this.packageName}.insight${path}?version=${this.packageVersion}`,
'browser-info': `i:${ts}:z:0:t:${path}`,
// Cache busting
rn: Date.now(),
};
const url = `https://mc.yandex.ru/watch/${this.trackingCode}`;
// Set custom cookie using tough-cookie
const _jar = request.jar();
const cookieString = `name=yandexuid; value=${this.clientId}; path=/;`;
const cookie = request.cookie(cookieString);
_jar.setCookie(cookie, url);
return {
url,
method: 'GET',
qs,
jar: _jar,
};
},
};

39
spa/node_modules/insight/lib/push.js generated vendored Normal file
View File

@@ -0,0 +1,39 @@
'use strict';
const request = require('request');
const async = require('async');
const Insight = require('.');
// Messaged on each debounced `track()`
// Gets the queue, merges is with the previous and tries to upload everything
// If it fails, it will save everything again
process.on('message', message => {
const insight = new Insight(message);
const {config} = insight;
const q = config.get('queue') || {};
Object.assign(q, message.queue);
config.delete('queue');
async.forEachSeries(Object.keys(q), (element, cb) => {
const parts = element.split(' ');
const id = parts[0];
const payload = q[element];
request(insight._getRequestObj(id, payload), error => {
if (error) {
cb(error);
return;
}
cb();
});
}, error => {
if (error) {
const q2 = config.get('queue') || {};
Object.assign(q2, q);
config.set('queue', q2);
}
process.exit();
});
});