export function isJsonRecord(value) {
    return typeof value === 'object' && value !== null && !Array.isArray(value);
}
export function toSerializableJson(value, stack = new Map(), path = '$') {
    if (!value || typeof value !== 'object')
        return value;
    const prior = stack.get(value);
    if (prior) {
        return { $ref: prior };
    }
    const next = new Map(stack);
    next.set(value, path);
    if (Array.isArray(value)) {
        return value.map((entry, index) => toSerializableJson(entry, next, `${path}[${index}]`));
    }
    return Object.fromEntries(Object.entries(value).map(([key, entry]) => [
        key,
        toSerializableJson(entry, next, `${path}.${key}`),
    ]));
}
export function serializableJsonResponse(body, init) {
    return Response.json(toSerializableJson(body), init);
}
export function scopeMatches(granted, required) {
    if (granted === '*' || granted === required)
        return true;
    if (granted.endsWith(':*')) {
        return required.startsWith(granted.slice(0, -1));
    }
    return false;
}
export function missingScopes(grantedScopes, requiredScopes) {
    const granted = grantedScopes ?? [];
    return requiredScopes.filter((required) => !granted.some((entry) => scopeMatches(entry, required)));
}
export function readChannelLifecycleAction(value) {
    return value === 'inspect'
        || value === 'setup'
        || value === 'retest'
        || value === 'connect'
        || value === 'disconnect'
        || value === 'start'
        || value === 'stop'
        || value === 'login'
        || value === 'logout'
        || value === 'wait_login'
        ? value
        : null;
}
export function readChannelConversationKind(value) {
    return value === 'direct' || value === 'group' || value === 'channel' || value === 'thread' || value === 'service'
        ? value
        : null;
}
