Byte manipulation in workflows
Prior to version 3.1.0 of opscotch, payload manipulation was limited to text - you could manipulate that at the byte level in JavaScript but it was very cumbersome and inefficient.
Version 3.1.0 of opscotch adds a ByteContext plus a ByteReader for low-level byte manipulation inside workflows. This is for engineers who already think in buffers, encodings, and compression.
The ByteContext gives you primitives to create, copy, combine, convert, compress, and read/write bytes. Almost every function returns or accepts a buffer handle (not raw arrays).
Importantly, the agent owns the actual memory; you work with buffer handles and maniplation instructions (via methods) and let opscotch do the heavy lifting.
Key docs: ByteContext and ByteReader.
Here is a summary of the methods:
- Create:
create(size),createFromByteArray([...]),createFromString("text"),copy(buffer) - Combine/move:
concat([buffers...]),writeBytes(dest, offset, source, sourceOffset, length) - Read/write:
writeByte(...),readByte(...),getSize(buffer) - Convert:
hexToBinary,binaryToHex,base64ToBinary,binaryToBase64 - Compress:
gzip,gunzip,zip,unzip - Stream:
reader(buffer)to read sequentially;reader()to read from the context stream - Release: buffers are freed automatically when the step finishes (or call
release(...)explicitly)
ByteReader is a forward-only reader with read(length), readAll(), and available(). context.getStream() also returns a ByteReader, so you can pipe incoming binary directly into buffers—see How can I upload binary files? or How can I process multipart HTTP uploads in workflows? for ingest patterns.
Creating and combining buffers
// UTF-8 from string
let text = "Hello opscotch";
let textBuf = byteContext.createFromString(text);
// From bytes
let header = byteContext.createFromByteArray([0xAA, 0xBB]);
// Concatenate
let packet = byteContext.concat([header, textBuf]);
Writing and reading bytes
let buf = byteContext.create(4);
byteContext.writeByte(buf, 0, 0xDE);
byteContext.writeByte(buf, 1, 0xAD);
byteContext.writeByte(buf, 2, 0xBE);
byteContext.writeByte(buf, 3, 0xEF);
let value = byteContext.readByte(buf, 2); // 0xBE
let size = byteContext.getSize(buf); // 4
Bulk copy between buffers:
let source = byteContext.createFromByteArray([1, 2, 3, 4, 5]);
let dest = byteContext.create(8);
byteContext.writeBytes(dest, 2, source, 1, 3); // writes [2,3,4] into dest starting at offset 2
Converting between text and bytes
// Hex to binary and back
let fromHex = byteContext.hexToBinary("48656C6C6F"); // "Hello"
let hex = byteContext.binaryToHex(fromHex); // "48656C6C6F"
// Base64 to binary and back
let fromB64 = byteContext.base64ToBinary("SGVsbG8=");
let b64 = byteContext.binaryToBase64(fromB64); // "SGVsbG8="
Compression
let textBuf = byteContext.createFromString("repeat me ".repeat(50));
let gz = byteContext.gzip(textBuf);
let restored = byteContext.gunzip(gz);
// ZIP alternative
let zipped = byteContext.zip(textBuf);
let unzipped = byteContext.unzip(zipped);
Working with streams (ByteReader)
ByteReader lets you read sequentially without managing offsets. You can get one from a buffer or from the context stream (e.g., HTTP binary upload).
// From an incoming binary HTTP body
let incoming = context.getStream(); // ByteReader from request body
let available = incoming.available();
let bodyBuf = incoming.readAll(); // buffer handle with all bytes
// Inspect as hex for debugging
let fingerprint = byteContext.binaryToHex(bodyBuf).substring(0, 16);
// Sequential parse from a buffer
let reader = byteContext.reader(bodyBuf);
let magic = reader.read(2); // first 2 bytes
let payload = reader.readAll(); // rest
Putting it together
// Receive a binary upload, compress it, and log a short fingerprint
let upload = context.getStream(); // ByteReader
let rawBuf = upload.readAll(); // buffer handle
let gzBuf = byteContext.gzip(rawBuf); // compressed buffer
let hexSig = byteContext.binaryToHex(gzBuf).substring(0, 12);
context.setMessage("stored compressed upload; sig=" + hexSig);
That’s the core: low-level byte primitives, conversions, compression, and streaming, all via handles owned by the agent. Build your higher-level formats on top, and let opscotch manage the buffers for you.
If you need to sign or encrypt what you build, pair these buffers with How can I use industry standard cryptographic functions in workflows.