@stacknext/cli 0.0.0-stage → 0.6.1
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/LICENSE +21 -0
- package/README.md +41 -2
- package/dist/bin.d.ts +3 -0
- package/dist/bin.d.ts.map +1 -0
- package/dist/bin.js +4 -0
- package/dist/bin.js.map +1 -0
- package/dist/collector/server.d.ts +28 -0
- package/dist/collector/server.d.ts.map +1 -0
- package/dist/collector/server.js +1258 -0
- package/dist/collector/server.js.map +1 -0
- package/dist/collector/test-runs.d.ts +40 -0
- package/dist/collector/test-runs.d.ts.map +1 -0
- package/dist/collector/test-runs.js +153 -0
- package/dist/collector/test-runs.js.map +1 -0
- package/dist/commands/baseline.d.ts +25 -0
- package/dist/commands/baseline.d.ts.map +1 -0
- package/dist/commands/baseline.js +151 -0
- package/dist/commands/baseline.js.map +1 -0
- package/dist/commands/capture.d.ts +13 -0
- package/dist/commands/capture.d.ts.map +1 -0
- package/dist/commands/capture.js +277 -0
- package/dist/commands/capture.js.map +1 -0
- package/dist/commands/compare.d.ts +17 -0
- package/dist/commands/compare.d.ts.map +1 -0
- package/dist/commands/compare.js +95 -0
- package/dist/commands/compare.js.map +1 -0
- package/dist/commands/coverage.d.ts +9 -0
- package/dist/commands/coverage.d.ts.map +1 -0
- package/dist/commands/coverage.js +124 -0
- package/dist/commands/coverage.js.map +1 -0
- package/dist/commands/dev.d.ts +19 -0
- package/dist/commands/dev.d.ts.map +1 -0
- package/dist/commands/dev.js +296 -0
- package/dist/commands/dev.js.map +1 -0
- package/dist/commands/diagnose.d.ts +22 -0
- package/dist/commands/diagnose.d.ts.map +1 -0
- package/dist/commands/diagnose.js +235 -0
- package/dist/commands/diagnose.js.map +1 -0
- package/dist/commands/doctor.d.ts +7 -0
- package/dist/commands/doctor.d.ts.map +1 -0
- package/dist/commands/doctor.js +176 -0
- package/dist/commands/doctor.js.map +1 -0
- package/dist/commands/export.d.ts +9 -0
- package/dist/commands/export.d.ts.map +1 -0
- package/dist/commands/export.js +55 -0
- package/dist/commands/export.js.map +1 -0
- package/dist/commands/init.d.ts +11 -0
- package/dist/commands/init.d.ts.map +1 -0
- package/dist/commands/init.js +203 -0
- package/dist/commands/init.js.map +1 -0
- package/dist/commands/mcp.d.ts +12 -0
- package/dist/commands/mcp.d.ts.map +1 -0
- package/dist/commands/mcp.js +32 -0
- package/dist/commands/mcp.js.map +1 -0
- package/dist/commands/regression-shared.d.ts +12 -0
- package/dist/commands/regression-shared.d.ts.map +1 -0
- package/dist/commands/regression-shared.js +149 -0
- package/dist/commands/regression-shared.js.map +1 -0
- package/dist/commands/runs.d.ts +13 -0
- package/dist/commands/runs.d.ts.map +1 -0
- package/dist/commands/runs.js +85 -0
- package/dist/commands/runs.js.map +1 -0
- package/dist/commands/status.d.ts +7 -0
- package/dist/commands/status.d.ts.map +1 -0
- package/dist/commands/status.js +70 -0
- package/dist/commands/status.js.map +1 -0
- package/dist/commands/uninstall.d.ts +15 -0
- package/dist/commands/uninstall.d.ts.map +1 -0
- package/dist/commands/uninstall.js +209 -0
- package/dist/commands/uninstall.js.map +1 -0
- package/dist/http.d.ts +7 -0
- package/dist/http.d.ts.map +1 -0
- package/dist/http.js +54 -0
- package/dist/http.js.map +1 -0
- package/dist/index.d.ts +22 -0
- package/dist/index.d.ts.map +1 -0
- package/dist/index.js +22 -0
- package/dist/index.js.map +1 -0
- package/dist/output.d.ts +16 -0
- package/dist/output.d.ts.map +1 -0
- package/dist/output.js +60 -0
- package/dist/output.js.map +1 -0
- package/dist/program.d.ts +4 -0
- package/dist/program.d.ts.map +1 -0
- package/dist/program.js +54 -0
- package/dist/program.js.map +1 -0
- package/dist/project.d.ts +35 -0
- package/dist/project.d.ts.map +1 -0
- package/dist/project.js +169 -0
- package/dist/project.js.map +1 -0
- package/dist/runtime.d.ts +26 -0
- package/dist/runtime.d.ts.map +1 -0
- package/dist/runtime.js +89 -0
- package/dist/runtime.js.map +1 -0
- package/dist/session.d.ts +10 -0
- package/dist/session.d.ts.map +1 -0
- package/dist/session.js +23 -0
- package/dist/session.js.map +1 -0
- package/dist/version.d.ts +2 -0
- package/dist/version.d.ts.map +1 -0
- package/dist/version.js +2 -0
- package/dist/version.js.map +1 -0
- package/package.json +58 -3
|
@@ -0,0 +1,176 @@
|
|
|
1
|
+
import { readFile, stat } from 'node:fs/promises';
|
|
2
|
+
import path from 'node:path';
|
|
3
|
+
import { StackNextConfigError } from '@stacknext/core';
|
|
4
|
+
import { loadConfig } from '@stacknext/core/config-file';
|
|
5
|
+
import { collectorJson } from '../http.js';
|
|
6
|
+
import { printSection, style } from '../output.js';
|
|
7
|
+
import { detectProject } from '../project.js';
|
|
8
|
+
import { isProcessAlive, readRuntimeState, runtimeStatePath } from '../runtime.js';
|
|
9
|
+
import { resolveDashboardDir } from '../collector/server.js';
|
|
10
|
+
import { requireRunningState } from '../session.js';
|
|
11
|
+
function nodeSupported(version) {
|
|
12
|
+
const [major = 0, minor = 0] = version.split('.').map(Number);
|
|
13
|
+
return major > 20 || (major === 20 && minor >= 9);
|
|
14
|
+
}
|
|
15
|
+
function isIntegrated(source) {
|
|
16
|
+
return source.includes('@stacknext/next');
|
|
17
|
+
}
|
|
18
|
+
async function fileMode(file) {
|
|
19
|
+
try {
|
|
20
|
+
const info = await stat(file);
|
|
21
|
+
return info.mode & 0o777;
|
|
22
|
+
}
|
|
23
|
+
catch {
|
|
24
|
+
return null;
|
|
25
|
+
}
|
|
26
|
+
}
|
|
27
|
+
export async function runDoctor(options, cwd = process.cwd()) {
|
|
28
|
+
const checks = [];
|
|
29
|
+
const add = (group, status, label, detail) => {
|
|
30
|
+
checks.push({ group, status, label, ...(detail ? { detail } : {}) });
|
|
31
|
+
};
|
|
32
|
+
add('Environment', nodeSupported(process.versions.node) ? 'pass' : 'fail', `Node.js ${process.versions.node}`, nodeSupported(process.versions.node) ? '>= 20.9' : 'StackNext requires Node.js 20.9 or newer');
|
|
33
|
+
let config = null;
|
|
34
|
+
let projectName = path.basename(cwd);
|
|
35
|
+
try {
|
|
36
|
+
const project = await detectProject(cwd);
|
|
37
|
+
projectName = project.name;
|
|
38
|
+
add('Project', 'pass', `Project ${project.name}`, project.dir);
|
|
39
|
+
if (project.nextVersion === null) {
|
|
40
|
+
add('Project', 'fail', 'Next.js dependency not found');
|
|
41
|
+
}
|
|
42
|
+
else if (project.nextMajor !== null && project.nextMajor >= 15 && project.nextMajor <= 16) {
|
|
43
|
+
add('Project', 'pass', `Next.js ${project.nextVersion}`);
|
|
44
|
+
}
|
|
45
|
+
else {
|
|
46
|
+
add('Project', 'fail', `Next.js ${project.nextVersion} is not supported`, 'Use Next.js 15 or 16 with the App Router');
|
|
47
|
+
}
|
|
48
|
+
if (project.appDir) {
|
|
49
|
+
add('Project', 'pass', `App Router at ${project.appDir}/`);
|
|
50
|
+
}
|
|
51
|
+
else {
|
|
52
|
+
add('Project', 'fail', 'App Router directory not found', 'StackNext does not support the Pages Router');
|
|
53
|
+
}
|
|
54
|
+
try {
|
|
55
|
+
config = await loadConfig(project.dir);
|
|
56
|
+
add('Project', 'pass', 'stacknext.config.json is valid');
|
|
57
|
+
}
|
|
58
|
+
catch (error) {
|
|
59
|
+
add('Project', 'fail', 'Configuration is invalid', error instanceof StackNextConfigError
|
|
60
|
+
? error.issues.join('; ')
|
|
61
|
+
: error instanceof Error
|
|
62
|
+
? error.message
|
|
63
|
+
: String(error));
|
|
64
|
+
}
|
|
65
|
+
if (!project.instrumentationExists || !project.instrumentationPath) {
|
|
66
|
+
add('Instrumentation', 'fail', 'instrumentation.ts not found', 'Run "stacknext init" to create it');
|
|
67
|
+
}
|
|
68
|
+
else {
|
|
69
|
+
const source = await readFile(project.instrumentationPath, 'utf8');
|
|
70
|
+
if (isIntegrated(source)) {
|
|
71
|
+
add('Instrumentation', 'pass', 'instrumentation.ts imports @stacknext/next', path.relative(project.dir, project.instrumentationPath));
|
|
72
|
+
}
|
|
73
|
+
else {
|
|
74
|
+
add('Instrumentation', 'fail', 'instrumentation.ts does not import @stacknext/next', 'Add registerStackNext()/onRequestError without removing existing monitoring');
|
|
75
|
+
}
|
|
76
|
+
}
|
|
77
|
+
const declared = project.dependencies['@stacknext/next'] ??
|
|
78
|
+
project.devDependencies['@stacknext/next'];
|
|
79
|
+
if (declared)
|
|
80
|
+
add('Instrumentation', 'pass', `@stacknext/next ${declared}`);
|
|
81
|
+
else
|
|
82
|
+
add('Instrumentation', 'warn', '@stacknext/next is not declared', 'Install it with the package manager command printed by "stacknext init"');
|
|
83
|
+
if (config) {
|
|
84
|
+
if (config.database.drizzle && !project.hasDrizzle) {
|
|
85
|
+
add('Adapters', 'warn', 'Drizzle is enabled but drizzle-orm is not installed');
|
|
86
|
+
}
|
|
87
|
+
if (config.database.prisma && !project.hasPrisma) {
|
|
88
|
+
add('Adapters', 'warn', 'Prisma is enabled but @prisma/client is not installed');
|
|
89
|
+
}
|
|
90
|
+
if (project.hasDrizzle && !config.database.drizzle) {
|
|
91
|
+
add('Adapters', 'warn', 'Drizzle detected but database.drizzle is false', 'Enable it in stacknext.config.json');
|
|
92
|
+
}
|
|
93
|
+
if (project.hasPrisma && !config.database.prisma) {
|
|
94
|
+
add('Adapters', 'warn', 'Prisma detected but database.prisma is false', 'Enable it in stacknext.config.json');
|
|
95
|
+
}
|
|
96
|
+
add('Privacy', 'pass', 'Bodies, headers, cookies and SQL parameters are disabled');
|
|
97
|
+
add('Privacy', 'pass', `Retention ${Math.round(config.collector.retentionMs / 1000)}s, ${config.collector.maxSpans} spans`);
|
|
98
|
+
}
|
|
99
|
+
}
|
|
100
|
+
catch (error) {
|
|
101
|
+
add('Project', 'fail', 'Could not inspect the project', error instanceof Error ? error.message : String(error));
|
|
102
|
+
}
|
|
103
|
+
try {
|
|
104
|
+
const dashboardDir = await resolveDashboardDir();
|
|
105
|
+
add('Dashboard', 'pass', 'Dashboard build found', dashboardDir);
|
|
106
|
+
}
|
|
107
|
+
catch (error) {
|
|
108
|
+
add('Dashboard', 'warn', 'Dashboard build not found', error instanceof Error ? error.message : String(error));
|
|
109
|
+
}
|
|
110
|
+
const runtime = await readRuntimeState(cwd).catch(() => null);
|
|
111
|
+
if (!runtime) {
|
|
112
|
+
add('Collector', 'warn', 'StackNext is not running', 'Start it with "stacknext dev"');
|
|
113
|
+
}
|
|
114
|
+
else if (!isProcessAlive(runtime.pid)) {
|
|
115
|
+
add('Collector', 'warn', 'Stale runtime state', `Process ${runtime.pid} is not running; restart with "stacknext dev"`);
|
|
116
|
+
}
|
|
117
|
+
else {
|
|
118
|
+
const mode = await fileMode(runtimeStatePath(cwd));
|
|
119
|
+
if (mode !== null && (mode & 0o077) !== 0) {
|
|
120
|
+
add('Collector', 'warn', 'Runtime token file is readable by other users', `${runtimeStatePath(cwd)} mode ${mode.toString(8)}`);
|
|
121
|
+
}
|
|
122
|
+
else {
|
|
123
|
+
add('Collector', 'pass', 'Runtime token file permissions are private');
|
|
124
|
+
}
|
|
125
|
+
try {
|
|
126
|
+
const state = await requireRunningState(cwd);
|
|
127
|
+
const health = await collectorJson(state.collectorUrl, '/api/health', state.token);
|
|
128
|
+
add('Collector', 'pass', `Collector healthy on port ${state.port}`);
|
|
129
|
+
add('Collector', health.connected ? 'pass' : 'warn', health.connected ? 'Instrumentation connected' : 'No app heartbeat yet', health.connected
|
|
130
|
+
? `${health.connections.filter((entry) => entry.connected).length} instance(s)`
|
|
131
|
+
: 'Make a request after Next.js starts');
|
|
132
|
+
add('Collector', 'pass', `${health.counts.requests} requests, ${health.counts.spans} spans, ${health.counts.errors} errors`);
|
|
133
|
+
if (health.exporter.lastError) {
|
|
134
|
+
add('Collector', 'warn', 'Exporter reported an error', health.exporter.lastError);
|
|
135
|
+
}
|
|
136
|
+
}
|
|
137
|
+
catch (error) {
|
|
138
|
+
add('Collector', 'fail', 'Collector is unreachable', error instanceof Error ? error.message : String(error));
|
|
139
|
+
}
|
|
140
|
+
}
|
|
141
|
+
const failures = checks.filter((check) => check.status === 'fail').length;
|
|
142
|
+
const warnings = checks.filter((check) => check.status === 'warn').length;
|
|
143
|
+
if (options.json) {
|
|
144
|
+
console.log(JSON.stringify({ projectName, checks, failures, warnings }, null, 2));
|
|
145
|
+
}
|
|
146
|
+
else {
|
|
147
|
+
console.log(`${style.bold('StackNext doctor')} — ${projectName}`);
|
|
148
|
+
let currentGroup = '';
|
|
149
|
+
for (const check of checks) {
|
|
150
|
+
if (check.group !== currentGroup) {
|
|
151
|
+
printSection(check.group);
|
|
152
|
+
currentGroup = check.group;
|
|
153
|
+
}
|
|
154
|
+
const marker = check.status === 'pass'
|
|
155
|
+
? style.green('✓')
|
|
156
|
+
: check.status === 'warn'
|
|
157
|
+
? style.yellow('!')
|
|
158
|
+
: style.red('✗');
|
|
159
|
+
console.log(`${marker} ${check.label}${check.detail ? style.dim(` — ${check.detail}`) : ''}`);
|
|
160
|
+
}
|
|
161
|
+
console.log(`\n${failures === 0 ? style.green('Ready') : style.red('Not ready')} — ${failures} failure(s), ${warnings} warning(s)`);
|
|
162
|
+
}
|
|
163
|
+
return failures === 0 ? 0 : 1;
|
|
164
|
+
}
|
|
165
|
+
export function registerDoctorCommand(program, cwd) {
|
|
166
|
+
program
|
|
167
|
+
.command('doctor')
|
|
168
|
+
.description('Check the project, instrumentation and collector')
|
|
169
|
+
.option('--json', 'print machine-readable JSON')
|
|
170
|
+
.action(async (options) => {
|
|
171
|
+
const code = await runDoctor(options, cwd);
|
|
172
|
+
if (code !== 0)
|
|
173
|
+
process.exitCode = code;
|
|
174
|
+
});
|
|
175
|
+
}
|
|
176
|
+
//# sourceMappingURL=doctor.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"doctor.js","sourceRoot":"","sources":["../../src/commands/doctor.ts"],"names":[],"mappings":"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"}
|
|
@@ -0,0 +1,9 @@
|
|
|
1
|
+
import type { Command } from 'commander';
|
|
2
|
+
export interface ExportOptions {
|
|
3
|
+
output?: string;
|
|
4
|
+
stdout?: boolean;
|
|
5
|
+
force?: boolean;
|
|
6
|
+
}
|
|
7
|
+
export declare function runExport(options: ExportOptions, cwd?: string): Promise<number>;
|
|
8
|
+
export declare function registerExportCommand(program: Command, cwd: string): void;
|
|
9
|
+
//# sourceMappingURL=export.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"export.d.ts","sourceRoot":"","sources":["../../src/commands/export.ts"],"names":[],"mappings":"AAEA,OAAO,KAAK,EAAE,OAAO,EAAE,MAAM,WAAW,CAAA;AAMxC,MAAM,WAAW,aAAa;IAC5B,MAAM,CAAC,EAAE,MAAM,CAAA;IACf,MAAM,CAAC,EAAE,OAAO,CAAA;IAChB,KAAK,CAAC,EAAE,OAAO,CAAA;CAChB;AAeD,wBAAsB,SAAS,CAC7B,OAAO,EAAE,aAAa,EACtB,GAAG,SAAgB,GAClB,OAAO,CAAC,MAAM,CAAC,CAwCjB;AAED,wBAAgB,qBAAqB,CAAC,OAAO,EAAE,OAAO,EAAE,GAAG,EAAE,MAAM,GAAG,IAAI,CAWzE"}
|
|
@@ -0,0 +1,55 @@
|
|
|
1
|
+
import { access, mkdir, writeFile } from 'node:fs/promises';
|
|
2
|
+
import path from 'node:path';
|
|
3
|
+
import { collectorJson } from '../http.js';
|
|
4
|
+
import { printCheck, printSection, style } from '../output.js';
|
|
5
|
+
import { requireRunningState } from '../session.js';
|
|
6
|
+
function timestamp() {
|
|
7
|
+
return new Date().toISOString().replace(/[:.]/g, '-').replace('T', '_').slice(0, 19);
|
|
8
|
+
}
|
|
9
|
+
async function exists(file) {
|
|
10
|
+
try {
|
|
11
|
+
await access(file);
|
|
12
|
+
return true;
|
|
13
|
+
}
|
|
14
|
+
catch {
|
|
15
|
+
return false;
|
|
16
|
+
}
|
|
17
|
+
}
|
|
18
|
+
export async function runExport(options, cwd = process.cwd()) {
|
|
19
|
+
if (options.output && options.stdout) {
|
|
20
|
+
throw new Error('Use either --output or --stdout, not both');
|
|
21
|
+
}
|
|
22
|
+
const state = await requireRunningState(cwd);
|
|
23
|
+
const payload = await collectorJson(state.collectorUrl, '/api/export', state.token);
|
|
24
|
+
const json = `${JSON.stringify(payload, null, 2)}\n`;
|
|
25
|
+
if (options.stdout) {
|
|
26
|
+
process.stdout.write(json);
|
|
27
|
+
return 0;
|
|
28
|
+
}
|
|
29
|
+
const file = path.resolve(cwd, options.output ??
|
|
30
|
+
`stacknext-export-${state.projectName.replace(/[^a-z0-9_-]+/gi, '-')}-${timestamp()}.json`);
|
|
31
|
+
if (!options.force && (await exists(file))) {
|
|
32
|
+
throw new Error(`${file} already exists. Choose another --output or pass --force.`);
|
|
33
|
+
}
|
|
34
|
+
await mkdir(path.dirname(file), { recursive: true });
|
|
35
|
+
await writeFile(file, json, { mode: 0o600 });
|
|
36
|
+
printSection('StackNext export');
|
|
37
|
+
printCheck('pass', `Wrote ${file}`);
|
|
38
|
+
printCheck('pass', `${payload.stats.requests} requests, ${payload.stats.spans} spans, ${payload.stats.errors} errors, ${payload.stats.databaseQueries} database queries`);
|
|
39
|
+
console.log(style.dim('Export contains redacted telemetry only: no bodies, headers, cookies or SQL parameters.'));
|
|
40
|
+
return 0;
|
|
41
|
+
}
|
|
42
|
+
export function registerExportCommand(program, cwd) {
|
|
43
|
+
program
|
|
44
|
+
.command('export')
|
|
45
|
+
.description('Export collected telemetry as JSON')
|
|
46
|
+
.option('-o, --output <file>', 'output file path')
|
|
47
|
+
.option('--stdout', 'write JSON to stdout')
|
|
48
|
+
.option('--force', 'overwrite an existing output file')
|
|
49
|
+
.action(async (options) => {
|
|
50
|
+
const code = await runExport(options, cwd);
|
|
51
|
+
if (code !== 0)
|
|
52
|
+
process.exitCode = code;
|
|
53
|
+
});
|
|
54
|
+
}
|
|
55
|
+
//# sourceMappingURL=export.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"export.js","sourceRoot":"","sources":["../../src/commands/export.ts"],"names":[],"mappings":"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"}
|
|
@@ -0,0 +1,11 @@
|
|
|
1
|
+
import type { Command } from 'commander';
|
|
2
|
+
export declare function generatedInstrumentation(typescript: boolean): string;
|
|
3
|
+
export declare function isGeneratedInstrumentation(source: string): boolean;
|
|
4
|
+
export declare function manualPatchSnippet(): string;
|
|
5
|
+
export declare function fileExists(file: string): Promise<boolean>;
|
|
6
|
+
export interface InitOptions {
|
|
7
|
+
install?: boolean;
|
|
8
|
+
}
|
|
9
|
+
export declare function runInit(options: InitOptions, cwd?: string): Promise<number>;
|
|
10
|
+
export declare function registerInitCommand(program: Command, cwd: string): void;
|
|
11
|
+
//# sourceMappingURL=init.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"init.d.ts","sourceRoot":"","sources":["../../src/commands/init.ts"],"names":[],"mappings":"AAGA,OAAO,KAAK,EAAE,OAAO,EAAE,MAAM,WAAW,CAAA;AAqBxC,wBAAgB,wBAAwB,CAAC,UAAU,EAAE,OAAO,GAAG,MAAM,CA+CpE;AAED,wBAAgB,0BAA0B,CAAC,MAAM,EAAE,MAAM,GAAG,OAAO,CAMlE;AAED,wBAAgB,kBAAkB,IAAI,MAAM,CAU3C;AAED,wBAAsB,UAAU,CAAC,IAAI,EAAE,MAAM,GAAG,OAAO,CAAC,OAAO,CAAC,CAO/D;AAoBD,MAAM,WAAW,WAAW;IAC1B,OAAO,CAAC,EAAE,OAAO,CAAA;CAClB;AAED,wBAAsB,OAAO,CAAC,OAAO,EAAE,WAAW,EAAE,GAAG,SAAgB,GAAG,OAAO,CAAC,MAAM,CAAC,CA2HxF;AAED,wBAAgB,mBAAmB,CAAC,OAAO,EAAE,OAAO,EAAE,GAAG,EAAE,MAAM,GAAG,IAAI,CASvE"}
|
|
@@ -0,0 +1,203 @@
|
|
|
1
|
+
import { spawn } from 'node:child_process';
|
|
2
|
+
import { access, readFile, writeFile } from 'node:fs/promises';
|
|
3
|
+
import path from 'node:path';
|
|
4
|
+
import { CONFIG_FILE_NAME, configPath, loadConfig } from '@stacknext/core/config-file';
|
|
5
|
+
import { detectProject, installCommand, isStackNextIntegrated, } from '../project.js';
|
|
6
|
+
import { printCheck, printSection, style } from '../output.js';
|
|
7
|
+
function instrumentationTarget(project) {
|
|
8
|
+
const inSrc = project.appDir?.startsWith('src/') === true ||
|
|
9
|
+
(project.appDir === null && project.srcDir);
|
|
10
|
+
return path.join(project.dir, inSrc ? 'src' : '', `instrumentation.${project.typescript ? 'ts' : 'js'}`);
|
|
11
|
+
}
|
|
12
|
+
export function generatedInstrumentation(typescript) {
|
|
13
|
+
if (typescript) {
|
|
14
|
+
return `type StackNextRequest = {
|
|
15
|
+
path: string
|
|
16
|
+
method: string
|
|
17
|
+
headers: NodeJS.Dict<string | string[]>
|
|
18
|
+
}
|
|
19
|
+
|
|
20
|
+
type StackNextRequestContext = {
|
|
21
|
+
routerKind: 'Pages Router' | 'App Router'
|
|
22
|
+
routePath: string
|
|
23
|
+
routeType: 'render' | 'route' | 'action' | 'proxy'
|
|
24
|
+
renderSource?: string
|
|
25
|
+
revalidateReason: 'on-demand' | 'stale' | undefined
|
|
26
|
+
}
|
|
27
|
+
|
|
28
|
+
// Generated by StackNext. Node.js runtime only; no-op without a local collector.
|
|
29
|
+
export async function register(): Promise<void> {
|
|
30
|
+
if (process.env.NEXT_RUNTIME !== 'nodejs') return
|
|
31
|
+
const stacknext = await import('@stacknext/next')
|
|
32
|
+
await stacknext.register()
|
|
33
|
+
}
|
|
34
|
+
|
|
35
|
+
export async function onRequestError(
|
|
36
|
+
error: unknown,
|
|
37
|
+
request: StackNextRequest,
|
|
38
|
+
context: StackNextRequestContext,
|
|
39
|
+
): Promise<void> {
|
|
40
|
+
if (process.env.NEXT_RUNTIME !== 'nodejs') return
|
|
41
|
+
const stacknext = await import('@stacknext/next')
|
|
42
|
+
stacknext.onRequestError(error, request, context)
|
|
43
|
+
}
|
|
44
|
+
`;
|
|
45
|
+
}
|
|
46
|
+
return `// Generated by StackNext. Node.js runtime only; no-op without a local collector.
|
|
47
|
+
export async function register() {
|
|
48
|
+
if (process.env.NEXT_RUNTIME !== 'nodejs') return
|
|
49
|
+
const stacknext = await import('@stacknext/next')
|
|
50
|
+
await stacknext.register()
|
|
51
|
+
}
|
|
52
|
+
|
|
53
|
+
export async function onRequestError(error, request, context) {
|
|
54
|
+
if (process.env.NEXT_RUNTIME !== 'nodejs') return
|
|
55
|
+
const stacknext = await import('@stacknext/next')
|
|
56
|
+
stacknext.onRequestError(error, request, context)
|
|
57
|
+
}
|
|
58
|
+
`;
|
|
59
|
+
}
|
|
60
|
+
export function isGeneratedInstrumentation(source) {
|
|
61
|
+
const normalized = source.replace(/\r\n/g, '\n').trimEnd();
|
|
62
|
+
return (normalized === generatedInstrumentation(true).trimEnd() ||
|
|
63
|
+
normalized === generatedInstrumentation(false).trimEnd());
|
|
64
|
+
}
|
|
65
|
+
export function manualPatchSnippet() {
|
|
66
|
+
return [
|
|
67
|
+
"import { registerStackNext, onRequestError as stackNextOnRequestError } from '@stacknext/next'",
|
|
68
|
+
'',
|
|
69
|
+
'// Inside your existing register():',
|
|
70
|
+
'await registerStackNext()',
|
|
71
|
+
'',
|
|
72
|
+
'// At module level, if you do not already export an error hook:',
|
|
73
|
+
'export const onRequestError = stackNextOnRequestError',
|
|
74
|
+
].join('\n');
|
|
75
|
+
}
|
|
76
|
+
export async function fileExists(file) {
|
|
77
|
+
try {
|
|
78
|
+
await access(file);
|
|
79
|
+
return true;
|
|
80
|
+
}
|
|
81
|
+
catch {
|
|
82
|
+
return false;
|
|
83
|
+
}
|
|
84
|
+
}
|
|
85
|
+
async function runInstall(project) {
|
|
86
|
+
const command = installCommand(project.packageManager, ['@stacknext/next'], true);
|
|
87
|
+
const [bin, ...args] = command.split(' ');
|
|
88
|
+
if (!bin)
|
|
89
|
+
return false;
|
|
90
|
+
return new Promise((resolve) => {
|
|
91
|
+
const child = spawn(bin, args, {
|
|
92
|
+
cwd: project.dir,
|
|
93
|
+
stdio: 'inherit',
|
|
94
|
+
shell: process.platform === 'win32',
|
|
95
|
+
});
|
|
96
|
+
child.once('error', (error) => {
|
|
97
|
+
printCheck('fail', 'Could not install @stacknext/next', error.message);
|
|
98
|
+
resolve(false);
|
|
99
|
+
});
|
|
100
|
+
child.once('exit', (code) => resolve(code === 0));
|
|
101
|
+
});
|
|
102
|
+
}
|
|
103
|
+
export async function runInit(options, cwd = process.cwd()) {
|
|
104
|
+
const project = await detectProject(cwd);
|
|
105
|
+
printSection(`StackNext init — ${project.name}`);
|
|
106
|
+
if (project.nextVersion === null) {
|
|
107
|
+
printCheck('fail', 'Next.js dependency not found', 'Install Next.js 15 or 16 first.');
|
|
108
|
+
return 1;
|
|
109
|
+
}
|
|
110
|
+
if (project.nextMajor !== null && project.nextMajor < 15) {
|
|
111
|
+
printCheck('fail', `Next.js ${project.nextVersion} is not supported`, 'StackNext requires Next.js 15 or 16 with the App Router.');
|
|
112
|
+
return 1;
|
|
113
|
+
}
|
|
114
|
+
if (project.nextMajor !== null && project.nextMajor > 16) {
|
|
115
|
+
printCheck('warn', `Next.js ${project.nextVersion} is newer than the tested range`, 'StackNext supports Next.js 15 and 16.');
|
|
116
|
+
}
|
|
117
|
+
else {
|
|
118
|
+
printCheck('pass', `Next.js ${project.nextVersion}`);
|
|
119
|
+
}
|
|
120
|
+
if (!project.appDir) {
|
|
121
|
+
printCheck('fail', 'App Router directory not found', 'StackNext supports the App Router only (app/ or src/app/).');
|
|
122
|
+
return 1;
|
|
123
|
+
}
|
|
124
|
+
printCheck('pass', `App Router at ${project.appDir}/`);
|
|
125
|
+
const configFile = configPath(project.dir);
|
|
126
|
+
if (!(await fileExists(configFile))) {
|
|
127
|
+
const config = {
|
|
128
|
+
projectName: project.name,
|
|
129
|
+
dashboard: { port: 4400 },
|
|
130
|
+
collector: { maxSpans: 5_000, retentionMs: 600_000 },
|
|
131
|
+
instrumentation: { verbose: false, captureFetch: true, captureErrors: true },
|
|
132
|
+
privacy: {
|
|
133
|
+
captureHeaders: false,
|
|
134
|
+
captureRequestBodies: false,
|
|
135
|
+
captureSqlParameters: false,
|
|
136
|
+
redactSensitiveData: true,
|
|
137
|
+
},
|
|
138
|
+
database: { drizzle: project.hasDrizzle, prisma: project.hasPrisma },
|
|
139
|
+
slowRequestMs: 500,
|
|
140
|
+
};
|
|
141
|
+
await writeFile(configFile, `${JSON.stringify(config, null, 2)}\n`, { mode: 0o600 });
|
|
142
|
+
printCheck('pass', `Created ${CONFIG_FILE_NAME}`);
|
|
143
|
+
}
|
|
144
|
+
else {
|
|
145
|
+
await loadConfig(project.dir);
|
|
146
|
+
printCheck('pass', `${CONFIG_FILE_NAME} is valid`);
|
|
147
|
+
}
|
|
148
|
+
if (project.instrumentationExists && project.instrumentationPath) {
|
|
149
|
+
const source = await readFile(project.instrumentationPath, 'utf8');
|
|
150
|
+
if (isStackNextIntegrated(source)) {
|
|
151
|
+
printCheck('pass', 'Instrumentation already imports @stacknext/next');
|
|
152
|
+
}
|
|
153
|
+
else {
|
|
154
|
+
printCheck('warn', 'Existing instrumentation.ts was left untouched', 'Add the hook below so your current monitoring keeps working:');
|
|
155
|
+
console.log(`\n${manualPatchSnippet()}\n`);
|
|
156
|
+
}
|
|
157
|
+
}
|
|
158
|
+
else {
|
|
159
|
+
const target = instrumentationTarget(project);
|
|
160
|
+
await writeFile(target, generatedInstrumentation(project.typescript), { mode: 0o600 });
|
|
161
|
+
printCheck('pass', `Created ${path.relative(project.dir, target)}`);
|
|
162
|
+
}
|
|
163
|
+
const declared = project.dependencies['@stacknext/next'] ??
|
|
164
|
+
project.devDependencies['@stacknext/next'];
|
|
165
|
+
if (!declared) {
|
|
166
|
+
if (options.install) {
|
|
167
|
+
const installed = await runInstall(project);
|
|
168
|
+
if (installed)
|
|
169
|
+
printCheck('pass', 'Installed @stacknext/next');
|
|
170
|
+
else
|
|
171
|
+
printCheck('warn', 'Install @stacknext/next before starting Next.js', installCommand(project.packageManager, ['@stacknext/next'], true));
|
|
172
|
+
}
|
|
173
|
+
else {
|
|
174
|
+
printCheck('warn', '@stacknext/next is not installed', installCommand(project.packageManager, ['@stacknext/next'], true));
|
|
175
|
+
}
|
|
176
|
+
}
|
|
177
|
+
else {
|
|
178
|
+
printCheck('pass', `@stacknext/next ${declared}`);
|
|
179
|
+
}
|
|
180
|
+
if (project.hasDrizzle) {
|
|
181
|
+
printCheck('warn', 'Drizzle detected', 'Add createStackNextDrizzleLogger() from @stacknext/drizzle to your db client.');
|
|
182
|
+
}
|
|
183
|
+
if (project.hasPrisma) {
|
|
184
|
+
printCheck('warn', 'Prisma detected', 'Add instrumentPrismaClient() from @stacknext/prisma after creating PrismaClient.');
|
|
185
|
+
}
|
|
186
|
+
printSection('Next steps');
|
|
187
|
+
console.log(`1. Run ${style.cyan('stacknext dev')} (or ${style.cyan('stacknext dev --install')} if packages are missing).`);
|
|
188
|
+
console.log(`2. Open the dashboard and make a request to your app.`);
|
|
189
|
+
console.log(`3. Run ${style.cyan('stacknext doctor')} if data does not appear.`);
|
|
190
|
+
return 0;
|
|
191
|
+
}
|
|
192
|
+
export function registerInitCommand(program, cwd) {
|
|
193
|
+
program
|
|
194
|
+
.command('init')
|
|
195
|
+
.description('Configure a Next.js project for StackNext')
|
|
196
|
+
.option('--install', 'install @stacknext/next with the detected package manager')
|
|
197
|
+
.action(async (options) => {
|
|
198
|
+
const code = await runInit(options, cwd);
|
|
199
|
+
if (code !== 0)
|
|
200
|
+
process.exitCode = code;
|
|
201
|
+
});
|
|
202
|
+
}
|
|
203
|
+
//# sourceMappingURL=init.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"init.js","sourceRoot":"","sources":["../../src/commands/init.ts"],"names":[],"mappings":"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"}
|
|
@@ -0,0 +1,12 @@
|
|
|
1
|
+
import type { Command } from 'commander';
|
|
2
|
+
export interface McpOptions {
|
|
3
|
+
collector?: string;
|
|
4
|
+
token?: string;
|
|
5
|
+
}
|
|
6
|
+
/**
|
|
7
|
+
* Starts the read-only MCP server on stdio. Diagnostics must go to stderr;
|
|
8
|
+
* stdout is reserved for the protocol.
|
|
9
|
+
*/
|
|
10
|
+
export declare function runMcp(options: McpOptions, cwd?: string): Promise<never>;
|
|
11
|
+
export declare function registerMcpCommand(program: Command, cwd: string): void;
|
|
12
|
+
//# sourceMappingURL=mcp.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"mcp.d.ts","sourceRoot":"","sources":["../../src/commands/mcp.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,OAAO,EAAE,MAAM,WAAW,CAAA;AAGxC,MAAM,WAAW,UAAU;IACzB,SAAS,CAAC,EAAE,MAAM,CAAA;IAClB,KAAK,CAAC,EAAE,MAAM,CAAA;CACf;AAED;;;GAGG;AACH,wBAAsB,MAAM,CAC1B,OAAO,EAAE,UAAU,EACnB,GAAG,SAAgB,GAClB,OAAO,CAAC,KAAK,CAAC,CAehB;AAED,wBAAgB,kBAAkB,CAAC,OAAO,EAAE,OAAO,EAAE,GAAG,EAAE,MAAM,GAAG,IAAI,CAStE"}
|
|
@@ -0,0 +1,32 @@
|
|
|
1
|
+
import { requireRunningState } from '../session.js';
|
|
2
|
+
/**
|
|
3
|
+
* Starts the read-only MCP server on stdio. Diagnostics must go to stderr;
|
|
4
|
+
* stdout is reserved for the protocol.
|
|
5
|
+
*/
|
|
6
|
+
export async function runMcp(options, cwd = process.cwd()) {
|
|
7
|
+
let baseUrl = options.collector;
|
|
8
|
+
let token = options.token;
|
|
9
|
+
if (!baseUrl || !token) {
|
|
10
|
+
const state = await requireRunningState(cwd);
|
|
11
|
+
baseUrl = baseUrl ?? state.collectorUrl;
|
|
12
|
+
token = token ?? state.token;
|
|
13
|
+
}
|
|
14
|
+
if (!token || token.length < 16) {
|
|
15
|
+
throw new Error('A collector token of at least 16 characters is required');
|
|
16
|
+
}
|
|
17
|
+
const { startMcpServer } = await import('@stacknext/mcp');
|
|
18
|
+
await startMcpServer({ baseUrl, token });
|
|
19
|
+
// MCP stdio servers run until the client closes stdin.
|
|
20
|
+
return new Promise(() => { });
|
|
21
|
+
}
|
|
22
|
+
export function registerMcpCommand(program, cwd) {
|
|
23
|
+
program
|
|
24
|
+
.command('mcp')
|
|
25
|
+
.description('Run the read-only MCP server over stdio')
|
|
26
|
+
.option('--collector <url>', 'collector URL (defaults to .stacknext/run.json)')
|
|
27
|
+
.option('--token <token>', 'collector bearer token (defaults to runtime state)')
|
|
28
|
+
.action(async (options) => {
|
|
29
|
+
await runMcp(options, cwd);
|
|
30
|
+
});
|
|
31
|
+
}
|
|
32
|
+
//# sourceMappingURL=mcp.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"mcp.js","sourceRoot":"","sources":["../../src/commands/mcp.ts"],"names":[],"mappings":"AACA,OAAO,EAAE,mBAAmB,EAAE,MAAM,eAAe,CAAA;AAOnD;;;GAGG;AACH,MAAM,CAAC,KAAK,UAAU,MAAM,CAC1B,OAAmB,EACnB,GAAG,GAAG,OAAO,CAAC,GAAG,EAAE;IAEnB,IAAI,OAAO,GAAG,OAAO,CAAC,SAAS,CAAA;IAC/B,IAAI,KAAK,GAAG,OAAO,CAAC,KAAK,CAAA;IACzB,IAAI,CAAC,OAAO,IAAI,CAAC,KAAK,EAAE,CAAC;QACvB,MAAM,KAAK,GAAG,MAAM,mBAAmB,CAAC,GAAG,CAAC,CAAA;QAC5C,OAAO,GAAG,OAAO,IAAI,KAAK,CAAC,YAAY,CAAA;QACvC,KAAK,GAAG,KAAK,IAAI,KAAK,CAAC,KAAK,CAAA;IAC9B,CAAC;IACD,IAAI,CAAC,KAAK,IAAI,KAAK,CAAC,MAAM,GAAG,EAAE,EAAE,CAAC;QAChC,MAAM,IAAI,KAAK,CAAC,yDAAyD,CAAC,CAAA;IAC5E,CAAC;IACD,MAAM,EAAE,cAAc,EAAE,GAAG,MAAM,MAAM,CAAC,gBAAgB,CAAC,CAAA;IACzD,MAAM,cAAc,CAAC,EAAE,OAAO,EAAE,KAAK,EAAE,CAAC,CAAA;IACxC,uDAAuD;IACvD,OAAO,IAAI,OAAO,CAAQ,GAAG,EAAE,GAAE,CAAC,CAAC,CAAA;AACrC,CAAC;AAED,MAAM,UAAU,kBAAkB,CAAC,OAAgB,EAAE,GAAW;IAC9D,OAAO;SACJ,OAAO,CAAC,KAAK,CAAC;SACd,WAAW,CAAC,yCAAyC,CAAC;SACtD,MAAM,CAAC,mBAAmB,EAAE,iDAAiD,CAAC;SAC9E,MAAM,CAAC,iBAAiB,EAAE,oDAAoD,CAAC;SAC/E,MAAM,CAAC,KAAK,EAAE,OAAmB,EAAE,EAAE;QACpC,MAAM,MAAM,CAAC,OAAO,EAAE,GAAG,CAAC,CAAA;IAC5B,CAAC,CAAC,CAAA;AACN,CAAC"}
|
|
@@ -0,0 +1,12 @@
|
|
|
1
|
+
import type { ConnectionInfo } from '@stacknext/core';
|
|
2
|
+
import type { Baseline, CapturedScenario, Comparison, EnvironmentSnapshot, RegressionStatus, TestRun } from '@stacknext/regression';
|
|
3
|
+
export declare function playwrightVersion(projectDir: string): Promise<string | undefined>;
|
|
4
|
+
export declare function latestConnection(connections: ConnectionInfo[]): ConnectionInfo | null;
|
|
5
|
+
export declare function statusMarker(status: RegressionStatus): string;
|
|
6
|
+
export declare function markerForRun(status: TestRun['status']): string;
|
|
7
|
+
export declare function environmentLines(environment: EnvironmentSnapshot): string[];
|
|
8
|
+
export declare function scenarioLines(scenario: CapturedScenario): string[];
|
|
9
|
+
export declare function runLines(run: TestRun, now?: number): string[];
|
|
10
|
+
export declare function baselineLines(baseline: Baseline, now?: number): string[];
|
|
11
|
+
export declare function comparisonLines(comparison: Comparison): string[];
|
|
12
|
+
//# sourceMappingURL=regression-shared.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"regression-shared.d.ts","sourceRoot":"","sources":["../../src/commands/regression-shared.ts"],"names":[],"mappings":"AAGA,OAAO,KAAK,EAAE,cAAc,EAAE,MAAM,iBAAiB,CAAA;AACrD,OAAO,KAAK,EACV,QAAQ,EACR,gBAAgB,EAChB,UAAU,EACV,mBAAmB,EACnB,gBAAgB,EAChB,OAAO,EACR,MAAM,uBAAuB,CAAA;AAG9B,wBAAsB,iBAAiB,CAAC,UAAU,EAAE,MAAM,GAAG,OAAO,CAAC,MAAM,GAAG,SAAS,CAAC,CAYvF;AAED,wBAAgB,gBAAgB,CAC9B,WAAW,EAAE,cAAc,EAAE,GAC5B,cAAc,GAAG,IAAI,CAEvB;AAED,wBAAgB,YAAY,CAAC,MAAM,EAAE,gBAAgB,GAAG,MAAM,CAW7D;AAED,wBAAgB,YAAY,CAAC,MAAM,EAAE,OAAO,CAAC,QAAQ,CAAC,GAAG,MAAM,CAY9D;AAED,wBAAgB,gBAAgB,CAAC,WAAW,EAAE,mBAAmB,GAAG,MAAM,EAAE,CAQ3E;AAED,wBAAgB,aAAa,CAAC,QAAQ,EAAE,gBAAgB,GAAG,MAAM,EAAE,CAgBlE;AAED,wBAAgB,QAAQ,CAAC,GAAG,EAAE,OAAO,EAAE,GAAG,SAAa,GAAG,MAAM,EAAE,CAwCjE;AAED,wBAAgB,aAAa,CAAC,QAAQ,EAAE,QAAQ,EAAE,GAAG,SAAa,GAAG,MAAM,EAAE,CAkB5E;AAED,wBAAgB,eAAe,CAAC,UAAU,EAAE,UAAU,GAAG,MAAM,EAAE,CA2DhE"}
|