33 lines
1.8 KiB
JavaScript
33 lines
1.8 KiB
JavaScript
// Passive capture only. Supply GAC_NAMED_BAKED_CAPTURE={output_directory, modules}
|
|
// in the caller's private prelude. Each entry is {module, file}; filenames must
|
|
// be plain basenames. This does not load or execute any Lua closure itself.
|
|
const plan = globalThis.GAC_NAMED_BAKED_CAPTURE;
|
|
if (!plan || typeof plan.output_directory !== 'string' || !Array.isArray(plan.modules) ||
|
|
plan.modules.length < 1 || plan.modules.length > 5) throw Error('Exact bounded capture plan required');
|
|
const requested = new Map();
|
|
for (const entry of plan.modules) {
|
|
if (!/^Ui\.[A-Za-z0-9_.]+$/.test(entry.module) || !/^[a-z0-9_-]+\.luau$/.test(entry.file))
|
|
throw Error('Invalid exact module or output basename');
|
|
requested.set('@BakedLua/' + entry.module.replace(/\./g, '/') + '.bytes', entry.file);
|
|
}
|
|
const module = Process.getModuleByName('xluau.dll');
|
|
const load = module.getExportByName('xluaL_loadbuffer');
|
|
const completed = new Set();
|
|
Interceptor.attach(load, {
|
|
onEnter(args) {
|
|
try {
|
|
const name = args[3].readUtf8String();
|
|
if (!requested.has(name) || completed.has(name)) return;
|
|
const size = args[2].toUInt32();
|
|
if (size < 4 || size > 131072) throw Error('Named chunk outside capture size bound');
|
|
const bytes = args[1].readByteArray(size);
|
|
const path = plan.output_directory.replace(/[\\/]$/, '') + '/' + requested.get(name);
|
|
const output = new File(path, 'wb');
|
|
try { output.write(bytes); output.flush(); } finally { output.close(); }
|
|
completed.add(name);
|
|
send({kind:'CAPTURED', module:name, path, bytes:size});
|
|
} catch (error) { send({kind:'ERROR', error:String(error)}); }
|
|
}
|
|
});
|
|
send({kind:'ATTACHED', modules:Array.from(requested.keys()), policy:'passive exact-name loadbuffer capture; no closure execution'});
|