Initial Commit
This commit is contained in:
@@ -0,0 +1,85 @@
|
||||
import { createHash } from "node:crypto";
|
||||
import { writeFile } from "node:fs/promises";
|
||||
import type { SerializedRoute } from "@suaveplan/api-types/sandbox-bridge";
|
||||
import {
|
||||
WASM_COMPILER_CODES,
|
||||
WasmCompilerError,
|
||||
} from "../error-codes/error-codes.js";
|
||||
|
||||
/** Inputs for {@link writeManifest}. */
|
||||
export interface WriteManifestOptions {
|
||||
/** Absolute path the manifest will be written to. */
|
||||
readonly manifestPath: string;
|
||||
/** Routes captured by the route-extract probe. */
|
||||
readonly routes: readonly SerializedRoute[];
|
||||
/** Pre-Javy bundled JS source — hashed into `sourceDigest`. */
|
||||
readonly bundledJs: string;
|
||||
/** Upstream Javy version pinned by the wrapper that compiled. */
|
||||
readonly javyVersion: string;
|
||||
/** This compiler's package version. */
|
||||
readonly compilerVersion: string;
|
||||
/** RFC 3339 UTC timestamp; defaults to `new Date().toISOString()`. */
|
||||
readonly compiledAt?: string;
|
||||
/**
|
||||
* Caller-supplied filesystem writer — defaults to
|
||||
* `node:fs/promises#writeFile`. Tests inject a recorder.
|
||||
*/
|
||||
readonly fsWrite?: (path: string, data: string) => Promise<void>;
|
||||
}
|
||||
|
||||
/** The full manifest record shape. */
|
||||
export interface CompiledPluginManifest {
|
||||
readonly routes: readonly SerializedRoute[];
|
||||
readonly abiVersion: string;
|
||||
readonly abiVariant: "wasi-stdio";
|
||||
readonly javyVersion: string;
|
||||
readonly compilerVersion: string;
|
||||
readonly compiledAt: string;
|
||||
readonly sourceDigest: string;
|
||||
}
|
||||
|
||||
/** The current compiler ABI version — semver string. */
|
||||
export const COMPILER_ABI_VERSION = "1.0.0" as const;
|
||||
|
||||
/**
|
||||
* Emit the `<basename>.wasm.json` sidecar. Refuses empty `routes`
|
||||
* with `WASM_COMPILER.MANIFEST_MISSING_ROUTES` — a routeless plugin
|
||||
* cannot route a single request through the bridge, so shipping the
|
||||
* artifact would be pointless.
|
||||
*
|
||||
* Returns the manifest record so the orchestrator can include it in
|
||||
* the compile result without re-reading from disk.
|
||||
*/
|
||||
export async function writeManifest(
|
||||
options: WriteManifestOptions
|
||||
): Promise<CompiledPluginManifest> {
|
||||
if (options.routes.length === 0) {
|
||||
throw new WasmCompilerError(
|
||||
WASM_COMPILER_CODES.MANIFEST_MISSING_ROUTES,
|
||||
"error.wasm_compiler.manifest_missing_routes",
|
||||
{
|
||||
context: { manifestPath: options.manifestPath },
|
||||
}
|
||||
);
|
||||
}
|
||||
const sourceDigest = createHash("sha256")
|
||||
.update(options.bundledJs)
|
||||
.digest("hex");
|
||||
const compiledAt = options.compiledAt ?? new Date().toISOString();
|
||||
const manifest: CompiledPluginManifest = {
|
||||
routes: options.routes,
|
||||
abiVersion: COMPILER_ABI_VERSION,
|
||||
abiVariant: "wasi-stdio",
|
||||
javyVersion: options.javyVersion,
|
||||
compilerVersion: options.compilerVersion,
|
||||
compiledAt,
|
||||
sourceDigest,
|
||||
};
|
||||
const writer = options.fsWrite ?? defaultWriter;
|
||||
await writer(options.manifestPath, JSON.stringify(manifest, null, 2));
|
||||
return manifest;
|
||||
}
|
||||
|
||||
async function defaultWriter(path: string, data: string): Promise<void> {
|
||||
await writeFile(path, data, "utf8");
|
||||
}
|
||||
Reference in New Issue
Block a user