[{"data":1,"prerenderedAt":4397},["ShallowReactive",2],{"docs-nav":3,"cli-commands":159,"docs-\u002Fdocs\u002Fguides\u002Fwriting-workflows":668},[4],{"title":5,"path":6,"stem":7,"children":8},"Docs","\u002Fdocs","docs",[9,22,47,80,101,142,146],{"title":10,"path":11,"stem":12,"children":13},"Getting Started","\u002Fdocs\u002Fgetting-started","docs\u002F1.getting-started\u002Findex",[14,18],{"title":15,"path":16,"stem":17},"Installation","\u002Fdocs\u002Fgetting-started\u002Finstallation","docs\u002F1.getting-started\u002F1.installation",{"title":19,"path":20,"stem":21},"Quick start","\u002Fdocs\u002Fgetting-started\u002Fquick-start","docs\u002F1.getting-started\u002F2.quick-start",{"title":23,"path":24,"stem":25,"children":26},"Concepts","\u002Fdocs\u002Fconcepts","docs\u002F2.concepts\u002Findex",[27,31,35,39,43],{"title":28,"path":29,"stem":30},"Files-first","\u002Fdocs\u002Fconcepts\u002Ffiles-first","docs\u002F2.concepts\u002F1.files-first",{"title":32,"path":33,"stem":34},"The hierarchy","\u002Fdocs\u002Fconcepts\u002Fhierarchy","docs\u002F2.concepts\u002F2.hierarchy",{"title":36,"path":37,"stem":38},"OpenAPI as the source of truth","\u002Fdocs\u002Fconcepts\u002Fopenapi-source-of-truth","docs\u002F2.concepts\u002F3.openapi-source-of-truth",{"title":40,"path":41,"stem":42},"Instance visibility","\u002Fdocs\u002Fconcepts\u002Finstance-visibility","docs\u002F2.concepts\u002F4.instance-visibility",{"title":44,"path":45,"stem":46},"Environments","\u002Fdocs\u002Fconcepts\u002Fenvironments","docs\u002F2.concepts\u002F5.environments",{"title":48,"path":49,"stem":50,"children":51},"Guides","\u002Fdocs\u002Fguides","docs\u002F3.guides\u002Findex",[52,56,60,64,68,72,76],{"title":53,"path":54,"stem":55},"Importing a spec","\u002Fdocs\u002Fguides\u002Fimporting-a-spec","docs\u002F3.guides\u002F1.importing-a-spec",{"title":57,"path":58,"stem":59},"Request instances","\u002Fdocs\u002Fguides\u002Frequest-instances","docs\u002F3.guides\u002F2.request-instances",{"title":61,"path":62,"stem":63},"Auth & middlewares","\u002Fdocs\u002Fguides\u002Fauth-and-middlewares","docs\u002F3.guides\u002F3.auth-and-middlewares",{"title":65,"path":66,"stem":67},"Writing workflows","\u002Fdocs\u002Fguides\u002Fwriting-workflows","docs\u002F3.guides\u002F4.writing-workflows",{"title":69,"path":70,"stem":71},"CI\u002FCD","\u002Fdocs\u002Fguides\u002Fci-cd","docs\u002F3.guides\u002F5.ci-cd",{"title":73,"path":74,"stem":75},"Documenting an API","\u002Fdocs\u002Fguides\u002Fdocumenting-an-api","docs\u002F3.guides\u002F6.documenting-an-api",{"title":77,"path":78,"stem":79},"Pro license","\u002Fdocs\u002Fguides\u002Fpro-license","docs\u002F3.guides\u002F7.pro-license",{"title":81,"path":82,"stem":83,"children":84},"Interface","\u002Fdocs\u002Finterface","docs\u002F4.interface\u002Findex",[85,89,93,97],{"title":86,"path":87,"stem":88},"Navigation","\u002Fdocs\u002Finterface\u002Fnavigation","docs\u002F4.interface\u002F1.navigation",{"title":90,"path":91,"stem":92},"History","\u002Fdocs\u002Finterface\u002Fhistory","docs\u002F4.interface\u002F2.history",{"title":94,"path":95,"stem":96},"Command palette","\u002Fdocs\u002Finterface\u002Fcommand-palette","docs\u002F4.interface\u002F3.command-palette",{"title":98,"path":99,"stem":100},"Keyboard shortcuts","\u002Fdocs\u002Finterface\u002Fkeyboard-shortcuts","docs\u002F4.interface\u002F4.keyboard-shortcuts",{"title":102,"path":103,"stem":104,"children":105},"Reference","\u002Fdocs\u002Freference","docs\u002F5.reference\u002Findex",[106],{"title":107,"path":108,"stem":109,"children":110},"File formats","\u002Fdocs\u002Freference\u002Ffile-formats","docs\u002F5.reference\u002F1.file-formats\u002Findex",[111,115,119,123,126,130,134,138],{"title":112,"path":113,"stem":114},"config.json","\u002Fdocs\u002Freference\u002Ffile-formats\u002Fconfig-json","docs\u002F5.reference\u002F1.file-formats\u002F1.config-json",{"title":116,"path":117,"stem":118},"api.json","\u002Fdocs\u002Freference\u002Ffile-formats\u002Fapi-json","docs\u002F5.reference\u002F1.file-formats\u002F2.api-json",{"title":120,"path":121,"stem":122},"_resource.json","\u002Fdocs\u002Freference\u002Ffile-formats\u002Fresource-json","docs\u002F5.reference\u002F1.file-formats\u002F3.resource-json",{"title":57,"path":124,"stem":125},"\u002Fdocs\u002Freference\u002Ffile-formats\u002Frequest-instance","docs\u002F5.reference\u002F1.file-formats\u002F4.request-instance",{"title":127,"path":128,"stem":129},"Environment files","\u002Fdocs\u002Freference\u002Ffile-formats\u002Fenvironment-schema","docs\u002F5.reference\u002F1.file-formats\u002F5.environment-schema",{"title":131,"path":132,"stem":133},"schema.rules.json","\u002Fdocs\u002Freference\u002Ffile-formats\u002Fschema-rules","docs\u002F5.reference\u002F1.file-formats\u002F6.schema-rules",{"title":135,"path":136,"stem":137},"Documentation files","\u002Fdocs\u002Freference\u002Ffile-formats\u002Fdocumentation","docs\u002F5.reference\u002F1.file-formats\u002F7.documentation",{"title":139,"path":140,"stem":141},"Workflow files","\u002Fdocs\u002Freference\u002Ffile-formats\u002Fworkflow","docs\u002F5.reference\u002F1.file-formats\u002F8.workflow",{"title":143,"path":144,"stem":145},"CLI reference","\u002Fdocs\u002Fcli","docs\u002F6.cli\u002Findex",{"title":147,"path":148,"stem":149,"children":150},"Plugins","\u002Fdocs\u002Fplugins","docs\u002F7.plugins\u002Findex",[151,155],{"title":152,"path":153,"stem":154},"Using plugins","\u002Fdocs\u002Fplugins\u002Fusing-plugins","docs\u002F7.plugins\u002F1.using-plugins",{"title":156,"path":157,"stem":158},"Writing a plugin","\u002Fdocs\u002Fplugins\u002Fwriting-a-plugin","docs\u002F7.plugins\u002F2.writing-a-plugin",{"id":160,"extension":161,"meta":162,"namespaces":163,"stem":665,"version":666,"__hash__":667},"cliCommands\u002Fdata\u002Fcli-commands.json","json",{},[164,201,277,406,422,501,537,608,640],{"namespace":165,"description":166,"commands":167,"seeAlso":198},"project","Create and validate an API Craft project.",[168,178,183,192],{"name":169,"usage":170,"description":171,"flags":172,"examples":176},"init","craftr project init \u003Cname> [--private]","Initialize an API Craft project in the current directory.",[173],{"name":174,"description":175},"--private","Mark the project as private (gitignore the apis directory and .api-craft).",[177],"craftr project init \"Petstore Project\"",{"name":179,"usage":180,"description":181,"flags":182},"validate","craftr project validate","Validate the project structure and report problems.",[],{"name":184,"usage":185,"description":186,"examples":187,"seeAlso":188},"trust","craftr project trust","Approve this project so its scripts (middlewares, custom auth, workflow scripts) can run. Persists until untrusted.",[185],[189],{"label":190,"to":191},"Auth & middlewares: middlewares","\u002Fdocs\u002Fguides\u002Fauth-and-middlewares#middlewares",{"name":193,"usage":194,"description":195,"seeAlso":196},"untrust","craftr project untrust","Refuse this project, blocking its scripts until it is trusted again.",[197],{"label":190,"to":191},[199,200],{"label":28,"to":29},{"label":19,"to":20},{"namespace":202,"description":203,"commands":204,"seeAlso":273},"api","Manage APIs and their default auth and overrides.",[205,210,223,229,242,261,267],{"name":206,"usage":207,"description":208,"flags":209},"list","craftr api list","List the APIs in the project.",[],{"name":211,"usage":212,"description":213,"flags":214,"examples":220},"create","craftr api create --api \u003Capi>","Create a new API.",[215],{"name":216,"short":217,"description":218,"takesValue":219,"required":219},"--api","-a","API slug.",true,[221,222],"craftr api create --api petstore-api","craftr api create -a petstore-api",{"name":224,"usage":225,"description":226,"flags":227},"delete","craftr api delete --api \u003Capi>","Delete an API.",[228],{"name":216,"short":217,"description":218,"takesValue":219,"required":219},{"name":230,"usage":231,"description":232,"flags":233,"examples":238,"seeAlso":240},"set auth bearer","craftr api set auth bearer --token \u003Ctoken> [--api \u003Capi>]","Set the API default auth to a bearer token. Supports {{variables}}.",[234,237],{"name":235,"description":236,"takesValue":219,"required":219},"--token","Bearer token value. Supports {{variables}}.",{"name":216,"short":217,"description":218,"takesValue":219},[239],"craftr api set auth bearer --token \"{{apiKey}}\" --api petstore-api",[241],{"label":61,"to":62},{"name":243,"usage":244,"description":245,"flags":246,"examples":257,"seeAlso":259},"set auth api-key","craftr api set auth api-key --in \u003Cheader|query> --name \u003Cname> --value \u003Cvalue> [--api \u003Capi>]","Set the API default auth to an API key sent as a header or query parameter.",[247,250,253,256],{"name":248,"description":249,"takesValue":219,"required":219},"--in","Where to send the key: header or query.",{"name":251,"description":252,"takesValue":219,"required":219},"--name","Header or query parameter name.",{"name":254,"description":255,"takesValue":219,"required":219},"--value","API key value. Supports {{variables}}.",{"name":216,"short":217,"description":218,"takesValue":219},[258],"craftr api set auth api-key --in header --name api_key --value \"{{apiKey}}\" -a petstore-api",[260],{"label":61,"to":62},{"name":262,"usage":263,"description":264,"flags":265},"unset auth","craftr api unset auth [--api \u003Capi>]","Clear the API default auth.",[266],{"name":216,"short":217,"description":218,"takesValue":219},{"name":268,"usage":269,"description":270,"flags":271},"overrides","craftr api overrides [--api \u003Capi>]","List all overrides for an API, grouped by kind (api, resource, operation, parameter).",[272],{"name":216,"short":217,"description":218,"takesValue":219},[274,275],{"label":61,"to":62},{"label":276,"to":117},"api.json format",{"namespace":278,"description":279,"commands":280,"seeAlso":403},"schema","Import an OpenAPI spec and manage the resource\u002Foperation mapping.",[281,302,308,314,320,326,334,349,355,361,370,376,382,397],{"name":282,"usage":283,"description":284,"flags":285,"examples":297,"seeAlso":300},"import","craftr schema import [source] [--api \u003Capi>] [--yes] [--no-persist-source] [--no-auto-clear-caught-up]","Import an OpenAPI spec: preview the diff, resolve conflicts, write, and remap. Source may be a file path or URL; omit to use the saved source or piped stdin.",[286,287,291,294],{"name":216,"short":217,"description":218,"takesValue":219},{"name":288,"short":289,"description":290},"--yes","-y","Skip the apply confirmation (required for non-interactive use).",{"name":292,"description":293},"--no-persist-source","Do not persist the spec source in api.json when a path or URL is given. Ignored for stdin and for a saved source.",{"name":295,"description":296},"--no-auto-clear-caught-up","Keep overrides whose value already matches the new source.",[298,299],"craftr schema import .\u002Fopenapi.json -a petstore-api","craftr schema import https:\u002F\u002Fpetstore3.swagger.io\u002Fapi\u002Fv3\u002Fopenapi.json -a petstore-api --yes",[301],{"label":53,"to":54},{"name":303,"usage":304,"description":305,"flags":306},"diff","craftr schema diff [source] [--api \u003Capi>]","Preview the diff between the current schema and a candidate spec. Uses the persisted source if no path is given.",[307],{"name":216,"short":217,"description":218,"takesValue":219},{"name":309,"usage":310,"description":311,"flags":312},"read","craftr schema read [--api \u003Capi>]","Read the effective schema (resources, unmapped, ignored, orphan rules).",[313],{"name":216,"short":217,"description":218,"takesValue":219},{"name":315,"usage":316,"description":317,"flags":318},"unmapped","craftr schema unmapped [--api \u003Capi>]","List operations that are not mapped to any resource.",[319],{"name":216,"short":217,"description":218,"takesValue":219},{"name":321,"usage":322,"description":323,"flags":324},"ignored","craftr schema ignored [--api \u003Capi>]","List ignored operations with their rule ids.",[325],{"name":216,"short":217,"description":218,"takesValue":219},{"name":327,"usage":328,"description":329,"flags":330,"examples":332},"map","craftr schema map \u003Coperation-id> \u003Cresource> \u003Coperation> [--api \u003Capi>]","Map an unmapped operation to a resource and operation name.",[331],{"name":216,"short":217,"description":218,"takesValue":219},[333],"craftr schema map updatePetWithForm Pet updateWithForm -a petstore-api",{"name":335,"usage":336,"description":337,"flags":338},"map-all","craftr schema map-all (--from \u003Cfile> | --default | --skip-all) [--api \u003Capi>]","Bulk-map every unmapped operation. Choose exactly one mode.",[339,342,345,348],{"name":340,"description":341,"takesValue":219},"--from","Path to a JSON array of {operationId, resource, operation, skip?}. Use \"-\" for stdin.",{"name":343,"description":344},"--default","Apply heuristic defaults to every unmapped operation.",{"name":346,"description":347},"--skip-all","Add an ignore rule for every unmapped operation.",{"name":216,"short":217,"description":218,"takesValue":219},{"name":350,"usage":351,"description":352,"flags":353},"rename operation","craftr schema rename operation \u003Cresource> \u003Coperation-name> \u003Cnew-name> [--api \u003Capi>]","Rename a single operation within a resource.",[354],{"name":216,"short":217,"description":218,"takesValue":219},{"name":356,"usage":357,"description":358,"flags":359},"rename resource","craftr schema rename resource \u003Cold-slug> \u003Cnew-slug> [--api \u003Capi>]","Rename a resource.",[360],{"name":216,"short":217,"description":218,"takesValue":219},{"name":362,"usage":363,"description":364,"flags":365},"set-parent","craftr schema set-parent \u003Cresource> [parent] [--clear] [--api \u003Capi>]","Set or clear the parent of a resource. Provide a parent or pass --clear, not both.",[366,369],{"name":367,"description":368},"--clear","Clear the parent instead of setting it.",{"name":216,"short":217,"description":218,"takesValue":219},{"name":371,"usage":372,"description":373,"flags":374},"ignore","craftr schema ignore \u003Coperation-id> [--api \u003Capi>]","Ignore an operation. It is removed from the effective schema.",[375],{"name":216,"short":217,"description":218,"takesValue":219},{"name":377,"usage":378,"description":379,"flags":380},"unignore","craftr schema unignore \u003Coperation-id> [--api \u003Capi>]","Remove an ignore rule by operationId.",[381],{"name":216,"short":217,"description":218,"takesValue":219},{"name":383,"usage":384,"description":385,"flags":386},"define","craftr schema define \u003Cresource> \u003Cname> --method \u003Cmethod> --path \u003Cpath> --operation-id \u003Cid> [--api \u003Capi>]","Define a local operation that does not exist in the source spec. Creates the resource if new.",[387,390,393,396],{"name":388,"description":389,"takesValue":219,"required":219},"--method","HTTP method (GET, POST, …).",{"name":391,"description":392,"takesValue":219,"required":219},"--path","OpenAPI path, e.g. \u002Fpet\u002F{petId}\u002Fvaccinations.",{"name":394,"description":395,"takesValue":219,"required":219},"--operation-id","Unique operationId.",{"name":216,"short":217,"description":218,"takesValue":219},{"name":398,"usage":399,"description":400,"flags":401},"undefine","craftr schema undefine \u003Cresource> \u003Cname> [--api \u003Capi>]","Delete a locally-defined operation.",[402],{"name":216,"short":217,"description":218,"takesValue":219},[404,405],{"label":53,"to":54},{"label":36,"to":37},{"namespace":407,"description":408,"commands":409,"seeAlso":420},"spec","Read the OpenAPI spec.",[410],{"name":309,"usage":411,"description":412,"flags":413,"examples":418},"craftr spec read [--api \u003Capi>] [--imported]","Print the effective OpenAPI spec, or the raw imported spec with --imported.",[414,415],{"name":216,"short":217,"description":218,"takesValue":219},{"name":416,"description":417},"--imported","Print the raw imported spec (spec.imported.json) instead of the projected one.",[419],"craftr spec read -a petstore-api | jq '.paths | keys'",[421],{"label":36,"to":37},{"namespace":423,"description":424,"commands":425,"seeAlso":497},"req","List, run, and manage request instances.",[426,439,474,480,486],{"name":206,"usage":427,"description":428,"flags":429},"craftr req list [--resource \u003Cresource>] [--filter \u003Ctext>] [--api \u003Capi>]","List request instances, optionally filtered.",[430,434,438],{"name":431,"short":432,"description":433,"takesValue":219},"--resource","-r","Resource slug to list. Omit to list every request.",{"name":435,"short":436,"description":437,"takesValue":219},"--filter","-f","Case-insensitive substring matched against resource and request name.",{"name":216,"short":217,"description":218,"takesValue":219},{"name":440,"usage":441,"description":442,"flags":443,"examples":465,"seeAlso":469},"run","craftr req run \u003Cresource\u002Fname> --env \u003Cenv> [--api \u003Capi>] [--var \u003Ck=v>…] [--set \u003Cns.k=v>…] [--full] [--trust] [--verbose]","Execute a request instance against an environment. Prints the response body by default.",[444,448,449,452,455,458,461],{"name":445,"short":446,"description":447,"takesValue":219,"required":219},"--env","-e","Environment name.",{"name":216,"short":217,"description":218,"takesValue":219},{"name":450,"description":451,"takesValue":219,"repeatable":219},"--var","Override an environment variable: key=value. The variable must be declared in the environment schema.",{"name":453,"description":454,"takesValue":219,"repeatable":219},"--set","Override a request parameter: \u003Cpath|query|header|body>.key=value. Body keys support dot-notation.",{"name":456,"description":457},"--full","Print the full execution result instead of just the response body.",{"name":459,"description":460},"--trust","Allow this project's scripts to run for this invocation only. Never saved.",{"name":462,"short":463,"description":464},"--verbose","-v","Print the trace to stderr. -v is info, -vv adds debug.",[466,467,468],"craftr req run Pet\u002Fget-pet -e dev","craftr req run Pet\u002Fget-pet -e dev --set path.petId=3 | jq '.name'","craftr req run Pet\u002Fget-pet -e dev --var apiKey=sk-test --full",[470,473],{"label":471,"to":472},"Request instances: running","\u002Fdocs\u002Fguides\u002Frequest-instances#running",{"label":69,"to":70},{"name":475,"usage":476,"description":477,"flags":478},"duplicate","craftr req duplicate \u003Cresource\u002Fname> \u003Cnew-name> [--api \u003Capi>]","Duplicate a request instance. The copy is created as private.",[479],{"name":216,"short":217,"description":218,"takesValue":219},{"name":481,"usage":482,"description":483,"flags":484},"rename","craftr req rename \u003Cresource\u002Fname> \u003Cnew-name> [--api \u003Capi>]","Rename a request instance.",[485],{"name":216,"short":217,"description":218,"takesValue":219},{"name":487,"usage":488,"description":489,"flags":490,"seeAlso":495},"set-visibility","craftr req set-visibility \u003Cresource\u002Fname> \u003Cpublic|private> [--new-name \u003Cname>] [--api \u003Capi>]","Change a request instance's visibility (public or private).",[491,494],{"name":492,"description":493,"takesValue":219},"--new-name","Rename the request as it changes visibility.",{"name":216,"short":217,"description":218,"takesValue":219},[496],{"label":40,"to":41},[498,499],{"label":57,"to":58},{"label":500,"to":124},"Request instance format",{"namespace":502,"description":503,"commands":504,"seeAlso":533},"env","Manage environments and their values.",[505,510,515,523,528],{"name":206,"usage":506,"description":507,"flags":508},"craftr env list [--api \u003Capi>]","List environments.",[509],{"name":216,"short":217,"description":218,"takesValue":219},{"name":309,"usage":511,"description":512,"flags":513},"craftr env read \u003Cenv> [--api \u003Capi>]","Read an environment's values, with the extends chain resolved.",[514],{"name":216,"short":217,"description":218,"takesValue":219},{"name":516,"usage":517,"description":518,"flags":519,"examples":521},"write","craftr env write \u003Cenv> \u003Ckey> \u003Cvalue> [--api \u003Capi>]","Write a single environment variable. The value is JSON-parsed if it is a valid scalar, otherwise stored as a string.",[520],{"name":216,"short":217,"description":218,"takesValue":219},[522],"craftr env write dev baseUrl https:\u002F\u002Fpetstore3.swagger.io\u002Fapi\u002Fv3",{"name":224,"usage":524,"description":525,"flags":526},"craftr env delete \u003Cenv> [--api \u003Capi>]","Delete an environment.",[527],{"name":216,"short":217,"description":218,"takesValue":219},{"name":481,"usage":529,"description":530,"flags":531},"craftr env rename \u003Cold-name> \u003Cnew-name> [--api \u003Capi>]","Rename an environment.",[532],{"name":216,"short":217,"description":218,"takesValue":219},[534,535],{"label":44,"to":45},{"label":536,"to":128},"Environment schema format",{"namespace":538,"description":539,"commands":540,"seeAlso":604},"workflow","Run project-scoped workflows.",[541,574,578,584,595,598,601],{"name":440,"usage":542,"description":543,"flags":544,"examples":565,"seeAlso":569},"craftr workflow run [\u003Cworkflow>...] [--all] --env \u003Capi>=\u003Cenv> [--input ...] [--concurrency \u003Cn>] [--on-failure halt|continue] [--full-output \u003Cfile>] [--trust]","Run one or more workflows (or every workflow with --all) and aggregate the results. Prints a JSON summary report on stdout, a human summary on stderr, and exits 1 if any workflow failed (130 if cancelled).",[545,548,550,553,556,559,561,564],{"name":546,"description":547},"--all","Run every workflow in the project. Mutually exclusive with named workflows.",{"name":445,"short":446,"description":549,"takesValue":219,"required":219,"repeatable":219},"Bind an environment to an API: \u003Capi>=\u003Cenv>. Repeat once per API the run touches (the union across a batch).",{"name":551,"description":552,"takesValue":219,"repeatable":219},"--input","Workflow input: [\u003Cworkflow>:]\u003Ckey>=\u003Cvalue>. Without a workflow prefix it applies to every workflow in the batch.",{"name":554,"description":555,"takesValue":219},"--concurrency","Workflows in flight at once (default 4). 1 runs them sequentially.",{"name":557,"description":558,"takesValue":219},"--on-failure","halt stops starting new workflows after a failure; continue (default) runs them all. Separate from a workflow file's own onFailure, which governs blocks within a run.",{"name":462,"short":463,"description":560},"Progress and traces to stderr: -v workflow level, -vv block logs, -vvv debug.",{"name":562,"description":563,"takesValue":219},"--full-output","Write the complete run result (every block and response) to this file. Omitted, that detail is discarded.",{"name":459,"description":460},[566,567,568],"craftr workflow run pet-lifecycle --env petstore-api=prod","craftr workflow run publish-and-verify -e petstore-api=prod -e catalog=staging","craftr workflow run --all -e petstore-api=prod -e catalog=staging",[570,573],{"label":571,"to":572},"Writing workflows: from the CLI","\u002Fdocs\u002Fguides\u002Fwriting-workflows#from-the-cli",{"label":69,"to":70},{"name":206,"usage":575,"description":576,"examples":577},"craftr workflow list","List every workflow in the project.",[575],{"name":179,"usage":579,"description":580,"examples":581},"craftr workflow validate [\u003Cworkflow>...]","Check that a workflow's references resolve (api, resource, operation, instance, scripts) and refresh the generated script typings. Omit the name to check every workflow. Sends no request, so it is cheap to run in CI before a run.",[582,583],"craftr workflow validate","craftr workflow validate pet-lifecycle",{"name":585,"usage":586,"description":587,"flags":588,"examples":592},"history","craftr workflow history [\u003Crun-id>] [--limit \u003Cn>]","List past workflow runs newest first, or read one run in full by id. Run ids are the ISO timestamp of the run with \":\" replaced by \"-\".",[589],{"name":590,"description":591,"takesValue":219},"--limit","Keep only the first N summaries. Ignored when an id is given.",[593,594],"craftr workflow history --limit 5","craftr workflow history 2026-08-23T10-14-02.981Z",{"name":481,"usage":596,"description":597},"craftr workflow rename \u003Cold-name> \u003Cnew-name>","Rename a workflow, its scripts directory included.",{"name":475,"usage":599,"description":600},"craftr workflow duplicate \u003Csource-name> \u003Cnew-name>","Duplicate a workflow, its scripts directory included.",{"name":224,"usage":602,"description":603},"craftr workflow delete \u003Cworkflow-name>","Delete a workflow and its scripts directory.",[605,606],{"label":65,"to":66},{"label":607,"to":140},"Workflow file format",{"namespace":609,"description":610,"commands":611,"seeAlso":635},"license","Install, inspect or remove the Pro license. Per user, not per project, so these work from any directory.",[612,623,629],{"name":613,"usage":614,"description":615,"flags":616,"examples":620},"install","craftr license install [--file \u003Cpath>]","Install a license from a file or from stdin. Verifies the signature first; on failure the current license, if any, is left in place.",[617],{"name":618,"description":619,"takesValue":219},"--file","Path to the license file. Reads stdin when omitted.",[621,622],"craftr license install --file=license.key","cat license.key | craftr license install",{"name":624,"usage":625,"description":626,"flags":627,"examples":628},"get","craftr license get","Print the active license state as JSON: status, tier, who it is issued to, expiry, features and limits. A limit of -1 means unlimited.",[],[625],{"name":630,"usage":631,"description":632,"flags":633,"examples":634},"remove","craftr license remove","Delete the installed license and fall back to the Free plan. Prints the resulting state.",[],[631],[636,637],{"label":77,"to":78},{"label":638,"to":639},"Pricing","\u002Fpricing",{"namespace":641,"description":642,"commands":643,"seeAlso":662},"completion","Shell tab-completion management.",[644,654],{"name":613,"usage":645,"description":646,"flags":647,"examples":651},"craftr completion install [--shell \u003Cbash|zsh|fish>]","Install shell tab-completion. Writes the completion script and, for bash and zsh, adds a marked block to the shell rc file that sources it.",[648],{"name":649,"description":650,"takesValue":219},"--shell","bash, zsh or fish. Defaults to the shell named by $SHELL.",[652,653],"craftr completion install","craftr completion install --shell fish",{"name":655,"usage":656,"description":657,"flags":658,"examples":660},"uninstall","craftr completion uninstall [--shell \u003Cbash|zsh|fish>]","Remove the completion script and the block it added to the shell rc file.",[659],{"name":649,"description":650,"takesValue":219},[661],"craftr completion uninstall",[663],{"label":15,"to":664},"\u002Fdocs\u002Fgetting-started\u002Finstallation#tab-completion","data\u002Fcli-commands",1,"wkEyqz4vOf0W24NAkAJY-4EyLZpK5NBQO7YE9JmKeUw",{"id":669,"title":65,"body":670,"description":4389,"extension":4390,"meta":4391,"navigation":4392,"path":66,"seo":4393,"stem":67,"__hash__":4396},"docs\u002Fdocs\u002F3.guides\u002F4.writing-workflows.md",{"type":671,"value":672,"toc":4361},"minimark",[673,677,686,707,710,746,751,765,775,782,786,920,1008,1011,1036,1117,1128,1131,1142,1240,1249,1335,1340,1372,1491,1513,1517,1541,1675,1678,1785,1809,1819,1823,1829,1880,1887,1891,1907,2107,2111,2114,2178,2205,2350,2356,2549,2553,2559,2716,2722,2726,2729,2781,2883,2888,2891,2894,2930,2951,2957,2979,2982,3002,3011,3096,3099,3155,3159,3166,3279,3379,3473,3480,3500,3514,3517,3524,3530,3555,3558,3564,3568,3572,3596,3601,3605,3621,3683,3700,3745,3763,3839,3996,4030,4043,4076,4086,4115,4137,4141,4154,4158,4161,4286,4291,4294,4304,4308,4313,4332,4343,4347,4357],[674,675,65],"h1",{"id":676},"writing-workflows",[678,679,680,681,685],"p",{},"A workflow is an ordered list of ",[682,683,684],"strong",{},"blocks",". Each block does one thing (fire a request, check a\nvalue, branch, loop) and later blocks read the results of earlier ones. The run passes only if\nevery block passes.",[678,687,688,689,692,693,697,698,701,702,706],{},"Workflows are ",[682,690,691],{},"project-scoped",": one workflow can call operations across several\n",[694,695,696],"a",{"href":33},"APIs"," (create through your admin API, then verify through another).\nThe environment isn't baked into the definition; it's bound ",[682,699,700],{},"per API at run time",". See\n",[694,703,705],{"href":704},"#multiple-apis--environments","Multiple APIs & environments",".",[678,708,709],{},"You build workflows in the app (drag blocks, fill the forms); the definition is saved as a plain\nJSON file, so it's committed and reviewable like everything else.",[711,712,713],"note",{},[678,714,715,718,719,723,724,723,727,723,730,733,734,737,738,741,742,706],{},[682,716,717],{},"Prefer native blocks over scripts."," ",[720,721,722],"code",{},"request",", ",[720,725,726],{},"assert",[720,728,729],{},"transform",[720,731,732],{},"condition"," and ",[720,735,736],{},"loop","\ncover most tests declaratively: no code to review, no runtime to trust. Reach for a ",[720,739,740],{},"script","\nblock only when a block can't express what you need. See ",[694,743,745],{"href":744},"#scripts","Scripts",[747,748,750],"h2",{"id":749},"where-it-lives","Where it lives",[678,752,753,754,760,761,764],{},"Workflows sit in a ",[682,755,756,757,759],{},"reserved ",[720,758,538],{}," directory"," under ",[720,762,763],{},"apis\u002F",", not tied to any one API:",[766,767,772],"pre",{"className":768,"code":770,"language":771},[769],"language-text","apis\u002F\n  workflow\u002F                          # reserved: project-scoped workflows\n    pet-lifecycle.json               # the workflow definition\n    scripts\u002F\n      pet-lifecycle\u002F                 # scripts for that workflow (one folder per workflow)\n        assert-missing.ts\n  petstore-api\u002F                          # your APIs\n  catalog\u002F\n","text",[720,773,770],{"__ignoreMap":774},"",[678,776,777,779,780,706],{},[720,778,538],{}," is a reserved API slug: you can't create an API named ",[720,781,538],{},[747,783,785],{"id":784},"anatomy","Anatomy",[766,787,790],{"className":788,"code":789,"language":161,"meta":774,"style":774},"language-json shiki shiki-themes github-light github-dark","{\n  \"version\": 1,\n  \"onFailure\": \"halt\",\n  \"validateContracts\": false,\n  \"inputs\": {\n    \"petName\": { \"type\": \"string\", \"required\": true, \"default\": \"Rufus\" }\n  },\n  \"blocks\": [ ... ]\n}\n",[720,791,792,800,816,830,843,852,892,898,914],{"__ignoreMap":774},[793,794,796],"span",{"class":795,"line":666},"line",[793,797,799],{"class":798},"sVt8B","{\n",[793,801,803,807,810,813],{"class":795,"line":802},2,[793,804,806],{"class":805},"sj4cs","  \"version\"",[793,808,809],{"class":798},": ",[793,811,812],{"class":805},"1",[793,814,815],{"class":798},",\n",[793,817,819,822,824,828],{"class":795,"line":818},3,[793,820,821],{"class":805},"  \"onFailure\"",[793,823,809],{"class":798},[793,825,827],{"class":826},"sZZnC","\"halt\"",[793,829,815],{"class":798},[793,831,833,836,838,841],{"class":795,"line":832},4,[793,834,835],{"class":805},"  \"validateContracts\"",[793,837,809],{"class":798},[793,839,840],{"class":805},"false",[793,842,815],{"class":798},[793,844,846,849],{"class":795,"line":845},5,[793,847,848],{"class":805},"  \"inputs\"",[793,850,851],{"class":798},": {\n",[793,853,855,858,861,864,866,869,871,874,876,879,881,884,886,889],{"class":795,"line":854},6,[793,856,857],{"class":805},"    \"petName\"",[793,859,860],{"class":798},": { ",[793,862,863],{"class":805},"\"type\"",[793,865,809],{"class":798},[793,867,868],{"class":826},"\"string\"",[793,870,723],{"class":798},[793,872,873],{"class":805},"\"required\"",[793,875,809],{"class":798},[793,877,878],{"class":805},"true",[793,880,723],{"class":798},[793,882,883],{"class":805},"\"default\"",[793,885,809],{"class":798},[793,887,888],{"class":826},"\"Rufus\"",[793,890,891],{"class":798}," }\n",[793,893,895],{"class":795,"line":894},7,[793,896,897],{"class":798},"  },\n",[793,899,901,904,907,911],{"class":795,"line":900},8,[793,902,903],{"class":805},"  \"blocks\"",[793,905,906],{"class":798},": [ ",[793,908,910],{"class":909},"s7hpK","...",[793,912,913],{"class":798}," ]\n",[793,915,917],{"class":795,"line":916},9,[793,918,919],{"class":798},"}\n",[921,922,923,936],"table",{},[924,925,926],"thead",{},[927,928,929,933],"tr",{},[930,931,932],"th",{},"Field",[930,934,935],{},"Meaning",[937,938,939,952,969,989,999],"tbody",{},[927,940,941,947],{},[942,943,944],"td",{},[720,945,946],{},"version",[942,948,949,950,706],{},"File format version. Always ",[720,951,812],{},[927,953,954,959],{},[942,955,956],{},[720,957,958],{},"onFailure",[942,960,961,964,965,968],{},[720,962,963],{},"halt"," (default) stops at the first failed block; ",[720,966,967],{},"continue"," runs the rest anyway.",[927,970,971,976],{},[942,972,973],{},[720,974,975],{},"validateContracts",[942,977,978,979,981,982,984,985,706],{},"When ",[720,980,878],{},", each ",[720,983,722],{}," block's response is checked against the operation's schema. See ",[694,986,988],{"href":987},"#contract-validation","Contract validation",[927,990,991,996],{},[942,992,993],{},[720,994,995],{},"inputs",[942,997,998],{},"Named parameters asked for at run time. See below.",[927,1000,1001,1005],{},[942,1002,1003],{},[720,1004,684],{},[942,1006,1007],{},"The ordered list of blocks.",[747,1009,1010],{"id":995},"Inputs",[678,1012,1013,1014,723,1017,1020,1021,1024,1025,1028,1029,1032,1033,1035],{},"Declare the values a run needs. Each is ",[720,1015,1016],{},"string",[720,1018,1019],{},"number",", or ",[720,1022,1023],{},"boolean",", optionally ",[720,1026,1027],{},"required","\nwith a ",[720,1030,1031],{},"default",". At run time the app prompts for them (the ",[682,1034,1010],{}," panel).",[766,1037,1039],{"className":788,"code":1038,"language":161,"meta":774,"style":774},"\"inputs\": {\n  \"petName\": { \"type\": \"string\", \"required\": true, \"default\": \"Rufus\" },\n  \"userId\":  { \"type\": \"number\", \"required\": false, \"default\": 1 }\n}\n",[720,1040,1041,1048,1080,1113],{"__ignoreMap":774},[793,1042,1043,1046],{"class":795,"line":666},[793,1044,1045],{"class":826},"\"inputs\"",[793,1047,851],{"class":798},[793,1049,1050,1053,1055,1057,1059,1061,1063,1065,1067,1069,1071,1073,1075,1077],{"class":795,"line":802},[793,1051,1052],{"class":805},"  \"petName\"",[793,1054,860],{"class":798},[793,1056,863],{"class":805},[793,1058,809],{"class":798},[793,1060,868],{"class":826},[793,1062,723],{"class":798},[793,1064,873],{"class":805},[793,1066,809],{"class":798},[793,1068,878],{"class":805},[793,1070,723],{"class":798},[793,1072,883],{"class":805},[793,1074,809],{"class":798},[793,1076,888],{"class":826},[793,1078,1079],{"class":798}," },\n",[793,1081,1082,1085,1088,1090,1092,1095,1097,1099,1101,1103,1105,1107,1109,1111],{"class":795,"line":818},[793,1083,1084],{"class":805},"  \"userId\"",[793,1086,1087],{"class":798},":  { ",[793,1089,863],{"class":805},[793,1091,809],{"class":798},[793,1093,1094],{"class":826},"\"number\"",[793,1096,723],{"class":798},[793,1098,873],{"class":805},[793,1100,809],{"class":798},[793,1102,840],{"class":805},[793,1104,723],{"class":798},[793,1106,883],{"class":805},[793,1108,809],{"class":798},[793,1110,812],{"class":805},[793,1112,891],{"class":798},[793,1114,1115],{"class":795,"line":832},[793,1116,919],{"class":798},[678,1118,1119,1120,1123,1124,706],{},"Reference an input anywhere a value is interpolated with ",[720,1121,1122],{},"{{name}}","; see\n",[694,1125,1127],{"href":1126},"#referencing-data","Referencing data",[747,1129,1130],{"id":684},"Blocks",[678,1132,1133,1134,1137,1138,1141],{},"Every block has a unique ",[720,1135,1136],{},"id"," and a ",[720,1139,1140],{},"type",". The id is how later blocks address its result.",[921,1143,1144,1154],{},[924,1145,1146],{},[927,1147,1148,1151],{},[930,1149,1150],{},"Type",[930,1152,1153],{},"Does",[937,1155,1156,1165,1174,1183,1200,1221,1231],{},[927,1157,1158,1162],{},[942,1159,1160],{},[720,1161,722],{},[942,1163,1164],{},"Runs an operation or a saved request instance.",[927,1166,1167,1171],{},[942,1168,1169],{},[720,1170,726],{},[942,1172,1173],{},"Checks one or more values. Fails the block if any check fails.",[927,1175,1176,1180],{},[942,1177,1178],{},[720,1179,729],{},[942,1181,1182],{},"Plucks values out of earlier results and names them for reuse.",[927,1184,1185,1189],{},[942,1186,1187],{},[720,1188,732],{},[942,1190,1191,1192,1195,1196,1199],{},"Runs a ",[720,1193,1194],{},"then"," or ",[720,1197,1198],{},"else"," branch based on a check.",[927,1201,1202,1206],{},[942,1203,1204],{},[720,1205,736],{},[942,1207,1208,1209,1212,1213,1216,1217,1220],{},"Repeats nested blocks: ",[720,1210,1211],{},"times"," N, ",[720,1214,1215],{},"forEach"," item, or ",[720,1218,1219],{},"until"," a check passes.",[927,1222,1223,1228],{},[942,1224,1225],{},[720,1226,1227],{},"group",[942,1229,1230],{},"Bundles nested blocks under one label. No behaviour of its own.",[927,1232,1233,1237],{},[942,1234,1235],{},[720,1236,740],{},[942,1238,1239],{},"Runs a free-form TypeScript function. Use sparingly.",[678,1241,1242,1243,1248],{},"Any block also accepts an optional ",[682,1244,1245],{},[720,1246,1247],{},"description",", free text explaining what the block is\nfor. It's the file format's only comment channel (JSON has no comments), and the app shows it\nnext to the block:",[766,1250,1252],{"className":788,"code":1251,"language":161,"meta":774,"style":774},"{\n  \"id\": \"create-pet\",\n  \"type\": \"request\",\n  \"description\": \"Create the pet the rest of the run operates on.\",\n  \"request\": { \"api\": \"petstore-api\", \"resource\": \"Pet\", \"operation\": \"create\" }\n}\n",[720,1253,1254,1258,1270,1282,1294,1331],{"__ignoreMap":774},[793,1255,1256],{"class":795,"line":666},[793,1257,799],{"class":798},[793,1259,1260,1263,1265,1268],{"class":795,"line":802},[793,1261,1262],{"class":805},"  \"id\"",[793,1264,809],{"class":798},[793,1266,1267],{"class":826},"\"create-pet\"",[793,1269,815],{"class":798},[793,1271,1272,1275,1277,1280],{"class":795,"line":818},[793,1273,1274],{"class":805},"  \"type\"",[793,1276,809],{"class":798},[793,1278,1279],{"class":826},"\"request\"",[793,1281,815],{"class":798},[793,1283,1284,1287,1289,1292],{"class":795,"line":832},[793,1285,1286],{"class":805},"  \"description\"",[793,1288,809],{"class":798},[793,1290,1291],{"class":826},"\"Create the pet the rest of the run operates on.\"",[793,1293,815],{"class":798},[793,1295,1296,1299,1301,1304,1306,1309,1311,1314,1316,1319,1321,1324,1326,1329],{"class":795,"line":845},[793,1297,1298],{"class":805},"  \"request\"",[793,1300,860],{"class":798},[793,1302,1303],{"class":805},"\"api\"",[793,1305,809],{"class":798},[793,1307,1308],{"class":826},"\"petstore-api\"",[793,1310,723],{"class":798},[793,1312,1313],{"class":805},"\"resource\"",[793,1315,809],{"class":798},[793,1317,1318],{"class":826},"\"Pet\"",[793,1320,723],{"class":798},[793,1322,1323],{"class":805},"\"operation\"",[793,1325,809],{"class":798},[793,1327,1328],{"class":826},"\"create\"",[793,1330,891],{"class":798},[793,1332,1333],{"class":795,"line":854},[793,1334,919],{"class":798},[1336,1337,1338],"h3",{"id":722},[720,1339,722],{},[678,1341,1342,1343,1347,1348,1351,1352,1355,1356,1359,1360,1351,1362,1365,1366,1368,1369,706],{},"Every request names the ",[682,1344,1345],{},[720,1346,202],{}," it targets, then either a schema operation\n(",[720,1349,1350],{},"resource"," + ",[720,1353,1354],{},"operation",") or a saved ",[694,1357,1358],{"href":58},"request instance","\n(",[720,1361,1350],{},[720,1363,1364],{},"instance","). ",[720,1367,268],{}," patch params and body for this run, and interpolate\n",[720,1370,1371],{},"{{...}}",[766,1373,1375],{"className":788,"code":1374,"language":161,"meta":774,"style":774},"{\n  \"id\": \"create-pet\",\n  \"type\": \"request\",\n  \"request\": {\n    \"api\": \"petstore-api\",\n    \"resource\": \"Pet\",\n    \"operation\": \"create\",\n    \"overrides\": {\n      \"body\": { \"name\": \"{{petName}}\", \"status\": \"available\" }\n    }\n  }\n}\n",[720,1376,1377,1381,1391,1401,1407,1418,1429,1440,1447,1474,1480,1486],{"__ignoreMap":774},[793,1378,1379],{"class":795,"line":666},[793,1380,799],{"class":798},[793,1382,1383,1385,1387,1389],{"class":795,"line":802},[793,1384,1262],{"class":805},[793,1386,809],{"class":798},[793,1388,1267],{"class":826},[793,1390,815],{"class":798},[793,1392,1393,1395,1397,1399],{"class":795,"line":818},[793,1394,1274],{"class":805},[793,1396,809],{"class":798},[793,1398,1279],{"class":826},[793,1400,815],{"class":798},[793,1402,1403,1405],{"class":795,"line":832},[793,1404,1298],{"class":805},[793,1406,851],{"class":798},[793,1408,1409,1412,1414,1416],{"class":795,"line":845},[793,1410,1411],{"class":805},"    \"api\"",[793,1413,809],{"class":798},[793,1415,1308],{"class":826},[793,1417,815],{"class":798},[793,1419,1420,1423,1425,1427],{"class":795,"line":854},[793,1421,1422],{"class":805},"    \"resource\"",[793,1424,809],{"class":798},[793,1426,1318],{"class":826},[793,1428,815],{"class":798},[793,1430,1431,1434,1436,1438],{"class":795,"line":894},[793,1432,1433],{"class":805},"    \"operation\"",[793,1435,809],{"class":798},[793,1437,1328],{"class":826},[793,1439,815],{"class":798},[793,1441,1442,1445],{"class":795,"line":900},[793,1443,1444],{"class":805},"    \"overrides\"",[793,1446,851],{"class":798},[793,1448,1449,1452,1454,1457,1459,1462,1464,1467,1469,1472],{"class":795,"line":916},[793,1450,1451],{"class":805},"      \"body\"",[793,1453,860],{"class":798},[793,1455,1456],{"class":805},"\"name\"",[793,1458,809],{"class":798},[793,1460,1461],{"class":826},"\"{{petName}}\"",[793,1463,723],{"class":798},[793,1465,1466],{"class":805},"\"status\"",[793,1468,809],{"class":798},[793,1470,1471],{"class":826},"\"available\"",[793,1473,891],{"class":798},[793,1475,1477],{"class":795,"line":1476},10,[793,1478,1479],{"class":798},"    }\n",[793,1481,1483],{"class":795,"line":1482},11,[793,1484,1485],{"class":798},"  }\n",[793,1487,1489],{"class":795,"line":1488},12,[793,1490,919],{"class":798},[678,1492,1493,1494,809,1497,723,1500,723,1503,1506,1507,1509,1510,1512],{},"The response lands at ",[720,1495,1496],{},"create-pet.response",[720,1498,1499],{},".status",[720,1501,1502],{},".body",[720,1504,1505],{},".headers",". ",[720,1508,202],{}," is the API's\nslug; the set of ",[720,1511,202],{}," values across all request blocks is the set of APIs the workflow touches.",[1336,1514,1515],{"id":726},[720,1516,726],{},[678,1518,1519,1520,1523,1524,1527,1528,1531,1532,1506,1535,1537,1538,706],{},"List ",[720,1521,1522],{},"assertions","; the block fails if any one fails. Each is a ",[720,1525,1526],{},"source"," path, an ",[720,1529,1530],{},"operator",", and\n(for most operators) a ",[720,1533,1534],{},"value",[720,1536,1534],{}," may itself be a ",[720,1539,1540],{},"{{token}}",[766,1542,1544],{"className":788,"code":1543,"language":161,"meta":774,"style":774},"{\n  \"id\": \"created\",\n  \"type\": \"assert\",\n  \"assertions\": [\n    { \"source\": \"create-pet.response.status\", \"operator\": \"equals\", \"value\": 201 },\n    { \"source\": \"create-pet.response.body.id\", \"operator\": \"exists\" },\n    { \"source\": \"create-pet.response.body.name\", \"operator\": \"equals\", \"value\": \"{{petName}}\" }\n  ]\n}\n",[720,1545,1546,1550,1561,1572,1580,1615,1637,1666,1671],{"__ignoreMap":774},[793,1547,1548],{"class":795,"line":666},[793,1549,799],{"class":798},[793,1551,1552,1554,1556,1559],{"class":795,"line":802},[793,1553,1262],{"class":805},[793,1555,809],{"class":798},[793,1557,1558],{"class":826},"\"created\"",[793,1560,815],{"class":798},[793,1562,1563,1565,1567,1570],{"class":795,"line":818},[793,1564,1274],{"class":805},[793,1566,809],{"class":798},[793,1568,1569],{"class":826},"\"assert\"",[793,1571,815],{"class":798},[793,1573,1574,1577],{"class":795,"line":832},[793,1575,1576],{"class":805},"  \"assertions\"",[793,1578,1579],{"class":798},": [\n",[793,1581,1582,1585,1588,1590,1593,1595,1598,1600,1603,1605,1608,1610,1613],{"class":795,"line":845},[793,1583,1584],{"class":798},"    { ",[793,1586,1587],{"class":805},"\"source\"",[793,1589,809],{"class":798},[793,1591,1592],{"class":826},"\"create-pet.response.status\"",[793,1594,723],{"class":798},[793,1596,1597],{"class":805},"\"operator\"",[793,1599,809],{"class":798},[793,1601,1602],{"class":826},"\"equals\"",[793,1604,723],{"class":798},[793,1606,1607],{"class":805},"\"value\"",[793,1609,809],{"class":798},[793,1611,1612],{"class":805},"201",[793,1614,1079],{"class":798},[793,1616,1617,1619,1621,1623,1626,1628,1630,1632,1635],{"class":795,"line":854},[793,1618,1584],{"class":798},[793,1620,1587],{"class":805},[793,1622,809],{"class":798},[793,1624,1625],{"class":826},"\"create-pet.response.body.id\"",[793,1627,723],{"class":798},[793,1629,1597],{"class":805},[793,1631,809],{"class":798},[793,1633,1634],{"class":826},"\"exists\"",[793,1636,1079],{"class":798},[793,1638,1639,1641,1643,1645,1648,1650,1652,1654,1656,1658,1660,1662,1664],{"class":795,"line":894},[793,1640,1584],{"class":798},[793,1642,1587],{"class":805},[793,1644,809],{"class":798},[793,1646,1647],{"class":826},"\"create-pet.response.body.name\"",[793,1649,723],{"class":798},[793,1651,1597],{"class":805},[793,1653,809],{"class":798},[793,1655,1602],{"class":826},[793,1657,723],{"class":798},[793,1659,1607],{"class":805},[793,1661,809],{"class":798},[793,1663,1461],{"class":826},[793,1665,891],{"class":798},[793,1667,1668],{"class":795,"line":900},[793,1669,1670],{"class":798},"  ]\n",[793,1672,1673],{"class":795,"line":916},[793,1674,919],{"class":798},[678,1676,1677],{},"Operators:",[921,1679,1680,1690],{},[924,1681,1682],{},[927,1683,1684,1687],{},[930,1685,1686],{},"Operator",[930,1688,1689],{},"Passes when",[937,1691,1692,1706,1730,1754,1767],{},[927,1693,1694,1703],{},[942,1695,1696,1699,1700],{},[720,1697,1698],{},"equals"," \u002F ",[720,1701,1702],{},"notEquals",[942,1704,1705],{},"Deep-equal (arrays\u002Fobjects too).",[927,1707,1708,1716],{},[942,1709,1710,1699,1713],{},[720,1711,1712],{},"exists",[720,1714,1715],{},"notExists",[942,1717,1718,1719,1722,1723,1726,1727,706],{},"The source ",[682,1720,1721],{},"path"," resolves \u002F doesn't. A key present but ",[720,1724,1725],{},"null"," still ",[1728,1729,1712],"em",{},[927,1731,1732,1740],{},[942,1733,1734,1699,1737],{},[720,1735,1736],{},"hasValue",[720,1738,1739],{},"hasNoValue",[942,1741,1742,1743,1746,1747,1749,1750,1753],{},"The path resolves ",[682,1744,1745],{},"and"," the value isn't ",[720,1748,1725],{},"\u002F",[720,1751,1752],{},"undefined"," \u002F it doesn't.",[927,1755,1756,1764],{},[942,1757,1758,1699,1761],{},[720,1759,1760],{},"greaterThan",[720,1762,1763],{},"lessThan",[942,1765,1766],{},"Both sides are numbers and the comparison holds.",[927,1768,1769,1774],{},[942,1770,1771],{},[720,1772,1773],{},"contains",[942,1775,1776,1778,1779,1781,1782,1784],{},[720,1777,1526],{}," is a string containing ",[720,1780,1534],{},", or an array with ",[720,1783,1534],{}," as a member.",[711,1786,1787],{},[678,1788,1789,1791,1792,723,1795,1791,1797,1800,1801,723,1803,1805,1806,1808],{},[720,1790,1712],{}," asks ",[1728,1793,1794],{},"is the field there?",[720,1796,1736],{},[1728,1798,1799],{},"is it there and filled in?"," For a nullable\nfield an API returns as ",[720,1802,1725],{},[720,1804,1712],{}," passes and ",[720,1807,1736],{}," fails. Pick the one that matches\nwhat you mean.",[678,1810,1811,1812,1814,1815,1123,1817,706],{},"For a check the operators can't express, use an assert ",[682,1813,740],{}," instead of ",[720,1816,1522],{},[694,1818,745],{"href":744},[1336,1820,1821],{"id":729},[720,1822,729],{},[678,1824,1825,1826,706],{},"Give earlier data a short name for later blocks. Each entry is ",[720,1827,1828],{},"outputName: sourcePath",[766,1830,1832],{"className":788,"code":1831,"language":161,"meta":774,"style":774},"{\n  \"id\": \"extract\",\n  \"type\": \"transform\",\n  \"transforms\": { \"petId\": \"create-pet.response.body.id\" }\n}\n",[720,1833,1834,1838,1849,1860,1876],{"__ignoreMap":774},[793,1835,1836],{"class":795,"line":666},[793,1837,799],{"class":798},[793,1839,1840,1842,1844,1847],{"class":795,"line":802},[793,1841,1262],{"class":805},[793,1843,809],{"class":798},[793,1845,1846],{"class":826},"\"extract\"",[793,1848,815],{"class":798},[793,1850,1851,1853,1855,1858],{"class":795,"line":818},[793,1852,1274],{"class":805},[793,1854,809],{"class":798},[793,1856,1857],{"class":826},"\"transform\"",[793,1859,815],{"class":798},[793,1861,1862,1865,1867,1870,1872,1874],{"class":795,"line":832},[793,1863,1864],{"class":805},"  \"transforms\"",[793,1866,860],{"class":798},[793,1868,1869],{"class":805},"\"petId\"",[793,1871,809],{"class":798},[793,1873,1625],{"class":826},[793,1875,891],{"class":798},[793,1877,1878],{"class":795,"line":845},[793,1879,919],{"class":798},[678,1881,1882,1883,1886],{},"Now ",[720,1884,1885],{},"{{extract.petId}}"," resolves to that id anywhere downstream.",[1336,1888,1889],{"id":732},[720,1890,732],{},[678,1892,1893,1894,1897,1898,1900,1901,1903,1904,706],{},"An ",[720,1895,1896],{},"if"," check picks the branch: ",[720,1899,1194],{}," runs when it passes, ",[720,1902,1198],{}," (optional) when it doesn't.\nBlocks in the branch not taken are marked ",[682,1905,1906],{},"skipped",[766,1908,1910],{"className":788,"code":1909,"language":161,"meta":774,"style":774},"{\n  \"id\": \"check-persisted\",\n  \"type\": \"condition\",\n  \"if\": { \"source\": \"get-pet.response.status\", \"operator\": \"equals\", \"value\": 200 },\n  \"then\": [\n    { \"id\": \"assert-name\", \"type\": \"assert\",\n      \"assertions\": [{ \"source\": \"get-pet.response.body.name\", \"operator\": \"equals\", \"value\": \"{{petName}}\" }] }\n  ],\n  \"else\": [\n    { \"id\": \"assert-gone\", \"type\": \"assert\",\n      \"assertions\": [{ \"source\": \"get-pet.response.status\", \"operator\": \"equals\", \"value\": 404 }] }\n  ]\n}\n",[720,1911,1912,1916,1927,1938,1971,1978,2000,2034,2039,2046,2067,2098,2102],{"__ignoreMap":774},[793,1913,1914],{"class":795,"line":666},[793,1915,799],{"class":798},[793,1917,1918,1920,1922,1925],{"class":795,"line":802},[793,1919,1262],{"class":805},[793,1921,809],{"class":798},[793,1923,1924],{"class":826},"\"check-persisted\"",[793,1926,815],{"class":798},[793,1928,1929,1931,1933,1936],{"class":795,"line":818},[793,1930,1274],{"class":805},[793,1932,809],{"class":798},[793,1934,1935],{"class":826},"\"condition\"",[793,1937,815],{"class":798},[793,1939,1940,1943,1945,1947,1949,1952,1954,1956,1958,1960,1962,1964,1966,1969],{"class":795,"line":832},[793,1941,1942],{"class":805},"  \"if\"",[793,1944,860],{"class":798},[793,1946,1587],{"class":805},[793,1948,809],{"class":798},[793,1950,1951],{"class":826},"\"get-pet.response.status\"",[793,1953,723],{"class":798},[793,1955,1597],{"class":805},[793,1957,809],{"class":798},[793,1959,1602],{"class":826},[793,1961,723],{"class":798},[793,1963,1607],{"class":805},[793,1965,809],{"class":798},[793,1967,1968],{"class":805},"200",[793,1970,1079],{"class":798},[793,1972,1973,1976],{"class":795,"line":845},[793,1974,1975],{"class":805},"  \"then\"",[793,1977,1579],{"class":798},[793,1979,1980,1982,1985,1987,1990,1992,1994,1996,1998],{"class":795,"line":854},[793,1981,1584],{"class":798},[793,1983,1984],{"class":805},"\"id\"",[793,1986,809],{"class":798},[793,1988,1989],{"class":826},"\"assert-name\"",[793,1991,723],{"class":798},[793,1993,863],{"class":805},[793,1995,809],{"class":798},[793,1997,1569],{"class":826},[793,1999,815],{"class":798},[793,2001,2002,2005,2008,2010,2012,2015,2017,2019,2021,2023,2025,2027,2029,2031],{"class":795,"line":894},[793,2003,2004],{"class":805},"      \"assertions\"",[793,2006,2007],{"class":798},": [{ ",[793,2009,1587],{"class":805},[793,2011,809],{"class":798},[793,2013,2014],{"class":826},"\"get-pet.response.body.name\"",[793,2016,723],{"class":798},[793,2018,1597],{"class":805},[793,2020,809],{"class":798},[793,2022,1602],{"class":826},[793,2024,723],{"class":798},[793,2026,1607],{"class":805},[793,2028,809],{"class":798},[793,2030,1461],{"class":826},[793,2032,2033],{"class":798}," }] }\n",[793,2035,2036],{"class":795,"line":900},[793,2037,2038],{"class":798},"  ],\n",[793,2040,2041,2044],{"class":795,"line":916},[793,2042,2043],{"class":805},"  \"else\"",[793,2045,1579],{"class":798},[793,2047,2048,2050,2052,2054,2057,2059,2061,2063,2065],{"class":795,"line":1476},[793,2049,1584],{"class":798},[793,2051,1984],{"class":805},[793,2053,809],{"class":798},[793,2055,2056],{"class":826},"\"assert-gone\"",[793,2058,723],{"class":798},[793,2060,863],{"class":805},[793,2062,809],{"class":798},[793,2064,1569],{"class":826},[793,2066,815],{"class":798},[793,2068,2069,2071,2073,2075,2077,2079,2081,2083,2085,2087,2089,2091,2093,2096],{"class":795,"line":1482},[793,2070,2004],{"class":805},[793,2072,2007],{"class":798},[793,2074,1587],{"class":805},[793,2076,809],{"class":798},[793,2078,1951],{"class":826},[793,2080,723],{"class":798},[793,2082,1597],{"class":805},[793,2084,809],{"class":798},[793,2086,1602],{"class":826},[793,2088,723],{"class":798},[793,2090,1607],{"class":805},[793,2092,809],{"class":798},[793,2094,2095],{"class":805},"404",[793,2097,2033],{"class":798},[793,2099,2100],{"class":795,"line":1488},[793,2101,1670],{"class":798},[793,2103,2105],{"class":795,"line":2104},13,[793,2106,919],{"class":798},[1336,2108,2109],{"id":736},[720,2110,736],{},[678,2112,2113],{},"Three modes:",[2115,2116,2117,2140,2150],"ul",{},[2118,2119,2120,2124,2125,2128,2129,2132,2133,2136,2137,706],"li",{},[682,2121,2122],{},[720,2123,1211],{},": repeat ",[720,2126,2127],{},"count"," times. The iterator (",[720,2130,2131],{},"iteratorVar",") is the index, ",[720,2134,2135],{},"0"," to ",[720,2138,2139],{},"count-1",[2118,2141,2142,2146,2147,2149],{},[682,2143,2144],{},[720,2145,1215],{},": walk an array at ",[720,2148,1526],{},". The iterator is each element.",[2118,2151,2152,2156,2157,2159,2160,2162,2163,2166,2167,2170,2171,2177],{},[682,2153,2154],{},[720,2155,1219],{},": repeat until a check passes (polling). Runs the body, then tests ",[720,2158,1219],{}," (an\nassertion) or a ",[720,2161,740],{},"; stops when it holds. ",[720,2164,2165],{},"delayMs"," waits between iterations, and\n",[720,2168,2169],{},"maxIterations"," caps them. ",[682,2172,2173,2174,2176],{},"If the check never passes within ",[720,2175,2169],{},", the loop\nfails",". The iterator is the 0-based attempt index.",[678,2179,2180,2183,2184,2187,2188,2191,2192,1749,2194,2196,2197,2200,2201,2204],{},[720,2181,2182],{},"execution"," is ",[720,2185,2186],{},"sequential"," (default) or ",[720,2189,2190],{},"parallel"," (",[720,2193,1211],{},[720,2195,1215],{}," only). Inside the loop,\n",[720,2198,2199],{},"{{iteratorVar}}"," also expands in nested block ",[682,2202,2203],{},"ids"," so each iteration's blocks stay uniquely\nnamed.",[766,2206,2208],{"className":788,"code":2207,"language":161,"meta":774,"style":774},"{\n  \"id\": \"check-each-pet\",\n  \"type\": \"loop\",\n  \"mode\": \"forEach\",\n  \"source\": \"list-pets.response.body\",\n  \"iteratorVar\": \"pet\",\n  \"execution\": \"parallel\",\n  \"blocks\": [\n    { \"id\": \"pet-available\", \"type\": \"assert\",\n      \"assertions\": [{ \"source\": \"pet.status\", \"operator\": \"equals\", \"value\": \"available\" }] }\n  ]\n}\n",[720,2209,2210,2214,2225,2236,2248,2260,2272,2284,2290,2311,2342,2346],{"__ignoreMap":774},[793,2211,2212],{"class":795,"line":666},[793,2213,799],{"class":798},[793,2215,2216,2218,2220,2223],{"class":795,"line":802},[793,2217,1262],{"class":805},[793,2219,809],{"class":798},[793,2221,2222],{"class":826},"\"check-each-pet\"",[793,2224,815],{"class":798},[793,2226,2227,2229,2231,2234],{"class":795,"line":818},[793,2228,1274],{"class":805},[793,2230,809],{"class":798},[793,2232,2233],{"class":826},"\"loop\"",[793,2235,815],{"class":798},[793,2237,2238,2241,2243,2246],{"class":795,"line":832},[793,2239,2240],{"class":805},"  \"mode\"",[793,2242,809],{"class":798},[793,2244,2245],{"class":826},"\"forEach\"",[793,2247,815],{"class":798},[793,2249,2250,2253,2255,2258],{"class":795,"line":845},[793,2251,2252],{"class":805},"  \"source\"",[793,2254,809],{"class":798},[793,2256,2257],{"class":826},"\"list-pets.response.body\"",[793,2259,815],{"class":798},[793,2261,2262,2265,2267,2270],{"class":795,"line":854},[793,2263,2264],{"class":805},"  \"iteratorVar\"",[793,2266,809],{"class":798},[793,2268,2269],{"class":826},"\"pet\"",[793,2271,815],{"class":798},[793,2273,2274,2277,2279,2282],{"class":795,"line":894},[793,2275,2276],{"class":805},"  \"execution\"",[793,2278,809],{"class":798},[793,2280,2281],{"class":826},"\"parallel\"",[793,2283,815],{"class":798},[793,2285,2286,2288],{"class":795,"line":900},[793,2287,903],{"class":805},[793,2289,1579],{"class":798},[793,2291,2292,2294,2296,2298,2301,2303,2305,2307,2309],{"class":795,"line":916},[793,2293,1584],{"class":798},[793,2295,1984],{"class":805},[793,2297,809],{"class":798},[793,2299,2300],{"class":826},"\"pet-available\"",[793,2302,723],{"class":798},[793,2304,863],{"class":805},[793,2306,809],{"class":798},[793,2308,1569],{"class":826},[793,2310,815],{"class":798},[793,2312,2313,2315,2317,2319,2321,2324,2326,2328,2330,2332,2334,2336,2338,2340],{"class":795,"line":1476},[793,2314,2004],{"class":805},[793,2316,2007],{"class":798},[793,2318,1587],{"class":805},[793,2320,809],{"class":798},[793,2322,2323],{"class":826},"\"pet.status\"",[793,2325,723],{"class":798},[793,2327,1597],{"class":805},[793,2329,809],{"class":798},[793,2331,1602],{"class":826},[793,2333,723],{"class":798},[793,2335,1607],{"class":805},[793,2337,809],{"class":798},[793,2339,1471],{"class":826},[793,2341,2033],{"class":798},[793,2343,2344],{"class":795,"line":1482},[793,2345,1670],{"class":798},[793,2347,2348],{"class":795,"line":1488},[793,2349,919],{"class":798},[678,2351,2352,2353,2355],{},"Polling with ",[720,2354,1219],{},": re-fetch until the pet is processed, up to 10 tries, 1s apart:",[766,2357,2359],{"className":788,"code":2358,"language":161,"meta":774,"style":774},"{\n  \"id\": \"wait-processed\",\n  \"type\": \"loop\",\n  \"mode\": \"until\",\n  \"maxIterations\": 10,\n  \"delayMs\": 1000,\n  \"until\": { \"source\": \"poll.response.body.status\", \"operator\": \"equals\", \"value\": \"processed\" },\n  \"blocks\": [\n    { \"id\": \"poll\", \"type\": \"request\",\n      \"request\": { \"api\": \"petstore-api\", \"resource\": \"Pet\", \"operation\": \"get\",\n        \"overrides\": { \"params\": { \"path\": { \"pet-id\": \"{{extract.petId}}\" } } } } }\n  ]\n}\n",[720,2360,2361,2365,2376,2386,2397,2409,2421,2454,2460,2481,2513,2541,2545],{"__ignoreMap":774},[793,2362,2363],{"class":795,"line":666},[793,2364,799],{"class":798},[793,2366,2367,2369,2371,2374],{"class":795,"line":802},[793,2368,1262],{"class":805},[793,2370,809],{"class":798},[793,2372,2373],{"class":826},"\"wait-processed\"",[793,2375,815],{"class":798},[793,2377,2378,2380,2382,2384],{"class":795,"line":818},[793,2379,1274],{"class":805},[793,2381,809],{"class":798},[793,2383,2233],{"class":826},[793,2385,815],{"class":798},[793,2387,2388,2390,2392,2395],{"class":795,"line":832},[793,2389,2240],{"class":805},[793,2391,809],{"class":798},[793,2393,2394],{"class":826},"\"until\"",[793,2396,815],{"class":798},[793,2398,2399,2402,2404,2407],{"class":795,"line":845},[793,2400,2401],{"class":805},"  \"maxIterations\"",[793,2403,809],{"class":798},[793,2405,2406],{"class":805},"10",[793,2408,815],{"class":798},[793,2410,2411,2414,2416,2419],{"class":795,"line":854},[793,2412,2413],{"class":805},"  \"delayMs\"",[793,2415,809],{"class":798},[793,2417,2418],{"class":805},"1000",[793,2420,815],{"class":798},[793,2422,2423,2426,2428,2430,2432,2435,2437,2439,2441,2443,2445,2447,2449,2452],{"class":795,"line":894},[793,2424,2425],{"class":805},"  \"until\"",[793,2427,860],{"class":798},[793,2429,1587],{"class":805},[793,2431,809],{"class":798},[793,2433,2434],{"class":826},"\"poll.response.body.status\"",[793,2436,723],{"class":798},[793,2438,1597],{"class":805},[793,2440,809],{"class":798},[793,2442,1602],{"class":826},[793,2444,723],{"class":798},[793,2446,1607],{"class":805},[793,2448,809],{"class":798},[793,2450,2451],{"class":826},"\"processed\"",[793,2453,1079],{"class":798},[793,2455,2456,2458],{"class":795,"line":900},[793,2457,903],{"class":805},[793,2459,1579],{"class":798},[793,2461,2462,2464,2466,2468,2471,2473,2475,2477,2479],{"class":795,"line":916},[793,2463,1584],{"class":798},[793,2465,1984],{"class":805},[793,2467,809],{"class":798},[793,2469,2470],{"class":826},"\"poll\"",[793,2472,723],{"class":798},[793,2474,863],{"class":805},[793,2476,809],{"class":798},[793,2478,1279],{"class":826},[793,2480,815],{"class":798},[793,2482,2483,2486,2488,2490,2492,2494,2496,2498,2500,2502,2504,2506,2508,2511],{"class":795,"line":1476},[793,2484,2485],{"class":805},"      \"request\"",[793,2487,860],{"class":798},[793,2489,1303],{"class":805},[793,2491,809],{"class":798},[793,2493,1308],{"class":826},[793,2495,723],{"class":798},[793,2497,1313],{"class":805},[793,2499,809],{"class":798},[793,2501,1318],{"class":826},[793,2503,723],{"class":798},[793,2505,1323],{"class":805},[793,2507,809],{"class":798},[793,2509,2510],{"class":826},"\"get\"",[793,2512,815],{"class":798},[793,2514,2515,2518,2520,2523,2525,2528,2530,2533,2535,2538],{"class":795,"line":1482},[793,2516,2517],{"class":805},"        \"overrides\"",[793,2519,860],{"class":798},[793,2521,2522],{"class":805},"\"params\"",[793,2524,860],{"class":798},[793,2526,2527],{"class":805},"\"path\"",[793,2529,860],{"class":798},[793,2531,2532],{"class":805},"\"pet-id\"",[793,2534,809],{"class":798},[793,2536,2537],{"class":826},"\"{{extract.petId}}\"",[793,2539,2540],{"class":798}," } } } } }\n",[793,2542,2543],{"class":795,"line":1488},[793,2544,1670],{"class":798},[793,2546,2547],{"class":795,"line":2104},[793,2548,919],{"class":798},[1336,2550,2551],{"id":1227},[720,2552,1227],{},[678,2554,2555,2556,2558],{},"Bundles nested blocks under one label so a long workflow stays readable. Collapse it in the app,\ngive it a ",[720,2557,1247],{},", and the blocks inside run exactly as they would at the top level. It adds\nno behaviour of its own: no branching, no repetition, no scope of its own.",[766,2560,2562],{"className":788,"code":2561,"language":161,"meta":774,"style":774},"{\n  \"id\": \"setup\",\n  \"type\": \"group\",\n  \"description\": \"Create the fixtures the assertions below rely on.\",\n  \"blocks\": [\n    { \"id\": \"create-pet\", \"type\": \"request\",\n      \"request\": { \"api\": \"petstore-api\", \"resource\": \"Pet\", \"operation\": \"create\" } },\n    { \"id\": \"created\", \"type\": \"assert\",\n      \"assertions\": [{ \"source\": \"create-pet.response.status\", \"operator\": \"equals\", \"value\": 201 }] }\n  ]\n}\n",[720,2563,2564,2568,2579,2590,2601,2607,2627,2658,2678,2708,2712],{"__ignoreMap":774},[793,2565,2566],{"class":795,"line":666},[793,2567,799],{"class":798},[793,2569,2570,2572,2574,2577],{"class":795,"line":802},[793,2571,1262],{"class":805},[793,2573,809],{"class":798},[793,2575,2576],{"class":826},"\"setup\"",[793,2578,815],{"class":798},[793,2580,2581,2583,2585,2588],{"class":795,"line":818},[793,2582,1274],{"class":805},[793,2584,809],{"class":798},[793,2586,2587],{"class":826},"\"group\"",[793,2589,815],{"class":798},[793,2591,2592,2594,2596,2599],{"class":795,"line":832},[793,2593,1286],{"class":805},[793,2595,809],{"class":798},[793,2597,2598],{"class":826},"\"Create the fixtures the assertions below rely on.\"",[793,2600,815],{"class":798},[793,2602,2603,2605],{"class":795,"line":845},[793,2604,903],{"class":805},[793,2606,1579],{"class":798},[793,2608,2609,2611,2613,2615,2617,2619,2621,2623,2625],{"class":795,"line":854},[793,2610,1584],{"class":798},[793,2612,1984],{"class":805},[793,2614,809],{"class":798},[793,2616,1267],{"class":826},[793,2618,723],{"class":798},[793,2620,863],{"class":805},[793,2622,809],{"class":798},[793,2624,1279],{"class":826},[793,2626,815],{"class":798},[793,2628,2629,2631,2633,2635,2637,2639,2641,2643,2645,2647,2649,2651,2653,2655],{"class":795,"line":894},[793,2630,2485],{"class":805},[793,2632,860],{"class":798},[793,2634,1303],{"class":805},[793,2636,809],{"class":798},[793,2638,1308],{"class":826},[793,2640,723],{"class":798},[793,2642,1313],{"class":805},[793,2644,809],{"class":798},[793,2646,1318],{"class":826},[793,2648,723],{"class":798},[793,2650,1323],{"class":805},[793,2652,809],{"class":798},[793,2654,1328],{"class":826},[793,2656,2657],{"class":798}," } },\n",[793,2659,2660,2662,2664,2666,2668,2670,2672,2674,2676],{"class":795,"line":900},[793,2661,1584],{"class":798},[793,2663,1984],{"class":805},[793,2665,809],{"class":798},[793,2667,1558],{"class":826},[793,2669,723],{"class":798},[793,2671,863],{"class":805},[793,2673,809],{"class":798},[793,2675,1569],{"class":826},[793,2677,815],{"class":798},[793,2679,2680,2682,2684,2686,2688,2690,2692,2694,2696,2698,2700,2702,2704,2706],{"class":795,"line":916},[793,2681,2004],{"class":805},[793,2683,2007],{"class":798},[793,2685,1587],{"class":805},[793,2687,809],{"class":798},[793,2689,1592],{"class":826},[793,2691,723],{"class":798},[793,2693,1597],{"class":805},[793,2695,809],{"class":798},[793,2697,1602],{"class":826},[793,2699,723],{"class":798},[793,2701,1607],{"class":805},[793,2703,809],{"class":798},[793,2705,1612],{"class":805},[793,2707,2033],{"class":798},[793,2709,2710],{"class":795,"line":1476},[793,2711,1670],{"class":798},[793,2713,2714],{"class":795,"line":1482},[793,2715,919],{"class":798},[678,2717,2718,2719,2721],{},"Block ids stay global: ",[720,2720,1496],{}," is reachable from outside the group, exactly as if\nthe group weren't there.",[1336,2723,2724],{"id":740},[720,2725,740],{},[678,2727,2728],{},"A free-form TypeScript block for the rare step no other block covers, most commonly a pause\nbetween requests:",[766,2730,2732],{"className":788,"code":2731,"language":161,"meta":774,"style":774},"{ \"id\": \"wait\", \"type\": \"script\", \"script\": { \"name\": \"wait-2s\", \"exportName\": \"run\" } }\n",[720,2733,2734],{"__ignoreMap":774},[793,2735,2736,2739,2741,2743,2746,2748,2750,2752,2755,2757,2759,2761,2763,2765,2768,2770,2773,2775,2778],{"class":795,"line":666},[793,2737,2738],{"class":798},"{ ",[793,2740,1984],{"class":805},[793,2742,809],{"class":798},[793,2744,2745],{"class":826},"\"wait\"",[793,2747,723],{"class":798},[793,2749,863],{"class":805},[793,2751,809],{"class":798},[793,2753,2754],{"class":826},"\"script\"",[793,2756,723],{"class":798},[793,2758,2754],{"class":805},[793,2760,860],{"class":798},[793,2762,1456],{"class":805},[793,2764,809],{"class":798},[793,2766,2767],{"class":826},"\"wait-2s\"",[793,2769,723],{"class":798},[793,2771,2772],{"class":805},"\"exportName\"",[793,2774,809],{"class":798},[793,2776,2777],{"class":826},"\"run\"",[793,2779,2780],{"class":798}," } }\n",[766,2782,2786],{"className":2783,"code":2784,"language":2785,"meta":774,"style":774},"language-ts shiki shiki-themes github-light github-dark","\u002F\u002F apis\u002Fworkflow\u002Fscripts\u002Fpet-lifecycle\u002Fwait-2s.ts\nimport type { ScriptContext } from '@apicrafthq\u002Fscript-sdk';\n\nexport const run = async (ctx: ScriptContext) => {\n  await ctx.sleep(2000);\n};\n","ts",[720,2787,2788,2794,2814,2819,2858,2878],{"__ignoreMap":774},[793,2789,2790],{"class":795,"line":666},[793,2791,2793],{"class":2792},"sJ8bj","\u002F\u002F apis\u002Fworkflow\u002Fscripts\u002Fpet-lifecycle\u002Fwait-2s.ts\n",[793,2795,2796,2799,2802,2805,2808,2811],{"class":795,"line":802},[793,2797,282],{"class":2798},"szBVR",[793,2800,2801],{"class":2798}," type",[793,2803,2804],{"class":798}," { ScriptContext } ",[793,2806,2807],{"class":2798},"from",[793,2809,2810],{"class":826}," '@apicrafthq\u002Fscript-sdk'",[793,2812,2813],{"class":798},";\n",[793,2815,2816],{"class":795,"line":818},[793,2817,2818],{"emptyLinePlaceholder":219},"\n",[793,2820,2821,2824,2827,2831,2834,2837,2839,2843,2846,2849,2852,2855],{"class":795,"line":832},[793,2822,2823],{"class":2798},"export",[793,2825,2826],{"class":2798}," const",[793,2828,2830],{"class":2829},"sScJk"," run",[793,2832,2833],{"class":2798}," =",[793,2835,2836],{"class":2798}," async",[793,2838,2191],{"class":798},[793,2840,2842],{"class":2841},"s4XuR","ctx",[793,2844,2845],{"class":2798},":",[793,2847,2848],{"class":2829}," ScriptContext",[793,2850,2851],{"class":798},") ",[793,2853,2854],{"class":2798},"=>",[793,2856,2857],{"class":798}," {\n",[793,2859,2860,2863,2866,2869,2872,2875],{"class":795,"line":845},[793,2861,2862],{"class":2798},"  await",[793,2864,2865],{"class":798}," ctx.",[793,2867,2868],{"class":2829},"sleep",[793,2870,2871],{"class":798},"(",[793,2873,2874],{"class":805},"2000",[793,2876,2877],{"class":798},");\n",[793,2879,2880],{"class":795,"line":854},[793,2881,2882],{"class":798},"};\n",[678,2884,2885,2887],{},[720,2886,740],{}," blocks exist for flexibility. If a native block can do the job, use it instead.",[747,2889,1127],{"id":2890},"referencing-data",[678,2892,2893],{},"Two ways to reach an earlier value, both using the same dot-path:",[2115,2895,2896,2920],{},[2118,2897,2898,2902,2903,723,2905,723,2908,723,2910,2913,2914,723,2917,706],{},[682,2899,2900],{},[720,2901,1526],{}," fields (in ",[720,2904,726],{},[720,2906,2907],{},"condition.if",[720,2909,729],{},[720,2911,2912],{},"loop.source",") take a raw path:\n",[720,2915,2916],{},"create-pet.response.body.id",[720,2918,2919],{},"list-pets.response.body.0.name",[2118,2921,2922,2926,2927,2929],{},[682,2923,2924],{},[720,2925,1540],{}," interpolation works inside any string value: overrides, assertion ",[720,2928,1534],{},"s,\nnested block ids.",[678,2931,2932,2933,2936,2937,2940,2941,2944,2945,2947,2948,2950],{},"A path's first segment is either a ",[682,2934,2935],{},"block id"," (its result) or an in-scope ",[682,2938,2939],{},"name",": a workflow\n",[720,2942,2943],{},"input",", a loop ",[720,2946,2131],{},", or a ",[720,2949,729],{}," output. The rest walks objects by key and arrays\nby numeric index.",[766,2952,2955],{"className":2953,"code":2954,"language":771},[769],"create-pet.response.body.id     # a block result\n{{petName}}                     # an input\npet.status                      # a loop iterator element\n{{extract.petId}}               # a transform output\n",[720,2956,2954],{"__ignoreMap":774},[678,2958,2959,2960,2963,2964,2967,2968,2971,2972,2191,2975,2978],{},"Inputs, block results, and transform outputs are ",[682,2961,2962],{},"global to the run",": they cross API\nboundaries freely, so a value from an ",[720,2965,2966],{},"admin","-API request feeds a later ",[720,2969,2970],{},"catalog","-API request.\nOnly the ",[682,2973,2974],{},"environment layer",[720,2976,2977],{},"baseUrl",", secrets, env values) resolves per the block's own API;\nsee below.",[747,2980,745],{"id":2981},"scripts",[678,2983,2984,2985,723,2987,815,2989,2991,2992,2994,2995,2998,2999,706],{},"When a block needs real logic, it runs a TypeScript function you write. ",[720,2986,726],{},[720,2988,732],{},[720,2990,729],{},", and ",[720,2993,740],{}," blocks can all point at one via ",[720,2996,2997],{},"\"script\": { \"name\": ..., \"exportName\": ... }",".\nFiles live in ",[720,3000,3001],{},"apis\u002Fworkflow\u002Fscripts\u002F\u003Cworkflow-name>\u002F",[678,3003,3004,3005,2845],{},"The function receives a context typed per block kind, all from\n",[694,3006,3008],{"href":3007},"\u002Fdocs\u002Fguides\u002Fauth-and-middlewares#the-script-sdk",[720,3009,3010],{},"@apicrafthq\u002Fscript-sdk",[921,3012,3013,3023],{},[924,3014,3015],{},[927,3016,3017,3020],{},[930,3018,3019],{},"Member",[930,3021,3022],{},"Purpose",[937,3024,3025,3039,3049,3059,3084],{},[927,3026,3027,3032],{},[942,3028,3029],{},[720,3030,3031],{},"ctx.blockResult(id)",[942,3033,3034,3035,3038],{},"Read an earlier block's result: ",[720,3036,3037],{},".response"," for request blocks, named keys for transforms.",[927,3040,3041,3046],{},[942,3042,3043],{},[720,3044,3045],{},"ctx.var(name)",[942,3047,3048],{},"Read an environment variable, typed from your schema.",[927,3050,3051,3056],{},[942,3052,3053],{},[720,3054,3055],{},"ctx.http",[942,3057,3058],{},"HTTP client for auxiliary calls.",[927,3060,3061,3066],{},[942,3062,3063],{},[720,3064,3065],{},"ctx.logger",[942,3067,3068,1749,3071,1749,3074,1749,3077,1506,3080,3083],{},[720,3069,3070],{},"debug",[720,3072,3073],{},"info",[720,3075,3076],{},"warn",[720,3078,3079],{},"error",[720,3081,3082],{},"console"," is not allowed.",[927,3085,3086,3091],{},[942,3087,3088],{},[720,3089,3090],{},"ctx.sleep(ms)",[942,3092,3093,3095],{},[720,3094,740],{}," blocks only. Non-blocking pause.",[678,3097,3098],{},"Each block kind expects a specific shape:",[2115,3100,3101,3115,3132,3145],{},[2118,3102,3103,2191,3107,3110,3111,3114],{},[682,3104,3105],{},[720,3106,726],{},[720,3108,3109],{},"AssertContext","): ",[682,3112,3113],{},"throw to fail",", return normally to pass.",[2118,3116,3117,2191,3121,3110,3124,3127,3128,1749,3130,706],{},[682,3118,3119],{},[720,3120,732],{},[720,3122,3123],{},"ConditionContext",[682,3125,3126],{},"return a boolean"," to pick ",[720,3129,1194],{},[720,3131,1198],{},[2118,3133,3134,2191,3138,3110,3141,3144],{},[682,3135,3136],{},[720,3137,729],{},[720,3139,3140],{},"TransformContext",[682,3142,3143],{},"return an object","; its keys become the block's outputs.",[2118,3146,3147,2191,3151,3154],{},[682,3148,3149],{},[720,3150,740],{},[720,3152,3153],{},"ScriptContext","): side effects only; return value is ignored.",[1336,3156,3158],{"id":3157},"assertions-in-scripts","Assertions in scripts",[678,3160,3161,3162,3165],{},"API Craft ships ",[682,3163,3164],{},"no assertion library",": an assert script fails by throwing, and you choose how:",[766,3167,3169],{"className":2783,"code":3168,"language":2785,"meta":774,"style":774},"\u002F\u002F apis\u002Fworkflow\u002Fscripts\u002Fpet-lifecycle\u002Fassert-missing.ts\nimport type { AssertContext } from '@apicrafthq\u002Fscript-sdk';\n\n\u002F\u002F 1. A plain throw\nexport const run = (ctx: AssertContext) => {\n  if (ctx.blockResult('get-missing-pet').response?.status !== 404) {\n    throw new Error('expected 404');\n  }\n};\n",[720,3170,3171,3176,3191,3195,3200,3225,3253,3271,3275],{"__ignoreMap":774},[793,3172,3173],{"class":795,"line":666},[793,3174,3175],{"class":2792},"\u002F\u002F apis\u002Fworkflow\u002Fscripts\u002Fpet-lifecycle\u002Fassert-missing.ts\n",[793,3177,3178,3180,3182,3185,3187,3189],{"class":795,"line":802},[793,3179,282],{"class":2798},[793,3181,2801],{"class":2798},[793,3183,3184],{"class":798}," { AssertContext } ",[793,3186,2807],{"class":2798},[793,3188,2810],{"class":826},[793,3190,2813],{"class":798},[793,3192,3193],{"class":795,"line":818},[793,3194,2818],{"emptyLinePlaceholder":219},[793,3196,3197],{"class":795,"line":832},[793,3198,3199],{"class":2792},"\u002F\u002F 1. A plain throw\n",[793,3201,3202,3204,3206,3208,3210,3212,3214,3216,3219,3221,3223],{"class":795,"line":845},[793,3203,2823],{"class":2798},[793,3205,2826],{"class":2798},[793,3207,2830],{"class":2829},[793,3209,2833],{"class":2798},[793,3211,2191],{"class":798},[793,3213,2842],{"class":2841},[793,3215,2845],{"class":2798},[793,3217,3218],{"class":2829}," AssertContext",[793,3220,2851],{"class":798},[793,3222,2854],{"class":2798},[793,3224,2857],{"class":798},[793,3226,3227,3230,3233,3236,3238,3241,3244,3247,3250],{"class":795,"line":854},[793,3228,3229],{"class":2798},"  if",[793,3231,3232],{"class":798}," (ctx.",[793,3234,3235],{"class":2829},"blockResult",[793,3237,2871],{"class":798},[793,3239,3240],{"class":826},"'get-missing-pet'",[793,3242,3243],{"class":798},").response?.status ",[793,3245,3246],{"class":2798},"!==",[793,3248,3249],{"class":805}," 404",[793,3251,3252],{"class":798},") {\n",[793,3254,3255,3258,3261,3264,3266,3269],{"class":795,"line":894},[793,3256,3257],{"class":2798},"    throw",[793,3259,3260],{"class":2798}," new",[793,3262,3263],{"class":2829}," Error",[793,3265,2871],{"class":798},[793,3267,3268],{"class":826},"'expected 404'",[793,3270,2877],{"class":798},[793,3272,3273],{"class":795,"line":900},[793,3274,1485],{"class":798},[793,3276,3277],{"class":795,"line":916},[793,3278,2882],{"class":798},[766,3280,3282],{"className":2783,"code":3281,"language":2785,"meta":774,"style":774},"\u002F\u002F 2. Node's built-in assert\nimport { strict as assert } from 'node:assert';\nimport type { AssertContext } from '@apicrafthq\u002Fscript-sdk';\n\nexport const run = (ctx: AssertContext) => {\n  assert.equal(ctx.blockResult('get-missing-pet').response?.status, 404);\n};\n",[720,3283,3284,3289,3309,3323,3327,3351,3375],{"__ignoreMap":774},[793,3285,3286],{"class":795,"line":666},[793,3287,3288],{"class":2792},"\u002F\u002F 2. Node's built-in assert\n",[793,3290,3291,3293,3296,3299,3302,3304,3307],{"class":795,"line":802},[793,3292,282],{"class":2798},[793,3294,3295],{"class":798}," { strict ",[793,3297,3298],{"class":2798},"as",[793,3300,3301],{"class":798}," assert } ",[793,3303,2807],{"class":2798},[793,3305,3306],{"class":826}," 'node:assert'",[793,3308,2813],{"class":798},[793,3310,3311,3313,3315,3317,3319,3321],{"class":795,"line":818},[793,3312,282],{"class":2798},[793,3314,2801],{"class":2798},[793,3316,3184],{"class":798},[793,3318,2807],{"class":2798},[793,3320,2810],{"class":826},[793,3322,2813],{"class":798},[793,3324,3325],{"class":795,"line":832},[793,3326,2818],{"emptyLinePlaceholder":219},[793,3328,3329,3331,3333,3335,3337,3339,3341,3343,3345,3347,3349],{"class":795,"line":845},[793,3330,2823],{"class":2798},[793,3332,2826],{"class":2798},[793,3334,2830],{"class":2829},[793,3336,2833],{"class":2798},[793,3338,2191],{"class":798},[793,3340,2842],{"class":2841},[793,3342,2845],{"class":2798},[793,3344,3218],{"class":2829},[793,3346,2851],{"class":798},[793,3348,2854],{"class":2798},[793,3350,2857],{"class":798},[793,3352,3353,3356,3359,3362,3364,3366,3368,3371,3373],{"class":795,"line":854},[793,3354,3355],{"class":798},"  assert.",[793,3357,3358],{"class":2829},"equal",[793,3360,3361],{"class":798},"(ctx.",[793,3363,3235],{"class":2829},[793,3365,2871],{"class":798},[793,3367,3240],{"class":826},[793,3369,3370],{"class":798},").response?.status, ",[793,3372,2095],{"class":805},[793,3374,2877],{"class":798},[793,3376,3377],{"class":795,"line":894},[793,3378,2882],{"class":798},[766,3380,3382],{"className":2783,"code":3381,"language":2785,"meta":774,"style":774},"\u002F\u002F 3. Your own library: add it as a dev dependency (e.g. chai)\nimport { expect } from 'chai';\nimport type { AssertContext } from '@apicrafthq\u002Fscript-sdk';\n\nexport const run = (ctx: AssertContext) => {\n  expect(ctx.blockResult('get-missing-pet').response?.status).to.equal(404);\n};\n",[720,3383,3384,3389,3403,3417,3421,3445,3469],{"__ignoreMap":774},[793,3385,3386],{"class":795,"line":666},[793,3387,3388],{"class":2792},"\u002F\u002F 3. Your own library: add it as a dev dependency (e.g. chai)\n",[793,3390,3391,3393,3396,3398,3401],{"class":795,"line":802},[793,3392,282],{"class":2798},[793,3394,3395],{"class":798}," { expect } ",[793,3397,2807],{"class":2798},[793,3399,3400],{"class":826}," 'chai'",[793,3402,2813],{"class":798},[793,3404,3405,3407,3409,3411,3413,3415],{"class":795,"line":818},[793,3406,282],{"class":2798},[793,3408,2801],{"class":2798},[793,3410,3184],{"class":798},[793,3412,2807],{"class":2798},[793,3414,2810],{"class":826},[793,3416,2813],{"class":798},[793,3418,3419],{"class":795,"line":832},[793,3420,2818],{"emptyLinePlaceholder":219},[793,3422,3423,3425,3427,3429,3431,3433,3435,3437,3439,3441,3443],{"class":795,"line":845},[793,3424,2823],{"class":2798},[793,3426,2826],{"class":2798},[793,3428,2830],{"class":2829},[793,3430,2833],{"class":2798},[793,3432,2191],{"class":798},[793,3434,2842],{"class":2841},[793,3436,2845],{"class":2798},[793,3438,3218],{"class":2829},[793,3440,2851],{"class":798},[793,3442,2854],{"class":2798},[793,3444,2857],{"class":798},[793,3446,3447,3450,3452,3454,3456,3458,3461,3463,3465,3467],{"class":795,"line":854},[793,3448,3449],{"class":2829},"  expect",[793,3451,3361],{"class":798},[793,3453,3235],{"class":2829},[793,3455,2871],{"class":798},[793,3457,3240],{"class":826},[793,3459,3460],{"class":798},").response?.status).to.",[793,3462,3358],{"class":2829},[793,3464,2871],{"class":798},[793,3466,2095],{"class":805},[793,3468,2877],{"class":798},[793,3470,3471],{"class":795,"line":894},[793,3472,2882],{"class":798},[678,3474,3475,3476,706],{},"Install a library the same way as the SDK, as a dev-only dependency your editor can resolve. See\n",[694,3477,3479],{"href":3478},"\u002Fdocs\u002Fguides\u002Fauth-and-middlewares#installing-the-types","Installing the types",[711,3481,3482],{},[678,3483,3484,3485,3488,3489,3492,3493,3496,3497,706],{},"Each script has a ",[682,3486,3487],{},"30-second timeout"," (override per block with ",[720,3490,3491],{},"timeoutMs","). A thrown error fails\nthe block. Scripts only run in a ",[682,3494,3495],{},"trusted project",", the same approval gate as\n",[694,3498,3499],{"href":191},"middlewares",[678,3501,3502,3503,1137,3506,3509,3510,3513],{},"When you create a script, API Craft generates a per-workflow ",[720,3504,3505],{},"tsconfig.json",[720,3507,3508],{},"blocks.d.ts","\nso ",[720,3511,3512],{},"ctx.blockResult('...')"," autocompletes your real block ids. Both are gitignored editor tooling.",[747,3515,705],{"id":3516},"multiple-apis-environments",[678,3518,3519,3520,3523],{},"Because a workflow can span APIs, there's no single \"the environment\" for a run. Instead the run\nsupplies an ",[682,3521,3522],{},"env binding per API",": every API the workflow touches gets its own environment:",[766,3525,3528],{"className":3526,"code":3527,"language":771},[769],"petstore-api → prod\ncatalog  → staging\n",[720,3529,3527],{"__ignoreMap":774},[678,3531,3532,3533,3536,3537,3540,3541,3543,3544,3547,3548,3551,3552,706],{},"This is deliberate: env names needn't match across APIs (",[720,3534,3535],{},"petstore-api"," may have ",[720,3538,3539],{},"prod"," while\n",[720,3542,2970],{}," has ",[720,3545,3546],{},"production","), so a single global env would be a fragile guess. Each block resolves\nits ",[720,3549,3550],{},"{{variables}}"," against the env bound to ",[682,3553,3554],{},"that block's API",[678,3556,3557],{},"Before a run starts, API Craft validates the binding: an API with no env fails fast rather than\nmid-run.",[766,3559,3562],{"className":3560,"code":3561,"language":771},[769],"WORKFLOW_MISSING_ENV_BINDING: no env provided for api \"catalog\"\n",[720,3563,3561],{"__ignoreMap":774},[747,3565,3567],{"id":3566},"running","Running",[1336,3569,3571],{"id":3570},"in-the-app","In the app",[678,3573,3574,3575,3578,3579,3582,3583,3585,3586,723,3589,3592,3593,3595],{},"The run panel shows ",[682,3576,3577],{},"one environment selector per API"," the workflow touches, all required\nbefore ",[682,3580,3581],{},"Run"," enables. Fill any ",[682,3584,1010],{},", then run. Each block reports ",[682,3587,3588],{},"passed",[682,3590,3591],{},"failed",",\nor ",[682,3594,1906],{},"; open a block to see its response and assertion details. The chosen binding is\nremembered for your session.",[3597,3598],"screenshot",{"alt":3599,"src":3600},"A workflow run showing per-API env selectors and per-block passed, failed, and skipped results","\u002Fimages\u002Fguides\u002Fworkflow-run.png",[1336,3602,3604],{"id":3603},"from-the-cli","From the CLI",[678,3606,3607,3610,3611,3614,3615,2191,3618,3620],{},[720,3608,3609],{},"craftr workflow run"," runs ",[682,3612,3613],{},"one or more"," workflows and aggregates the results, the same engine\nas the app, made for CI. Bind an environment per API with ",[720,3616,3617],{},"--env \u003Capi>=\u003Cenv>",[720,3619,446],{},"), once per\nAPI the run touches:",[766,3622,3626],{"className":3623,"code":3624,"language":3625,"meta":774,"style":774},"language-bash shiki shiki-themes github-light github-dark","# One workflow\ncraftr workflow run pet-lifecycle --env petstore-api=prod\n\n# A multi-API workflow: one --env per API it touches\ncraftr workflow run publish-and-verify -e petstore-api=prod -e catalog=staging\n","bash",[720,3627,3628,3633,3652,3656,3661],{"__ignoreMap":774},[793,3629,3630],{"class":795,"line":666},[793,3631,3632],{"class":2792},"# One workflow\n",[793,3634,3635,3638,3641,3643,3646,3649],{"class":795,"line":802},[793,3636,3637],{"class":2829},"craftr",[793,3639,3640],{"class":826}," workflow",[793,3642,2830],{"class":826},[793,3644,3645],{"class":826}," pet-lifecycle",[793,3647,3648],{"class":805}," --env",[793,3650,3651],{"class":826}," petstore-api=prod\n",[793,3653,3654],{"class":795,"line":818},[793,3655,2818],{"emptyLinePlaceholder":219},[793,3657,3658],{"class":795,"line":832},[793,3659,3660],{"class":2792},"# A multi-API workflow: one --env per API it touches\n",[793,3662,3663,3665,3667,3669,3672,3675,3678,3680],{"class":795,"line":845},[793,3664,3637],{"class":2829},[793,3666,3640],{"class":826},[793,3668,2830],{"class":826},[793,3670,3671],{"class":826}," publish-and-verify",[793,3673,3674],{"class":805}," -e",[793,3676,3677],{"class":826}," petstore-api=prod",[793,3679,3674],{"class":805},[793,3681,3682],{"class":826}," catalog=staging\n",[678,3684,3685,3686,3689,3690,3692,3693,3695,3696,3699],{},"Pass ",[682,3687,3688],{},"several names"," to run a batch, or ",[720,3691,546],{}," for every workflow in the project. The ",[720,3694,445],{},"\nbinding must cover the ",[682,3697,3698],{},"union"," of APIs across the whole batch:",[766,3701,3703],{"className":3623,"code":3702,"language":3625,"meta":774,"style":774},"craftr workflow run pet-lifecycle order-flow -e petstore-api=prod -e catalog=staging\ncraftr workflow run --all -e petstore-api=prod -e catalog=staging\n",[720,3704,3705,3726],{"__ignoreMap":774},[793,3706,3707,3709,3711,3713,3715,3718,3720,3722,3724],{"class":795,"line":666},[793,3708,3637],{"class":2829},[793,3710,3640],{"class":826},[793,3712,2830],{"class":826},[793,3714,3645],{"class":826},[793,3716,3717],{"class":826}," order-flow",[793,3719,3674],{"class":805},[793,3721,3677],{"class":826},[793,3723,3674],{"class":805},[793,3725,3682],{"class":826},[793,3727,3728,3730,3732,3734,3737,3739,3741,3743],{"class":795,"line":802},[793,3729,3637],{"class":2829},[793,3731,3640],{"class":826},[793,3733,2830],{"class":826},[793,3735,3736],{"class":805}," --all",[793,3738,3674],{"class":805},[793,3740,3677],{"class":826},[793,3742,3674],{"class":805},[793,3744,3682],{"class":826},[678,3746,3747,3748,3751,3752,3755,3756,3758,3759,3762],{},"By default the batch runs ",[682,3749,3750],{},"4 at a time","; set ",[720,3753,3754],{},"--concurrency 1"," to run sequentially. ",[720,3757,551],{},"\nfeeds workflow inputs. Prefix with ",[720,3760,3761],{},"\u003Cworkflow>:"," to target one, or leave it off to apply to\nevery workflow in the batch:",[766,3764,3766],{"className":3623,"code":3765,"language":3625,"meta":774,"style":774},"craftr workflow run pet-lifecycle order-flow \\\n  -e petstore-api=prod \\\n  --input petName=Rufus \\          # applies to both workflows\n  --input order-flow:qty=3 \\       # only order-flow\n  --concurrency 2 \\\n  --on-failure halt\n",[720,3767,3768,3783,3792,3806,3821,3831],{"__ignoreMap":774},[793,3769,3770,3772,3774,3776,3778,3780],{"class":795,"line":666},[793,3771,3637],{"class":2829},[793,3773,3640],{"class":826},[793,3775,2830],{"class":826},[793,3777,3645],{"class":826},[793,3779,3717],{"class":826},[793,3781,3782],{"class":805}," \\\n",[793,3784,3785,3788,3790],{"class":795,"line":802},[793,3786,3787],{"class":805},"  -e",[793,3789,3677],{"class":826},[793,3791,3782],{"class":805},[793,3793,3794,3797,3800,3803],{"class":795,"line":818},[793,3795,3796],{"class":805},"  --input",[793,3798,3799],{"class":826}," petName=Rufus",[793,3801,3802],{"class":805}," \\ ",[793,3804,3805],{"class":2792},"         # applies to both workflows\n",[793,3807,3808,3810,3813,3816,3818],{"class":795,"line":832},[793,3809,3796],{"class":2829},[793,3811,3812],{"class":826}," order-flow:qty=",[793,3814,3815],{"class":805},"3",[793,3817,3802],{"class":805},[793,3819,3820],{"class":2792},"      # only order-flow\n",[793,3822,3823,3826,3829],{"class":795,"line":845},[793,3824,3825],{"class":2829},"  --concurrency",[793,3827,3828],{"class":805}," 2",[793,3830,3782],{"class":805},[793,3832,3833,3836],{"class":795,"line":854},[793,3834,3835],{"class":805},"  --on-failure",[793,3837,3838],{"class":826}," halt\n",[921,3840,3841,3853],{},[924,3842,3843],{},[927,3844,3845,3848,3851],{},[930,3846,3847],{},"Flag",[930,3849,3850],{},"Default",[930,3852,935],{},[937,3854,3855,3870,3882,3898,3912,3929,3951,3962,3972],{},[927,3856,3857,3862,3865],{},[942,3858,3859],{},[1728,3860,3861],{},"(positional)",[942,3863,3864],{},"—",[942,3866,3867,3868,706],{},"Workflow name(s). Repeat to batch several. Omit with ",[720,3869,546],{},[927,3871,3872,3876,3879],{},[942,3873,3874],{},[720,3875,546],{},[942,3877,3878],{},"off",[942,3880,3881],{},"Run every workflow in the project. Mutually exclusive with names.",[927,3883,3884,3890,3892],{},[942,3885,3886,723,3888],{},[720,3887,445],{},[720,3889,446],{},[942,3891,3864],{},[942,3893,3894,3897],{},[720,3895,3896],{},"\u003Capi>=\u003Cenv>"," binding. Repeat, one per API the batch uses.",[927,3899,3900,3904,3906],{},[942,3901,3902],{},[720,3903,551],{},[942,3905,3864],{},[942,3907,3908,3911],{},[720,3909,3910],{},"[\u003Cworkflow>:]\u003Ckey>=\u003Cvalue>",". Repeat. Unprefixed applies to all.",[927,3913,3914,3918,3923],{},[942,3915,3916],{},[720,3917,554],{},[942,3919,3920],{},[720,3921,3922],{},"4",[942,3924,3925,3926,3928],{},"Workflows in flight at once. ",[720,3927,812],{}," = sequential.",[927,3930,3931,3935,3939],{},[942,3932,3933],{},[720,3934,557],{},[942,3936,3937],{},[720,3938,967],{},[942,3940,3941,3943,3944,3947,3948,3950],{},[720,3942,963],{}," stops ",[682,3945,3946],{},"starting"," more workflows after one fails; ",[720,3949,967],{}," runs them all.",[927,3952,3953,3957,3959],{},[942,3954,3955],{},[720,3956,562],{},[942,3958,3864],{},[942,3960,3961],{},"File to write the complete run result to (every block and response). Omitted, that detail is discarded.",[927,3963,3964,3968,3970],{},[942,3965,3966],{},[720,3967,459],{},[942,3969,3878],{},[942,3971,460],{},[927,3973,3974,3980,3982],{},[942,3975,3976,723,3978],{},[720,3977,462],{},[720,3979,463],{},[942,3981,3878],{},[942,3983,3984,3985,3987,3988,3991,3992,3995],{},"Progress\u002Ftraces to stderr: ",[720,3986,463],{}," workflow, ",[720,3989,3990],{},"-vv"," block logs, ",[720,3993,3994],{},"-vvv"," debug.",[711,3997,3998],{},[678,3999,4000,4001,4004,4005,718,4008,4010,4011,4014,4015,4017,4018,4022,4023,4026,4027,4029],{},"Two independent ",[720,4002,4003],{},"on-failure"," controls: the ",[682,4006,4007],{},"workflow file's",[720,4009,958],{}," governs blocks ",[1728,4012,4013],{},"inside","\none workflow (default ",[720,4016,963],{},"); the CLI's ",[682,4019,4020],{},[720,4021,557],{}," governs whether to keep launching\n",[1728,4024,4025],{},"other"," workflows in the batch (default ",[720,4028,967],{},").",[678,4031,4032,4035,4036,4039,4040,706],{},[682,4033,4034],{},"stdout"," gets a JSON ",[682,4037,4038],{},"summary report",": the batch status, counts, the env binding, and one\nentry per workflow with its failures, small enough to pipe and assert on. A human-readable\nsummary goes to ",[682,4041,4042],{},"stderr",[766,4044,4046],{"className":3623,"code":4045,"language":3625,"meta":774,"style":774},"craftr workflow run --all -e petstore-api=prod -e catalog=staging | jq '.status'\n",[720,4047,4048],{"__ignoreMap":774},[793,4049,4050,4052,4054,4056,4058,4060,4062,4064,4067,4070,4073],{"class":795,"line":666},[793,4051,3637],{"class":2829},[793,4053,3640],{"class":826},[793,4055,2830],{"class":826},[793,4057,3736],{"class":805},[793,4059,3674],{"class":805},[793,4061,3677],{"class":826},[793,4063,3674],{"class":805},[793,4065,4066],{"class":826}," catalog=staging",[793,4068,4069],{"class":2798}," |",[793,4071,4072],{"class":2829}," jq",[793,4074,4075],{"class":826}," '.status'\n",[678,4077,4078,4079,4082,4083,4085],{},"The per-block detail (every block, every response) is ",[682,4080,4081],{},"not"," on stdout: pass ",[720,4084,562],{}," to\nwrite it to a file, otherwise it's discarded.",[766,4087,4089],{"className":3623,"code":4088,"language":3625,"meta":774,"style":774},"craftr workflow run --all -e petstore-api=prod -e catalog=staging --full-output run.json\n",[720,4090,4091],{"__ignoreMap":774},[793,4092,4093,4095,4097,4099,4101,4103,4105,4107,4109,4112],{"class":795,"line":666},[793,4094,3637],{"class":2829},[793,4096,3640],{"class":826},[793,4098,2830],{"class":826},[793,4100,3736],{"class":805},[793,4102,3674],{"class":805},[793,4104,3677],{"class":826},[793,4106,3674],{"class":805},[793,4108,4066],{"class":826},[793,4110,4111],{"class":805}," --full-output",[793,4113,4114],{"class":826}," run.json\n",[678,4116,4117,4118,4122,4123,4127,4128,4133,4134,4136],{},"Exit codes: ",[682,4119,4120],{},[720,4121,2135],{}," all passed, ",[682,4124,4125],{},[720,4126,812],{}," at least one workflow failed (so CI goes red on its own),\nand ",[682,4129,4130],{},[720,4131,4132],{},"130"," if the run was cancelled (Ctrl+C). Before anything runs, the binding is validated: a\ntouched API with no ",[720,4135,445],{}," errors out up front.",[1336,4138,4140],{"id":4139},"scripts-and-trust","Scripts and trust",[678,4142,4143,4144,4147,4148,4150,4151,4153],{},"A workflow with scripts only runs in a ",[694,4145,4146],{"href":744},"trusted"," project. In CI there's no one to click\napprove, so either trust the project once (",[720,4149,185],{},", persisted in local state) or\npass ",[720,4152,459],{}," to allow scripts for that single invocation without saving anything.",[1336,4155,4157],{"id":4156},"the-other-workflow-commands","The other workflow commands",[678,4159,4160],{},"Running isn't all the CLI does. The rest of the namespace manages the workflow files themselves:",[766,4162,4164],{"className":3623,"code":4163,"language":3625,"meta":774,"style":774},"craftr workflow list                        # every workflow in the project\ncraftr workflow validate                    # check refs resolve; refresh script typings\ncraftr workflow validate pet-lifecycle      # ...or just these\ncraftr workflow history                     # past runs, newest first (--limit N)\ncraftr workflow history \u003Crun-id>            # read one run in full\ncraftr workflow rename old new              # scripts directory included\ncraftr workflow duplicate source new        # scripts directory included\ncraftr workflow delete pet-lifecycle        # workflow + its scripts directory\n",[720,4165,4166,4178,4190,4203,4215,4238,4255,4272],{"__ignoreMap":774},[793,4167,4168,4170,4172,4175],{"class":795,"line":666},[793,4169,3637],{"class":2829},[793,4171,3640],{"class":826},[793,4173,4174],{"class":826}," list",[793,4176,4177],{"class":2792},"                        # every workflow in the project\n",[793,4179,4180,4182,4184,4187],{"class":795,"line":802},[793,4181,3637],{"class":2829},[793,4183,3640],{"class":826},[793,4185,4186],{"class":826}," validate",[793,4188,4189],{"class":2792},"                    # check refs resolve; refresh script typings\n",[793,4191,4192,4194,4196,4198,4200],{"class":795,"line":818},[793,4193,3637],{"class":2829},[793,4195,3640],{"class":826},[793,4197,4186],{"class":826},[793,4199,3645],{"class":826},[793,4201,4202],{"class":2792},"      # ...or just these\n",[793,4204,4205,4207,4209,4212],{"class":795,"line":832},[793,4206,3637],{"class":2829},[793,4208,3640],{"class":826},[793,4210,4211],{"class":826}," history",[793,4213,4214],{"class":2792},"                     # past runs, newest first (--limit N)\n",[793,4216,4217,4219,4221,4223,4226,4229,4232,4235],{"class":795,"line":845},[793,4218,3637],{"class":2829},[793,4220,3640],{"class":826},[793,4222,4211],{"class":826},[793,4224,4225],{"class":2798}," \u003C",[793,4227,4228],{"class":826},"run-i",[793,4230,4231],{"class":798},"d",[793,4233,4234],{"class":2798},">",[793,4236,4237],{"class":2792},"            # read one run in full\n",[793,4239,4240,4242,4244,4247,4250,4252],{"class":795,"line":854},[793,4241,3637],{"class":2829},[793,4243,3640],{"class":826},[793,4245,4246],{"class":826}," rename",[793,4248,4249],{"class":826}," old",[793,4251,3260],{"class":826},[793,4253,4254],{"class":2792},"              # scripts directory included\n",[793,4256,4257,4259,4261,4264,4267,4269],{"class":795,"line":894},[793,4258,3637],{"class":2829},[793,4260,3640],{"class":826},[793,4262,4263],{"class":826}," duplicate",[793,4265,4266],{"class":826}," source",[793,4268,3260],{"class":826},[793,4270,4271],{"class":2792},"        # scripts directory included\n",[793,4273,4274,4276,4278,4281,4283],{"class":795,"line":900},[793,4275,3637],{"class":2829},[793,4277,3640],{"class":826},[793,4279,4280],{"class":826}," delete",[793,4282,3645],{"class":826},[793,4284,4285],{"class":2792},"        # workflow + its scripts directory\n",[678,4287,4288,4290],{},[720,4289,179],{}," is the useful one in CI ahead of a run: it catches a block pointing at an API,\noperation, or instance that no longer exists, without sending a single request.",[747,4292,988],{"id":4293},"contract-validation",[678,4295,4296,4297,4300,4301,4303],{},"Set ",[720,4298,4299],{},"validateContracts: true"," and every ",[720,4302,722],{}," block's response is validated against its\noperation's schema (status, body shape). A violation fails that block, a fast way to catch an\nAPI drifting from its spec inside an end-to-end test.",[747,4305,4307],{"id":4306},"failure-handling","Failure handling",[678,4309,4310,4312],{},[720,4311,958],{}," decides what happens after a block fails:",[2115,4314,4315,4322],{},[2118,4316,4317,4321],{},[682,4318,4319],{},[720,4320,963],{}," (default): stop immediately; remaining blocks are marked skipped.",[2118,4323,4324,4328,4329,4331],{},[682,4325,4326],{},[720,4327,967],{},": keep going; the run still ends ",[682,4330,3591],{},", but you see every block's result.",[678,4333,4334,4335,4337,4338,4340,4341,3950],{},"Inside a ",[720,4336,736],{},", the same rule applies per iteration: ",[720,4339,963],{}," stops the sequential loop at the\nfirst failed iteration; ",[720,4342,967],{},[747,4344,4346],{"id":4345},"next","Next",[678,4348,4349,4350,4352,4353,4356],{},"Run requests and workflows in a pipeline with ",[694,4351,69],{"href":70},", or revisit\n",[694,4354,4355],{"href":62},"auth & middlewares"," for the shared script SDK.",[4358,4359,4360],"style",{},"html pre.shiki code .sVt8B, html code.shiki .sVt8B{--shiki-default:#24292E;--shiki-dark:#E1E4E8}html pre.shiki code .sj4cs, html code.shiki .sj4cs{--shiki-default:#005CC5;--shiki-dark:#79B8FF}html pre.shiki code .sZZnC, html code.shiki .sZZnC{--shiki-default:#032F62;--shiki-dark:#9ECBFF}html pre.shiki code .s7hpK, html code.shiki .s7hpK{--shiki-default:#B31D28;--shiki-default-font-style:italic;--shiki-dark:#FDAEB7;--shiki-dark-font-style:italic}html .default .shiki span {color: var(--shiki-default);background: var(--shiki-default-bg);font-style: var(--shiki-default-font-style);font-weight: var(--shiki-default-font-weight);text-decoration: var(--shiki-default-text-decoration);}html .shiki span {color: var(--shiki-default);background: var(--shiki-default-bg);font-style: var(--shiki-default-font-style);font-weight: var(--shiki-default-font-weight);text-decoration: var(--shiki-default-text-decoration);}html .dark .shiki span {color: var(--shiki-dark);background: var(--shiki-dark-bg);font-style: var(--shiki-dark-font-style);font-weight: var(--shiki-dark-font-weight);text-decoration: var(--shiki-dark-text-decoration);}html.dark .shiki span {color: var(--shiki-dark);background: var(--shiki-dark-bg);font-style: var(--shiki-dark-font-style);font-weight: var(--shiki-dark-font-weight);text-decoration: var(--shiki-dark-text-decoration);}html pre.shiki code .sJ8bj, html code.shiki .sJ8bj{--shiki-default:#6A737D;--shiki-dark:#6A737D}html pre.shiki code .szBVR, html code.shiki .szBVR{--shiki-default:#D73A49;--shiki-dark:#F97583}html pre.shiki code .sScJk, html code.shiki .sScJk{--shiki-default:#6F42C1;--shiki-dark:#B392F0}html pre.shiki code .s4XuR, html code.shiki .s4XuR{--shiki-default:#E36209;--shiki-dark:#FFAB70}",{"title":774,"searchDepth":802,"depth":802,"links":4362},[4363,4364,4365,4366,4375,4376,4379,4380,4386,4387,4388],{"id":749,"depth":802,"text":750},{"id":784,"depth":802,"text":785},{"id":995,"depth":802,"text":1010},{"id":684,"depth":802,"text":1130,"children":4367},[4368,4369,4370,4371,4372,4373,4374],{"id":722,"depth":818,"text":722},{"id":726,"depth":818,"text":726},{"id":729,"depth":818,"text":729},{"id":732,"depth":818,"text":732},{"id":736,"depth":818,"text":736},{"id":1227,"depth":818,"text":1227},{"id":740,"depth":818,"text":740},{"id":2890,"depth":802,"text":1127},{"id":2981,"depth":802,"text":745,"children":4377},[4378],{"id":3157,"depth":818,"text":3158},{"id":3516,"depth":802,"text":705},{"id":3566,"depth":802,"text":3567,"children":4381},[4382,4383,4384,4385],{"id":3570,"depth":818,"text":3571},{"id":3603,"depth":818,"text":3604},{"id":4139,"depth":818,"text":4140},{"id":4156,"depth":818,"text":4157},{"id":4293,"depth":802,"text":988},{"id":4306,"depth":802,"text":4307},{"id":4345,"depth":802,"text":4346},"[object Object]","md",{},null,{"title":65,"description":4394},{"Chain requests across your APIs into a multi-step test":4395},"request, assert, transform, condition, loop, group, and script blocks.","A0to-qQgxUmlvc59F8d4R68jq7cyAvlBQNZqc2uhCjI",1789469406461]