Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
25 changes: 23 additions & 2 deletions eslint.config.mjs
Original file line number Diff line number Diff line change
Expand Up @@ -3,8 +3,29 @@
import eslint from '@eslint/js';
import { defineConfig } from 'eslint/config';
import tseslint from 'typescript-eslint';
import stylistic from '@stylistic/eslint-plugin';

export default defineConfig(
eslint.configs.recommended,
tseslint.configs.recommended,
eslint.configs.recommended,
tseslint.configs.recommended,
stylistic.configs.recommended,
{
rules: {
'@stylistic/brace-style': ['error', '1tbs'],
'@stylistic/member-delimiter-style': [
'error',
{
multiline: {
delimiter: 'semi',
requireLast: true,
},
singleline: {
delimiter: 'comma',
requireLast: false,
},
},
],
'@stylistic/semi': ['error', 'always'],
},
},
);
80 changes: 63 additions & 17 deletions package-lock.json

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

5 changes: 3 additions & 2 deletions package.json
Original file line number Diff line number Diff line change
Expand Up @@ -8,12 +8,13 @@
"start": "node dist/src/server.js",
"dev": "tsx watch src/server.ts",
"lint": "eslint 'src/**/*.ts'",
"format": "prettier --write 'src/**/*.ts'"
"format": "eslint 'src/**/*.ts' --fix"
},
"keywords": [],
"author": "",
"license": "ISC",
"dependencies": {
"@discoveryjs/json-ext": "^1.1.0",
"@prisma/adapter-better-sqlite3": "^7.10.0",
"@prisma/client": "^7.10.0",
"@types/escape-html": "^1.0.4",
Expand All @@ -25,12 +26,12 @@
},
"devDependencies": {
"@eslint/js": "^10.0.1",
"@stylistic/eslint-plugin": "^5.10.0",
"@types/better-sqlite3": "^7.6.13",
"@types/cors": "^2.8.19",
"@types/express": "^5.0.6",
"@types/node": "^26.1.2",
"eslint": "^10.8.0",
"prettier": "^3.9.6",
"prisma": "^7.9.1",
"tsx": "^4.22.4",
"typescript": "^5.9.3",
Expand Down
81 changes: 43 additions & 38 deletions src/aggregateDaily.ts
Original file line number Diff line number Diff line change
@@ -1,46 +1,53 @@
import {aggregateSpeedscopeData} from "./repositories/profileRepository.js";
import {AggregatedProfileType} from "../generated/prisma/enums.js";
import {gzipSync} from "node:zlib";
import {prisma} from "./prisma.js";
import {AggregatedProfile} from "../generated/prisma/client.js";
import config from "./config/config.js";
import {
aggregateSpeedscopeData,
FrameTimings,
} from './repositories/profileRepository.js';
import { AggregatedProfileType } from '../generated/prisma/enums.js';
import { prisma } from './prisma.js';
import { AggregatedProfile } from '../generated/prisma/client.js';
import config from './config/config.js';
import { jsonifyAndCompressFrameTimings, jsonifyAndCompressProfile } from './utils/jsonHelper.js';
import { SpeedscopeFile } from './models/speedscope';

const end = new Date();
const start = new Date(end.getTime() - (24 * 60 * 60 * 1000)); // 1 day ago

const aggregatedProfiles: AggregatedProfile[] = await prisma.aggregatedProfile.findMany({
where: {
startTime: {
gte: start,
const aggregateData = async (start: Date, end: Date) => {
const aggregatedProfiles: AggregatedProfile[] = await prisma.aggregatedProfile.findMany({
where: {
startTime: {
gte: start,
},
type: AggregatedProfileType.HOURLY,
},
type: AggregatedProfileType.HOURLY,
},
orderBy: {
startTime: 'asc',
},
});
orderBy: {
startTime: 'asc',
},
});

if (!aggregatedProfiles || aggregatedProfiles.length === 0) {
console.log('No profiles found in the last day.');
process.exit(0);
}
if (!aggregatedProfiles || aggregatedProfiles.length === 0) {
console.log('No profiles found in the last day.');
process.exit(0);
}

const aggregatedData = aggregateSpeedscopeData(
const aggregatedData = aggregateSpeedscopeData(
aggregatedProfiles,
`Daily aggregation (${start.toISOString()} to ${end.toISOString()})`
);
`Daily aggregation (${start.toISOString()} to ${end.toISOString()})`,
);

console.log('Converting data to JSON...');
const profileCount = aggregatedProfiles
.map(p => p.profileCount)
.reduce((a, b) => a + b, 0);

const profileJson = JSON.stringify(aggregatedData.file);
delete aggregatedData.file;
return { aggregatedData: aggregatedData, profileCount: profileCount };
};

const frameTimingJson = JSON.stringify(aggregatedData.frameTimings, (k, v) => {
if (v instanceof Map) {
return Array.from(v.entries());
}
return v;
});
const { aggregatedData, profileCount } = await aggregateData(start, end);
console.log('Compressing profile...');
const compressedProfile = await jsonifyAndCompressProfile(aggregatedData.file as SpeedscopeFile);
delete aggregatedData.file;
console.log('Compressing frame timings...');
const compressedFrameTimings = await jsonifyAndCompressFrameTimings(aggregatedData.frameTimings as FrameTimings);
delete aggregatedData.frameTimings;

console.log('Writing data to DB...');
Expand All @@ -50,12 +57,10 @@ await prisma.aggregatedProfile.create({
startTime: start,
endTime: end,
type: AggregatedProfileType.DAILY,
profileCount: aggregatedProfiles
.map((p) => p.profileCount)
.reduce((a, b) => a + b, 0),
speedscopeData: gzipSync(profileJson),
frameTimingData: gzipSync(frameTimingJson),
}
profileCount: profileCount,
speedscopeData: compressedProfile,
frameTimingData: compressedFrameTimings,
},
});

