Skip to content
getnextpdf.com

Pro edition

Output Pipeline — Deep Reference

This page is the deep reference for the public surface of NextPDF\Pro\OutputPipeline. It covers manifest construction and validation, topological execution order, retry and timeout semantics, resume behavior, and the fail-closed pack-capability gate. It states parameters, defaults, and failure modes for every public symbol. Read the Output Pipeline capability page first for workflow guidance.

This capability ships in NextPDF Pro (nextpdf/pro) and activates with a Pro-tier license envelope. A deployment without that entitlement does not load the capability’s classes. Compare editions and get a license.

The executor and seven of the ten step types carry no per-feature flag. Three step types additionally require a Pack capability:

Step typeManifest valueRequired capabilityPack
Redactredactpack.privacy.redactPrivacy Pack
Extractextractpack.intelligence.extractIntelligence Pack
OCR overlayocr_overlaypack.intelligence.searchable_pdfIntelligence Pack

The gate is enforced at execution time, fail-closed, before the step reaches its resolver. An unlicensed gated step yields a Failed step result carrying the SPEC-LIC-001 code and the required capability; the resolver is never invoked. A pipeline with no injected capability resolver rejects every gated step.

Terminal window
composer require nextpdf/pro:^3

The nextpdf/premium metapackage installs the nextpdf/pro code; this module lives under the NextPDF\Pro\OutputPipeline namespace.

