ultimatedarktower 4.1.0 → 5.0.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.
Files changed (77) hide show
  1. package/CHANGELOG.md +51 -0
  2. package/dist/esm/index.mjs +1598 -556
  3. package/dist/src/UltimateDarkTower.d.ts +5 -13
  4. package/dist/src/UltimateDarkTower.js +33 -44
  5. package/dist/src/UltimateDarkTower.js.map +1 -1
  6. package/dist/src/adapters/NodeBluetoothAdapter.js +7 -9
  7. package/dist/src/adapters/NodeBluetoothAdapter.js.map +1 -1
  8. package/dist/src/adapters/WebBluetoothAdapter.js +1 -0
  9. package/dist/src/adapters/WebBluetoothAdapter.js.map +1 -1
  10. package/dist/src/data/board/index.d.ts +9 -0
  11. package/dist/src/data/board/index.js +26 -0
  12. package/dist/src/data/board/index.js.map +1 -0
  13. package/dist/src/data/board/udtBoardAdjacency.js.map +1 -0
  14. package/dist/src/data/board/udtBoardAnchors.js.map +1 -0
  15. package/dist/src/data/board/udtGameBoard.js.map +1 -0
  16. package/dist/src/data/index.d.ts +19 -0
  17. package/dist/src/data/index.js +56 -0
  18. package/dist/src/data/index.js.map +1 -0
  19. package/dist/src/data/udtBoxInventory.d.ts +47 -0
  20. package/dist/src/data/udtBoxInventory.js +679 -0
  21. package/dist/src/data/udtBoxInventory.js.map +1 -0
  22. package/dist/src/{udtFoes.d.ts → data/udtFoes.d.ts} +1 -1
  23. package/dist/src/data/udtFoes.js.map +1 -0
  24. package/dist/src/data/udtGameContent.d.ts +418 -0
  25. package/dist/src/data/udtGameContent.js +293 -0
  26. package/dist/src/data/udtGameContent.js.map +1 -0
  27. package/dist/src/data/udtHeroes.js.map +1 -0
  28. package/dist/src/data/udtMonuments.js.map +1 -0
  29. package/dist/src/index.d.ts +2 -15
  30. package/dist/src/index.js +30 -55
  31. package/dist/src/index.js.map +1 -1
  32. package/dist/src/seed/index.d.ts +7 -0
  33. package/dist/src/seed/index.js +24 -0
  34. package/dist/src/seed/index.js.map +1 -0
  35. package/dist/src/seed/udtSeedParser.js.map +1 -0
  36. package/dist/src/{udtSystemRandom.d.ts → seed/udtSystemRandom.d.ts} +6 -0
  37. package/dist/src/{udtSystemRandom.js → seed/udtSystemRandom.js} +21 -2
  38. package/dist/src/seed/udtSystemRandom.js.map +1 -0
  39. package/dist/src/udtBleConnection.js +3 -2
  40. package/dist/src/udtBleConnection.js.map +1 -1
  41. package/dist/src/udtCommandFactory.d.ts +1 -1
  42. package/dist/src/udtCommandFactory.js +4 -2
  43. package/dist/src/udtCommandFactory.js.map +1 -1
  44. package/dist/src/udtDiagnostics.js +2 -1
  45. package/dist/src/udtDiagnostics.js.map +1 -1
  46. package/dist/src/udtHelpers.js +1 -4
  47. package/dist/src/udtHelpers.js.map +1 -1
  48. package/dist/src/udtLogger.js +11 -6
  49. package/dist/src/udtLogger.js.map +1 -1
  50. package/dist/src/udtTowerCommands.d.ts +10 -0
  51. package/dist/src/udtTowerCommands.js +66 -37
  52. package/dist/src/udtTowerCommands.js.map +1 -1
  53. package/dist/src/udtTowerResponse.d.ts +9 -0
  54. package/dist/src/udtTowerResponse.js +12 -1
  55. package/dist/src/udtTowerResponse.js.map +1 -1
  56. package/package.json +1 -1
  57. package/dist/src/udtBoardAdjacency.js.map +0 -1
  58. package/dist/src/udtBoardAnchors.js.map +0 -1
  59. package/dist/src/udtFoes.js.map +0 -1
  60. package/dist/src/udtGameBoard.js.map +0 -1
  61. package/dist/src/udtHeroes.js.map +0 -1
  62. package/dist/src/udtMonuments.js.map +0 -1
  63. package/dist/src/udtSeedParser.js.map +0 -1
  64. package/dist/src/udtSystemRandom.js.map +0 -1
  65. /package/dist/src/{udtBoardAdjacency.d.ts → data/board/udtBoardAdjacency.d.ts} +0 -0
  66. /package/dist/src/{udtBoardAdjacency.js → data/board/udtBoardAdjacency.js} +0 -0
  67. /package/dist/src/{udtBoardAnchors.d.ts → data/board/udtBoardAnchors.d.ts} +0 -0
  68. /package/dist/src/{udtBoardAnchors.js → data/board/udtBoardAnchors.js} +0 -0
  69. /package/dist/src/{udtGameBoard.d.ts → data/board/udtGameBoard.d.ts} +0 -0
  70. /package/dist/src/{udtGameBoard.js → data/board/udtGameBoard.js} +0 -0
  71. /package/dist/src/{udtFoes.js → data/udtFoes.js} +0 -0
  72. /package/dist/src/{udtHeroes.d.ts → data/udtHeroes.d.ts} +0 -0
  73. /package/dist/src/{udtHeroes.js → data/udtHeroes.js} +0 -0
  74. /package/dist/src/{udtMonuments.d.ts → data/udtMonuments.d.ts} +0 -0
  75. /package/dist/src/{udtMonuments.js → data/udtMonuments.js} +0 -0
  76. /package/dist/src/{udtSeedParser.d.ts → seed/udtSeedParser.d.ts} +0 -0
  77. /package/dist/src/{udtSeedParser.js → seed/udtSeedParser.js} +0 -0
