next
Version:
The React Framework
31 lines • 6.86 kB
JavaScript
"use strict";exports.__esModule=true;exports.Telemetry=void 0;var _chalk=_interopRequireDefault(require("chalk"));var _conf=_interopRequireDefault(require("next/dist/compiled/conf"));var _crypto=require("crypto");var _isDocker=_interopRequireDefault(require("next/dist/compiled/is-docker"));var _path=_interopRequireDefault(require("path"));var _anonymousMeta=require("./anonymous-meta");var ciEnvironment=_interopRequireWildcard(require("./ci-info"));var _postPayload2=require("./post-payload");var _projectId=require("./project-id");function _getRequireWildcardCache(){if(typeof WeakMap!=="function")return null;var cache=new WeakMap();_getRequireWildcardCache=function(){return cache;};return cache;}function _interopRequireWildcard(obj){if(obj&&obj.__esModule){return obj;}if(obj===null||typeof obj!=="object"&&typeof obj!=="function"){return{default:obj};}var cache=_getRequireWildcardCache();if(cache&&cache.has(obj)){return cache.get(obj);}var newObj={};var hasPropertyDescriptor=Object.defineProperty&&Object.getOwnPropertyDescriptor;for(var key in obj){if(Object.prototype.hasOwnProperty.call(obj,key)){var desc=hasPropertyDescriptor?Object.getOwnPropertyDescriptor(obj,key):null;if(desc&&(desc.get||desc.set)){Object.defineProperty(newObj,key,desc);}else{newObj[key]=obj[key];}}}newObj.default=obj;if(cache){cache.set(obj,newObj);}return newObj;}function _interopRequireDefault(obj){return obj&&obj.__esModule?obj:{default:obj};}// This is the key that stores whether or not telemetry is enabled or disabled.
const TELEMETRY_KEY_ENABLED='telemetry.enabled';// This is the key that specifies when the user was informed about anonymous
// telemetry collection.
const TELEMETRY_KEY_NOTIFY_DATE='telemetry.notifiedAt';// This is a quasi-persistent identifier used to dedupe recurring events. It's
// generated from random data and completely anonymous.
const TELEMETRY_KEY_ID=`telemetry.anonymousId`;// This is the cryptographic salt that is included within every hashed value.
// This salt value is never sent to us, ensuring privacy and the one-way nature
// of the hash (prevents dictionary lookups of pre-computed hashes).
// See the `oneWayHash` function.
const TELEMETRY_KEY_SALT=`telemetry.salt`;class Telemetry{constructor({distDir}){this.conf=void 0;this.sessionId=void 0;this.rawProjectId=void 0;this.NEXT_TELEMETRY_DISABLED=void 0;this.NEXT_TELEMETRY_DEBUG=void 0;this.queue=void 0;this.notify=()=>{if(this.isDisabled||!this.conf){return;}// The end-user has already been notified about our telemetry integration. We
// don't need to constantly annoy them about it.
// We will re-inform users about the telemetry if significant changes are
// ever made.
if(this.conf.get(TELEMETRY_KEY_NOTIFY_DATE,'')){return;}this.conf.set(TELEMETRY_KEY_NOTIFY_DATE,Date.now().toString());console.log(`${_chalk.default.magenta.bold('Attention')}: Next.js now collects completely anonymous telemetry regarding usage.`);console.log(`This information is used to shape Next.js' roadmap and prioritize features.`);console.log(`You can learn more, including how to opt-out if you'd not like to participate in this anonymous program, by visiting the following URL:`);console.log(_chalk.default.cyan('https://nextjs.org/telemetry'));console.log();};this.setEnabled=_enabled=>{const enabled=!!_enabled;this.conf&&this.conf.set(TELEMETRY_KEY_ENABLED,enabled);};this.oneWayHash=payload=>{const hash=(0,_crypto.createHash)('sha256');// Always prepend the payload value with salt. This ensures the hash is truly
// one-way.
hash.update(this.salt);// Update is an append operation, not a replacement. The salt from the prior
// update is still present!
hash.update(payload);return hash.digest('hex');};this.record=_events=>{const _this=this;// pseudo try-catch
async function wrapper(){return await _this.submitRecord(_events);}const prom=wrapper().then(value=>({isFulfilled:true,isRejected:false,value})).catch(reason=>({isFulfilled:false,isRejected:true,reason}))// Acts as `Promise#finally` because `catch` transforms the error
.then(res=>{// Clean up the event to prevent unbounded `Set` growth
this.queue.delete(prom);return res;});// Track this `Promise` so we can flush pending events
this.queue.add(prom);return prom;};this.flush=async()=>Promise.all(this.queue).catch(()=>null);this.submitRecord=_events=>{let events;if(Array.isArray(_events)){events=_events;}else{events=[_events];}if(events.length<1){return Promise.resolve();}if(this.NEXT_TELEMETRY_DEBUG){// Print to standard error to simplify selecting the output
events.forEach(({eventName,payload})=>console.error(`[telemetry] `+JSON.stringify({eventName,payload},null,2)));// Do not send the telemetry data if debugging. Users may use this feature
// to preview what data would be sent.
return Promise.resolve();}// Skip recording telemetry if the feature is disabled
if(this.isDisabled){return Promise.resolve();}const context={anonymousId:this.anonymousId,projectId:this.projectId,sessionId:this.sessionId};const meta=(0,_anonymousMeta.getAnonymousMeta)();return(0,_postPayload2._postPayload)(`https://telemetry.nextjs.org/api/v1/record`,{context,meta,events:events.map(({eventName,payload})=>({eventName,fields:payload}))});};// Read in the constructor so that .env can be loaded before reading
const{NEXT_TELEMETRY_DISABLED,NEXT_TELEMETRY_DEBUG}=process.env;this.NEXT_TELEMETRY_DISABLED=NEXT_TELEMETRY_DISABLED;this.NEXT_TELEMETRY_DEBUG=NEXT_TELEMETRY_DEBUG;const storageDirectory=getStorageDirectory(distDir);try{// `conf` incorrectly throws a permission error during initialization
// instead of waiting for first use. We need to handle it, otherwise the
// process may crash.
this.conf=new _conf.default({projectName:'nextjs',cwd:storageDirectory});}catch(_){this.conf=null;}this.sessionId=(0,_crypto.randomBytes)(32).toString('hex');this.rawProjectId=(0,_projectId.getRawProjectId)();this.queue=new Set();this.notify();}get anonymousId(){const val=this.conf&&this.conf.get(TELEMETRY_KEY_ID);if(val){return val;}const generated=(0,_crypto.randomBytes)(32).toString('hex');this.conf&&this.conf.set(TELEMETRY_KEY_ID,generated);return generated;}get salt(){const val=this.conf&&this.conf.get(TELEMETRY_KEY_SALT);if(val){return val;}const generated=(0,_crypto.randomBytes)(16).toString('hex');this.conf&&this.conf.set(TELEMETRY_KEY_SALT,generated);return generated;}get isDisabled(){if(!!this.NEXT_TELEMETRY_DISABLED||!this.conf){return true;}return this.conf.get(TELEMETRY_KEY_ENABLED,true)===false;}get isEnabled(){return!!this.conf&&this.conf.get(TELEMETRY_KEY_ENABLED,true)!==false;}get projectId(){return this.oneWayHash(this.rawProjectId);}}exports.Telemetry=Telemetry;function getStorageDirectory(distDir){const isLikelyEphemeral=ciEnvironment.isCI||(0,_isDocker.default)();if(isLikelyEphemeral){return _path.default.join(distDir,'cache');}return undefined;}
//# sourceMappingURL=storage.js.map