SymbolParametersDefault behaviorReturnsThrows or fails withNotes
PipelineExecutor::__constructStepResolverRegistry $registry, ?CapabilityResolverInterface $capabilityResolver = nullBinds the built-in resolver registry and the optional entitlement sourcePipelineExecutorNothing declaredA null capability resolver rejects every pack-gated step
PipelineExecutor::executePipelineManifest $manifest, array $variables = []Runs steps in topological order and aggregates resultsPipelineResultNothing declared; resolver failures are captured as Failed step resultsDesigned to run inside an asynchronous job worker
PipelineManifest::__constructstring $id, array $steps, PipelineOptions $options = new PipelineOptions(), ?string $resumeFromStepId = nullValidates the step graph at constructionPipelineManifestInvalidArgumentException on an empty step list, duplicate step IDs, unknown dependencies, cycles, output-type mismatch, or a missing resume step; OverflowException above 10 000 stepsAll validation completes before any execution
PipelineManifest::topologicalOrdernoneOrders steps with dependencies before dependentslist<PipelineStep>Nothing declaredDeterministic for a given manifest
PipelineManifest::getStepstring $stepIdLinear lookup by step ID?PipelineStepNothing declarednull for an unknown ID
PipelineManifest::rootStepsnoneReturns the steps with no dependencieslist<PipelineStep>Nothing declaredRoot steps run first
PipelineManifestBuilder::createstring $manifestIdStarts a new builderselfNothing declaredThe constructor is private; this is the only entry
PipelineManifestBuilder::addStepstring $id, PipelineStepType $type, array $parameters = [], array $dependsOn = [], ?StepOutputType $outputType = nullAppends a step; a null output type is inferred from the step typeselfNothing declaredValidation is deferred to build()
PipelineManifestBuilder::stopOnErrorbool $stop = trueSets halt-on-first-failureselfNothing declaredDefaults to true
PipelineManifestBuilder::maxRetriesint $retriesSets the per-step retry ceilingselfNothing declaredDefaults to 0 (no retries)
PipelineManifestBuilder::timeoutint $timeoutMsSets the global pipeline timeoutselfNothing declared0 disables the timeout
PipelineManifestBuilder::resumeFromstring $stepIdSets the resume pointselfNothing declaredThe step must exist at build() time
PipelineManifestBuilder::buildnoneConstructs the validated manifestPipelineManifestAs PipelineManifest::__construct
PipelineOptions::__constructbool $stopOnError = true, int $maxRetries = 0, int $timeoutMs = 0Immutable execution optionsPipelineOptionsNothing declaredReadonly value object
PipelineStep::__constructstring $id, PipelineStepType $type, array $parameters = [], array $dependsOn = [], StepOutputType $outputType = StepOutputType::PdfImmutable step definitionPipelineStepNothing declaredDirect construction defaults the output type to PDF for every type
PipelineStep::isRootnoneTrue when the step has no dependenciesboolNothing declared
PipelineStepType (enum)Ten string-backed cases: generate, merge, split, inspect, compress, sign, convert, plus the gated redact, extract, ocr_overlayOne case per built-in operation
PipelineStepType::requiresPacknoneTrue for Redact, Extract, and OcrOverlayboolNothing declaredAll other cases return false
PipelineStepType::requiredCapabilitynoneMaps gated cases to their capability codes?stringNothing declarednull for non-gated cases
PipelineStatus (enum)Five cases: pending, running, completed, failed, cancelledShared by pipeline and step results
PipelineStatus::isTerminalnoneTrue for Completed, Failed, and CancelledboolNothing declaredPending and Running are non-terminal
StepOutputType (enum)Three cases: pdf, json, metadataDrives build-time edge validation
StepOutputType::forStepTypePipelineStepType $stepTypeDefault output type for a step typeselfNothing declaredInspect and Extract map to JSON; all other types map to PDF
StepOutputType::isCompatibleWithself $expectedInputTrue for a same-type match or a PDF outputboolNothing declaredHelper; PDF is the universal input
PipelineContext::__constructstring $manifestId, array $variables = [], ?string $resumeFromStepId = nullPer-run in-memory contextPipelineContextNothing declaredNo TTL, expiry, persistence, or backing store
PipelineContext::setStepResult / ::getStepResultstring $stepId (+ StepResult on set)Records or reads a step resultvoid / ?StepResultNothing declarednull for a step not yet executed
PipelineContext::setStepOutput / ::getStepOutputstring $stepId (+ mixed on set)Stores or reads an intermediate outputvoid / mixedNothing declarednull for a missing output
PipelineContext::hasStepResultstring $stepIdWhether a step already executedboolNothing declaredSupports resume checks
PipelineContext::allStepResultsnoneAll results recorded so fararray<string, StepResult>Nothing declaredKeyed by step ID
PipelineContext::isResumenoneWhether the run resumes from a stepboolNothing declared
PipelineResult::isSuccessnoneTrue only for overall Completed statusboolNothing declaredResult is produced by the executor
PipelineResult::getStepResultstring $stepIdFinds one step result by ID?StepResultNothing declarednull for skipped or unknown steps
PipelineResult::failedStepsnoneFilters the failed step resultslist<StepResult>Nothing declaredEmpty list on full success
StepResult::isSuccessnoneTrue only for step status CompletedboolNothing declaredCarries stepId, type, status, durationMs, error, output
CapabilityResolverInterface::hasCapabilitystring $capabilityAffirmative entitlement test for one capability codeboolMust not throwDeny-by-omission: false for unknown, expired, or unmapped codes
final class PipelineExecutor
{
public function __construct(
private readonly StepResolverRegistry $registry,
private readonly ?CapabilityResolverInterface $capabilityResolver = null,
)
public function execute(PipelineManifest $manifest, array $variables = []): PipelineResult
}
final class PipelineManifestBuilder
{
public static function create(string $manifestId): self
public function addStep(
string $id,
PipelineStepType $type,
array $parameters = [],
array $dependsOn = [],
?StepOutputType $outputType = null,
): self
public function stopOnError(bool $stop = true): self
public function maxRetries(int $retries): self
public function timeout(int $timeoutMs): self
public function resumeFrom(string $stepId): self
public function build(): PipelineManifest
}
interface CapabilityResolverInterface
{
public function hasCapability(string $capability): bool;
}

Validation runs in the PipelineManifest constructor, before any execution. In order: the step list must be non-empty; the step count is capped at 10 000, converting adversarially deep dependency chains into a catchable OverflowException instead of native stack exhaustion; step IDs must be unique; every dependsOn reference must resolve; the dependency graph must be acyclic; output types must be compatible; a declared resume step must exist. Each violation raises InvalidArgumentException with a specific message.

