ConnectDevice connect.device@1

Generated at from openvibe-contracts v0.419.0 and openvibe-sdk v0.161.0.

Version
1.0.0
Owner
connect
Visibility
public
Status
active
Compatibility
backward
Schema
https://openvibe.network/contracts/connect/device.v1.json

connect.device@1: one device in a private Connect mesh, as its owner sees it. A device belongs to exactly one tenant (the person's own network or a project's), is identified by a Network node principal, and carries only self-reported posture. The mesh control-plane's internal node id, pre-auth key and WireGuard keys are not part of this document.

Fields

FieldTypeRequiredDescriptionConstraints
idstringyes
  • pattern ^dev_[0-9A-HJKMNP-TV-Z]{26}$
owneranyyesThe person who owns the device.
project_idstring | nullThe project whose mesh the device joins; null for a personal mesh.
  • pattern ^prj_[0-9A-HJKMNP-TV-Z]{26}$
tenantone ofyesThe isolation boundary: one headscale tenant per workspace in v1, never one shared tailnet for all consumer devices.
node_idstring | nullThe Network node principal the device presents; null for an agent or server that joins through a pre-auth key.
  • pattern ^lnk_[0-9A-HJKMNP-TV-Z]{26}$
namestringyesOne DNS label in the mesh, shown as name.owner (e.g. pc.alice); never a public hostname.
  • pattern ^[a-z0-9](?:[a-z0-9-]{0,61}[a-z0-9])?$
statusenumyespending waits for the owner's approval of a pre-auth join; removed is terminal and its keys are revoked.
  • one of "pending", "online", "offline", "removed"
osenumyes
  • one of "linux", "macos", "windows", "ios", "android", "other"
archenum
  • one of "amd64", "arm64", "386", "arm", "other"
versionstringyesThe Link release running on the device.
  • minLength 1
  • maxLength 40
addressesarray of stringThe device's private mesh addresses; never a public address.
  • maxItems 8
  • items: minLength 2
  • items: maxLength 64
tagsarray of string
  • maxItems 50
  • unique items
  • items: pattern ^[a-z][a-z0-9-]{0,62}$
postureobject | nullSelf-reported posture, a signal not a guarantee; checked_at says when it was read.
routesarray of stringSubnet routes the device advertises, e.g. 192.168.1.0/24; empty for none.
  • maxItems 50
  • items: minLength 2
  • items: maxLength 64
exit_nodebooleanWhether the owner allows the device to act as an exit node for this tenant only; never a public proxy.
approved_atstring | null
  • format date-time
approved_byanyThe person who approved the join; null while pending.
last_seen_atstring | null
  • format date-time
expires_atstring | nullWhen an unapproved or temporary device stops being valid; null for no expiry.
  • format date-time
created_atstringyes
  • format date-time
updated_atstringyes
  • format date-time
revoked_atstring | null
  • format date-time

Examples

From the contract's own test fixtures: valid ones validate, rejected ones must fail.

