import type { Tracer } from "@opentelemetry/api";
import { SyncronizationStatus } from "@superblocksteam/library-shared/types";
import { type DegradedMode, type ApplicationHashChangeSource, TracedEventEmitter } from "@superblocksteam/shared";
import type { DraftEventMap, DraftInterface } from "../draft-interface.js";
import { type ErrorEventMap } from "../errors/error-handler.js";
import type { LockService } from "../lock-service/index.js";
import type { AutoConnectingRpcClient } from "../server-rpc/index.js";
import type { GenerationNumberSequence } from "../util/generation-number-sequence.js";
import type { Logger } from "../util/logger.js";
import { OperationQueue } from "../util/operation-queue.js";
export declare enum SyncServiceStatus {
    /** The sync service is not currently syncing or scheduled to sync */
    IDLE = "IDLE",
    /** The sync service is scheduled to sync */
    SCHEDULED = "SCHEDULED",
    /** The sync service is currently syncing server -> local */
    DOWNLOADING = "DOWNLOADING",
    /** The sync service is currently syncing local -> server */
    UPLOADING = "UPLOADING",
    /** The sync service is currently paused */
    PAUSED = "PAUSED"
}
/** Configuration for the SyncService passed to the constructor */
export interface SyncServiceConfig {
    superblocksBaseUrl: string;
    fsOperationQueue: OperationQueue;
    appRootDirPath: string;
    applicationId: string;
    branchName: string;
    lockService: LockService;
    tracer: Tracer;
    rpcClient: AutoConnectingRpcClient;
    logger: Logger;
}
interface EventMap extends ErrorEventMap, DraftEventMap {
    /** Emitted when the sync service status changes, which indicates what the service is currently doing */
    statusChange: [
        status: SyncServiceStatus,
        /** The time when the next sync is scheduled to be performed, in milliseconds in the monotonic clock (`performance.now()`) */
        scheduledSyncTime: number | undefined
    ];
    /** Emitted when the synchronization status changes, which indicates whether the server and local directories are in sync */
    synchronizationStatusChange: [
        status: SyncronizationStatus,
        generationNumber: number | undefined
    ];
    /** Emitted when the degraded mode changes */
    degradedModeChange: [degradedMode: DegradedMode | undefined];
    /** Emitted when the last commit ID changes after a successful commit */
    commitIdChanged: [commitId: string];
}
export declare class SyncService extends TracedEventEmitter<EventMap> implements DraftInterface {
    private readonly appRootDirPath;
    readonly applicationId: string;
    private _branchName;
    generationNumberSequence: GenerationNumberSequence | undefined;
    private lastSyncedGenerationNumber;
    private hashCache;
    lastSyncedDirectoryHash: string | undefined;
    /** The most recent commit ID returned by the server after a successful commit */
    lastCommitId: string | undefined;
    private readonly fsOperationQueue;
    private readonly syncOperationQueue;
    /** This will be defined if (and only if) a sync is currently pending */
    private pendingSyncUp;
    /** When true, `uploadDirectory()` short-circuits so the migration can
     *  run `flipTemplate()` without waiting behind autosave queue entries. */
    private _autoSyncPaused;
    private lockService;
    private _status;
    private _synchronizationStatus;
    private _tracer;
    private _rpcClient;
    private _logger;
    private _moduleInvalidationCallback?;
    constructor(config: SyncServiceConfig);
    private getLogger;
    get branchName(): string;
    get currentBranchName(): string;
    setBranchName(nextBranchName: string): void;
    /** The current status of the sync service, which indicates what the service is currently doing */
    get status(): SyncServiceStatus;
    private set status(value);
    /** The current synchronization status, which indicates whether the server and local directories are in sync */
    get synchronizationStatus(): SyncronizationStatus;
    private set synchronizationStatus(value);
    /**
     * Enqueues a filesystem operation to be executed one at a time and avoiding conflicts with sync operations.
     */
    private fsOperation;
    /**
     * Sets a callback to invalidate Vite's module graph when files are created/modified.
     * This ensures that TypeScript checks and builds get fresh data after file writes.
     *
     * @param callback - Function that takes a file path (relative to app root) and invalidates the module
     */
    setModuleInvalidationCallback(callback: (filePath: string) => void): void;
    /**
     * Pulls the application down from the server.
     */
    downloadDirectory(): Promise<void>;
    /**
     * Checks whether the local directory is behind the server and, if so,
     * pulls the latest version.  Skips the refresh when:
     *  - a local upload is already pending (`pendingSyncUp` set)
     *  - the server hash matches `lastSyncedDirectoryHash`
     *  - there are unsynced local draft changes
     *
     * Intended to be called on editor (re-)connect so a warm-pool pod that
     * was assigned after Clark pushed new content will converge to the
     * latest DBFS state before the user sees the app.
     *
     * @returns `true` if a download was performed, `false` if skipped.
     */
    refreshIfStale(): Promise<boolean>;
    /**
     * Request a sync of the local application directory to the server.
     *
     * This method is asynchronous, in the sense that it does not wait for the sync to complete. It simply schedules
     * a sync to happen in the future. The returned promise resolves as soon as the method has collected enough information
     * to schedule the sync. So the caller must wait for the returned promise to resolve before performing any filesystem
     * operations.
     * This method is also idempotent.
     */
    uploadDirectory(source: ApplicationHashChangeSource): Promise<void>;
    /**
     * Requests an immediate sync of the local application directory to the server, if there are any pending changes.
     * If there are no pending changes, the method returns immediately.
     *
     * @returns the dbfs hash of the most recent sync
     */
    uploadDirectoryNowIfNeeded(source: ApplicationHashChangeSource): Promise<{
        directoryHash: string;
        commitId?: string;
    }>;
    private scheduleUploadDirectory;
    cancelPendingSync(): void;
    /**
     * Prevents future `uploadDirectory()` calls from enqueuing work into
     * `fsOperationQueue` / `syncOperationQueue`.  Also cancels any pending
     * timeout-based sync that hasn't fired yet.
     *
     * This is used by the v2→v3 migration: the restructure step writes many
     * files, and the Vite file-watcher would normally funnel each change into
     * `uploadDirectory()`.  By pausing first we keep the queues empty so that
     * `flipTemplate()` can enqueue immediately.
     *
     * Call `resumeAutoSync()` in failure paths so the user can continue
     * editing normally.  On success the SABS pod restarts with a fresh
     * SyncService instance, so resume is unnecessary.
     */
    pauseAutoSync(): void;
    /**
     * Re-enables the normal `uploadDirectory()` auto-sync path after a
     * failed migration so edits are no longer silently dropped.
     */
    resumeAutoSync(): void;
    /**
     * Takes a snapshot of an arbitrary local directory and uploads it to DBFS.
     * Used by the git deploy flow to upload a worktree snapshot for a main branch commit.
     * Does NOT create any internal commits — the caller is responsible for that.
     */
    uploadSnapshotToDbfs(localDirectoryPath: string): Promise<{
        directoryHash: string;
    }>;
    /**
     * Uploads the local application directory to the server, retrying if the server returns a BadRequestError.
     */
    private uploadDirectoryWithRetry;
    /**
     * Performs the actual upload of the local application directory to the server.
     *
     * `targetTemplateName` is only meaningful when `source === 'migrate:templateFlip'`.
     * It is threaded into the RPC payload so the server can atomically update
     * `application_v2.template_name` in the same transaction that creates the
     * first post-migration commit.
     */
    private performUploadDirectory;
    /**
     * Atomically flip the application's template to `targetTemplateName` and
     * upload the current local directory (which the caller must have already
     * restructured to match the new template) as the first commit on that
     * template. This is the V2 -> V3 migration entry point invoked by the
     * dev server after it finishes the deterministic folder restructure.
     *
     * The server performs three things in a single database transaction:
     *   1. update application_v2.template_name = targetTemplateName
     *   2. advance the live-edit directory hash to the uploaded snapshot
     *   3. create a new application_commit that inherits the new template_name
     * After the transaction commits, the server terminates the SABS live-edit
     * pod so the next pod starts with the new TEMPLATE_NAME env var. Older
     * deployed/preview commits retain their original template_name and keep
     * rendering on the legacy runtime.
     */
    flipTemplate({ targetTemplateName, }: {
        targetTemplateName: string;
    }): Promise<{
        directoryHash: string;
        commitId?: string;
    }>;
    /**
     * Snapshot the current local directory and push it to the server as a
     * named pre-migration checkpoint, regardless of whether anything changed
     * vs the last sync.
     *
     * `uploadDirectoryNowIfNeeded` is not a fit here: it short-circuits when
     * there is no pending snapshot, and on the server side a plain `edit`
     * source also short-circuits when the hash matches the last checkpoint.
     * Both are correct for normal autosave behavior -- but the whole point of
     * the pre-migration backup is to produce a restore target precisely when
     * nothing has changed (i.e. "checkpoint what is on disk right now, before
     * I move it to scratch/v2-backup").
     *
     * The server recognizes `source: 'migrate:backup'` and unconditionally
     * writes a SAVEPOINT_MANUAL commit whose `template_name` is inherited
     * from the still-unflipped `application_v2.template_name`, i.e. the
     * legacy template. That makes the backup commit a valid rollback target
     * for the v2 runtime.
     */
    backupCurrentDirectory(): Promise<{
        directoryHash: string;
        commitId?: string;
    }>;
    /**
     * Resolve datasource integration IDs (UUIDs) to plugin IDs.
     * Used by migration preflight to classify whether UUID-backed steps map to
     * supported SDK integration types.
     */
    getIntegrationPluginIds(integrationIds: string[]): Promise<Map<string, string>>;
    /**
     * Checks if there are any local draft changes (.sbswap.edit and .sbswap.add files).
     *
     * @returns A promise that resolves to true if any draft files are found, false otherwise.
     */
    hasLocalDraftChanges(): Promise<boolean>;
    /**
     * Gets information about current draft changes.
     *
     * @returns A promise that resolves to information about draft edits, additions, and deletions.
     */
    getDraftChanges(): Promise<{
        edits: string[];
        additions: string[];
        deletions: string[];
    }>;
    /**
     * Gets a git-like diff representation of all draft changes.
     *
     * @returns A promise that resolves to a git-like diff string.
     */
    getDraftDiff(specificPaths: string[]): Promise<string>;
    /**
     * Creates a draft edit or addition for a file.
     *
     * @param filePath - The path to the file to edit or add (relative to app root).
     * @param draftContent - The content of the draft edit or addition.
     * @returns A promise that resolves when the draft edit or addition is created.
     */
    createDraftFile(filePath: string, draftContent: string | Buffer): Promise<void>;
    /**
     * Creates the marker file only for a draft edit or addition.
     * Compare to `createDraftFile`. This method does not actually write content to target file.
     *
     * @param filePath - The path to the file for which to create the respective marker (relative to app root).
     * @returns A promise that resolves when the draft edit or addition marker is created.
     */
    createDraftMarkerOnly(filePath: string): Promise<void>;
    /**
     * Creates a draft deletion by backing up the file and removing it from the workspace.
     *
     * @param filePath - The path to the file to delete (relative to app root).
     * @returns A promise that resolves when the draft deletion is created.
     */
    createDraftDelete(filePath: string): Promise<void>;
    /**
     * Discards all local draft changes by restoring original files and removing draft additions.
     *
     * @returns A promise that resolves when all draft changes have been discarded.
     */
    discardLocalDraftChanges(source: ApplicationHashChangeSource): Promise<void>;
    /**
     * Commits all draft changes by removing .sbswap.edit and .sbswap.add markers.
     * This makes the current filesystem state the committed state.
     *
     * @returns A promise that resolves when all drafts have been committed.
     */
    commitLocalDraftChanges(source: ApplicationHashChangeSource): Promise<{
        commitId: string;
    } | undefined>;
    /**
     * Reports draft state to the server
     */
    reportDraftStateToServer(hasDraft: boolean): Promise<void>;
    /**
     * Clears the drafts directory without restoring or uploading.
     * Used when restoring from a checkpoint where the database provides the correct state.
     */
    clearDraftsDirectory(): Promise<void>;
}
export {};
//# sourceMappingURL=index.d.ts.map