diff --git a/src/features/device-state/index.ts b/src/features/device-state/index.ts index 0c556cc46..30d34f0bd 100644 --- a/src/features/device-state/index.ts +++ b/src/features/device-state/index.ts @@ -3,6 +3,7 @@ import type StrictEventEmitter from 'strict-event-emitter-types'; import { EventEmitter } from 'events'; import { middleware } from '../../infra/auth'; +import type { Device } from '../../balena-model'; import { resolveOrDenyDevicesWithStatus } from './middleware'; import { stateV2 } from './routes/state-get-v2'; @@ -14,9 +15,10 @@ import { statePatchV3, } from './routes/state-patch-v3'; import { fleetStateV3 } from './routes/fleet-state-get-v3'; -import { Device } from '../../balena-model'; +import type { GetStateEventStoredDeviceFields } from './state-get-utils'; export { + getStateEventAdditionalFields, getConfig, setReadTransaction, filterDeviceConfig, @@ -74,7 +76,10 @@ export interface Events { info: Pick & { config?: Dictionary; ipAddress: string | undefined; + // TODO: Drop in the next major + /** @deprecated use the storedDeviceFields */ storedPublicAddress: Device['public_address']; + storedDeviceFields: GetStateEventStoredDeviceFields; }, ) => void; } diff --git a/src/features/device-state/routes/state-get-v2.ts b/src/features/device-state/routes/state-get-v2.ts index 9c15ef2bd..5fe1ec5f8 100644 --- a/src/features/device-state/routes/state-get-v2.ts +++ b/src/features/device-state/routes/state-get-v2.ts @@ -15,6 +15,7 @@ import { ConfigurationVarsToLabels, getStateDelayingEmpty, getConfig, + getStateEventAdditionalFields, } from '../state-get-utils'; import { sbvrUtils } from '@balena/pinejs'; import { events } from '..'; @@ -194,7 +195,7 @@ const stateQuery = _.once(() => resource: 'device', id: { uuid: { '@': 'uuid' } }, options: { - $select: ['device_name', 'public_address'], + $select: ['device_name', ...getStateEventAdditionalFields], $expand: { device_config_variable: { $select: ['name', 'value'], @@ -250,7 +251,9 @@ const getStateV2 = async (req: Request, uuid: string): Promise => { apiKey: req.apiKey, config, ipAddress: getIP(req), + // TODO: Drop in the next major in favor of storedDeviceFields storedPublicAddress: device.public_address as Device['public_address'], + storedDeviceFields: _.pick(device, getStateEventAdditionalFields), }); const userApp = getUserAppForState(device, config); diff --git a/src/features/device-state/routes/state-get-v3.ts b/src/features/device-state/routes/state-get-v3.ts index 813110b75..ba7eef427 100644 --- a/src/features/device-state/routes/state-get-v3.ts +++ b/src/features/device-state/routes/state-get-v3.ts @@ -12,6 +12,7 @@ import { getConfig, getReleaseForDevice, getStateDelayingEmpty, + getStateEventAdditionalFields, readTransaction, serviceInstallFromImage, varListInsert, @@ -270,7 +271,7 @@ const stateQuery = _.once(() => resource: 'device', id: { uuid: { '@': 'uuid' } }, options: { - $select: ['device_name', 'public_address'], + $select: ['device_name', ...getStateEventAdditionalFields], $expand: deviceExpand, }, }), @@ -287,7 +288,9 @@ const getStateV3 = async (req: Request, uuid: string): Promise => { apiKey: req.apiKey, config, ipAddress: getIP(req), + // TODO: Drop in the next major in favor of storedDeviceFields storedPublicAddress: device.public_address as Device['public_address'], + storedDeviceFields: _.pick(device, getStateEventAdditionalFields), }); let apps = getUserAppState(device, config); diff --git a/src/features/device-state/state-get-utils.ts b/src/features/device-state/state-get-utils.ts index 0e5b94f89..0f2f274bd 100644 --- a/src/features/device-state/state-get-utils.ts +++ b/src/features/device-state/state-get-utils.ts @@ -8,6 +8,19 @@ import { createMultiLevelStore, reqPermissionNormalizer, } from '../../infra/cache'; +import type { Device } from '../../balena-model'; + +// eslint-disable-next-line @typescript-eslint/no-empty-interface -- This needs to be an interface so that downstream projects can extend it. +export interface GetStateEventStoredDeviceFields + extends Pick {} + +// We do not use "satisfies" or "as const" so that downstream projects can augment this list. +export const getStateEventAdditionalFields: Array< + keyof GetStateEventStoredDeviceFields +> = [ + // TODO: Remove the public_address from this list in the next major since it's not used by oB-api and downstream projects can set it if needed. + 'public_address', +]; const defaultConfigVariableFns: Array<(config: Dictionary) => void> = [ function setMinPollInterval(config) {