const hexString = process.argv[2];
if (!hexString) {
console.error("Usage: node decode_runner_config.js <hex_data>");
process.exit(1);
}
const buffer = Buffer.from(hexString, "hex");
const version = buffer.readUInt16LE(0);
const dataBuffer = buffer.slice(2);
console.log("Embedded VBARE Version:", version);
class BareDecoder {
constructor(buffer) {
this.buffer = buffer;
this.offset = 0;
}
readByte() {
return this.buffer[this.offset++];
}
readUint() {
let result = 0;
let shift = 0;
while (true) {
const byte = this.readByte();
result |= (byte & 0x7f) << shift;
if ((byte & 0x80) === 0) break;
shift += 7;
}
return result;
}
readU32() {
const value = this.buffer.readUInt32LE(this.offset);
this.offset += 4;
return value;
}
readU64() {
const value = this.buffer.readBigUInt64LE(this.offset);
this.offset += 8;
return value;
}
readData() {
const length = this.readUint();
const data = this.buffer.slice(this.offset, this.offset + length);
this.offset += length;
return data;
}
readString() {
return this.readData().toString("utf8");
}
readBool() {
return this.readByte() !== 0;
}
readEnum() {
return this.readUint();
}
readOptional(readFn) {
const hasValue = this.readByte();
if (hasValue === 0) return null;
return readFn.call(this);
}
readMap(keyReadFn, valueReadFn) {
const length = this.readUint();
const map = {};
for (let i = 0; i < length; i++) {
const key = keyReadFn.call(this);
const value = valueReadFn.call(this);
map[key] = value;
}
return map;
}
readUnion(variants, tagNames) {
const tag = this.readUint();
const value = variants[tag].call(this);
const result = {
tag: tagNames ? tagNames[tag] : tag,
};
if (value !== undefined && value !== null && value !== "Normal") {
result.value = value;
}
return result;
}
}
const decoder = new BareDecoder(dataBuffer);
console.log("Decoding runner config from hex:", hexString);
const runnerConfig = {};
const kind = decoder.readUnion(
[
() => {
const serverless = {};
serverless.url = decoder.readString();
serverless.headers = decoder.readMap(
() => decoder.readString(),
() => decoder.readString(),
);
serverless.request_lifespan = decoder.readU32();
serverless.max_concurrent_actors = decoder.readU64().toString();
serverless.drain_grace_period = decoder.readU32();
serverless.slots_per_runner = decoder.readU32();
serverless.min_runners = decoder.readU32();
serverless.max_runners = decoder.readU32();
serverless.runners_margin = decoder.readU32();
serverless.metadata_poll_interval = decoder.readOptional(
() => decoder.readU64().toString(),
);
return serverless;
},
() => "Normal",
],
["Serverless", "Normal"],
);
runnerConfig.kind = kind;
runnerConfig.metadata = decoder.readOptional(() => decoder.readString());
runnerConfig.drain_on_version_upgrade = decoder.readBool();
console.log("Decoded runner config:");
console.log(JSON.stringify(runnerConfig, null, 2));
console.log("\nBytes consumed:", decoder.offset, "/", dataBuffer.length);