feat(device-plane): add core-initiated edge channel

This commit is contained in:
Codex
2026-08-11 19:30:18 +03:00
parent 393741f1bd
commit 50b9179fe4
11 changed files with 2089 additions and 0 deletions
@@ -0,0 +1,77 @@
import assert from "node:assert/strict";
import test from "node:test";
import {
createChannelEnvelope,
createChannelEnvelopeDecoder,
encodeChannelEnvelope,
nextReconnectDelay,
normalizeChannelEnvelope,
} from "../src/index.mjs";
const now = "2026-08-11T12:00:00.000Z";
function envelope(overrides = {}) {
return createChannelEnvelope({
edgeRegistrationId: "edge:pilot-1",
channelGeneration: "generation:pilot-1",
trackerSessionId: "channel:control",
adapterProfileRef: "channel.control.v1",
sequence: 1,
eventAt: now,
receivedAt: now,
messageKind: "channel.hello",
correlationId: "correlation:hello-1",
payload: { status: "ready" },
...overrides,
}, { direction: "edge-to-core" });
}
test("round-trips a bounded versioned Edge envelope", () => {
const decoder = createChannelEnvelopeDecoder({ direction: "edge-to-core" });
const encoded = encodeChannelEnvelope(envelope(), {
direction: "edge-to-core",
});
const split = Math.floor(encoded.length / 2);
assert.deepEqual(decoder.push(encoded.subarray(0, split)), []);
assert.deepEqual(decoder.push(encoded.subarray(split)), [envelope()]);
assert.equal(decoder.bufferedBytes(), 0);
decoder.finish();
});
test("fails closed on unknown kinds, payload mismatches and oversized frames", () => {
const valid = envelope();
assert.throws(() => normalizeChannelEnvelope({
...valid,
messageKind: "tcp.forward",
}, { direction: "edge-to-core" }), /message_kind_invalid/);
assert.throws(() => normalizeChannelEnvelope({
...valid,
payloadBytes: valid.payloadBytes + 1,
}, { direction: "edge-to-core" }), /payload_length_mismatch/);
const decoder = createChannelEnvelopeDecoder({
direction: "edge-to-core",
maxEnvelopeBytes: 256,
});
assert.throws(() => decoder.push(Buffer.alloc(257, 0x61)), /envelope_too_large/);
});
test("uses bounded jittered exponential reconnect delays", () => {
assert.equal(nextReconnectDelay(0, {
minimumMs: 1000,
maximumMs: 30_000,
random: () => 1,
}), 1000);
assert.equal(nextReconnectDelay(5, {
minimumMs: 1000,
maximumMs: 30_000,
random: () => 1,
}), 30_000);
assert.equal(nextReconnectDelay(5, {
minimumMs: 1000,
maximumMs: 30_000,
random: () => 0,
}), 15_000);
});