UNPKG

forest-cli

Version:

The Lumberjacks' toolbelt is the Forest CLI which makes easy to manage your back office application directly from the terminal.

116 lines 5.71 kB
/** * 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