writing-scripts
Write Celigo JavaScript hook scripts -- preSavePage, preMap, postMap, postSubmit, postResponseMap, filter, transform, branching, handleRequest. Use when creating or editing scripts, choosing the right hook point, understanding input/output data shapes, or debugging script behavior.
By celigo · 1,073 installs
npx skills add celigo/ai --skill writing-scripts
Source repository · Upstream listing
<! TIER:1
Writing Scripts
A script is a JavaScript function that runs at a specific hook point in the Celigo data pipeline. Scripts handle logic that expressions, filters, and visual mappings cannot complex conditionals, cross record calculations, API calls within the pipeline, and custom routing.
Concerns when writing a script:
Choosing the right hook point which function type matches what you're trying to accomplish
Input/output contracts what options contains and what the function must return (array length rules are strict)
Expression alternative filter, transform, and output filter have expression based alternatives that don't require a script; prefer expressions when possible
Available modules scripts can import three built in modules: integrator api (call Celigo APIs), dayjs (date/time manipulation), and sjcl (Stanford JavaScript Crypto Library for hashing/encryption)
One script, many functions a single script resource can contain multiple exported functions, each wired independently to different hook points
Used across flows, APIs, and tools.
Hook Points
Every script function runs at a specific point in the pipeline. Choose based on when you need to act and what data you need access to.
Data Pipeline Hooks
Hook Runs on When Input Must return
preSavePage Export After retrieval, before pipeline options.data[] , errors[] , files[] , retryData{} { data[], errors[], abort, newErrorsAndRetryData[] }
preMap Import Before field mapping options.data[] (unmapped records) Array matching data.length : { data } , { errors } , or {} to skip
postMap Import After field mapping, before submit options.preMapData[] , postMapData[] Array matching postMapData.length : { data } , { errors } , or {} to skip
postSubmit Import After destination submission options.preMapData[] , postMapData[] , responseData[] responseData[] (same length, modified)
postAggregate Import After file aggregation upload options.postAggregateData: { success, json, code, message } void
Record Level Processors (on export or import)
Hook When Input Must return
filter Per record, before processing options.record boolean (true = process)
input filter Per record on lookup exports options.record boolean (true = include)
transform Per record, reshaping before mapping options.record Transformed record
filter and transform have expression based alternatives. Only use a script when the logic is too complex for an expression (multi field conditionals, date math, external lookups).
Flow Level Hook
Hook Runs on When Input Must return
postResponseMap Page processor (flow/API/tool) After response mapping merges results options.postResponseMapData[] , responseData[] postResponseMapData[] (same length)
Configured on the flow's pageProcessors[] entry, not on the export/import. Plan this hook when building the resource, but wire it at the flow level.
Routing and Handlers
Hook Runs on When Input Must return
branching Router Per record routing decision options.record , settings number[] (branch indices, e.g., [0, 2] )
handleRequest API resource Incoming HTTP request (script mode API) options.method , headers , queryString , body , rawBody { statusCode, headers?, body }
contentBasedFlowRouter AS2 connection EDI message routing options.httpHeaders , mimeHeaders , rawMessageBody { flowId, exportId }
Quick Reference
Hook Point Decision Matrix
When you need to... Use hook Configured on Input / Output
Transform or filter a batch after retrieval preSavePage Export Receives pages of records, returns pages (with optional errors)
Filter individual records before processing filter Export or import Receives single record, returns boolean (true = keep)
Filter records entering a lookup export input filter Export (lookup) Receives single record, returns boolean (true = include)
Reshape records before mapping transform Export or import Receives single record, returns transformed record
Transform records before field mapping preMap Import Receives unmapped records array, returns array (same length)
Transform records after field mapping postMap Import Receives pre map + post map arrays, returns array (same length)
Process API responses after submission postSubmit Import Receives pre map, post map, and response arrays, returns response array
Handle results after file aggregation postAggregate Import (file) Receives aggregation result, returns void
Post response processing (merge lookup/import results) postResponseMap Flow pageProcessors[] entry Receives merged records + response data, returns merged records (same length)
Route records to branches branching Router in flow/tool Receives single record + settings, returns branch indices array
Handle incoming HTTP requests (script mode API) handleRequest API resource Receives method, headers, query, body; returns { statusCode, headers?, body }
Route EDI messages to flows contentBasedFlowRouter AS2 connection Receives HTTP/MIME headers + raw body, returns { flowId, exportId }
Minimum Required Fields
A script resource needs only two fields:
name descriptive name (convention: <System <step <hookType , e.g., "Salesforce getBatchRecords postResponseMap" )
content the JavaScript source code as a string
See [references/schemas/request.yml](references/schemas/request.yml) for the full create/update schema.
Related Skills
[configuring exports Quick Reference](../configuring exports/SKILL.md quick reference) export configuration, where preSavePage , filter , transform , and input filter hooks are wired
[configuring imports Quick Reference](../configuring imports/SKILL.md quick reference) import configuration, where preMap , postMap , postSubmit , and postAggregate hooks are wired
[building flows How to Build a Flow](../building flows/SKILL.md how to build a flow) flow construction, where postResponseMap and branching hooks are wired
[writing handlebars Quick Reference](../writing handlebars/SKILL.md quick reference) Handlebars expressions for dynamic values in scripts and hook configurations
<! TIER:2
Common Options Available to All Hooks
Most hooks receive these context fields in options :
flowId , integrationId , apiId , parentIntegrationId execution context IDs
exportId or importId the step's resource ID
connectionId the connection in use
settings custom settings in scope for the resource
testMode boolean, whether running in test/preview mode
job the current job object
Function Point Categories
Scripts run at twelve function points, grouped into four categories. The [Hook Points]( hook points) tables above give each one's input/output contract; this is the mental model for which kind of point you're wiring and whether a non script alternative exists.
Step level pipeline hooks (on the export or import) preSavePage , preMap , postMap , postSubmit , postAggregate
Parent level response hook (on the flow/API/tool pageProcessors[] entry, not the step) postResponseMap
Script mode replacements for declarative slots filter , input filter , transform , branching
Resource specific function points contentBasedFlowRouter (on an AS2 connection) and handleRequest (on a script mode API)
Script only points have no declarative equivalent: postSubmit , postResponseMap , postAggregate , contentBasedFlowRouter , and handleRequest . On those slots a script is the only option. The four script mode slots ( filter , input filter , transform , branching ) each hold either a declarative rule tree or a script never both so prefer the declarative path there unless the logic genuinely can't be expressed as rules (see [Declarative vs Script Mode]( declarative vs script mode)).
Declarative vs Script Mode
The four mode switchable slots filter , input filter , transform , and branching hold a declarative rule tree or a script reference at any one moment, not both. Because the slot's contents change, switching modes is a two part operation.
From script mode to declarative mode (the common direction prototype with a script, then clean up):
1. Clear the script from the slot. The slot reverts to declarative mode by default.
2. Author the declarative rule for that slot (rules engine filter, Mapper 2.0 transform, or router input filter rule).
From declarative mode to script mode (rarer the rules engine couldn't express what you need):
1. Wire a script into the slot. The declarative rules already there are replaced by the script reference automatically.
Wiring a script and clearing it are mirror operations on the same slot. Recognize the mode swap in phrasing like "switch the filter to rules" , "convert this transform back to expressions" , or "use a script for this filter instead of rules" .
How to Write a Script
1. Determine what you need to accomplish
Map your goal to the right hook point using the [Hook Point Decision Matrix]( hook point decision matrix) above.
2. Check if an expression can handle it
Filter, transform, and output filter all have expression based alternatives. Expressions are simpler to maintain and don't require a script resource. Use a script only when you need:
Multi step logic or loops
Cross record calculations (totals, deduplication)
External API calls via integrator api
Error handling with retry data
Access to preMapData alongside postMapData
3. Check for existing scripts in the account
4. Create the script resource
Build the script with the correct function name matching the hook point. A single script can contain multiple functions.
See [references/schemas/request.yml](references/schemas/request.yml) for the create/update schema and [references/schemas/response.yml](references/schemas/response.yml) for the response shape.
Key fields:
name descriptive name (convention: <System <step <hookType , e.g., "Salesforce getBatchRecords postResponseMap" )
content the JavaScript source code
5. Wire the script to the resource
Wiring depends on the hook type:
Hook Wiring pattern Where
preSavePage , preMap , postMap , postSubmit , postAggregate hooks.{hookType}: { scriptId, function } Export or import resource
filter , input filter , transform {field}: { type: "script", script: { scriptId, function } } Export or import resource
postResponseMap hooks.postResponseMap: { scriptId, function } Flow pageProcessors[] entry
branching routeRecordsUsing: "script" + script reference Router in flow
handleRequest script: { scriptId, function } + type: "script" API resource
contentBasedFlowRouter as2.contentBasedFlowRouter: { scriptId, function } AS2 connection
Hook based attachment (preSavePage, preMap, etc.) is additive adding a hook doesn't remove existing config. Replace based attachment (filter, transform) replaces the existing filter/transform expression.
6. Test and iterate
Available Modules
Scripts can import three built in modules:
integrator api
Call Celigo APIs from within the script run exports, read connections, trigger imports.
Useful in preSavePage for enrichment, handleRequest for orchestration, and postSubmit for triggering downstream processes.
dayjs
Date and time manipulation. Handles parsing, formatting, diffing, and timezone conversions without manual date math.
sjcl
Stanford JavaS