Valid: max-label
{
  "id": "dev_01J8Z3Q4R5S6T7V8W9X0Y1Z2A8",
  "owner": {
    "type": "user",
    "id": "usr_01J8Z3Q4R5S6T7V8W9X0Y1Z2A6"
  },
  "project_id": null,
  "tenant": {
    "type": "user",
    "id": "usr_01J8Z3Q4R5S6T7V8W9X0Y1Z2A6"
  },
  "node_id": "lnk_01J8Z3Q4R5S6T7V8W9X0Y1Z2A5",
  "name": "a-------------------------------------------------------------z",
  "status": "online",
  "os": "linux",
  "arch": "amd64",
  "version": "0.42.0",
  "addresses": [
    "100.64.0.2"
  ],
  "tags": [
    "owner",
    "linux"
  ],
  "posture": {
    "node_current": true,
    "os_patched": true,
    "firewall_on": true,
    "disk_encryption": true,
    "risky_ports": [],
    "checked_at": "2026-10-29T09:00:00.000Z"
  },
  "routes": [],
  "exit_node": false,
  "approved_at": "2026-10-29T08:05:00.000Z",
  "approved_by": {
    "type": "user",
    "id": "usr_01J8Z3Q4R5S6T7V8W9X0Y1Z2A6"
  },
  "last_seen_at": "2026-10-29T09:00:00.000Z",
  "expires_at": null,
  "created_at": "2026-10-29T08:00:00.000Z",
  "updated_at": "2026-10-29T09:00:00.000Z",
  "revoked_at": null
}
Valid: one-char
{
  "id": "dev_01J8Z3Q4R5S6T7V8W9X0Y1Z2A8",
  "owner": {
    "type": "user",
    "id": "usr_01J8Z3Q4R5S6T7V8W9X0Y1Z2A6"
  },
  "project_id": null,
  "tenant": {
    "type": "user",
    "id": "usr_01J8Z3Q4R5S6T7V8W9X0Y1Z2A6"
  },
  "node_id": "lnk_01J8Z3Q4R5S6T7V8W9X0Y1Z2A5",
  "name": "a",
  "status": "online",
  "os": "linux",
  "arch": "amd64",
  "version": "0.42.0",
  "addresses": [
    "100.64.0.2"
  ],
  "tags": [
    "owner",
    "linux"
  ],
  "posture": {
    "node_current": true,
    "os_patched": true,
    "firewall_on": true,
    "disk_encryption": true,
    "risky_ports": [],
    "checked_at": "2026-10-29T09:00:00.000Z"
  },
  "routes": [],
  "exit_node": false,
  "approved_at": "2026-10-29T08:05:00.000Z",
  "approved_by": {
    "type": "user",
    "id": "usr_01J8Z3Q4R5S6T7V8W9X0Y1Z2A6"
  },
  "last_seen_at": "2026-10-29T09:00:00.000Z",
  "expires_at": null,
  "created_at": "2026-10-29T08:00:00.000Z",
  "updated_at": "2026-10-29T09:00:00.000Z",
  "revoked_at": null
}
Valid: two-char
{
  "id": "dev_01J8Z3Q4R5S6T7V8W9X0Y1Z2A8",
  "owner": {
    "type": "user",
    "id": "usr_01J8Z3Q4R5S6T7V8W9X0Y1Z2A6"
  },
  "project_id": null,
  "tenant": {
    "type": "user",
    "id": "usr_01J8Z3Q4R5S6T7V8W9X0Y1Z2A6"
  },
  "node_id": "lnk_01J8Z3Q4R5S6T7V8W9X0Y1Z2A5",
  "name": "ab",
  "status": "online",
  "os": "linux",
  "arch": "amd64",
  "version": "0.42.0",
  "addresses": [
    "100.64.0.2"
  ],
  "tags": [
    "owner",
    "linux"
  ],
  "posture": {
    "node_current": true,
    "os_patched": true,
    "firewall_on": true,
    "disk_encryption": true,
    "risky_ports": [],
    "checked_at": "2026-10-29T09:00:00.000Z"
  },
  "routes": [],
  "exit_node": false,
  "approved_at": "2026-10-29T08:05:00.000Z",
  "approved_by": {
    "type": "user",
    "id": "usr_01J8Z3Q4R5S6T7V8W9X0Y1Z2A6"
  },
  "last_seen_at": "2026-10-29T09:00:00.000Z",
  "expires_at": null,
  "created_at": "2026-10-29T08:00:00.000Z",
  "updated_at": "2026-10-29T09:00:00.000Z",
  "revoked_at": null
}
Valid: workstation
{
  "id": "dev_01J8Z3Q4R5S6T7V8W9X0Y1Z2A8",
  "owner": {
    "type": "user",
    "id": "usr_01J8Z3Q4R5S6T7V8W9X0Y1Z2A6"
  },
  "project_id": null,
  "tenant": {
    "type": "user",
    "id": "usr_01J8Z3Q4R5S6T7V8W9X0Y1Z2A6"
  },
  "node_id": "lnk_01J8Z3Q4R5S6T7V8W9X0Y1Z2A5",
  "name": "workstation",
  "status": "online",
  "os": "linux",
  "arch": "amd64",
  "version": "0.42.0",
  "addresses": [
    "100.64.0.2"
  ],
  "tags": [
    "owner",
    "linux"
  ],
  "posture": {
    "node_current": true,
    "os_patched": true,
    "firewall_on": true,
    "disk_encryption": true,
    "risky_ports": [],
    "checked_at": "2026-10-29T09:00:00.000Z"
  },
  "routes": [],
  "exit_node": false,
  "approved_at": "2026-10-29T08:05:00.000Z",
  "approved_by": {
    "type": "user",
    "id": "usr_01J8Z3Q4R5S6T7V8W9X0Y1Z2A6"
  },
  "last_seen_at": "2026-10-29T09:00:00.000Z",
  "expires_at": null,
  "created_at": "2026-10-29T08:00:00.000Z",
  "updated_at": "2026-10-29T09:00:00.000Z",
  "revoked_at": null
}
Rejected: bad-status
{
  "id": "dev_01J8Z3Q4R5S6T7V8W9X0Y1Z2A8",
  "owner": {
    "type": "user",
    "id": "usr_01J8Z3Q4R5S6T7V8W9X0Y1Z2A6"
  },
  "tenant": {
    "type": "user",
    "id": "usr_01J8Z3Q4R5S6T7V8W9X0Y1Z2A6"
  },
  "name": "workstation",
  "status": "connected",
  "os": "linux",
  "version": "0.42.0",
  "created_at": "2026-10-29T08:00:00.000Z",
  "updated_at": "2026-10-29T09:00:00.000Z"
}
Rejected: bad-tenant
{
  "id": "dev_01J8Z3Q4R5S6T7V8W9X0Y1Z2A8",
  "owner": {
    "type": "user",
    "id": "usr_01J8Z3Q4R5S6T7V8W9X0Y1Z2A6"
  },
  "tenant": {
    "type": "user",
    "id": "team_01J8Z3Q4R5S6T7V8W9X0Y1Z2A6"
  },
  "name": "workstation",
  "status": "online",
  "os": "linux",
  "version": "0.42.0",
  "created_at": "2026-10-29T08:00:00.000Z",
  "updated_at": "2026-10-29T09:00:00.000Z"
}
Rejected: leading-hyphen
{
  "id": "dev_01J8Z3Q4R5S6T7V8W9X0Y1Z2A8",
  "owner": {
    "type": "user",
    "id": "usr_01J8Z3Q4R5S6T7V8W9X0Y1Z2A6"
  },
  "project_id": null,
  "tenant": {
    "type": "user",
    "id": "usr_01J8Z3Q4R5S6T7V8W9X0Y1Z2A6"
  },
  "node_id": "lnk_01J8Z3Q4R5S6T7V8W9X0Y1Z2A5",
  "name": "-ab",
  "status": "online",
  "os": "linux",
  "arch": "amd64",
  "version": "0.42.0",
  "addresses": [
    "100.64.0.2"
  ],
  "tags": [
    "owner",
    "linux"
  ],
  "posture": {
    "node_current": true,
    "os_patched": true,
    "firewall_on": true,
    "disk_encryption": true,
    "risky_ports": [],
    "checked_at": "2026-10-29T09:00:00.000Z"
  },
  "routes": [],
  "exit_node": false,
  "approved_at": "2026-10-29T08:05:00.000Z",
  "approved_by": {
    "type": "user",
    "id": "usr_01J8Z3Q4R5S6T7V8W9X0Y1Z2A6"
  },
  "last_seen_at": "2026-10-29T09:00:00.000Z",
  "expires_at": null,
  "created_at": "2026-10-29T08:00:00.000Z",
  "updated_at": "2026-10-29T09:00:00.000Z",
  "revoked_at": null
}
Rejected: too-long
{
  "id": "dev_01J8Z3Q4R5S6T7V8W9X0Y1Z2A8",
  "owner": {
    "type": "user",
    "id": "usr_01J8Z3Q4R5S6T7V8W9X0Y1Z2A6"
  },
  "project_id": null,
  "tenant": {
    "type": "user",
    "id": "usr_01J8Z3Q4R5S6T7V8W9X0Y1Z2A6"
  },
  "node_id": "lnk_01J8Z3Q4R5S6T7V8W9X0Y1Z2A5",
  "name": "aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa",
  "status": "online",
  "os": "linux",
  "arch": "amd64",
  "version": "0.42.0",
  "addresses": [
    "100.64.0.2"
  ],
  "tags": [
    "owner",
    "linux"
  ],
  "posture": {
    "node_current": true,
    "os_patched": true,
    "firewall_on": true,
    "disk_encryption": true,
    "risky_ports": [],
    "checked_at": "2026-10-29T09:00:00.000Z"
  },
  "routes": [],
  "exit_node": false,
  "approved_at": "2026-10-29T08:05:00.000Z",
  "approved_by": {
    "type": "user",
    "id": "usr_01J8Z3Q4R5S6T7V8W9X0Y1Z2A6"
  },
  "last_seen_at": "2026-10-29T09:00:00.000Z",
  "expires_at": null,
  "created_at": "2026-10-29T08:00:00.000Z",
  "updated_at": "2026-10-29T09:00:00.000Z",
  "revoked_at": null
}
Rejected: trailing-hyphen
{
  "id": "dev_01J8Z3Q4R5S6T7V8W9X0Y1Z2A8",
  "owner": {
    "type": "user",
    "id": "usr_01J8Z3Q4R5S6T7V8W9X0Y1Z2A6"
  },
  "project_id": null,
  "tenant": {
    "type": "user",
    "id": "usr_01J8Z3Q4R5S6T7V8W9X0Y1Z2A6"
  },
  "node_id": "lnk_01J8Z3Q4R5S6T7V8W9X0Y1Z2A5",
  "name": "ab-",
  "status": "online",
  "os": "linux",
  "arch": "amd64",
  "version": "0.42.0",
  "addresses": [
    "100.64.0.2"
  ],
  "tags": [
    "owner",
    "linux"
  ],
  "posture": {
    "node_current": true,
    "os_patched": true,
    "firewall_on": true,
    "disk_encryption": true,
    "risky_ports": [],
    "checked_at": "2026-10-29T09:00:00.000Z"
  },
  "routes": [],
  "exit_node": false,
  "approved_at": "2026-10-29T08:05:00.000Z",
  "approved_by": {
    "type": "user",
    "id": "usr_01J8Z3Q4R5S6T7V8W9X0Y1Z2A6"
  },
  "last_seen_at": "2026-10-29T09:00:00.000Z",
  "expires_at": null,
  "created_at": "2026-10-29T08:00:00.000Z",
  "updated_at": "2026-10-29T09:00:00.000Z",
  "revoked_at": null
}

Validate

const contracts = require('openvibe-contracts');
contracts.validate('connect.device@1', value);   // { valid, errors: [{ path, message }] }