package/CHANGELOG.md CHANGED
@@ -6,6 +6,57 @@ The format is based on [Keep a Changelog](https://keepachangelog.com/), and this
6
6
 
7
7
  ## [Unreleased]
8
8
 
9
+ ## [5.0.1] - 2026-07-03
10
+
11
+ ### Fixed
12
+
13
+ Fixes from a full-source code review, ordered by severity:
14
+
15
+ - **Node adapter: a failed `connect()` no longer permanently breaks retries.** `NodeBluetoothAdapter.cleanup()` was nulling the `onCharacteristicValueChanged`/`onDisconnect`/`onBluetoothAvailabilityChanged` callbacks on any connection failure, but `UdtBleConnection` only wires those callbacks once. A failed connect (e.g. a scan timeout) silently broke all future notifications on the next successful `connect()` — no battery heartbeat, no command responses, forcing a disconnect ~3s later. `cleanup()` no longer clears these caller-owned callback fields, matching `WebBluetoothAdapter`'s existing behavior.
16
+ - **Tower state aliasing fixed: `onTowerStateUpdate` now receives distinct old/new objects.** `getCurrentTowerState()` (both the internal command-builder dependency and the public method) previously returned the live state object (or a shallow copy sharing nested `layer`/`drum` objects), so commands that mutated it in place before calling `setTowerState` produced `oldState === newState` — consumers couldn't diff, and `logDetail` always logged "No changes detected". Both now return a full deep copy (`UdtCommandFactory.deepCopyTowerState`, now public). `createTransientAudioCommandWithModifications` also switched from a shallow spread to a deep copy, since its `Object.assign` calls on nested drum/layer/beam objects were mutating the caller's original state.
17
+ - **Drum-position tracking after rotation.** As a consequence of the above, `rotate()` and `rotateWithState()` — which mutated the (now-copied) state directly — needed explicit fixes: `rotate()` now calls `setTowerState` after updating drum positions so the change is actually recorded and notified; `rotateWithState()`'s `finally` block no longer force-writes all three drum positions unconditionally, since that masked partial failures (a drum that never rotated could be recorded as if it had) and was redundant on success (each `rotateDrumStateful()` call already records its own drum).
18
+ - **Send failures are no longer swallowed.** `sendTowerCommandDirect` returned normally instead of throwing when not connected or after retries were exhausted, so the command queue only ever learned of the failure via its 30s timeout — any command issued while disconnected silently hung for 30 seconds before rejecting with a misleading "Command timeout". It now throws immediately in both cases.
19
+ - **Calibration flags are now set before the command is sent**, not after `await`, so a fast calibration-complete response can't arrive before `performingCalibration` is set (which would suppress heartbeat disconnect detection and never fire `onCalibrationComplete`). The flags are cleared again if the send fails.
20
+ - **`logDetail` no longer discards the command queue.** Setting `tower.logDetail` used to reconstruct the whole `UdtTowerCommands`/`CommandQueue`, orphaning any in-flight/queued commands (they could then only resolve via their own 30s timeout, since responses routed to the new queue). It now updates the existing instance in place. `retrySendCommandMax` is likewise now a live setter instead of a value copied once at construction (previously it only "refreshed" as an accidental side effect of toggling `logDetail`).
21
+ - **`breakSeal` now syncs volume whenever it actually changes**, not just when the requested volume is truthy. Requesting volume `0` (Loud) while the tower's tracked volume was non-zero previously skipped the sync entirely, so the seal sound played at the wrong volume.
22
+ - **Removed duplicate console logging** — `Logger`'s constructor already installs a default `ConsoleOutput`; `UltimateDarkTower` was adding a second one, duplicating every default log line.
23
+ - **Unsolicited tower notifications no longer resolve the wrong queued command.** Spontaneous mechanical-sensor notifications (jiggle detection, unexpected trigger, differential readings) can arrive at any time and were being treated like a command ack, prematurely completing whatever command was in flight. These are now excluded from queue resolution while still reaching the public raw `onTowerResponse` passthrough.
24
+ - **`DOMOutput` no longer goes silent on pages without `logLevel-*` checkboxes** — it now defaults to showing all levels when none of the expected checkbox elements exist, instead of filtering out all output.
25
+ - Diagnostics `LIBRARY_VERSION` corrected from a stale `3.0.0` to `5.0.0`.
26
+ - **NodeBluetoothAdapter** no longer leaks a noble `stateChange` listener across repeated connect/disconnect cycles (it's now removed in `disconnect()`, not just `cleanup()`).
27
+ - **WebBluetoothAdapter** now cleans up partial connection state (GATT connection, listeners) when `connect()` fails partway through, matching the Node adapter's existing behavior.
28
+ - **Sound index validation tightened.** `playSound`/`playSoundStateful` were checking `soundIndex === null`, which let `undefined`/`NaN` silently through as a "valid" index; they now use `Number.isFinite`. `rotate()`'s optional `soundIndex` is now bounds-checked against the audio library (previously written unvalidated).
29
+ - `UdtBleConnection.disconnect()` no longer fires `onTowerDisconnect` (and clears the command queue) when called on a connection that was never established.
30
+ - Battery log line now correctly labels its already-volts value as `v` instead of `mv`.
31
+ - **`SystemRandom.nextRange`'s large-range branch (> `Int32.MaxValue`) now faithfully ports .NET's `GetSampleForLargeRange()`** instead of a rougher approximation, so seed-derived sequences match the reference implementation for wide ranges too.
32
+ - Disconnect detection in `sendTowerCommandDirect` now checks `instanceof BluetoothConnectionError` first, falling back to message-substring checks only for untyped native errors; removed a dead substring check that could never match.
33
+ - Removed the deprecated, uncalled `updateGlyphPositionsForRotation` method.
34
+ - `commandToPacketString` now zero-pads each byte to 2 hex digits (e.g. `[0f,03]` instead of `[f,3]`), removing ambiguity in packet dumps/logs.
35
+
36
+ ## [5.0.0] - 2026-06-20
37
+
38
+ ### Changed
39
+
40
+ - **BREAKING — reference/game data and the seed subsystem moved off the flat root API into the `data` and `seed` namespaces.** The library's exports are now split by concern: tower control / BLE / protocol stay at the root (`UltimateDarkTower`, adapters, state, logger, diagnostics, helpers, all `udtConstants` like `GLYPHS`/`TOWER_AUDIO_LIBRARY` — unchanged), while browseable reference data lives under `data.*` and the seed encode/decode + RNG subsystem under `seed.*`. The modules also moved on disk into `src/data/` (with `src/data/board/`) and `src/seed/`. Migrate imports:
41
+
42
+ | Old (flat, `'ultimatedarktower'`) | New |
43
+ |---|---|
44
+ | `HEROES`, `HERO_BY_ID`, `Hero`, `HeroId`, `ContentSource` | `data.heroes.*` |
45
+ | `MONUMENTS`, `MONUMENT_BY_ID`, `Monument`, `MonumentId` | `data.monuments.*` |
46
+ | `FOE_STATUSES`, `FOES`, `ADVERSARY_ROSTER`, `ALL_FOES`, `FOE_BY_ID`, `FOE_BY_NAME`, `FoeStatus`/`FoeLevel`/`FoeId`/`FoeName`/`Foe` | `data.foes.*` |
47
+ | `BOARD_LOCATIONS`, `BOARD_LOCATION_BY_NAME`, `BOARD_GROUPINGS`, `BOARD_ANCHORS`, `BOARD_IMAGE_INFO`, `BOARD_ADJACENCY`, `neighborsOf`, `stepDistance`, `shortestPath` + board types | `data.board.*` |
48
+ | seed fns (`charToValue`…`dumpSeedChars`), rosters (`TIER1_FOES`…`GAME_SOURCES`), seed types | `seed.*` |
49
+ | `SystemRandom` | `seed.SystemRandom` |
50
+
51
+ Example: `import { HEROES } from 'ultimatedarktower'` → `import { data } from 'ultimatedarktower'; data.heroes.HEROES`. Sub-namespacing also lets the two distinct hero/foe datasets coexist (board roster `data.heroes.HEROES` vs gameplay content `data.content.HEROES`). This is a major (v5.0.0) change; downstream consumers (`ultimatedarktowerboard`, `ultimatedarktowerdigital`) migrate to the namespaces and bump their dependency.
52
+
53
+ ### Added
54
+
55
+ - **`data.content` — gameplay reference content** (`src/data/udtGameContent.ts`). Keyed records with derived union types for the 10 playable heroes (`HEROES` with `defaultVirtues`/`unlockableVirtues`/`bannerAction`), the level 2–4 `FOES` and level-5 `ADVERSARIES`, `COMPANIONS`, and `KINGDOM_VIRTUES` (keyed East/North/South/West), plus list views (`heroes`/`foes`/`adversaries`/`companions`/`kingdomVirtues`). Uses the official spreadsheet wording — intentionally **not** reconciled with `TOWER_AUDIO_LIBRARY` keys (e.g. "Isa The Exile" vs the audio cue `IsatheHollow`).
56
+ - **`data.inventory` — box component counts** (`src/data/udtBoxInventory.ts`). `expansions` / `EXPANSIONS` (Base Game, Alliances, Covenant, Dark Horde) of categorized `Component` line-items, plus `coffers`, `coffers2`, `skullsPack`, and `sleeves`.
57
+
58
+ ## [4.1.0] - 2026-06-18
59
+
9
60
  ### Added
10
61
 
11
62
  - **`onTowerResponse` public callback (`UltimateDarkTower`).** A new assignable hook that fires with the **raw, verbatim bytes** (`Uint8Array`) of every non-battery tower notification (tower-state responses, command acknowledgements). It complements the decoded `onTowerStateUpdate` for consumers that need the exact packet rather than the parsed `TowerState` — e.g. a relay forwarding the tower's 20-byte state to other consumers. Documented in `docs/api/events.md`.