var __awaiter = (this && this.__awaiter) || function (thisArg, _arguments, P, generator) {
    function adopt(value) { return value instanceof P ? value : new P(function (resolve) { resolve(value); }); }
    return new (P || (P = Promise))(function (resolve, reject) {
        function fulfilled(value) { try { step(generator.next(value)); } catch (e) { reject(e); } }
        function rejected(value) { try { step(generator["throw"](value)); } catch (e) { reject(e); } }
        function step(result) { result.done ? resolve(result.value) : adopt(result.value).then(fulfilled, rejected); }
        step((generator = generator.apply(thisArg, _arguments || [])).next());
    });
};
/** Deterministic bytewise string comparator for hash inputs and canonical IDs. */
export function lexicographicalCompare(a, b) {
    if (a > b) {
        return 1;
    }
    if (a < b) {
        return -1;
    }
    return 0;
}
// ---------------------------------------------------------------------------
// Sync scope and scope identity
// ---------------------------------------------------------------------------
/**
 * Root algorithm used by durable message-feed full/protocol sync scopes.
 */
export const SYNC_PROJECTION_ROOT_VERSION = 'replication-log-feed-v1';
/**
 * Authorization-epoch algorithm used by delegated Messages.Read sync links.
 *
 * The authorization epoch is separate from the projection ID: re-granting the
 * same scope or changing delegate grants must invalidate in-flight work without
 * changing the primary CID set being compared.
 */
export const SYNC_AUTHORIZATION_EPOCH_VERSION = 'messages-read-grants-v1';
/**
 * Normalizes a protocol list into canonical scope-union order.
 */
export function normalizeSyncProtocols(protocols) {
    const unique = [...new Set(protocols)].sort(lexicographicalCompare);
    if (unique.length === 0) {
        throw new Error('SyncScope: protocol-set scope requires at least one protocol URI.');
    }
    return unique;
}
/** Converts persisted identity options into the canonical sync scope. */
export function syncScopeFromProtocols(protocols) {
    return protocols === 'all'
        ? { kind: 'full' }
        : { kind: 'protocolSet', protocols: normalizeSyncProtocols(protocols) };
}
/** Returns the protocol list covered by a scope, or `undefined` for full scope. */
export function protocolsForSyncScope(scope) {
    if (scope.kind === 'full') {
        return undefined;
    }
    return scope.protocols;
}
/** Returns the single protocol root covered by a protocol-set scope, if any. */
export function singleProtocolForSyncScope(scope) {
    return scope.kind === 'protocolSet' && scope.protocols.length === 1 ? scope.protocols[0] : undefined;
}
/** Stable base64url SHA-256 hash for canonical JSON objects. */
function hashCanonicalObject(value) {
    return __awaiter(this, void 0, void 0, function* () {
        const json = JSON.stringify(value);
        const bytes = new TextEncoder().encode(json);
        const hashBuffer = yield crypto.subtle.digest('SHA-256', bytes);
        const hashArray = new Uint8Array(hashBuffer);
        let base64 = '';
        for (const b of hashArray) {
            base64 += String.fromCharCode(b);
        }
        const result = btoa(base64).replaceAll('+', '-').replaceAll('/', '_');
        let end = result.length;
        while (end > 0 && result.codePointAt(end - 1) === 61) {
            end--;
        }
        return end === result.length ? result : result.slice(0, end);
    });
}
/** Returns a canonical JSON-ready representation of a sync scope. */
export function canonicalizeSyncScope(scope) {
    if (scope.kind === 'full') {
        return { kind: 'full' };
    }
    return { kind: 'protocolSet', protocols: normalizeSyncProtocols(scope.protocols) };
}
/**
 * Computes a deterministic, collision-resistant projection ID.
 *
 * The projection ID is derived from tenant DID, normalized scope, and the
 * projection-root algorithm version. It intentionally excludes endpoint,
 * grant IDs, authorization epoch, and remote diff contents.
 */
export function computeProjectionId(tenantDid, scope) {
    return __awaiter(this, void 0, void 0, function* () {
        const canonicalScope = canonicalizeSyncScope(scope);
        return hashCanonicalObject({
            scope: canonicalScope,
            tenantDid,
            version: SYNC_PROJECTION_ROOT_VERSION,
        });
    });
}
/**
 * Computes the authorization epoch for a link.
 *
 * Owner epochs are stable for owner sync. Delegate epochs are derived
 * from the delegate DID plus the active grant IDs and expiry metadata. A changed
 * grant set creates a new link key even when the projection ID is unchanged.
 */
export function computeAuthorizationEpoch(input) {
    return __awaiter(this, void 0, void 0, function* () {
        if (input.kind === 'owner') {
            return hashCanonicalObject({
                kind: 'owner',
                version: SYNC_AUTHORIZATION_EPOCH_VERSION,
            });
        }
        const grants = [...input.grants]
            .sort((a, b) => lexicographicalCompare(a.id, b.id))
            .map(grant => ({
            dateExpires: grant.dateExpires,
            dateGranted: grant.dateGranted,
            id: grant.id,
        }));
        return hashCanonicalObject({
            delegateDid: input.delegateDid,
            grants,
            kind: 'delegate',
            version: SYNC_AUTHORIZATION_EPOCH_VERSION,
        });
    });
}
export function isTerminalPushFailure(failure) {
    return failure.terminal === true;
}
export function isTenantInactivePushFailure(failure) {
    return failure.tenantInactive === true;
}
//# sourceMappingURL=sync.js.map