feat(device-plane): add typed B2 service ping transport

This commit is contained in:
Codex
2026-08-12 22:57:09 +03:00
parent bdb85cb4f7
commit 4b73a15765
24 changed files with 1322 additions and 88 deletions
@@ -90,7 +90,7 @@ export function createDeviceEdgeChannelServer(options = {}) {
status: "ready",
transport: "http2-mtls",
trustGeneration: trust.generationRef,
commandTransport: "disabled",
commandTransport: config.commandTransport,
}, {
trackerSessionId: CHANNEL_TRACKER_SESSION_ID,
adapterProfileRef: CHANNEL_PROFILE_REF,
@@ -156,7 +156,10 @@ export function createDeviceEdgeChannelServer(options = {}) {
if (!result?.discovery) {
throw new Error("device_edge_channel_discovery_acceptance_invalid");
}
return result.discovery;
return Object.freeze({
...result.discovery,
...(result.commandOffer ? { commandOffer: result.commandOffer } : {}),
});
},
async submitAdapterMessage(message) {
const normalized = normalizeAdapterMessage(message, {
@@ -173,7 +176,24 @@ export function createDeviceEdgeChannelServer(options = {}) {
if (acceptance.idempotencyKey !== normalized.idempotencyKey) {
throw new Error("device_edge_channel_acceptance_mismatch");
}
return acceptance;
return Object.freeze({
...acceptance,
...(result.commandOffer ? { commandOffer: result.commandOffer } : {}),
});
},
async submitCommandStatus(status) {
const normalized = normalizeCommandStatus(status);
const result = await submitEvent("command.status", {
status: normalized,
}, {
trackerSessionId: normalized.sessionRef,
adapterProfileRef: normalized.adapterProfileRef,
eventAt: normalized.observedAt,
});
if (result?.status !== "recorded") {
throw new Error("device_edge_channel_command_status_invalid");
}
return Object.freeze({ status: "recorded" });
},
status() {
return Object.freeze({
@@ -191,7 +211,7 @@ export function createDeviceEdgeChannelServer(options = {}) {
eventsRejected: totalEventsRejected,
protocolFailures: totalProtocolFailures,
trackerIngress: "disabled",
commandTransport: "disabled",
commandTransport: config.commandTransport,
});
},
rotateTrust(next) {
@@ -271,7 +291,10 @@ export function createDeviceEdgeChannelServer(options = {}) {
if (envelope.messageKind !== "channel.accepted") {
throw new Error("device_edge_channel_acceptance_required");
}
if (envelope.payload?.status !== "accepted") {
if (
envelope.payload?.status !== "accepted"
|| envelope.payload?.commandTransport !== config.commandTransport
) {
throw new Error("device_edge_channel_acceptance_invalid");
}
state.accepted = true;
@@ -410,6 +433,7 @@ function normalizeConfig(options) {
return Object.freeze({
edgeRegistrationId,
channelGeneration,
commandTransport: normalizeCommandTransport(options.commandTransport),
trust,
host: normalizeHost(options.host ?? "127.0.0.1"),
port: normalizePort(options.port ?? 443),
@@ -442,6 +466,50 @@ function normalizeConfig(options) {
});
}
function normalizeCommandTransport(value) {
const normalized = value ?? "disabled";
if (!["disabled", "typed-service-ping-v1"].includes(normalized)) {
throw new TypeError("device_edge_channel_command_transport_invalid");
}
return normalized;
}
function normalizeCommandStatus(value) {
if (!value || typeof value !== "object" || Array.isArray(value)) {
throw new TypeError("device_edge_channel_command_status_invalid");
}
const commandRef = normalizeRef(value.commandRef, "command_ref");
const transportMessageRef = normalizeRef(
value.transportMessageRef,
"transport_message_ref",
);
const sessionRef = normalizeRef(value.sessionRef, "tracker_session_ref");
const adapterProfileRef = normalizeRef(
value.adapterProfileRef,
"adapter_profile_ref",
);
if (!["acknowledged", "unknown"].includes(value.lifecycleState)) {
throw new TypeError("device_edge_channel_command_lifecycle_invalid");
}
const resultCode = String(value.resultCode || "");
if (!/^[a-z][a-z0-9._-]{1,63}$/.test(resultCode)) {
throw new TypeError("device_edge_channel_command_result_invalid");
}
const observedAt = new Date(value.observedAt);
if (Number.isNaN(observedAt.getTime())) {
throw new TypeError("device_edge_channel_command_observed_at_invalid");
}
return Object.freeze({
commandRef,
transportMessageRef,
sessionRef,
adapterProfileRef,
lifecycleState: value.lifecycleState,
resultCode,
observedAt: observedAt.toISOString(),
});
}
function normalizeTrust(value) {
if (!value || typeof value !== "object") {
throw new TypeError("device_edge_channel_tls_invalid");