Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
2 changes: 1 addition & 1 deletion src/api/client.ts
Original file line number Diff line number Diff line change
Expand Up @@ -233,7 +233,7 @@ export function getTraceDetail(tag: string): Promise<TraceDetail> {

export async function getObserver(observerId: string): Promise<Observer> {
const observer = await request<Observer>(`/observers/${observerId}`);
// The server marshals the stored JSON byte slice as base64; decode it, and accept an object once json.RawMessage ships.
// Servers before json.RawMessage (and cache entries written by them) send the stored JSON as base64.
let metadata: unknown = observer.statusMetadata;
if (typeof metadata === "string") {
try { metadata = JSON.parse(new TextDecoder().decode(Uint8Array.from(atob(metadata), c => c.charCodeAt(0)))); }
Expand Down
4 changes: 2 additions & 2 deletions src/features/nodes/node-updates.ts
Original file line number Diff line number Diff line change
Expand Up @@ -18,8 +18,8 @@ export function patchNodeSummary(
// only name/coords move in practice; nodeType/iatas are near-static, so we drop data.nodeType here
// and let a reload carry a rare type change rather than keep a numeric-type lookup in sync
const name = data.name || prev.name;
const lat = data.lat ?? prev.lat;
const lng = data.lng ?? prev.lng;
const lat = data.lat === undefined ? prev.lat : data.lat;
const lng = data.lng === undefined ? prev.lng : data.lng;
const possiblyForeign = data.possiblyForeign === undefined ? prev.possiblyForeign : data.possiblyForeign ?? undefined;
// a re-advert that re-sends the same values must keep the SAME ref so patchInfinitePages no-ops
// (otherwise an unchanged node would trigger a full map FeatureCollection rebuild + setData)
Expand Down
6 changes: 3 additions & 3 deletions src/types/ws.ts
Original file line number Diff line number Diff line change
Expand Up @@ -110,9 +110,9 @@ export interface WsNodeUpdate {
// Omitted leaves the prior verdict unchanged; null clears an unknown/reset position.
possiblyForeign?: boolean | null;
iata: string;
// decimal degrees, same as REST /nodes (api/nodes.go serializes *float64 degrees to both)
lat?: number;
lng?: number;
// decimal degrees as in REST /nodes; omitted keeps the prior position, null clears it (explicit 0/0 advert)
lat?: number | null;
lng?: number | null;
isObserver: boolean;
iatas: NodeIATA[];
defaultScope?: string;
Expand Down
19 changes: 19 additions & 0 deletions tests/features/nodes/node-updates.test.ts
Original file line number Diff line number Diff line change
Expand Up @@ -68,6 +68,19 @@ describe("patchNodeSummary", () => {
expect(out[0]!.lng).toBe(20);
});

it("clears the position when the update sends explicit null", () => {
const list = [node({ id: "a", lat: 10, lng: 20 })];
const out = patchNodeSummary(list, update({ nodeId: "a", lat: null, lng: null }))!;
expect(out).not.toBe(list);
expect(out[0]!.lat).toBeNull();
expect(out[0]!.lng).toBeNull();
});

it("returns the same ref when a null clear hits a node that is already unlocated", () => {
const list = [node({ id: "a", name: "Keep", lat: null, lng: null })];
expect(patchNodeSummary(list, update({ nodeId: "a", name: "Keep", lat: null, lng: null }))).toBe(list);
});

it("returns the same list ref when the update changes nothing (no needless repaint)", () => {
const list = [node({ id: "a", name: "Keep", lat: 10, lng: 20 })];
// re-advert with identical name + omitted coords: every field resolves back to the prev value
Expand Down Expand Up @@ -114,4 +127,10 @@ describe("upsertNodePages", () => {
it("passes undefined caches through", () => {
expect(upsertNodePages(undefined, update({}))).toBeUndefined();
});

it("inserts a fresh node with an explicit null position", () => {
const old = pages([node({ id: "a" })]);
const out = upsertNodePages(old, update({ nodeId: "new1", lat: null, lng: null }))!;
expect(out.pages[0]!.items[1]).toMatchObject({ id: "new1", lat: null, lng: null });
});
});
Loading