@stati/core 1.16.2 → 1.17.0
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/dist/core/build.d.ts +41 -12
- package/dist/core/build.d.ts.map +1 -1
- package/dist/core/build.js +92 -11
- package/dist/core/dev.js +3 -3
- package/dist/core/index.d.ts +1 -1
- package/dist/core/index.d.ts.map +1 -1
- package/dist/core/isg/ttl.js +1 -1
- package/dist/core/templates.d.ts +10 -1
- package/dist/core/templates.d.ts.map +1 -1
- package/dist/core/templates.js +11 -14
- package/dist/core/utils/glob-patterns.utils.d.ts.map +1 -1
- package/dist/core/utils/glob-patterns.utils.js +1 -6
- package/dist/index.d.ts +3 -1
- package/dist/index.d.ts.map +1 -1
- package/dist/index.js +1 -0
- package/dist/metrics/index.d.ts +38 -0
- package/dist/metrics/index.d.ts.map +1 -0
- package/dist/metrics/index.js +42 -0
- package/dist/metrics/noop.d.ts +12 -0
- package/dist/metrics/noop.d.ts.map +1 -0
- package/dist/metrics/noop.js +88 -0
- package/dist/metrics/recorder.d.ts +31 -0
- package/dist/metrics/recorder.d.ts.map +1 -0
- package/dist/metrics/recorder.js +176 -0
- package/dist/metrics/types.d.ts +236 -0
- package/dist/metrics/types.d.ts.map +1 -0
- package/dist/metrics/types.js +7 -0
- package/dist/metrics/utils/index.d.ts +9 -0
- package/dist/metrics/utils/index.d.ts.map +1 -0
- package/dist/metrics/utils/index.js +9 -0
- package/dist/metrics/utils/system.utils.d.ts +44 -0
- package/dist/metrics/utils/system.utils.d.ts.map +1 -0
- package/dist/metrics/utils/system.utils.js +95 -0
- package/dist/metrics/utils/writer.utils.d.ts +64 -0
- package/dist/metrics/utils/writer.utils.d.ts.map +1 -0
- package/dist/metrics/utils/writer.utils.js +145 -0
- package/package.json +1 -1
|
@@ -0,0 +1,95 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* System information utilities for metrics collection.
|
|
3
|
+
* Uses only Node.js built-ins to avoid external dependencies.
|
|
4
|
+
*/
|
|
5
|
+
import { execSync } from 'node:child_process';
|
|
6
|
+
import { cpus, platform, arch } from 'node:os';
|
|
7
|
+
/**
|
|
8
|
+
* CI environment detection environment variables.
|
|
9
|
+
*/
|
|
10
|
+
const CI_ENV_VARS = [
|
|
11
|
+
'CI',
|
|
12
|
+
'GITHUB_ACTIONS',
|
|
13
|
+
'GITLAB_CI',
|
|
14
|
+
'CIRCLECI',
|
|
15
|
+
'TRAVIS',
|
|
16
|
+
'JENKINS_URL',
|
|
17
|
+
'BUILDKITE',
|
|
18
|
+
'AZURE_PIPELINES',
|
|
19
|
+
'TF_BUILD',
|
|
20
|
+
];
|
|
21
|
+
/**
|
|
22
|
+
* Detect if running in a CI environment.
|
|
23
|
+
*/
|
|
24
|
+
export function isCI() {
|
|
25
|
+
return CI_ENV_VARS.some((envVar) => process.env[envVar] !== undefined);
|
|
26
|
+
}
|
|
27
|
+
/**
|
|
28
|
+
* Get the current Git commit SHA.
|
|
29
|
+
* Returns undefined if not in a git repository or git is not available.
|
|
30
|
+
*/
|
|
31
|
+
export function getGitCommit() {
|
|
32
|
+
try {
|
|
33
|
+
const result = execSync('git rev-parse HEAD', {
|
|
34
|
+
encoding: 'utf-8',
|
|
35
|
+
stdio: ['pipe', 'pipe', 'pipe'],
|
|
36
|
+
timeout: 5000,
|
|
37
|
+
});
|
|
38
|
+
return result.trim() || undefined;
|
|
39
|
+
}
|
|
40
|
+
catch {
|
|
41
|
+
return undefined;
|
|
42
|
+
}
|
|
43
|
+
}
|
|
44
|
+
/**
|
|
45
|
+
* Get the current Git branch name.
|
|
46
|
+
* Returns undefined if not in a git repository or git is not available.
|
|
47
|
+
*/
|
|
48
|
+
export function getGitBranch() {
|
|
49
|
+
try {
|
|
50
|
+
const result = execSync('git rev-parse --abbrev-ref HEAD', {
|
|
51
|
+
encoding: 'utf-8',
|
|
52
|
+
stdio: ['pipe', 'pipe', 'pipe'],
|
|
53
|
+
timeout: 5000,
|
|
54
|
+
});
|
|
55
|
+
return result.trim() || undefined;
|
|
56
|
+
}
|
|
57
|
+
catch {
|
|
58
|
+
return undefined;
|
|
59
|
+
}
|
|
60
|
+
}
|
|
61
|
+
/**
|
|
62
|
+
* Get the number of CPU cores.
|
|
63
|
+
*/
|
|
64
|
+
export function getCpuCount() {
|
|
65
|
+
return cpus().length;
|
|
66
|
+
}
|
|
67
|
+
/**
|
|
68
|
+
* Get the current platform.
|
|
69
|
+
*/
|
|
70
|
+
export function getPlatform() {
|
|
71
|
+
return platform();
|
|
72
|
+
}
|
|
73
|
+
/**
|
|
74
|
+
* Get the CPU architecture.
|
|
75
|
+
*/
|
|
76
|
+
export function getArch() {
|
|
77
|
+
return arch();
|
|
78
|
+
}
|
|
79
|
+
/**
|
|
80
|
+
* Get Node.js version string (without the 'v' prefix).
|
|
81
|
+
*/
|
|
82
|
+
export function getNodeVersion() {
|
|
83
|
+
return process.version.replace(/^v/, '');
|
|
84
|
+
}
|
|
85
|
+
/**
|
|
86
|
+
* Get current memory usage snapshot.
|
|
87
|
+
*/
|
|
88
|
+
export function getMemoryUsage() {
|
|
89
|
+
const usage = process.memoryUsage();
|
|
90
|
+
return {
|
|
91
|
+
rss: usage.rss,
|
|
92
|
+
heapUsed: usage.heapUsed,
|
|
93
|
+
heapTotal: usage.heapTotal,
|
|
94
|
+
};
|
|
95
|
+
}
|
|
@@ -0,0 +1,64 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Metrics file writing utilities.
|
|
3
|
+
* Handles graceful degradation - never blocks builds on write failures.
|
|
4
|
+
*/
|
|
5
|
+
import type { BuildMetrics } from '../types.js';
|
|
6
|
+
/**
|
|
7
|
+
* Default metrics output directory (relative to cache dir).
|
|
8
|
+
*/
|
|
9
|
+
export declare const DEFAULT_METRICS_DIR = "metrics";
|
|
10
|
+
/**
|
|
11
|
+
* Generate a timestamped filename for metrics output.
|
|
12
|
+
*
|
|
13
|
+
* @param command - The command that was run (build, dev)
|
|
14
|
+
* @param timestamp - ISO timestamp
|
|
15
|
+
* @returns Filename like "build-2024-01-15T10-30-00.json"
|
|
16
|
+
*/
|
|
17
|
+
export declare function generateMetricsFilename(command: string, timestamp: string): string;
|
|
18
|
+
/**
|
|
19
|
+
* Options for writing metrics.
|
|
20
|
+
*/
|
|
21
|
+
export interface WriteMetricsOptions {
|
|
22
|
+
/** Base cache directory (e.g., .stati) */
|
|
23
|
+
cacheDir: string;
|
|
24
|
+
/** Custom output path (overrides default) */
|
|
25
|
+
outputPath?: string | undefined;
|
|
26
|
+
/** Format: json (default) or ndjson */
|
|
27
|
+
format?: 'json' | 'ndjson' | undefined;
|
|
28
|
+
}
|
|
29
|
+
/**
|
|
30
|
+
* Result of metrics write operation.
|
|
31
|
+
*/
|
|
32
|
+
export interface WriteMetricsResult {
|
|
33
|
+
success: boolean;
|
|
34
|
+
path?: string;
|
|
35
|
+
error?: string;
|
|
36
|
+
}
|
|
37
|
+
/**
|
|
38
|
+
* Write build metrics to a JSON file.
|
|
39
|
+
* Degrades gracefully on failure - logs warning but doesn't throw.
|
|
40
|
+
*
|
|
41
|
+
* @param metrics - The metrics to write
|
|
42
|
+
* @param options - Write options
|
|
43
|
+
* @returns Result indicating success/failure and path
|
|
44
|
+
*
|
|
45
|
+
* @example
|
|
46
|
+
* ```typescript
|
|
47
|
+
* const result = await writeMetrics(metrics, {
|
|
48
|
+
* cacheDir: '.stati',
|
|
49
|
+
* });
|
|
50
|
+
*
|
|
51
|
+
* if (result.success) {
|
|
52
|
+
* console.log(`Metrics written to ${result.path}`);
|
|
53
|
+
* }
|
|
54
|
+
* ```
|
|
55
|
+
*/
|
|
56
|
+
export declare function writeMetrics(metrics: BuildMetrics, options: WriteMetricsOptions): Promise<WriteMetricsResult>;
|
|
57
|
+
/**
|
|
58
|
+
* Format metrics for CLI summary output.
|
|
59
|
+
*
|
|
60
|
+
* @param metrics - Build metrics to format
|
|
61
|
+
* @returns Array of formatted lines for CLI output
|
|
62
|
+
*/
|
|
63
|
+
export declare function formatMetricsSummary(metrics: BuildMetrics): string[];
|
|
64
|
+
//# sourceMappingURL=writer.utils.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"writer.utils.d.ts","sourceRoot":"","sources":["../../../src/metrics/utils/writer.utils.ts"],"names":[],"mappings":"AAAA;;;GAGG;AAIH,OAAO,KAAK,EAAE,YAAY,EAAE,MAAM,aAAa,CAAC;AAEhD;;GAEG;AACH,eAAO,MAAM,mBAAmB,YAAY,CAAC;AAuB7C;;;;;;GAMG;AACH,wBAAgB,uBAAuB,CAAC,OAAO,EAAE,MAAM,EAAE,SAAS,EAAE,MAAM,GAAG,MAAM,CAIlF;AAED;;GAEG;AACH,MAAM,WAAW,mBAAmB;IAClC,0CAA0C;IAC1C,QAAQ,EAAE,MAAM,CAAC;IACjB,6CAA6C;IAC7C,UAAU,CAAC,EAAE,MAAM,GAAG,SAAS,CAAC;IAChC,uCAAuC;IACvC,MAAM,CAAC,EAAE,MAAM,GAAG,QAAQ,GAAG,SAAS,CAAC;CACxC;AAED;;GAEG;AACH,MAAM,WAAW,kBAAkB;IACjC,OAAO,EAAE,OAAO,CAAC;IACjB,IAAI,CAAC,EAAE,MAAM,CAAC;IACd,KAAK,CAAC,EAAE,MAAM,CAAC;CAChB;AAED;;;;;;;;;;;;;;;;;;GAkBG;AACH,wBAAsB,YAAY,CAChC,OAAO,EAAE,YAAY,EACrB,OAAO,EAAE,mBAAmB,GAC3B,OAAO,CAAC,kBAAkB,CAAC,CA2C7B;AAED;;;;;GAKG;AACH,wBAAgB,oBAAoB,CAAC,OAAO,EAAE,YAAY,GAAG,MAAM,EAAE,CA6CpE"}
|
|
@@ -0,0 +1,145 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Metrics file writing utilities.
|
|
3
|
+
* Handles graceful degradation - never blocks builds on write failures.
|
|
4
|
+
*/
|
|
5
|
+
import { writeFile, mkdir } from 'node:fs/promises';
|
|
6
|
+
import { join, dirname } from 'node:path';
|
|
7
|
+
/**
|
|
8
|
+
* Default metrics output directory (relative to cache dir).
|
|
9
|
+
*/
|
|
10
|
+
export const DEFAULT_METRICS_DIR = 'metrics';
|
|
11
|
+
/**
|
|
12
|
+
* Display names for build phases.
|
|
13
|
+
* Maps raw phase keys (e.g., 'configLoadMs') to human-readable labels.
|
|
14
|
+
*/
|
|
15
|
+
const PHASE_DISPLAY_NAMES = {
|
|
16
|
+
configLoadMs: 'Config Load',
|
|
17
|
+
contentDiscoveryMs: 'Content Discovery',
|
|
18
|
+
navigationBuildMs: 'Navigation Build',
|
|
19
|
+
cacheManifestLoadMs: 'Cache Manifest Load',
|
|
20
|
+
typescriptCompileMs: 'TypeScript Compile',
|
|
21
|
+
pageRenderingMs: 'Page Rendering',
|
|
22
|
+
assetCopyMs: 'Asset Copy',
|
|
23
|
+
cacheManifestSaveMs: 'Cache Manifest Save',
|
|
24
|
+
sitemapGenerationMs: 'Sitemap Generation',
|
|
25
|
+
rssGenerationMs: 'RSS Generation',
|
|
26
|
+
hookBeforeAllMs: 'Hook: Before All',
|
|
27
|
+
hookAfterAllMs: 'Hook: After All',
|
|
28
|
+
hookBeforeRenderTotalMs: 'Hook: Before Render (Total)',
|
|
29
|
+
hookAfterRenderTotalMs: 'Hook: After Render (Total)',
|
|
30
|
+
};
|
|
31
|
+
/**
|
|
32
|
+
* Generate a timestamped filename for metrics output.
|
|
33
|
+
*
|
|
34
|
+
* @param command - The command that was run (build, dev)
|
|
35
|
+
* @param timestamp - ISO timestamp
|
|
36
|
+
* @returns Filename like "build-2024-01-15T10-30-00.json"
|
|
37
|
+
*/
|
|
38
|
+
export function generateMetricsFilename(command, timestamp) {
|
|
39
|
+
// Replace colons with dashes for Windows compatibility
|
|
40
|
+
const safeTimestamp = timestamp.replace(/:/g, '-').replace(/\.\d+Z$/, 'Z');
|
|
41
|
+
return `${command}-${safeTimestamp}.json`;
|
|
42
|
+
}
|
|
43
|
+
/**
|
|
44
|
+
* Write build metrics to a JSON file.
|
|
45
|
+
* Degrades gracefully on failure - logs warning but doesn't throw.
|
|
46
|
+
*
|
|
47
|
+
* @param metrics - The metrics to write
|
|
48
|
+
* @param options - Write options
|
|
49
|
+
* @returns Result indicating success/failure and path
|
|
50
|
+
*
|
|
51
|
+
* @example
|
|
52
|
+
* ```typescript
|
|
53
|
+
* const result = await writeMetrics(metrics, {
|
|
54
|
+
* cacheDir: '.stati',
|
|
55
|
+
* });
|
|
56
|
+
*
|
|
57
|
+
* if (result.success) {
|
|
58
|
+
* console.log(`Metrics written to ${result.path}`);
|
|
59
|
+
* }
|
|
60
|
+
* ```
|
|
61
|
+
*/
|
|
62
|
+
export async function writeMetrics(metrics, options) {
|
|
63
|
+
try {
|
|
64
|
+
// Determine output path
|
|
65
|
+
let outputPath;
|
|
66
|
+
if (options.outputPath) {
|
|
67
|
+
outputPath = options.outputPath;
|
|
68
|
+
}
|
|
69
|
+
else {
|
|
70
|
+
const metricsDir = join(options.cacheDir, DEFAULT_METRICS_DIR);
|
|
71
|
+
const filename = generateMetricsFilename(metrics.meta.command, metrics.meta.timestamp);
|
|
72
|
+
outputPath = join(metricsDir, filename);
|
|
73
|
+
}
|
|
74
|
+
// Ensure directory exists
|
|
75
|
+
await mkdir(dirname(outputPath), { recursive: true });
|
|
76
|
+
// Format content
|
|
77
|
+
const format = options.format ?? 'json';
|
|
78
|
+
let content;
|
|
79
|
+
if (format === 'ndjson') {
|
|
80
|
+
// NDJSON: one JSON object per line, no pretty printing
|
|
81
|
+
content = JSON.stringify(metrics) + '\n';
|
|
82
|
+
}
|
|
83
|
+
else {
|
|
84
|
+
// JSON: pretty printed for readability
|
|
85
|
+
content = JSON.stringify(metrics, null, 2) + '\n';
|
|
86
|
+
}
|
|
87
|
+
// Write file
|
|
88
|
+
await writeFile(outputPath, content, 'utf-8');
|
|
89
|
+
return {
|
|
90
|
+
success: true,
|
|
91
|
+
path: outputPath,
|
|
92
|
+
};
|
|
93
|
+
}
|
|
94
|
+
catch (error) {
|
|
95
|
+
// Graceful degradation - don't throw, just report failure
|
|
96
|
+
const errorMessage = error instanceof Error ? error.message : String(error);
|
|
97
|
+
return {
|
|
98
|
+
success: false,
|
|
99
|
+
error: `Failed to write metrics: ${errorMessage}`,
|
|
100
|
+
};
|
|
101
|
+
}
|
|
102
|
+
}
|
|
103
|
+
/**
|
|
104
|
+
* Format metrics for CLI summary output.
|
|
105
|
+
*
|
|
106
|
+
* @param metrics - Build metrics to format
|
|
107
|
+
* @returns Array of formatted lines for CLI output
|
|
108
|
+
*/
|
|
109
|
+
export function formatMetricsSummary(metrics) {
|
|
110
|
+
const lines = [];
|
|
111
|
+
// Header
|
|
112
|
+
lines.push('');
|
|
113
|
+
lines.push('Build Metrics Summary');
|
|
114
|
+
lines.push('─'.repeat(40));
|
|
115
|
+
// Total duration
|
|
116
|
+
const totalSeconds = (metrics.totals.durationMs / 1000).toFixed(2);
|
|
117
|
+
lines.push(`Total build time: ${totalSeconds}s`);
|
|
118
|
+
// Page stats
|
|
119
|
+
const { totalPages, renderedPages, cachedPages } = metrics.counts;
|
|
120
|
+
lines.push(`Pages: ${totalPages} total, ${renderedPages} rendered, ${cachedPages} cached`);
|
|
121
|
+
// Cache hit rate
|
|
122
|
+
const hitRate = (metrics.isg.cacheHitRate * 100).toFixed(1);
|
|
123
|
+
lines.push(`Cache hit rate: ${hitRate}%`);
|
|
124
|
+
// Memory
|
|
125
|
+
const peakMB = (metrics.totals.peakRssBytes / 1024 / 1024).toFixed(1);
|
|
126
|
+
lines.push(`Peak memory: ${peakMB} MB`);
|
|
127
|
+
// Top phases (sorted by duration, top 3)
|
|
128
|
+
const phases = Object.entries(metrics.phases)
|
|
129
|
+
.filter(([, duration]) => duration !== undefined && duration > 0)
|
|
130
|
+
.map(([name, duration]) => ({ name, duration: duration }))
|
|
131
|
+
.sort((a, b) => b.duration - a.duration)
|
|
132
|
+
.slice(0, 3);
|
|
133
|
+
if (phases.length > 0) {
|
|
134
|
+
lines.push('');
|
|
135
|
+
lines.push('Top phases:');
|
|
136
|
+
for (const phase of phases) {
|
|
137
|
+
// Use mapped display name if available, otherwise fall back to raw name
|
|
138
|
+
const phaseName = PHASE_DISPLAY_NAMES[phase.name] || phase.name;
|
|
139
|
+
const phaseMs = phase.duration.toFixed(0);
|
|
140
|
+
lines.push(` ${phaseName}: ${phaseMs}ms`);
|
|
141
|
+
}
|
|
142
|
+
}
|
|
143
|
+
lines.push('─'.repeat(40));
|
|
144
|
+
return lines;
|
|
145
|
+
}
|