Appearance
YuzeScript
What is YuzeScript?
YuzeScript is a JavaScript-based scripting language for writing custom logic in Yuze. It runs on the V8 engine and supports modern JavaScript features including async/await.
YuzeScript is used in:
- Workflow steps: Process and transform datapoints with custom logic
- Schema Mapping Expressions: Calculate field values during data transformation
- API Connectors: Handle incoming HTTP requests and produce datapoints
The editor provides IntelliSense with type definitions based on your schemas, making it easier to write correct code.
YuzeScript in Workflow Steps
In a workflow step, YuzeScript lets you write custom processing logic.
Available globals: context (consume/produce/workflowStep/vars), yuze (master data helpers), and console (logging).
source, target, and request are not available here. There is no HTTP client or fetch — outbound API calls are handled by connectors, not workflow scripts.
context.consume
Retrieves all datapoints from the consumed feed. Takes no arguments, returns an array matching the input feed schema.
javascript
const datapoints = await context.consume();
for (const dp of datapoints) {
console.log(dp.EquipmentId);
}context.produce
Writes datapoints to the produced feed. Accepts a single object or an array.
javascript
await context.produce({
EquipmentId: 'PUMP-001',
Status: 'Active'
});
// Or multiple datapoints
await context.produce([
{ EquipmentId: 'PUMP-001', Status: 'Active' },
{ EquipmentId: 'PUMP-002', Status: 'Inactive' }
]);context.workflowStep
Identifies the current workflow step instance. Useful for logging or conditional logic.
javascript
console.log(context.workflowStep.Id); // UUID string
console.log(context.workflowStep.Name); // Workflow step nameTIP
context.yuzecase is a legacy alias for context.workflowStep and still works, but prefer context.workflowStep in new scripts.
context.vars
Reads variables defined on the workflow (see the workflow Settings tab). Reference a variable by name as context.vars.<name>. A name that isn't defined reads as undefined.
javascript
console.log('Reporting year: ' + context.vars.YEAR);
await context.produce({
EquipmentId: 'PUMP-001',
Year: context.vars.YEAR
});TIP
The same variables can also be used in non-script settings via the double-curly-brace token form. Inside YuzeScript, use context.vars.YEAR instead — it's valid code the editor understands.
Complete Workflow Step Example
javascript
const datapoints = await context.consume();
const results = datapoints.map(dp => ({
...dp,
processed: true,
processedAt: new Date().toISOString()
}));
await context.produce(results);Enriching with Master Data
When looking up master data for each item, use a for loop instead of .map() because each iteration requires await:
javascript
const items = await context.consume();
const enriched = [];
for (const item of items) {
const ref = await yuze.createExternalMasterDataItemReference('Equipment', 'SAP', item.EquipmentId);
const equipment = await yuze.lookupMasterDataItem(ref);
enriched.push({
...item,
EquipmentName: equipment?.displayName || 'Unknown'
});
}
await context.produce(enriched);YuzeScript in Schema Mappings
In schema mapping expressions, YuzeScript calculates field values during data transformation. You work with source (input data) and assign values to target fields.
Available globals: source (read-only input), target (writable output), yuze (master data helpers), and console (logging).
context and request are not available here. Only explicitly mapped fields assigned to target appear in the output.
source
The input data being transformed. Contains all fields from the source schema (read-only).
javascript
console.log(source.FirstName); // 'John'
console.log(source.LastName); // 'Doe'
console.log(source.Address.City);target
The output data structure. Assign values to target properties to set the output fields.
javascript
target.FullName = source.FirstName + ' ' + source.LastName;
target.ProcessedAt = new Date().toISOString();Complete Schema Mapping Example
javascript
target.FullName = source.FirstName + ' ' + source.LastName;
target.Address = [source.Street, source.City, source.Country].filter(Boolean).join(', ');
target.Priority = source.Severity > 7 ? 'High' : 'Low';YuzeScript in API Connectors
API connectors use YuzeScript to handle incoming HTTP requests and produce datapoints.
Available globals: request (incoming HTTP request), context.produce() (write datapoints), yuze (master data helpers), and console (logging).
context.consume(), source, and target are not available here.
request
The incoming HTTP request object:
request.method— HTTP method ('POST', 'GET', etc.)request.headers— Object with header names as keysrequest.query— Query parameters from the URLrequest.path— URL path after connector base URLrequest.body— Parsed body. JSON is parsed natively. XML is auto-converted to JSON: all values become strings, single child elements are objects (not arrays), attributes become@name, text content becomes#text.request.bodyRaw— Raw unparsed body string. Use when you need the exact original text or when the auto-converted JSON shape is not suitable.
javascript
console.log(request.method); // 'POST'
console.log(request.headers['content-type']);
console.log(request.query.status); // query parameter
console.log(request.path); // URL path after connector base URL
console.log(request.body); // parsed body (JSON or XML-to-JSON)
console.log(request.bodyRaw); // raw unparsed body stringresponse (Return Value)
Return an object { status, body?, headers? } to define the HTTP response.
javascript
return {
status: 200,
body: { success: true }
};
// Error response
return {
status: 400,
body: { error: 'Invalid request' }
};
// With custom response headers
return {
status: 200,
body: { ok: true },
headers: { 'X-Request-Id': request.headers['x-request-id'] || 'none' }
};context.produce (API Connector)
Writes datapoints to the configured feed.
javascript
await context.produce(request.body);Complete API Connector Example
javascript
await context.produce(request.body);
return {
status: 200,
body: { success: true }
};Built-in Functions
The yuze object provides helper functions available in all contexts.
yuze.createExternalMasterDataItemReference
Creates a reference to a master data item from an external system.
javascript
const ref = await yuze.createExternalMasterDataItemReference(
'Equipment', // type
'SAP', // source system
'PUMP-001' // source ID
);
// Returns: 'master-data-ext:Equipment:SAP:PUMP-001'yuze.createInternalMasterDataItemReference
Creates a reference to an internally managed master data item.
javascript
const ref = await yuze.createInternalMasterDataItemReference(
'Location', // type
'SITE-A' // ID
);
// Returns: 'master-data:Location:SITE-A'yuze.lookupMasterDataItem
Retrieves a master data item by its identifier. Returns null if not found.
javascript
const item = await yuze.lookupMasterDataItem('master-data:Equipment:PUMP-001');
if (item) {
console.log(item.displayName);
console.log(item.properties.Status);
console.log(item.mappingIdentifiers.SAP[0]);
}yuze.searchMasterDataItems
Searches for master data items with filters. Returns paginated results with a continue token for fetching additional pages.
Parameters:
query: Search criteriatype: Master data type to searchonlyRootItems: (optional) Filter to only root itemsmetadata: (optional) Filter by metadata field values
pagination: Pagination optionspageSize: Number of items per pagenextPageToken: (optional) Token from previous result for next page
Returns: CursorPagingResult<MasterDataItem>
items: Array of matching master data itemsnextPageToken: Token for fetching the next page (undefined if no more pages)
Basic Example
javascript
const result = await yuze.searchMasterDataItems(
{
type: 'Equipment',
onlyRootItems: true,
metadata: { Status: 'Active' }
},
{ pageSize: 50 }
);
for (const item of result.items) {
console.log(item.displayName);
}Paginating Through All Results
Use a do-while loop to fetch all pages using the nextPageToken:
javascript
let nextPageToken = undefined;
do {
const result = await yuze.searchMasterDataItems(
{
type: 'Equipment',
metadata: { Status: 'Active' }
},
{
pageSize: 100,
nextPageToken: nextPageToken
}
);
for (const item of result.items) {
console.log(`Processing: ${item.displayName}`);
}
nextPageToken = result.nextPageToken;
} while (nextPageToken);yuze.lookupMasterDataItemSystemKey
Gets the external system identifier for a master data item.
javascript
const sapId = await yuze.lookupMasterDataItemSystemKey(
'master-data:Equipment:PUMP-001',
'SAP'
);
// Returns: 'SAP-PUMP-001' or nullyuze.saveMasterDataItem
Creates or updates a master data item.
javascript
await yuze.saveMasterDataItem({
identifier: 'master-data-ext:Equipment:SAP:PUMP-001',
displayName: 'Main Cooling Pump',
parentId: 'master-data:Location:PLANT-A',
properties: {
SerialNumber: 'SN-12345',
Status: 'Active'
},
mappingIdentifiers: {
SAP: ['10001234']
}
});yuze.deleteMasterDataItem
Deletes a master data item by its identifier. Children of the item are not deleted — they are left without a parent.
javascript
await yuze.deleteMasterDataItem('master-data:Equipment:PUMP-001');yuze.saveMasterDataHierarchy
Saves one or more complete master data trees in a single call, keeping stored data in step with the source system that owns them. The items you pass are authoritative for the trees they describe: each item is created or updated as needed, and any item already stored under one of those trees that is not in your payload is removed. Use this when a source owns a whole hierarchy and you want the stored data to match its latest payload exactly — instead of dropping and re-creating the tree.
Pass the flat list of items (parent links are carried on each item via parentId, the same item shape as yuze.saveMasterDataItem above) plus an options object:
javascript
const result = await yuze.saveMasterDataHierarchy(
[
{ identifier: 'master-data:Location:PLANT-A', displayName: 'Plant A' },
{
identifier: 'master-data:Location:LINE-1',
displayName: 'Assembly Line 1',
parentId: 'master-data:Location:PLANT-A'
},
{
identifier: 'master-data:Location:CELL-1',
displayName: 'Cell 1',
parentId: 'master-data:Location:LINE-1'
}
],
{ onMissing: { strategy: 'delete' } }
);
console.log(result); // { Inserted, Updated, Unchanged, Deleted, Unlinked, Archived }Options:
onMissing— what to do with items still stored under a tree but missing from your payload. Pass an object{ strategy, property }. Supported strategies:'delete'(default) — remove them, so stored data matches the source.'unlink'— keep them, detaching the removed branch from its parent so it survives as its own tree.'archive'— keep them exactly where they are and stamp the current timestamp into a metadata property so you can recognise them as archived. The property name is set viaproperty(defaults to'ArchivedAt'). Already-archived items keep their original timestamp — re-running the sync does not move it or re-archive them.
javascript
// Archive missing items into a custom property instead of deleting them
const result = await yuze.saveMasterDataHierarchy(
items,
{ onMissing: { strategy: 'archive', property: 'RetiredOn' } }
);Only items that actually changed are updated; unchanged items are left as-is. When anything inside a tree changes, its ancestors up to the root are marked as changed as well, so Incremental Sync re-syncs only the affected hierarchies rather than the entire dataset.
Choosing the archive property
The property you archive into is yours to choose, because "archived" means different things to different sources — some flag a status field, others stamp a retirement date. If you don't pass property, the timestamp lands in ArchivedAt. Reserved properties (DisplayName, Identifier, ParentId) can't be used.
Re-sending an archived item un-archives it
If an archived item later reappears in your payload, it is treated as a normal update and the archive marker is cleared — the item is live again. You don't need a separate "un-archive" step: sending the item back is the signal. (The marker is only cleared if your payload doesn't itself carry that property; whatever you send for it wins.)
Authority is per tree, not across trees
Removal only applies to the trees you actually send: items missing from a tree you send are removed, but a whole hierarchy you simply stop sending is left untouched — there is no signal to distinguish "deliberately removed" from "not included in this run." Decide per workflow how entire hierarchies get retired; the save can't infer it.
yuze.sha256Hash
Calculates a SHA-256 hash. Useful for deduplication.
javascript
const hash = await yuze.sha256Hash({ id: 123, name: 'Test' });
// Returns: 64-character hex stringyuze.searchDataPoints
Searches recorded data points with filters. Returns paginated results with a continue token for fetching additional pages.
Parameters:
query: Search criteria (all fields optional)schema: A schema id (e.g.'schema:emissions') or a schema version id (e.g.'schema-version:emissions:1.0') — the form is detected automatically. A schema id matches data points of any version of that schema; a schema version id matches only that version.fromDate/toDate: ISO-8601 timestamps bounding the data point's timestamp.bucket: Restrict to a single bucket.propertyFilters: Array of{ propertyName, operator, value }. Operators:Equals,NotEquals,Contains,StartsWith,EndsWith,IsNull,IsNotNull(valueis omitted for the last two).
pagination: Pagination options.pageSize: Number of items per page (required).nextPageToken: (optional) Opaque cursor to read from. Omit (or passnull) to start from the beginning; pass back either token from a previous result to continue from there. Results are always ordered oldest → newest.
Returns:
items: Array of matching data points (code,type,values,numberValue,stringValue,schemas,associatedWith,bucket,timeStamp,position, …)nextPageToken: Cursor for the next page, ornullonce you have read everything. Loop while it is set to walk the whole result set.resumeToken: Cursor for where you got to. Stays set even once you are caught up, so you can save it and pass it back on a later run to read only what has been written since.nullonly when nothing has ever matched your query.
Both are opaque — store them as-is and pass them back verbatim; don't parse or build them.
Paginate through everything with a do-while loop:
javascript
let nextPageToken = undefined;
const all = [];
do {
const result = await yuze.searchDataPoints(
{ schema: 'schema:emissions' },
{ pageSize: 100, nextPageToken }
);
all.push(...result.items);
nextPageToken = result.nextPageToken;
} while (nextPageToken);javascript
const result = await yuze.searchDataPoints(
{
schema: 'schema:emissions',
fromDate: '2026-01-01T00:00:00Z',
propertyFilters: [
{ propertyName: 'Scope', operator: 'Equals', value: 'Scope 1' },
{ propertyName: 'Note', operator: 'IsNotNull' }
]
},
{ pageSize: 50 }
);
for (const dataPoint of result.items) {
console.log(dataPoint.code, dataPoint.numberValue);
}Reading only what's new (remembering where you left off)
Use resumeToken when you want a script to pick up where it left off rather than re-read everything. Persist it, and next time you pass it back you continue from that point — so you only ever read data points written since.
- First read / from scratch: omit
nextPageToken(or passnull). Results come oldest-first. - Read only what's new: pass the previous run's
resumeTokenback. - Re-read everything: omit the token again.
resumeToken stays set once any data has matched, including on a page that came back empty — so it's always safe to save. That's the difference between the two tokens: nextPageToken goes null to end a paging loop, resumeToken survives one so it can be stored between runs.
javascript
// Example: an API connector that returns new emissions data points since the caller's last token.
const page = await yuze.searchDataPoints(
{ schema: 'schema-version:emissions:1.0' },
{
pageSize: 200,
nextPageToken: request.query.token ?? null // null on the first call
}
);
return {
status: 200,
body: {
items: page.items.map(x => x.values),
// The caller persists this and sends it back next time to get only newer data points.
token: page.resumeToken ?? null
}
};WARNING
This surfaces newly written data points only — not edits or deletes to existing ones. It's a "read what's new" feed, not a full change feed.
XML transformations
yuze.xml converts between XML and plain JavaScript objects — useful when an external system speaks XML but the rest of your script works with objects. These helpers are synchronous (no await needed).
yuze.xml.build
Builds an XML string from an object. Keys starting with @_ become attributes; arrays become repeated elements; text is entity-escaped automatically — never hand-concatenate XML.
javascript
const xml = yuze.xml.build({
Order: {
'@_id': 'A1',
Customer: 'Foo & Sons', // the & is escaped to & for you
Line: ['Widget', 'Gadget'] // an array becomes repeated <Line> elements
}
}, { format: true }); // format: true pretty-prints with indentation
// <Order id="A1">
// <Customer>Foo & Sons</Customer>
// <Line>Widget</Line>
// <Line>Gadget</Line>
// </Order>
return xml;yuze.xml.parse
Parses an XML string into an object. It throws if the XML is malformed, so you never get silent garbage.
Always list repeating elements in arrays. XML has no array syntax, so a single <Line> parses as an object but two <Line> elements parse as an array. That inconsistency breaks scripts that expect a list. Naming the element in arrays forces it to always be an array — even when there's only one.
javascript
const doc = yuze.xml.parse(xml, { arrays: ['Line'] });
const orderId = doc.Order['@_id']; // attributes are read with the @_ prefix
const lines = doc.Order.Line; // always an array thanks to the arrays optionWARNING
All parsed values are strings — even numbers. <Code>00123</Code> parses as the string "00123" (this deliberately preserves leading zeros in external-system IDs). Convert explicitly when you need a number: Number(doc.Item.Code).
yuze.xml.validate
Checks whether a string is well-formed XML without parsing it. Returns { valid: true } or { valid: false, error: '...' }.
javascript
const check = yuze.xml.validate(input);
if (!check.valid) {
throw new Error('Bad XML from the supplier: ' + check.error);
}Console Logging
Standard console methods are available and captured in execution logs:
javascript
console.log('Processing started');
console.warn('Missing optional field');
console.error('Failed to process item');| Method | Log Level |
|---|---|
console.log() | Information |
console.warn() | Warning |
console.error() | Error |
Error Handling
Script errors include line numbers and stack traces. Use try-catch for graceful error handling:
javascript
try {
const item = await yuze.lookupMasterDataItem(identifier);
if (!item) {
console.warn(`Item not found: ${identifier}`);
return null;
}
return item.properties;
} catch (error) {
console.error(`Lookup failed: ${error.message}`);
throw error;
}Tips
- Use async/await: All
yuzefunctions and context methods are asynchronous - Check for null: Lookup functions return
nullwhen items are not found - Use console.log: Debug your scripts by logging intermediate values
