Skip to main content

Command Palette

Search for a command to run...

SpriteDX - Implementing Computed Properties

Updated
2 min read
SpriteDX - Implementing Computed Properties

Here we go. 99 days til Alpha. Today, w will be implementing aforementioned computed properties.

Quick Recap

We will use following format to allow for arbitrary javascript to run inside a safe quick-js sandbox.

"inputs": {
  "fullName": {
    "type": "string",
    "computed": {
      "sandbox": "quickjs", // default, but required to be specified
      "with": {
        "firstName": "..userInfo.firstName",
        "lastName": "..userInfo.lastName"
      },
      "script": "`${firstName} ${lastName}`"
    }
  }
}

The main use-case again will be transforming inputs before feeding into the comfy workflow.

/**
 * Run compute in a safe sandbox (QuickJS)
 *
 * "computed": {
 *   "sandbox": "quickjs",
 *   "with": { "scene": "sceneDescription", "shots": "shots" },
 *   "script": "`[SCENE DESCRIPTION] ${scene}\\n\\n${shots.map((shot, i) => `[SHOT ${i + 1}] ${shot.prompt}`).join('\\n\\n')}`"
 * }
 */
function runSafeCompute<T = unknown>(
  computed: Computed,
  idPath: string,
  fromPath: string,
  pipeline: Pipeline,
  values: Record<string, unknown>
): T {
  const { sandbox, with: withMap, script } = computed;
  if (sandbox !== "quickjs") {
    throw new Error(`Unsupported compute sandbox: ${sandbox}`);
  }
  const withValues: Record<string, unknown> = {};
  for (const [varName, varSource] of Object.entries(withMap)) {
    withValues[varName] = getValueFromPipeline(varSource, fromPath, pipeline, values);
  }
  const QuickJS = globalThis.QuickJS;
  if (!QuickJS) {
    throw new Error("QuickJS is not loaded yet.");
  }
  const vm = QuickJS.newContext();
  try {
    Object.entries(withValues).forEach(([k, v]) => {
      const prepResult = vm.evalCode(`var ${k} = ${JSON.stringify(v)};`);
      if (prepResult.error) {
        const dumped = vm.dump(prepResult.error);
        prepResult.error.dispose();
        throw new Error(
          `Error when setting props for computed script for ${idPath}: ${JSON.stringify(dumped)}`
        );
      }
      prepResult.value.dispose();
    });
    const result = vm.evalCode(script);
    if (result.error) {
      const dumped = vm.dump(result.error);
      result.error.dispose();
      throw new Error(`Error in computed script for ${idPath}: ${JSON.stringify(dumped)}`);
    }
    const value = vm.dump(result.value);
    result.value.dispose();
    return value as T;
  } finally {
    vm.dispose();
  }
}

Here is the implementation.

It basically produces following script, and runs it inside QuickJS container.

var ${k} = ${JSON.stringify(v)};
{script}

Looks good so far.


—Sprited Dev 🌱