/** * Is this error the S3/STS "access denied" class? Expected when a scoped * member/guest credential touches a key outside its granted ACL prefixes * (the server's `SCOPE_EXCEEDS_PARENT` surfaces as a 403 AccessDenied / * Forbidden). */ export declare function isAccessDenied(err: unknown): boolean; /** Host resource snapshot used to decide the default transfer fan-out. */ export interface HostLoadProbe { /** Logical CPU count (0 when unknown). */ cores: number; /** 1-minute load average (0 on platforms without it, e.g. Windows). */ load1: number; /** * Memory *available to applications* as a fraction of total (0..1). This is * NOT `os.freemem() / os.totalmem()`: on macOS and Linux the OS keeps most * "free" RAM as reclaimable file cache, so raw free-page counts report a * near-full machine as memory-starved. `readAvailableMemoryFraction` * measures available memory per-platform instead. */ availableMemFraction: number; } /** * Measure memory *available to applications* as a fraction of total RAM. * * `os.freemem()` counts only unused pages; both macOS and Linux hold most idle * RAM as reclaimable cache, so it drastically understates what an app can get * (an idle 16 GB Mac reports ~8% "free" while ~75% is actually available). * Reading it as pressure would pin every pass to the busy tier. We instead read * the platform's available figure; any failure falls back optimistically (1.0) * so a bad probe never throttles — the upload byte budget is the real * memory-safety net. */ export declare function readAvailableMemoryFraction(): number; /** Read the current host load. Pure I/O; callers inject a probe in tests. */ export declare function readHostLoad(): HostLoadProbe; /** * True when the host is already under meaningful CPU or memory load from other * processes. `cores === 0` (unknown) disables the CPU signal rather than * dividing by zero; `load1 === 0` (Windows has no load average) likewise leaves * the CPU signal inert, so those hosts fall back to the memory signal only. */ export declare function machineAlreadyBusy(probe: HostLoadProbe): boolean; /** * Concurrency for the per-file transfer pool (uploads + downloads). * * An explicit, valid `HQ_SYNC_TRANSFER_CONCURRENCY` always wins. Otherwise the * default adapts to the host: 64-way normally, 32-way when the machine is * already busy (see `machineAlreadyBusy`). Callers capture the probe at pass * entry — BEFORE the walk/hash pass — and inject it, so the reading reflects * other processes rather than sync's own load; tests inject a synthetic probe. */ export declare function resolveTransferConcurrency(probe?: HostLoadProbe): number; /** * A run-scoped permit pool for payload transfers. * * Most syncs have one engine, whose local executor uses * {@link resolveTransferConcurrency}. Company fanout intentionally starts * several independent engines at once, though, so the runner gives each one * the same semaphore when `HQ_SYNC_MAX_CONCURRENCY` is configured. That makes * the documented bandwidth-governor ceiling apply to the whole run rather * than once per company. */ export declare class TransferSemaphore { private available; private readonly waiters; constructor(capacity: number); withPermit(fn: () => Promise): Promise; } /** * Total in-flight upload-body bytes the upload pool may hold at once. Because * `uploadFile` buffers whole files, this — not the worker count — is what * bounds sync's peak memory. Sized from AVAILABLE memory (the pass-entry * probe's `availableMemFraction`), so a memory-tight host gets a small budget * that cannot exhaust what is left while an idle host is capped at 1 GiB. No * hard floor: a tiny budget is safe because the pool always admits one item * when nothing is in flight, so a single oversized file still uploads. Override * for tuning/tests with `HQ_SYNC_UPLOAD_BYTE_BUDGET_MB` (absolute, fractional * MB accepted). */ export declare function resolveUploadByteBudget(availableMemFraction?: number, totalMemBytes?: number): number; /** * Resolve active company from .hq/config.json. */ export declare function resolveActiveCompany(hqRoot: string): string | undefined; /** * Returns true when the remote object appears to have moved since the * journal entry's last-recorded sync. When both sides expose content lineage, * compare the remote published SHA-256 to the journal's local baseline before * considering the ETag. ETags remain version/concurrency tokens and are the * back-compat fallback for legacy objects and list-only results. */ export declare function hasRemoteChanged(remote: { lastModified: Date; etag: string; contentHash?: string; }, entry: { syncedAt: string; remoteEtag?: string; hash?: string; }): boolean; //# sourceMappingURL=sync-core.d.ts.map