@axiapps/axilog 0.1.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/package.json ADDED
@@ -0,0 +1,46 @@
1
+ {
2
+ "name": "@axiapps/axilog",
3
+ "version": "0.1.1",
4
+ "description": "Node bindings (napi-rs) for axilog's Rust GW2 arcdps WvW parsing core",
5
+ "main": "index.js",
6
+ "types": "index.d.ts",
7
+ "license": "MIT",
8
+ "files": [
9
+ "index.d.ts",
10
+ "index.js",
11
+ "types.d.ts"
12
+ ],
13
+ "napi": {
14
+ "binaryName": "axilog",
15
+ "packageName": "@axiapps/axilog",
16
+ "targets": [
17
+ "x86_64-pc-windows-msvc",
18
+ "x86_64-apple-darwin",
19
+ "x86_64-unknown-linux-gnu",
20
+ "x86_64-unknown-linux-musl",
21
+ "aarch64-unknown-linux-gnu",
22
+ "aarch64-apple-darwin",
23
+ "aarch64-unknown-linux-musl",
24
+ "aarch64-pc-windows-msvc"
25
+ ]
26
+ },
27
+ "engines": {
28
+ "node": ">= 18"
29
+ },
30
+ "optionalDependencies": {
31
+ "@axiapps/axilog-linux-x64-gnu": "0.1.1",
32
+ "@axiapps/axilog-linux-arm64-gnu": "0.1.1",
33
+ "@axiapps/axilog-win32-x64-msvc": "0.1.1",
34
+ "@axiapps/axilog-darwin-x64": "0.1.1",
35
+ "@axiapps/axilog-darwin-arm64": "0.1.1"
36
+ },
37
+ "scripts": {
38
+ "build": "napi build --platform --release && node scripts/patch-dts.mjs",
39
+ "build:debug": "napi build --platform && node scripts/patch-dts.mjs",
40
+ "artifacts": "napi artifacts",
41
+ "test": "node --test __test__/*.test.mjs"
42
+ },
43
+ "devDependencies": {
44
+ "@napi-rs/cli": "3.8.2"
45
+ }
46
+ }
package/types.d.ts ADDED
@@ -0,0 +1,487 @@
1
+ /**
2
+ * Hand-maintained TypeScript definitions for axilog's native `Report`
3
+ * shape (M5 Task 2).
4
+ *
5
+ * napi-rs's typegen only sees the Rust *function signatures* declared in
6
+ * `src/lib.rs`; every exported function here returns a plain
7
+ * `serde_json::Value` (see that file's module doc for why -- napi's
8
+ * serde-json interop turns a `Value::Object` into a plain JS object
9
+ * key-by-key, keeping the exact snake_case field names `axilog_schema`
10
+ * already produces, rather than the camelCase rewriting `#[napi(object)]`
11
+ * would apply). Because the return type is an opaque `Value`, napi's dts
12
+ * generator can only ever emit `any` for `parseFile`/`parseBuffer` -- it
13
+ * has no visibility into `axilog_schema::Report`'s actual field layout.
14
+ *
15
+ * This file closes that gap by hand-transcribing `axilog_schema::Report`
16
+ * (`crates/axilog-schema/src/lib.rs` -- the serde struct definitions are
17
+ * the source of truth; keep this file in sync with that one) into real
18
+ * TypeScript types, and `index.d.ts` imports `Report` from here to type
19
+ * `parseFile`/`parseBuffer`'s return value (see `index.d.ts`'s top-of-file
20
+ * comment and `scripts/patch-dts.mjs` for how that reference survives
21
+ * `napi build` regenerating `index.d.ts`).
22
+ *
23
+ * `parseFileEi`'s return value (the Elite-Insights-compatibility JSON from
24
+ * `axilog_ei::to_ei_json`) is a materially different, larger shape (not a
25
+ * serialized `Report`) and isn't typed here -- it stays `any` in
26
+ * `index.d.ts`, called out in that file's doc comment.
27
+ *
28
+ * Numeric-field note: every Rust `u64`/`u32`/`f64` field below is typed as
29
+ * plain `number` -- napi's serde-json bridge converts JSON numbers to JS
30
+ * `number` (not `BigInt`), which is exact for every value this schema
31
+ * actually produces (agent-table addresses/ids, ms durations, damage
32
+ * totals) but would lose precision for a `u64` beyond 2^53; documented
33
+ * here rather than silently assumed.
34
+ */
35
+
36
+ /** One `CBTS_MARKER` assignment observed in the log (native-only, no EI equivalent). */
37
+ export interface MarkerAssignmentOut {
38
+ agent_addr: number
39
+ marker: string
40
+ time_ms: number
41
+ }
42
+
43
+ /** `CBTS_TICK` tick-rate telemetry (native-only). Omitted from `EncounterOut` when the log has fewer than two `CBTS_TICK` events. */
44
+ export interface TickRateOut {
45
+ avg: number
46
+ min: number
47
+ per_second: number[]
48
+ }
49
+
50
+ /** Commander-tag colour/variant, present alongside `PlayerOut.commander` when the player has a tag. */
51
+ export interface CommanderTagOut {
52
+ variant: string
53
+ guid: string
54
+ }
55
+
56
+ export interface TeamOut {
57
+ color: string
58
+ team_id: number
59
+ /** Stable content GUID for this team, when known (omitted, not null, when absent). */
60
+ guid?: string
61
+ }
62
+
63
+ export interface PerEnemyOut {
64
+ enemy_id: number
65
+ total: number
66
+ }
67
+
68
+ export interface DamageOut {
69
+ total: number
70
+ dps: number
71
+ per_enemy: PerEnemyOut[]
72
+ }
73
+
74
+ /**
75
+ * One skill id's aggregated hit stats within some grouping (M12, Task 1).
76
+ * `hits`/`min`/`max` count only CONTRIBUTING (`dmg > 0`) events, matching
77
+ * this project's established damage predicate -- a deliberate divergence
78
+ * from GW2EI's own `totalDamageDist[].hits` (which also counts 0-damage
79
+ * missed/blocked/invulned/evaded attempts). `crit_hits`/`flank_hits` are
80
+ * hit COUNTS (not damage sums).
81
+ */
82
+ export interface SkillEntryOut {
83
+ skill_id: number
84
+ total: number
85
+ hits: number
86
+ min: number
87
+ max: number
88
+ crit_hits: number
89
+ flank_hits: number
90
+ }
91
+
92
+ /** One enemy's per-skill outgoing breakdown (M12, Task 1) -- explicit `enemy_id`, not positional. */
93
+ export interface PerTargetSkillsOut {
94
+ enemy_id: number
95
+ skills: SkillEntryOut[]
96
+ }
97
+
98
+ /**
99
+ * Per-skill damage distribution: outgoing (total + per-target) and
100
+ * incoming, each grouped by skill id (M12, Task 1). `sum(outgoing[*].total)
101
+ * == DamageOut.total` and `sum(taken[*].total) == PlayerOut.damage_taken`
102
+ * hold exactly by construction. Pet/minion damage is folded onto the owner
103
+ * here (using the pet's own skill id), matching `DamageOut.total`'s own
104
+ * pet-fold -- unlike GW2EI's `totalDamageDist`, which tracks the player
105
+ * actor only and excludes pet/minion damage entirely.
106
+ */
107
+ export interface SkillDamageOut {
108
+ outgoing: SkillEntryOut[]
109
+ taken: SkillEntryOut[]
110
+ per_target: PerTargetSkillsOut[]
111
+ }
112
+
113
+ /** One enemy's cumulative per-second outgoing-damage series (M12, Task 2). */
114
+ export interface PlayerTargetSeriesOut {
115
+ enemy_id: number
116
+ damage: number[]
117
+ }
118
+
119
+ /**
120
+ * A player's per-second detail block (M12, Task 2), opt-in -- see
121
+ * `PlayerOut.per_second`. `damage`/`damage_taken`/every `per_target[].damage`
122
+ * are CUMULATIVE running totals, one entry per second, bucketed the same way
123
+ * `Report.timeline` is (`resolution_ms = 1000`, from the log's first event)
124
+ * -- mirrors GW2EI's `damage1S`/`damageTaken1S`/`targetDamage1S` cumulative
125
+ * (not instant-delta) shape.
126
+ */
127
+ export interface PlayerPerSecondOut {
128
+ damage: number[]
129
+ damage_taken: number[]
130
+ per_target: PlayerTargetSeriesOut[]
131
+ }
132
+
133
+ /** One enemy's whole-fight dps/damage summary (M12, Task 2) -- see `PlayerOut.dps_targets`. */
134
+ export interface DpsTargetOut {
135
+ enemy_id: number
136
+ damage: number
137
+ dps: number
138
+ }
139
+
140
+ export interface CcOut {
141
+ applied_total: number
142
+ applied_duration_ms: number
143
+ stun_breaks: number
144
+ removed_stun_duration_ms: number
145
+ }
146
+
147
+ /** Self/group/squad boon-generation attribution, 0-100 (duration boons) / raw average-concurrent-stack-count (intensity boons) scale -- same scale as `BoonOut.presence_pct`/`avg_stacks`. */
148
+ export interface GenerationOut {
149
+ self_pct: number
150
+ group_pct: number
151
+ squad_pct: number
152
+ }
153
+
154
+ /**
155
+ * One tracked boon's whole-fight summary for one player.
156
+ * `presence_pct` is "% of the fight with >=1 held stack" (0-100), for every
157
+ * boon. `avg_stacks` (time-weighted mean held-stack count) is only present
158
+ * for the two INTENSITY-type boons (Might, Stability); omitted (not a
159
+ * meaningless 0) for the other 10 duration-type boons.
160
+ */
161
+ export interface BoonOut {
162
+ id: number
163
+ name: string
164
+ presence_pct: number
165
+ avg_stacks?: number
166
+ generation: GenerationOut
167
+ }
168
+
169
+ /** Condition-cleanse/boon-strip/resurrect counts. Stun-break counts stay on `CcOut`. */
170
+ export interface SupportOut {
171
+ cleanses: number
172
+ cleanses_self: number
173
+ strips: number
174
+ resurrects: number
175
+ }
176
+
177
+ /**
178
+ * arcdps healing-extension totals (M10, Task 1) -- outgoing healing/barrier
179
+ * scalars, mirroring EI's `extHealingStats`/`extBarrierStats`.
180
+ * `healing_out_allies` is `healing_out_total - healing_out_self`.
181
+ */
182
+ export interface HealingOut {
183
+ healing_out_total: number
184
+ healing_out_allies: number
185
+ healing_out_self: number
186
+ barrier_out: number
187
+ downed_healing_out: number
188
+ }
189
+
190
+ /**
191
+ * The arcdps-methodology contribution family's four stats (M11, Task 2) --
192
+ * used for both `PlayerOut.downs_contribution` (outgoing: this player's own
193
+ * credit toward downing enemy players) and `PlayerOut.downed_by` (incoming:
194
+ * what non-squad contributors did to THIS player before each of their own
195
+ * downs, aggregated onto this row, not broken down by attacker). Replaces
196
+ * the retired M1-era `down_contribution` 10s-window approximation (schema
197
+ * 0.1 -> 0.2).
198
+ */
199
+ export interface ContributionOut {
200
+ damage: number
201
+ cc: number
202
+ strips: number
203
+ movement_impairing: number
204
+ }
205
+
206
+ /**
207
+ * Outgoing hit-quality stats (M13, Task 1) -- mirrors EI's `statsAll[0]`.
208
+ * `against_downed`/`above90_*` are plain per-event wire flags (NOT
209
+ * down-interval/health-tracker state); this block deliberately does NOT
210
+ * fold pet/minion damage onto the owner (unlike `DamageOut`/
211
+ * `SkillDamageOut`) -- EI's own `statsAll[0]` is actor-only. Always present
212
+ * (not gated) -- no per-target/per-skill combinatorial blowup here.
213
+ */
214
+ export interface HitStatsOut {
215
+ crit_count: number
216
+ crit_damage: number
217
+ flank_count: number
218
+ glance_count: number
219
+ moving_count: number
220
+ connected_count: number
221
+ connected_damage: number
222
+ direct_count: number
223
+ direct_damage: number
224
+ condition_count: number
225
+ condition_damage: number
226
+ critable_direct_count: number
227
+ against_downed_count: number
228
+ against_downed_damage: number
229
+ life_leech_count: number
230
+ life_leech_damage: number
231
+ above90_power_count: number
232
+ above90_power_damage: number
233
+ above90_condition_count: number
234
+ above90_condition_damage: number
235
+ }
236
+
237
+ /**
238
+ * Incoming defenses: hit-outcome counts + damage-taken breakdown (M13,
239
+ * Task 2) -- mirrors EI's `defenses[0]`. `dodge_count` is NOT derived from
240
+ * any incoming event (a self-cast dodge-skill count, independent of
241
+ * `evaded_count`); `power_count`/`power_damage` always equal
242
+ * `strike_count`/`strike_damage` + `life_leech_count`/`life_leech_damage`;
243
+ * `life_leech_count`/`life_leech_damage` are the TRUE values (a real GW2EI
244
+ * counting bug in its own `lifeLeechDamageTakenCount` is deliberately not
245
+ * reproduced). Purely additive alongside `downs_taken`/`deaths`/
246
+ * `damage_taken`/`cc`. Always present (not gated), like `hit_stats`.
247
+ */
248
+ export interface DefensesOut {
249
+ blocked_count: number
250
+ evaded_count: number
251
+ dodge_count: number
252
+ missed_count: number
253
+ interrupted_count: number
254
+ invulned_count: number
255
+ strike_count: number
256
+ strike_damage: number
257
+ power_count: number
258
+ power_damage: number
259
+ condition_count: number
260
+ condition_damage: number
261
+ life_leech_count: number
262
+ life_leech_damage: number
263
+ barrier_count: number
264
+ barrier_damage: number
265
+ breakbar_count: number
266
+ breakbar_damage: number
267
+ }
268
+
269
+ export interface PlayerOut {
270
+ account: string
271
+ character: string
272
+ profession: string
273
+ elite_spec: string
274
+ team: string
275
+ subgroup: number
276
+ in_squad: boolean
277
+ commander: boolean
278
+ /** The player's current squad marker, name or hex GUID fallback. Omitted when no marker is assigned. */
279
+ marker?: string
280
+ /** Present when `commander` is true. */
281
+ commander_tag?: CommanderTagOut
282
+ damage: DamageOut
283
+ downs_dealt: number
284
+ kills_dealt: number
285
+ downs_taken: number
286
+ deaths: number
287
+ damage_taken: number
288
+ cc: CcOut
289
+ /**
290
+ * Outgoing arcdps-methodology contribution toward downing enemy players
291
+ * (M11, Task 2). See `ContributionOut`.
292
+ */
293
+ downs_contribution: ContributionOut
294
+ /**
295
+ * The mirror: what non-squad contributors did to THIS player before each
296
+ * of their own downs, aggregated onto this row, not broken down by
297
+ * attacker (M11, Task 2).
298
+ */
299
+ downed_by: ContributionOut
300
+ /** One entry per tracked boon id, in `axilog_core::analysis::buffs::BOON_IDS` order. */
301
+ boons: BoonOut[]
302
+ support: SupportOut
303
+ /**
304
+ * arcdps healing-extension totals (M10, Task 1). Omitted entirely (not
305
+ * present as a `null`/all-zero object) when the log carries no
306
+ * healing-extension data at all -- a real "no data" signal, not "the
307
+ * player never healed".
308
+ */
309
+ healing?: HealingOut
310
+ /**
311
+ * Per-skill damage distribution (M12, Task 1), opt-in like `replay`/
312
+ * `missiles` -- present only when requested (`{ skillDamage: true }`,
313
+ * see `ParseOptions.skillDamage` in `index.d.ts`). Omitted entirely
314
+ * (not `null`) when not requested; measured +249% native JSON size on
315
+ * the committed fixture when always-on, hence opt-in rather than
316
+ * always-present like `boons`/`support`.
317
+ */
318
+ skill_damage?: SkillDamageOut
319
+ /**
320
+ * Per-second cumulative `damage`/`damage_taken`/`per_target` detail
321
+ * (M12, Task 2), opt-in like `skill_damage` -- present only when
322
+ * requested (`{ timeseries: true }`, see `ParseOptions.timeseries` in
323
+ * `index.d.ts`). Omitted entirely (not `null`) when not requested;
324
+ * measured +147.7% native JSON size on the committed fixture when
325
+ * always-on, hence opt-in.
326
+ */
327
+ per_second?: PlayerPerSecondOut
328
+ /**
329
+ * Per-enemy whole-fight dps/damage summary (M12, Task 2). Gated by the
330
+ * SAME `{ timeseries: true }` option as `per_second` (NOT always-on --
331
+ * measured +36.4% native JSON size alone on the committed fixture, a
332
+ * real WvW log can enumerate dozens of enemies per player). Omitted
333
+ * entirely (not `[]`) when not requested.
334
+ */
335
+ dps_targets?: DpsTargetOut[]
336
+ /**
337
+ * Outgoing hit-quality stats (M13, Task 1). Always present, unlike
338
+ * `skill_damage`/`per_second`/`dps_targets`. See `HitStatsOut`.
339
+ */
340
+ hit_stats: HitStatsOut
341
+ /**
342
+ * Incoming defenses: hit-outcome counts + damage-taken breakdown (M13,
343
+ * Task 2). Always present, same as `hit_stats`. See `DefensesOut`.
344
+ */
345
+ defenses: DefensesOut
346
+ }
347
+
348
+ export interface EnemyOut {
349
+ id: number
350
+ name: string
351
+ team: string
352
+ is_player: boolean
353
+ /** Mirrors `PlayerOut.marker`. Omitted when absent. */
354
+ marker?: string
355
+ }
356
+
357
+ export interface PerSecondOut {
358
+ squad_damage: number[]
359
+ cc_applied: number[]
360
+ downs: number[]
361
+ }
362
+
363
+ export interface TimelineOut {
364
+ resolution_ms: number
365
+ per_second: PerSecondOut
366
+ }
367
+
368
+ export interface EncounterOut {
369
+ kind: string
370
+ map: string
371
+ duration_ms: number
372
+ build: string
373
+ revision: number
374
+ /** `null` (not omitted) when unknown -- `Option<String>` without `skip_serializing_if`. */
375
+ recorded_by: string | null
376
+ teams: TeamOut[]
377
+ /** Every `CBTS_MARKER` assignment observed in the log, across all agents -- not just squad/enemy players. Always present (possibly empty), never omitted. */
378
+ markers: MarkerAssignmentOut[]
379
+ /** Omitted entirely (not `null`) when the log has fewer than two `CBTS_TICK` events. */
380
+ tick_rate?: TickRateOut
381
+ }
382
+
383
+ /** Min/max `x`/`y` observed across every `ReplayOut.tracks[].samples` -- lets a consumer size a viewBox without a second pass over `tracks`. */
384
+ export interface ReplayBoundsOut {
385
+ min_x: number
386
+ min_y: number
387
+ max_x: number
388
+ max_y: number
389
+ }
390
+
391
+ /**
392
+ * One tracked agent's combat-replay track (M9, Task 2). `name`/`team` mirror
393
+ * the display-field precedence used elsewhere (`PlayerOut.character` for
394
+ * squad players, `EnemyOut.name` for enemy-player representatives).
395
+ * `samples` are `[t_ms, x, y]` triples (`x`/`y` rounded to 1 decimal place);
396
+ * `down_intervals`/`dead_intervals` are `[start_ms, end_ms]` pairs.
397
+ */
398
+ export interface ReplayTrackOut {
399
+ name: string
400
+ team: string
401
+ commander: boolean
402
+ is_squad: boolean
403
+ samples: [number, number, number][]
404
+ down_intervals: [number, number][]
405
+ dead_intervals: [number, number][]
406
+ }
407
+
408
+ /**
409
+ * Combat-replay position tracks (M9, Task 2), native-only -- present only
410
+ * when the caller opted in (CLI `--replay` / SDK `replay: true`). See
411
+ * `axilog_core::analysis::replay` for how `poll_ms`/samples/intervals are
412
+ * computed.
413
+ */
414
+ export interface ReplayOut {
415
+ poll_ms: number
416
+ bounds: ReplayBoundsOut
417
+ tracks: ReplayTrackOut[]
418
+ }
419
+
420
+ /**
421
+ * One squad player's missile totals (M10, Task 2), account-folded across
422
+ * relog/build-swap addrs like every other per-player metric. `account`
423
+ * (final-review fix wave) is the join key back to `Report.players[]` --
424
+ * `agent_addr` alone isn't exposed anywhere else in the native JSON. See
425
+ * `axilog_core::analysis::missiles`'s module doc for exactly what `fired`/
426
+ * `hit`/`denied`/`reflected_at_self` are (and are NOT) attributable to --
427
+ * notably `denied` deliberately does not distinguish blocked/reflected/
428
+ * destroyed/expired outcomes, and `reflected_at_self` is an explicitly
429
+ * labeled heuristic (GW2EI's own "Maybe"-prefixed signal), not a certainty.
430
+ */
431
+ export interface PlayerMissilesOut {
432
+ agent_addr: number
433
+ account: string
434
+ fired: number
435
+ hit: number
436
+ denied: number
437
+ reflected_at_self: number
438
+ }
439
+
440
+ /**
441
+ * Squad-wide missile totals (M10, Task 2) -- the sum of every
442
+ * `PlayerMissilesOut` entry, plus the aggregate, unattributed "incoming,
443
+ * denied" defensive rollup (`incoming_fired`/`incoming_denied`: no
444
+ * per-player credit exists for who denied an incoming missile, per the
445
+ * `axilog_core::analysis::missiles` module doc).
446
+ */
447
+ export interface SquadMissilesOut {
448
+ fired: number
449
+ hit: number
450
+ denied: number
451
+ incoming_fired: number
452
+ incoming_denied: number
453
+ }
454
+
455
+ /**
456
+ * Opt-in missile (projectile) analytics (M10, Task 2), native-only --
457
+ * present only when the caller opted in (CLI `--missiles` / SDK
458
+ * `{ missiles: true }`, see `ParseOptions.missiles`, added final-review
459
+ * fix wave).
460
+ */
461
+ export interface MissilesOut {
462
+ players: PlayerMissilesOut[]
463
+ squad: SquadMissilesOut
464
+ }
465
+
466
+ /**
467
+ * axilog's native report shape (`axilog_schema::Report`), as returned by
468
+ * `parseFile`/`parseBuffer`. `schema_version` is currently always `"0.2"`.
469
+ */
470
+ export interface Report {
471
+ schema_version: string
472
+ axilog_version: string
473
+ encounter: EncounterOut
474
+ players: PlayerOut[]
475
+ enemies: EnemyOut[]
476
+ timeline: TimelineOut
477
+ /** Structured, user-facing analysis warnings (e.g. an unsupported post-rework build). Omitted entirely (not `[]`) when there are none. */
478
+ warnings?: string[]
479
+ /** Opt-in combat-replay block (M9, Task 2) -- present only when requested via `{ replay: true }`. Omitted entirely (not `null`) otherwise. */
480
+ replay?: ReplayOut
481
+ /**
482
+ * Opt-in missile (projectile) analytics block (M10, Task 2) -- present
483
+ * only when requested via `{ missiles: true }` (`ParseOptions.missiles`,
484
+ * added final-review fix wave). Omitted entirely (not `null`) otherwise.
485
+ */
486
+ missiles?: MissilesOut
487
+ }