The output-type check applies to steps whose type maps to PDF output: every dependency of such a step must itself produce PDF output. Dependency edges into JSON-producing step types (inspect, extract) are not type-checked in this release.

execute($manifest, $variables) builds a fresh PipelineContext, computes the topological order, and runs steps sequentially in that order. With a resume point set, earlier steps are skipped until the named step is reached. Skipped predecessors are not re-executed and their outputs are not restored: the context is per-run and in-memory, so a resumed step reading a skipped predecessor’s output observes null.

The global timeout, when positive, is evaluated between steps, before each step starts. On expiry the pipeline status becomes Failed and remaining steps do not start. A step already running is never interrupted mid-execution, so one long step can overrun the budget.

Each step receives at most maxRetries + 1 attempts. A successful attempt returns immediately. Any failed attempt — a Failed result from the resolver, or a thrown Throwable — is retried while attempts remain; the final attempt’s result is returned. A Throwable raised inside a resolver is downgraded to a Failed step result carrying the exception message, or Unknown error when the message is empty. execute() therefore always returns a PipelineResult; it never propagates a resolver failure.

A step type with no registered resolver yields a Failed step result with an explicit message; the run is not aborted. With stopOnError true (the default), execution halts on the first failed step and the pipeline status is Failed. With it false, execution continues and the final status is Failed if any step failed, otherwise Completed.

Before any resolver dispatch, every pack-gated step (Redact, Extract, OcrOverlay) is checked against the injected CapabilityResolverInterface. The gate is fail-closed: a missing resolver, a false answer, or an unmapped capability code all reject the step. Rejection produces a Failed step result whose error carries the SPEC-LIC-001 code, the step type, and the required capability. A gated rejection consumes no retry attempts and reports a duration of 0.0. Implementations of the resolver must return true only for an affirmatively held entitlement and must not throw.

PipelineResult reports the manifest ID, overall status, per-step results in execution order, total duration in milliseconds, and the total, completed, and failed step counts. stepsTotal counts every step in the manifest, including steps skipped by resume or unreached after a halt; stepsCompleted and stepsFailed count executed steps only.

  • The executor is designed for asynchronous execution inside a job worker. Inline use blocks the caller for the full pipeline duration.
  • The global timeout is a between-steps check. A single long step can overrun the budget; no step is interrupted mid-flight.
  • Resume skips steps within the same execution only. It does not restore outputs from any store; cross-run resume with cached outputs is not implemented.
  • Constructing PipelineStep directly defaults the output type to PDF for every step type. Use the builder, or pass the output type explicitly, so inspect and extract steps declare JSON output and edge validation stays meaningful.
  • A resolver exception with an empty message is normalized to Unknown error in the step result.
  • Failed step results produced by the gate or by a missing resolver report a duration of 0.0.
  • PipelineResult::getStepResult() returns null both for unknown IDs and for steps skipped by resume or a halt; distinguish via stepsTotal versus the result list length.
  • This module performs no cryptographic operations and defines no FIPS-specific behavior. FIPS posture for the sign step is governed by the signing module, not by the pipeline.

The pipeline performs no format conformance work of its own. Conformance of each produced artifact is owned by the module behind the executing step — signing, optimization, conversion, and so on — and is documented on those modules’ reference pages.

  • The module source carries @since 2.2.0; this reference documents the surface as shipped in nextpdf/pro 3.1.0.
  • All classes are final; the manifest, options, step, and result types are readonly value objects. Construct new instances instead of mutating.
  • StepResolverInterface and StepResolverRegistry are @internal. Step resolvers are built-in only; user-defined custom step handlers are not supported in this release.
  • CapabilityResolverInterface is the public entitlement seam. Implementations must be deny-by-omission and must not default-allow.
  • This PHP executor is the manifest-validation and sequential execution path; production deployments may dispatch through the sidecar for parallel orchestration. The capability gate on the PHP path is independently fail-closed either way.
  • Internal mechanism detail stays in the source repository’s internal documentation and is out of scope for this manual.

This page documents externally observable behavior and the supported public API surface only. Internal namespace paths, helper classes, mechanism tables, runbook filenames, and ticket prefixes are out of scope.