feat: expand companion platform, device controls, and memoir workflows
ci / verify (push) Canceled after 0s
ci / verify (push) Canceled after 0s
Add customer and operator login, BLE provisioning, device fleet controls, call memory, memoir generation, and refreshed family and maintenance portals. Include API contracts, migrations, firmware sources, tests, assets, and deployment documentation.
This commit is contained in:
@@ -0,0 +1,40 @@
|
||||
// Read-only production checks on the independent handoff device. Never bind it,
|
||||
// start a real conversation or print private keys/voice/MQTT credentials.
|
||||
const fs = require('node:fs');
|
||||
const crypto = require('node:crypto');
|
||||
const net = require('node:net');
|
||||
const assert = require('node:assert/strict');
|
||||
const { sign } = require('../docs/embedded-signing-reference.cjs');
|
||||
async function main() {
|
||||
const init = JSON.parse(fs.readFileSync(process.argv[2], 'utf8').replace(/^\uFEFF/, ''));
|
||||
assert.equal(init.factory_id, 'KP01-020000260914');
|
||||
assert.equal(init.origin, 'https://82.157.201.114');
|
||||
const health = await fetch(init.origin + '/health/ready', { signal: AbortSignal.timeout(15000) });
|
||||
assert.equal(health.status, 200);
|
||||
const offset = Date.parse(health.headers.get('date')) - Date.now();
|
||||
assert.ok(Number.isFinite(offset));
|
||||
const post = async (path, input) => {
|
||||
const raw = JSON.stringify(input);
|
||||
const headers = sign(Buffer.from(init.device_key_hex, 'hex'), { path, deviceId: init.factory_id,
|
||||
keyVersion: init.key_version, timestamp: Date.now() + offset, nonce: crypto.randomBytes(16).toString('base64url'), requestId: crypto.randomUUID(), raw }).headers;
|
||||
const response = await fetch(init.origin + path, { method: 'POST', headers, body: raw, signal: AbortSignal.timeout(15000) });
|
||||
return { status: response.status, body: await response.json() };
|
||||
};
|
||||
const state = await post('/api/v1/device/ble-state', {});
|
||||
assert.equal(state.status, 200);
|
||||
assert.equal(state.body.data.bound, false, 'Test device is bound: skip any chat probe');
|
||||
const start = await post('/api/v1/device/chat/start', { device_id: init.factory_id, session_id: crypto.randomUUID() });
|
||||
assert.equal(start.status, 409);
|
||||
assert.equal(start.body.code, 'DEVICE_UNBOUND');
|
||||
const mqtt = await new Promise(resolve => {
|
||||
const socket = net.connect({ host: '82.157.201.114', port: 1883 });
|
||||
socket.setTimeout(8000);
|
||||
socket.once('connect', () => { resolve('TCP_OK'); socket.destroy(); });
|
||||
socket.once('timeout', () => { resolve('TIMEOUT'); socket.destroy(); });
|
||||
socket.once('error', error => { resolve(error.code || 'TCP_FAILED'); socket.destroy(); });
|
||||
});
|
||||
console.log(JSON.stringify({ health: health.status, device_id: init.factory_id, bound: false,
|
||||
chat_without_boot_id: start.status, chat_error: start.body.code, mqtt_public_tcp: mqtt,
|
||||
startup_endpoints_called: 0, bindings_changed: 0, real_calls_started: 0 }));
|
||||
}
|
||||
main().catch(() => { console.error('Live probe failed; no private values printed.'); process.exitCode = 1; });
|
||||
Reference in New Issue
Block a user