feat(device-plane): enable B2 discovery ingress
This commit is contained in:
@@ -0,0 +1,75 @@
|
||||
export function createCoreDiscoveryClient({
|
||||
coreUrl,
|
||||
gatewayToken,
|
||||
timeoutMs = 5000,
|
||||
fetchImpl = fetch,
|
||||
} = {}) {
|
||||
const endpoint = normalizeCoreEndpoint(coreUrl);
|
||||
if (typeof gatewayToken !== "string" || gatewayToken.length < 32) {
|
||||
throw new TypeError("device_gateway_core_token_invalid");
|
||||
}
|
||||
const normalizedTimeout = Number(timeoutMs);
|
||||
if (
|
||||
!Number.isSafeInteger(normalizedTimeout)
|
||||
|| normalizedTimeout < 100
|
||||
|| normalizedTimeout > 30_000
|
||||
) {
|
||||
throw new TypeError("device_gateway_core_timeout_invalid");
|
||||
}
|
||||
if (typeof fetchImpl !== "function") {
|
||||
throw new TypeError("device_gateway_core_fetch_invalid");
|
||||
}
|
||||
|
||||
return async function observeDiscovery(signal) {
|
||||
const response = await fetchImpl(endpoint, {
|
||||
method: "POST",
|
||||
headers: {
|
||||
Authorization: `Bearer ${gatewayToken}`,
|
||||
"Content-Type": "application/json",
|
||||
},
|
||||
body: JSON.stringify(signal),
|
||||
signal: AbortSignal.timeout(normalizedTimeout),
|
||||
});
|
||||
const body = await readBoundedJson(response, 32 * 1024);
|
||||
if (!response.ok || body?.ok !== true) {
|
||||
throw new Error("device_gateway_core_ingest_failed");
|
||||
}
|
||||
if (
|
||||
!body.discovery
|
||||
|| body.discovery.lifecycleState !== "quarantine"
|
||||
|| body.discovery.commandTransport !== "disabled"
|
||||
) {
|
||||
throw new Error("device_gateway_core_ingest_contract_invalid");
|
||||
}
|
||||
return body.discovery;
|
||||
};
|
||||
}
|
||||
|
||||
function normalizeCoreEndpoint(value) {
|
||||
let url;
|
||||
try {
|
||||
url = new URL(String(value || ""));
|
||||
} catch {
|
||||
throw new TypeError("device_gateway_core_url_invalid");
|
||||
}
|
||||
if (url.protocol !== "http:" || url.username || url.password) {
|
||||
throw new TypeError("device_gateway_core_url_invalid");
|
||||
}
|
||||
if (url.pathname !== "/" || url.search || url.hash) {
|
||||
throw new TypeError("device_gateway_core_url_invalid");
|
||||
}
|
||||
url.pathname = "/internal/v1/device-discoveries:observe";
|
||||
return url.toString();
|
||||
}
|
||||
|
||||
async function readBoundedJson(response, maxBytes) {
|
||||
const text = await response.text();
|
||||
if (Buffer.byteLength(text, "utf8") > maxBytes) {
|
||||
throw new Error("device_gateway_core_response_too_large");
|
||||
}
|
||||
try {
|
||||
return JSON.parse(text);
|
||||
} catch {
|
||||
throw new Error("device_gateway_core_response_invalid");
|
||||
}
|
||||
}
|
||||
Reference in New Issue
Block a user