Add node location access RPCs and operator visibility
This commit is contained in:
@@ -155,6 +155,64 @@ describe('system handlers', () => {
|
||||
expect(presence[0]?.channel).toBe('telegram');
|
||||
expect(getPath(result.result, 'summary')).toEqual({ total: 1, online: 1, offline: 0 });
|
||||
});
|
||||
|
||||
it('system.location returns empty result when getNodeLocations is not provided', async () => {
|
||||
const req: GatewayRequest = { id: 6, method: 'system.location' };
|
||||
const result = await handlers['system.location'](req) as GatewayResponse;
|
||||
expect(result.id).toBe(6);
|
||||
expect(getPath(result.result, 'locations')).toEqual([]);
|
||||
expect(getPath(result.result, 'summary')).toEqual({ total: 0 });
|
||||
});
|
||||
|
||||
it('system.location returns filtered node locations', async () => {
|
||||
const handlers = createSystemHandlers({
|
||||
...deps,
|
||||
getNodeLocations: ({ role, nodeId, limit } = {}) => {
|
||||
const all = [
|
||||
{
|
||||
nodeId: 'node-1',
|
||||
role: 'companion',
|
||||
connectionId: 'c1',
|
||||
location: {
|
||||
latitude: 37.7,
|
||||
longitude: -122.4,
|
||||
source: 'gps' as const,
|
||||
capturedAt: 1000,
|
||||
receivedAt: 1005,
|
||||
},
|
||||
},
|
||||
{
|
||||
nodeId: 'node-2',
|
||||
role: 'observer',
|
||||
connectionId: 'c2',
|
||||
location: {
|
||||
latitude: 40.7,
|
||||
longitude: -74.0,
|
||||
source: 'network' as const,
|
||||
capturedAt: 900,
|
||||
receivedAt: 905,
|
||||
},
|
||||
},
|
||||
];
|
||||
|
||||
return all
|
||||
.filter((entry) => !role || entry.role === role)
|
||||
.filter((entry) => !nodeId || entry.nodeId === nodeId)
|
||||
.slice(0, limit ?? 100);
|
||||
},
|
||||
});
|
||||
|
||||
const req: GatewayRequest = {
|
||||
id: 7,
|
||||
method: 'system.location',
|
||||
params: { role: 'companion', limit: 1 },
|
||||
};
|
||||
const result = await handlers['system.location'](req) as GatewayResponse;
|
||||
const locations = getPath(result.result, 'locations') as Array<{ nodeId: string }>;
|
||||
expect(locations).toHaveLength(1);
|
||||
expect(locations[0]?.nodeId).toBe('node-1');
|
||||
expect(getPath(result.result, 'summary')).toEqual({ total: 1 });
|
||||
});
|
||||
});
|
||||
|
||||
describe('system.tokenUsage handler', () => {
|
||||
@@ -731,6 +789,14 @@ describe('config handlers', () => {
|
||||
debounce_ms: 0,
|
||||
summarize_overflow: true,
|
||||
},
|
||||
nodes: {
|
||||
enabled: false,
|
||||
allowed_roles: ['companion'],
|
||||
feature_gates: {},
|
||||
location: {
|
||||
enabled: false,
|
||||
},
|
||||
},
|
||||
},
|
||||
models: {
|
||||
default: { provider: 'anthropic' as const, model: 'claude-3-haiku', api_key: 'sk-secret-key' },
|
||||
@@ -767,13 +833,14 @@ describe('config handlers', () => {
|
||||
'hooks.log': ['file.read'],
|
||||
'server.queue.mode': 'followup',
|
||||
'server.queue.debounce_ms': 100,
|
||||
'server.nodes.location.enabled': true,
|
||||
},
|
||||
},
|
||||
};
|
||||
const result = await handlers['config.patch'](req) as GatewayResponse;
|
||||
|
||||
const r = result.result as { applied: string[]; rejected: string[]; persisted: boolean };
|
||||
expect(r.applied).toEqual(['hooks.confirm', 'hooks.log', 'server.queue.mode', 'server.queue.debounce_ms']);
|
||||
expect(r.applied).toEqual(['hooks.confirm', 'hooks.log', 'server.queue.mode', 'server.queue.debounce_ms', 'server.nodes.location.enabled']);
|
||||
expect(r.rejected).toEqual([]);
|
||||
expect(r.persisted).toBe(false);
|
||||
// Verify the config was actually mutated
|
||||
@@ -781,6 +848,7 @@ describe('config handlers', () => {
|
||||
expect(config.hooks.log).toEqual(['file.read']);
|
||||
expect(config.server.queue.mode).toBe('followup');
|
||||
expect(config.server.queue.debounce_ms).toBe(100);
|
||||
expect(config.server.nodes.location.enabled).toBe(true);
|
||||
});
|
||||
|
||||
it('config.patch rejects unknown keys', async () => {
|
||||
|
||||
Reference in New Issue
Block a user