/**
 * BPMN sidecar transport for `layout pull/apply --with-workflows`.
 *
 * A workflow's BPMN is not part of the patchable document — it lives in S3 and
 * `bpmnAwsS3Identifier` is a per-environment pointer, not portable across envs.
 * So the round-trip stores the bytes in `workflows/<id>.bpmn` files next to the
 * layout: `pull` downloads them, `apply` re-uploads them to the target and links
 * the fresh version. All the pure decision logic lives here (the commands only
 * do I/O) so it can be unit-tested.
 */
import type LayoutManager from './layout-manager';
import type { LayoutScope } from './types';
/**
 * A workflow id becomes a sidecar filename (`workflows/<id>.bpmn`). Because that
 * id comes from a layout file, a crafted file could set it to `../../.ssh/id_rsa`
 * and make `apply --with-workflows` read an arbitrary file (or `pull` write
 * outside the workflows dir). Only accept ids that are a single, traversal-free
 * path segment — Forest ids are UUIDs, so this is deliberately strict.
 */
export declare function isSafeWorkflowId(id: unknown): id is string;
/** The sidecar path for a workflow id, or null when the id is unsafe. */
export declare function sidecarPath(dir: string, id: unknown): string | null;
/**
 * Resolve a file workflow to its target-env counterpart by DELEGATING to the
 * diff engine's own resolver (`remoteResolver` in diff.ts), so the sidecar
 * upload targets the very workflow the domain patch addressed — including on
 * duplicate names, where the resolver's Map makes the LAST remote win. A
 * dev→prod promote typically matches by NAME (each env mints its own ids).
 */
export declare function resolveRemoteWorkflow(remoteWorkflows: Array<Record<string, unknown>>, workflow: {
    id: string;
    name?: string;
}): Record<string, unknown> | undefined;
/** A file workflow that declares BPMN in the layout but has no sidecar on disk. */
export type MissingSidecar = {
    id: string;
    name: string;
};
/**
 * Split the missing-sidecar workflows by what actually happens to their BPMN:
 * - `targetKeepsOwn`: the workflow exists in the target env (id-then-name), so
 *   the strip of `bpmnAwsS3Identifier` leaves the target's own BPMN untouched;
 * - `createdWithoutBpmn`: the workflow matches nothing in the target — this
 *   apply `add`s it, and with its declared pointer stripped and no sidecar to
 *   upload, it is created with NO BPMN at all. The caller must warn explicitly:
 *   "keeps its own" would be a lie here.
 */
export declare function partitionMissingSidecars(missing: MissingSidecar[], remoteWorkflows: Array<Record<string, unknown>>): {
    createdWithoutBpmn: MissingSidecar[];
    targetKeepsOwn: MissingSidecar[];
};
/**
 * When `--with-workflows`, BPMN transport is owned by the sidecar upload, not by
 * the JSON patch: `bpmnAwsS3Identifier` is a per-environment S3 pointer and is not
 * portable. Drop it from the diff so a pulled file never patches a target workflow
 * to the source env's (nonexistent) version — for workflows with a sidecar the
 * upload links the fresh id; for those without, the target keeps its own BPMN.
 */
export declare function stripWorkflowBpmnOps<T extends {
    op: string;
    path: string;
    value?: unknown;
}>(ops: T[]): T[];
/**
 * True when the plan would write a `bpmnAwsS3Identifier` into the target — either
 * as a replace of the pointer itself or inside an added workflow. Used by `apply`
 * WITHOUT `--with-workflows` to warn on cross-environment applies: the pointer is
 * env-local, so patching it into another env plants a dead S3 reference.
 */
export declare function hasWorkflowBpmnOps(ops: Array<{
    op: string;
    path: string;
    value?: unknown;
}>): boolean;
/** A sidecar file read from disk, keyed by the SOURCE (layout-file) workflow. */
export type SidecarFile = {
    bpmn: string;
    workflow: {
        collectionId: string;
        id: string;
        name: string;
    };
};
/** A sidecar that must be uploaded, with the TARGET-env workflow it links to. */
export type SidecarUpload = SidecarFile & {
    /**
     * The workflow to upload to in the target env (resolved id-then-name), or
     * null when the workflow does not exist there yet — it is being added by this
     * very apply, so the target must be re-resolved after the domain patch.
     */
    target: {
        collectionId: string;
        id: string;
    } | null;
};
/**
 * Decide which sidecars need uploading, resolving each to its TARGET-env
 * workflow first (id-then-name, like the diff) so that:
 * - a same-name workflow with a different id (dev→prod promote) is uploaded
 *   under the TARGET id, never the source one;
 * - byte-identical BPMN is skipped (idempotent re-apply), including in that
 *   name-matched case.
 */
export declare function planSidecarUploads(manager: LayoutManager, scope: LayoutScope, sidecars: SidecarFile[], remoteWorkflows: Array<Record<string, unknown>>, renderingId: number): Promise<SidecarUpload[]>;
/**
 * The sidecar filenames a pull should prune: files named after a server
 * workflow id (`<num-or-uuid>.bpmn`) that matches no workflow left in the
 * environment. Everything else is preserved:
 * - files whose basename is not a server-shaped id (a user's own BPMN files,
 *   e.g. `review.bpmn` — pull never wrote them, so pull never deletes them);
 * - sidecars of workflows still present in the env, even when their download
 *   was skipped (dead S3 ref) — that sidecar may be the last copy of the BPMN,
 *   and a backup tool must never destroy the backup.
 */
export declare function selectStaleSidecars(entries: string[], keepIds: ReadonlySet<string>): string[];
//# sourceMappingURL=workflow-sidecar.d.ts.map