feat(device-plane): add universal adapter acceptance boundary

This commit is contained in:
Codex
2026-08-11 19:11:48 +03:00
parent 227c7c26c1
commit 393741f1bd
26 changed files with 1887 additions and 127 deletions
@@ -0,0 +1,151 @@
export const DEVICE_ADAPTER_CONTRACT_VERSION =
"nodedc.device-adapter.v1";
const ADAPTER_REF_RE = /^[a-z][a-z0-9-]{1,62}$/;
const PROFILE_REF_RE = /^[a-z][a-z0-9._-]{2,127}$/;
const RUNTIME_PACKAGE_REF_RE = /^@[a-z0-9-]+\/[a-z0-9-]+$/;
export function defineDeviceAdapter(input) {
assertPlainObject(input, "device_adapter");
if (input.contractVersion !== DEVICE_ADAPTER_CONTRACT_VERSION) {
throw new TypeError("device_adapter_contract_version_invalid");
}
const adapterRef = normalizeRef(
input.adapterRef,
ADAPTER_REF_RE,
"device_adapter_ref_invalid",
);
const runtimePackageRef = normalizeRef(
input.runtimePackageRef,
RUNTIME_PACKAGE_REF_RE,
"device_adapter_runtime_package_ref_invalid",
);
if (!Array.isArray(input.profiles) || input.profiles.length === 0) {
throw new TypeError("device_adapter_profiles_required");
}
const profiles = input.profiles.map((profile) =>
normalizeProfile(profile, adapterRef)
);
if (new Set(profiles.map((profile) => profile.profileRef)).size !== profiles.length) {
throw new TypeError("device_adapter_profile_duplicate");
}
if (typeof input.createSession !== "function") {
throw new TypeError("device_adapter_session_factory_required");
}
return deepFreeze({
contractVersion: DEVICE_ADAPTER_CONTRACT_VERSION,
adapterRef,
runtimePackageRef,
profiles,
createSession: input.createSession,
});
}
export function createDeviceAdapterRegistry({ adapters = [] } = {}) {
if (!Array.isArray(adapters)) {
throw new TypeError("device_adapter_registry_adapters_invalid");
}
const byAdapterRef = new Map();
const byProfileRef = new Map();
for (const adapter of adapters) {
const normalized = defineDeviceAdapter(adapter);
if (byAdapterRef.has(normalized.adapterRef)) {
throw new TypeError("device_adapter_registry_adapter_duplicate");
}
byAdapterRef.set(normalized.adapterRef, normalized);
for (const profile of normalized.profiles) {
if (byProfileRef.has(profile.profileRef)) {
throw new TypeError("device_adapter_registry_profile_duplicate");
}
byProfileRef.set(profile.profileRef, Object.freeze({
adapter: normalized,
profile,
}));
}
}
return Object.freeze({
adapterRefs: Object.freeze([...byAdapterRef.keys()].sort()),
profileRefs: Object.freeze([...byProfileRef.keys()].sort()),
getAdapter(adapterRef) {
const normalized = normalizeRef(
adapterRef,
ADAPTER_REF_RE,
"device_adapter_ref_invalid",
);
const adapter = byAdapterRef.get(normalized);
if (!adapter) throw new TypeError("device_adapter_not_allowlisted");
return adapter;
},
resolveProfile(profileRef) {
const normalized = normalizeRef(
profileRef,
PROFILE_REF_RE,
"device_adapter_profile_ref_invalid",
);
const registration = byProfileRef.get(normalized);
if (!registration) {
throw new TypeError("device_adapter_profile_not_allowlisted");
}
return registration;
},
});
}
export function assertDeviceAdapterSession(session) {
assertPlainObject(session, "device_adapter_session");
for (const method of [
"parseHeader",
"buildHeaderAcknowledgement",
"parseMessage",
"buildMessageAcknowledgement",
]) {
if (typeof session[method] !== "function") {
throw new TypeError(`device_adapter_session_method_missing:${method}`);
}
}
return session;
}
function normalizeProfile(profile, adapterRef) {
assertPlainObject(profile, "device_adapter_profile");
const profileRef = normalizeRef(
profile.profileRef,
PROFILE_REF_RE,
"device_adapter_profile_ref_invalid",
);
if (profile.adapterRef != null && profile.adapterRef !== adapterRef) {
throw new TypeError("device_adapter_profile_adapter_mismatch");
}
const maxBufferedBytes = Number(profile?.framing?.maxBufferedBytes);
if (
!Number.isSafeInteger(maxBufferedBytes)
|| maxBufferedBytes < 1024
|| maxBufferedBytes > 256 * 1024
) {
throw new TypeError("device_adapter_profile_buffer_limit_invalid");
}
return deepFreeze({ ...profile, profileRef, adapterRef });
}
function normalizeRef(value, pattern, errorCode) {
if (typeof value !== "string" || !pattern.test(value)) {
throw new TypeError(errorCode);
}
return value;
}
function assertPlainObject(value, label) {
if (!value || typeof value !== "object" || Array.isArray(value)) {
throw new TypeError(`${label}_invalid`);
}
}
function deepFreeze(value) {
if (!value || typeof value !== "object" || Object.isFrozen(value)) {
return value;
}
Object.values(value).forEach(deepFreeze);
return Object.freeze(value);
}