@axiapps/bridge-metrics 0.1.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/aggregationTypes.cjs +18 -0
- package/dist/aggregationTypes.d.cts +21 -0
- package/dist/aggregationTypes.d.ts +21 -0
- package/dist/aggregationTypes.js +1 -0
- package/dist/boonGeneration.cjs +308 -0
- package/dist/boonGeneration.d.cts +65 -0
- package/dist/boonGeneration.d.ts +65 -0
- package/dist/boonGeneration.js +16 -0
- package/dist/chunk-42DVJJLC.js +106 -0
- package/dist/chunk-4F55Q6K2.js +0 -0
- package/dist/chunk-ELKDB763.js +349 -0
- package/dist/chunk-FU74LJEM.js +77 -0
- package/dist/chunk-J3YCFY3C.js +37 -0
- package/dist/chunk-JP2ZL44R.js +18 -0
- package/dist/chunk-K2SRAMGC.js +0 -0
- package/dist/chunk-KRHODGVU.js +48 -0
- package/dist/chunk-LIGIXSSA.js +1383 -0
- package/dist/chunk-M2WR3JBQ.js +0 -0
- package/dist/chunk-PMVLNDZZ.js +279 -0
- package/dist/chunk-R5EJF5AW.js +147 -0
- package/dist/chunk-RGXSI3AI.js +298 -0
- package/dist/chunk-UFJJ6WLD.js +197 -0
- package/dist/chunk-WW5XFXGC.js +234 -0
- package/dist/chunk-ZFZS7JFU.js +10 -0
- package/dist/combatMetrics.cjs +251 -0
- package/dist/combatMetrics.d.cts +26 -0
- package/dist/combatMetrics.d.ts +26 -0
- package/dist/combatMetrics.js +21 -0
- package/dist/computePlayerAggregation.cjs +2042 -0
- package/dist/computePlayerAggregation.d.cts +249 -0
- package/dist/computePlayerAggregation.d.ts +249 -0
- package/dist/computePlayerAggregation.js +30 -0
- package/dist/conditionsMetrics.cjs +328 -0
- package/dist/conditionsMetrics.d.cts +67 -0
- package/dist/conditionsMetrics.d.ts +67 -0
- package/dist/conditionsMetrics.js +18 -0
- package/dist/constants.cjs +36 -0
- package/dist/constants.d.cts +18 -0
- package/dist/constants.d.ts +18 -0
- package/dist/constants.js +10 -0
- package/dist/dashboardMetrics.cjs +226 -0
- package/dist/dashboardMetrics.d.cts +29 -0
- package/dist/dashboardMetrics.d.ts +29 -0
- package/dist/dashboardMetrics.js +42 -0
- package/dist/dpsReportTypes.cjs +18 -0
- package/dist/dpsReportTypes.d.cts +294 -0
- package/dist/dpsReportTypes.d.ts +294 -0
- package/dist/dpsReportTypes.js +1 -0
- package/dist/index.cjs +2902 -0
- package/dist/index.d.cts +13 -0
- package/dist/index.d.ts +13 -0
- package/dist/index.js +152 -0
- package/dist/metrics-methods.json +38 -0
- package/dist/metricsSettings.cjs +75 -0
- package/dist/metricsSettings.d.cts +23 -0
- package/dist/metricsSettings.d.ts +23 -0
- package/dist/metricsSettings.js +8 -0
- package/dist/professionUtils.cjs +265 -0
- package/dist/professionUtils.d.cts +10 -0
- package/dist/professionUtils.d.ts +10 -0
- package/dist/professionUtils.js +20 -0
- package/dist/reportMetrics.cjs +224 -0
- package/dist/reportMetrics.d.cts +85 -0
- package/dist/reportMetrics.d.ts +85 -0
- package/dist/reportMetrics.js +12 -0
- package/dist/resUtility.cjs +52 -0
- package/dist/resUtility.d.cts +5 -0
- package/dist/resUtility.d.ts +5 -0
- package/dist/resUtility.js +8 -0
- package/dist/roles.cjs +18 -0
- package/dist/roles.d.cts +17 -0
- package/dist/roles.d.ts +17 -0
- package/dist/roles.js +1 -0
- package/dist/rollup.cjs +378 -0
- package/dist/rollup.d.cts +103 -0
- package/dist/rollup.d.ts +103 -0
- package/dist/rollup.js +16 -0
- package/dist/statsMetrics.cjs +153 -0
- package/dist/statsMetrics.d.cts +39 -0
- package/dist/statsMetrics.d.ts +39 -0
- package/dist/statsMetrics.js +22 -0
- package/dist/timestampUtils.cjs +63 -0
- package/dist/timestampUtils.d.cts +12 -0
- package/dist/timestampUtils.d.ts +12 -0
- package/dist/timestampUtils.js +9 -0
- package/package.json +44 -0
package/dist/rollup.cjs
ADDED
|
@@ -0,0 +1,378 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
var __defProp = Object.defineProperty;
|
|
3
|
+
var __getOwnPropDesc = Object.getOwnPropertyDescriptor;
|
|
4
|
+
var __getOwnPropNames = Object.getOwnPropertyNames;
|
|
5
|
+
var __hasOwnProp = Object.prototype.hasOwnProperty;
|
|
6
|
+
var __export = (target, all) => {
|
|
7
|
+
for (var name in all)
|
|
8
|
+
__defProp(target, name, { get: all[name], enumerable: true });
|
|
9
|
+
};
|
|
10
|
+
var __copyProps = (to, from, except, desc) => {
|
|
11
|
+
if (from && typeof from === "object" || typeof from === "function") {
|
|
12
|
+
for (let key of __getOwnPropNames(from))
|
|
13
|
+
if (!__hasOwnProp.call(to, key) && key !== except)
|
|
14
|
+
__defProp(to, key, { get: () => from[key], enumerable: !(desc = __getOwnPropDesc(from, key)) || desc.enumerable });
|
|
15
|
+
}
|
|
16
|
+
return to;
|
|
17
|
+
};
|
|
18
|
+
var __toCommonJS = (mod) => __copyProps(__defProp({}, "__esModule", { value: true }), mod);
|
|
19
|
+
|
|
20
|
+
// src/rollup.ts
|
|
21
|
+
var rollup_exports = {};
|
|
22
|
+
__export(rollup_exports, {
|
|
23
|
+
ROLLUP_SOURCES_VERSION: () => ROLLUP_SOURCES_VERSION,
|
|
24
|
+
buildRollupData: () => buildRollupData,
|
|
25
|
+
extractRollupSource: () => extractRollupSource,
|
|
26
|
+
parseRollupSourcesFile: () => parseRollupSourcesFile,
|
|
27
|
+
removeRollupSources: () => removeRollupSources,
|
|
28
|
+
updateRollupSourcesForPublish: () => updateRollupSourcesForPublish
|
|
29
|
+
});
|
|
30
|
+
module.exports = __toCommonJS(rollup_exports);
|
|
31
|
+
var ROLLUP_SOURCES_VERSION = 1;
|
|
32
|
+
var extractRollupSource = (payload) => {
|
|
33
|
+
const meta = payload?.meta || {};
|
|
34
|
+
const commanderRows = Array.isArray(payload?.stats?.commanderStats?.rows) ? payload.stats.commanderStats.rows : [];
|
|
35
|
+
const attendanceRows = Array.isArray(payload?.stats?.attendanceData) ? payload.stats.attendanceData : [];
|
|
36
|
+
return {
|
|
37
|
+
meta: {
|
|
38
|
+
id: meta.id,
|
|
39
|
+
dateStart: meta.dateStart,
|
|
40
|
+
dateEnd: meta.dateEnd,
|
|
41
|
+
generatedAt: meta.generatedAt
|
|
42
|
+
},
|
|
43
|
+
stats: {
|
|
44
|
+
commanderStats: {
|
|
45
|
+
rows: commanderRows.map((row) => ({
|
|
46
|
+
key: row?.key,
|
|
47
|
+
account: row?.account,
|
|
48
|
+
characterNames: Array.isArray(row?.characterNames) ? row.characterNames : [],
|
|
49
|
+
profession: row?.profession,
|
|
50
|
+
fights: row?.fights,
|
|
51
|
+
kills: row?.kills,
|
|
52
|
+
downs: row?.downs,
|
|
53
|
+
commanderDeaths: row?.commanderDeaths,
|
|
54
|
+
alliesDead: row?.alliesDead,
|
|
55
|
+
wins: row?.wins,
|
|
56
|
+
losses: row?.losses
|
|
57
|
+
}))
|
|
58
|
+
},
|
|
59
|
+
attendanceData: attendanceRows.map((row) => ({
|
|
60
|
+
account: row?.account,
|
|
61
|
+
characterNames: Array.isArray(row?.characterNames) ? row.characterNames : [],
|
|
62
|
+
combatTimeMs: row?.combatTimeMs,
|
|
63
|
+
squadTimeMs: row?.squadTimeMs,
|
|
64
|
+
classTimes: (Array.isArray(row?.classTimes) ? row.classTimes : []).map((entry) => ({
|
|
65
|
+
profession: entry?.profession,
|
|
66
|
+
timeMs: entry?.timeMs
|
|
67
|
+
}))
|
|
68
|
+
}))
|
|
69
|
+
}
|
|
70
|
+
};
|
|
71
|
+
};
|
|
72
|
+
var updateRollupSourcesForPublish = (options) => {
|
|
73
|
+
const { existingSources, currentReport, validIds, loadLocalReport } = options;
|
|
74
|
+
const sourcesById = /* @__PURE__ */ new Map();
|
|
75
|
+
existingSources.forEach((source) => {
|
|
76
|
+
const id = String(source?.meta?.id || "").trim();
|
|
77
|
+
if (id) sourcesById.set(id, source);
|
|
78
|
+
});
|
|
79
|
+
const currentId = String(currentReport?.meta?.id || "").trim();
|
|
80
|
+
if (currentId) {
|
|
81
|
+
sourcesById.set(currentId, extractRollupSource(currentReport));
|
|
82
|
+
}
|
|
83
|
+
const validIdSet = new Set(validIds.map((id) => String(id || "").trim()).filter(Boolean));
|
|
84
|
+
if (loadLocalReport) {
|
|
85
|
+
for (const id of validIdSet) {
|
|
86
|
+
if (sourcesById.has(id)) continue;
|
|
87
|
+
const localReport = loadLocalReport(id);
|
|
88
|
+
if (localReport) {
|
|
89
|
+
sourcesById.set(id, extractRollupSource(localReport));
|
|
90
|
+
}
|
|
91
|
+
}
|
|
92
|
+
}
|
|
93
|
+
const sources = Array.from(sourcesById.entries()).filter(([id]) => validIdSet.has(id)).map(([, source]) => source);
|
|
94
|
+
return {
|
|
95
|
+
version: ROLLUP_SOURCES_VERSION,
|
|
96
|
+
sources,
|
|
97
|
+
rollup: buildRollupData(sources)
|
|
98
|
+
};
|
|
99
|
+
};
|
|
100
|
+
var removeRollupSources = (file, deletedIds) => {
|
|
101
|
+
const deleted = new Set(deletedIds.map((id) => String(id || "").trim()).filter(Boolean));
|
|
102
|
+
const sources = file.sources.filter(
|
|
103
|
+
(source) => !deleted.has(String(source?.meta?.id || "").trim())
|
|
104
|
+
);
|
|
105
|
+
return {
|
|
106
|
+
version: ROLLUP_SOURCES_VERSION,
|
|
107
|
+
sources,
|
|
108
|
+
rollup: buildRollupData(sources)
|
|
109
|
+
};
|
|
110
|
+
};
|
|
111
|
+
var parseRollupSourcesFile = (data) => {
|
|
112
|
+
const candidate = data;
|
|
113
|
+
if (!candidate || typeof candidate !== "object") return null;
|
|
114
|
+
if (candidate.version !== ROLLUP_SOURCES_VERSION) return null;
|
|
115
|
+
if (!Array.isArray(candidate.sources)) return null;
|
|
116
|
+
if (!candidate.rollup || typeof candidate.rollup !== "object") return null;
|
|
117
|
+
return candidate;
|
|
118
|
+
};
|
|
119
|
+
var toFiniteNumber = (value) => {
|
|
120
|
+
const numeric = Number(value ?? 0);
|
|
121
|
+
return Number.isFinite(numeric) ? numeric : 0;
|
|
122
|
+
};
|
|
123
|
+
var parseTimestamp = (meta) => {
|
|
124
|
+
const candidates = [meta?.dateEnd, meta?.dateStart];
|
|
125
|
+
for (const candidate of candidates) {
|
|
126
|
+
if (!candidate) continue;
|
|
127
|
+
const parsed = new Date(candidate).getTime();
|
|
128
|
+
if (Number.isFinite(parsed) && parsed > 0) {
|
|
129
|
+
return parsed;
|
|
130
|
+
}
|
|
131
|
+
}
|
|
132
|
+
return 0;
|
|
133
|
+
};
|
|
134
|
+
var parseGeneratedTimestamp = (meta) => {
|
|
135
|
+
const generated = meta?.generatedAt ? new Date(meta.generatedAt).getTime() : 0;
|
|
136
|
+
if (Number.isFinite(generated) && generated > 0) {
|
|
137
|
+
return generated;
|
|
138
|
+
}
|
|
139
|
+
return parseTimestamp(meta);
|
|
140
|
+
};
|
|
141
|
+
var buildRaidKey = (report, fallbackIndex) => {
|
|
142
|
+
const dateStart = String(report?.meta?.dateStart || "").trim();
|
|
143
|
+
const dateEnd = String(report?.meta?.dateEnd || "").trim();
|
|
144
|
+
if (dateStart || dateEnd) {
|
|
145
|
+
return `${dateStart}|${dateEnd}`;
|
|
146
|
+
}
|
|
147
|
+
const id = String(report?.meta?.id || "").trim();
|
|
148
|
+
if (id) return id;
|
|
149
|
+
return `report-${fallbackIndex}`;
|
|
150
|
+
};
|
|
151
|
+
var choosePrimaryProfession = (professionTimeMs, fallback = "Unknown") => {
|
|
152
|
+
const entries = Object.entries(professionTimeMs).filter(([profession, timeMs]) => profession && timeMs > 0).sort((a, b) => {
|
|
153
|
+
const delta = b[1] - a[1];
|
|
154
|
+
if (delta !== 0) return delta;
|
|
155
|
+
return a[0].localeCompare(b[0]);
|
|
156
|
+
});
|
|
157
|
+
return entries[0]?.[0] || fallback;
|
|
158
|
+
};
|
|
159
|
+
var chooseMostCommonProfession = (professionCounts, fallback = "Unknown") => {
|
|
160
|
+
const entries = Object.entries(professionCounts).filter(([profession, count]) => profession && count > 0).sort((a, b) => {
|
|
161
|
+
const delta = b[1] - a[1];
|
|
162
|
+
if (delta !== 0) return delta;
|
|
163
|
+
return a[0].localeCompare(b[0]);
|
|
164
|
+
});
|
|
165
|
+
return entries[0]?.[0] || fallback;
|
|
166
|
+
};
|
|
167
|
+
var buildProfessionBreakdown = (professionRuns) => Object.entries(professionRuns).filter(([profession, runs]) => profession && runs > 0).sort((a, b) => {
|
|
168
|
+
const delta = b[1] - a[1];
|
|
169
|
+
if (delta !== 0) return delta;
|
|
170
|
+
return a[0].localeCompare(b[0]);
|
|
171
|
+
}).map(([profession, runs]) => ({ profession, runs }));
|
|
172
|
+
var buildRollupData = (reports) => {
|
|
173
|
+
const uniqueRaidKeys = /* @__PURE__ */ new Set();
|
|
174
|
+
const reportsByRaid = /* @__PURE__ */ new Map();
|
|
175
|
+
reports.forEach((report, index) => {
|
|
176
|
+
const raidKey = buildRaidKey(report, index);
|
|
177
|
+
uniqueRaidKeys.add(raidKey);
|
|
178
|
+
const generatedTs = parseGeneratedTimestamp(report?.meta);
|
|
179
|
+
if (!reportsByRaid.has(raidKey)) {
|
|
180
|
+
reportsByRaid.set(raidKey, []);
|
|
181
|
+
}
|
|
182
|
+
reportsByRaid.get(raidKey).push({ report, generatedTs, index });
|
|
183
|
+
});
|
|
184
|
+
const raidGroups = Array.from(reportsByRaid.values()).sort((a, b) => {
|
|
185
|
+
const aLatest = Math.max(...a.map((entry) => entry.generatedTs || 0));
|
|
186
|
+
const bLatest = Math.max(...b.map((entry) => entry.generatedTs || 0));
|
|
187
|
+
if (bLatest !== aLatest) return bLatest - aLatest;
|
|
188
|
+
const aIndex = Math.max(...a.map((entry) => entry.index));
|
|
189
|
+
const bIndex = Math.max(...b.map((entry) => entry.index));
|
|
190
|
+
return bIndex - aIndex;
|
|
191
|
+
}).map((entries) => [...entries].sort((a, b) => {
|
|
192
|
+
if (b.generatedTs !== a.generatedTs) return b.generatedTs - a.generatedTs;
|
|
193
|
+
return b.index - a.index;
|
|
194
|
+
}));
|
|
195
|
+
const commanders = /* @__PURE__ */ new Map();
|
|
196
|
+
const players = /* @__PURE__ */ new Map();
|
|
197
|
+
let reportsWithCommanderDetails = 0;
|
|
198
|
+
let reportsMissingCommanderDetails = 0;
|
|
199
|
+
let reportsWithAttendanceDetails = 0;
|
|
200
|
+
let reportsMissingAttendanceDetails = 0;
|
|
201
|
+
let includedRaidGroups = 0;
|
|
202
|
+
let includedSourceReports = 0;
|
|
203
|
+
raidGroups.forEach((group) => {
|
|
204
|
+
const attendanceSource = group.find((entry) => Array.isArray(entry.report?.stats?.attendanceData) && entry.report.stats.attendanceData.length > 0) || null;
|
|
205
|
+
const attendanceReport = attendanceSource?.report || null;
|
|
206
|
+
const attendanceTimestamp = attendanceReport ? parseTimestamp(attendanceReport.meta) : 0;
|
|
207
|
+
const attendanceRows = Array.isArray(attendanceReport?.stats?.attendanceData) ? attendanceReport.stats.attendanceData : [];
|
|
208
|
+
if (attendanceRows.length > 0) {
|
|
209
|
+
reportsWithAttendanceDetails += 1;
|
|
210
|
+
} else {
|
|
211
|
+
reportsMissingAttendanceDetails += 1;
|
|
212
|
+
}
|
|
213
|
+
const latestCommanderRowsByAccount = /* @__PURE__ */ new Map();
|
|
214
|
+
group.forEach((entry) => {
|
|
215
|
+
const report = entry.report;
|
|
216
|
+
const timestamp = parseTimestamp(report?.meta);
|
|
217
|
+
const commanderRows2 = Array.isArray(report?.stats?.commanderStats?.rows) ? report.stats.commanderStats.rows : [];
|
|
218
|
+
commanderRows2.forEach((row) => {
|
|
219
|
+
const account = String(row?.account || row?.key || "").trim();
|
|
220
|
+
if (!account) return;
|
|
221
|
+
const existing = latestCommanderRowsByAccount.get(account);
|
|
222
|
+
if (!existing) {
|
|
223
|
+
latestCommanderRowsByAccount.set(account, { row, timestamp, generatedTs: entry.generatedTs, index: entry.index });
|
|
224
|
+
return;
|
|
225
|
+
}
|
|
226
|
+
const shouldReplace = entry.generatedTs > existing.generatedTs || entry.generatedTs === existing.generatedTs && entry.index > existing.index;
|
|
227
|
+
if (shouldReplace) {
|
|
228
|
+
latestCommanderRowsByAccount.set(account, { row, timestamp, generatedTs: entry.generatedTs, index: entry.index });
|
|
229
|
+
}
|
|
230
|
+
});
|
|
231
|
+
});
|
|
232
|
+
if (latestCommanderRowsByAccount.size > 0) {
|
|
233
|
+
reportsWithCommanderDetails += 1;
|
|
234
|
+
} else {
|
|
235
|
+
reportsMissingCommanderDetails += 1;
|
|
236
|
+
}
|
|
237
|
+
if (attendanceRows.length === 0 || latestCommanderRowsByAccount.size === 0) {
|
|
238
|
+
return;
|
|
239
|
+
}
|
|
240
|
+
includedRaidGroups += 1;
|
|
241
|
+
includedSourceReports += group.length;
|
|
242
|
+
attendanceRows.forEach((row) => {
|
|
243
|
+
const account = String(row?.account || "").trim();
|
|
244
|
+
if (!account || account === "Unknown") return;
|
|
245
|
+
const existing = players.get(account) || {
|
|
246
|
+
account,
|
|
247
|
+
characterNames: /* @__PURE__ */ new Set(),
|
|
248
|
+
professionTimeMs: {},
|
|
249
|
+
professionRuns: {},
|
|
250
|
+
runs: 0,
|
|
251
|
+
combatTimeMs: 0,
|
|
252
|
+
squadTimeMs: 0,
|
|
253
|
+
lastSeenTs: 0
|
|
254
|
+
};
|
|
255
|
+
existing.runs += 1;
|
|
256
|
+
existing.combatTimeMs += Math.max(0, toFiniteNumber(row?.combatTimeMs));
|
|
257
|
+
existing.squadTimeMs += Math.max(0, toFiniteNumber(row?.squadTimeMs));
|
|
258
|
+
existing.lastSeenTs = Math.max(existing.lastSeenTs, attendanceTimestamp);
|
|
259
|
+
if (Array.isArray(row?.characterNames)) {
|
|
260
|
+
row.characterNames.forEach((name) => {
|
|
261
|
+
const normalized = String(name || "").trim();
|
|
262
|
+
if (normalized) existing.characterNames.add(normalized);
|
|
263
|
+
});
|
|
264
|
+
}
|
|
265
|
+
const classTimes = Array.isArray(row?.classTimes) ? row.classTimes : [];
|
|
266
|
+
const professionsThisRun = /* @__PURE__ */ new Set();
|
|
267
|
+
classTimes.forEach((classRow) => {
|
|
268
|
+
const profession = String(classRow?.profession || "").trim();
|
|
269
|
+
if (!profession || profession === "Unknown") return;
|
|
270
|
+
const timeMs = Math.max(0, toFiniteNumber(classRow?.timeMs));
|
|
271
|
+
existing.professionTimeMs[profession] = (existing.professionTimeMs[profession] || 0) + timeMs;
|
|
272
|
+
if (timeMs > 0) professionsThisRun.add(profession);
|
|
273
|
+
});
|
|
274
|
+
professionsThisRun.forEach((profession) => {
|
|
275
|
+
existing.professionRuns[profession] = (existing.professionRuns[profession] || 0) + 1;
|
|
276
|
+
});
|
|
277
|
+
players.set(account, existing);
|
|
278
|
+
});
|
|
279
|
+
latestCommanderRowsByAccount.forEach(({ row, timestamp }) => {
|
|
280
|
+
const account = String(row?.account || row?.key || "").trim();
|
|
281
|
+
if (!account) return;
|
|
282
|
+
const existing = commanders.get(account) || {
|
|
283
|
+
account,
|
|
284
|
+
characterNames: /* @__PURE__ */ new Set(),
|
|
285
|
+
professionCounts: {},
|
|
286
|
+
runs: 0,
|
|
287
|
+
fightsLed: 0,
|
|
288
|
+
kills: 0,
|
|
289
|
+
downs: 0,
|
|
290
|
+
commanderDeaths: 0,
|
|
291
|
+
alliesDead: 0,
|
|
292
|
+
wins: 0,
|
|
293
|
+
losses: 0,
|
|
294
|
+
lastSeenTs: 0
|
|
295
|
+
};
|
|
296
|
+
existing.runs += 1;
|
|
297
|
+
existing.fightsLed += Math.max(0, toFiniteNumber(row?.fights));
|
|
298
|
+
existing.kills += Math.max(0, toFiniteNumber(row?.kills));
|
|
299
|
+
existing.downs += Math.max(0, toFiniteNumber(row?.downs));
|
|
300
|
+
existing.commanderDeaths += Math.max(0, toFiniteNumber(row?.commanderDeaths));
|
|
301
|
+
existing.alliesDead += Math.max(0, toFiniteNumber(row?.alliesDead));
|
|
302
|
+
existing.wins += Math.max(0, toFiniteNumber(row?.wins));
|
|
303
|
+
existing.losses += Math.max(0, toFiniteNumber(row?.losses));
|
|
304
|
+
existing.lastSeenTs = Math.max(existing.lastSeenTs, timestamp);
|
|
305
|
+
if (Array.isArray(row?.characterNames)) {
|
|
306
|
+
row.characterNames.forEach((name) => {
|
|
307
|
+
const normalized = String(name || "").trim();
|
|
308
|
+
if (normalized) existing.characterNames.add(normalized);
|
|
309
|
+
});
|
|
310
|
+
}
|
|
311
|
+
const profession = String(row?.profession || "").trim();
|
|
312
|
+
if (profession) {
|
|
313
|
+
existing.professionCounts[profession] = (existing.professionCounts[profession] || 0) + 1;
|
|
314
|
+
}
|
|
315
|
+
commanders.set(account, existing);
|
|
316
|
+
});
|
|
317
|
+
});
|
|
318
|
+
const commanderRows = Array.from(commanders.values()).map((entry) => {
|
|
319
|
+
const kdr = entry.alliesDead > 0 ? entry.kills / entry.alliesDead : entry.kills;
|
|
320
|
+
return {
|
|
321
|
+
account: entry.account,
|
|
322
|
+
characterNames: Array.from(entry.characterNames.values()).sort((a, b) => a.localeCompare(b)),
|
|
323
|
+
profession: chooseMostCommonProfession(entry.professionCounts),
|
|
324
|
+
professionBreakdown: buildProfessionBreakdown(entry.professionCounts),
|
|
325
|
+
runs: entry.runs,
|
|
326
|
+
fightsLed: entry.fightsLed,
|
|
327
|
+
kills: entry.kills,
|
|
328
|
+
downs: entry.downs,
|
|
329
|
+
commanderDeaths: entry.commanderDeaths,
|
|
330
|
+
alliesDead: entry.alliesDead,
|
|
331
|
+
wins: entry.wins,
|
|
332
|
+
losses: entry.losses,
|
|
333
|
+
kdr,
|
|
334
|
+
lastSeenTs: entry.lastSeenTs
|
|
335
|
+
};
|
|
336
|
+
}).sort((a, b) => {
|
|
337
|
+
if (b.runs !== a.runs) return b.runs - a.runs;
|
|
338
|
+
if (b.fightsLed !== a.fightsLed) return b.fightsLed - a.fightsLed;
|
|
339
|
+
if (b.kills !== a.kills) return b.kills - a.kills;
|
|
340
|
+
return a.account.localeCompare(b.account);
|
|
341
|
+
});
|
|
342
|
+
const playerRows = Array.from(players.values()).map((entry) => ({
|
|
343
|
+
account: entry.account,
|
|
344
|
+
characterNames: Array.from(entry.characterNames.values()).sort((a, b) => a.localeCompare(b)),
|
|
345
|
+
profession: choosePrimaryProfession(entry.professionTimeMs),
|
|
346
|
+
professionBreakdown: buildProfessionBreakdown(entry.professionRuns),
|
|
347
|
+
runs: entry.runs,
|
|
348
|
+
combatTimeMs: entry.combatTimeMs,
|
|
349
|
+
squadTimeMs: entry.squadTimeMs,
|
|
350
|
+
lastSeenTs: entry.lastSeenTs
|
|
351
|
+
})).sort((a, b) => {
|
|
352
|
+
if (b.runs !== a.runs) return b.runs - a.runs;
|
|
353
|
+
if (b.lastSeenTs !== a.lastSeenTs) return b.lastSeenTs - a.lastSeenTs;
|
|
354
|
+
if (b.squadTimeMs !== a.squadTimeMs) return b.squadTimeMs - a.squadTimeMs;
|
|
355
|
+
return a.account.localeCompare(b.account);
|
|
356
|
+
});
|
|
357
|
+
return {
|
|
358
|
+
commanderRows,
|
|
359
|
+
playerRows,
|
|
360
|
+
sourceReports: reports.length,
|
|
361
|
+
uniqueRaids: includedRaidGroups,
|
|
362
|
+
duplicateReportsCollapsed: Math.max(0, includedSourceReports - includedRaidGroups),
|
|
363
|
+
raidsSkippedMissingRequiredData: Math.max(0, raidGroups.length - includedRaidGroups),
|
|
364
|
+
reportsWithCommanderDetails,
|
|
365
|
+
reportsMissingCommanderDetails,
|
|
366
|
+
reportsWithAttendanceDetails,
|
|
367
|
+
reportsMissingAttendanceDetails
|
|
368
|
+
};
|
|
369
|
+
};
|
|
370
|
+
// Annotate the CommonJS export names for ESM import in node:
|
|
371
|
+
0 && (module.exports = {
|
|
372
|
+
ROLLUP_SOURCES_VERSION,
|
|
373
|
+
buildRollupData,
|
|
374
|
+
extractRollupSource,
|
|
375
|
+
parseRollupSourcesFile,
|
|
376
|
+
removeRollupSources,
|
|
377
|
+
updateRollupSourcesForPublish
|
|
378
|
+
});
|
|
@@ -0,0 +1,103 @@
|
|
|
1
|
+
interface RollupProfessionUsage {
|
|
2
|
+
profession: string;
|
|
3
|
+
runs: number;
|
|
4
|
+
}
|
|
5
|
+
interface RollupCommanderRow {
|
|
6
|
+
account: string;
|
|
7
|
+
characterNames: string[];
|
|
8
|
+
profession: string;
|
|
9
|
+
professionBreakdown: RollupProfessionUsage[];
|
|
10
|
+
runs: number;
|
|
11
|
+
fightsLed: number;
|
|
12
|
+
kills: number;
|
|
13
|
+
downs: number;
|
|
14
|
+
commanderDeaths: number;
|
|
15
|
+
alliesDead: number;
|
|
16
|
+
wins: number;
|
|
17
|
+
losses: number;
|
|
18
|
+
kdr: number;
|
|
19
|
+
lastSeenTs: number;
|
|
20
|
+
}
|
|
21
|
+
interface RollupPlayerRow {
|
|
22
|
+
account: string;
|
|
23
|
+
characterNames: string[];
|
|
24
|
+
profession: string;
|
|
25
|
+
professionBreakdown: RollupProfessionUsage[];
|
|
26
|
+
runs: number;
|
|
27
|
+
combatTimeMs: number;
|
|
28
|
+
squadTimeMs: number;
|
|
29
|
+
lastSeenTs: number;
|
|
30
|
+
}
|
|
31
|
+
interface RollupData {
|
|
32
|
+
commanderRows: RollupCommanderRow[];
|
|
33
|
+
playerRows: RollupPlayerRow[];
|
|
34
|
+
sourceReports: number;
|
|
35
|
+
uniqueRaids: number;
|
|
36
|
+
duplicateReportsCollapsed: number;
|
|
37
|
+
raidsSkippedMissingRequiredData: number;
|
|
38
|
+
reportsWithCommanderDetails: number;
|
|
39
|
+
reportsMissingCommanderDetails: number;
|
|
40
|
+
reportsWithAttendanceDetails: number;
|
|
41
|
+
reportsMissingAttendanceDetails: number;
|
|
42
|
+
}
|
|
43
|
+
type RollupReportPayload = {
|
|
44
|
+
meta?: {
|
|
45
|
+
id?: string;
|
|
46
|
+
title?: string;
|
|
47
|
+
dateStart?: string;
|
|
48
|
+
dateEnd?: string;
|
|
49
|
+
generatedAt?: string;
|
|
50
|
+
commanders?: string[];
|
|
51
|
+
};
|
|
52
|
+
stats?: {
|
|
53
|
+
commanderStats?: {
|
|
54
|
+
rows?: any[];
|
|
55
|
+
};
|
|
56
|
+
attendanceData?: any[];
|
|
57
|
+
};
|
|
58
|
+
};
|
|
59
|
+
|
|
60
|
+
/**
|
|
61
|
+
* Precomputed rollup file published alongside the reports (reports/rollup.json).
|
|
62
|
+
* `sources` holds the minimal per-report projection that buildRollupData needs,
|
|
63
|
+
* so the rollup can be incrementally rebuilt at publish time — and the viewer
|
|
64
|
+
* can merge in legacy reports that predate this file without refetching the rest.
|
|
65
|
+
*/
|
|
66
|
+
interface RollupSourcesFile {
|
|
67
|
+
version: number;
|
|
68
|
+
sources: RollupReportPayload[];
|
|
69
|
+
rollup: RollupData;
|
|
70
|
+
}
|
|
71
|
+
declare const ROLLUP_SOURCES_VERSION = 1;
|
|
72
|
+
/**
|
|
73
|
+
* Project a full report payload down to the minimal fields buildRollupData reads.
|
|
74
|
+
* Commander rows in particular carry ~50 fields the rollup ignores; dropping them
|
|
75
|
+
* takes a typical source from ~360KB to ~8KB.
|
|
76
|
+
*/
|
|
77
|
+
declare const extractRollupSource: (payload: RollupReportPayload) => RollupReportPayload;
|
|
78
|
+
/**
|
|
79
|
+
* Build the rollup.json contents for a publish: merge the just-published
|
|
80
|
+
* report's source into the existing sources, backfill missing reports via the
|
|
81
|
+
* caller-provided loader, drop sources for reports no longer in the index, and
|
|
82
|
+
* recompute the aggregate. Pure aside from the injected loader.
|
|
83
|
+
*/
|
|
84
|
+
declare const updateRollupSourcesForPublish: (options: {
|
|
85
|
+
existingSources: RollupReportPayload[];
|
|
86
|
+
currentReport: RollupReportPayload;
|
|
87
|
+
validIds: string[];
|
|
88
|
+
loadLocalReport?: (id: string) => RollupReportPayload | null;
|
|
89
|
+
}) => RollupSourcesFile;
|
|
90
|
+
/**
|
|
91
|
+
* Build the rollup.json contents after deleting reports: drop their sources
|
|
92
|
+
* and recompute the aggregate.
|
|
93
|
+
*/
|
|
94
|
+
declare const removeRollupSources: (file: RollupSourcesFile, deletedIds: string[]) => RollupSourcesFile;
|
|
95
|
+
/**
|
|
96
|
+
* Parse a fetched/stored rollup.json defensively. Returns null when the file is
|
|
97
|
+
* absent, a different version, or structurally invalid — callers fall back to
|
|
98
|
+
* rebuilding from full report payloads.
|
|
99
|
+
*/
|
|
100
|
+
declare const parseRollupSourcesFile: (data: unknown) => RollupSourcesFile | null;
|
|
101
|
+
declare const buildRollupData: (reports: RollupReportPayload[]) => RollupData;
|
|
102
|
+
|
|
103
|
+
export { ROLLUP_SOURCES_VERSION, type RollupCommanderRow, type RollupData, type RollupPlayerRow, type RollupProfessionUsage, type RollupReportPayload, type RollupSourcesFile, buildRollupData, extractRollupSource, parseRollupSourcesFile, removeRollupSources, updateRollupSourcesForPublish };
|
package/dist/rollup.d.ts
ADDED
|
@@ -0,0 +1,103 @@
|
|
|
1
|
+
interface RollupProfessionUsage {
|
|
2
|
+
profession: string;
|
|
3
|
+
runs: number;
|
|
4
|
+
}
|
|
5
|
+
interface RollupCommanderRow {
|
|
6
|
+
account: string;
|
|
7
|
+
characterNames: string[];
|
|
8
|
+
profession: string;
|
|
9
|
+
professionBreakdown: RollupProfessionUsage[];
|
|
10
|
+
runs: number;
|
|
11
|
+
fightsLed: number;
|
|
12
|
+
kills: number;
|
|
13
|
+
downs: number;
|
|
14
|
+
commanderDeaths: number;
|
|
15
|
+
alliesDead: number;
|
|
16
|
+
wins: number;
|
|
17
|
+
losses: number;
|
|
18
|
+
kdr: number;
|
|
19
|
+
lastSeenTs: number;
|
|
20
|
+
}
|
|
21
|
+
interface RollupPlayerRow {
|
|
22
|
+
account: string;
|
|
23
|
+
characterNames: string[];
|
|
24
|
+
profession: string;
|
|
25
|
+
professionBreakdown: RollupProfessionUsage[];
|
|
26
|
+
runs: number;
|
|
27
|
+
combatTimeMs: number;
|
|
28
|
+
squadTimeMs: number;
|
|
29
|
+
lastSeenTs: number;
|
|
30
|
+
}
|
|
31
|
+
interface RollupData {
|
|
32
|
+
commanderRows: RollupCommanderRow[];
|
|
33
|
+
playerRows: RollupPlayerRow[];
|
|
34
|
+
sourceReports: number;
|
|
35
|
+
uniqueRaids: number;
|
|
36
|
+
duplicateReportsCollapsed: number;
|
|
37
|
+
raidsSkippedMissingRequiredData: number;
|
|
38
|
+
reportsWithCommanderDetails: number;
|
|
39
|
+
reportsMissingCommanderDetails: number;
|
|
40
|
+
reportsWithAttendanceDetails: number;
|
|
41
|
+
reportsMissingAttendanceDetails: number;
|
|
42
|
+
}
|
|
43
|
+
type RollupReportPayload = {
|
|
44
|
+
meta?: {
|
|
45
|
+
id?: string;
|
|
46
|
+
title?: string;
|
|
47
|
+
dateStart?: string;
|
|
48
|
+
dateEnd?: string;
|
|
49
|
+
generatedAt?: string;
|
|
50
|
+
commanders?: string[];
|
|
51
|
+
};
|
|
52
|
+
stats?: {
|
|
53
|
+
commanderStats?: {
|
|
54
|
+
rows?: any[];
|
|
55
|
+
};
|
|
56
|
+
attendanceData?: any[];
|
|
57
|
+
};
|
|
58
|
+
};
|
|
59
|
+
|
|
60
|
+
/**
|
|
61
|
+
* Precomputed rollup file published alongside the reports (reports/rollup.json).
|
|
62
|
+
* `sources` holds the minimal per-report projection that buildRollupData needs,
|
|
63
|
+
* so the rollup can be incrementally rebuilt at publish time — and the viewer
|
|
64
|
+
* can merge in legacy reports that predate this file without refetching the rest.
|
|
65
|
+
*/
|
|
66
|
+
interface RollupSourcesFile {
|
|
67
|
+
version: number;
|
|
68
|
+
sources: RollupReportPayload[];
|
|
69
|
+
rollup: RollupData;
|
|
70
|
+
}
|
|
71
|
+
declare const ROLLUP_SOURCES_VERSION = 1;
|
|
72
|
+
/**
|
|
73
|
+
* Project a full report payload down to the minimal fields buildRollupData reads.
|
|
74
|
+
* Commander rows in particular carry ~50 fields the rollup ignores; dropping them
|
|
75
|
+
* takes a typical source from ~360KB to ~8KB.
|
|
76
|
+
*/
|
|
77
|
+
declare const extractRollupSource: (payload: RollupReportPayload) => RollupReportPayload;
|
|
78
|
+
/**
|
|
79
|
+
* Build the rollup.json contents for a publish: merge the just-published
|
|
80
|
+
* report's source into the existing sources, backfill missing reports via the
|
|
81
|
+
* caller-provided loader, drop sources for reports no longer in the index, and
|
|
82
|
+
* recompute the aggregate. Pure aside from the injected loader.
|
|
83
|
+
*/
|
|
84
|
+
declare const updateRollupSourcesForPublish: (options: {
|
|
85
|
+
existingSources: RollupReportPayload[];
|
|
86
|
+
currentReport: RollupReportPayload;
|
|
87
|
+
validIds: string[];
|
|
88
|
+
loadLocalReport?: (id: string) => RollupReportPayload | null;
|
|
89
|
+
}) => RollupSourcesFile;
|
|
90
|
+
/**
|
|
91
|
+
* Build the rollup.json contents after deleting reports: drop their sources
|
|
92
|
+
* and recompute the aggregate.
|
|
93
|
+
*/
|
|
94
|
+
declare const removeRollupSources: (file: RollupSourcesFile, deletedIds: string[]) => RollupSourcesFile;
|
|
95
|
+
/**
|
|
96
|
+
* Parse a fetched/stored rollup.json defensively. Returns null when the file is
|
|
97
|
+
* absent, a different version, or structurally invalid — callers fall back to
|
|
98
|
+
* rebuilding from full report payloads.
|
|
99
|
+
*/
|
|
100
|
+
declare const parseRollupSourcesFile: (data: unknown) => RollupSourcesFile | null;
|
|
101
|
+
declare const buildRollupData: (reports: RollupReportPayload[]) => RollupData;
|
|
102
|
+
|
|
103
|
+
export { ROLLUP_SOURCES_VERSION, type RollupCommanderRow, type RollupData, type RollupPlayerRow, type RollupProfessionUsage, type RollupReportPayload, type RollupSourcesFile, buildRollupData, extractRollupSource, parseRollupSourcesFile, removeRollupSources, updateRollupSourcesForPublish };
|
package/dist/rollup.js
ADDED
|
@@ -0,0 +1,16 @@
|
|
|
1
|
+
import {
|
|
2
|
+
ROLLUP_SOURCES_VERSION,
|
|
3
|
+
buildRollupData,
|
|
4
|
+
extractRollupSource,
|
|
5
|
+
parseRollupSourcesFile,
|
|
6
|
+
removeRollupSources,
|
|
7
|
+
updateRollupSourcesForPublish
|
|
8
|
+
} from "./chunk-ELKDB763.js";
|
|
9
|
+
export {
|
|
10
|
+
ROLLUP_SOURCES_VERSION,
|
|
11
|
+
buildRollupData,
|
|
12
|
+
extractRollupSource,
|
|
13
|
+
parseRollupSourcesFile,
|
|
14
|
+
removeRollupSources,
|
|
15
|
+
updateRollupSourcesForPublish
|
|
16
|
+
};
|