---
id: scripting--java-script-script
title: "JavaScript script"
summary: "Runs your own JavaScript (Google V8 engine) for every message that reaches the component. Use it for transformations and small integrations when you prefer JavaScript over C#; `async`/`await`, `fetch`, `setTimeout` / `setInterval` and `console` are available."
audience: user
keywords: "input, output, script"
---
# JavaScript script

Runs your own JavaScript (Google V8 engine) for every message that reaches the component. Use it for transformations and small integrations when you prefer JavaScript over C#; `async`/`await`, `fetch`, `setTimeout` / `setInterval` and `console` are available.

## Pins

| Pin | Kind | Types | Description |
|---|---|---|---|
| Input | input | any | The data from the previous component. Its type is the type of the input connection. |
| Output | output | any | Whatever the script passes to `services.Next`. The template creates an object of the output connection's type. |

## Configuration

| Field | Type | Default | Description |
|---|---|---|---|
| `Script` | code (JavaScript) | empty | The user script: an `async function execute(metaData, inputData)` plus any functions and classes you need. Empty means the generated template is used. |

## Behaviour

- Before your code the component generates a JavaScript class for every type of the flow (same class and property names as in the flow, e.g. `inputData.Name`), the classes `FlowMetaData`, `NoInputData`, `AnyInputData` and `ViaFileInfo`, and the global `services`. This part is hidden in the editor; your code starts after the `/*viaducta.javascript.code*/` marker, and the line numbers of errors and of the debugger are the lines of your script.
- The script is loaded once when the flow starts (top-level code runs then); for every message the component calls `execute(metaData, inputData)`, where `inputData` already is an instance of the input connection's class (`NoInputData` when nothing is connected). Global variables keep their values between messages. Messages are processed one at a time per component.
- The generated template:

  ```javascript
  async function execute(metaData, inputData) {
  	const outputData = new CustomerDto();
  	services.Next(metaData, outputData);
  }
  ```

  `CustomerDto` is the output connection's type; without an output connection the template calls `services.Next(metaData, inputData)`.
- `services` is the component's flow service (`IFlowService`) with the C# member names, the same services a C# or Python script has: `services.Log`, `services.Messaging`, `services.Settings`, `services.Component`, `services.Flow`, `services.Profiler`, `services.Batches`, `services.Storage`, `services.Repository` and the rest. .NET methods that return a `Task` return a promise (`await` it).
- `services.Next(metaData, obj)` sends `obj` to the components connected to `Output`; `obj` must be an instance of one of the generated flow classes (plain JavaScript objects can't be sent). It can be called zero, one or many times. `services.Next(metaData, obj, connectionId)` sends to one connection only; `await services.NextAsync(metaData, obj)` waits for the delivery.
- Frequently used services:
  - `services.Log.Information("...")` (also `Debug`, `Warning`, `Error`, `Fatal`) writes to the flow log.
  - `services.Messaging.Information("...")` (also `Warning`, `Error`, `Trace`) writes to the designer console; `UpdateStatusMessage("...")`, `UpdateProgress(0.5)` (0 to 1), `StopProgress()` and `Clear()` update the component.
  - `services.Settings.Get("Package", "Name")` reads an expression setting.
  - `services.Component.Id` / `.Name`; `services.Profiler.UpdateRecordsProduced(services.Component.Id, 1)`.
  - `services.Batches.Begin(metaData, "label")` opens a batch: send the records with `batch.MetaData`, call `batch.Complete()` and `batch.Dispose()` in a `finally` block; disposing without `Complete()` fails the batch (see the example).
  - `await services.HandleExceptionAsync(metaData, inputData, error)` hands a caught error to the flow's error handling and carries on.
- List and array properties are JavaScript arrays: index, `length`, `for...of`, `map`/`filter`, `push`, `pop`, `splice`, `x[i] = v`, `length = 0` and assigning a whole array (`order.Lines = [...]`) are written through to the .NET list. Items of flow types are instances of their generated class. Date properties are returned as JavaScript `Date` objects. Decimal properties are numbers (about 17 significant digits); assign a string (`order.Amount = "12345678901234.123"`) to set an exact decimal.
- `console.log` / `info` / `debug` / `table` write information messages, `console.warn` warnings, `console.error` errors, `console.trace` trace messages to the designer console; `alert(...)` is an information message.
- The component waits until `execute` is done. For timer-based scripts call `wait()` to keep the message open and `end()` when you are done.
- `fetch(url, { method, headers, body })` works like in a browser: the response has `status`, `ok`, `statusText`, `url`, `redirected`, `headers.get(name)`, `text()`, `json()`, `bytes()` and `arrayBuffer()`. An HTTP error status is a response with `ok == false`; only network errors reject. A string body is sent as `application/json` unless a `Content-Type` header says otherwise, an object body is sent as JSON, a `Uint8Array` / `ArrayBuffer` as bytes.
- Other helpers: `sleep(ms)` (blocks the thread) and the host object `crypto`.
- An error that leaves `execute` goes to the flow's error handling as `JavaScriptScriptException`: the message is `TypeError: ...`, the stack trace lists the functions of your script with their lines, and the error line is marked in the editor.
- In debug mode breakpoints and stepping work in the script editor: the debugger stops on the breakpoint lines and shows the local variables. Stepping into the generated classes or the runtime is skipped.

## Notes

- There is no Node.js / browser runtime: `require`, `import`, DOM, `Blob`, `FormData` are not available.
- The template is generated from the connections that exist when it is created; connect first, then open the editor (or clear the script).
- Flow objects the script creates are released when the JavaScript garbage collector collects them.

## Example

Input connection type `Customer`, output connection type `CustomerDto`:

```javascript
/*viaducta.javascript.code*/
let counter = 0;

async function execute(metaData, inputData) {
	if (!inputData.Email) return;          // filter: nothing is sent on
	const outputData = new CustomerDto();
	outputData.Name = inputData.Name.toUpperCase();
	outputData.Email = inputData.Email.toLowerCase();
	outputData.Tags = inputData.Tags.filter(tag => tag !== "");
	counter++;
	services.Messaging.UpdateStatusMessage(`Mapped customer ${counter}: ${outputData.Email}`);
	services.Next(metaData, outputData);
}
```

A batch per file:

```javascript
async function execute(metaData, inputData) {
	const batch = services.Batches.Begin(metaData, inputData.FileName);
	try {
		for (const line of inputData.Lines) {
			const row = new Row();
			row.Text = line;
			services.Next(batch.MetaData, row);
		}
		batch.Complete();
	} finally {
		batch.Dispose();
	}
}
```

Http listener → Json deserializer → **JavaScript script** → Json serializer → ...
