mirror of
https://github.com/okieselbach/AutopilotMonitor.git
synced 2026-10-25 13:10:13 +00:00
Compare commits
5 Commits
| Author | SHA1 | Date | |
|---|---|---|---|
| 0ed1e6f542 | |||
| 522911c5a7 | |||
| 0bfe1e327b | |||
| 2cf7216be5 | |||
| 587adc5ddf |
@@ -68,7 +68,12 @@ jobs:
|
||||
- name: Build MSI
|
||||
shell: pwsh
|
||||
run: |
|
||||
wix build "$env:MSI_PROJECT_DIR/Package.wxs" -arch x64 -o $env:STABLE_MSI
|
||||
# wix resolves File/@Source relative to the working directory, not the wxs —
|
||||
# build from inside the project dir (same as the local build documented in the wxs).
|
||||
$out = Join-Path (Get-Location) $env:STABLE_MSI
|
||||
Push-Location $env:MSI_PROJECT_DIR
|
||||
wix build Package.wxs -arch x64 -o $out
|
||||
Pop-Location
|
||||
if (-not (Test-Path $env:STABLE_MSI)) { Write-Error "wix build produced no MSI"; exit 1 }
|
||||
$sha256 = (Get-FileHash $env:STABLE_MSI -Algorithm SHA256).Hash.ToLowerInvariant()
|
||||
Write-Host "Built $env:STABLE_MSI ($([math]::Round((Get-Item $env:STABLE_MSI).Length / 1KB)) KB)"
|
||||
|
||||
+1
-1
@@ -629,7 +629,7 @@
|
||||
"category": "always",
|
||||
"pattern": "Failed to get AAD token\\..*?errorCode = (?<errorCode>.*?)$",
|
||||
"action": "imeTokenFailure",
|
||||
"description": "IME token acquisition failure ('Failed to get AAD token. len = N using client id ... and resource id ..., errorCode = N', IntuneTokenManager, IntuneManagementExtension.log). Complements IME-TOKEN-SUCCESS: an auth outage (WAM broken, conditional access, network) previously left every check-in silently doing nothing with no timeline evidence. errorCode can be empty when IME logged none; the agent dedups to one Warning per distinct code. Verified against IME 1.97 and 1.104 decompiled sources.",
|
||||
"description": "IME token acquisition failure ('Failed to get AAD token. len = N using client id ... and resource id ..., errorCode = N', IntuneTokenManager, IntuneManagementExtension.log). This line appears ROUTINELY during the device phase (no user token exists yet), so the agent holds the failure pending: any IME-TOKEN-SUCCESS match clears it, and the ime_token_failure Warning fires only when no success follows for the whole 30-min grace window (then deduped to one Warning per distinct errorCode). A genuine auth outage (WAM broken, conditional access, network) runs long enough to hit the window. Verified against IME 1.97 and 1.104 decompiled sources.",
|
||||
"enabled": true
|
||||
},
|
||||
{
|
||||
|
||||
@@ -4,6 +4,6 @@
|
||||
"category": "always",
|
||||
"pattern": "Failed to get AAD token\\..*?errorCode = (?<errorCode>.*?)$",
|
||||
"action": "imeTokenFailure",
|
||||
"description": "IME token acquisition failure ('Failed to get AAD token. len = N using client id ... and resource id ..., errorCode = N', IntuneTokenManager, IntuneManagementExtension.log). Complements IME-TOKEN-SUCCESS: an auth outage (WAM broken, conditional access, network) previously left every check-in silently doing nothing with no timeline evidence. errorCode can be empty when IME logged none; the agent dedups to one Warning per distinct code. Verified against IME 1.97 and 1.104 decompiled sources.",
|
||||
"description": "IME token acquisition failure ('Failed to get AAD token. len = N using client id ... and resource id ..., errorCode = N', IntuneTokenManager, IntuneManagementExtension.log). This line appears ROUTINELY during the device phase (no user token exists yet), so the agent holds the failure pending: any IME-TOKEN-SUCCESS match clears it, and the ime_token_failure Warning fires only when no success follows for the whole 30-min grace window (then deduped to one Warning per distinct errorCode). A genuine auth outage (WAM broken, conditional access, network) runs long enough to hit the window. Verified against IME 1.97 and 1.104 decompiled sources.",
|
||||
"enabled": true
|
||||
}
|
||||
|
||||
+34
@@ -119,6 +119,40 @@ namespace AutopilotMonitor.Agent.V2.Core.Tests.Monitoring.SystemSignals
|
||||
Assert.Equal("success", evt.Payload["enforcementClass"]);
|
||||
}
|
||||
|
||||
[Fact]
|
||||
public void NonEmpty_baseline_emits_one_summary_with_counts()
|
||||
{
|
||||
var (sink, clock, observer) = CreateObserver(trackerApps: null);
|
||||
var current = Snapshot((App1, 1000, 0), (App2, 5003, 101));
|
||||
|
||||
using (new ImeRegistryAppStateObserver.ScopedSnapshotOverride(() => current))
|
||||
{
|
||||
observer.Tick("baseline");
|
||||
observer.Tick("periodic"); // summary is one-shot, not per tick
|
||||
}
|
||||
|
||||
var summary = Assert.Single(Events(sink, SharedEventTypes.RegistryAppBaseline));
|
||||
Assert.Equal("2", summary.Payload!["totalApps"]);
|
||||
Assert.Equal("1", summary.Payload["successCount"]);
|
||||
Assert.Equal("1", summary.Payload["errorCount"]);
|
||||
// The baseline stays silent on the diff rail.
|
||||
Assert.Empty(Events(sink, SharedEventTypes.RegistryAppState));
|
||||
}
|
||||
|
||||
[Fact]
|
||||
public void Empty_baseline_emits_no_summary()
|
||||
{
|
||||
var (sink, clock, observer) = CreateObserver(trackerApps: null);
|
||||
var current = new ImeRegistrySnapshot();
|
||||
|
||||
using (new ImeRegistryAppStateObserver.ScopedSnapshotOverride(() => current))
|
||||
{
|
||||
observer.Tick("baseline");
|
||||
}
|
||||
|
||||
Assert.Empty(Events(sink, SharedEventTypes.RegistryAppBaseline));
|
||||
}
|
||||
|
||||
[Fact]
|
||||
public void Unchanged_snapshot_emits_nothing()
|
||||
{
|
||||
|
||||
+20
-4
@@ -479,16 +479,32 @@ namespace AutopilotMonitor.Agent.V2.Core.Tests.SignalAdapters
|
||||
}
|
||||
|
||||
[Fact]
|
||||
public void ImeTokenFailure_tracker_dedups_per_error_code()
|
||||
public void ImeTokenFailure_grace_window_emits_only_without_token_success()
|
||||
{
|
||||
// "Failed to get AAD token" appears routinely during the device phase (no user
|
||||
// token yet) — the Warning must fire only when NO success follows for the whole
|
||||
// grace window.
|
||||
using var f = new ImeLogTrackerAdapterFixture();
|
||||
using var adapter = new ImeLogTrackerAdapter(f.Tracker, f.Ingress, f.Clock);
|
||||
var t0 = DateTime.UtcNow;
|
||||
|
||||
// Failure resolved by a token success: never emitted, not even after the window.
|
||||
f.Tracker.HandleImeTokenFailureForTest("100", "line a");
|
||||
f.Tracker.HandleImeTokenFailureForTest("100", "line b"); // same code — suppressed
|
||||
f.Tracker.HandleImeTokenFailureForTest("200", "line c"); // new code — emitted
|
||||
f.Tracker.NoteTokenSuccessForTest();
|
||||
f.Tracker.CheckPendingTokenFailure(t0 + ImeLogTracker.TokenFailureGraceWindow + TimeSpan.FromMinutes(1));
|
||||
Assert.Empty(f.InfoEvents(SharedEventTypes.ImeTokenFailure));
|
||||
|
||||
Assert.Equal(2, f.InfoEvents(SharedEventTypes.ImeTokenFailure).Count);
|
||||
// Unresolved failure: silent before the window, one Warning after it.
|
||||
f.Tracker.HandleImeTokenFailureForTest("100", "line b");
|
||||
f.Tracker.CheckPendingTokenFailure(t0 + TimeSpan.FromMinutes(5));
|
||||
Assert.Empty(f.InfoEvents(SharedEventTypes.ImeTokenFailure));
|
||||
f.Tracker.CheckPendingTokenFailure(t0 + ImeLogTracker.TokenFailureGraceWindow + TimeSpan.FromHours(1));
|
||||
Assert.Single(f.InfoEvents(SharedEventTypes.ImeTokenFailure));
|
||||
|
||||
// Same code again: re-armed window expires but the per-code dedup suppresses.
|
||||
f.Tracker.HandleImeTokenFailureForTest("100", "line c");
|
||||
f.Tracker.CheckPendingTokenFailure(t0 + TimeSpan.FromHours(3));
|
||||
Assert.Single(f.InfoEvents(SharedEventTypes.ImeTokenFailure));
|
||||
}
|
||||
|
||||
[Fact]
|
||||
|
||||
+52
-7
@@ -25,25 +25,70 @@ namespace AutopilotMonitor.Agent.V2.Core.Monitoring.Enrollment.Ime
|
||||
private DateTime _impersonationLastRollupUtc = DateTime.MinValue;
|
||||
private static readonly TimeSpan ImpersonationRollupInterval = TimeSpan.FromSeconds(60);
|
||||
|
||||
// IME retries token acquisition on every check-in — dedup per distinct error
|
||||
// code so an outage yields one Warning, not a timeline flood.
|
||||
// "Failed to get AAD token" is logged ROUTINELY during the device phase (no user
|
||||
// token exists yet — field-confirmed: the line appears en masse in every enrollment,
|
||||
// Oliver 2026-08-18). A failure is therefore only meaningful when NO token success
|
||||
// follows: the failure is held pending, any IME-TOKEN-SUCCESS match clears it, and
|
||||
// the Warning fires only after the grace window elapses without a success. Genuine
|
||||
// auth outages (WAM broken, conditional access, network) run long enough to hit it.
|
||||
// Not persisted across restarts — failures keep arriving, the window re-arms.
|
||||
internal static readonly TimeSpan TokenFailureGraceWindow = TimeSpan.FromMinutes(30);
|
||||
|
||||
private sealed class PendingTokenFailure
|
||||
{
|
||||
public string Code = "unknown";
|
||||
public string Excerpt = string.Empty;
|
||||
public DateTime FirstFailureUtc;
|
||||
}
|
||||
|
||||
private PendingTokenFailure _pendingTokenFailure;
|
||||
// Dedup per distinct error code so a persistent outage yields one Warning total.
|
||||
private readonly HashSet<string> _reportedTokenFailureCodes = new HashSet<string>(StringComparer.OrdinalIgnoreCase);
|
||||
|
||||
private void HandleImeTokenFailure(string errorCode, string message)
|
||||
{
|
||||
var code = string.IsNullOrEmpty(errorCode) ? "unknown" : errorCode.Trim();
|
||||
if (!_reportedTokenFailureCodes.Add(code)) return;
|
||||
if (_pendingTokenFailure != null) return; // earliest unresolved failure wins
|
||||
|
||||
var code = string.IsNullOrEmpty(errorCode) ? "unknown" : errorCode.Trim();
|
||||
var excerpt = message ?? string.Empty;
|
||||
if (excerpt.Length > 300) excerpt = excerpt.Substring(0, 300);
|
||||
|
||||
_logger.Warning($"ImeLogTracker: IME token acquisition failure (errorCode={code})");
|
||||
OnImeTokenFailure?.Invoke(code, excerpt);
|
||||
_pendingTokenFailure = new PendingTokenFailure
|
||||
{
|
||||
Code = code,
|
||||
Excerpt = excerpt,
|
||||
// Source-line time so a late-starting agent replaying an ongoing outage
|
||||
// ages the window correctly; a success later in the same log still clears
|
||||
// before the expiry check runs (lines are drained first, expiry after).
|
||||
FirstFailureUtc = LastMatchedLogTimestamp ?? DateTime.UtcNow,
|
||||
};
|
||||
}
|
||||
|
||||
// Test seam: drives HandleImeTokenFailure without the regex pipeline.
|
||||
private void ClearPendingTokenFailure()
|
||||
{
|
||||
if (_pendingTokenFailure == null) return;
|
||||
_logger.Debug($"ImeLogTracker: token success observed — pending token failure (errorCode={_pendingTokenFailure.Code}) cleared");
|
||||
_pendingTokenFailure = null;
|
||||
}
|
||||
|
||||
/// <summary>Called once per poll cycle after the log drain (and testable directly).</summary>
|
||||
internal void CheckPendingTokenFailure(DateTime nowUtc)
|
||||
{
|
||||
var pending = _pendingTokenFailure;
|
||||
if (pending == null) return;
|
||||
if (nowUtc - pending.FirstFailureUtc < TokenFailureGraceWindow) return;
|
||||
|
||||
_pendingTokenFailure = null; // next failure line re-arms a fresh window
|
||||
if (!_reportedTokenFailureCodes.Add(pending.Code)) return;
|
||||
|
||||
_logger.Warning($"ImeLogTracker: IME token acquisition failing for >= {TokenFailureGraceWindow.TotalMinutes:0} min without a success (errorCode={pending.Code})");
|
||||
OnImeTokenFailure?.Invoke(pending.Code, pending.Excerpt);
|
||||
}
|
||||
|
||||
// Test seams: drive the pending/clear/expiry cycle without the regex pipeline.
|
||||
internal void HandleImeTokenFailureForTest(string errorCode, string message)
|
||||
=> HandleImeTokenFailure(errorCode, message);
|
||||
internal void NoteTokenSuccessForTest() => ClearPendingTokenFailure();
|
||||
|
||||
private void HandleImeImpersonation(string user)
|
||||
{
|
||||
|
||||
+8
@@ -244,6 +244,14 @@ namespace AutopilotMonitor.Agent.V2.Core.Monitoring.Enrollment.Ime
|
||||
return;
|
||||
}
|
||||
|
||||
// A token success resolves any pending token failure (grace-window model, see
|
||||
// HandleImeTokenFailure). Matched on our own stable pattern ID — the line also
|
||||
// drives espPhaseDetected, whose handler must stay unaware of token semantics.
|
||||
// Placed after the staleness gate so a success replayed from a previous
|
||||
// enrollment's log cannot clear a genuine current outage.
|
||||
if (!isStaleReplayLine && string.Equals(pattern.PatternId, "IME-TOKEN-SUCCESS", StringComparison.OrdinalIgnoreCase))
|
||||
ClearPendingTokenFailure();
|
||||
|
||||
try
|
||||
{
|
||||
var id = match.Groups["id"]?.Value;
|
||||
|
||||
@@ -607,6 +607,11 @@ namespace AutopilotMonitor.Agent.V2.Core.Monitoring.Enrollment.Ime
|
||||
// line never arrived within the grace period. Runs on this same loop
|
||||
// thread (no locking) so it observes the buffer right after parsing.
|
||||
FlushStalePlatformScriptResults(DateTime.UtcNow);
|
||||
|
||||
// Token-failure grace window: fires only when the failure stayed
|
||||
// unresolved (no IME-TOKEN-SUCCESS) for the whole window. Runs after
|
||||
// the drain so a success later in the same batch clears first.
|
||||
CheckPendingTokenFailure(DateTime.UtcNow);
|
||||
}
|
||||
catch (OperationCanceledException) { break; }
|
||||
catch (Exception ex)
|
||||
|
||||
+67
-1
@@ -119,9 +119,15 @@ namespace AutopilotMonitor.Agent.V2.Core.Monitoring.Enrollment.SystemSignals
|
||||
|
||||
if (_last == null)
|
||||
{
|
||||
// Silent baseline — see class doc.
|
||||
// Silent baseline for the DIFF stream — see class doc. But the baseline
|
||||
// itself is valuable evidence: on WDP the DPP-policy apps install in
|
||||
// Batch 1 BEFORE the agent (bootstrap = Batch 2), so their terminal
|
||||
// states exist ONLY here. One capped summary event closes that
|
||||
// pre-agent gap without any log backfill (Oliver, 2026-08-18).
|
||||
_last = snapshot;
|
||||
_logger?.Info($"RegistryAppState: baseline captured ({snapshot.Entries.Count} app entries, trigger={reason})");
|
||||
if (snapshot.Entries.Count > 0)
|
||||
EmitBaselineSummary(snapshot, nowUtc);
|
||||
return;
|
||||
}
|
||||
|
||||
@@ -181,6 +187,7 @@ namespace AutopilotMonitor.Agent.V2.Core.Monitoring.Enrollment.SystemSignals
|
||||
var entry = snapshot.GetOrAdd(userName, appId);
|
||||
entry.ExitCode = TryReadInt(appKey.GetValue("ExitCode"));
|
||||
entry.Intent = TryReadInt(appKey.GetValue("Intent"));
|
||||
entry.LastUpdatedUtc = appKey.GetValue("LastUpdatedTimeUtc") as string;
|
||||
|
||||
using var esm = appKey.OpenSubKey("EnforcementStateMessage");
|
||||
var json = esm?.GetValue("EnforcementStateMessage") as string;
|
||||
@@ -452,6 +459,64 @@ namespace AutopilotMonitor.Agent.V2.Core.Monitoring.Enrollment.SystemSignals
|
||||
occurredAtUtc: nowUtc);
|
||||
}
|
||||
|
||||
// Baseline entries in the summary's typed payload are capped — a long-lived device
|
||||
// with many historical Win32Apps entries must not produce an oversized event.
|
||||
internal const int MaxBaselineSummaryApps = 50;
|
||||
|
||||
private void EmitBaselineSummary(ImeRegistrySnapshot snapshot, DateTime nowUtc)
|
||||
{
|
||||
int success = 0, error = 0, inProgress = 0, other = 0;
|
||||
var apps = new List<Dictionary<string, string>>();
|
||||
foreach (var entry in snapshot.Entries.Values)
|
||||
{
|
||||
var cls = entry.EnforcementState is int es ? ClassifyEnforcementState(es) : null;
|
||||
switch (cls)
|
||||
{
|
||||
case "success": success++; break;
|
||||
case "error": error++; break;
|
||||
case "inProgress": inProgress++; break;
|
||||
default: other++; break;
|
||||
}
|
||||
|
||||
if (apps.Count >= MaxBaselineSummaryApps) continue;
|
||||
var app = new Dictionary<string, string>(StringComparer.Ordinal)
|
||||
{
|
||||
["appId"] = entry.AppId,
|
||||
["userContext"] = entry.UserContext,
|
||||
};
|
||||
if (entry.EnforcementState is int state)
|
||||
{
|
||||
app["enforcementState"] = state.ToString(CultureInfo.InvariantCulture);
|
||||
app["enforcementClass"] = ClassifyEnforcementState(state);
|
||||
}
|
||||
if (entry.ErrorCode is long ec) app["errorCode"] = ec.ToString(CultureInfo.InvariantCulture);
|
||||
if (entry.ExitCode is int xc) app["exitCode"] = xc.ToString(CultureInfo.InvariantCulture);
|
||||
if (!string.IsNullOrEmpty(entry.LastUpdatedUtc)) app["lastUpdatedUtc"] = entry.LastUpdatedUtc!;
|
||||
if (entry.EspTracked) app["espTracked"] = "true";
|
||||
apps.Add(app);
|
||||
}
|
||||
|
||||
var data = new Dictionary<string, string>(StringComparer.Ordinal)
|
||||
{
|
||||
["totalApps"] = snapshot.Entries.Count.ToString(CultureInfo.InvariantCulture),
|
||||
["successCount"] = success.ToString(CultureInfo.InvariantCulture),
|
||||
["errorCount"] = error.ToString(CultureInfo.InvariantCulture),
|
||||
["inProgressCount"] = inProgress.ToString(CultureInfo.InvariantCulture),
|
||||
["otherCount"] = other.ToString(CultureInfo.InvariantCulture),
|
||||
};
|
||||
if (snapshot.Entries.Count > MaxBaselineSummaryApps)
|
||||
data["appListTruncated"] = "true";
|
||||
|
||||
_post.Emit(
|
||||
eventType: SharedEventTypes.RegistryAppBaseline,
|
||||
source: SourceLabel,
|
||||
message: $"Registry app baseline at agent start: {snapshot.Entries.Count} apps ({success} success, {error} error, {inProgress} in progress) — state that predates this agent run",
|
||||
severity: EventSeverity.Info,
|
||||
data: data,
|
||||
occurredAtUtc: nowUtc,
|
||||
typedPayload: new { apps });
|
||||
}
|
||||
|
||||
private void TrackTerminalTransitions(ImeRegistrySnapshot snapshot, DateTime nowUtc)
|
||||
{
|
||||
foreach (var kv in snapshot.Entries)
|
||||
@@ -552,6 +617,7 @@ namespace AutopilotMonitor.Agent.V2.Core.Monitoring.Enrollment.SystemSignals
|
||||
public string Key { get; }
|
||||
public string UserContext { get; }
|
||||
public string AppId { get; }
|
||||
public string? LastUpdatedUtc { get; set; }
|
||||
public int? EnforcementState { get; set; }
|
||||
public long? ErrorCode { get; set; }
|
||||
public int? ExitCode { get; set; }
|
||||
|
||||
+4
-4
@@ -24,7 +24,7 @@
|
||||
"@types/compression": "^1.8.1",
|
||||
"@types/express": "^5.0.6",
|
||||
"@types/node": "^22.20.1",
|
||||
"tsx": "^4.23.11",
|
||||
"tsx": "^4.23.12",
|
||||
"typescript": "^5.0.0",
|
||||
"vitest": "^4.1.10"
|
||||
},
|
||||
@@ -3823,9 +3823,9 @@
|
||||
"optional": true
|
||||
},
|
||||
"node_modules/tsx": {
|
||||
"version": "4.23.11",
|
||||
"resolved": "https://registry.npmjs.org/tsx/-/tsx-4.23.11.tgz",
|
||||
"integrity": "sha512-Ry2oTEUnhBdeEdWIztY8kf3/nBGnPnjMLVGL0YfdRXMORuPER5NlKmayqxtxRxwB1xBN+RivRaJfe7PM1rtiyw==",
|
||||
"version": "4.23.12",
|
||||
"resolved": "https://registry.npmjs.org/tsx/-/tsx-4.23.12.tgz",
|
||||
"integrity": "sha512-FDf4L4sYzKtzWYhU/Xm0AQFdTjdIxNo9ElTf2mxXM6k8YMHXzYUe4yODVaXP4V9uMFbVg8c0qyBccK2OOxb45Q==",
|
||||
"dev": true,
|
||||
"license": "MIT",
|
||||
"dependencies": {
|
||||
|
||||
@@ -32,7 +32,7 @@
|
||||
"@types/compression": "^1.8.1",
|
||||
"@types/express": "^5.0.6",
|
||||
"@types/node": "^22.20.1",
|
||||
"tsx": "^4.23.11",
|
||||
"tsx": "^4.23.12",
|
||||
"typescript": "^5.0.0",
|
||||
"vitest": "^4.1.10"
|
||||
},
|
||||
|
||||
@@ -148,6 +148,7 @@ export const EVENT_TYPES_CATALOG = {
|
||||
'ime_agent_version',
|
||||
'ime_token_failure',
|
||||
'registry_app_state',
|
||||
'registry_app_baseline',
|
||||
'app_state_reconciliation',
|
||||
'ime_user_session_completed',
|
||||
'ime_session_change',
|
||||
|
||||
@@ -421,6 +421,7 @@ namespace AutopilotMonitor.Shared
|
||||
// per-app state read straight from HKLM\...\IntuneManagementExtension. Observability only —
|
||||
// never consumed by the DecisionEngine.
|
||||
public const string RegistryAppState = "registry_app_state"; // Info, state-change-only (snapshot-diff vs silent startup baseline; capped 200/session, cap announced once as Warning): per-app EnforcementState/ErrorCode/ExitCode/StatusService status/ESP-tracking from the registry.
|
||||
public const string RegistryAppBaseline = "registry_app_baseline"; // Info, one-shot at agent start (only when non-empty): summary of the Win32Apps state that PREDATES this agent run. Closes the WDP pre-agent gap — DPP-policy apps install in Batch 1 before the bootstrap-script agent exists, so their outcomes live only in this baseline (typed payload capped at 50 apps).
|
||||
public const string AppStateReconciliation = "app_state_reconciliation"; // Warning, once per app, immediate upload: registry terminal outcome (settled >= 90 s) diverges from the IME-log-derived app state — the built-in log-pattern drift alarm (registry = truth, logs = narrative).
|
||||
public const string ImeUserSessionCompleted = "ime_user_session_completed";
|
||||
public const string DoTelemetry = "do_telemetry";
|
||||
|
||||
+64
-64
@@ -13,25 +13,25 @@
|
||||
"@microsoft/applicationinsights-web": "^3.4.3",
|
||||
"@microsoft/signalr": "^10.0.11",
|
||||
"@types/leaflet": "^1.9.22",
|
||||
"@xyflow/react": "^12.11.2",
|
||||
"@xyflow/react": "^12.11.3",
|
||||
"dagre": "^0.8.5",
|
||||
"fflate": "^0.8.3",
|
||||
"leaflet": "^1.9.4",
|
||||
"next": "^16.3.0",
|
||||
"next": "^16.3.1",
|
||||
"react": "^19.2.8",
|
||||
"react-dom": "^19.2.8",
|
||||
"react-leaflet": "^5.0.0",
|
||||
"recharts": "^2.15.4"
|
||||
},
|
||||
"devDependencies": {
|
||||
"@next/bundle-analyzer": "^16.3.0",
|
||||
"@next/bundle-analyzer": "^16.3.1",
|
||||
"@types/dagre": "^0.7.54",
|
||||
"@types/node": "^22.20.1",
|
||||
"@types/react": "^19",
|
||||
"@types/react-dom": "^19",
|
||||
"autoprefixer": "^10.5.4",
|
||||
"eslint": "^9.39.5",
|
||||
"eslint-config-next": "^16.3.0",
|
||||
"eslint-config-next": "^16.3.1",
|
||||
"postcss": "^8.5.12",
|
||||
"tailwindcss": "^3.4.17",
|
||||
"typescript": "^5.7.3",
|
||||
@@ -1358,9 +1358,9 @@
|
||||
"license": "MIT"
|
||||
},
|
||||
"node_modules/@next/bundle-analyzer": {
|
||||
"version": "16.3.0",
|
||||
"resolved": "https://registry.npmjs.org/@next/bundle-analyzer/-/bundle-analyzer-16.3.0.tgz",
|
||||
"integrity": "sha512-o8OiXKIATcSC6kHm5BIEmaDEDTFUDhpy9POQIbzAQTlb8NWwFhEQheTLFSbyQXxH2ywhjZ/e8EUlbOjj2k22Yg==",
|
||||
"version": "16.3.1",
|
||||
"resolved": "https://registry.npmjs.org/@next/bundle-analyzer/-/bundle-analyzer-16.3.1.tgz",
|
||||
"integrity": "sha512-/6XQeYPHM6jF1gTeJ82Mu6yXOHQIFVxzAn3DkPtHDp5v6SDXoCicBMTHloN+2h4WKFCQujSLCgLZHItJ3jN1uw==",
|
||||
"dev": true,
|
||||
"license": "MIT",
|
||||
"dependencies": {
|
||||
@@ -1368,15 +1368,15 @@
|
||||
}
|
||||
},
|
||||
"node_modules/@next/env": {
|
||||
"version": "16.3.0",
|
||||
"resolved": "https://registry.npmjs.org/@next/env/-/env-16.3.0.tgz",
|
||||
"integrity": "sha512-o9r1S0BNiNreHP9Vs+Qnqd9kviDkJh8xIACY7UFZSmiGbbQRzPBBosvHzAU4TULHOIuOj/18RSsyz2qrREmIFw==",
|
||||
"version": "16.3.1",
|
||||
"resolved": "https://registry.npmjs.org/@next/env/-/env-16.3.1.tgz",
|
||||
"integrity": "sha512-35G3xwkQUb2oETSDjFXGrVugknoayLFBh7vSE+yAcl9IP2zT9wyGwq7297AYHR11kJld807t5f8AJBs6WBzXsQ==",
|
||||
"license": "MIT"
|
||||
},
|
||||
"node_modules/@next/eslint-plugin-next": {
|
||||
"version": "16.3.0",
|
||||
"resolved": "https://registry.npmjs.org/@next/eslint-plugin-next/-/eslint-plugin-next-16.3.0.tgz",
|
||||
"integrity": "sha512-OqgJ8PN0d04KcPhDX/PTY5tJUJZxlbrt7O7FBsm4XE0XW2JDrKnDXsc9uo9WUimJGPoo2j+JRGhyXApC//mvbw==",
|
||||
"version": "16.3.1",
|
||||
"resolved": "https://registry.npmjs.org/@next/eslint-plugin-next/-/eslint-plugin-next-16.3.1.tgz",
|
||||
"integrity": "sha512-B4SznlXwVpaLDa7Tbi6zLuueria2d/PmFDhXyDymPGrk2r1n/RMJmcn5FZq1L64k+Jsyte1lKvOr7lP9Xo80mQ==",
|
||||
"dev": true,
|
||||
"license": "MIT",
|
||||
"dependencies": {
|
||||
@@ -1385,9 +1385,9 @@
|
||||
}
|
||||
},
|
||||
"node_modules/@next/swc-darwin-arm64": {
|
||||
"version": "16.3.0",
|
||||
"resolved": "https://registry.npmjs.org/@next/swc-darwin-arm64/-/swc-darwin-arm64-16.3.0.tgz",
|
||||
"integrity": "sha512-55hpqq18bEVAlxedlTt3tFqZmKg2nUXT1kn1G/BGEy0R13h3LwtwHPVzzjG6P4LLeOHE32PFDQUVaJEWvBEZBw==",
|
||||
"version": "16.3.1",
|
||||
"resolved": "https://registry.npmjs.org/@next/swc-darwin-arm64/-/swc-darwin-arm64-16.3.1.tgz",
|
||||
"integrity": "sha512-ABMIu2zQ7cnNIHm5ivKGwZwUrm0pAai3yiJ/gK/rF1c1VP9UOnj7XECbMKFdVKp9I9eMYq9NoDs1WXOoowxzJw==",
|
||||
"cpu": [
|
||||
"arm64"
|
||||
],
|
||||
@@ -1401,9 +1401,9 @@
|
||||
}
|
||||
},
|
||||
"node_modules/@next/swc-darwin-x64": {
|
||||
"version": "16.3.0",
|
||||
"resolved": "https://registry.npmjs.org/@next/swc-darwin-x64/-/swc-darwin-x64-16.3.0.tgz",
|
||||
"integrity": "sha512-SOi96kSaF5T+0wW4koiM1bWzSPwjzTesC1p3df+FjdOi5LIQkBK/blxh7HdoKnNuI4PURF1OO7TZqtfnbWDSgw==",
|
||||
"version": "16.3.1",
|
||||
"resolved": "https://registry.npmjs.org/@next/swc-darwin-x64/-/swc-darwin-x64-16.3.1.tgz",
|
||||
"integrity": "sha512-gNG21e/UnrroeScbY/QndUEdl0mF1FRibW7BBeYUz/5ABCepjqDdEdgr592vpzMtCn/m7FTjYq3TN4TpyDnutw==",
|
||||
"cpu": [
|
||||
"x64"
|
||||
],
|
||||
@@ -1417,9 +1417,9 @@
|
||||
}
|
||||
},
|
||||
"node_modules/@next/swc-linux-arm64-gnu": {
|
||||
"version": "16.3.0",
|
||||
"resolved": "https://registry.npmjs.org/@next/swc-linux-arm64-gnu/-/swc-linux-arm64-gnu-16.3.0.tgz",
|
||||
"integrity": "sha512-P0gZAoPMF4dyTRzhmkV4PrqVzSOB6t4mC1oI3c4dqijJ+OVEVx5clIXAKR4/uQpsqw2KKM/0D5tVumcR2r5blg==",
|
||||
"version": "16.3.1",
|
||||
"resolved": "https://registry.npmjs.org/@next/swc-linux-arm64-gnu/-/swc-linux-arm64-gnu-16.3.1.tgz",
|
||||
"integrity": "sha512-6B6Lw016iwNUQuaJoraMMTLh6TwHzFUtxipSScD1F3YyymcrRWkobodRS2ftIOkF5vrs4zNlyUrTC5YZQ9Lz5w==",
|
||||
"cpu": [
|
||||
"arm64"
|
||||
],
|
||||
@@ -1436,9 +1436,9 @@
|
||||
}
|
||||
},
|
||||
"node_modules/@next/swc-linux-arm64-musl": {
|
||||
"version": "16.3.0",
|
||||
"resolved": "https://registry.npmjs.org/@next/swc-linux-arm64-musl/-/swc-linux-arm64-musl-16.3.0.tgz",
|
||||
"integrity": "sha512-tXXGKJw0m37O0eKJARVTX/TheKPhz0QFVtVVZXmOig+9YKLQOSP6hvf2pxv5DO7CLEJyTHx3Pg043CDQkv1G4Q==",
|
||||
"version": "16.3.1",
|
||||
"resolved": "https://registry.npmjs.org/@next/swc-linux-arm64-musl/-/swc-linux-arm64-musl-16.3.1.tgz",
|
||||
"integrity": "sha512-JUiPXZKK9wOhjf4MgDiH29GZLxfqOesbLtHq2pDxwH/WwscTRV2ToymnOTh1egzaZf0ueUf8T2+CeYTGHjW0Iw==",
|
||||
"cpu": [
|
||||
"arm64"
|
||||
],
|
||||
@@ -1455,9 +1455,9 @@
|
||||
}
|
||||
},
|
||||
"node_modules/@next/swc-linux-x64-gnu": {
|
||||
"version": "16.3.0",
|
||||
"resolved": "https://registry.npmjs.org/@next/swc-linux-x64-gnu/-/swc-linux-x64-gnu-16.3.0.tgz",
|
||||
"integrity": "sha512-pjGxK5EY7yWml78ALejFkWmgHsU7wbFQrISiugpH6FbUJhgEvw3xFZ/EBAtLl7QtL0WdQKiG9eWJ3mOKGTukHw==",
|
||||
"version": "16.3.1",
|
||||
"resolved": "https://registry.npmjs.org/@next/swc-linux-x64-gnu/-/swc-linux-x64-gnu-16.3.1.tgz",
|
||||
"integrity": "sha512-Uog9jsrmIRIL/lfvIp9htmskSNC7JcQsMVucXL2V2YY1y/D9IUN3LPEafqy0zRJ2cIU1SQ0V6F6TlffQ+pLAGg==",
|
||||
"cpu": [
|
||||
"x64"
|
||||
],
|
||||
@@ -1474,9 +1474,9 @@
|
||||
}
|
||||
},
|
||||
"node_modules/@next/swc-linux-x64-musl": {
|
||||
"version": "16.3.0",
|
||||
"resolved": "https://registry.npmjs.org/@next/swc-linux-x64-musl/-/swc-linux-x64-musl-16.3.0.tgz",
|
||||
"integrity": "sha512-sjo++Xx+lomlPs3HRsHWhVDyGG6ms1kGW5EtHLERdII8AyG1i+f6aq68xHREO6AEMlhjTNEWBSmfJfqm9orf7g==",
|
||||
"version": "16.3.1",
|
||||
"resolved": "https://registry.npmjs.org/@next/swc-linux-x64-musl/-/swc-linux-x64-musl-16.3.1.tgz",
|
||||
"integrity": "sha512-6yy3FT13KgUFOj5H8bl8w/6nKiJwHIvbtwh1V+1acsu+7y4tJjnemSa6mhsh53BeoVrlozE+fMgZhXH46WmjMA==",
|
||||
"cpu": [
|
||||
"x64"
|
||||
],
|
||||
@@ -1493,9 +1493,9 @@
|
||||
}
|
||||
},
|
||||
"node_modules/@next/swc-win32-arm64-msvc": {
|
||||
"version": "16.3.0",
|
||||
"resolved": "https://registry.npmjs.org/@next/swc-win32-arm64-msvc/-/swc-win32-arm64-msvc-16.3.0.tgz",
|
||||
"integrity": "sha512-C5JSgiO54wURdaxdEUIXqkz04uMqC9UmPX1gtDrV/5Tf1UowdWYI8uA5hfFbPolTlp0q4KZ60xlHePNibf0VIw==",
|
||||
"version": "16.3.1",
|
||||
"resolved": "https://registry.npmjs.org/@next/swc-win32-arm64-msvc/-/swc-win32-arm64-msvc-16.3.1.tgz",
|
||||
"integrity": "sha512-iOoN1QecUoGNZik536U/vtK43YwgyrCsGIkth52yIkl612n+0C9MjSnJbQAikISpb+WYRooBVhaDlUW7iZoKog==",
|
||||
"cpu": [
|
||||
"arm64"
|
||||
],
|
||||
@@ -1890,9 +1890,9 @@
|
||||
"license": "MIT"
|
||||
},
|
||||
"node_modules/@swc/helpers": {
|
||||
"version": "0.5.15",
|
||||
"resolved": "https://registry.npmjs.org/@swc/helpers/-/helpers-0.5.15.tgz",
|
||||
"integrity": "sha512-JQ5TuMi45Owi4/BIMAJBoSQoOJu12oOk/gADqlcUL9JEdHB8vyjUSsxqeNXnmXHjYKMi2WcYtezGEEhqUI/E2g==",
|
||||
"version": "0.5.23",
|
||||
"resolved": "https://registry.npmjs.org/@swc/helpers/-/helpers-0.5.23.tgz",
|
||||
"integrity": "sha512-5lSsMOTXURePglDfvuAQUqkGek9Hg2kksOYay2m0+XR++b2NWYL/4sWyuvVBIs8oKnJaxkdi9whaL/sqN13afw==",
|
||||
"license": "Apache-2.0",
|
||||
"dependencies": {
|
||||
"tslib": "^2.8.0"
|
||||
@@ -2762,12 +2762,12 @@
|
||||
}
|
||||
},
|
||||
"node_modules/@xyflow/react": {
|
||||
"version": "12.11.2",
|
||||
"resolved": "https://registry.npmjs.org/@xyflow/react/-/react-12.11.2.tgz",
|
||||
"integrity": "sha512-eLAlDWJfWnQEhJwGMjlWdAXO9eYllKpliUmPQlAmOLxz6mExXuzMVDUKLMquixgkrtmMFFtug3jGKmYYld12cA==",
|
||||
"version": "12.11.3",
|
||||
"resolved": "https://registry.npmjs.org/@xyflow/react/-/react-12.11.3.tgz",
|
||||
"integrity": "sha512-G3jogHz2GWUtIOkhavUGno2YzY9u6fILIJBttfsBendb0/HWB90JG+sOTAvlIMEwyvq9zgy9V9ZQSwyQjR5QzQ==",
|
||||
"license": "MIT",
|
||||
"dependencies": {
|
||||
"@xyflow/system": "0.0.79",
|
||||
"@xyflow/system": "0.0.80",
|
||||
"classcat": "^5.0.3",
|
||||
"zustand": "^4.4.0"
|
||||
},
|
||||
@@ -2787,9 +2787,9 @@
|
||||
}
|
||||
},
|
||||
"node_modules/@xyflow/system": {
|
||||
"version": "0.0.79",
|
||||
"resolved": "https://registry.npmjs.org/@xyflow/system/-/system-0.0.79.tgz",
|
||||
"integrity": "sha512-czLyOh91NF0hIzbNzwi8I6GlqG23BHh2435OddfI6uiaLH3xdrdygO93gqgH1Bv9mhy8XPFQJOBn1FTq4LvEWA==",
|
||||
"version": "0.0.80",
|
||||
"resolved": "https://registry.npmjs.org/@xyflow/system/-/system-0.0.80.tgz",
|
||||
"integrity": "sha512-ywc3ZqG91brzWrH1WlwMdIX4goOfrpBy6AbLdVSaof/Xx9l138ijIKRExM6EkMro2F+OImGmSiA/WKcXvKVcfA==",
|
||||
"license": "MIT",
|
||||
"dependencies": {
|
||||
"@types/d3-drag": "^3.0.7",
|
||||
@@ -4216,13 +4216,13 @@
|
||||
}
|
||||
},
|
||||
"node_modules/eslint-config-next": {
|
||||
"version": "16.3.0",
|
||||
"resolved": "https://registry.npmjs.org/eslint-config-next/-/eslint-config-next-16.3.0.tgz",
|
||||
"integrity": "sha512-lPrf1kHsMJEZqO0uXkNB400c5MGrhrTk3BNX7P0ol4gt61+iUlQfjy9TyIOEA9eOXrf+5+mYbT/JsY8+zqUByQ==",
|
||||
"version": "16.3.1",
|
||||
"resolved": "https://registry.npmjs.org/eslint-config-next/-/eslint-config-next-16.3.1.tgz",
|
||||
"integrity": "sha512-0vtrpwFVHFEkycUgV/DyrG29OS+HSRdah5Yu8YuZoiBMtlAT6NIiWzaLwDkJZxr2kGfx+9LIvfQ7KHAlEs0VsA==",
|
||||
"dev": true,
|
||||
"license": "MIT",
|
||||
"dependencies": {
|
||||
"@next/eslint-plugin-next": "16.3.0",
|
||||
"@next/eslint-plugin-next": "16.3.1",
|
||||
"eslint-import-resolver-node": "^0.3.6",
|
||||
"eslint-import-resolver-typescript": "^3.5.2",
|
||||
"eslint-plugin-import": "^2.32.0",
|
||||
@@ -6308,13 +6308,13 @@
|
||||
"license": "MIT"
|
||||
},
|
||||
"node_modules/next": {
|
||||
"version": "16.3.0",
|
||||
"resolved": "https://registry.npmjs.org/next/-/next-16.3.0.tgz",
|
||||
"integrity": "sha512-NEdGOzH+08eTXMUp9UYkA99Nhi5N6Thrhc1jgFOQgfgnGK/dA2hRwBpXep+exdFQrnwlRf/3Wixyp8lLBUpE2A==",
|
||||
"version": "16.3.1",
|
||||
"resolved": "https://registry.npmjs.org/next/-/next-16.3.1.tgz",
|
||||
"integrity": "sha512-hsAp0i7Rh+/dhe7DGIeN2YlpLM1DP4MNxti9EtDMtqcO612X81MvvEj388/oTce9U1EcEIOWDlGq0zRwrBKvuA==",
|
||||
"license": "MIT",
|
||||
"dependencies": {
|
||||
"@next/env": "16.3.0",
|
||||
"@swc/helpers": "0.5.15",
|
||||
"@next/env": "16.3.1",
|
||||
"@swc/helpers": "0.5.23",
|
||||
"baseline-browser-mapping": "^2.9.19",
|
||||
"caniuse-lite": "^1.0.30001579",
|
||||
"postcss": "8.5.23",
|
||||
@@ -6327,14 +6327,14 @@
|
||||
"node": ">=20.9.0"
|
||||
},
|
||||
"optionalDependencies": {
|
||||
"@next/swc-darwin-arm64": "16.3.0",
|
||||
"@next/swc-darwin-x64": "16.3.0",
|
||||
"@next/swc-linux-arm64-gnu": "16.3.0",
|
||||
"@next/swc-linux-arm64-musl": "16.3.0",
|
||||
"@next/swc-linux-x64-gnu": "16.3.0",
|
||||
"@next/swc-linux-x64-musl": "16.3.0",
|
||||
"@next/swc-win32-arm64-msvc": "16.3.0",
|
||||
"@next/swc-win32-x64-msvc": "16.3.0",
|
||||
"@next/swc-darwin-arm64": "16.3.1",
|
||||
"@next/swc-darwin-x64": "16.3.1",
|
||||
"@next/swc-linux-arm64-gnu": "16.3.1",
|
||||
"@next/swc-linux-arm64-musl": "16.3.1",
|
||||
"@next/swc-linux-x64-gnu": "16.3.1",
|
||||
"@next/swc-linux-x64-musl": "16.3.1",
|
||||
"@next/swc-win32-arm64-msvc": "16.3.1",
|
||||
"@next/swc-win32-x64-msvc": "16.3.1",
|
||||
"sharp": "^0.35.3"
|
||||
},
|
||||
"peerDependencies": {
|
||||
@@ -6361,9 +6361,9 @@
|
||||
}
|
||||
},
|
||||
"node_modules/next/node_modules/@next/swc-win32-x64-msvc": {
|
||||
"version": "16.3.0",
|
||||
"resolved": "https://registry.npmjs.org/@next/swc-win32-x64-msvc/-/swc-win32-x64-msvc-16.3.0.tgz",
|
||||
"integrity": "sha512-fDOggsweNb5SSw0ZKVk6U+gxSyGFFlIBY/LBc1r8GUj4u/6t6oArL+Pmkg0MBnsgR+KkdsURilVH4F3GXUGepA==",
|
||||
"version": "16.3.1",
|
||||
"resolved": "https://registry.npmjs.org/@next/swc-win32-x64-msvc/-/swc-win32-x64-msvc-16.3.1.tgz",
|
||||
"integrity": "sha512-d/k+PpAriUPaeMJJOG7HUSdqfEX46FEPWU1p3/nm2ACmXhj9hFEWdFODUBIpkuijXYkfL90qZzTqVPRp4BW/hw==",
|
||||
"cpu": [
|
||||
"x64"
|
||||
],
|
||||
|
||||
@@ -20,25 +20,25 @@
|
||||
"@microsoft/applicationinsights-web": "^3.4.3",
|
||||
"@microsoft/signalr": "^10.0.11",
|
||||
"@types/leaflet": "^1.9.22",
|
||||
"@xyflow/react": "^12.11.2",
|
||||
"@xyflow/react": "^12.11.3",
|
||||
"dagre": "^0.8.5",
|
||||
"fflate": "^0.8.3",
|
||||
"leaflet": "^1.9.4",
|
||||
"next": "^16.3.0",
|
||||
"next": "^16.3.1",
|
||||
"react": "^19.2.8",
|
||||
"react-dom": "^19.2.8",
|
||||
"react-leaflet": "^5.0.0",
|
||||
"recharts": "^2.15.4"
|
||||
},
|
||||
"devDependencies": {
|
||||
"@next/bundle-analyzer": "^16.3.0",
|
||||
"@next/bundle-analyzer": "^16.3.1",
|
||||
"@types/dagre": "^0.7.54",
|
||||
"@types/node": "^22.20.1",
|
||||
"@types/react": "^19",
|
||||
"@types/react-dom": "^19",
|
||||
"autoprefixer": "^10.5.4",
|
||||
"eslint": "^9.39.5",
|
||||
"eslint-config-next": "^16.3.0",
|
||||
"eslint-config-next": "^16.3.1",
|
||||
"postcss": "^8.5.12",
|
||||
"tailwindcss": "^3.4.17",
|
||||
"typescript": "^5.7.3",
|
||||
|
||||
@@ -604,6 +604,7 @@ export const SHARED_MANIFEST = {
|
||||
"realmjoin_resolved",
|
||||
"realmjoin_timeout",
|
||||
"reboot_triggered",
|
||||
"registry_app_baseline",
|
||||
"registry_app_state",
|
||||
"remote_config_fetch_failed",
|
||||
"script_completed",
|
||||
|
||||
@@ -600,6 +600,7 @@
|
||||
"realmjoin_resolved",
|
||||
"realmjoin_timeout",
|
||||
"reboot_triggered",
|
||||
"registry_app_baseline",
|
||||
"registry_app_state",
|
||||
"remote_config_fetch_failed",
|
||||
"script_completed",
|
||||
|
||||
Reference in New Issue
Block a user