if (config.purgeHourlyAggregations) {
Expand Down
16 changes: 8 additions & 8 deletions src/aggregateHourly.ts
Original file line number Diff line number Diff line change
@@ -1,8 +1,8 @@
import {aggregateSpeedscopeData} from './repositories/profileRepository.js';
import {prisma} from "./prisma.js";
import {gzipSync} from "node:zlib";
import {AggregatedProfileType, Profile} from "../generated/prisma/client.js";
import config from "./config/config.js";
import { aggregateSpeedscopeData } from './repositories/profileRepository.js';
import { prisma } from './prisma.js';
import { gzipSync } from 'node:zlib';
import { AggregatedProfileType, Profile } from '../generated/prisma/client.js';
import config from './config/config.js';

const end = new Date();
const start = new Date(end.getTime() - (60 * 60 * 1000)); // 1 hour ago
Expand All @@ -24,8 +24,8 @@ if (profiles.length === 0) {
process.exit(0);
}
const aggregatedData = aggregateSpeedscopeData(
profiles,
`Hourly aggregation (${start.toISOString()} to ${end.toISOString()})`
profiles,
`Hourly aggregation (${start.toISOString()} to ${end.toISOString()})`,
);
await prisma.aggregatedProfile.create({
data: {
Expand All @@ -40,7 +40,7 @@ await prisma.aggregatedProfile.create({
}
return v;
})),
}
},
});

if (config.purgeProfiles) {
Expand Down
4 changes: 2 additions & 2 deletions src/app.ts
Original file line number Diff line number Diff line change
@@ -1,8 +1,8 @@
import express from 'express';
import routes from './routes/routes.js';
import { errorHandler } from './middlewares/errorHandler.js';
import path from "node:path";
import {fileURLToPath} from "node:url";
import path from 'node:path';
import { fileURLToPath } from 'node:url';

const app = express();

Expand Down
Loading