@gguf/claw
Version:
Multi-channel AI gateway with extensible messaging integrations
1,385 lines (1,367 loc) • 87.5 kB
JavaScript
import { g as resolveStateDir } from "./paths-B4BZAPZh.js";
import { a as logError, i as logDebug } from "./exec-DYqRzFbo.js";
import { h as GATEWAY_CLIENT_NAMES, m as GATEWAY_CLIENT_MODES, p as GATEWAY_CLIENT_IDS } from "./message-channel-Bena1Tzd.js";
import { i as isSecureWebSocketUrl, t as rawDataToString } from "./ws-CV6gEox3.js";
import { t as INPUT_PROVENANCE_KIND_VALUES } from "./input-provenance-DkoU-lPU.js";
import { c as writeJsonAtomic, i as resolvePairingPaths, n as verifyPairingToken, o as createAsyncLock, r as pruneExpiredPending, s as readJsonFile, t as generatePairingToken } from "./pairing-token-B-_eiWlR.js";
import fs from "node:fs";
import path from "node:path";
import crypto, { randomUUID } from "node:crypto";
import AjvPkg from "ajv";
import { WebSocket as WebSocket$1 } from "ws";
import { Type } from "@sinclair/typebox";
//#region src/infra/device-identity.ts
function resolveDefaultIdentityPath() {
return path.join(resolveStateDir(), "identity", "device.json");
}
function ensureDir(filePath) {
fs.mkdirSync(path.dirname(filePath), { recursive: true });
}
const ED25519_SPKI_PREFIX = Buffer.from("302a300506032b6570032100", "hex");
function base64UrlEncode(buf) {
return buf.toString("base64").replaceAll("+", "-").replaceAll("/", "_").replace(/=+$/g, "");
}
function base64UrlDecode(input) {
const normalized = input.replaceAll("-", "+").replaceAll("_", "/");
const padded = normalized + "=".repeat((4 - normalized.length % 4) % 4);
return Buffer.from(padded, "base64");
}
function derivePublicKeyRaw(publicKeyPem) {
const spki = crypto.createPublicKey(publicKeyPem).export({
type: "spki",
format: "der"
});
if (spki.length === ED25519_SPKI_PREFIX.length + 32 && spki.subarray(0, ED25519_SPKI_PREFIX.length).equals(ED25519_SPKI_PREFIX)) return spki.subarray(ED25519_SPKI_PREFIX.length);
return spki;
}
function fingerprintPublicKey(publicKeyPem) {
const raw = derivePublicKeyRaw(publicKeyPem);
return crypto.createHash("sha256").update(raw).digest("hex");
}
function generateIdentity() {
const { publicKey, privateKey } = crypto.generateKeyPairSync("ed25519");
const publicKeyPem = publicKey.export({
type: "spki",
format: "pem"
}).toString();
const privateKeyPem = privateKey.export({
type: "pkcs8",
format: "pem"
}).toString();
return {
deviceId: fingerprintPublicKey(publicKeyPem),
publicKeyPem,
privateKeyPem
};
}
function loadOrCreateDeviceIdentity(filePath = resolveDefaultIdentityPath()) {
try {
if (fs.existsSync(filePath)) {
const raw = fs.readFileSync(filePath, "utf8");
const parsed = JSON.parse(raw);
if (parsed?.version === 1 && typeof parsed.deviceId === "string" && typeof parsed.publicKeyPem === "string" && typeof parsed.privateKeyPem === "string") {
const derivedId = fingerprintPublicKey(parsed.publicKeyPem);
if (derivedId && derivedId !== parsed.deviceId) {
const updated = {
...parsed,
deviceId: derivedId
};
fs.writeFileSync(filePath, `${JSON.stringify(updated, null, 2)}\n`, { mode: 384 });
try {
fs.chmodSync(filePath, 384);
} catch {}
return {
deviceId: derivedId,
publicKeyPem: parsed.publicKeyPem,
privateKeyPem: parsed.privateKeyPem
};
}
return {
deviceId: parsed.deviceId,
publicKeyPem: parsed.publicKeyPem,
privateKeyPem: parsed.privateKeyPem
};
}
}
} catch {}
const identity = generateIdentity();
ensureDir(filePath);
const stored = {
version: 1,
deviceId: identity.deviceId,
publicKeyPem: identity.publicKeyPem,
privateKeyPem: identity.privateKeyPem,
createdAtMs: Date.now()
};
fs.writeFileSync(filePath, `${JSON.stringify(stored, null, 2)}\n`, { mode: 384 });
try {
fs.chmodSync(filePath, 384);
} catch {}
return identity;
}
function signDevicePayload(privateKeyPem, payload) {
const key = crypto.createPrivateKey(privateKeyPem);
return base64UrlEncode(crypto.sign(null, Buffer.from(payload, "utf8"), key));
}
function normalizeDevicePublicKeyBase64Url(publicKey) {
try {
if (publicKey.includes("BEGIN")) return base64UrlEncode(derivePublicKeyRaw(publicKey));
return base64UrlEncode(base64UrlDecode(publicKey));
} catch {
return null;
}
}
function deriveDeviceIdFromPublicKey(publicKey) {
try {
const raw = publicKey.includes("BEGIN") ? derivePublicKeyRaw(publicKey) : base64UrlDecode(publicKey);
return crypto.createHash("sha256").update(raw).digest("hex");
} catch {
return null;
}
}
function publicKeyRawBase64UrlFromPem(publicKeyPem) {
return base64UrlEncode(derivePublicKeyRaw(publicKeyPem));
}
function verifyDeviceSignature(publicKey, payload, signatureBase64Url) {
try {
const key = publicKey.includes("BEGIN") ? crypto.createPublicKey(publicKey) : crypto.createPublicKey({
key: Buffer.concat([ED25519_SPKI_PREFIX, base64UrlDecode(publicKey)]),
type: "spki",
format: "der"
});
const sig = (() => {
try {
return base64UrlDecode(signatureBase64Url);
} catch {
return Buffer.from(signatureBase64Url, "base64");
}
})();
return crypto.verify(null, Buffer.from(payload, "utf8"), key, sig);
} catch {
return false;
}
}
//#endregion
//#region src/infra/tls/fingerprint.ts
function normalizeFingerprint(input) {
return input.trim().replace(/^sha-?256\s*:?\s*/i, "").replace(/[^a-fA-F0-9]/g, "").toLowerCase();
}
//#endregion
//#region src/shared/device-auth.ts
function normalizeDeviceAuthRole(role) {
return role.trim();
}
function normalizeDeviceAuthScopes(scopes) {
if (!Array.isArray(scopes)) return [];
const out = /* @__PURE__ */ new Set();
for (const scope of scopes) {
const trimmed = scope.trim();
if (trimmed) out.add(trimmed);
}
return [...out].toSorted();
}
//#endregion
//#region src/infra/device-auth-store.ts
const DEVICE_AUTH_FILE = "device-auth.json";
function resolveDeviceAuthPath(env = process.env) {
return path.join(resolveStateDir(env), "identity", DEVICE_AUTH_FILE);
}
function readStore(filePath) {
try {
if (!fs.existsSync(filePath)) return null;
const raw = fs.readFileSync(filePath, "utf8");
const parsed = JSON.parse(raw);
if (parsed?.version !== 1 || typeof parsed.deviceId !== "string") return null;
if (!parsed.tokens || typeof parsed.tokens !== "object") return null;
return parsed;
} catch {
return null;
}
}
function writeStore(filePath, store) {
fs.mkdirSync(path.dirname(filePath), { recursive: true });
fs.writeFileSync(filePath, `${JSON.stringify(store, null, 2)}\n`, { mode: 384 });
try {
fs.chmodSync(filePath, 384);
} catch {}
}
function loadDeviceAuthToken(params) {
const store = readStore(resolveDeviceAuthPath(params.env));
if (!store) return null;
if (store.deviceId !== params.deviceId) return null;
const role = normalizeDeviceAuthRole(params.role);
const entry = store.tokens[role];
if (!entry || typeof entry.token !== "string") return null;
return entry;
}
function storeDeviceAuthToken(params) {
const filePath = resolveDeviceAuthPath(params.env);
const existing = readStore(filePath);
const role = normalizeDeviceAuthRole(params.role);
const next = {
version: 1,
deviceId: params.deviceId,
tokens: existing && existing.deviceId === params.deviceId && existing.tokens ? { ...existing.tokens } : {}
};
const entry = {
token: params.token,
role,
scopes: normalizeDeviceAuthScopes(params.scopes),
updatedAtMs: Date.now()
};
next.tokens[role] = entry;
writeStore(filePath, next);
return entry;
}
function clearDeviceAuthToken(params) {
const filePath = resolveDeviceAuthPath(params.env);
const store = readStore(filePath);
if (!store || store.deviceId !== params.deviceId) return;
const role = normalizeDeviceAuthRole(params.role);
if (!store.tokens[role]) return;
const next = {
version: 1,
deviceId: store.deviceId,
tokens: { ...store.tokens }
};
delete next.tokens[role];
writeStore(filePath, next);
}
//#endregion
//#region src/shared/operator-scope-compat.ts
const OPERATOR_ROLE = "operator";
const OPERATOR_ADMIN_SCOPE = "operator.admin";
const OPERATOR_READ_SCOPE = "operator.read";
const OPERATOR_WRITE_SCOPE = "operator.write";
function normalizeScopeList(scopes) {
const out = /* @__PURE__ */ new Set();
for (const scope of scopes) {
const trimmed = scope.trim();
if (trimmed) out.add(trimmed);
}
return [...out];
}
function operatorScopeSatisfied(requestedScope, granted) {
if (requestedScope === OPERATOR_READ_SCOPE) return granted.has(OPERATOR_READ_SCOPE) || granted.has(OPERATOR_WRITE_SCOPE) || granted.has(OPERATOR_ADMIN_SCOPE);
return granted.has(requestedScope);
}
function roleScopesAllow(params) {
const requested = normalizeScopeList(params.requestedScopes);
if (requested.length === 0) return true;
const allowed = normalizeScopeList(params.allowedScopes);
if (allowed.length === 0) return false;
const allowedSet = new Set(allowed);
if (params.role.trim() !== OPERATOR_ROLE) return requested.every((scope) => allowedSet.has(scope));
return requested.every((scope) => operatorScopeSatisfied(scope, allowedSet));
}
//#endregion
//#region src/infra/device-pairing.ts
const PENDING_TTL_MS = 300 * 1e3;
const withLock = createAsyncLock();
async function loadState(baseDir) {
const { pendingPath, pairedPath } = resolvePairingPaths(baseDir, "devices");
const [pending, paired] = await Promise.all([readJsonFile(pendingPath), readJsonFile(pairedPath)]);
const state = {
pendingById: pending ?? {},
pairedByDeviceId: paired ?? {}
};
pruneExpiredPending(state.pendingById, Date.now(), PENDING_TTL_MS);
return state;
}
async function persistState(state, baseDir) {
const { pendingPath, pairedPath } = resolvePairingPaths(baseDir, "devices");
await Promise.all([writeJsonAtomic(pendingPath, state.pendingById), writeJsonAtomic(pairedPath, state.pairedByDeviceId)]);
}
function normalizeDeviceId(deviceId) {
return deviceId.trim();
}
function normalizeRole(role) {
const trimmed = role?.trim();
return trimmed ? trimmed : null;
}
function mergeRoles(...items) {
const roles = /* @__PURE__ */ new Set();
for (const item of items) {
if (!item) continue;
if (Array.isArray(item)) for (const role of item) {
const trimmed = role.trim();
if (trimmed) roles.add(trimmed);
}
else {
const trimmed = item.trim();
if (trimmed) roles.add(trimmed);
}
}
if (roles.size === 0) return;
return [...roles];
}
function mergeScopes(...items) {
const scopes = /* @__PURE__ */ new Set();
for (const item of items) {
if (!item) continue;
for (const scope of item) {
const trimmed = scope.trim();
if (trimmed) scopes.add(trimmed);
}
}
if (scopes.size === 0) return;
return [...scopes];
}
function mergePendingDevicePairingRequest(existing, incoming, isRepair) {
const existingRole = normalizeRole(existing.role);
const incomingRole = normalizeRole(incoming.role);
return {
...existing,
displayName: incoming.displayName ?? existing.displayName,
platform: incoming.platform ?? existing.platform,
clientId: incoming.clientId ?? existing.clientId,
clientMode: incoming.clientMode ?? existing.clientMode,
role: existingRole ?? incomingRole ?? void 0,
roles: mergeRoles(existing.roles, existing.role, incoming.role),
scopes: mergeScopes(existing.scopes, incoming.scopes),
remoteIp: incoming.remoteIp ?? existing.remoteIp,
silent: Boolean(existing.silent && incoming.silent),
isRepair: existing.isRepair || isRepair,
ts: Date.now()
};
}
function scopesAllow(requested, allowed) {
if (requested.length === 0) return true;
if (allowed.length === 0) return false;
const allowedSet = new Set(allowed);
return requested.every((scope) => allowedSet.has(scope));
}
const DEVICE_SCOPE_IMPLICATIONS = {
"operator.admin": [
"operator.read",
"operator.write",
"operator.approvals",
"operator.pairing"
],
"operator.write": ["operator.read"]
};
function expandScopeImplications(scopes) {
const expanded = new Set(scopes);
const queue = [...scopes];
while (queue.length > 0) {
const scope = queue.pop();
if (!scope) continue;
for (const impliedScope of DEVICE_SCOPE_IMPLICATIONS[scope] ?? []) if (!expanded.has(impliedScope)) {
expanded.add(impliedScope);
queue.push(impliedScope);
}
}
return [...expanded];
}
function scopesAllowWithImplications(requested, allowed) {
return scopesAllow(expandScopeImplications(requested), expandScopeImplications(allowed));
}
function newToken() {
return generatePairingToken();
}
function getPairedDeviceFromState(state, deviceId) {
return state.pairedByDeviceId[normalizeDeviceId(deviceId)] ?? null;
}
function cloneDeviceTokens(device) {
return device.tokens ? { ...device.tokens } : {};
}
function buildDeviceAuthToken(params) {
return {
token: newToken(),
role: params.role,
scopes: params.scopes,
createdAtMs: params.existing?.createdAtMs ?? params.now,
rotatedAtMs: params.rotatedAtMs,
revokedAtMs: void 0,
lastUsedAtMs: params.existing?.lastUsedAtMs
};
}
async function listDevicePairing(baseDir) {
const state = await loadState(baseDir);
return {
pending: Object.values(state.pendingById).toSorted((a, b) => b.ts - a.ts),
paired: Object.values(state.pairedByDeviceId).toSorted((a, b) => b.approvedAtMs - a.approvedAtMs)
};
}
async function getPairedDevice(deviceId, baseDir) {
return (await loadState(baseDir)).pairedByDeviceId[normalizeDeviceId(deviceId)] ?? null;
}
async function requestDevicePairing(req, baseDir) {
return await withLock(async () => {
const state = await loadState(baseDir);
const deviceId = normalizeDeviceId(req.deviceId);
if (!deviceId) throw new Error("deviceId required");
const isRepair = Boolean(state.pairedByDeviceId[deviceId]);
const existing = Object.values(state.pendingById).find((pending) => pending.deviceId === deviceId);
if (existing) {
const merged = mergePendingDevicePairingRequest(existing, req, isRepair);
state.pendingById[existing.requestId] = merged;
await persistState(state, baseDir);
return {
status: "pending",
request: merged,
created: false
};
}
const request = {
requestId: randomUUID(),
deviceId,
publicKey: req.publicKey,
displayName: req.displayName,
platform: req.platform,
clientId: req.clientId,
clientMode: req.clientMode,
role: req.role,
roles: req.role ? [req.role] : void 0,
scopes: req.scopes,
remoteIp: req.remoteIp,
silent: req.silent,
isRepair,
ts: Date.now()
};
state.pendingById[request.requestId] = request;
await persistState(state, baseDir);
return {
status: "pending",
request,
created: true
};
});
}
async function approveDevicePairing(requestId, baseDir) {
return await withLock(async () => {
const state = await loadState(baseDir);
const pending = state.pendingById[requestId];
if (!pending) return null;
const now = Date.now();
const existing = state.pairedByDeviceId[pending.deviceId];
const roles = mergeRoles(existing?.roles, existing?.role, pending.roles, pending.role);
const approvedScopes = mergeScopes(existing?.approvedScopes ?? existing?.scopes, pending.scopes);
const tokens = existing?.tokens ? { ...existing.tokens } : {};
const roleForToken = normalizeRole(pending.role);
if (roleForToken) {
const nextScopes = normalizeDeviceAuthScopes(pending.scopes);
const existingToken = tokens[roleForToken];
const now = Date.now();
tokens[roleForToken] = {
token: newToken(),
role: roleForToken,
scopes: nextScopes,
createdAtMs: existingToken?.createdAtMs ?? now,
rotatedAtMs: existingToken ? now : void 0,
revokedAtMs: void 0,
lastUsedAtMs: existingToken?.lastUsedAtMs
};
}
const device = {
deviceId: pending.deviceId,
publicKey: pending.publicKey,
displayName: pending.displayName,
platform: pending.platform,
clientId: pending.clientId,
clientMode: pending.clientMode,
role: pending.role,
roles,
scopes: approvedScopes,
approvedScopes,
remoteIp: pending.remoteIp,
tokens,
createdAtMs: existing?.createdAtMs ?? now,
approvedAtMs: now
};
delete state.pendingById[requestId];
state.pairedByDeviceId[device.deviceId] = device;
await persistState(state, baseDir);
return {
requestId,
device
};
});
}
async function rejectDevicePairing(requestId, baseDir) {
return await withLock(async () => {
const state = await loadState(baseDir);
const pending = state.pendingById[requestId];
if (!pending) return null;
delete state.pendingById[requestId];
await persistState(state, baseDir);
return {
requestId,
deviceId: pending.deviceId
};
});
}
async function removePairedDevice(deviceId, baseDir) {
return await withLock(async () => {
const state = await loadState(baseDir);
const normalized = normalizeDeviceId(deviceId);
if (!normalized || !state.pairedByDeviceId[normalized]) return null;
delete state.pairedByDeviceId[normalized];
await persistState(state, baseDir);
return { deviceId: normalized };
});
}
async function updatePairedDeviceMetadata(deviceId, patch, baseDir) {
return await withLock(async () => {
const state = await loadState(baseDir);
const existing = state.pairedByDeviceId[normalizeDeviceId(deviceId)];
if (!existing) return;
const roles = mergeRoles(existing.roles, existing.role, patch.role);
const scopes = mergeScopes(existing.scopes, patch.scopes);
state.pairedByDeviceId[deviceId] = {
...existing,
...patch,
deviceId: existing.deviceId,
createdAtMs: existing.createdAtMs,
approvedAtMs: existing.approvedAtMs,
approvedScopes: existing.approvedScopes,
role: patch.role ?? existing.role,
roles,
scopes
};
await persistState(state, baseDir);
});
}
function summarizeDeviceTokens(tokens) {
if (!tokens) return;
const summaries = Object.values(tokens).map((token) => ({
role: token.role,
scopes: token.scopes,
createdAtMs: token.createdAtMs,
rotatedAtMs: token.rotatedAtMs,
revokedAtMs: token.revokedAtMs,
lastUsedAtMs: token.lastUsedAtMs
})).toSorted((a, b) => a.role.localeCompare(b.role));
return summaries.length > 0 ? summaries : void 0;
}
async function verifyDeviceToken(params) {
return await withLock(async () => {
const state = await loadState(params.baseDir);
const device = getPairedDeviceFromState(state, params.deviceId);
if (!device) return {
ok: false,
reason: "device-not-paired"
};
const role = normalizeRole(params.role);
if (!role) return {
ok: false,
reason: "role-missing"
};
const entry = device.tokens?.[role];
if (!entry) return {
ok: false,
reason: "token-missing"
};
if (entry.revokedAtMs) return {
ok: false,
reason: "token-revoked"
};
if (!verifyPairingToken(params.token, entry.token)) return {
ok: false,
reason: "token-mismatch"
};
if (!roleScopesAllow({
role,
requestedScopes: normalizeDeviceAuthScopes(params.scopes),
allowedScopes: entry.scopes
})) return {
ok: false,
reason: "scope-mismatch"
};
entry.lastUsedAtMs = Date.now();
device.tokens ??= {};
device.tokens[role] = entry;
state.pairedByDeviceId[device.deviceId] = device;
await persistState(state, params.baseDir);
return { ok: true };
});
}
async function ensureDeviceToken(params) {
return await withLock(async () => {
const state = await loadState(params.baseDir);
const requestedScopes = normalizeDeviceAuthScopes(params.scopes);
const context = resolveDeviceTokenUpdateContext({
state,
deviceId: params.deviceId,
role: params.role
});
if (!context) return null;
const { device, role, tokens, existing } = context;
if (existing && !existing.revokedAtMs) {
if (roleScopesAllow({
role,
requestedScopes,
allowedScopes: existing.scopes
})) return existing;
}
const now = Date.now();
const next = buildDeviceAuthToken({
role,
scopes: requestedScopes,
existing,
now,
rotatedAtMs: existing ? now : void 0
});
tokens[role] = next;
device.tokens = tokens;
state.pairedByDeviceId[device.deviceId] = device;
await persistState(state, params.baseDir);
return next;
});
}
function resolveDeviceTokenUpdateContext(params) {
const device = getPairedDeviceFromState(params.state, params.deviceId);
if (!device) return null;
const role = normalizeRole(params.role);
if (!role) return null;
const tokens = cloneDeviceTokens(device);
return {
device,
role,
tokens,
existing: tokens[role]
};
}
async function rotateDeviceToken(params) {
return await withLock(async () => {
const state = await loadState(params.baseDir);
const context = resolveDeviceTokenUpdateContext({
state,
deviceId: params.deviceId,
role: params.role
});
if (!context) return null;
const { device, role, tokens, existing } = context;
const requestedScopes = normalizeDeviceAuthScopes(params.scopes ?? existing?.scopes ?? device.scopes);
if (!scopesAllowWithImplications(requestedScopes, normalizeDeviceAuthScopes(device.approvedScopes ?? device.scopes ?? existing?.scopes))) return null;
const now = Date.now();
const next = buildDeviceAuthToken({
role,
scopes: requestedScopes,
existing,
now,
rotatedAtMs: now
});
tokens[role] = next;
device.tokens = tokens;
state.pairedByDeviceId[device.deviceId] = device;
await persistState(state, params.baseDir);
return next;
});
}
async function revokeDeviceToken(params) {
return await withLock(async () => {
const state = await loadState(params.baseDir);
const device = state.pairedByDeviceId[normalizeDeviceId(params.deviceId)];
if (!device) return null;
const role = normalizeRole(params.role);
if (!role) return null;
if (!device.tokens?.[role]) return null;
const tokens = { ...device.tokens };
const entry = {
...tokens[role],
revokedAtMs: Date.now()
};
tokens[role] = entry;
device.tokens = tokens;
state.pairedByDeviceId[device.deviceId] = device;
await persistState(state, params.baseDir);
return entry;
});
}
async function clearDevicePairing(deviceId, baseDir) {
return await withLock(async () => {
const state = await loadState(baseDir);
const normalizedId = normalizeDeviceId(deviceId);
if (!state.pairedByDeviceId[normalizedId]) return false;
delete state.pairedByDeviceId[normalizedId];
await persistState(state, baseDir);
return true;
});
}
//#endregion
//#region src/gateway/device-auth.ts
function buildDeviceAuthPayload(params) {
const version = params.version ?? (params.nonce ? "v2" : "v1");
const scopes = params.scopes.join(",");
const token = params.token ?? "";
const base = [
version,
params.deviceId,
params.clientId,
params.clientMode,
params.role,
scopes,
String(params.signedAtMs),
token
];
if (version === "v2") base.push(params.nonce ?? "");
return base.join("|");
}
//#endregion
//#region src/sessions/session-label.ts
const SESSION_LABEL_MAX_LENGTH = 64;
function parseSessionLabel(raw) {
if (typeof raw !== "string") return {
ok: false,
error: "invalid label: must be a string"
};
const trimmed = raw.trim();
if (!trimmed) return {
ok: false,
error: "invalid label: empty"
};
if (trimmed.length > SESSION_LABEL_MAX_LENGTH) return {
ok: false,
error: `invalid label: too long (max ${SESSION_LABEL_MAX_LENGTH})`
};
return {
ok: true,
label: trimmed
};
}
//#endregion
//#region src/gateway/protocol/schema/primitives.ts
const NonEmptyString = Type.String({ minLength: 1 });
const SessionLabelString = Type.String({
minLength: 1,
maxLength: SESSION_LABEL_MAX_LENGTH
});
const GatewayClientIdSchema = Type.Union(Object.values(GATEWAY_CLIENT_IDS).map((value) => Type.Literal(value)));
const GatewayClientModeSchema = Type.Union(Object.values(GATEWAY_CLIENT_MODES).map((value) => Type.Literal(value)));
//#endregion
//#region src/gateway/protocol/schema/agent.ts
const AgentEventSchema = Type.Object({
runId: NonEmptyString,
seq: Type.Integer({ minimum: 0 }),
stream: NonEmptyString,
ts: Type.Integer({ minimum: 0 }),
data: Type.Record(Type.String(), Type.Unknown())
}, { additionalProperties: false });
const SendParamsSchema = Type.Object({
to: NonEmptyString,
message: Type.Optional(Type.String()),
mediaUrl: Type.Optional(Type.String()),
mediaUrls: Type.Optional(Type.Array(Type.String())),
gifPlayback: Type.Optional(Type.Boolean()),
channel: Type.Optional(Type.String()),
accountId: Type.Optional(Type.String()),
threadId: Type.Optional(Type.String()),
sessionKey: Type.Optional(Type.String()),
idempotencyKey: NonEmptyString
}, { additionalProperties: false });
const PollParamsSchema = Type.Object({
to: NonEmptyString,
question: NonEmptyString,
options: Type.Array(NonEmptyString, {
minItems: 2,
maxItems: 12
}),
maxSelections: Type.Optional(Type.Integer({
minimum: 1,
maximum: 12
})),
durationSeconds: Type.Optional(Type.Integer({
minimum: 1,
maximum: 604800
})),
durationHours: Type.Optional(Type.Integer({ minimum: 1 })),
silent: Type.Optional(Type.Boolean()),
isAnonymous: Type.Optional(Type.Boolean()),
threadId: Type.Optional(Type.String()),
channel: Type.Optional(Type.String()),
accountId: Type.Optional(Type.String()),
idempotencyKey: NonEmptyString
}, { additionalProperties: false });
const AgentParamsSchema = Type.Object({
message: NonEmptyString,
agentId: Type.Optional(NonEmptyString),
to: Type.Optional(Type.String()),
replyTo: Type.Optional(Type.String()),
sessionId: Type.Optional(Type.String()),
sessionKey: Type.Optional(Type.String()),
thinking: Type.Optional(Type.String()),
deliver: Type.Optional(Type.Boolean()),
attachments: Type.Optional(Type.Array(Type.Unknown())),
channel: Type.Optional(Type.String()),
replyChannel: Type.Optional(Type.String()),
accountId: Type.Optional(Type.String()),
replyAccountId: Type.Optional(Type.String()),
threadId: Type.Optional(Type.String()),
groupId: Type.Optional(Type.String()),
groupChannel: Type.Optional(Type.String()),
groupSpace: Type.Optional(Type.String()),
timeout: Type.Optional(Type.Integer({ minimum: 0 })),
lane: Type.Optional(Type.String()),
extraSystemPrompt: Type.Optional(Type.String()),
inputProvenance: Type.Optional(Type.Object({
kind: Type.String({ enum: [...INPUT_PROVENANCE_KIND_VALUES] }),
sourceSessionKey: Type.Optional(Type.String()),
sourceChannel: Type.Optional(Type.String()),
sourceTool: Type.Optional(Type.String())
}, { additionalProperties: false })),
idempotencyKey: NonEmptyString,
label: Type.Optional(SessionLabelString),
spawnedBy: Type.Optional(Type.String())
}, { additionalProperties: false });
const AgentIdentityParamsSchema = Type.Object({
agentId: Type.Optional(NonEmptyString),
sessionKey: Type.Optional(Type.String())
}, { additionalProperties: false });
const AgentIdentityResultSchema = Type.Object({
agentId: NonEmptyString,
name: Type.Optional(NonEmptyString),
avatar: Type.Optional(NonEmptyString),
emoji: Type.Optional(NonEmptyString)
}, { additionalProperties: false });
const AgentWaitParamsSchema = Type.Object({
runId: NonEmptyString,
timeoutMs: Type.Optional(Type.Integer({ minimum: 0 }))
}, { additionalProperties: false });
const WakeParamsSchema = Type.Object({
mode: Type.Union([Type.Literal("now"), Type.Literal("next-heartbeat")]),
text: NonEmptyString
}, { additionalProperties: false });
//#endregion
//#region src/gateway/protocol/schema/agents-models-skills.ts
const ModelChoiceSchema = Type.Object({
id: NonEmptyString,
name: NonEmptyString,
provider: NonEmptyString,
contextWindow: Type.Optional(Type.Integer({ minimum: 1 })),
reasoning: Type.Optional(Type.Boolean())
}, { additionalProperties: false });
const AgentSummarySchema = Type.Object({
id: NonEmptyString,
name: Type.Optional(NonEmptyString),
identity: Type.Optional(Type.Object({
name: Type.Optional(NonEmptyString),
theme: Type.Optional(NonEmptyString),
emoji: Type.Optional(NonEmptyString),
avatar: Type.Optional(NonEmptyString),
avatarUrl: Type.Optional(NonEmptyString)
}, { additionalProperties: false }))
}, { additionalProperties: false });
const AgentsListParamsSchema = Type.Object({}, { additionalProperties: false });
const AgentsListResultSchema = Type.Object({
defaultId: NonEmptyString,
mainKey: NonEmptyString,
scope: Type.Union([Type.Literal("per-sender"), Type.Literal("global")]),
agents: Type.Array(AgentSummarySchema)
}, { additionalProperties: false });
const AgentsCreateParamsSchema = Type.Object({
name: NonEmptyString,
workspace: NonEmptyString,
emoji: Type.Optional(Type.String()),
avatar: Type.Optional(Type.String())
}, { additionalProperties: false });
const AgentsCreateResultSchema = Type.Object({
ok: Type.Literal(true),
agentId: NonEmptyString,
name: NonEmptyString,
workspace: NonEmptyString
}, { additionalProperties: false });
const AgentsUpdateParamsSchema = Type.Object({
agentId: NonEmptyString,
name: Type.Optional(NonEmptyString),
workspace: Type.Optional(NonEmptyString),
model: Type.Optional(NonEmptyString),
avatar: Type.Optional(Type.String())
}, { additionalProperties: false });
const AgentsUpdateResultSchema = Type.Object({
ok: Type.Literal(true),
agentId: NonEmptyString
}, { additionalProperties: false });
const AgentsDeleteParamsSchema = Type.Object({
agentId: NonEmptyString,
deleteFiles: Type.Optional(Type.Boolean())
}, { additionalProperties: false });
const AgentsDeleteResultSchema = Type.Object({
ok: Type.Literal(true),
agentId: NonEmptyString,
removedBindings: Type.Integer({ minimum: 0 })
}, { additionalProperties: false });
const AgentsFileEntrySchema = Type.Object({
name: NonEmptyString,
path: NonEmptyString,
missing: Type.Boolean(),
size: Type.Optional(Type.Integer({ minimum: 0 })),
updatedAtMs: Type.Optional(Type.Integer({ minimum: 0 })),
content: Type.Optional(Type.String())
}, { additionalProperties: false });
const AgentsFilesListParamsSchema = Type.Object({ agentId: NonEmptyString }, { additionalProperties: false });
const AgentsFilesListResultSchema = Type.Object({
agentId: NonEmptyString,
workspace: NonEmptyString,
files: Type.Array(AgentsFileEntrySchema)
}, { additionalProperties: false });
const AgentsFilesGetParamsSchema = Type.Object({
agentId: NonEmptyString,
name: NonEmptyString
}, { additionalProperties: false });
const AgentsFilesGetResultSchema = Type.Object({
agentId: NonEmptyString,
workspace: NonEmptyString,
file: AgentsFileEntrySchema
}, { additionalProperties: false });
const AgentsFilesSetParamsSchema = Type.Object({
agentId: NonEmptyString,
name: NonEmptyString,
content: Type.String()
}, { additionalProperties: false });
const AgentsFilesSetResultSchema = Type.Object({
ok: Type.Literal(true),
agentId: NonEmptyString,
workspace: NonEmptyString,
file: AgentsFileEntrySchema
}, { additionalProperties: false });
const ModelsListParamsSchema = Type.Object({}, { additionalProperties: false });
const ModelsListResultSchema = Type.Object({ models: Type.Array(ModelChoiceSchema) }, { additionalProperties: false });
const SkillsStatusParamsSchema = Type.Object({ agentId: Type.Optional(NonEmptyString) }, { additionalProperties: false });
const SkillsBinsParamsSchema = Type.Object({}, { additionalProperties: false });
const SkillsBinsResultSchema = Type.Object({ bins: Type.Array(NonEmptyString) }, { additionalProperties: false });
const SkillsInstallParamsSchema = Type.Object({
name: NonEmptyString,
installId: NonEmptyString,
timeoutMs: Type.Optional(Type.Integer({ minimum: 1e3 }))
}, { additionalProperties: false });
const SkillsUpdateParamsSchema = Type.Object({
skillKey: NonEmptyString,
enabled: Type.Optional(Type.Boolean()),
apiKey: Type.Optional(Type.String()),
env: Type.Optional(Type.Record(NonEmptyString, Type.String()))
}, { additionalProperties: false });
//#endregion
//#region src/gateway/protocol/schema/channels.ts
const TalkModeParamsSchema = Type.Object({
enabled: Type.Boolean(),
phase: Type.Optional(Type.String())
}, { additionalProperties: false });
const TalkConfigParamsSchema = Type.Object({ includeSecrets: Type.Optional(Type.Boolean()) }, { additionalProperties: false });
const TalkConfigResultSchema = Type.Object({ config: Type.Object({
talk: Type.Optional(Type.Object({
voiceId: Type.Optional(Type.String()),
voiceAliases: Type.Optional(Type.Record(Type.String(), Type.String())),
modelId: Type.Optional(Type.String()),
outputFormat: Type.Optional(Type.String()),
apiKey: Type.Optional(Type.String()),
interruptOnSpeech: Type.Optional(Type.Boolean())
}, { additionalProperties: false })),
session: Type.Optional(Type.Object({ mainKey: Type.Optional(Type.String()) }, { additionalProperties: false })),
ui: Type.Optional(Type.Object({ seamColor: Type.Optional(Type.String()) }, { additionalProperties: false }))
}, { additionalProperties: false }) }, { additionalProperties: false });
const ChannelsStatusParamsSchema = Type.Object({
probe: Type.Optional(Type.Boolean()),
timeoutMs: Type.Optional(Type.Integer({ minimum: 0 }))
}, { additionalProperties: false });
const ChannelAccountSnapshotSchema = Type.Object({
accountId: NonEmptyString,
name: Type.Optional(Type.String()),
enabled: Type.Optional(Type.Boolean()),
configured: Type.Optional(Type.Boolean()),
linked: Type.Optional(Type.Boolean()),
running: Type.Optional(Type.Boolean()),
connected: Type.Optional(Type.Boolean()),
reconnectAttempts: Type.Optional(Type.Integer({ minimum: 0 })),
lastConnectedAt: Type.Optional(Type.Integer({ minimum: 0 })),
lastError: Type.Optional(Type.String()),
lastStartAt: Type.Optional(Type.Integer({ minimum: 0 })),
lastStopAt: Type.Optional(Type.Integer({ minimum: 0 })),
lastInboundAt: Type.Optional(Type.Integer({ minimum: 0 })),
lastOutboundAt: Type.Optional(Type.Integer({ minimum: 0 })),
lastProbeAt: Type.Optional(Type.Integer({ minimum: 0 })),
mode: Type.Optional(Type.String()),
dmPolicy: Type.Optional(Type.String()),
allowFrom: Type.Optional(Type.Array(Type.String())),
tokenSource: Type.Optional(Type.String()),
botTokenSource: Type.Optional(Type.String()),
appTokenSource: Type.Optional(Type.String()),
baseUrl: Type.Optional(Type.String()),
allowUnmentionedGroups: Type.Optional(Type.Boolean()),
cliPath: Type.Optional(Type.Union([Type.String(), Type.Null()])),
dbPath: Type.Optional(Type.Union([Type.String(), Type.Null()])),
port: Type.Optional(Type.Union([Type.Integer({ minimum: 0 }), Type.Null()])),
probe: Type.Optional(Type.Unknown()),
audit: Type.Optional(Type.Unknown()),
application: Type.Optional(Type.Unknown())
}, { additionalProperties: true });
const ChannelUiMetaSchema = Type.Object({
id: NonEmptyString,
label: NonEmptyString,
detailLabel: NonEmptyString,
systemImage: Type.Optional(Type.String())
}, { additionalProperties: false });
const ChannelsStatusResultSchema = Type.Object({
ts: Type.Integer({ minimum: 0 }),
channelOrder: Type.Array(NonEmptyString),
channelLabels: Type.Record(NonEmptyString, NonEmptyString),
channelDetailLabels: Type.Optional(Type.Record(NonEmptyString, NonEmptyString)),
channelSystemImages: Type.Optional(Type.Record(NonEmptyString, NonEmptyString)),
channelMeta: Type.Optional(Type.Array(ChannelUiMetaSchema)),
channels: Type.Record(NonEmptyString, Type.Unknown()),
channelAccounts: Type.Record(NonEmptyString, Type.Array(ChannelAccountSnapshotSchema)),
channelDefaultAccountId: Type.Record(NonEmptyString, NonEmptyString)
}, { additionalProperties: false });
const ChannelsLogoutParamsSchema = Type.Object({
channel: NonEmptyString,
accountId: Type.Optional(Type.String())
}, { additionalProperties: false });
const WebLoginStartParamsSchema = Type.Object({
force: Type.Optional(Type.Boolean()),
timeoutMs: Type.Optional(Type.Integer({ minimum: 0 })),
verbose: Type.Optional(Type.Boolean()),
accountId: Type.Optional(Type.String())
}, { additionalProperties: false });
const WebLoginWaitParamsSchema = Type.Object({
timeoutMs: Type.Optional(Type.Integer({ minimum: 0 })),
accountId: Type.Optional(Type.String())
}, { additionalProperties: false });
//#endregion
//#region src/gateway/protocol/schema/config.ts
const ConfigGetParamsSchema = Type.Object({}, { additionalProperties: false });
const ConfigSetParamsSchema = Type.Object({
raw: NonEmptyString,
baseHash: Type.Optional(NonEmptyString)
}, { additionalProperties: false });
const ConfigApplyLikeParamsSchema = Type.Object({
raw: NonEmptyString,
baseHash: Type.Optional(NonEmptyString),
sessionKey: Type.Optional(Type.String()),
note: Type.Optional(Type.String()),
restartDelayMs: Type.Optional(Type.Integer({ minimum: 0 }))
}, { additionalProperties: false });
const ConfigApplyParamsSchema = ConfigApplyLikeParamsSchema;
const ConfigPatchParamsSchema = ConfigApplyLikeParamsSchema;
const ConfigSchemaParamsSchema = Type.Object({}, { additionalProperties: false });
const UpdateRunParamsSchema = Type.Object({
sessionKey: Type.Optional(Type.String()),
note: Type.Optional(Type.String()),
restartDelayMs: Type.Optional(Type.Integer({ minimum: 0 })),
timeoutMs: Type.Optional(Type.Integer({ minimum: 1 }))
}, { additionalProperties: false });
const ConfigUiHintSchema = Type.Object({
label: Type.Optional(Type.String()),
help: Type.Optional(Type.String()),
group: Type.Optional(Type.String()),
order: Type.Optional(Type.Integer()),
advanced: Type.Optional(Type.Boolean()),
sensitive: Type.Optional(Type.Boolean()),
placeholder: Type.Optional(Type.String()),
itemTemplate: Type.Optional(Type.Unknown())
}, { additionalProperties: false });
const ConfigSchemaResponseSchema = Type.Object({
schema: Type.Unknown(),
uiHints: Type.Record(Type.String(), ConfigUiHintSchema),
version: NonEmptyString,
generatedAt: NonEmptyString
}, { additionalProperties: false });
//#endregion
//#region src/gateway/protocol/schema/cron.ts
function cronAgentTurnPayloadSchema(params) {
return Type.Object({
kind: Type.Literal("agentTurn"),
message: params.message,
model: Type.Optional(Type.String()),
thinking: Type.Optional(Type.String()),
timeoutSeconds: Type.Optional(Type.Integer({ minimum: 0 })),
allowUnsafeExternalContent: Type.Optional(Type.Boolean()),
deliver: Type.Optional(Type.Boolean()),
channel: Type.Optional(Type.String()),
to: Type.Optional(Type.String()),
bestEffortDeliver: Type.Optional(Type.Boolean())
}, { additionalProperties: false });
}
const CronSessionTargetSchema = Type.Union([Type.Literal("main"), Type.Literal("isolated")]);
const CronWakeModeSchema = Type.Union([Type.Literal("next-heartbeat"), Type.Literal("now")]);
const CronCommonOptionalFields = {
agentId: Type.Optional(Type.Union([NonEmptyString, Type.Null()])),
sessionKey: Type.Optional(Type.Union([NonEmptyString, Type.Null()])),
description: Type.Optional(Type.String()),
enabled: Type.Optional(Type.Boolean()),
deleteAfterRun: Type.Optional(Type.Boolean())
};
function cronIdOrJobIdParams(extraFields) {
return Type.Union([Type.Object({
id: NonEmptyString,
...extraFields
}, { additionalProperties: false }), Type.Object({
jobId: NonEmptyString,
...extraFields
}, { additionalProperties: false })]);
}
const CronScheduleSchema = Type.Union([
Type.Object({
kind: Type.Literal("at"),
at: NonEmptyString
}, { additionalProperties: false }),
Type.Object({
kind: Type.Literal("every"),
everyMs: Type.Integer({ minimum: 1 }),
anchorMs: Type.Optional(Type.Integer({ minimum: 0 }))
}, { additionalProperties: false }),
Type.Object({
kind: Type.Literal("cron"),
expr: NonEmptyString,
tz: Type.Optional(Type.String()),
staggerMs: Type.Optional(Type.Integer({ minimum: 0 }))
}, { additionalProperties: false })
]);
const CronPayloadSchema = Type.Union([Type.Object({
kind: Type.Literal("systemEvent"),
text: NonEmptyString
}, { additionalProperties: false }), cronAgentTurnPayloadSchema({ message: NonEmptyString })]);
const CronPayloadPatchSchema = Type.Union([Type.Object({
kind: Type.Literal("systemEvent"),
text: Type.Optional(NonEmptyString)
}, { additionalProperties: false }), cronAgentTurnPayloadSchema({ message: Type.Optional(NonEmptyString) })]);
const CronDeliverySharedProperties = {
channel: Type.Optional(Type.Union([Type.Literal("last"), NonEmptyString])),
bestEffort: Type.Optional(Type.Boolean())
};
const CronDeliveryNoopSchema = Type.Object({
mode: Type.Literal("none"),
...CronDeliverySharedProperties,
to: Type.Optional(Type.String())
}, { additionalProperties: false });
const CronDeliveryAnnounceSchema = Type.Object({
mode: Type.Literal("announce"),
...CronDeliverySharedProperties,
to: Type.Optional(Type.String())
}, { additionalProperties: false });
const CronDeliveryWebhookSchema = Type.Object({
mode: Type.Literal("webhook"),
...CronDeliverySharedProperties,
to: NonEmptyString
}, { additionalProperties: false });
const CronDeliverySchema = Type.Union([
CronDeliveryNoopSchema,
CronDeliveryAnnounceSchema,
CronDeliveryWebhookSchema
]);
const CronDeliveryPatchSchema = Type.Object({
mode: Type.Optional(Type.Union([
Type.Literal("none"),
Type.Literal("announce"),
Type.Literal("webhook")
])),
...CronDeliverySharedProperties,
to: Type.Optional(Type.String())
}, { additionalProperties: false });
const CronJobStateSchema = Type.Object({
nextRunAtMs: Type.Optional(Type.Integer({ minimum: 0 })),
runningAtMs: Type.Optional(Type.Integer({ minimum: 0 })),
lastRunAtMs: Type.Optional(Type.Integer({ minimum: 0 })),
lastStatus: Type.Optional(Type.Union([
Type.Literal("ok"),
Type.Literal("error"),
Type.Literal("skipped")
])),
lastError: Type.Optional(Type.String()),
lastDurationMs: Type.Optional(Type.Integer({ minimum: 0 })),
consecutiveErrors: Type.Optional(Type.Integer({ minimum: 0 }))
}, { additionalProperties: false });
const CronJobSchema = Type.Object({
id: NonEmptyString,
agentId: Type.Optional(NonEmptyString),
sessionKey: Type.Optional(NonEmptyString),
name: NonEmptyString,
description: Type.Optional(Type.String()),
enabled: Type.Boolean(),
deleteAfterRun: Type.Optional(Type.Boolean()),
createdAtMs: Type.Integer({ minimum: 0 }),
updatedAtMs: Type.Integer({ minimum: 0 }),
schedule: CronScheduleSchema,
sessionTarget: CronSessionTargetSchema,
wakeMode: CronWakeModeSchema,
payload: CronPayloadSchema,
delivery: Type.Optional(CronDeliverySchema),
state: CronJobStateSchema
}, { additionalProperties: false });
const CronListParamsSchema = Type.Object({ includeDisabled: Type.Optional(Type.Boolean()) }, { additionalProperties: false });
const CronStatusParamsSchema = Type.Object({}, { additionalProperties: false });
const CronAddParamsSchema = Type.Object({
name: NonEmptyString,
...CronCommonOptionalFields,
schedule: CronScheduleSchema,
sessionTarget: CronSessionTargetSchema,
wakeMode: CronWakeModeSchema,
payload: CronPayloadSchema,
delivery: Type.Optional(CronDeliverySchema)
}, { additionalProperties: false });
const CronJobPatchSchema = Type.Object({
name: Type.Optional(NonEmptyString),
...CronCommonOptionalFields,
schedule: Type.Optional(CronScheduleSchema),
sessionTarget: Type.Optional(CronSessionTargetSchema),
wakeMode: Type.Optional(CronWakeModeSchema),
payload: Type.Optional(CronPayloadPatchSchema),
delivery: Type.Optional(CronDeliveryPatchSchema),
state: Type.Optional(Type.Partial(CronJobStateSchema))
}, { additionalProperties: false });
const CronUpdateParamsSchema = cronIdOrJobIdParams({ patch: CronJobPatchSchema });
const CronRemoveParamsSchema = cronIdOrJobIdParams({});
const CronRunParamsSchema = cronIdOrJobIdParams({ mode: Type.Optional(Type.Union([Type.Literal("due"), Type.Literal("force")])) });
const CronRunsParamsSchema = cronIdOrJobIdParams({ limit: Type.Optional(Type.Integer({
minimum: 1,
maximum: 5e3
})) });
const CronRunLogEntrySchema = Type.Object({
ts: Type.Integer({ minimum: 0 }),
jobId: NonEmptyString,
action: Type.Literal("finished"),
status: Type.Optional(Type.Union([
Type.Literal("ok"),
Type.Literal("error"),
Type.Literal("skipped")
])),
error: Type.Optional(Type.String()),
summary: Type.Optional(Type.String()),
sessionId: Type.Optional(NonEmptyString),
sessionKey: Type.Optional(NonEmptyString),
runAtMs: Type.Optional(Type.Integer({ minimum: 0 })),
durationMs: Type.Optional(Type.Integer({ minimum: 0 })),
nextRunAtMs: Type.Optional(Type.Integer({ minimum: 0 }))
}, { additionalProperties: false });
//#endregion
//#region src/gateway/protocol/schema/error-codes.ts
const ErrorCodes = {
NOT_LINKED: "NOT_LINKED",
NOT_PAIRED: "NOT_PAIRED",
AGENT_TIMEOUT: "AGENT_TIMEOUT",
INVALID_REQUEST: "INVALID_REQUEST",
UNAVAILABLE: "UNAVAILABLE"
};
function errorShape(code, message, opts) {
return {
code,
message,
...opts
};
}
//#endregion
//#region src/gateway/protocol/schema/exec-approvals.ts
const ExecApprovalsAllowlistEntrySchema = Type.Object({
id: Type.Optional(NonEmptyString),
pattern: Type.String(),
lastUsedAt: Type.Optional(Type.Integer({ minimum: 0 })),
lastUsedCommand: Type.Optional(Type.String()),
lastResolvedPath: Type.Optional(Type.String())
}, { additionalProperties: false });
const ExecApprovalsDefaultsSchema = Type.Object({
security: Type.Optional(Type.String()),
ask: Type.Optional(Type.String()),
askFallback: Type.Optional(Type.String()),
autoAllowSkills: Type.Optional(Type.Boolean())
}, { additionalProperties: false });
const ExecApprovalsAgentSchema = Type.Object({
security: Type.Optional(Type.String()),
ask: Type.Optional(Type.String()),
askFallback: Type.Optional(Type.String()),
autoAllowSkills: Type.Optional(Type.Boolean()),
allowlist: Type.Optional(Type.Array(ExecApprovalsAllowlistEntrySchema))
}, { additionalProperties: false });
const ExecApprovalsFileSchema = Type.Object({
version: Type.Literal(1),
socket: Type.Optional(Type.Object({
path: Type.Optional(Type.String()),
token: Type.Optional(Type.String())
}, { additionalProperties: false })),
defaults: Type.Optional(ExecApprovalsDefaultsSchema),
agents: Type.Optional(Type.Record(Type.String(), ExecApprovalsAgentSchema))
}, { additionalProperties: false });
const ExecApprovalsSnapshotSchema = Type.Object({
path: NonEmptyString,
exists: Type.Boolean(),
hash: NonEmptyString,
file: ExecApprovalsFileSchema
}, { additionalProperties: false });
const ExecApprovalsGetParamsSchema = Type.Object({}, { additionalProperties: false });
const ExecApprovalsSetParamsSchema = Type.Object({
file: ExecApprovalsFileSchema,
baseHash: Type.Optional(NonEmptyString)
}, { additionalProperties: false });
const ExecApprovalsNodeGetParamsSchema = Type.Object({ nodeId: NonEmptyString }, { additionalProperties: false });
const ExecApprovalsNodeSetParamsSchema = Type.Object({
nodeId: NonEmptyString,
file: ExecApprovalsFileSchema,
baseHash: Type.Optional(NonEmptyString)
}, { additionalProperties: false });
const ExecApprovalRequestParamsSchema = Type.Object({
id: Type.Optional(NonEmptyString),
command: NonEmptyString,
cwd: Type.Optional(Type.Union([Type.String(), Type.Null()])),
host: Type.Optional(Type.Union([Type.String(), Type.Null()])),
security: Type.Optional(Type.Union([Type.String(), Type.Null()])),
ask: Type.Optional(Type.Union([Type.String(), Type.Null()])),
agentId: Type.Optional(Type.Union([Type.String(), Type.Null()])),
resolvedPath: Type.Optional(Type.Union([Type.String(), Type.Null()])),
sessionKey: Type.Optional(Type.Union([Type.String(), Type.Null()])),
timeoutMs: Type.Optional(Type.Integer({ minimum: 1 })),
twoPhase: Type.Optional(Type.Boolean())
}, { additionalProperties: false });
const ExecApprovalResolveParamsSchema = Type.Object({
id: NonEmptyString,
decision: NonEmptyString
}, { additionalProperties: false });
//#endregion
//#region src/gateway/protocol/schema/devices.ts
const DevicePairListParamsSchema = Type.Object({}, { additionalProperties: false });
const DevicePairApproveParamsSchema = Type.Object({ requestId: NonEmptyString }, { additionalProperties: false });
const DevicePairRejectParamsSchema = Type.Object({ requestId: NonEmptyString }, { additionalProperties: false });
const DevicePairRemoveParamsSchema = Type.Object({ deviceId: NonEmptyString }, { additionalProperties: false });
const DeviceTokenRotateParamsSchema = Type.Object({
deviceId: NonEmptyString,
role: NonEmptyString,
scopes: Type.Optional(Type.Array(NonEmptyString))
}, { additionalProperties: false });
const DeviceTokenRevokeParamsSchema = Type.Object({
deviceId: NonEmptyString,
role: NonEmptyString
}, { additionalProperties: false });
const DevicePairRequestedEventSchema = Type.Object({
requestId: NonEmptyString,
deviceId: NonEmptyString,
publicKey: NonEmptyString,
displayName: Type.Optional(NonEmptyString),
platform: Type.Optional(NonEmptyString),
clientId: Type.Optional(NonEmptyString),
clientMode: Type.Optional(NonEmptyString),
role: Type.Optional(NonEmptyString),
roles: Type.Optional(Type.Array(NonEmptyString)),
scopes: Type.Optional(Type.Array(NonEmptyString)),
remoteIp: Type.Optional(NonEmptyString),
silent: Type.Optional(Type.Boolean()),
isRepair: Type.Optional(Type.Boolean()),
ts: Type.Integer({ minimum: 0 })
}, { additionalProperties: false });
const DevicePairResolvedEventSchema = Type.Object({
requestId: NonEmptyString,
deviceId: NonEmptyString,
decision: NonEmptyString,
ts: Type.Integer({ minimum: 0 })
}, { additionalProperties: false });
//#endregion
//#region src/gateway/protocol/schema/snapshot.ts
const PresenceEntrySchema = Type.Object({
host: Type.Optional(NonEmptyString),
ip: Type.Optional(NonEmptyString),
version: Type.Optional(NonEmptyString),
platform: Type.Optional(NonEmptyString),
deviceFamily: Type.Optional(NonEmptyString),
modelIdentifier: Type.Optional(NonEmptyString),
mode: Type.Optional(NonEmptyString),
lastInputSeconds: Type.Optional(Type.Integer({ minimum: 0 })),
reason: Type.Optional(NonEmptyString),
tags: Type.Optional(Type.Array(NonEmptyString)),
text: Type.Optional(Type.String()),
ts: Type.Integer({ minimum: 0 }),
deviceId: Type.Optional(NonEmptyString),
roles: Type.Optional(Type.Array(NonEmptyString)),
scopes: Type.Optional(Type.Array(NonEmptyString)),
instanceId: Type.Optional(NonEmptyString)
}, { additionalProperties: false });
const HealthSnapshotSchema = Type.Any();
const SessionDefaultsSchema = Type.Object({
defaultAgentId: NonEmptyString,
mainKey: NonEmptyString,
mainSessi