Script API Reference
Hodor runs your scripts in a built-in JavaScript engine. Depending on the script type, Hodor calls one of the entry functions below at the right time — you only implement the logic you need. If you do not modify anything, delete the unused entry function to avoid unnecessary calls.
Available global objects and classes:
| Category | Names |
|---|---|
| Entry functions | onRequest, onResponse, onSessionCompleted, onSchedule, onMock, abort() |
Native $ modules | $codec, $hash, $hmac, $crypto, $jwt, $format, $fs, $env, $uuid, $log |
| Web standard APIs | fetch, HTTPClient, setTimeout / setInterval, btoa / atob / sleep / require / TextEncoder / crypto, console |
| HTTP classes | Request, Response, Body, Headers, URLSearchParams |
| Storage | SharedPreferences, sdk variables |
| Contexts | RewriteContext, CompletedContext, ScheduleContext |
Use console.log(...) anywhere in a script to inspect values — output is shown in the script's log view.
Entry Functions
Scripts are detected by scanning for async function declarations — the parameter count of each entry function is fixed (onRequest/onResponse/onMock take 3, onSessionCompleted takes 4, onSchedule takes 1). Arrow-function assignments (let onRequest = async (...) => {}) are not detected. Parameter names are free.
onRequest(context, url, request)
Designed for Rewrite Script and Quick Request pre-request scripts. This function is called before the HTTP request is sent to the server. Return the (possibly modified) request.
| Parameter | Type | Description |
|---|---|---|
context | RewriteContext | The context object. |
url | string | The URL of the HTTP request. |
request | Request | The HTTP request object. |
// modify request body
async function onRequest(context, url, request) {
// parse to Text
var text = request.body.parseText()
console.log(text)
request.body = "this is a replaced request text"
// parse to JSON
var json = request.body.parseJSON()
json["script_json"] = "JSONValue"
request.body = json
// parse to URLSearchParams
var urlencoded = request.body.parseURLSearchParams()
urlencoded.append("script", "parseURLSearchParams")
request.body = urlencoded
// Done
return request;
}
// redirect, modify path / queries / headers
async function onRequest(context, url, request) {
console.log(url);
// set a parameter, you can get it in onResponse
context.parameters["custom"] = "custom parameter on request"
// redirect
request.scheme = "http"
request.path = "/upload/json"
request.host = "192.168.3.30"
request.port = 6000
// change method
request.method = "POST"
// queries operation
request.queries.append("name", "value1") // add query
request.queries.set("name", "value2") // replace or add query
request.queries.get("name") // get query by name
request.queries.delete("name") // delete query by name
// headers operation
request.headers.delete("accept") // delete header by name
request.headers.append("hodor", "custom value") // add name-value pair
request.headers.forEach((value, name) => {
console.log(name + ":" + value)
});
// Done
return request;
}
onResponse(context, url, response)
Designed for Rewrite Script and Quick Request post-response scripts. This function is called before the HTTP response is sent to the client. Return the (possibly modified) response.
| Parameter | Type | Description |
|---|---|---|
context | RewriteContext | The context object. |
url | string | The URL of the HTTP response. |
response | Response | The HTTP response object. |
// response body
async function onResponse(context, url, response) {
// parse to Text
var text = response.body.parseText()
console.log(text)
response.body = "this is a replaced response text"
// parse to JSON
var json = response.body.parseJSON()
json["script_json"] = "JSONValue"
response.body = json
// parse to URLSearchParams
var urlencoded = response.body.parseURLSearchParams()
urlencoded.append("script", "parseURLSearchParams")
response.body = urlencoded
// Done
return response;
}
// change status code and headers
async function onResponse(context, url, response) {
// get parameters set in onRequest
console.log(context.parameters["custom"]) // Output "custom parameter on request"
response.statusCode = 200 // change status code
response.statusPhrase = "OK" // change status phrase
response.headers.delete("accept")
response.headers.append("hodor", "custom value")
response.headers.forEach((value, name) => {
console.log(name + ":" + value)
});
// Done
return response
}
onSessionCompleted(context, url, request, response)
Designed for HTTP Completed Script. Called asynchronously after the HTTP response is returned, without affecting data transmission between the app and the server. Useful for data collection and forwarding.
| Parameter | Type | Description |
|---|---|---|
context | CompletedContext | The context object. |
url | string | The URL of the HTTP request. |
request | Request | The HTTP request object. |
response | Response | The HTTP response object. |
// sample: pass session data to your own server
async function onSessionCompleted(context, url, request, response) {
try {
var reqText = request.body.parseText();
var rspText = response.body.parseText()
var params = {
"body": { // HTTPClient post body data
"url": url, // request url
"reqHeader": request.headers.encode(), // request headers
"reqText": reqText, // request body
"rspHeader": response.headers.encode(), // response headers
"rspText": rspText, // response body
},
"headers": { // HTTPClient headers
"from": "onSessionCompleted"
},
}
const rsp = await HTTPClient.post("http://192.168.3.30:8000/upload", params)
let text = rsp.body.parseText()
console.log(text)
} catch(error) {
console.log(error)
}
}
onSchedule(context)
Designed for Schedule Script. Called at the scheduled trigger time (5 or 6-part cron expressions are supported). Use abort() to stop the schedule loop.
| Parameter | Type | Description |
|---|---|---|
context | ScheduleContext | The context object. |
async function onSchedule(context) {
// set custom parameters for next runloop
context.parameters["custom"] = "custom parameters for next runloop";
// repeated count
console.log(`repeatedCount ${context.repeatedCount}`);
// if repeatedCount is 2, abort schedule
if (context.repeatedCount == 2) {
abort()
}
// you can also use HTTPClient to send requests
const rsp = await HTTPClient.get("https://www.apple.com")
let text = rsp.body.parseText()
console.log(text)
}
onMock(context, url, request)
Designed for Mock Script. Called instead of sending the request to the server — whatever you return is delivered to the client as the response.
| Parameter | Type | Description |
|---|---|---|
context | RewriteContext | The context object. |
url | string | The URL of the HTTP request. |
request | Request | The HTTP request object. |
// return a mocked JSON response
async function onMock(context, url, request) {
const response = new Response({
statusCode: 200,
statusPhrase: 'OK',
headers: {'Content-Type': 'application/json'},
textBody: JSON.stringify({code: 0, message: 'mocked by script', data: {time: Date.now()}}),
});
return response;
}
abort()
Inside channel scripts (onRequest / onResponse / onSchedule), call abort() to stop the script and abort the current execution immediately — it throws an AbortError that Hodor reports back to you.
// ✅ correct — abort() is injected into the script scope
async function onRequest(context, url, request) {
if (url.includes("/tracking")) abort();
return request;
}
Do not declare onRequest(context, url, request, aborter) with a 4th parameter. The parameter count of entry functions is fixed — a 4th parameter makes the entry undetectable.
Native Modules
All $-prefixed modules are injected when the runtime activates. They are implemented natively, return synchronously (unless noted) and treat string inputs as UTF-8.
$codec — Encode & Decode
Base64 / Hex / URL percent encoding for protocol conversion and data transfer.
| Method | Returns |
|---|---|
$codec.base64Encode(str) | Base64 string. |
$codec.base64Decode(str) | Decoded string; invalid input returns "" (does not throw). |
$codec.hexEncode(str) | Lowercase hex string. |
$codec.hexDecode(str) | Decoded string; invalid characters are skipped. |
$codec.urlEncode(str) | Percent-encoded string. |
$codec.urlDecode(str) | Decoded string; invalid sequences are returned as-is. |
$codec.base64Encode("Hello, World!"); // "SGVsbG8sIFdvcmxkIQ=="
$codec.base64Decode("SGVsbG8sIFdvcmxkIQ=="); // "Hello, World!"
$codec.hexEncode("ABC"); // "414243"
$codec.hexDecode("414243"); // "ABC"
$codec.urlEncode("hello world&foo=bar"); // "hello%20world%26foo%3Dbar"
$hash — Hashing
Digest computation for integrity checks, content addressing and anonymization. Returns lowercase hex.
| Method | Output length |
|---|---|
$hash.md5(str) | 32 hex chars |
$hash.sha1(str) | 40 hex chars |
$hash.sha256(str) | 64 hex chars |
$hash.sha384(str) | 96 hex chars |
$hash.sha512(str) | 128 hex chars |
$hash.md5("hello"); // "5d41402abc4b2a76b9719d911017c592"
$hash.sha256("hello"); // "2cf24dba5fb0a30e26e83b2ac5b9e29e1b161e5c1fa7425e73043362938b9824"
// integrity check
const checksum = $hash.sha256(JSON.stringify({user: "admin"}));
$hmac — Message Authentication Code
Keyed hashing for API signing and tamper detection. Both (data, key) are UTF-8 encoded; returns lowercase hex.
| Method | Algorithm |
|---|---|
$hmac.md5(data, key) | HMAC-MD5 |
$hmac.sha1(data, key) | HMAC-SHA1 |
$hmac.sha256(data, key) | HMAC-SHA256 |
$hmac.sha384(data, key) | HMAC-SHA384 |
$hmac.sha512(data, key) | HMAC-SHA512 |
const signature = $hmac.sha256("important data", "my-secret-key");
const isValid = (signature === $hmac.sha256("important data", "my-secret-key")); // true
$crypto — Symmetric Encryption
AES-GCM authenticated encryption (recommended) and DES (legacy compatibility).
| Method | Returns |
|---|---|
$crypto.encryptAES(plaintext, password, options?) | Base64 ciphertext; failures return an "Error: <reason>" string. |
$crypto.decryptAES(ciphertext, password, options?) | Plaintext; invalid ciphertext returns "Error: Invalid ciphertext". |
$crypto.encryptDES(plaintext, key) | DES-ECB + PKCS7, key truncated to 8 bytes → Base64. |
$crypto.decryptDES(ciphertext, key) | Plaintext; non-Base64 input returns "". |
options: { keySize: 128 \| 192 \| 256 } (default 256). The AES ciphertext format is base64(nonce[12] + ciphertext + tag[16]) — pair it with decryptAES; when interoperating with other languages you must unpack this format yourself.
const encrypted = $crypto.encryptAES("sensitive data", "my-password");
$crypto.decryptAES(encrypted, "my-password"); // "sensitive data"
// 128-bit key
const e128 = $crypto.encryptAES("data", "pass", { keySize: 128 });
// errors are returned as strings, not thrown — check the prefix
const out = $crypto.decryptAES("not-base64!!", "p");
if (out.startsWith("Error:")) { /* handle error */ }
$jwt — JSON Web Token
JWT creation, parsing and signature verification (HMAC family) for authentication flow scripts.
| Method | Returns |
|---|---|
$jwt.sign(payload, secret, algorithm?) | JWT string; default HS256. |
$jwt.decode(token) | {header, payload} object (signature is not verified); returns null on malformed tokens. |
$jwt.verify(token, secret, algorithm?) | boolean — signature verification result. |
algorithm: "HS256" | "HS384" | "HS512".
// sign
const payload = JSON.stringify({ sub: "user123", exp: Math.floor(Date.now() / 1000) + 3600 });
const token = $jwt.sign(payload, "my-secret", "HS256");
// decode — returns an object directly, no JSON.parse needed
const decoded = $jwt.decode(token);
decoded.header.alg; // "HS256"
decoded.payload.sub; // "user123"
// verify
$jwt.verify(token, "my-secret", "HS256"); // true
$jwt.verify(token, "wrong-secret", "HS256"); // false
// expiry check
const exp = $jwt.decode(token).payload.exp;
const expired = exp * 1000 < Date.now();
$format — Data Formatting
JSON/XML pretty-printing and minification for logging and debugging. JSON keys are sorted alphabetically in the output.
| Method | Returns |
|---|---|
$format.json(str, indent?) | Pretty-printed JSON; indent clamped to 1–8 (default 2); invalid input returns "Error: Invalid JSON". |
$format.minify(str) | Minified JSON (sorted keys, no whitespace); invalid input returns "Error: Invalid JSON". |
$format.xml(str) | Simple indented XML. |
$format.json('{"b":1,"a":2}');
// {
// "a": 2,
// "b": 1
// }
$format.json('{"a":2}', 4); // 4-space indent
$format.minify('{ "a": 2 }'); // '{"a":2}'
$format.xml('<root><child>t</child></root>');
// <root>
// <child>t</child>
// </root>
$fs — File System
Lightweight file read/write inside scripts (config, cache, export). Paths support ~ expansion; write creates missing parent directories automatically.
| Method | Returns |
|---|---|
$fs.read(path) | UTF-8 content; failure returns "Error: Cannot read file at <path>". |
$fs.readBinary(path) | Bytes as Base64; failure returns "". |
$fs.write(path, content) | boolean — success. |
$fs.exists(path) | boolean. |
$fs.delete(path) | boolean; missing files return false. |
$fs.list(path) | string[] of directory entries; failure returns []. |
$fs.info(path) | JSON string {size, modified, isDirectory, path}; missing paths return undefined. |
const file = $env.tmpDir() + "/hodor-test.txt";
$fs.write(file, "Hello from Hodor!");
$fs.read(file); // "Hello from Hodor!"
$fs.exists(file); // true
$fs.list($env.tmpDir()); // ["hodor-test.txt", ...]
const info = JSON.parse($fs.info(file));
info.size; // byte count
info.isDirectory; // false
$fs.delete(file); // true
Failure shapes differ per method: read returns an "Error: ..." string, readBinary returns "", list returns [] and info returns undefined — handle each accordingly.
$env — Environment Variables
Process environment variables and system paths. Note: $env is the process environment (shared across executions, lives with the process). To persist user-facing variables use sdk.setEnvVar or SharedPreferences instead.
| Method | Returns |
|---|---|
$env.get(key) | Value; missing keys return "". |
$env.set(key, value) | boolean — setenv result. |
$env.all() | JSON string of all environment variables. |
$env.cwd() | Current working directory. |
$env.tmpDir() | Temporary directory. |
$env.homeDir() | User home directory. |
$env.set("APP_VERSION", "1.0.0");
$env.get("APP_VERSION"); // "1.0.0"
const all = JSON.parse($env.all());
$uuid — UUID
Generate and validate UUIDs (request IDs, idempotency keys).
| Method | Returns |
|---|---|
$uuid.v4() | Standard v4 UUID (uppercase, hyphenated), e.g. "550e8400-E29B-41D4-A716-446655440000". |
$uuid.compact() | Hyphen-free, lowercase form. |
$uuid.validate(str) | Whether the string is a valid UUID. |
const id = $uuid.v4();
$uuid.compact(); // "550e8400e29b41d4a716446655440000"
$uuid.validate($uuid.v4()); // true
$uuid.validate("not-uuid"); // false
validate only accepts the hyphenated format — validate($uuid.compact()) returns false. Re-insert hyphens before validating a compact string.
$log — Structured Logging
Timestamped, leveled log lines routed through the engine's console system (collected into the script's log view).
| Method | Returns |
|---|---|
$log.log(level, message, tag?) | Formatted log line (also printed). |
$log.debug / info / warn / error(message) | Convenience level methods, output only. |
Log line format: [yyyy-MM-dd'T'HH:mm:ss.SSSZ] [LEVEL] [tag] message (the [tag] segment is omitted when no tag is given).
$log.info("Server started on port 8080");
// [2025-07-24T01:11:45.548+0800] [INFO] Server started on port 8080
$log.log("info", "Request processed", "API");
// [2025-07-24T01:11:45.548+0800] [INFO] [API] Request processed
Web APIs
fetch
Send real HTTP requests from scripts — the main channel for Postman-style workflows.
fetch(url: string, options?: object) → Promise<response>
options:
| Field | Type | Default | Description |
|---|---|---|---|
method | string | "GET" | Case-insensitive; unknown values fall back to GET. |
timeoutInterval | number | 30 | Seconds. |
headers | [[k, v]] or [{k: v}] | [] | Both shapes are accepted. |
textBody | string | — | Request body text. |
encoding | string | — | "hex" means textBody is a hex string. |
The resolved value is a plain object: statusCode (number), headers (array of single-key objects, duplicate keys preserved), and textBody() — a function that returns {text, encoding} with automatic character-set detection (undecodable bodies fall back to {text: <hex>, encoding: "hex"}). The rejected value is an error message string.
// GET
const rsp = await fetch("https://httpbin.org/get");
if (rsp.statusCode === 200) {
const body = rsp.textBody(); // {text: "...", encoding: "utf-8"}
const json = JSON.parse(body.text);
}
// POST JSON
const rsp2 = await fetch("https://httpbin.org/post", {
method: "POST",
headers: [["Content-Type", "application/json"]],
textBody: JSON.stringify({a: 1}),
timeoutInterval: 10,
});
HTTPClient
The HTTPClient class sends HTTP requests from any script (implemented on top of fetch). All methods are async and return a response object with statusCode, headers and textBody().
| Method | Description |
|---|---|
HTTPClient.get(url, params?) | Send a GET request. |
HTTPClient.post(url, params?) | Send a POST request. |
HTTPClient.put(url, params?) | Send a PUT request. |
HTTPClient.update(url, params?) | Send an UPDATE request. |
HTTPClient.delete(url, params?) | Send a DELETE request. |
HTTPClient.request(url, method, params?) | Send a request with a custom method. |
params is an optional object with:
headers: request headers object, e.g.{"key1": "value1"}body: request body — a string, JSON object (serialized automatically) or URLSearchParamstimeoutInterval: timeout in seconds (default 60)
try {
var params = {
"headers": {"key1": "value1"},
"body": {"a": "a1", "b": "b1"},
};
const response = await HTTPClient.post("https://dummyjson.com/products/1", params);
console.log(response.textBody().text);
} catch(error) {
console.log(error);
}
Timers
setTimeout / setInterval / clearTimeout / clearInterval work as in browsers. Callbacks are dispatched on a serial engine queue, so timers fire reliably regardless of the host thread.
| Function | Returns |
|---|---|
setTimeout(callback, ms) | Timer id (string), fires once. |
setInterval(callback, ms) | Timer id, fires repeatedly. |
clearTimeout(id) / clearInterval(id) | Cancel (idempotent, unknown ids are ignored). |
await new Promise(resolve => setTimeout(resolve, 500)); // wait 0.5s
const timer = setInterval(() => console.log("tick"), 1000);
setTimeout(() => clearInterval(timer), 3500);
Global Functions
| Name | Signature | Description |
|---|---|---|
btoa(str) | (string) → string | Base64 encode — UTF-8 symmetric semantics (non-Latin1 strings are allowed, unlike browsers). |
atob(str) | (string) → string | Base64 decode; invalid input returns "". |
performance.now() | () → number | Milliseconds since the epoch (not page load). |
sleep(ms) | (number) → Promise | Resolve after ms; use await sleep(1000). |
require(id) | (string) → any | Load a script library by CommonJS semantics (module.exports); the key is @libs/<key>, resolved as script-library identifier → script-library name (unique) → built-in libs; throws when not found. |
TextEncoder | new TextEncoder().encode(str) | UTF-8 encode into a Uint8Array (encoding is always "utf-8"). |
crypto.getRandomValues(n) | (Array) → number[] | Fill with n random UInt32 values. |
crypto.randomUUID() | () → string | Random UUID (uppercase, hyphenated). |
btoa("Hello"); // "SGVsbG8="
atob("SGVsbG8="); // "Hello"
btoa("中文"); // works — UTF-8 bytes are encoded
performance.now(); // 1760000000000.123
await sleep(100);
const { encode } = require("@libs/base64"); // built-in lib
const { sign } = require("@libs/sign-lib"); // your script library
new TextEncoder().encode("hi"); // Uint8Array [104, 105]
Libraries are managed in the script module manager. The require key is always @libs/<key>: your script libraries resolve by identifier first (stable across renames), then by name (unique match), then the built-in libs @libs/base64 / @libs/hex. Libraries export via module.exports, may require other libraries, and a missing key throws (pre-send failures abort the request, post-response failures keep the original response). See Quick Request scripting, Require Script Libraries for the full guide.
console
console.log / info / warn / error prints values to the script's log view. Multiple arguments are serialized, so you can log objects and arrays directly:
console.log("headers", {Accept: "application/json"}, [1, 2, 3]);
$log offers structured, leveled output (see $log) — both channels are visible in Hodor's script log view.
HTTP Classes
Request
The Request class is the packaged HTTP request passed to onRequest / onSessionCompleted.
| Member | Type | Description |
|---|---|---|
scheme | string (get / set) | The scheme of the request, e.g. https. |
host | string (get / set) | The host of the request. |
port | number (get / set) | The port of the request. |
path | string (get / set) | The path of the request. |
method | string (get / set) | The HTTP method, e.g. GET. |
queries | URLSearchParams (get) | The query parameters of the request. |
headers | Headers (get) | The headers of the request. |
body | Body (get) / string | Map | Array | URLSearchParams (set) | The body of the request. |
Headers must be modified with .set() / .append() — index assignment (e.g. headers["X-Key"] = v) is ignored.
You can also construct a request yourself:
const request = new Request({
scheme: 'https',
host: 'example.com',
port: 8080,
path: '/api',
method: 'GET',
queries: 'param1=value1¶m2=value2',
headers: [
['Content-Type', 'application/json'],
['Authorization', 'Bearer token']
],
textBody: '{"key": "value"}'
});
console.log(request.encode());
Response
The Response class represents the HTTP response passed to onResponse / onSessionCompleted.
| Member | Type | Description |
|---|---|---|
statusCode | number (get / set) | The status code of the response. |
statusPhrase | string (get / set) | The status phrase of the response, e.g. OK. |
headers | Headers (get) | The headers of the response. |
body | Body (get) / string | Map | Array | URLSearchParams (set) | The body of the response. |
const response = new Response({
statusCode: 404,
statusPhrase: 'Not Found',
headers: {
'Content-Type': 'application/json',
'Cache-Control': 'no-cache'
},
textBody: '{"error": "Resource not found"}'
});
console.log(response.encode());
Body
The Body class represents the body of an HTTP request or response. Assigning a new value to request.body / response.body replaces the whole body.
| Method | Returns | Description |
|---|---|---|
parseText() | string | null | Parse the body as text. |
parseJSON() | object | null | Parse the body as JSON. |
parseURLSearchParams() | URLSearchParams | null | Parse the body as URL-encoded parameters. |
const bodyInstance = new Body('{"user": "alice"}');
const json = bodyInstance.parseJSON();
if (json) {
console.log('User:' + json.user);
} else {
console.error('Failed to parse JSON');
}
Headers
The Headers class represents HTTP headers.
| Method | Returns | Description |
|---|---|---|
append(name, value) | void | Append a value to the specified header. |
set(name, value) | void | Set (replace) the value of the specified header. |
get(name) | string | null | Get the value of the specified header. |
has(name) | boolean | Check if the specified header exists. |
delete(name) | void | Delete the specified header. |
forEach(callback, thisArg?) | void | Call a function for each header. |
entries() / keys() / values() | Iterator | Iterate over entries / keys / values. |
encode() | Array | Encode the headers into a serializable format. |
const headers = new Headers();
headers.append('Content-Type', 'application/json');
headers.set('Content-Length', '1024');
console.log(headers.get('Content-Type')); // 'application/json'
console.log(headers.has('Authorization')); // false
headers.forEach((value, name) => {
console.log(name + ' ' + value);
});
URLSearchParams
The URLSearchParams class represents URL query (or urlencoded body) parameters.
| Method | Returns | Description |
|---|---|---|
append(name, value) | void | Append a value to the specified parameter. |
set(name, value) | void | Set (replace) the value of the specified parameter. |
get(name) | string | null | Get the value of the specified parameter. |
has(name) | boolean | Check if the specified parameter exists. |
delete(name) | void | Delete the specified parameter. |
forEach(callback, thisArg?) | void | Call a function for each parameter. |
entries() / keys() / values() | Iterator | Iterate over entries / keys / values. |
sort() | void | Sort the parameters. |
toString() | string | Serialize to a urlencoded string. |
const params = new URLSearchParams({ key1: 'value1', key2: 'value2' });
console.log(params.get('key1')); // 'value1'
console.log(params.get('key3')); // null
params.forEach((value, key) => console.log(key + ' ' + value));
SharedPreferences
The SharedPreferences class provides local persistent key-value storage that survives script runs and app restarts (backed by system user defaults).
| Method | Returns | Description |
|---|---|---|
SharedPreferences.write(key, value) | void | Write a value (string / number / boolean / object / array). Writing null deletes the key. |
SharedPreferences.read(key) | any | Read the value associated with the key, or null if it does not exist. |
SharedPreferences.write("test_key", "test_value");
const value = SharedPreferences.read("test_key");
console.log(value);
SharedPreferences.write("cfg", {a: 1}); // objects are stored directly
SharedPreferences.write("cfg", null); // deletes "cfg"
sdk — Quick Request Scripts
sdk (alias pm) is injected only in Quick Request pre/post scripts. It bridges the app's variable storage (environments, global and runtime variables) and collects assertions, with a Postman-like API shape.
| Member | Description |
|---|---|
sdk.env.get(key) | Read an environment variable defined in the app. |
sdk.env.set(key, value) | Set an environment variable (same as sdk.setEnvVar). |
sdk.setEnvVar(key, value) | Write an env variable — collected and persisted back to the app. |
sdk.setVar(key, value) | Write a runtime (local) variable. |
sdk.setGlobalVar(key, value) | Write a global variable. |
sdk.getVar(key) | Read a runtime variable. |
sdk.test(name, fn) | Run a named assertion block; failures are collected and reported in the app. |
sdk.expect(value) | Assertion primitives: toBe, toEqual, toBeTruthy. |
sdk.jsonPath(object, path) | Dot-path lookup, e.g. "$.data.list[0].id". |
sdk.utils.uuid() | Same as crypto.randomUUID(). |
sdk.utils.base64Encode(s) / base64Decode(s) | Same as btoa / atob. |
sdk.utils.md5(s) | Same as $hash.md5. |
// Quick Request pre-request script: sign the request
async function onRequest(context, url, request) {
// read variables defined in the app's environment
const secret = sdk.env.get("secret") || "test-key";
sdk.expect(secret).toBeTruthy();
const ts = String(Date.now());
const bodyText = request.body && request.body.text ? request.body.text : '';
const sig = $hmac.sha256(ts + bodyText, secret);
// headers must be set via .set / .append
request.headers.set("X-Signature", sig);
request.headers.set("X-Timestamp", ts);
// persist variables back to the app
sdk.setEnvVar("lastTs", ts);
sdk.test("signature is 64 hex", () => {
sdk.expect(sig.length).toBe(64);
});
console.log("signed request for", url);
return request;
}
Assertion results are reported for pre-request scripts. In post-response scripts, assertions run but results are not collected.
Contexts
RewriteContext
The context object passed to rewrite scripts (onRequest / onResponse).
| Member | Type | Description |
|---|---|---|
isEnableOnRequest | boolean (get) | Whether the onRequest entry is enabled. |
isEnableOnResponse | boolean (get) | Whether the onResponse entry is enabled. |
parameters | object (get / set) | A parameters dictionary shared between onRequest and onResponse. |
scriptName | string (get) | The name of the script. |
CompletedContext
The context object passed to HTTP completed scripts.
| Member | Type | Description |
|---|---|---|
session | object (get) | The session object associated with the completed script. |
scriptName | string (get) | The name of the completed script. |
ScheduleContext
The context object passed to schedule scripts.
| Member | Type | Description |
|---|---|---|
parameters | object (get / set) | Parameters passed to the next runloop when set. |
cron | string (get) | The cron expression of the schedule. |
repeatedCount | number (get) | How many times the script has been repeated. |
scriptName | string (get) | The name of the scheduled script. |
Behavior Notes
- Uncaught exceptions fail the script. Errors (including
AbortErrorfromabort()) propagate to Hodor and the execution is reported as failed — partial rewrites made before the error are discarded, so guard risky blocks withtry / catch. - Timeout watchdog. Each script run has a time budget; a script that never finishes (e.g. an endless loop or a hung
await) is force-interrupted and reported as a timeout. - Errors as return values. Some APIs never throw:
$codec.base64Decodereturns"",$cryptoreturns"Error: ..."strings,$fs.readreturns"Error: ..."strings and$fs.inforeturnsundefined. Check these return values instead of relying ontry / catch. console.logvs$log. Both are visible in the script log view;$logadds timestamps and levels.- Script runtime persistence. Variables written with
sdk.setVarand files written with$fsremain available to subsequent executions of the same script;SharedPreferencespersists across app restarts.