chore(vendor): import pi 0.85.1
Imported as a linear vendor commit so forge rebases do not replay the upstream root tree. git-subtree-dir: third_party/pi git-subtree-split: d981de1229ef899957bbe968bc8dcda02a21f477
This commit is contained in:
416
third_party/pi/packages/chord/src/node/bundle-loader.ts
vendored
Normal file
416
third_party/pi/packages/chord/src/node/bundle-loader.ts
vendored
Normal file
@@ -0,0 +1,416 @@
|
||||
import { createHash } from "node:crypto";
|
||||
import { mkdir, mkdtemp, readFile, rm, writeFile } from "node:fs/promises";
|
||||
import { createRequire, isBuiltin } from "node:module";
|
||||
import { tmpdir } from "node:os";
|
||||
import { basename, dirname, isAbsolute, join, resolve } from "node:path";
|
||||
import { fileURLToPath } from "node:url";
|
||||
import { compileFunction } from "node:vm";
|
||||
import type { Facet, FacetLoader, LoadedFacets } from "../types.ts";
|
||||
import {
|
||||
FACET_BUNDLE_ARTIFACT_FORMAT,
|
||||
FACET_BUNDLE_ARTIFACT_FORMAT_VERSION,
|
||||
FACET_BUNDLE_FORMAT,
|
||||
FACET_BUNDLE_FORMAT_VERSION,
|
||||
FACET_BUNDLE_MANIFEST_FILE,
|
||||
type FacetBundleArtifact,
|
||||
type FacetBundleEntry,
|
||||
type FacetBundleManifest,
|
||||
} from "./manifest.ts";
|
||||
|
||||
export type FacetBundleExternalResolver = (specifier: string) => string | URL | undefined;
|
||||
|
||||
export interface FacetBundleLoaderOptions {
|
||||
readonly manifestPath: string | URL;
|
||||
readonly entry: string;
|
||||
/** Verify the entry's SHA-256 integrity before evaluating it. Defaults to true. */
|
||||
readonly verifyIntegrity?: boolean;
|
||||
/** Resolve host-provided external imports when the bundle is outside the host's package tree. */
|
||||
readonly resolveExternal?: FacetBundleExternalResolver;
|
||||
}
|
||||
|
||||
export interface FacetBundleArtifactLoaderOptions {
|
||||
readonly artifact: unknown;
|
||||
/** Resolve host-provided external imports against the receiving application. */
|
||||
readonly resolveExternal?: FacetBundleExternalResolver;
|
||||
/** Parent directory for materialized module generations. Defaults to the operating system temp directory. */
|
||||
readonly temporaryDirectory?: string;
|
||||
}
|
||||
|
||||
interface CommonJsModule {
|
||||
exports: unknown;
|
||||
}
|
||||
|
||||
/** Read and validate a versioned facet bundle manifest. */
|
||||
export async function readFacetBundleManifest(path: string | URL): Promise<FacetBundleManifest> {
|
||||
const manifestPath = toFilePath(path);
|
||||
let parsed: unknown;
|
||||
try {
|
||||
parsed = JSON.parse(await readFile(manifestPath, "utf8"));
|
||||
} catch (error) {
|
||||
throw new Error(`Could not read facet bundle manifest ${manifestPath}`, { cause: error });
|
||||
}
|
||||
return validateManifest(parsed, manifestPath);
|
||||
}
|
||||
|
||||
/** Read and verify one transportable entry from a facet bundle on disk. */
|
||||
export async function readFacetBundleArtifact(options: {
|
||||
readonly manifestPath: string | URL;
|
||||
readonly entry: string;
|
||||
}): Promise<FacetBundleArtifact> {
|
||||
if (options.entry.length === 0) throw new TypeError("Facet bundle entry name must not be empty");
|
||||
const manifestPath = toFilePath(options.manifestPath);
|
||||
const manifest = await readFacetBundleManifest(manifestPath);
|
||||
const entry = manifest.entries[options.entry];
|
||||
if (entry === undefined) throw new Error(`Facet bundle ${manifest.plugin.id} has no entry named ${options.entry}`);
|
||||
const modulePath = resolveBundleFile(manifestPath, entry.file, "entry");
|
||||
const source = await readFile(modulePath, "utf8");
|
||||
verifySource(source, entry);
|
||||
const sourceMapContents =
|
||||
entry.sourceMap === undefined
|
||||
? undefined
|
||||
: await readFile(resolveBundleFile(manifestPath, entry.sourceMap, "source map"), "utf8");
|
||||
return Object.freeze({
|
||||
format: FACET_BUNDLE_ARTIFACT_FORMAT,
|
||||
formatVersion: FACET_BUNDLE_ARTIFACT_FORMAT_VERSION,
|
||||
plugin: manifest.plugin,
|
||||
entryName: options.entry,
|
||||
entry,
|
||||
source,
|
||||
...(sourceMapContents === undefined ? {} : { sourceMapContents }),
|
||||
});
|
||||
}
|
||||
|
||||
/** Materialize a transported artifact and create a fresh VM-compiled CommonJS generation for each load. */
|
||||
export function createFacetBundleArtifactLoader(options: FacetBundleArtifactLoaderOptions): FacetLoader {
|
||||
const artifact = validateArtifact(options.artifact);
|
||||
const temporaryParent = resolve(options.temporaryDirectory ?? tmpdir());
|
||||
return {
|
||||
async load(): Promise<LoadedFacets> {
|
||||
await mkdir(temporaryParent, { recursive: true });
|
||||
const directory = await mkdtemp(join(temporaryParent, "chord-facet-"));
|
||||
try {
|
||||
await materializeArtifact(directory, artifact);
|
||||
const loaded = await createFacetBundleLoader({
|
||||
manifestPath: join(directory, FACET_BUNDLE_MANIFEST_FILE),
|
||||
entry: artifact.entryName,
|
||||
resolveExternal: options.resolveExternal,
|
||||
}).load();
|
||||
let disposed = false;
|
||||
return {
|
||||
get facets() {
|
||||
return loaded.facets;
|
||||
},
|
||||
async dispose() {
|
||||
if (disposed) return;
|
||||
disposed = true;
|
||||
const errors: unknown[] = [];
|
||||
try {
|
||||
await loaded.dispose();
|
||||
} catch (error) {
|
||||
errors.push(error);
|
||||
}
|
||||
try {
|
||||
await rm(directory, { force: true, recursive: true });
|
||||
} catch (error) {
|
||||
errors.push(error);
|
||||
}
|
||||
if (errors.length === 1) throw errors[0];
|
||||
if (errors.length > 1) throw new AggregateError(errors, "Failed to dispose facet bundle artifact");
|
||||
},
|
||||
};
|
||||
} catch (error) {
|
||||
try {
|
||||
await rm(directory, { force: true, recursive: true });
|
||||
} catch (cleanupError) {
|
||||
throw new AggregateError([error, cleanupError], "Facet bundle artifact loading and cleanup failed");
|
||||
}
|
||||
throw error;
|
||||
}
|
||||
},
|
||||
};
|
||||
}
|
||||
|
||||
/** Create a reusable loader for one opaque entry in a facet bundle manifest. */
|
||||
export function createFacetBundleLoader(options: FacetBundleLoaderOptions): FacetLoader {
|
||||
if (options.entry.length === 0) throw new TypeError("Facet bundle entry name must not be empty");
|
||||
const manifestPath = toFilePath(options.manifestPath);
|
||||
return {
|
||||
async load(): Promise<LoadedFacets> {
|
||||
const manifest = await readFacetBundleManifest(manifestPath);
|
||||
const entry = manifest.entries[options.entry];
|
||||
if (entry === undefined) {
|
||||
throw new Error(`Facet bundle ${manifest.plugin.id} has no entry named ${options.entry}`);
|
||||
}
|
||||
const modulePath = resolveBundleFile(manifestPath, entry.file, "entry");
|
||||
try {
|
||||
const source = await readFile(modulePath, "utf8");
|
||||
if (options.verifyIntegrity !== false) verifySource(source, entry);
|
||||
const exported = executeCommonJsModule(source, modulePath, entry.externalImports, options.resolveExternal);
|
||||
let facets = facetsFromModule(exported, manifest.plugin.id, options.entry);
|
||||
let disposed = false;
|
||||
return {
|
||||
get facets() {
|
||||
return facets;
|
||||
},
|
||||
async dispose() {
|
||||
if (disposed) return;
|
||||
disposed = true;
|
||||
facets = Object.freeze([]);
|
||||
},
|
||||
};
|
||||
} catch (error) {
|
||||
const detail = error instanceof Error ? `: ${error.message}` : "";
|
||||
throw new Error(`Could not load facet bundle entry ${manifest.plugin.id}/${options.entry}${detail}`, {
|
||||
cause: error,
|
||||
});
|
||||
}
|
||||
},
|
||||
};
|
||||
}
|
||||
|
||||
function executeCommonJsModule(
|
||||
source: string,
|
||||
modulePath: string,
|
||||
externalImports: readonly string[],
|
||||
resolver?: FacetBundleExternalResolver,
|
||||
): unknown {
|
||||
const requireFromModule = createRequire(modulePath);
|
||||
const externalTargets = new Map<string, string>();
|
||||
for (const specifier of externalImports) {
|
||||
if (!isBuiltin(specifier)) validatePackageSpecifier(specifier);
|
||||
externalTargets.set(specifier, toRequireSpecifier(resolveExternalTarget(specifier, resolver)));
|
||||
}
|
||||
const targetFor = (specifier: string): string => {
|
||||
const target = externalTargets.get(specifier);
|
||||
if (target === undefined) throw new Error(`Facet bundle required undeclared external import: ${specifier}`);
|
||||
return target;
|
||||
};
|
||||
const requireExternal = Object.assign((specifier: string): unknown => requireFromModule(targetFor(specifier)), {
|
||||
resolve: (specifier: string): string => requireFromModule.resolve(targetFor(specifier)),
|
||||
});
|
||||
const commonJsModule: CommonJsModule = { exports: Object.create(null) };
|
||||
const compiled = compileFunction(source, ["exports", "require", "module", "__filename", "__dirname"], {
|
||||
filename: modulePath,
|
||||
});
|
||||
Reflect.apply(compiled, commonJsModule.exports, [
|
||||
commonJsModule.exports,
|
||||
requireExternal,
|
||||
commonJsModule,
|
||||
modulePath,
|
||||
dirname(modulePath),
|
||||
]);
|
||||
return commonJsModule.exports;
|
||||
}
|
||||
|
||||
function toRequireSpecifier(target: string): string {
|
||||
if (isAbsolute(target) || isBuiltin(target)) return target;
|
||||
let url: URL;
|
||||
try {
|
||||
url = new URL(target);
|
||||
} catch {
|
||||
return target;
|
||||
}
|
||||
if (url.protocol === "file:") return fileURLToPath(url);
|
||||
if (url.protocol === "node:") return url.href;
|
||||
throw new Error(`Facet bundle external target must be a file, package, or built-in module: ${target}`);
|
||||
}
|
||||
|
||||
function toFilePath(path: string | URL): string {
|
||||
if (typeof path === "string") return resolve(path);
|
||||
if (path.protocol !== "file:") throw new TypeError(`Facet bundle manifest must be a file URL, not ${path.protocol}`);
|
||||
return fileURLToPath(path);
|
||||
}
|
||||
|
||||
function resolveBundleFile(manifestPath: string, file: string, label: string): string {
|
||||
if (file.length === 0 || isAbsolute(file) || basename(file) !== file || file === "." || file === "..") {
|
||||
throw new Error(`Facet bundle ${label} must be a filename relative to its manifest`);
|
||||
}
|
||||
return resolve(dirname(manifestPath), file);
|
||||
}
|
||||
|
||||
function verifySource(source: string, entry: FacetBundleEntry): void {
|
||||
const expected = parseIntegrity(entry.integrity);
|
||||
const actual = createHash("sha256").update(source, "utf8").digest("base64");
|
||||
if (actual !== expected) throw new Error(`Facet bundle integrity check failed for ${entry.file}`);
|
||||
}
|
||||
|
||||
function parseIntegrity(integrity: string): string {
|
||||
const prefix = "sha256-";
|
||||
if (!integrity.startsWith(prefix) || integrity.length === prefix.length) {
|
||||
throw new Error("Facet bundle entry has an invalid SHA-256 integrity value");
|
||||
}
|
||||
return integrity.slice(prefix.length);
|
||||
}
|
||||
|
||||
function facetsFromModule(imported: unknown, pluginId: string, entryName: string): readonly Facet[] {
|
||||
if (!isRecord(imported)) throw new Error(`Facet bundle entry ${pluginId}/${entryName} did not export a module`);
|
||||
const exported = imported.default;
|
||||
const candidates: readonly unknown[] = Array.isArray(exported) ? (exported as readonly unknown[]) : [exported];
|
||||
if (candidates.length === 0) {
|
||||
throw new Error(`Facet bundle entry ${pluginId}/${entryName} exported no facets`);
|
||||
}
|
||||
const facets: Facet[] = [];
|
||||
for (const candidate of candidates) {
|
||||
if (!isRecord(candidate) || typeof candidate.id !== "string" || candidate.id.length === 0) {
|
||||
throw new Error(`Facet bundle entry ${pluginId}/${entryName} has a facet with an invalid ID`);
|
||||
}
|
||||
if (typeof candidate.setup !== "function") {
|
||||
throw new Error(`Facet bundle entry ${pluginId}/${entryName} facet ${candidate.id} has no setup function`);
|
||||
}
|
||||
facets.push(candidate as unknown as Facet);
|
||||
}
|
||||
const ids = facets.map(({ id }) => id);
|
||||
if (new Set(ids).size !== ids.length) {
|
||||
throw new Error(`Facet bundle entry ${pluginId}/${entryName} exports duplicate facet IDs`);
|
||||
}
|
||||
return Object.freeze(facets);
|
||||
}
|
||||
|
||||
function validateArtifact(value: unknown): FacetBundleArtifact {
|
||||
if (
|
||||
!isRecord(value) ||
|
||||
value.format !== FACET_BUNDLE_ARTIFACT_FORMAT ||
|
||||
value.formatVersion !== FACET_BUNDLE_ARTIFACT_FORMAT_VERSION ||
|
||||
typeof value.entryName !== "string" ||
|
||||
value.entryName.length === 0 ||
|
||||
typeof value.source !== "string"
|
||||
) {
|
||||
throw new Error("Invalid facet bundle artifact");
|
||||
}
|
||||
const manifest = validateManifest(
|
||||
{
|
||||
format: FACET_BUNDLE_FORMAT,
|
||||
formatVersion: FACET_BUNDLE_FORMAT_VERSION,
|
||||
plugin: value.plugin,
|
||||
entries: { [value.entryName]: value.entry },
|
||||
},
|
||||
"facet bundle artifact",
|
||||
);
|
||||
const entry = manifest.entries[value.entryName]!;
|
||||
if (entry.sourceMap === undefined) {
|
||||
if (value.sourceMapContents !== undefined) {
|
||||
throw new Error("Facet bundle artifact has source map contents without a source map");
|
||||
}
|
||||
} else if (typeof value.sourceMapContents !== "string") {
|
||||
throw new Error("Facet bundle artifact is missing its source map contents");
|
||||
}
|
||||
verifySource(value.source, entry);
|
||||
return Object.freeze({
|
||||
format: FACET_BUNDLE_ARTIFACT_FORMAT,
|
||||
formatVersion: FACET_BUNDLE_ARTIFACT_FORMAT_VERSION,
|
||||
plugin: manifest.plugin,
|
||||
entryName: value.entryName,
|
||||
entry,
|
||||
source: value.source,
|
||||
...(value.sourceMapContents === undefined ? {} : { sourceMapContents: value.sourceMapContents }),
|
||||
});
|
||||
}
|
||||
|
||||
async function materializeArtifact(directory: string, artifact: FacetBundleArtifact): Promise<void> {
|
||||
const manifest: FacetBundleManifest = {
|
||||
format: FACET_BUNDLE_FORMAT,
|
||||
formatVersion: FACET_BUNDLE_FORMAT_VERSION,
|
||||
plugin: artifact.plugin,
|
||||
entries: { [artifact.entryName]: artifact.entry },
|
||||
};
|
||||
await Promise.all([
|
||||
writeFile(join(directory, artifact.entry.file), artifact.source, "utf8"),
|
||||
writeFile(join(directory, FACET_BUNDLE_MANIFEST_FILE), `${JSON.stringify(manifest, null, 2)}\n`, "utf8"),
|
||||
...(artifact.entry.sourceMap === undefined
|
||||
? []
|
||||
: [writeFile(join(directory, artifact.entry.sourceMap), artifact.sourceMapContents!, "utf8")]),
|
||||
]);
|
||||
}
|
||||
|
||||
function resolveExternalTarget(specifier: string, resolver?: FacetBundleExternalResolver): string {
|
||||
const resolved = resolver?.(specifier);
|
||||
if (resolved !== undefined) return typeof resolved === "string" ? resolved : resolved.href;
|
||||
const extension = import.meta.url.endsWith(".ts") ? "ts" : "js";
|
||||
if (specifier === "@earendil-works/chord") return new URL(`../index.${extension}`, import.meta.url).href;
|
||||
if (specifier === "@earendil-works/chord/context") {
|
||||
return new URL(`../context/index.${extension}`, import.meta.url).href;
|
||||
}
|
||||
if (specifier === "@earendil-works/chord/node") return new URL(`../node.${extension}`, import.meta.url).href;
|
||||
return import.meta.resolve(specifier);
|
||||
}
|
||||
|
||||
function validatePackageSpecifier(specifier: string): void {
|
||||
const segments = specifier.split("/");
|
||||
const packageParts = specifier.startsWith("@") ? 2 : 1;
|
||||
if (
|
||||
specifier.startsWith(".") ||
|
||||
specifier.startsWith("/") ||
|
||||
specifier.startsWith("#") ||
|
||||
specifier.includes(":") ||
|
||||
specifier.includes("\\") ||
|
||||
segments.length < packageParts ||
|
||||
segments.some((part) => part.length === 0 || part === "." || part === "..")
|
||||
) {
|
||||
throw new Error(`Facet bundle artifact has an unsupported external import: ${specifier}`);
|
||||
}
|
||||
}
|
||||
|
||||
function validateManifest(value: unknown, path: string): FacetBundleManifest {
|
||||
if (!isRecord(value) || value.format !== FACET_BUNDLE_FORMAT) {
|
||||
throw new Error(`Invalid facet bundle manifest format in ${path}`);
|
||||
}
|
||||
if (value.formatVersion !== FACET_BUNDLE_FORMAT_VERSION) {
|
||||
throw new Error(`Unsupported facet bundle manifest version in ${path}: ${String(value.formatVersion)}`);
|
||||
}
|
||||
if (!isRecord(value.plugin) || typeof value.plugin.id !== "string" || value.plugin.id.length === 0) {
|
||||
throw new Error(`Facet bundle manifest has an invalid plugin identity in ${path}`);
|
||||
}
|
||||
if (
|
||||
value.plugin.version !== undefined &&
|
||||
(typeof value.plugin.version !== "string" || value.plugin.version.length === 0)
|
||||
) {
|
||||
throw new Error(`Facet bundle manifest has an invalid plugin version in ${path}`);
|
||||
}
|
||||
if (!isRecord(value.entries) || Object.keys(value.entries).length === 0) {
|
||||
throw new Error(`Facet bundle manifest has no entries in ${path}`);
|
||||
}
|
||||
const entries: Record<string, FacetBundleEntry> = {};
|
||||
for (const [name, candidate] of Object.entries(value.entries)) {
|
||||
if (name.length === 0 || !isRecord(candidate)) {
|
||||
throw new Error(`Facet bundle manifest has an invalid entry in ${path}`);
|
||||
}
|
||||
if (typeof candidate.file !== "string") throw new Error(`Facet bundle entry ${name} has no file`);
|
||||
resolveBundleFile(path, candidate.file, `entry ${name}`);
|
||||
if (typeof candidate.integrity !== "string") throw new Error(`Facet bundle entry ${name} has no integrity`);
|
||||
parseIntegrity(candidate.integrity);
|
||||
if (
|
||||
!Array.isArray(candidate.externalImports) ||
|
||||
candidate.externalImports.some((item) => typeof item !== "string")
|
||||
) {
|
||||
throw new Error(`Facet bundle entry ${name} has invalid external imports`);
|
||||
}
|
||||
const externalImports = Object.freeze([...(candidate.externalImports as readonly string[])]);
|
||||
if (new Set(externalImports).size !== externalImports.length) {
|
||||
throw new Error(`Facet bundle entry ${name} has duplicate external imports`);
|
||||
}
|
||||
if (candidate.sourceMap !== undefined) {
|
||||
if (typeof candidate.sourceMap !== "string")
|
||||
throw new Error(`Facet bundle entry ${name} has an invalid source map`);
|
||||
resolveBundleFile(path, candidate.sourceMap, `entry ${name} source map`);
|
||||
}
|
||||
entries[name] = Object.freeze({
|
||||
file: candidate.file,
|
||||
integrity: candidate.integrity,
|
||||
externalImports,
|
||||
...(candidate.sourceMap === undefined ? {} : { sourceMap: candidate.sourceMap }),
|
||||
});
|
||||
}
|
||||
return Object.freeze({
|
||||
format: FACET_BUNDLE_FORMAT,
|
||||
formatVersion: FACET_BUNDLE_FORMAT_VERSION,
|
||||
plugin: Object.freeze({
|
||||
id: value.plugin.id,
|
||||
...(value.plugin.version === undefined ? {} : { version: value.plugin.version }),
|
||||
}),
|
||||
entries: Object.freeze(entries),
|
||||
});
|
||||
}
|
||||
|
||||
function isRecord(value: unknown): value is Record<string, unknown> {
|
||||
return typeof value === "object" && value !== null && !Array.isArray(value);
|
||||
}
|
||||
222
third_party/pi/packages/chord/src/node/bundle.ts
vendored
Normal file
222
third_party/pi/packages/chord/src/node/bundle.ts
vendored
Normal file
@@ -0,0 +1,222 @@
|
||||
import { createHash, randomUUID } from "node:crypto";
|
||||
import { mkdir, readFile, rename, rm, stat, writeFile } from "node:fs/promises";
|
||||
import { basename, dirname, extname, join, relative, resolve, sep } from "node:path";
|
||||
import { type BuildOptions, build, type Message } from "esbuild";
|
||||
import {
|
||||
FACET_BUNDLE_FORMAT,
|
||||
FACET_BUNDLE_FORMAT_VERSION,
|
||||
FACET_BUNDLE_MANIFEST_FILE,
|
||||
type FacetBundleEntry,
|
||||
type FacetBundleManifest,
|
||||
} from "./manifest.ts";
|
||||
|
||||
export type FacetBundlePlatform = "node" | "browser" | "neutral";
|
||||
|
||||
export interface BundleFacetsOptions {
|
||||
readonly plugin: {
|
||||
readonly id: string;
|
||||
readonly version?: string;
|
||||
};
|
||||
/** Opaque application-selected entry names mapped to TypeScript or JavaScript source files. */
|
||||
readonly entries: Readonly<Record<string, string>>;
|
||||
readonly outdir: string;
|
||||
readonly workingDirectory?: string;
|
||||
/** Additional package imports intentionally left for the loading application to resolve. */
|
||||
readonly external?: readonly string[];
|
||||
readonly sourceMap?: boolean;
|
||||
readonly minify?: boolean;
|
||||
readonly define?: Readonly<Record<string, string>>;
|
||||
readonly platform?: FacetBundlePlatform;
|
||||
readonly target?: string | readonly string[];
|
||||
}
|
||||
|
||||
export interface BundleFacetsResult {
|
||||
readonly manifest: FacetBundleManifest;
|
||||
readonly manifestPath: string;
|
||||
}
|
||||
|
||||
/** Bundle each opaque facet entry into an independent content-addressed CommonJS file. */
|
||||
export async function bundleFacets(options: BundleFacetsOptions): Promise<BundleFacetsResult> {
|
||||
validateOptions(options);
|
||||
const workingDirectory = resolve(options.workingDirectory ?? process.cwd());
|
||||
const outputDirectory = resolve(workingDirectory, options.outdir);
|
||||
const outputParent = dirname(outputDirectory);
|
||||
await mkdir(outputParent, { recursive: true });
|
||||
const temporaryDirectory = join(outputParent, `.${basename(outputDirectory)}.tmp-${randomUUID()}`);
|
||||
await mkdir(temporaryDirectory);
|
||||
try {
|
||||
const entries: Record<string, FacetBundleEntry> = {};
|
||||
for (const [entryName, source] of Object.entries(options.entries).sort(([left], [right]) =>
|
||||
left.localeCompare(right),
|
||||
)) {
|
||||
entries[entryName] = await bundleEntry({
|
||||
entryName,
|
||||
source: resolve(workingDirectory, source),
|
||||
temporaryDirectory,
|
||||
workingDirectory,
|
||||
options,
|
||||
});
|
||||
}
|
||||
const manifest: FacetBundleManifest = Object.freeze({
|
||||
format: FACET_BUNDLE_FORMAT,
|
||||
formatVersion: FACET_BUNDLE_FORMAT_VERSION,
|
||||
plugin: Object.freeze({
|
||||
id: options.plugin.id,
|
||||
...(options.plugin.version === undefined ? {} : { version: options.plugin.version }),
|
||||
}),
|
||||
entries: Object.freeze(entries),
|
||||
});
|
||||
await writeFile(join(temporaryDirectory, FACET_BUNDLE_MANIFEST_FILE), `${JSON.stringify(manifest, null, 2)}\n`);
|
||||
await replaceDirectory(temporaryDirectory, outputDirectory);
|
||||
return Object.freeze({
|
||||
manifest,
|
||||
manifestPath: join(outputDirectory, FACET_BUNDLE_MANIFEST_FILE),
|
||||
});
|
||||
} catch (error) {
|
||||
await rm(temporaryDirectory, { force: true, recursive: true });
|
||||
throw error;
|
||||
}
|
||||
}
|
||||
|
||||
async function bundleEntry(input: {
|
||||
readonly entryName: string;
|
||||
readonly source: string;
|
||||
readonly temporaryDirectory: string;
|
||||
readonly workingDirectory: string;
|
||||
readonly options: BundleFacetsOptions;
|
||||
}): Promise<FacetBundleEntry> {
|
||||
const entryPrefix = `facet-${shortHash(input.entryName)}`;
|
||||
const requestedPlatform = input.options.platform ?? "node";
|
||||
const buildOptions: BuildOptions = {
|
||||
absWorkingDir: input.workingDirectory,
|
||||
banner: { js: '"use strict";' },
|
||||
bundle: true,
|
||||
define: input.options.define,
|
||||
entryNames: `${entryPrefix}-[hash]`,
|
||||
entryPoints: [input.source],
|
||||
external: [...new Set(["@earendil-works/chord", "@earendil-works/chord/*", ...(input.options.external ?? [])])],
|
||||
format: "cjs",
|
||||
legalComments: "none",
|
||||
logLevel: "silent",
|
||||
metafile: true,
|
||||
minify: input.options.minify ?? false,
|
||||
outdir: input.temporaryDirectory,
|
||||
outExtension: { ".js": ".cjs" },
|
||||
platform: requestedPlatform,
|
||||
sourcemap: input.options.sourceMap === true ? "external" : false,
|
||||
supported: { "dynamic-import": false },
|
||||
target:
|
||||
input.options.target === undefined
|
||||
? requestedPlatform === "node"
|
||||
? "node22.19"
|
||||
: "es2022"
|
||||
: typeof input.options.target === "string"
|
||||
? input.options.target
|
||||
: [...input.options.target],
|
||||
write: true,
|
||||
};
|
||||
let result: Awaited<ReturnType<typeof build>>;
|
||||
try {
|
||||
result = await build(buildOptions);
|
||||
} catch (error) {
|
||||
const diagnostics = esbuildMessages(error);
|
||||
const detail = diagnostics.length === 0 ? "" : `\n${diagnostics.join("\n")}`;
|
||||
throw new Error(`Could not bundle facet entry ${input.entryName}${detail}`, { cause: error });
|
||||
}
|
||||
const metafile = result.metafile;
|
||||
if (metafile === undefined) throw new Error(`Facet entry ${input.entryName} produced no build metadata`);
|
||||
const outputs = Object.entries(metafile.outputs).filter(
|
||||
([path, output]) => output.entryPoint !== undefined && extname(path) === ".cjs",
|
||||
);
|
||||
if (outputs.length !== 1)
|
||||
throw new Error(`Facet entry ${input.entryName} did not produce exactly one JavaScript file`);
|
||||
const [outputPath, metadata] = outputs[0]!;
|
||||
const absoluteOutputPath = resolve(input.workingDirectory, outputPath);
|
||||
const file = relative(input.temporaryDirectory, absoluteOutputPath);
|
||||
if (file.length === 0 || file.startsWith(`..${sep}`) || basename(file) !== file) {
|
||||
throw new Error(`Facet entry ${input.entryName} produced an invalid output path`);
|
||||
}
|
||||
const sourceMap = input.options.sourceMap === true ? `${file}.map` : undefined;
|
||||
const allowedOutputs = new Set([absoluteOutputPath]);
|
||||
if (sourceMap !== undefined) allowedOutputs.add(join(input.temporaryDirectory, sourceMap));
|
||||
const unexpectedOutputs = Object.keys(metafile.outputs)
|
||||
.map((path) => resolve(input.workingDirectory, path))
|
||||
.filter((path) => !allowedOutputs.has(path));
|
||||
if (unexpectedOutputs.length > 0) {
|
||||
throw new Error(`Facet entry ${input.entryName} produced files other than its JavaScript bundle and source map`);
|
||||
}
|
||||
const contents = await readFile(absoluteOutputPath);
|
||||
if (sourceMap !== undefined) await stat(join(input.temporaryDirectory, sourceMap));
|
||||
return Object.freeze({
|
||||
file,
|
||||
integrity: `sha256-${createHash("sha256").update(contents).digest("base64")}`,
|
||||
externalImports: Object.freeze(
|
||||
[...new Set(metadata.imports.filter(({ external }) => external).map(({ path }) => path))].sort(),
|
||||
),
|
||||
...(sourceMap === undefined ? {} : { sourceMap }),
|
||||
});
|
||||
}
|
||||
|
||||
function validateOptions(options: BundleFacetsOptions): void {
|
||||
if (options.plugin.id.length === 0) throw new TypeError("Facet bundle plugin ID must not be empty");
|
||||
if (options.plugin.version !== undefined && options.plugin.version.length === 0) {
|
||||
throw new TypeError("Facet bundle plugin version must not be empty");
|
||||
}
|
||||
const entries = Object.entries(options.entries);
|
||||
if (entries.length === 0) throw new TypeError("Facet bundle must contain at least one entry");
|
||||
for (const [name, source] of entries) {
|
||||
if (name.length === 0) throw new TypeError("Facet bundle entry name must not be empty");
|
||||
if (source.length === 0) throw new TypeError(`Facet bundle entry ${name} must have a source path`);
|
||||
}
|
||||
for (const external of options.external ?? []) {
|
||||
if (external.length === 0) throw new TypeError("Facet bundle external import must not be empty");
|
||||
}
|
||||
}
|
||||
|
||||
async function replaceDirectory(temporaryDirectory: string, outputDirectory: string): Promise<void> {
|
||||
const backupDirectory = `${outputDirectory}.old-${randomUUID()}`;
|
||||
let movedExisting = false;
|
||||
try {
|
||||
await rename(outputDirectory, backupDirectory);
|
||||
movedExisting = true;
|
||||
} catch (error) {
|
||||
if (!isMissingPath(error)) throw error;
|
||||
}
|
||||
try {
|
||||
await rename(temporaryDirectory, outputDirectory);
|
||||
} catch (error) {
|
||||
if (movedExisting) await rename(backupDirectory, outputDirectory);
|
||||
throw error;
|
||||
}
|
||||
if (movedExisting) await rm(backupDirectory, { force: true, recursive: true });
|
||||
}
|
||||
|
||||
function shortHash(value: string): string {
|
||||
return createHash("sha256").update(value).digest("hex").slice(0, 12);
|
||||
}
|
||||
|
||||
function esbuildMessages(error: unknown): string[] {
|
||||
if (!isRecord(error) || !Array.isArray(error.errors)) return [];
|
||||
return (error.errors as readonly unknown[]).flatMap((candidate) =>
|
||||
isEsbuildMessage(candidate) ? [formatEsbuildMessage(candidate)] : [],
|
||||
);
|
||||
}
|
||||
|
||||
function formatEsbuildMessage(message: Message): string {
|
||||
const location = message.location;
|
||||
return location === null
|
||||
? message.text
|
||||
: `${location.file}:${location.line}:${location.column + 1}: ${message.text}`;
|
||||
}
|
||||
|
||||
function isEsbuildMessage(value: unknown): value is Message {
|
||||
return isRecord(value) && typeof value.text === "string" && (value.location === null || isRecord(value.location));
|
||||
}
|
||||
|
||||
function isMissingPath(error: unknown): boolean {
|
||||
return isRecord(error) && error.code === "ENOENT";
|
||||
}
|
||||
|
||||
function isRecord(value: unknown): value is Record<string, unknown> {
|
||||
return typeof value === "object" && value !== null && !Array.isArray(value);
|
||||
}
|
||||
39
third_party/pi/packages/chord/src/node/manifest.ts
vendored
Normal file
39
third_party/pi/packages/chord/src/node/manifest.ts
vendored
Normal file
@@ -0,0 +1,39 @@
|
||||
export const FACET_BUNDLE_FORMAT = "chord.facet-bundle";
|
||||
export const FACET_BUNDLE_FORMAT_VERSION = 2;
|
||||
export const FACET_BUNDLE_MANIFEST_FILE = "chord-facets.json";
|
||||
export const FACET_BUNDLE_ARTIFACT_FORMAT = "chord.facet-bundle-artifact";
|
||||
export const FACET_BUNDLE_ARTIFACT_FORMAT_VERSION = 2;
|
||||
|
||||
export interface FacetBundleEntry {
|
||||
/** Content-addressed CommonJS filename relative to the manifest. */
|
||||
readonly file: string;
|
||||
/** SHA-256 subresource-integrity value for the JavaScript file. */
|
||||
readonly integrity: string;
|
||||
/** Imports intentionally left for the loading application to resolve. */
|
||||
readonly externalImports: readonly string[];
|
||||
/** Source map filename relative to the manifest, when emitted. */
|
||||
readonly sourceMap?: string;
|
||||
}
|
||||
|
||||
export interface FacetBundleManifest {
|
||||
readonly format: typeof FACET_BUNDLE_FORMAT;
|
||||
readonly formatVersion: typeof FACET_BUNDLE_FORMAT_VERSION;
|
||||
readonly plugin: FacetBundlePlugin;
|
||||
readonly entries: Readonly<Record<string, FacetBundleEntry>>;
|
||||
}
|
||||
|
||||
export interface FacetBundlePlugin {
|
||||
readonly id: string;
|
||||
readonly version?: string;
|
||||
}
|
||||
|
||||
/** One self-contained manifest entry suitable for storage or transport to another Node host. */
|
||||
export interface FacetBundleArtifact {
|
||||
readonly format: typeof FACET_BUNDLE_ARTIFACT_FORMAT;
|
||||
readonly formatVersion: typeof FACET_BUNDLE_ARTIFACT_FORMAT_VERSION;
|
||||
readonly plugin: FacetBundlePlugin;
|
||||
readonly entryName: string;
|
||||
readonly entry: FacetBundleEntry;
|
||||
readonly source: string;
|
||||
readonly sourceMapContents?: string;
|
||||
}
|
||||
232
third_party/pi/packages/chord/src/node/package.ts
vendored
Normal file
232
third_party/pi/packages/chord/src/node/package.ts
vendored
Normal file
@@ -0,0 +1,232 @@
|
||||
import { readFile, realpath, stat } from "node:fs/promises";
|
||||
import { basename, dirname, isAbsolute, join, relative, resolve, sep } from "node:path";
|
||||
import { type BundleFacetsResult, bundleFacets } from "./bundle.ts";
|
||||
|
||||
export interface BundleFacetPackageOptions {
|
||||
/** Plugin package directory or its package.json path. */
|
||||
readonly packagePath: string;
|
||||
readonly outdir: string;
|
||||
/** Application conventions applied when the corresponding source file exists. */
|
||||
readonly defaultFacets?: Readonly<Record<string, string>>;
|
||||
}
|
||||
|
||||
export interface BundleFacetPackageResult extends BundleFacetsResult {
|
||||
readonly packageDirectory: string;
|
||||
readonly packageJsonPath: string;
|
||||
}
|
||||
|
||||
interface FacetPackageMetadata {
|
||||
readonly packageDirectory: string;
|
||||
readonly packageJsonPath: string;
|
||||
readonly name: string;
|
||||
readonly version: string;
|
||||
readonly peerDependencies: readonly string[];
|
||||
readonly configuredFacets: Readonly<Record<string, string | false>>;
|
||||
readonly external: readonly string[];
|
||||
readonly sourceMap: boolean;
|
||||
}
|
||||
|
||||
/** Build a plugin package using package.json metadata and application-provided facet conventions. */
|
||||
export async function bundleFacetPackage(options: BundleFacetPackageOptions): Promise<BundleFacetPackageResult> {
|
||||
const metadata = await readFacetPackageMetadata(options.packagePath);
|
||||
const entries = await resolveFacetEntries(metadata, options.defaultFacets ?? {});
|
||||
const external = [...metadata.peerDependencies, ...metadata.external].flatMap((specifier) => [
|
||||
specifier,
|
||||
`${specifier}/*`,
|
||||
]);
|
||||
const result = await bundleFacets({
|
||||
plugin: { id: metadata.name, version: metadata.version },
|
||||
entries,
|
||||
outdir: options.outdir,
|
||||
workingDirectory: metadata.packageDirectory,
|
||||
external,
|
||||
sourceMap: metadata.sourceMap,
|
||||
});
|
||||
return Object.freeze({
|
||||
...result,
|
||||
packageDirectory: metadata.packageDirectory,
|
||||
packageJsonPath: metadata.packageJsonPath,
|
||||
});
|
||||
}
|
||||
|
||||
async function readFacetPackageMetadata(packagePath: string): Promise<FacetPackageMetadata> {
|
||||
if (packagePath.length === 0) throw new TypeError("Facet package path must not be empty");
|
||||
const candidate = resolve(packagePath);
|
||||
let packageDirectory: string;
|
||||
let packageJsonPath: string;
|
||||
let candidateStats: Awaited<ReturnType<typeof stat>>;
|
||||
try {
|
||||
candidateStats = await stat(candidate);
|
||||
} catch (error) {
|
||||
throw new Error(`Could not access facet package ${candidate}`, { cause: error });
|
||||
}
|
||||
if (candidateStats.isDirectory()) {
|
||||
packageDirectory = await realpath(candidate);
|
||||
packageJsonPath = join(packageDirectory, "package.json");
|
||||
} else if (candidateStats.isFile() && basename(candidate) === "package.json") {
|
||||
packageJsonPath = await realpath(candidate);
|
||||
packageDirectory = dirname(packageJsonPath);
|
||||
} else {
|
||||
throw new Error(`Facet package path must name a directory or package.json: ${candidate}`);
|
||||
}
|
||||
|
||||
let parsed: unknown;
|
||||
try {
|
||||
parsed = JSON.parse(await readFile(packageJsonPath, "utf8"));
|
||||
} catch (error) {
|
||||
throw new Error(`Could not read facet package metadata ${packageJsonPath}`, { cause: error });
|
||||
}
|
||||
if (!isRecord(parsed)) throw new Error(`Facet package metadata must be an object: ${packageJsonPath}`);
|
||||
if (typeof parsed.name !== "string" || parsed.name.length === 0) {
|
||||
throw new Error(`Facet package must have a non-empty name: ${packageJsonPath}`);
|
||||
}
|
||||
if (typeof parsed.version !== "string" || parsed.version.length === 0) {
|
||||
throw new Error(`Facet package must have a non-empty version: ${packageJsonPath}`);
|
||||
}
|
||||
const peerDependencies = parsePeerDependencies(parsed.peerDependencies, packageJsonPath);
|
||||
const chord = parseChordConfiguration(parsed.chord, packageJsonPath);
|
||||
return {
|
||||
packageDirectory,
|
||||
packageJsonPath,
|
||||
name: parsed.name,
|
||||
version: parsed.version,
|
||||
peerDependencies,
|
||||
configuredFacets: chord.facets,
|
||||
external: chord.external,
|
||||
sourceMap: chord.sourceMap,
|
||||
};
|
||||
}
|
||||
|
||||
function parsePeerDependencies(value: unknown, packageJsonPath: string): readonly string[] {
|
||||
if (value === undefined) return [];
|
||||
if (
|
||||
!isRecord(value) ||
|
||||
Object.entries(value).some(([name, version]) => name.length === 0 || typeof version !== "string")
|
||||
) {
|
||||
throw new Error(`Facet package has invalid peerDependencies: ${packageJsonPath}`);
|
||||
}
|
||||
return Object.freeze(Object.keys(value).sort());
|
||||
}
|
||||
|
||||
function parseChordConfiguration(
|
||||
value: unknown,
|
||||
packageJsonPath: string,
|
||||
): {
|
||||
readonly facets: Readonly<Record<string, string | false>>;
|
||||
readonly external: readonly string[];
|
||||
readonly sourceMap: boolean;
|
||||
} {
|
||||
if (value === undefined) return { facets: Object.freeze({}), external: Object.freeze([]), sourceMap: true };
|
||||
if (!isRecord(value)) throw new Error(`Facet package chord configuration must be an object: ${packageJsonPath}`);
|
||||
if (Object.keys(value).some((key) => key !== "facets" && key !== "external" && key !== "sourceMap")) {
|
||||
throw new Error(`Facet package chord configuration has an unknown field: ${packageJsonPath}`);
|
||||
}
|
||||
const facets: Record<string, string | false> = {};
|
||||
if (value.facets !== undefined) {
|
||||
if (!isRecord(value.facets)) {
|
||||
throw new Error(`Facet package chord.facets must be an object: ${packageJsonPath}`);
|
||||
}
|
||||
for (const [name, source] of Object.entries(value.facets)) {
|
||||
if (name.length === 0 || (typeof source !== "string" && source !== false) || source === "") {
|
||||
throw new Error(`Facet package has an invalid chord.facets entry: ${packageJsonPath}`);
|
||||
}
|
||||
facets[name] = source;
|
||||
}
|
||||
}
|
||||
let external: readonly string[] = [];
|
||||
if (value.external !== undefined) {
|
||||
if (
|
||||
!Array.isArray(value.external) ||
|
||||
value.external.some((specifier) => typeof specifier !== "string" || specifier.length === 0)
|
||||
) {
|
||||
throw new Error(`Facet package chord.external must contain non-empty strings: ${packageJsonPath}`);
|
||||
}
|
||||
external = Object.freeze([...new Set(value.external as readonly string[])].sort());
|
||||
}
|
||||
if (value.sourceMap !== undefined && typeof value.sourceMap !== "boolean") {
|
||||
throw new Error(`Facet package chord.sourceMap must be a boolean: ${packageJsonPath}`);
|
||||
}
|
||||
return {
|
||||
facets: Object.freeze(facets),
|
||||
external,
|
||||
sourceMap: value.sourceMap ?? true,
|
||||
};
|
||||
}
|
||||
|
||||
async function resolveFacetEntries(
|
||||
metadata: FacetPackageMetadata,
|
||||
defaultFacets: Readonly<Record<string, string>>,
|
||||
): Promise<Readonly<Record<string, string>>> {
|
||||
const entries: Record<string, string> = {};
|
||||
for (const [name, source] of Object.entries(defaultFacets)) {
|
||||
validateFacetMapping(name, source, "default");
|
||||
const path = resolvePackageEntry(metadata.packageDirectory, source, name);
|
||||
try {
|
||||
const entryStats = await stat(path);
|
||||
if (!entryStats.isFile()) throw new Error(`Default facet entry ${name} is not a file: ${path}`);
|
||||
const canonicalPath = await realpath(path);
|
||||
validateCanonicalPackageEntry(metadata.packageDirectory, canonicalPath, name);
|
||||
entries[name] = canonicalPath;
|
||||
} catch (error) {
|
||||
if (isMissingPath(error)) continue;
|
||||
throw error;
|
||||
}
|
||||
}
|
||||
for (const [name, source] of Object.entries(metadata.configuredFacets)) {
|
||||
if (source === false) {
|
||||
delete entries[name];
|
||||
continue;
|
||||
}
|
||||
validateFacetMapping(name, source, "configured");
|
||||
const path = resolvePackageEntry(metadata.packageDirectory, source, name);
|
||||
let entryStats: Awaited<ReturnType<typeof stat>>;
|
||||
try {
|
||||
entryStats = await stat(path);
|
||||
} catch (error) {
|
||||
throw new Error(`Could not access configured facet entry ${name}: ${path}`, { cause: error });
|
||||
}
|
||||
if (!entryStats.isFile()) throw new Error(`Configured facet entry ${name} is not a file: ${path}`);
|
||||
const canonicalPath = await realpath(path);
|
||||
validateCanonicalPackageEntry(metadata.packageDirectory, canonicalPath, name);
|
||||
entries[name] = canonicalPath;
|
||||
}
|
||||
if (Object.keys(entries).length === 0) {
|
||||
throw new Error(`Facet package ${metadata.name} has no configured or conventional facet entries`);
|
||||
}
|
||||
return Object.freeze(entries);
|
||||
}
|
||||
|
||||
function validateFacetMapping(name: string, source: string, kind: string): void {
|
||||
if (name.length === 0) throw new Error(`Facet package ${kind} entry name must not be empty`);
|
||||
if (source.length === 0) throw new Error(`Facet package ${kind} entry ${name} must have a source path`);
|
||||
}
|
||||
|
||||
function resolvePackageEntry(packageDirectory: string, source: string, name: string): string {
|
||||
if (isAbsolute(source)) throw new Error(`Facet package entry ${name} must be relative to the package directory`);
|
||||
const path = resolve(packageDirectory, source);
|
||||
const relativePath = relative(packageDirectory, path);
|
||||
if (
|
||||
relativePath.length === 0 ||
|
||||
relativePath === ".." ||
|
||||
relativePath.startsWith(`..${sep}`) ||
|
||||
isAbsolute(relativePath)
|
||||
) {
|
||||
throw new Error(`Facet package entry ${name} escapes the package directory`);
|
||||
}
|
||||
return path;
|
||||
}
|
||||
|
||||
function validateCanonicalPackageEntry(packageDirectory: string, path: string, name: string): void {
|
||||
const relativePath = relative(packageDirectory, path);
|
||||
if (relativePath === ".." || relativePath.startsWith(`..${sep}`) || isAbsolute(relativePath)) {
|
||||
throw new Error(`Facet package entry ${name} resolves outside the package directory`);
|
||||
}
|
||||
}
|
||||
|
||||
function isMissingPath(error: unknown): boolean {
|
||||
return isRecord(error) && error.code === "ENOENT";
|
||||
}
|
||||
|
||||
function isRecord(value: unknown): value is Record<string, unknown> {
|
||||
return typeof value === "object" && value !== null && !Array.isArray(value);
|
||||
}
|
||||
Reference in New Issue
Block a user