This commit is contained in:
Kismet Hasanaj
2026-05-02 20:07:02 +02:00
parent ce8672e283
commit 34dc9aec52
9428 changed files with 1733330 additions and 0 deletions
+17
View File
@@ -0,0 +1,17 @@
type AnonymousMeta = {
systemPlatform: NodeJS.Platform;
systemRelease: string;
systemArchitecture: string;
cpuCount: number;
cpuModel: string | null;
cpuSpeed: number | null;
memoryInMb: number;
isDocker: boolean;
isNowDev: boolean;
isWsl: boolean;
isCI: boolean;
ciName: string | null;
nextVersion: string;
};
export declare function getAnonymousMeta(): AnonymousMeta;
export {};
+89
View File
@@ -0,0 +1,89 @@
"use strict";
Object.defineProperty(exports, "__esModule", {
value: true
});
Object.defineProperty(exports, "getAnonymousMeta", {
enumerable: true,
get: function() {
return getAnonymousMeta;
}
});
const _isdocker = /*#__PURE__*/ _interop_require_default(require("next/dist/compiled/is-docker"));
const _iswsl = /*#__PURE__*/ _interop_require_default(require("next/dist/compiled/is-wsl"));
const _os = /*#__PURE__*/ _interop_require_default(require("os"));
const _ciinfo = /*#__PURE__*/ _interop_require_wildcard(require("../server/ci-info"));
function _interop_require_default(obj) {
return obj && obj.__esModule ? obj : {
default: obj
};
}
function _getRequireWildcardCache(nodeInterop) {
if (typeof WeakMap !== "function") return null;
var cacheBabelInterop = new WeakMap();
var cacheNodeInterop = new WeakMap();
return (_getRequireWildcardCache = function(nodeInterop) {
return nodeInterop ? cacheNodeInterop : cacheBabelInterop;
})(nodeInterop);
}
function _interop_require_wildcard(obj, nodeInterop) {
if (!nodeInterop && obj && obj.__esModule) {
return obj;
}
if (obj === null || typeof obj !== "object" && typeof obj !== "function") {
return {
default: obj
};
}
var cache = _getRequireWildcardCache(nodeInterop);
if (cache && cache.has(obj)) {
return cache.get(obj);
}
var newObj = {
__proto__: null
};
var hasPropertyDescriptor = Object.defineProperty && Object.getOwnPropertyDescriptor;
for(var key in obj){
if (key !== "default" && 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;
}
let traits;
function getAnonymousMeta() {
if (traits) {
return traits;
}
const cpus = _os.default.cpus() || [];
const { NOW_REGION } = process.env;
traits = {
// Software information
systemPlatform: _os.default.platform(),
systemRelease: _os.default.release(),
systemArchitecture: _os.default.arch(),
// Machine information
cpuCount: cpus.length,
cpuModel: cpus.length ? cpus[0].model : null,
cpuSpeed: cpus.length ? cpus[0].speed : null,
memoryInMb: Math.trunc(_os.default.totalmem() / Math.pow(1024, 2)),
// Environment information
isDocker: (0, _isdocker.default)(),
isNowDev: NOW_REGION === 'dev1',
isWsl: _iswsl.default,
isCI: _ciinfo.isCI,
ciName: _ciinfo.isCI && _ciinfo.name || null,
nextVersion: "16.2.0"
};
return traits;
}
//# sourceMappingURL=anonymous-meta.js.map
+1
View File
@@ -0,0 +1 @@
{"version":3,"sources":["../../src/telemetry/anonymous-meta.ts"],"sourcesContent":["import isDockerFunction from 'next/dist/compiled/is-docker'\nimport isWslBoolean from 'next/dist/compiled/is-wsl'\nimport os from 'os'\n\nimport * as ciEnvironment from '../server/ci-info'\n\ntype AnonymousMeta = {\n systemPlatform: NodeJS.Platform\n systemRelease: string\n systemArchitecture: string\n cpuCount: number\n cpuModel: string | null\n cpuSpeed: number | null\n memoryInMb: number\n isDocker: boolean\n isNowDev: boolean\n isWsl: boolean\n isCI: boolean\n ciName: string | null\n nextVersion: string\n}\n\nlet traits: AnonymousMeta | undefined\n\nexport function getAnonymousMeta(): AnonymousMeta {\n if (traits) {\n return traits\n }\n\n const cpus = os.cpus() || []\n const { NOW_REGION } = process.env\n traits = {\n // Software information\n systemPlatform: os.platform(),\n systemRelease: os.release(),\n systemArchitecture: os.arch(),\n // Machine information\n cpuCount: cpus.length,\n cpuModel: cpus.length ? cpus[0].model : null,\n cpuSpeed: cpus.length ? cpus[0].speed : null,\n memoryInMb: Math.trunc(os.totalmem() / Math.pow(1024, 2)),\n // Environment information\n isDocker: isDockerFunction(),\n isNowDev: NOW_REGION === 'dev1',\n isWsl: isWslBoolean,\n isCI: ciEnvironment.isCI,\n ciName: (ciEnvironment.isCI && ciEnvironment.name) || null,\n nextVersion: process.env.__NEXT_VERSION as string,\n }\n\n return traits\n}\n"],"names":["getAnonymousMeta","traits","cpus","os","NOW_REGION","process","env","systemPlatform","platform","systemRelease","release","systemArchitecture","arch","cpuCount","length","cpuModel","model","cpuSpeed","speed","memoryInMb","Math","trunc","totalmem","pow","isDocker","isDockerFunction","isNowDev","isWsl","isWslBoolean","isCI","ciEnvironment","ciName","name","nextVersion","__NEXT_VERSION"],"mappings":";;;;+BAwBgBA;;;eAAAA;;;iEAxBa;8DACJ;2DACV;gEAEgB;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;AAkB/B,IAAIC;AAEG,SAASD;IACd,IAAIC,QAAQ;QACV,OAAOA;IACT;IAEA,MAAMC,OAAOC,WAAE,CAACD,IAAI,MAAM,EAAE;IAC5B,MAAM,EAAEE,UAAU,EAAE,GAAGC,QAAQC,GAAG;IAClCL,SAAS;QACP,uBAAuB;QACvBM,gBAAgBJ,WAAE,CAACK,QAAQ;QAC3BC,eAAeN,WAAE,CAACO,OAAO;QACzBC,oBAAoBR,WAAE,CAACS,IAAI;QAC3B,sBAAsB;QACtBC,UAAUX,KAAKY,MAAM;QACrBC,UAAUb,KAAKY,MAAM,GAAGZ,IAAI,CAAC,EAAE,CAACc,KAAK,GAAG;QACxCC,UAAUf,KAAKY,MAAM,GAAGZ,IAAI,CAAC,EAAE,CAACgB,KAAK,GAAG;QACxCC,YAAYC,KAAKC,KAAK,CAAClB,WAAE,CAACmB,QAAQ,KAAKF,KAAKG,GAAG,CAAC,MAAM;QACtD,0BAA0B;QAC1BC,UAAUC,IAAAA,iBAAgB;QAC1BC,UAAUtB,eAAe;QACzBuB,OAAOC,cAAY;QACnBC,MAAMC,QAAcD,IAAI;QACxBE,QAAQ,AAACD,QAAcD,IAAI,IAAIC,QAAcE,IAAI,IAAK;QACtDC,aAAa5B,QAAQC,GAAG,CAAC4B,cAAc;IACzC;IAEA,OAAOjC;AACT","ignoreList":[0]}
+1
View File
@@ -0,0 +1 @@
export {};
+56
View File
@@ -0,0 +1,56 @@
"use strict";
Object.defineProperty(exports, "__esModule", {
value: true
});
const _fs = /*#__PURE__*/ _interop_require_default(require("fs"));
const _path = /*#__PURE__*/ _interop_require_default(require("path"));
const _storage = require("./storage");
const _config = /*#__PURE__*/ _interop_require_default(require("../server/config"));
const _getprojectdir = require("../lib/get-project-dir");
const _constants = require("../shared/lib/constants");
function _interop_require_default(obj) {
return obj && obj.__esModule ? obj : {
default: obj
};
}
(async ()=>{
const args = [
...process.argv
];
const eventsFile = args.pop();
let dir = args.pop();
const mode = args.pop();
if (!dir || mode !== 'dev') {
throw Object.defineProperty(new Error(`Invalid flags should be run as node detached-flush dev ./path-to/project [eventsFile]`), "__NEXT_ERROR_CODE", {
value: "E908",
enumerable: false,
configurable: true
});
}
dir = (0, _getprojectdir.getProjectDir)(dir);
const config = await (0, _config.default)(_constants.PHASE_DEVELOPMENT_SERVER, dir);
const distDir = _path.default.join(dir, config.distDir || '.next');
// Support both old format (no eventsFile arg) and new format (with eventsFile arg)
const eventsPath = _path.default.join(distDir, eventsFile && !eventsFile.includes('/') ? eventsFile : '_events.json');
let events;
try {
events = JSON.parse(_fs.default.readFileSync(eventsPath, 'utf8'));
} catch (err) {
if (err.code === 'ENOENT') {
// no events to process we can exit now
process.exit(0);
}
throw err;
}
const telemetry = new _storage.Telemetry({
distDir
});
await telemetry.record(events);
await telemetry.flush();
// finished flushing events clean-up
_fs.default.unlinkSync(eventsPath);
// Don't call process.exit() here - let Node.js exit naturally after
// all pending work completes (e.g., setTimeout in debug telemetry)
})();
//# sourceMappingURL=detached-flush.js.map
+1
View File
@@ -0,0 +1 @@
{"version":3,"sources":["../../src/telemetry/detached-flush.ts"],"sourcesContent":["import fs from 'fs'\nimport path from 'path'\nimport type { TelemetryEvent } from './storage'\nimport { Telemetry } from './storage'\nimport loadConfig from '../server/config'\nimport { getProjectDir } from '../lib/get-project-dir'\nimport { PHASE_DEVELOPMENT_SERVER } from '../shared/lib/constants'\n\n// this process should be started with following arg order\n// 1. mode e.g. dev, export, start\n// 2. project dir\n// 3. events filename (optional, defaults to _events.json)\n;(async () => {\n const args = [...process.argv]\n const eventsFile = args.pop()\n let dir = args.pop()\n const mode = args.pop()\n\n if (!dir || mode !== 'dev') {\n throw new Error(\n `Invalid flags should be run as node detached-flush dev ./path-to/project [eventsFile]`\n )\n }\n dir = getProjectDir(dir)\n\n const config = await loadConfig(PHASE_DEVELOPMENT_SERVER, dir)\n const distDir = path.join(dir, config.distDir || '.next')\n // Support both old format (no eventsFile arg) and new format (with eventsFile arg)\n const eventsPath = path.join(\n distDir,\n eventsFile && !eventsFile.includes('/') ? eventsFile : '_events.json'\n )\n\n let events: TelemetryEvent[]\n try {\n events = JSON.parse(fs.readFileSync(eventsPath, 'utf8'))\n } catch (err: any) {\n if (err.code === 'ENOENT') {\n // no events to process we can exit now\n process.exit(0)\n }\n throw err\n }\n\n const telemetry = new Telemetry({ distDir })\n await telemetry.record(events)\n await telemetry.flush()\n\n // finished flushing events clean-up\n fs.unlinkSync(eventsPath)\n // Don't call process.exit() here - let Node.js exit naturally after\n // all pending work completes (e.g., setTimeout in debug telemetry)\n})()\n"],"names":["args","process","argv","eventsFile","pop","dir","mode","Error","getProjectDir","config","loadConfig","PHASE_DEVELOPMENT_SERVER","distDir","path","join","eventsPath","includes","events","JSON","parse","fs","readFileSync","err","code","exit","telemetry","Telemetry","record","flush","unlinkSync"],"mappings":";;;;2DAAe;6DACE;yBAES;+DACH;+BACO;2BACW;;;;;;AAMvC,CAAA;IACA,MAAMA,OAAO;WAAIC,QAAQC,IAAI;KAAC;IAC9B,MAAMC,aAAaH,KAAKI,GAAG;IAC3B,IAAIC,MAAML,KAAKI,GAAG;IAClB,MAAME,OAAON,KAAKI,GAAG;IAErB,IAAI,CAACC,OAAOC,SAAS,OAAO;QAC1B,MAAM,qBAEL,CAFK,IAAIC,MACR,CAAC,qFAAqF,CAAC,GADnF,qBAAA;mBAAA;wBAAA;0BAAA;QAEN;IACF;IACAF,MAAMG,IAAAA,4BAAa,EAACH;IAEpB,MAAMI,SAAS,MAAMC,IAAAA,eAAU,EAACC,mCAAwB,EAAEN;IAC1D,MAAMO,UAAUC,aAAI,CAACC,IAAI,CAACT,KAAKI,OAAOG,OAAO,IAAI;IACjD,mFAAmF;IACnF,MAAMG,aAAaF,aAAI,CAACC,IAAI,CAC1BF,SACAT,cAAc,CAACA,WAAWa,QAAQ,CAAC,OAAOb,aAAa;IAGzD,IAAIc;IACJ,IAAI;QACFA,SAASC,KAAKC,KAAK,CAACC,WAAE,CAACC,YAAY,CAACN,YAAY;IAClD,EAAE,OAAOO,KAAU;QACjB,IAAIA,IAAIC,IAAI,KAAK,UAAU;YACzB,uCAAuC;YACvCtB,QAAQuB,IAAI,CAAC;QACf;QACA,MAAMF;IACR;IAEA,MAAMG,YAAY,IAAIC,kBAAS,CAAC;QAAEd;IAAQ;IAC1C,MAAMa,UAAUE,MAAM,CAACV;IACvB,MAAMQ,UAAUG,KAAK;IAErB,oCAAoC;IACpCR,WAAE,CAACS,UAAU,CAACd;AACd,oEAAoE;AACpE,mEAAmE;AACrE,CAAA","ignoreList":[0]}
+132
View File
@@ -0,0 +1,132 @@
import type { TelemetryPlugin } from '../../build/webpack/plugins/telemetry-plugin/telemetry-plugin';
import type { SWC_TARGET_TRIPLE } from '../../build/webpack/plugins/telemetry-plugin/telemetry-plugin';
import type { UseCacheTrackerKey } from '../../build/webpack/plugins/telemetry-plugin/use-cache-tracker-utils';
type EventTypeCheckCompleted = {
durationInSeconds: number;
typescriptVersion: string | null;
inputFilesCount?: number;
totalFilesCount?: number;
incremental?: boolean;
};
export declare function eventTypeCheckCompleted(event: EventTypeCheckCompleted): {
eventName: string;
payload: EventTypeCheckCompleted;
};
export type EventLintCheckCompleted = {
durationInSeconds: number;
eslintVersion: string | null;
lintedFilesCount?: number;
lintFix?: boolean;
buildLint?: boolean;
nextEslintPluginVersion?: string | null;
nextEslintPluginErrorsCount?: number;
nextEslintPluginWarningsCount?: number;
nextRulesEnabled: {
[ruleName: `@next/next/${string}`]: 'off' | 'warn' | 'error';
};
};
export declare function eventLintCheckCompleted(event: EventLintCheckCompleted): {
eventName: string;
payload: EventLintCheckCompleted;
};
type AnalyzeEventCompleted = {
durationInSeconds: number;
success: true;
totalPageCount: number;
} | {
success: false;
};
export declare function eventAnalyzeCompleted(event: AnalyzeEventCompleted): {
eventName: string;
payload: AnalyzeEventCompleted;
};
type EventBuildCompleted = {
bundler: 'webpack' | 'rspack' | 'turbopack';
durationInSeconds: number;
totalPageCount: number;
hasDunderPages: boolean;
hasTestPages: boolean;
totalAppPagesCount?: number;
};
export declare function eventBuildCompleted(pagePaths: string[], event: Omit<EventBuildCompleted, 'totalPageCount' | 'hasDunderPages' | 'hasTestPages'>): {
eventName: string;
payload: EventBuildCompleted;
};
type EventBuildFailed = {
bundler: 'webpack' | 'rspack' | 'turbopack';
errorCode: string;
durationInSeconds: number;
};
export declare function eventBuildFailed(event: EventBuildFailed): {
eventName: string;
payload: EventBuildFailed;
};
type EventBuildOptimized = {
durationInSeconds: number;
totalPageCount: number;
staticPageCount: number;
staticPropsPageCount: number;
serverPropsPageCount: number;
ssrPageCount: number;
hasDunderPages: boolean;
hasTestPages: boolean;
hasStatic404: boolean;
hasReportWebVitals: boolean;
headersCount: number;
rewritesCount: number;
redirectsCount: number;
headersWithHasCount: number;
rewritesWithHasCount: number;
redirectsWithHasCount: number;
middlewareCount: number;
isRspack: boolean;
totalAppPagesCount?: number;
staticAppPagesCount?: number;
serverAppPagesCount?: number;
edgeRuntimeAppCount?: number;
edgeRuntimePagesCount?: number;
};
export declare function eventBuildOptimize(pagePaths: string[], event: Omit<EventBuildOptimized, 'totalPageCount' | 'hasDunderPages' | 'hasTestPages' | 'isRspack'>): {
eventName: string;
payload: EventBuildOptimized;
};
export declare const EVENT_BUILD_FEATURE_USAGE = "NEXT_BUILD_FEATURE_USAGE";
export type EventBuildFeatureUsage = {
featureName: 'next/image' | 'next/legacy/image' | 'next/future/image' | 'next/script' | 'next/dynamic' | '@next/font/google' | '@next/font/local' | 'next/font/google' | 'next/font/local' | 'experimental/nextScriptWorkers' | 'experimental/cacheComponents' | 'experimental/optimizeCss' | 'experimental/ppr' | 'swcLoader' | 'swcRelay' | 'swcStyledComponents' | 'swcReactRemoveProperties' | 'swcExperimentalDecorators' | 'swcRemoveConsole' | 'swcImportSource' | 'swcEmotion' | `swc/target/${SWC_TARGET_TRIPLE}` | 'turbotrace' | 'vercelImageGeneration' | 'transpilePackages' | 'skipProxyUrlNormalize' | 'skipTrailingSlashRedirect' | 'modularizeImports' | 'esmExternals' | 'webpackPlugins' | UseCacheTrackerKey | 'turbopackFileSystemCache' | 'runAfterProductionCompile';
invocationCount: number;
};
export declare function eventBuildFeatureUsage(usages: ReturnType<TelemetryPlugin['usages']>): Array<{
eventName: string;
payload: EventBuildFeatureUsage;
}>;
export declare const EVENT_NAME_PACKAGE_USED_IN_GET_SERVER_SIDE_PROPS = "NEXT_PACKAGE_USED_IN_GET_SERVER_SIDE_PROPS";
export type EventPackageUsedInGetServerSideProps = {
package: string;
};
export declare function eventPackageUsedInGetServerSideProps(packagesUsedInServerSideProps: ReturnType<TelemetryPlugin['packagesUsedInServerSideProps']>): Array<{
eventName: string;
payload: EventPackageUsedInGetServerSideProps;
}>;
export declare const EVENT_MCP_TOOL_USAGE = "NEXT_MCP_TOOL_USAGE";
export type McpToolName = 'mcp/get_errors' | 'mcp/get_logs' | 'mcp/get_page_metadata' | 'mcp/get_project_metadata' | 'mcp/get_routes' | 'mcp/get_server_action_by_id';
export type EventMcpToolUsage = {
toolName: McpToolName;
invocationCount: number;
};
export declare function eventMcpToolUsage(usages: Array<{
featureName: McpToolName;
invocationCount: number;
}>): Array<{
eventName: string;
payload: EventMcpToolUsage;
}>;
export declare const ERROR_THROWN_EVENT = "NEXT_ERROR_THROWN";
type ErrorThrownEvent = {
eventName: typeof ERROR_THROWN_EVENT;
payload: {
errorCode: string | undefined;
location: string | undefined;
};
};
export declare function eventErrorThrown(error: Error, anonymizedLocation: string | undefined): ErrorThrownEvent;
export {};
+174
View File
@@ -0,0 +1,174 @@
"use strict";
Object.defineProperty(exports, "__esModule", {
value: true
});
0 && (module.exports = {
ERROR_THROWN_EVENT: null,
EVENT_BUILD_FEATURE_USAGE: null,
EVENT_MCP_TOOL_USAGE: null,
EVENT_NAME_PACKAGE_USED_IN_GET_SERVER_SIDE_PROPS: null,
eventAnalyzeCompleted: null,
eventBuildCompleted: null,
eventBuildFailed: null,
eventBuildFeatureUsage: null,
eventBuildOptimize: null,
eventErrorThrown: null,
eventLintCheckCompleted: null,
eventMcpToolUsage: null,
eventPackageUsedInGetServerSideProps: null,
eventTypeCheckCompleted: null
});
function _export(target, all) {
for(var name in all)Object.defineProperty(target, name, {
enumerable: true,
get: all[name]
});
}
_export(exports, {
ERROR_THROWN_EVENT: function() {
return ERROR_THROWN_EVENT;
},
EVENT_BUILD_FEATURE_USAGE: function() {
return EVENT_BUILD_FEATURE_USAGE;
},
EVENT_MCP_TOOL_USAGE: function() {
return EVENT_MCP_TOOL_USAGE;
},
EVENT_NAME_PACKAGE_USED_IN_GET_SERVER_SIDE_PROPS: function() {
return EVENT_NAME_PACKAGE_USED_IN_GET_SERVER_SIDE_PROPS;
},
eventAnalyzeCompleted: function() {
return eventAnalyzeCompleted;
},
eventBuildCompleted: function() {
return eventBuildCompleted;
},
eventBuildFailed: function() {
return eventBuildFailed;
},
eventBuildFeatureUsage: function() {
return eventBuildFeatureUsage;
},
eventBuildOptimize: function() {
return eventBuildOptimize;
},
eventErrorThrown: function() {
return eventErrorThrown;
},
eventLintCheckCompleted: function() {
return eventLintCheckCompleted;
},
eventMcpToolUsage: function() {
return eventMcpToolUsage;
},
eventPackageUsedInGetServerSideProps: function() {
return eventPackageUsedInGetServerSideProps;
},
eventTypeCheckCompleted: function() {
return eventTypeCheckCompleted;
}
});
const _errortelemetryutils = require("../../lib/error-telemetry-utils");
const REGEXP_DIRECTORY_DUNDER = /[\\/]__[^\\/]+(?<![\\/]__(?:tests|mocks))__[\\/]/i;
const REGEXP_DIRECTORY_TESTS = /[\\/]__(tests|mocks)__[\\/]/i;
const REGEXP_FILE_TEST = /\.(?:spec|test)\.[^.]+$/i;
const EVENT_TYPE_CHECK_COMPLETED = 'NEXT_TYPE_CHECK_COMPLETED';
function eventTypeCheckCompleted(event) {
return {
eventName: EVENT_TYPE_CHECK_COMPLETED,
payload: event
};
}
const EVENT_LINT_CHECK_COMPLETED = 'NEXT_LINT_CHECK_COMPLETED';
function eventLintCheckCompleted(event) {
return {
eventName: EVENT_LINT_CHECK_COMPLETED,
payload: event
};
}
const EVENT_ANALYZE_COMPLETED = 'NEXT_ANALYZE_COMPLETED';
function eventAnalyzeCompleted(event) {
return {
eventName: EVENT_ANALYZE_COMPLETED,
payload: event
};
}
const EVENT_BUILD_COMPLETED = 'NEXT_BUILD_COMPLETED';
function eventBuildCompleted(pagePaths, event) {
return {
eventName: EVENT_BUILD_COMPLETED,
payload: {
...event,
totalPageCount: pagePaths.length,
hasDunderPages: pagePaths.some((path)=>REGEXP_DIRECTORY_DUNDER.test(path)),
hasTestPages: pagePaths.some((path)=>REGEXP_DIRECTORY_TESTS.test(path) || REGEXP_FILE_TEST.test(path)),
totalAppPagesCount: event.totalAppPagesCount
}
};
}
const EVENT_BUILD_FAILED = 'NEXT_BUILD_FAILED';
function eventBuildFailed(event) {
return {
eventName: EVENT_BUILD_FAILED,
payload: event
};
}
const EVENT_BUILD_OPTIMIZED = 'NEXT_BUILD_OPTIMIZED';
function eventBuildOptimize(pagePaths, event) {
return {
eventName: EVENT_BUILD_OPTIMIZED,
payload: {
...event,
totalPageCount: pagePaths.length,
hasDunderPages: pagePaths.some((path)=>REGEXP_DIRECTORY_DUNDER.test(path)),
hasTestPages: pagePaths.some((path)=>REGEXP_DIRECTORY_TESTS.test(path) || REGEXP_FILE_TEST.test(path)),
totalAppPagesCount: event.totalAppPagesCount,
staticAppPagesCount: event.staticAppPagesCount,
serverAppPagesCount: event.serverAppPagesCount,
edgeRuntimeAppCount: event.edgeRuntimeAppCount,
edgeRuntimePagesCount: event.edgeRuntimePagesCount,
isRspack: process.env.NEXT_RSPACK !== undefined
}
};
}
const EVENT_BUILD_FEATURE_USAGE = 'NEXT_BUILD_FEATURE_USAGE';
function eventBuildFeatureUsage(usages) {
return usages.map(({ featureName, invocationCount })=>({
eventName: EVENT_BUILD_FEATURE_USAGE,
payload: {
featureName,
invocationCount
}
}));
}
const EVENT_NAME_PACKAGE_USED_IN_GET_SERVER_SIDE_PROPS = 'NEXT_PACKAGE_USED_IN_GET_SERVER_SIDE_PROPS';
function eventPackageUsedInGetServerSideProps(packagesUsedInServerSideProps) {
return packagesUsedInServerSideProps.map((packageName)=>({
eventName: EVENT_NAME_PACKAGE_USED_IN_GET_SERVER_SIDE_PROPS,
payload: {
package: packageName
}
}));
}
const EVENT_MCP_TOOL_USAGE = 'NEXT_MCP_TOOL_USAGE';
function eventMcpToolUsage(usages) {
return usages.map(({ featureName, invocationCount })=>({
eventName: EVENT_MCP_TOOL_USAGE,
payload: {
toolName: featureName,
invocationCount
}
}));
}
const ERROR_THROWN_EVENT = 'NEXT_ERROR_THROWN';
function eventErrorThrown(error, anonymizedLocation) {
return {
eventName: ERROR_THROWN_EVENT,
payload: {
errorCode: (0, _errortelemetryutils.extractNextErrorCode)(error) || 'Unknown',
location: anonymizedLocation
}
};
}
//# sourceMappingURL=build.js.map
File diff suppressed because one or more lines are too long
+20
View File
@@ -0,0 +1,20 @@
export declare const eventNameErrorFeedback = "NEXT_ERROR_FEEDBACK";
export type EventErrorFeedback = {
errorCode: string;
wasHelpful: boolean;
};
/**
* Records telemetry for error feedback.
*
* @example
* ```ts
* telemetry.record(eventErrorFeedback({
* errorCode: 'E1',
* wasHelpful: true
* }))
* ```
*/
export declare function eventErrorFeedback(event: EventErrorFeedback): {
eventName: string;
payload: EventErrorFeedback;
};
+31
View File
@@ -0,0 +1,31 @@
"use strict";
Object.defineProperty(exports, "__esModule", {
value: true
});
0 && (module.exports = {
eventErrorFeedback: null,
eventNameErrorFeedback: null
});
function _export(target, all) {
for(var name in all)Object.defineProperty(target, name, {
enumerable: true,
get: all[name]
});
}
_export(exports, {
eventErrorFeedback: function() {
return eventErrorFeedback;
},
eventNameErrorFeedback: function() {
return eventNameErrorFeedback;
}
});
const eventNameErrorFeedback = 'NEXT_ERROR_FEEDBACK';
function eventErrorFeedback(event) {
return {
eventName: eventNameErrorFeedback,
payload: event
};
}
//# sourceMappingURL=error-feedback.js.map
+1
View File
@@ -0,0 +1 @@
{"version":3,"sources":["../../../src/telemetry/events/error-feedback.ts"],"sourcesContent":["export const eventNameErrorFeedback = 'NEXT_ERROR_FEEDBACK'\n\nexport type EventErrorFeedback = {\n errorCode: string\n wasHelpful: boolean\n}\n\n/**\n * Records telemetry for error feedback.\n *\n * @example\n * ```ts\n * telemetry.record(eventErrorFeedback({\n * errorCode: 'E1',\n * wasHelpful: true\n * }))\n * ```\n */\nexport function eventErrorFeedback(event: EventErrorFeedback): {\n eventName: string\n payload: EventErrorFeedback\n} {\n return {\n eventName: eventNameErrorFeedback,\n payload: event,\n }\n}\n"],"names":["eventErrorFeedback","eventNameErrorFeedback","event","eventName","payload"],"mappings":";;;;;;;;;;;;;;;IAkBgBA,kBAAkB;eAAlBA;;IAlBHC,sBAAsB;eAAtBA;;;AAAN,MAAMA,yBAAyB;AAkB/B,SAASD,mBAAmBE,KAAyB;IAI1D,OAAO;QACLC,WAAWF;QACXG,SAASF;IACX;AACF","ignoreList":[0]}
+5
View File
@@ -0,0 +1,5 @@
export * from './version';
export * from './build';
export * from './plugins';
export type { McpToolName, EventMcpToolUsage } from './build';
export { EVENT_MCP_TOOL_USAGE, eventMcpToolUsage } from './build';
+41
View File
@@ -0,0 +1,41 @@
"use strict";
Object.defineProperty(exports, "__esModule", {
value: true
});
0 && (module.exports = {
EVENT_MCP_TOOL_USAGE: null,
eventMcpToolUsage: null
});
function _export(target, all) {
for(var name in all)Object.defineProperty(target, name, {
enumerable: true,
get: all[name]
});
}
_export(exports, {
EVENT_MCP_TOOL_USAGE: function() {
return _build.EVENT_MCP_TOOL_USAGE;
},
eventMcpToolUsage: function() {
return _build.eventMcpToolUsage;
}
});
0 && __export(require("./version")) && __export(require("./build")) && __export(require("./plugins"));
_export_star(require("./version"), exports);
const _build = _export_star(require("./build"), exports);
_export_star(require("./plugins"), exports);
function _export_star(from, to) {
Object.keys(from).forEach(function(k) {
if (k !== "default" && !Object.prototype.hasOwnProperty.call(to, k)) {
Object.defineProperty(to, k, {
enumerable: true,
get: function() {
return from[k];
}
});
}
});
return from;
}
//# sourceMappingURL=index.js.map
+1
View File
@@ -0,0 +1 @@
{"version":3,"sources":["../../../src/telemetry/events/index.ts"],"sourcesContent":["export * from './version'\nexport * from './build'\nexport * from './plugins'\n\n// Re-export MCP-specific types and functions\nexport type { McpToolName, EventMcpToolUsage } from './build'\nexport { EVENT_MCP_TOOL_USAGE, eventMcpToolUsage } from './build'\n"],"names":["EVENT_MCP_TOOL_USAGE","eventMcpToolUsage"],"mappings":";;;;;;;;;;;;;;;IAMSA,oBAAoB;eAApBA,2BAAoB;;IAAEC,iBAAiB;eAAjBA,wBAAiB;;;;qBANlC;oCACA;qBACA","ignoreList":[0]}
+107
View File
@@ -0,0 +1,107 @@
/**
* @jest-environment node
*/ "use strict";
Object.defineProperty(exports, "__esModule", {
value: true
});
const _build = require("./build");
describe('MCP Telemetry Events', ()=>{
it('should generate correct telemetry events for single tool', ()=>{
const usages = [
{
featureName: 'mcp/get_errors',
invocationCount: 5
}
];
const events = (0, _build.eventMcpToolUsage)(usages);
expect(events).toHaveLength(1);
expect(events[0]).toEqual({
eventName: _build.EVENT_MCP_TOOL_USAGE,
payload: {
toolName: 'mcp/get_errors',
invocationCount: 5
}
});
});
it('should generate correct telemetry events for multiple tools', ()=>{
const usages = [
{
featureName: 'mcp/get_errors',
invocationCount: 3
},
{
featureName: 'mcp/get_logs',
invocationCount: 1
},
{
featureName: 'mcp/get_page_metadata',
invocationCount: 7
}
];
const events = (0, _build.eventMcpToolUsage)(usages);
expect(events).toHaveLength(3);
expect(events[0]).toEqual({
eventName: _build.EVENT_MCP_TOOL_USAGE,
payload: {
toolName: 'mcp/get_errors',
invocationCount: 3
}
});
expect(events[1]).toEqual({
eventName: _build.EVENT_MCP_TOOL_USAGE,
payload: {
toolName: 'mcp/get_logs',
invocationCount: 1
}
});
expect(events[2]).toEqual({
eventName: _build.EVENT_MCP_TOOL_USAGE,
payload: {
toolName: 'mcp/get_page_metadata',
invocationCount: 7
}
});
});
it('should handle all MCP tool types', ()=>{
const allTools = [
'mcp/get_errors',
'mcp/get_logs',
'mcp/get_page_metadata',
'mcp/get_project_metadata',
'mcp/get_server_action_by_id'
];
const usages = allTools.map((tool, index)=>({
featureName: tool,
invocationCount: index + 1
}));
const events = (0, _build.eventMcpToolUsage)(usages);
expect(events).toHaveLength(5);
events.forEach((event, index)=>{
expect(event.eventName).toBe(_build.EVENT_MCP_TOOL_USAGE);
expect(event.payload.toolName).toBe(allTools[index]);
expect(event.payload.invocationCount).toBe(index + 1);
});
});
it('should handle empty usage array', ()=>{
const events = (0, _build.eventMcpToolUsage)([]);
expect(events).toEqual([]);
});
it('should use correct event name constant', ()=>{
expect(_build.EVENT_MCP_TOOL_USAGE).toBe('NEXT_MCP_TOOL_USAGE');
});
it('should transform featureName to toolName in payload', ()=>{
const usages = [
{
featureName: 'mcp/get_project_metadata',
invocationCount: 2
}
];
const events = (0, _build.eventMcpToolUsage)(usages);
// Verify the input has 'featureName' but output has 'toolName'
expect(usages[0]).toHaveProperty('featureName');
expect(events[0].payload).toHaveProperty('toolName');
expect(events[0].payload).not.toHaveProperty('featureName');
});
});
//# sourceMappingURL=mcp-telemetry.test.js.map
File diff suppressed because one or more lines are too long
+9
View File
@@ -0,0 +1,9 @@
type NextPluginsEvent = {
eventName: string;
payload: {
packageName: string;
packageVersion: string;
};
};
export declare function eventNextPlugins(dir: string): Promise<Array<NextPluginsEvent>>;
export {};
+51
View File
@@ -0,0 +1,51 @@
"use strict";
Object.defineProperty(exports, "__esModule", {
value: true
});
Object.defineProperty(exports, "eventNextPlugins", {
enumerable: true,
get: function() {
return eventNextPlugins;
}
});
const _findup = /*#__PURE__*/ _interop_require_default(require("next/dist/compiled/find-up"));
function _interop_require_default(obj) {
return obj && obj.__esModule ? obj : {
default: obj
};
}
const EVENT_PLUGIN_PRESENT = 'NEXT_PACKAGE_DETECTED';
async function eventNextPlugins(dir) {
try {
const packageJsonPath = await (0, _findup.default)('package.json', {
cwd: dir
});
if (!packageJsonPath) {
return [];
}
const { dependencies = {}, devDependencies = {} } = require(packageJsonPath);
const deps = {
...devDependencies,
...dependencies
};
return Object.keys(deps).reduce((events, plugin)=>{
const version = deps[plugin];
// Don't add deps without a version set
if (!version) {
return events;
}
events.push({
eventName: EVENT_PLUGIN_PRESENT,
payload: {
packageName: plugin,
packageVersion: version
}
});
return events;
}, []);
} catch (_) {
return [];
}
}
//# sourceMappingURL=plugins.js.map
+1
View File
@@ -0,0 +1 @@
{"version":3,"sources":["../../../src/telemetry/events/plugins.ts"],"sourcesContent":["import findUp from 'next/dist/compiled/find-up'\n\nconst EVENT_PLUGIN_PRESENT = 'NEXT_PACKAGE_DETECTED'\ntype NextPluginsEvent = {\n eventName: string\n payload: {\n packageName: string\n packageVersion: string\n }\n}\n\nexport async function eventNextPlugins(\n dir: string\n): Promise<Array<NextPluginsEvent>> {\n try {\n const packageJsonPath = await findUp('package.json', { cwd: dir })\n if (!packageJsonPath) {\n return []\n }\n\n const { dependencies = {}, devDependencies = {} } = require(packageJsonPath)\n\n const deps = { ...devDependencies, ...dependencies }\n\n return Object.keys(deps).reduce(\n (events: NextPluginsEvent[], plugin: string): NextPluginsEvent[] => {\n const version = deps[plugin]\n // Don't add deps without a version set\n if (!version) {\n return events\n }\n\n events.push({\n eventName: EVENT_PLUGIN_PRESENT,\n payload: {\n packageName: plugin,\n packageVersion: version,\n },\n })\n\n return events\n },\n []\n )\n } catch (_) {\n return []\n }\n}\n"],"names":["eventNextPlugins","EVENT_PLUGIN_PRESENT","dir","packageJsonPath","findUp","cwd","dependencies","devDependencies","require","deps","Object","keys","reduce","events","plugin","version","push","eventName","payload","packageName","packageVersion","_"],"mappings":";;;;+BAWsBA;;;eAAAA;;;+DAXH;;;;;;AAEnB,MAAMC,uBAAuB;AAStB,eAAeD,iBACpBE,GAAW;IAEX,IAAI;QACF,MAAMC,kBAAkB,MAAMC,IAAAA,eAAM,EAAC,gBAAgB;YAAEC,KAAKH;QAAI;QAChE,IAAI,CAACC,iBAAiB;YACpB,OAAO,EAAE;QACX;QAEA,MAAM,EAAEG,eAAe,CAAC,CAAC,EAAEC,kBAAkB,CAAC,CAAC,EAAE,GAAGC,QAAQL;QAE5D,MAAMM,OAAO;YAAE,GAAGF,eAAe;YAAE,GAAGD,YAAY;QAAC;QAEnD,OAAOI,OAAOC,IAAI,CAACF,MAAMG,MAAM,CAC7B,CAACC,QAA4BC;YAC3B,MAAMC,UAAUN,IAAI,CAACK,OAAO;YAC5B,uCAAuC;YACvC,IAAI,CAACC,SAAS;gBACZ,OAAOF;YACT;YAEAA,OAAOG,IAAI,CAAC;gBACVC,WAAWhB;gBACXiB,SAAS;oBACPC,aAAaL;oBACbM,gBAAgBL;gBAClB;YACF;YAEA,OAAOF;QACT,GACA,EAAE;IAEN,EAAE,OAAOQ,GAAG;QACV,OAAO,EAAE;IACX;AACF","ignoreList":[0]}
+14
View File
@@ -0,0 +1,14 @@
export type EventCliSessionStopped = {
cliCommand: string;
nextVersion: string;
nodeVersion: string;
turboFlag?: boolean | null;
durationMilliseconds?: number | null;
pagesDir?: boolean;
appDir?: boolean;
isRspack: boolean;
};
export declare function eventCliSessionStopped(event: Omit<EventCliSessionStopped, 'nextVersion' | 'nodeVersion' | 'isRspack'>): {
eventName: string;
payload: EventCliSessionStopped;
}[];
+37
View File
@@ -0,0 +1,37 @@
"use strict";
Object.defineProperty(exports, "__esModule", {
value: true
});
Object.defineProperty(exports, "eventCliSessionStopped", {
enumerable: true,
get: function() {
return eventCliSessionStopped;
}
});
const EVENT_VERSION = 'NEXT_CLI_SESSION_STOPPED';
function eventCliSessionStopped(event) {
// This should be an invariant, if it fails our build tooling is broken.
if (typeof "16.2.0" !== 'string') {
return [];
}
const payload = {
nextVersion: "16.2.0",
nodeVersion: process.version,
cliCommand: event.cliCommand,
durationMilliseconds: event.durationMilliseconds,
...typeof event.turboFlag !== 'undefined' ? {
turboFlag: !!event.turboFlag
} : {},
pagesDir: event.pagesDir,
appDir: event.appDir,
isRspack: process.env.NEXT_RSPACK !== undefined
};
return [
{
eventName: EVENT_VERSION,
payload
}
];
}
//# sourceMappingURL=session-stopped.js.map
+1
View File
@@ -0,0 +1 @@
{"version":3,"sources":["../../../src/telemetry/events/session-stopped.ts"],"sourcesContent":["const EVENT_VERSION = 'NEXT_CLI_SESSION_STOPPED'\n\nexport type EventCliSessionStopped = {\n cliCommand: string\n nextVersion: string\n nodeVersion: string\n turboFlag?: boolean | null\n durationMilliseconds?: number | null\n pagesDir?: boolean\n appDir?: boolean\n isRspack: boolean\n}\n\nexport function eventCliSessionStopped(\n event: Omit<\n EventCliSessionStopped,\n 'nextVersion' | 'nodeVersion' | 'isRspack'\n >\n): { eventName: string; payload: EventCliSessionStopped }[] {\n // This should be an invariant, if it fails our build tooling is broken.\n if (typeof process.env.__NEXT_VERSION !== 'string') {\n return []\n }\n\n const payload: EventCliSessionStopped = {\n nextVersion: process.env.__NEXT_VERSION,\n nodeVersion: process.version,\n cliCommand: event.cliCommand,\n durationMilliseconds: event.durationMilliseconds,\n ...(typeof event.turboFlag !== 'undefined'\n ? {\n turboFlag: !!event.turboFlag,\n }\n : {}),\n pagesDir: event.pagesDir,\n appDir: event.appDir,\n isRspack: process.env.NEXT_RSPACK !== undefined,\n }\n return [{ eventName: EVENT_VERSION, payload }]\n}\n"],"names":["eventCliSessionStopped","EVENT_VERSION","event","process","env","__NEXT_VERSION","payload","nextVersion","nodeVersion","version","cliCommand","durationMilliseconds","turboFlag","pagesDir","appDir","isRspack","NEXT_RSPACK","undefined","eventName"],"mappings":";;;;+BAagBA;;;eAAAA;;;AAbhB,MAAMC,gBAAgB;AAaf,SAASD,uBACdE,KAGC;IAED,wEAAwE;IACxE,IAAI,OAAOC,QAAQC,GAAG,CAACC,cAAc,KAAK,UAAU;QAClD,OAAO,EAAE;IACX;IAEA,MAAMC,UAAkC;QACtCC,aAAaJ,QAAQC,GAAG,CAACC,cAAc;QACvCG,aAAaL,QAAQM,OAAO;QAC5BC,YAAYR,MAAMQ,UAAU;QAC5BC,sBAAsBT,MAAMS,oBAAoB;QAChD,GAAI,OAAOT,MAAMU,SAAS,KAAK,cAC3B;YACEA,WAAW,CAAC,CAACV,MAAMU,SAAS;QAC9B,IACA,CAAC,CAAC;QACNC,UAAUX,MAAMW,QAAQ;QACxBC,QAAQZ,MAAMY,MAAM;QACpBC,UAAUZ,QAAQC,GAAG,CAACY,WAAW,KAAKC;IACxC;IACA,OAAO;QAAC;YAAEC,WAAWjB;YAAeK;QAAQ;KAAE;AAChD","ignoreList":[0]}
+14
View File
@@ -0,0 +1,14 @@
export type EventSwcLoadFailure = {
eventName: string;
payload: {
platform: string;
arch: string;
nodeVersion: string;
nextVersion: string;
wasm?: 'enabled' | 'fallback' | 'failed';
glibcVersion?: string;
installedSwcPackages?: string;
nativeBindingsErrorCode?: string;
};
};
export declare function eventSwcLoadFailure(event?: Pick<EventSwcLoadFailure['payload'], 'wasm' | 'nativeBindingsErrorCode'>): Promise<void>;
+55
View File
@@ -0,0 +1,55 @@
"use strict";
Object.defineProperty(exports, "__esModule", {
value: true
});
Object.defineProperty(exports, "eventSwcLoadFailure", {
enumerable: true,
get: function() {
return eventSwcLoadFailure;
}
});
const _shared = require("../../trace/shared");
const _packagejson = require("next/package.json");
const EVENT_PLUGIN_PRESENT = 'NEXT_SWC_LOAD_FAILURE';
async function eventSwcLoadFailure(event) {
const telemetry = _shared.traceGlobals.get('telemetry');
// can't continue if telemetry isn't set
if (!telemetry) return;
let glibcVersion;
let installedSwcPackages;
try {
var _process_report;
// @ts-ignore
glibcVersion = (_process_report = process.report) == null ? void 0 : _process_report.getReport().header.glibcVersionRuntime;
} catch {}
try {
const pkgNames = Object.keys(_packagejson.optionalDependencies || {}).filter((pkg)=>pkg.startsWith('@next/swc'));
const installedPkgs = [];
for (const pkg of pkgNames){
try {
const { version } = require(`${pkg}/package.json`);
installedPkgs.push(`${pkg}@${version}`);
} catch {}
}
if (installedPkgs.length > 0) {
installedSwcPackages = installedPkgs.sort().join(',');
}
} catch {}
telemetry.record({
eventName: EVENT_PLUGIN_PRESENT,
payload: {
nextVersion: "16.2.0",
glibcVersion,
installedSwcPackages,
arch: process.arch,
platform: process.platform,
nodeVersion: process.versions.node,
wasm: event == null ? void 0 : event.wasm,
nativeBindingsErrorCode: event == null ? void 0 : event.nativeBindingsErrorCode
}
});
// ensure this event is flushed before process exits
await telemetry.flush();
}
//# sourceMappingURL=swc-load-failure.js.map
+1
View File
@@ -0,0 +1 @@
{"version":3,"sources":["../../../src/telemetry/events/swc-load-failure.ts"],"sourcesContent":["import { traceGlobals } from '../../trace/shared'\nimport type { Telemetry } from '../storage'\n// @ts-ignore JSON\nimport { optionalDependencies } from 'next/package.json'\n\nconst EVENT_PLUGIN_PRESENT = 'NEXT_SWC_LOAD_FAILURE'\nexport type EventSwcLoadFailure = {\n eventName: string\n payload: {\n platform: string\n arch: string\n nodeVersion: string\n nextVersion: string\n wasm?: 'enabled' | 'fallback' | 'failed'\n glibcVersion?: string\n installedSwcPackages?: string\n nativeBindingsErrorCode?: string\n }\n}\n\nexport async function eventSwcLoadFailure(\n event?: Pick<\n EventSwcLoadFailure['payload'],\n 'wasm' | 'nativeBindingsErrorCode'\n >\n): Promise<void> {\n const telemetry: Telemetry | undefined = traceGlobals.get('telemetry')\n // can't continue if telemetry isn't set\n if (!telemetry) return\n\n let glibcVersion\n let installedSwcPackages\n\n try {\n // @ts-ignore\n glibcVersion = process.report?.getReport().header.glibcVersionRuntime\n } catch {}\n\n try {\n const pkgNames = Object.keys(optionalDependencies || {}).filter((pkg) =>\n pkg.startsWith('@next/swc')\n )\n const installedPkgs = []\n\n for (const pkg of pkgNames) {\n try {\n const { version } = require(`${pkg}/package.json`)\n installedPkgs.push(`${pkg}@${version}`)\n } catch {}\n }\n\n if (installedPkgs.length > 0) {\n installedSwcPackages = installedPkgs.sort().join(',')\n }\n } catch {}\n\n telemetry.record({\n eventName: EVENT_PLUGIN_PRESENT,\n payload: {\n nextVersion: process.env.__NEXT_VERSION as string,\n glibcVersion,\n installedSwcPackages,\n arch: process.arch,\n platform: process.platform,\n nodeVersion: process.versions.node,\n wasm: event?.wasm,\n nativeBindingsErrorCode: event?.nativeBindingsErrorCode,\n },\n })\n // ensure this event is flushed before process exits\n await telemetry.flush()\n}\n"],"names":["eventSwcLoadFailure","EVENT_PLUGIN_PRESENT","event","telemetry","traceGlobals","get","glibcVersion","installedSwcPackages","process","report","getReport","header","glibcVersionRuntime","pkgNames","Object","keys","optionalDependencies","filter","pkg","startsWith","installedPkgs","version","require","push","length","sort","join","record","eventName","payload","nextVersion","env","__NEXT_VERSION","arch","platform","nodeVersion","versions","node","wasm","nativeBindingsErrorCode","flush"],"mappings":";;;;+BAoBsBA;;;eAAAA;;;wBApBO;6BAGQ;AAErC,MAAMC,uBAAuB;AAetB,eAAeD,oBACpBE,KAGC;IAED,MAAMC,YAAmCC,oBAAY,CAACC,GAAG,CAAC;IAC1D,wCAAwC;IACxC,IAAI,CAACF,WAAW;IAEhB,IAAIG;IACJ,IAAIC;IAEJ,IAAI;YAEaC;QADf,aAAa;QACbF,gBAAeE,kBAAAA,QAAQC,MAAM,qBAAdD,gBAAgBE,SAAS,GAAGC,MAAM,CAACC,mBAAmB;IACvE,EAAE,OAAM,CAAC;IAET,IAAI;QACF,MAAMC,WAAWC,OAAOC,IAAI,CAACC,iCAAoB,IAAI,CAAC,GAAGC,MAAM,CAAC,CAACC,MAC/DA,IAAIC,UAAU,CAAC;QAEjB,MAAMC,gBAAgB,EAAE;QAExB,KAAK,MAAMF,OAAOL,SAAU;YAC1B,IAAI;gBACF,MAAM,EAAEQ,OAAO,EAAE,GAAGC,QAAQ,GAAGJ,IAAI,aAAa,CAAC;gBACjDE,cAAcG,IAAI,CAAC,GAAGL,IAAI,CAAC,EAAEG,SAAS;YACxC,EAAE,OAAM,CAAC;QACX;QAEA,IAAID,cAAcI,MAAM,GAAG,GAAG;YAC5BjB,uBAAuBa,cAAcK,IAAI,GAAGC,IAAI,CAAC;QACnD;IACF,EAAE,OAAM,CAAC;IAETvB,UAAUwB,MAAM,CAAC;QACfC,WAAW3B;QACX4B,SAAS;YACPC,aAAatB,QAAQuB,GAAG,CAACC,cAAc;YACvC1B;YACAC;YACA0B,MAAMzB,QAAQyB,IAAI;YAClBC,UAAU1B,QAAQ0B,QAAQ;YAC1BC,aAAa3B,QAAQ4B,QAAQ,CAACC,IAAI;YAClCC,IAAI,EAAEpC,yBAAAA,MAAOoC,IAAI;YACjBC,uBAAuB,EAAErC,yBAAAA,MAAOqC,uBAAuB;QACzD;IACF;IACA,oDAAoD;IACpD,MAAMpC,UAAUqC,KAAK;AACvB","ignoreList":[0]}
+10
View File
@@ -0,0 +1,10 @@
import type { NextConfig } from '../../server/config-shared';
type SwcPluginsEvent = {
eventName: string;
payload: {
pluginName: string;
pluginVersion?: string;
};
};
export declare function eventSwcPlugins(dir: string, config: NextConfig): Promise<Array<SwcPluginsEvent>>;
export {};
+55
View File
@@ -0,0 +1,55 @@
"use strict";
Object.defineProperty(exports, "__esModule", {
value: true
});
Object.defineProperty(exports, "eventSwcPlugins", {
enumerable: true,
get: function() {
return eventSwcPlugins;
}
});
const _findup = /*#__PURE__*/ _interop_require_default(require("next/dist/compiled/find-up"));
const _path = /*#__PURE__*/ _interop_require_default(require("path"));
const _fs = /*#__PURE__*/ _interop_require_default(require("fs"));
function _interop_require_default(obj) {
return obj && obj.__esModule ? obj : {
default: obj
};
}
const EVENT_SWC_PLUGIN_PRESENT = 'NEXT_SWC_PLUGIN_DETECTED';
async function eventSwcPlugins(dir, config) {
try {
var _config_experimental_swcPlugins, _config_experimental;
const packageJsonPath = await (0, _findup.default)('package.json', {
cwd: dir
});
if (!packageJsonPath) {
return [];
}
const { dependencies = {}, devDependencies = {} } = require(packageJsonPath);
const deps = {
...devDependencies,
...dependencies
};
const swcPluginPackages = ((_config_experimental = config.experimental) == null ? void 0 : (_config_experimental_swcPlugins = _config_experimental.swcPlugins) == null ? void 0 : _config_experimental_swcPlugins.map(([name, _])=>name)) ?? [];
return swcPluginPackages.map((plugin)=>{
// swc plugins can be non-npm pkgs with absolute path doesn't have version
const version = deps[plugin] ?? undefined;
let pluginName = plugin;
if (_fs.default.existsSync(pluginName)) {
pluginName = _path.default.basename(plugin, '.wasm');
}
return {
eventName: EVENT_SWC_PLUGIN_PRESENT,
payload: {
pluginName: pluginName,
pluginVersion: version
}
};
});
} catch (_) {
return [];
}
}
//# sourceMappingURL=swc-plugins.js.map
+1
View File
@@ -0,0 +1 @@
{"version":3,"sources":["../../../src/telemetry/events/swc-plugins.ts"],"sourcesContent":["import findUp from 'next/dist/compiled/find-up'\nimport path from 'path'\nimport fs from 'fs'\nimport type { NextConfig } from '../../server/config-shared'\n\nconst EVENT_SWC_PLUGIN_PRESENT = 'NEXT_SWC_PLUGIN_DETECTED'\ntype SwcPluginsEvent = {\n eventName: string\n payload: {\n pluginName: string\n pluginVersion?: string\n }\n}\n\nexport async function eventSwcPlugins(\n dir: string,\n config: NextConfig\n): Promise<Array<SwcPluginsEvent>> {\n try {\n const packageJsonPath = await findUp('package.json', { cwd: dir })\n if (!packageJsonPath) {\n return []\n }\n\n const { dependencies = {}, devDependencies = {} } = require(packageJsonPath)\n\n const deps = { ...devDependencies, ...dependencies }\n const swcPluginPackages =\n config.experimental?.swcPlugins?.map(([name, _]) => name) ?? []\n\n return swcPluginPackages.map((plugin) => {\n // swc plugins can be non-npm pkgs with absolute path doesn't have version\n const version = deps[plugin] ?? undefined\n let pluginName = plugin\n if (fs.existsSync(pluginName)) {\n pluginName = path.basename(plugin, '.wasm')\n }\n\n return {\n eventName: EVENT_SWC_PLUGIN_PRESENT,\n payload: {\n pluginName: pluginName,\n pluginVersion: version,\n },\n }\n })\n } catch (_) {\n return []\n }\n}\n"],"names":["eventSwcPlugins","EVENT_SWC_PLUGIN_PRESENT","dir","config","packageJsonPath","findUp","cwd","dependencies","devDependencies","require","deps","swcPluginPackages","experimental","swcPlugins","map","name","_","plugin","version","undefined","pluginName","fs","existsSync","path","basename","eventName","payload","pluginVersion"],"mappings":";;;;+BAcsBA;;;eAAAA;;;+DAdH;6DACF;2DACF;;;;;;AAGf,MAAMC,2BAA2B;AAS1B,eAAeD,gBACpBE,GAAW,EACXC,MAAkB;IAElB,IAAI;YAUAA,iCAAAA;QATF,MAAMC,kBAAkB,MAAMC,IAAAA,eAAM,EAAC,gBAAgB;YAAEC,KAAKJ;QAAI;QAChE,IAAI,CAACE,iBAAiB;YACpB,OAAO,EAAE;QACX;QAEA,MAAM,EAAEG,eAAe,CAAC,CAAC,EAAEC,kBAAkB,CAAC,CAAC,EAAE,GAAGC,QAAQL;QAE5D,MAAMM,OAAO;YAAE,GAAGF,eAAe;YAAE,GAAGD,YAAY;QAAC;QACnD,MAAMI,oBACJR,EAAAA,uBAAAA,OAAOS,YAAY,sBAAnBT,kCAAAA,qBAAqBU,UAAU,qBAA/BV,gCAAiCW,GAAG,CAAC,CAAC,CAACC,MAAMC,EAAE,GAAKD,UAAS,EAAE;QAEjE,OAAOJ,kBAAkBG,GAAG,CAAC,CAACG;YAC5B,0EAA0E;YAC1E,MAAMC,UAAUR,IAAI,CAACO,OAAO,IAAIE;YAChC,IAAIC,aAAaH;YACjB,IAAII,WAAE,CAACC,UAAU,CAACF,aAAa;gBAC7BA,aAAaG,aAAI,CAACC,QAAQ,CAACP,QAAQ;YACrC;YAEA,OAAO;gBACLQ,WAAWxB;gBACXyB,SAAS;oBACPN,YAAYA;oBACZO,eAAeT;gBACjB;YACF;QACF;IACF,EAAE,OAAOF,GAAG;QACV,OAAO,EAAE;IACX;AACF","ignoreList":[0]}
+45
View File
@@ -0,0 +1,45 @@
import type { NextConfigComplete } from '../../server/config-shared';
type EventCliSessionStarted = {
nextVersion: string;
nodeVersion: string;
cliCommand: string;
isSrcDir: boolean | null;
hasNowJson: boolean;
isCustomServer: boolean | null;
hasNextConfig: boolean;
buildTarget: string;
hasWebpackConfig: boolean;
hasBabelConfig: boolean;
basePathEnabled: boolean;
i18nEnabled: boolean;
imageEnabled: boolean;
imageFutureEnabled: boolean;
locales: string | null;
localeDomainsCount: number | null;
localeDetectionEnabled: boolean | null;
imageDomainsCount: number | null;
imageRemotePatternsCount: number | null;
imageLocalPatternsCount: number | null;
imageQualities: string | null;
imageSizes: string | null;
imageLoader: string | null;
imageFormats: string | null;
nextConfigOutput: string | null;
trailingSlashEnabled: boolean;
reactStrictMode: boolean;
webpackVersion: number | null;
turboFlag: boolean;
isRspack: boolean;
appDir: boolean | null;
pagesDir: boolean | null;
staticStaleTime: number | null;
dynamicStaleTime: number | null;
reactCompiler: boolean;
reactCompilerCompilationMode: string | null;
reactCompilerPanicThreshold: string | null;
};
export declare function eventCliSession(nextConfig: NextConfigComplete, event: Omit<EventCliSessionStarted, 'nextVersion' | 'nodeVersion' | 'hasNextConfig' | 'buildTarget' | 'hasWebpackConfig' | 'hasBabelConfig' | 'basePathEnabled' | 'i18nEnabled' | 'imageEnabled' | 'imageFutureEnabled' | 'locales' | 'localeDomainsCount' | 'localeDetectionEnabled' | 'imageDomainsCount' | 'imageRemotePatternsCount' | 'imageLocalPatternsCount' | 'imageQualities' | 'imageSizes' | 'imageLoader' | 'imageFormats' | 'nextConfigOutput' | 'trailingSlashEnabled' | 'reactStrictMode' | 'staticStaleTime' | 'dynamicStaleTime' | 'reactCompiler' | 'reactCompilerCompilationMode' | 'reactCompilerPanicThreshold' | 'isRspack'>): {
eventName: string;
payload: EventCliSessionStarted;
}[];
export {};
+66
View File
@@ -0,0 +1,66 @@
"use strict";
Object.defineProperty(exports, "__esModule", {
value: true
});
Object.defineProperty(exports, "eventCliSession", {
enumerable: true,
get: function() {
return eventCliSession;
}
});
const EVENT_VERSION = 'NEXT_CLI_SESSION_STARTED';
function eventCliSession(nextConfig, event) {
var _nextConfig_experimental_staleTimes, _nextConfig_experimental_staleTimes1, _nextConfig_reactCompiler, _nextConfig_reactCompiler1;
// This should be an invariant, if it fails our build tooling is broken.
if (typeof "16.2.0" !== 'string') {
return [];
}
const { images, i18n } = nextConfig || {};
const payload = {
nextVersion: "16.2.0",
nodeVersion: process.version,
cliCommand: event.cliCommand,
isSrcDir: event.isSrcDir,
hasNowJson: event.hasNowJson,
isCustomServer: event.isCustomServer,
hasNextConfig: nextConfig.configOrigin !== 'default',
buildTarget: 'default',
hasWebpackConfig: typeof (nextConfig == null ? void 0 : nextConfig.webpack) === 'function',
hasBabelConfig: false,
imageEnabled: !!images,
imageFutureEnabled: !!images,
basePathEnabled: !!(nextConfig == null ? void 0 : nextConfig.basePath),
i18nEnabled: !!i18n,
locales: (i18n == null ? void 0 : i18n.locales) ? i18n.locales.join(',') : null,
localeDomainsCount: (i18n == null ? void 0 : i18n.domains) ? i18n.domains.length : null,
localeDetectionEnabled: !i18n ? null : i18n.localeDetection !== false,
imageDomainsCount: (images == null ? void 0 : images.domains) ? images.domains.length : null,
imageRemotePatternsCount: (images == null ? void 0 : images.remotePatterns) ? images.remotePatterns.length : null,
imageLocalPatternsCount: (images == null ? void 0 : images.localPatterns) ? images.localPatterns.length : null,
imageSizes: (images == null ? void 0 : images.imageSizes) ? images.imageSizes.join(',') : null,
imageQualities: (images == null ? void 0 : images.qualities) ? images.qualities.join(',') : null,
imageLoader: images == null ? void 0 : images.loader,
imageFormats: (images == null ? void 0 : images.formats) ? images.formats.join(',') : null,
nextConfigOutput: (nextConfig == null ? void 0 : nextConfig.output) || null,
trailingSlashEnabled: !!(nextConfig == null ? void 0 : nextConfig.trailingSlash),
reactStrictMode: !!(nextConfig == null ? void 0 : nextConfig.reactStrictMode),
webpackVersion: event.webpackVersion || null,
turboFlag: event.turboFlag || false,
isRspack: process.env.NEXT_RSPACK !== undefined,
appDir: event.appDir,
pagesDir: event.pagesDir,
staticStaleTime: ((_nextConfig_experimental_staleTimes = nextConfig.experimental.staleTimes) == null ? void 0 : _nextConfig_experimental_staleTimes.static) ?? null,
dynamicStaleTime: ((_nextConfig_experimental_staleTimes1 = nextConfig.experimental.staleTimes) == null ? void 0 : _nextConfig_experimental_staleTimes1.dynamic) ?? null,
reactCompiler: Boolean(nextConfig.reactCompiler),
reactCompilerCompilationMode: typeof nextConfig.reactCompiler !== 'boolean' ? ((_nextConfig_reactCompiler = nextConfig.reactCompiler) == null ? void 0 : _nextConfig_reactCompiler.compilationMode) ?? null : null,
reactCompilerPanicThreshold: typeof nextConfig.reactCompiler !== 'boolean' ? ((_nextConfig_reactCompiler1 = nextConfig.reactCompiler) == null ? void 0 : _nextConfig_reactCompiler1.panicThreshold) ?? null : null
};
return [
{
eventName: EVENT_VERSION,
payload
}
];
}
//# sourceMappingURL=version.js.map
File diff suppressed because one or more lines are too long
+1
View File
@@ -0,0 +1 @@
export declare function flushTelemetry(): Promise<void>;
+19
View File
@@ -0,0 +1,19 @@
"use strict";
Object.defineProperty(exports, "__esModule", {
value: true
});
Object.defineProperty(exports, "flushTelemetry", {
enumerable: true,
get: function() {
return flushTelemetry;
}
});
const _shared = require("../trace/shared");
async function flushTelemetry() {
let telemetry = _shared.traceGlobals.get('telemetry');
if (telemetry) {
await telemetry.flush();
}
}
//# sourceMappingURL=flush-telemetry.js.map
+1
View File
@@ -0,0 +1 @@
{"version":3,"sources":["../../src/telemetry/flush-telemetry.ts"],"sourcesContent":["import { traceGlobals } from '../trace/shared'\n\nexport async function flushTelemetry() {\n let telemetry = traceGlobals.get('telemetry') as\n | InstanceType<typeof import('./storage').Telemetry>\n | undefined\n if (telemetry) {\n await telemetry.flush()\n }\n}\n"],"names":["flushTelemetry","telemetry","traceGlobals","get","flush"],"mappings":";;;;+BAEsBA;;;eAAAA;;;wBAFO;AAEtB,eAAeA;IACpB,IAAIC,YAAYC,oBAAY,CAACC,GAAG,CAAC;IAGjC,IAAIF,WAAW;QACb,MAAMA,UAAUG,KAAK;IACvB;AACF","ignoreList":[0]}
+16
View File
@@ -0,0 +1,16 @@
interface Payload {
meta: {
[key: string]: unknown;
};
context: {
anonymousId: string;
projectId: string;
sessionId: string;
};
events: Array<{
eventName: string;
fields: object;
}>;
}
export declare function postNextTelemetryPayload(payload: Payload, signal?: any): any;
export {};
+48
View File
@@ -0,0 +1,48 @@
"use strict";
Object.defineProperty(exports, "__esModule", {
value: true
});
Object.defineProperty(exports, "postNextTelemetryPayload", {
enumerable: true,
get: function() {
return postNextTelemetryPayload;
}
});
const _asyncretry = /*#__PURE__*/ _interop_require_default(require("next/dist/compiled/async-retry"));
function _interop_require_default(obj) {
return obj && obj.__esModule ? obj : {
default: obj
};
}
function postNextTelemetryPayload(payload, signal) {
if (!signal && 'timeout' in AbortSignal) {
signal = AbortSignal.timeout(5000);
}
return (0, _asyncretry.default)(()=>fetch('https://telemetry.nextjs.org/api/v1/record', {
method: 'POST',
body: JSON.stringify(payload),
headers: {
'content-type': 'application/json'
},
signal
}).then((res)=>{
if (!res.ok) {
const err = Object.defineProperty(new Error(res.statusText), "__NEXT_ERROR_CODE", {
value: "E394",
enumerable: false,
configurable: true
});
err.response = res;
throw err;
}
}), {
minTimeout: 500,
retries: 1,
factor: 1
}).catch(()=>{
// We swallow errors when telemetry cannot be sent
})// Ensure promise is voided
.then(()=>{}, ()=>{});
}
//# sourceMappingURL=post-telemetry-payload.js.map
+1
View File
@@ -0,0 +1 @@
{"version":3,"sources":["../../src/telemetry/post-telemetry-payload.ts"],"sourcesContent":["import retry from 'next/dist/compiled/async-retry'\n\ninterface Payload {\n meta: { [key: string]: unknown }\n\n context: {\n anonymousId: string\n projectId: string\n sessionId: string\n }\n\n events: Array<{\n eventName: string\n fields: object\n }>\n}\n\nexport function postNextTelemetryPayload(payload: Payload, signal?: any) {\n if (!signal && 'timeout' in AbortSignal) {\n signal = AbortSignal.timeout(5000)\n }\n return (\n retry(\n () =>\n fetch('https://telemetry.nextjs.org/api/v1/record', {\n method: 'POST',\n body: JSON.stringify(payload),\n headers: { 'content-type': 'application/json' },\n signal,\n }).then((res) => {\n if (!res.ok) {\n const err = new Error(res.statusText)\n ;(err as any).response = res\n throw err\n }\n }),\n { minTimeout: 500, retries: 1, factor: 1 }\n )\n .catch(() => {\n // We swallow errors when telemetry cannot be sent\n })\n // Ensure promise is voided\n .then(\n () => {},\n () => {}\n )\n )\n}\n"],"names":["postNextTelemetryPayload","payload","signal","AbortSignal","timeout","retry","fetch","method","body","JSON","stringify","headers","then","res","ok","err","Error","statusText","response","minTimeout","retries","factor","catch"],"mappings":";;;;+BAiBgBA;;;eAAAA;;;mEAjBE;;;;;;AAiBX,SAASA,yBAAyBC,OAAgB,EAAEC,MAAY;IACrE,IAAI,CAACA,UAAU,aAAaC,aAAa;QACvCD,SAASC,YAAYC,OAAO,CAAC;IAC/B;IACA,OACEC,IAAAA,mBAAK,EACH,IACEC,MAAM,8CAA8C;YAClDC,QAAQ;YACRC,MAAMC,KAAKC,SAAS,CAACT;YACrBU,SAAS;gBAAE,gBAAgB;YAAmB;YAC9CT;QACF,GAAGU,IAAI,CAAC,CAACC;YACP,IAAI,CAACA,IAAIC,EAAE,EAAE;gBACX,MAAMC,MAAM,qBAAyB,CAAzB,IAAIC,MAAMH,IAAII,UAAU,GAAxB,qBAAA;2BAAA;gCAAA;kCAAA;gBAAwB;gBAClCF,IAAYG,QAAQ,GAAGL;gBACzB,MAAME;YACR;QACF,IACF;QAAEI,YAAY;QAAKC,SAAS;QAAGC,QAAQ;IAAE,GAExCC,KAAK,CAAC;IACL,kDAAkD;IACpD,EACA,2BAA2B;KAC1BV,IAAI,CACH,KAAO,GACP,KAAO;AAGf","ignoreList":[0]}
+83
View File
@@ -0,0 +1,83 @@
"use strict";
Object.defineProperty(exports, "__esModule", {
value: true
});
const _posttelemetrypayload = require("./post-telemetry-payload");
describe('postNextTelemetryPayload', ()=>{
let originalFetch;
beforeEach(()=>{
originalFetch = global.fetch;
});
afterEach(()=>{
global.fetch = originalFetch;
});
it('sends telemetry payload successfully', async ()=>{
const mockFetch = jest.fn().mockResolvedValue({
ok: true
});
global.fetch = mockFetch;
const payload = {
meta: {
version: '1.0'
},
context: {
anonymousId: 'test-id',
projectId: 'test-project',
sessionId: 'test-session'
},
events: [
{
eventName: 'test-event',
fields: {
foo: 'bar'
}
}
]
};
await (0, _posttelemetrypayload.postNextTelemetryPayload)(payload);
expect(mockFetch).toHaveBeenCalledWith('https://telemetry.nextjs.org/api/v1/record', {
method: 'POST',
body: JSON.stringify(payload),
headers: {
'content-type': 'application/json'
},
signal: expect.any(AbortSignal)
});
});
it('retries on failure', async ()=>{
const mockFetch = jest.fn().mockRejectedValueOnce(new Error('Network error')).mockResolvedValueOnce({
ok: true
});
global.fetch = mockFetch;
const payload = {
meta: {},
context: {
anonymousId: 'test-id',
projectId: 'test-project',
sessionId: 'test-session'
},
events: []
};
await (0, _posttelemetrypayload.postNextTelemetryPayload)(payload);
expect(mockFetch).toHaveBeenCalledTimes(2);
});
it('swallows errors after retries exhausted', async ()=>{
const mockFetch = jest.fn().mockRejectedValue(new Error('Network error'));
global.fetch = mockFetch;
const payload = {
meta: {},
context: {
anonymousId: 'test-id',
projectId: 'test-project',
sessionId: 'test-session'
},
events: []
};
// Should not throw
await (0, _posttelemetrypayload.postNextTelemetryPayload)(payload);
expect(mockFetch).toHaveBeenCalledTimes(2) // Initial try + 1 retry
;
});
});
//# sourceMappingURL=post-telemetry-payload.test.js.map
+1
View File
@@ -0,0 +1 @@
{"version":3,"sources":["../../src/telemetry/post-telemetry-payload.test.ts"],"sourcesContent":["import { postNextTelemetryPayload } from './post-telemetry-payload'\n\ndescribe('postNextTelemetryPayload', () => {\n let originalFetch: typeof fetch\n\n beforeEach(() => {\n originalFetch = global.fetch\n })\n\n afterEach(() => {\n global.fetch = originalFetch\n })\n\n it('sends telemetry payload successfully', async () => {\n const mockFetch = jest.fn().mockResolvedValue({\n ok: true,\n })\n global.fetch = mockFetch\n\n const payload = {\n meta: { version: '1.0' },\n context: {\n anonymousId: 'test-id',\n projectId: 'test-project',\n sessionId: 'test-session',\n },\n events: [\n {\n eventName: 'test-event',\n fields: { foo: 'bar' },\n },\n ],\n }\n\n await postNextTelemetryPayload(payload)\n\n expect(mockFetch).toHaveBeenCalledWith(\n 'https://telemetry.nextjs.org/api/v1/record',\n {\n method: 'POST',\n body: JSON.stringify(payload),\n headers: { 'content-type': 'application/json' },\n signal: expect.any(AbortSignal),\n }\n )\n })\n\n it('retries on failure', async () => {\n const mockFetch = jest\n .fn()\n .mockRejectedValueOnce(new Error('Network error'))\n .mockResolvedValueOnce({ ok: true })\n global.fetch = mockFetch\n\n const payload = {\n meta: {},\n context: {\n anonymousId: 'test-id',\n projectId: 'test-project',\n sessionId: 'test-session',\n },\n events: [],\n }\n\n await postNextTelemetryPayload(payload)\n\n expect(mockFetch).toHaveBeenCalledTimes(2)\n })\n\n it('swallows errors after retries exhausted', async () => {\n const mockFetch = jest.fn().mockRejectedValue(new Error('Network error'))\n global.fetch = mockFetch\n\n const payload = {\n meta: {},\n context: {\n anonymousId: 'test-id',\n projectId: 'test-project',\n sessionId: 'test-session',\n },\n events: [],\n }\n\n // Should not throw\n await postNextTelemetryPayload(payload)\n\n expect(mockFetch).toHaveBeenCalledTimes(2) // Initial try + 1 retry\n })\n})\n"],"names":["describe","originalFetch","beforeEach","global","fetch","afterEach","it","mockFetch","jest","fn","mockResolvedValue","ok","payload","meta","version","context","anonymousId","projectId","sessionId","events","eventName","fields","foo","postNextTelemetryPayload","expect","toHaveBeenCalledWith","method","body","JSON","stringify","headers","signal","any","AbortSignal","mockRejectedValueOnce","Error","mockResolvedValueOnce","toHaveBeenCalledTimes","mockRejectedValue"],"mappings":";;;;sCAAyC;AAEzCA,SAAS,4BAA4B;IACnC,IAAIC;IAEJC,WAAW;QACTD,gBAAgBE,OAAOC,KAAK;IAC9B;IAEAC,UAAU;QACRF,OAAOC,KAAK,GAAGH;IACjB;IAEAK,GAAG,wCAAwC;QACzC,MAAMC,YAAYC,KAAKC,EAAE,GAAGC,iBAAiB,CAAC;YAC5CC,IAAI;QACN;QACAR,OAAOC,KAAK,GAAGG;QAEf,MAAMK,UAAU;YACdC,MAAM;gBAAEC,SAAS;YAAM;YACvBC,SAAS;gBACPC,aAAa;gBACbC,WAAW;gBACXC,WAAW;YACb;YACAC,QAAQ;gBACN;oBACEC,WAAW;oBACXC,QAAQ;wBAAEC,KAAK;oBAAM;gBACvB;aACD;QACH;QAEA,MAAMC,IAAAA,8CAAwB,EAACX;QAE/BY,OAAOjB,WAAWkB,oBAAoB,CACpC,8CACA;YACEC,QAAQ;YACRC,MAAMC,KAAKC,SAAS,CAACjB;YACrBkB,SAAS;gBAAE,gBAAgB;YAAmB;YAC9CC,QAAQP,OAAOQ,GAAG,CAACC;QACrB;IAEJ;IAEA3B,GAAG,sBAAsB;QACvB,MAAMC,YAAYC,KACfC,EAAE,GACFyB,qBAAqB,CAAC,IAAIC,MAAM,kBAChCC,qBAAqB,CAAC;YAAEzB,IAAI;QAAK;QACpCR,OAAOC,KAAK,GAAGG;QAEf,MAAMK,UAAU;YACdC,MAAM,CAAC;YACPE,SAAS;gBACPC,aAAa;gBACbC,WAAW;gBACXC,WAAW;YACb;YACAC,QAAQ,EAAE;QACZ;QAEA,MAAMI,IAAAA,8CAAwB,EAACX;QAE/BY,OAAOjB,WAAW8B,qBAAqB,CAAC;IAC1C;IAEA/B,GAAG,2CAA2C;QAC5C,MAAMC,YAAYC,KAAKC,EAAE,GAAG6B,iBAAiB,CAAC,IAAIH,MAAM;QACxDhC,OAAOC,KAAK,GAAGG;QAEf,MAAMK,UAAU;YACdC,MAAM,CAAC;YACPE,SAAS;gBACPC,aAAa;gBACbC,WAAW;gBACXC,WAAW;YACb;YACAC,QAAQ,EAAE;QACZ;QAEA,mBAAmB;QACnB,MAAMI,IAAAA,8CAAwB,EAACX;QAE/BY,OAAOjB,WAAW8B,qBAAqB,CAAC,GAAG,wBAAwB;;IACrE;AACF","ignoreList":[0]}
+1
View File
@@ -0,0 +1 @@
export declare function getRawProjectId(): Promise<string>;
+48
View File
@@ -0,0 +1,48 @@
"use strict";
Object.defineProperty(exports, "__esModule", {
value: true
});
Object.defineProperty(exports, "getRawProjectId", {
enumerable: true,
get: function() {
return getRawProjectId;
}
});
const _child_process = require("child_process");
// Q: Why does Next.js need a project ID? Why is it looking at my git remote?
// A:
// Next.js' telemetry is and always will be completely anonymous. Because of
// this, we need a way to differentiate different projects to track feature
// usage accurately. For example, to prevent a feature from appearing to be
// constantly `used` and then `unused` when switching between local projects.
// To reiterate,
// we **never** can read your actual git remote. The value is hashed one-way
// with random salt data, making it impossible for us to reverse or try to
// guess the remote by re-computing hashes.
async function _getProjectIdByGit() {
try {
let resolve, reject;
const promise = new Promise((res, rej)=>{
resolve = res;
reject = rej;
});
(0, _child_process.exec)(`git config --local --get remote.origin.url`, {
timeout: 1000,
windowsHide: true
}, (error, stdout)=>{
if (error) {
reject(error);
return;
}
resolve(stdout);
});
return String(await promise).trim();
} catch (_) {
return null;
}
}
async function getRawProjectId() {
return await _getProjectIdByGit() || process.env.REPOSITORY_URL || process.cwd();
}
//# sourceMappingURL=project-id.js.map
+1
View File
@@ -0,0 +1 @@
{"version":3,"sources":["../../src/telemetry/project-id.ts"],"sourcesContent":["import { exec } from 'child_process'\n\n// Q: Why does Next.js need a project ID? Why is it looking at my git remote?\n// A:\n// Next.js' telemetry is and always will be completely anonymous. Because of\n// this, we need a way to differentiate different projects to track feature\n// usage accurately. For example, to prevent a feature from appearing to be\n// constantly `used` and then `unused` when switching between local projects.\n// To reiterate,\n// we **never** can read your actual git remote. The value is hashed one-way\n// with random salt data, making it impossible for us to reverse or try to\n// guess the remote by re-computing hashes.\n\nasync function _getProjectIdByGit() {\n try {\n let resolve: (value: Buffer | string) => void, reject: (err: Error) => void\n const promise = new Promise<Buffer | string>((res, rej) => {\n resolve = res\n reject = rej\n })\n\n exec(\n `git config --local --get remote.origin.url`,\n {\n timeout: 1000,\n windowsHide: true,\n },\n (error: null | Error, stdout: Buffer | string) => {\n if (error) {\n reject(error)\n return\n }\n resolve(stdout)\n }\n )\n\n return String(await promise).trim()\n } catch (_) {\n return null\n }\n}\n\nexport async function getRawProjectId(): Promise<string> {\n return (\n (await _getProjectIdByGit()) || process.env.REPOSITORY_URL || process.cwd()\n )\n}\n"],"names":["getRawProjectId","_getProjectIdByGit","resolve","reject","promise","Promise","res","rej","exec","timeout","windowsHide","error","stdout","String","trim","_","process","env","REPOSITORY_URL","cwd"],"mappings":";;;;+BA0CsBA;;;eAAAA;;;+BA1CD;AAErB,6EAA6E;AAC7E,KAAK;AACL,4EAA4E;AAC5E,2EAA2E;AAC3E,2EAA2E;AAC3E,6EAA6E;AAC7E,gBAAgB;AAChB,4EAA4E;AAC5E,0EAA0E;AAC1E,2CAA2C;AAE3C,eAAeC;IACb,IAAI;QACF,IAAIC,SAA2CC;QAC/C,MAAMC,UAAU,IAAIC,QAAyB,CAACC,KAAKC;YACjDL,UAAUI;YACVH,SAASI;QACX;QAEAC,IAAAA,mBAAI,EACF,CAAC,0CAA0C,CAAC,EAC5C;YACEC,SAAS;YACTC,aAAa;QACf,GACA,CAACC,OAAqBC;YACpB,IAAID,OAAO;gBACTR,OAAOQ;gBACP;YACF;YACAT,QAAQU;QACV;QAGF,OAAOC,OAAO,MAAMT,SAASU,IAAI;IACnC,EAAE,OAAOC,GAAG;QACV,OAAO;IACT;AACF;AAEO,eAAef;IACpB,OACE,AAAC,MAAMC,wBAAyBe,QAAQC,GAAG,CAACC,cAAc,IAAIF,QAAQG,GAAG;AAE7E","ignoreList":[0]}
+36
View File
@@ -0,0 +1,36 @@
import type { BinaryLike } from 'crypto';
export type TelemetryEvent = {
eventName: string;
payload: object;
};
type RecordObject = {
isFulfilled: boolean;
isRejected: boolean;
value?: any;
reason?: any;
};
export declare class Telemetry {
readonly sessionId: string;
private conf;
private distDir;
private loadProjectId;
private NEXT_TELEMETRY_DISABLED;
private NEXT_TELEMETRY_DEBUG;
private queue;
constructor({ distDir }: {
distDir: string;
});
private notify;
get anonymousId(): string;
get salt(): string;
private get isDisabled();
setEnabled: (_enabled: boolean) => string | null;
get isEnabled(): boolean;
oneWayHash: (payload: BinaryLike) => string;
private getProjectId;
record: (_events: TelemetryEvent | TelemetryEvent[], deferred?: boolean) => Promise<RecordObject>;
flush: () => Promise<RecordObject[] | null>;
flushDetached: (mode: "dev", dir: string) => void;
private submitRecord;
}
export {};
+301
View File
@@ -0,0 +1,301 @@
"use strict";
Object.defineProperty(exports, "__esModule", {
value: true
});
Object.defineProperty(exports, "Telemetry", {
enumerable: true,
get: function() {
return Telemetry;
}
});
const _picocolors = require("../lib/picocolors");
const _conf = /*#__PURE__*/ _interop_require_default(require("next/dist/compiled/conf"));
const _crypto = require("crypto");
const _isdocker = /*#__PURE__*/ _interop_require_default(require("next/dist/compiled/is-docker"));
const _path = /*#__PURE__*/ _interop_require_default(require("path"));
const _anonymousmeta = require("./anonymous-meta");
const _ciinfo = /*#__PURE__*/ _interop_require_wildcard(require("../server/ci-info"));
const _posttelemetrypayload = require("./post-telemetry-payload");
const _projectid = require("./project-id");
const _ponyfill = require("next/dist/compiled/@edge-runtime/ponyfill");
const _fs = /*#__PURE__*/ _interop_require_default(require("fs"));
function _interop_require_default(obj) {
return obj && obj.__esModule ? obj : {
default: obj
};
}
function _getRequireWildcardCache(nodeInterop) {
if (typeof WeakMap !== "function") return null;
var cacheBabelInterop = new WeakMap();
var cacheNodeInterop = new WeakMap();
return (_getRequireWildcardCache = function(nodeInterop) {
return nodeInterop ? cacheNodeInterop : cacheBabelInterop;
})(nodeInterop);
}
function _interop_require_wildcard(obj, nodeInterop) {
if (!nodeInterop && obj && obj.__esModule) {
return obj;
}
if (obj === null || typeof obj !== "object" && typeof obj !== "function") {
return {
default: obj
};
}
var cache = _getRequireWildcardCache(nodeInterop);
if (cache && cache.has(obj)) {
return cache.get(obj);
}
var newObj = {
__proto__: null
};
var hasPropertyDescriptor = Object.defineProperty && Object.getOwnPropertyDescriptor;
for(var key in obj){
if (key !== "default" && 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;
}
// 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`;
function getStorageDirectory(distDir) {
const isLikelyEphemeral = _ciinfo.isCI || (0, _isdocker.default)();
if (isLikelyEphemeral) {
return _path.default.join(distDir, 'cache');
}
return undefined;
}
class Telemetry {
constructor({ distDir }){
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(`${(0, _picocolors.magenta)((0, _picocolors.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((0, _picocolors.cyan)('https://nextjs.org/telemetry'));
console.log();
};
this.setEnabled = (_enabled)=>{
const enabled = !!_enabled;
this.conf && this.conf.set(TELEMETRY_KEY_ENABLED, enabled);
return this.conf && this.conf.path;
};
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, deferred)=>{
const prom = (deferred ? // flushDetached we can skip starting the initial
// submitRecord which will then be cancelled
new Promise((resolve)=>resolve({
isFulfilled: true,
isRejected: false,
value: _events
})) : this.submitRecord(_events)).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
if (!deferred) {
this.queue.delete(prom);
}
return res;
});
prom._events = Array.isArray(_events) ? _events : [
_events
];
prom._controller = prom._controller;
// Track this `Promise` so we can flush pending events
this.queue.add(prom);
return prom;
};
this.flush = async ()=>{
return Promise.all(this.queue).catch(()=>null);
};
// writes current events to disk and spawns separate
// detached process to submit the records without blocking
// the main process from exiting
this.flushDetached = (mode, dir)=>{
const allEvents = [];
this.queue.forEach((item)=>{
try {
var _item__controller;
(_item__controller = item._controller) == null ? void 0 : _item__controller.abort();
allEvents.push(...item._events);
} catch (_) {
// if we fail to abort ignore this event
}
});
if (allEvents.length === 0) {
// No events to flush
return;
}
_fs.default.mkdirSync(this.distDir, {
recursive: true
});
// Use unique filename per process to avoid race conditions between parent/child
const eventsFile = `_events_${process.pid}.json`;
_fs.default.writeFileSync(_path.default.join(this.distDir, eventsFile), JSON.stringify(allEvents));
// Note: cross-spawn is not used here as it causes
// a new command window to appear when we don't want it to
const child_process = require('child_process');
// we use spawnSync when debugging to ensure logs are piped
// correctly to stdout/stderr
const spawn = this.NEXT_TELEMETRY_DEBUG ? child_process.spawnSync : child_process.spawn;
spawn(process.execPath, [
require.resolve('./detached-flush'),
mode,
dir,
eventsFile
], {
detached: !this.NEXT_TELEMETRY_DEBUG,
windowsHide: true,
shell: false,
...this.NEXT_TELEMETRY_DEBUG ? {
stdio: 'inherit'
} : {}
});
};
this.submitRecord = async (_events)=>{
let events;
if (Array.isArray(_events)) {
events = _events;
} else {
events = [
_events
];
}
if (events.length < 1) {
return Promise.resolve();
}
if (this.NEXT_TELEMETRY_DEBUG) {
// Return a promise that resolves after logging to ensure the output
// is captured before the process exits (e.g., during flushDetached)
return new Promise((resolve)=>{
setTimeout(()=>{
// Print to standard error to simplify selecting the output
events.forEach(({ eventName, payload })=>console.error(`[telemetry] ` + JSON.stringify({
eventName,
payload
}, null, 2)));
resolve(undefined);
}, 100);
});
}
// Skip recording telemetry if the feature is disabled
if (this.isDisabled) {
return Promise.resolve();
}
const postController = new _ponyfill.AbortController();
const res = (0, _posttelemetrypayload.postNextTelemetryPayload)({
context: {
anonymousId: this.anonymousId,
projectId: await this.getProjectId(),
sessionId: this.sessionId
},
meta: (0, _anonymousmeta.getAnonymousMeta)(),
events: events.map(({ eventName, payload })=>({
eventName,
fields: payload
}))
}, postController.signal);
res._controller = postController;
return res;
};
// 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;
this.distDir = distDir;
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.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.NEXT_TELEMETRY_DISABLED && !!this.conf && this.conf.get(TELEMETRY_KEY_ENABLED, true) !== false;
}
async getProjectId() {
this.loadProjectId = this.loadProjectId || (0, _projectid.getRawProjectId)();
return this.oneWayHash(await this.loadProjectId);
}
}
//# sourceMappingURL=storage.js.map
File diff suppressed because one or more lines are too long