feat(device-core): expose safe project control views

This commit is contained in:
Codex
2026-08-10 20:49:10 +03:00
parent f5d7916338
commit 1d1e9a96b3
3 changed files with 583 additions and 4 deletions
@@ -127,12 +127,222 @@ export async function getDeviceProjectWorkspace(client, actor, projectId) {
[projectId],
);
const capabilities = new Set(access.capabilities);
const mayManageRoutes = capabilities.has("route.manage");
const catalogParameters = [projectId, mayManageRoutes];
const adapterPackages = await client.query(
`select ap.id, ap.package_key, ap.display_name, ap.publisher_ref,
ap.lifecycle_state, ap.created_at, ap.updated_at
from device_adapter_packages ap
where $2::boolean
or exists (
select 1
from device_adapter_versions av
join device_model_profiles dmp on dmp.adapter_version_id = av.id
where av.adapter_package_id = ap.id
and (
exists (
select 1 from device_routes dr
where dr.project_id = $1 and dr.model_profile_ref = dmp.profile_ref
)
or exists (
select 1 from device_instances di
where di.project_id = $1 and di.model_profile_ref = dmp.profile_ref
)
)
)
order by ap.display_name, ap.id`,
catalogParameters,
);
const adapterVersions = await client.query(
`select av.id, av.adapter_package_id, av.version,
av.runtime_package_ref, av.content_digest, av.contract_version,
av.capabilities, av.lifecycle_state, av.created_at, av.updated_at
from device_adapter_versions av
where $2::boolean
or exists (
select 1 from device_model_profiles dmp
where dmp.adapter_version_id = av.id
and (
exists (
select 1 from device_routes dr
where dr.project_id = $1 and dr.model_profile_ref = dmp.profile_ref
)
or exists (
select 1 from device_instances di
where di.project_id = $1 and di.model_profile_ref = dmp.profile_ref
)
)
)
order by av.adapter_package_id, av.created_at, av.id`,
catalogParameters,
);
const modelProfiles = await client.query(
`select dmp.profile_ref, dmp.adapter_version_id, dmp.schema_version,
dmp.vendor, dmp.model, dmp.device_type, dmp.protocol,
dmp.schema_artifact_ref, dmp.profile_digest, dmp.capabilities,
dmp.lifecycle_state, dmp.created_at, dmp.updated_at
from device_model_profiles dmp
where $2::boolean
or exists (
select 1 from device_routes dr
where dr.project_id = $1 and dr.model_profile_ref = dmp.profile_ref
)
or exists (
select 1 from device_instances di
where di.project_id = $1 and di.model_profile_ref = dmp.profile_ref
)
order by dmp.vendor, dmp.model, dmp.profile_ref`,
catalogParameters,
);
const edges = await client.query(
`select de.id, de.edge_key, de.display_name, de.deployment_ref,
de.lifecycle_state, de.created_at, de.updated_at
from device_edges de
where $2::boolean
or exists (
select 1 from device_routes dr
where dr.project_id = $1 and dr.edge_id = de.id
)
order by de.display_name, de.id`,
catalogParameters,
);
const routes = await client.query(
`select dr.id, dr.route_key, dr.display_name, dr.edge_id,
de.display_name as edge_name, dr.model_profile_ref,
dmp.vendor as profile_vendor, dmp.model as profile_model,
dr.listener_ref, dr.protocol, dr.direction, dr.lifecycle_state,
dr.created_at, dr.updated_at,
count(ds.id)::bigint as session_count,
(count(ds.id) filter (
where ds.lifecycle_state in ('connecting', 'online')
))::bigint as active_session_count
from device_routes dr
join device_edges de on de.id = dr.edge_id
join device_model_profiles dmp on dmp.profile_ref = dr.model_profile_ref
left join device_sessions ds on ds.route_id = dr.id
where dr.project_id = $1
group by dr.id, de.display_name, dmp.vendor, dmp.model
order by dr.display_name, dr.id`,
[projectId],
);
const sessions = capabilities.has("telemetry.observe")
? await client.query(
`select ds.id, ds.route_id, dr.display_name as route_name,
ds.device_id, di.display_name as device_name,
ds.protocol, ds.lifecycle_state, ds.connected_at,
ds.last_seen_at, ds.disconnected_at, ds.close_reason_code,
ds.frame_count, ds.byte_count
from device_sessions ds
join device_routes dr on dr.id = ds.route_id
left join device_instances di on di.id = ds.device_id
where ds.project_id = $1
order by ds.last_seen_at desc, ds.id
limit 200`,
[projectId],
)
: { rows: [] };
const bindings = capabilities.has("binding.manage")
? await client.query(
`select drb.id, drb.binding_key, drb.display_name,
drb.source_kind, drb.device_id, drb.collection_id,
coalesce(di.display_name, dc.name) as source_name,
drb.target_kind, drb.target_ref, drb.capabilities,
drb.lifecycle_state, drb.source_approved_at,
drb.created_at, drb.updated_at
from device_resource_bindings drb
left join device_instances di on di.id = drb.device_id
left join device_collections dc on dc.id = drb.collection_id
where drb.project_id = $1
order by drb.updated_at desc, drb.id`,
[projectId],
)
: { rows: [] };
const configurationRevisions = capabilities.has("configuration.read")
? await client.query(
`select dcr.id, dcr.device_id, di.display_name as device_name,
dcr.revision_number, dcr.model_profile_ref,
dcr.schema_artifact_ref, dcr.configuration_digest,
dcr.change_summary, dcr.created_at
from device_configuration_revisions dcr
join device_instances di on di.id = dcr.device_id
where dcr.project_id = $1
order by dcr.created_at desc, dcr.id
limit 200`,
[projectId],
)
: { rows: [] };
const configurationStates = capabilities.has("configuration.read")
? await client.query(
`select dcs.device_id, di.display_name as device_name,
dcs.desired_revision_id, dcs.applied_revision_id,
dcs.applied_at, dcs.updated_at
from device_configuration_state dcs
join device_instances di on di.id = dcs.device_id
where dcs.project_id = $1
order by di.display_name, dcs.device_id`,
[projectId],
)
: { rows: [] };
const mayReadCommands = ["command.plan", "command.confirm", "command.dispatch"]
.some((capability) => capabilities.has(capability));
const commands = mayReadCommands
? await client.query(
`select dc.id, dc.device_id, di.display_name as device_name,
dc.command_key, dc.command_catalog_ref, dc.command_type,
dc.risk_class, dc.lifecycle_state, dc.planned_at, dc.expires_at,
dc.confirmed_at, dc.dispatched_at, dc.acknowledged_at,
dc.terminal_at, dc.terminal_reason_code,
dc.created_at, dc.updated_at
from device_commands dc
join device_instances di on di.id = dc.device_id
where dc.project_id = $1
order by dc.updated_at desc, dc.id
limit 200`,
[projectId],
)
: { rows: [] };
const auditEvents = capabilities.has("audit.read")
? await client.query(
`select dae.id, dae.event_type, dae.actor_ref,
dae.device_id, dae.discovery_id, dae.occurred_at
from device_audit_events dae
where dae.project_id = $1
order by dae.occurred_at desc, dae.id
limit 300`,
[projectId],
)
: { rows: [] };
const projectGrants = capabilities.has("access.manage")
? grantsResult
: { rows: [] };
return {
project: projectSummaryView(project, access),
devices: devices.rows.map(deviceView),
collections: collections.rows.map(collectionView),
discoveries: discoveries.rows.map(discoveryView),
enrollments: enrollments.rows.map(enrollmentView),
adapterPackages: adapterPackages.rows.map(adapterPackageView),
adapterVersions: adapterVersions.rows.map(adapterVersionView),
modelProfiles: modelProfiles.rows.map(modelProfileView),
edges: edges.rows.map(edgeView),
routes: routes.rows.map(routeView),
sessions: sessions.rows.map(sessionView),
bindings: bindings.rows.map(bindingView),
configurationRevisions: configurationRevisions.rows.map(
configurationRevisionView,
),
configurationStates: configurationStates.rows.map(configurationStateView),
commands: commands.rows.map(commandView),
auditEvents: auditEvents.rows.map(auditEventView),
grants: projectGrants.rows.map(storedGrantView),
policies: {
commandTransport: "disabled",
commandPlanningApi: "disabled",
identifierProjection: "masked-only",
auditPayloadProjection: "metadata-only",
},
};
}
@@ -202,7 +412,7 @@ function discoveryView(row) {
protocol: row.protocol,
lifecycleState: row.lifecycle_state,
enrollmentIntentRef: row.enrollment_intent_id
? `enrollment:${row.enrollment_intent_id}`
? `enrollment-intent:${row.enrollment_intent_id}`
: null,
claimedDeviceRef: row.claimed_device_id ? `device:${row.claimed_device_id}` : null,
firstObservedAt: toIso(row.first_observed_at),
@@ -212,7 +422,7 @@ function discoveryView(row) {
function enrollmentView(row) {
return {
enrollmentIntentRef: `enrollment:${row.id}`,
enrollmentIntentRef: `enrollment-intent:${row.id}`,
enrollmentKey: row.enrollment_key,
displayName: row.display_name,
modelProfileRef: row.model_profile_ref,
@@ -231,6 +441,186 @@ function enrollmentView(row) {
};
}
function adapterPackageView(row) {
return {
adapterPackageRef: `adapter-package:${row.id}`,
packageKey: row.package_key,
displayName: row.display_name,
publisherRef: row.publisher_ref,
lifecycleState: row.lifecycle_state,
createdAt: toIso(row.created_at),
updatedAt: toIso(row.updated_at),
};
}
function adapterVersionView(row) {
return {
adapterVersionRef: `adapter-version:${row.id}`,
adapterPackageRef: `adapter-package:${row.adapter_package_id}`,
version: row.version,
runtimePackageRef: row.runtime_package_ref,
contentDigest: row.content_digest,
contractVersion: row.contract_version,
capabilities: [...(row.capabilities ?? [])].sort(),
lifecycleState: row.lifecycle_state,
createdAt: toIso(row.created_at),
updatedAt: toIso(row.updated_at),
};
}
function modelProfileView(row) {
return {
modelProfileRef: row.profile_ref,
adapterVersionRef: row.adapter_version_id
? `adapter-version:${row.adapter_version_id}`
: null,
schemaVersion: row.schema_version,
vendor: row.vendor,
model: row.model,
deviceType: row.device_type,
protocol: row.protocol,
schemaArtifactRef: row.schema_artifact_ref ?? null,
profileDigest: row.profile_digest ?? null,
capabilities: [...(row.capabilities ?? [])].sort(),
lifecycleState: row.lifecycle_state,
createdAt: toIso(row.created_at),
updatedAt: toIso(row.updated_at),
};
}
function edgeView(row) {
return {
edgeRef: `edge:${row.id}`,
edgeKey: row.edge_key,
displayName: row.display_name,
deploymentRef: row.deployment_ref ?? null,
lifecycleState: row.lifecycle_state,
createdAt: toIso(row.created_at),
updatedAt: toIso(row.updated_at),
};
}
function routeView(row) {
return {
routeRef: `route:${row.id}`,
routeKey: row.route_key,
displayName: row.display_name,
edgeRef: `edge:${row.edge_id}`,
edgeName: row.edge_name,
modelProfileRef: row.model_profile_ref,
profileName: `${row.profile_vendor} ${row.profile_model}`.trim(),
listenerRef: row.listener_ref,
protocol: row.protocol,
direction: row.direction,
lifecycleState: row.lifecycle_state,
sessionCount: numericCount(row.session_count),
activeSessionCount: numericCount(row.active_session_count),
createdAt: toIso(row.created_at),
updatedAt: toIso(row.updated_at),
};
}
function sessionView(row) {
return {
sessionRef: `session:${row.id}`,
routeRef: `route:${row.route_id}`,
routeName: row.route_name,
deviceRef: row.device_id ? `device:${row.device_id}` : null,
deviceName: row.device_name ?? null,
protocol: row.protocol,
lifecycleState: row.lifecycle_state,
connectedAt: toIso(row.connected_at),
lastSeenAt: toIso(row.last_seen_at),
disconnectedAt: toIso(row.disconnected_at),
closeReasonCode: row.close_reason_code ?? null,
frameCount: numericCount(row.frame_count),
byteCount: numericCount(row.byte_count),
};
}
function bindingView(row) {
return {
bindingRef: `binding:${row.id}`,
bindingKey: row.binding_key,
displayName: row.display_name,
source: {
kind: row.source_kind,
ref: row.source_kind === "device"
? `device:${row.device_id}`
: `collection:${row.collection_id}`,
displayName: row.source_name,
},
target: { kind: row.target_kind, ref: row.target_ref },
capabilities: [...(row.capabilities ?? [])].sort(),
lifecycleState: row.lifecycle_state,
sourceApprovedAt: toIso(row.source_approved_at),
createdAt: toIso(row.created_at),
updatedAt: toIso(row.updated_at),
};
}
function configurationRevisionView(row) {
return {
configurationRevisionRef: `configuration-revision:${row.id}`,
deviceRef: `device:${row.device_id}`,
deviceName: row.device_name,
revisionNumber: numericCount(row.revision_number),
modelProfileRef: row.model_profile_ref,
schemaArtifactRef: row.schema_artifact_ref,
configurationDigest: row.configuration_digest,
changeSummary: row.change_summary ?? null,
createdAt: toIso(row.created_at),
};
}
function configurationStateView(row) {
return {
deviceRef: `device:${row.device_id}`,
deviceName: row.device_name,
desiredConfigurationRevisionRef: row.desired_revision_id
? `configuration-revision:${row.desired_revision_id}`
: null,
appliedConfigurationRevisionRef: row.applied_revision_id
? `configuration-revision:${row.applied_revision_id}`
: null,
appliedAt: toIso(row.applied_at),
updatedAt: toIso(row.updated_at),
};
}
function commandView(row) {
return {
commandRef: `command:${row.id}`,
deviceRef: `device:${row.device_id}`,
deviceName: row.device_name,
commandKey: row.command_key,
commandCatalogRef: row.command_catalog_ref,
commandType: row.command_type,
riskClass: row.risk_class,
lifecycleState: row.lifecycle_state,
plannedAt: toIso(row.planned_at),
expiresAt: toIso(row.expires_at),
confirmedAt: toIso(row.confirmed_at),
dispatchedAt: toIso(row.dispatched_at),
acknowledgedAt: toIso(row.acknowledged_at),
terminalAt: toIso(row.terminal_at),
terminalReasonCode: row.terminal_reason_code ?? null,
createdAt: toIso(row.created_at),
updatedAt: toIso(row.updated_at),
};
}
function auditEventView(row) {
return {
auditEventRef: `audit-event:${row.id}`,
eventType: row.event_type,
actorRef: row.actor_ref,
deviceRef: row.device_id ? `device:${row.device_id}` : null,
discoveryRef: row.discovery_id ? `discovery:${row.discovery_id}` : null,
occurredAt: toIso(row.occurred_at),
};
}
function grantView(row) {
return storedGrantView({
id: row.grant_id,