Feat: Multi Tenant ZeroTier Config

This commit is contained in:
2026-03-29 21:33:37 +05:45
parent 6ab4b8c2a5
commit a0532ba010
6 changed files with 661 additions and 10 deletions
+75 -9
View File
@@ -1370,6 +1370,14 @@ export const api = {
{ method: "DELETE" }, true, requestConfig,
),
/** List all ZeroTier networks from the org's controller/account, annotated
* with whether each is already managed as a portal network. */
listAvailableZtNetworks: (orgId: string, requestConfig?: RequestConfig) =>
request<{ networks: AvailableZtNetwork[]; count: number; zt_error?: string }>(
`/organizations/${orgId}/zerotier/available-networks`,
{}, true, requestConfig,
),
getNetworkMembers: (orgId: string, networkId: string, requestConfig?: RequestConfig) =>
request<{ memberships: DeviceNetworkMembership[]; count: number }>(
`/organizations/${orgId}/networks/${networkId}/members`,
@@ -1442,6 +1450,12 @@ export const api = {
`/organizations/${orgId}/approvals`, {}, true, requestConfig,
),
adminListAllApprovals: (orgId: string, networkId?: string, state?: string, requestConfig?: RequestConfig) =>
request<{ approvals: UserNetworkApproval[]; count: number }>(
`/organizations/${orgId}/admin/approvals${networkId || state ? `?${new URLSearchParams(Object.fromEntries(Object.entries({ network_id: networkId, state }).filter(([, v]) => v != null) as [string, string][]))}` : ""}`,
{}, true, requestConfig,
),
listPendingApprovals: (orgId: string, networkId?: string, requestConfig?: RequestConfig) =>
request<{ approvals: UserNetworkApproval[]; count: number }>(
`/organizations/${orgId}/approvals/pending${networkId ? `?network_id=${networkId}` : ""}`,
@@ -1558,25 +1572,25 @@ export const api = {
true, requestConfig,
),
// ── ZeroTier Controller (admin) ──────────────────────────────────────────
getZtStatus: (requestConfig?: RequestConfig) =>
// ── ZeroTier Controller (org-scoped admin) ─────────────────────────────────
getZtStatus: (orgId: string, requestConfig?: RequestConfig) =>
request<{ status: Record<string, unknown> }>(
"/admin/zerotier/status", {}, true, requestConfig,
`/admin/zerotier/status?org_id=${orgId}`, {}, true, requestConfig,
),
listZtNetworks: (requestConfig?: RequestConfig) =>
listZtNetworks: (orgId: string, requestConfig?: RequestConfig) =>
request<{ networks: ZeroTierNetwork[]; count: number }>(
"/admin/zerotier/networks", {}, true, requestConfig,
`/admin/zerotier/networks?org_id=${orgId}`, {}, true, requestConfig,
),
getZtNetwork: (networkId: string, requestConfig?: RequestConfig) =>
getZtNetwork: (orgId: string, networkId: string, requestConfig?: RequestConfig) =>
request<{ network: ZeroTierNetwork }>(
`/admin/zerotier/networks/${networkId}`, {}, true, requestConfig,
`/admin/zerotier/networks/${networkId}?org_id=${orgId}`, {}, true, requestConfig,
),
listZtMembers: (networkId: string, requestConfig?: RequestConfig) =>
listZtMembers: (orgId: string, networkId: string, requestConfig?: RequestConfig) =>
request<{ members: ZeroTierMember[]; count: number }>(
`/admin/zerotier/networks/${networkId}/members`, {}, true, requestConfig,
`/admin/zerotier/networks/${networkId}/members?org_id=${orgId}`, {}, true, requestConfig,
),
triggerReconciliation: (requestConfig?: RequestConfig) =>
@@ -1584,6 +1598,26 @@ export const api = {
"/admin/zerotier/reconcile",
{ method: "POST" }, true, requestConfig,
),
// ── Per-org ZeroTier config ──────────────────────────────────────────────
getOrgZtConfig: (orgId: string, requestConfig?: RequestConfig) =>
request<{ zerotier_config: ZeroTierOrgConfig }>(
`/organizations/${orgId}/zerotier-config`,
{}, true, requestConfig,
),
setOrgZtConfig: (orgId: string, data: ZeroTierOrgConfigInput, requestConfig?: RequestConfig) =>
request<{ zerotier_config: ZeroTierOrgConfig; connectivity_test: { ok: boolean; error: string | null } }>(
`/organizations/${orgId}/zerotier-config`,
{ method: "PUT", body: JSON.stringify(data) },
true, requestConfig,
),
deleteOrgZtConfig: (orgId: string, requestConfig?: RequestConfig) =>
request<{ message: string }>(
`/organizations/${orgId}/zerotier-config`,
{ method: "DELETE" }, true, requestConfig,
),
},
};
@@ -1894,6 +1928,21 @@ export interface PortalNetwork {
active_membership_count?: number;
}
/** A ZeroTier network returned from the controller, annotated with whether
* it is already managed as a portal network in Secuird. */
export interface AvailableZtNetwork {
id: string;
name: string;
description: string | null;
owner_id: string | null;
online_member_count: number;
authorized_member_count: number;
total_member_count: number;
already_managed: boolean;
portal_network_id: string | null;
portal_network_name: string | null;
}
export interface Device {
id: string;
user_id: string;
@@ -2038,4 +2087,21 @@ export interface ZeroTierNetwork {
ip_assignment_pools: Record<string, unknown>[];
routes: Record<string, unknown>[];
};
}
/** Current per-org ZeroTier config as returned by GET /organizations/:id/zerotier-config */
export interface ZeroTierOrgConfig {
/** Whether an API token has been saved (the actual value is never returned). */
zt_api_token_set: boolean;
/** Custom controller / Central base URL, or null when server default is used. */
zt_api_url: string | null;
/** "central" | "controller", or null when server default is used. */
zt_api_mode: "central" | "controller" | null;
}
/** Body for PUT /organizations/:id/zerotier-config */
export interface ZeroTierOrgConfigInput {
zt_api_token: string;
zt_api_url: string;
zt_api_mode: "central" | "controller";
}