@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.
Files changed (86) hide show
  1. package/dist/aggregationTypes.cjs +18 -0
  2. package/dist/aggregationTypes.d.cts +21 -0
  3. package/dist/aggregationTypes.d.ts +21 -0
  4. package/dist/aggregationTypes.js +1 -0
  5. package/dist/boonGeneration.cjs +308 -0
  6. package/dist/boonGeneration.d.cts +65 -0
  7. package/dist/boonGeneration.d.ts +65 -0
  8. package/dist/boonGeneration.js +16 -0
  9. package/dist/chunk-42DVJJLC.js +106 -0
  10. package/dist/chunk-4F55Q6K2.js +0 -0
  11. package/dist/chunk-ELKDB763.js +349 -0
  12. package/dist/chunk-FU74LJEM.js +77 -0
  13. package/dist/chunk-J3YCFY3C.js +37 -0
  14. package/dist/chunk-JP2ZL44R.js +18 -0
  15. package/dist/chunk-K2SRAMGC.js +0 -0
  16. package/dist/chunk-KRHODGVU.js +48 -0
  17. package/dist/chunk-LIGIXSSA.js +1383 -0
  18. package/dist/chunk-M2WR3JBQ.js +0 -0
  19. package/dist/chunk-PMVLNDZZ.js +279 -0
  20. package/dist/chunk-R5EJF5AW.js +147 -0
  21. package/dist/chunk-RGXSI3AI.js +298 -0
  22. package/dist/chunk-UFJJ6WLD.js +197 -0
  23. package/dist/chunk-WW5XFXGC.js +234 -0
  24. package/dist/chunk-ZFZS7JFU.js +10 -0
  25. package/dist/combatMetrics.cjs +251 -0
  26. package/dist/combatMetrics.d.cts +26 -0
  27. package/dist/combatMetrics.d.ts +26 -0
  28. package/dist/combatMetrics.js +21 -0
  29. package/dist/computePlayerAggregation.cjs +2042 -0
  30. package/dist/computePlayerAggregation.d.cts +249 -0
  31. package/dist/computePlayerAggregation.d.ts +249 -0
  32. package/dist/computePlayerAggregation.js +30 -0
  33. package/dist/conditionsMetrics.cjs +328 -0
  34. package/dist/conditionsMetrics.d.cts +67 -0
  35. package/dist/conditionsMetrics.d.ts +67 -0
  36. package/dist/conditionsMetrics.js +18 -0
  37. package/dist/constants.cjs +36 -0
  38. package/dist/constants.d.cts +18 -0
  39. package/dist/constants.d.ts +18 -0
  40. package/dist/constants.js +10 -0
  41. package/dist/dashboardMetrics.cjs +226 -0
  42. package/dist/dashboardMetrics.d.cts +29 -0
  43. package/dist/dashboardMetrics.d.ts +29 -0
  44. package/dist/dashboardMetrics.js +42 -0
  45. package/dist/dpsReportTypes.cjs +18 -0
  46. package/dist/dpsReportTypes.d.cts +294 -0
  47. package/dist/dpsReportTypes.d.ts +294 -0
  48. package/dist/dpsReportTypes.js +1 -0
  49. package/dist/index.cjs +2902 -0
  50. package/dist/index.d.cts +13 -0
  51. package/dist/index.d.ts +13 -0
  52. package/dist/index.js +152 -0
  53. package/dist/metrics-methods.json +38 -0
  54. package/dist/metricsSettings.cjs +75 -0
  55. package/dist/metricsSettings.d.cts +23 -0
  56. package/dist/metricsSettings.d.ts +23 -0
  57. package/dist/metricsSettings.js +8 -0
  58. package/dist/professionUtils.cjs +265 -0
  59. package/dist/professionUtils.d.cts +10 -0
  60. package/dist/professionUtils.d.ts +10 -0
  61. package/dist/professionUtils.js +20 -0
  62. package/dist/reportMetrics.cjs +224 -0
  63. package/dist/reportMetrics.d.cts +85 -0
  64. package/dist/reportMetrics.d.ts +85 -0
  65. package/dist/reportMetrics.js +12 -0
  66. package/dist/resUtility.cjs +52 -0
  67. package/dist/resUtility.d.cts +5 -0
  68. package/dist/resUtility.d.ts +5 -0
  69. package/dist/resUtility.js +8 -0
  70. package/dist/roles.cjs +18 -0
  71. package/dist/roles.d.cts +17 -0
  72. package/dist/roles.d.ts +17 -0
  73. package/dist/roles.js +1 -0
  74. package/dist/rollup.cjs +378 -0
  75. package/dist/rollup.d.cts +103 -0
  76. package/dist/rollup.d.ts +103 -0
  77. package/dist/rollup.js +16 -0
  78. package/dist/statsMetrics.cjs +153 -0
  79. package/dist/statsMetrics.d.cts +39 -0
  80. package/dist/statsMetrics.d.ts +39 -0
  81. package/dist/statsMetrics.js +22 -0
  82. package/dist/timestampUtils.cjs +63 -0
  83. package/dist/timestampUtils.d.cts +12 -0
  84. package/dist/timestampUtils.d.ts +12 -0
  85. package/dist/timestampUtils.js +9 -0
  86. package/package.json +44 -0
@@ -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 };
@@ -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
+ };