← Files Biological Sequence & Alignment ViewerARCHIVED FILE
src/workspace-export-publisher.test.ts
27.9 KB · Sep 30, 2026 · 23:01 UTC
import { createHash, randomUUID } from "node:crypto";
import {
link,
mkdir,
mkdtemp,
readFile,
readdir,
rename,
rm,
stat,
symlink,
utimes,
writeFile,
} from "node:fs/promises";
import os from "node:os";
import path from "node:path";
import { pathToFileURL } from "node:url";
import { afterEach, describe, expect, it } from "vitest";
import {
readWorkspaceFileBytes,
type RootsRequestExtra,
} from "./chat-file-resource";
import type { SequenceWorkbenchPayloadDeclaration } from "./workbench-persistence-protocol";
import { SequenceWorkspaceExportPublisher } from "./workspace-export-publisher";
const temporaryDirectories: Array<string> = [];
afterEach(async () => {
await Promise.all(
temporaryDirectories
.splice(0)
.map((directory) => rm(directory, { force: true, recursive: true })),
);
});
describe("SequenceWorkspaceExportPublisher", () => {
it("publishes exact bytes and path-free provenance beside the opened source", async () => {
const fixture = await createFixture();
const publisher = new SequenceWorkspaceExportPublisher({
now: () => 1_750_000_000_000,
});
await expect(
publisher.bindSession(
fixture.sessionId,
fixture.sourcePath,
fixture.extra,
),
).resolves.toBe(true);
const content = ">visible\nACGT\n";
const declaration = workspaceDeclaration(content, fixture.sessionId, {
relativePath: "exports/family-visible.fasta",
});
const plan = await publisher.prepare(declaration);
if (plan == null) throw new Error("Expected workspace plan.");
const result = await publisher.publish(
plan,
Buffer.from(content),
declaration.sha256,
new AbortController().signal,
);
expect(result).toEqual({
destination: { base: "opened-source", kind: "workspace" },
format: "fasta",
mediaType: "text/x-fasta",
name: "family-visible.fasta",
outputWorkspacePath: "data/exports/family-visible.fasta",
provenanceWorkspacePath:
"data/exports/family-visible.fasta.provenance.json",
sha256: declaration.sha256,
size: Buffer.byteLength(content),
version: 1,
});
await expect(
readFile(
path.join(fixture.projectRoot, result.outputWorkspacePath),
"utf8",
),
).resolves.toBe(content);
const provenance = await readFile(
path.join(fixture.projectRoot, result.provenanceWorkspacePath),
"utf8",
);
expect(provenance).toContain('"workspacePath": "data/family.aln-fasta"');
expect(provenance).toContain(`"sha256": "${declaration.sha256}"`);
expect(provenance).not.toContain(fixture.directory);
await expect(readFile(fixture.sourcePath, "utf8")).resolves.toBe(
fixture.sourceContent,
);
const reopened = await readWorkspaceFileBytes({
extra: fixture.extra,
filePath: result.outputWorkspacePath,
isSupportedFileName: (fileName) => fileName.endsWith(".fasta"),
maxFileBytes: 1_024 * 1_024,
viewerName: "biological sequence viewer",
});
expect(reopened.name).toBe("family-visible.fasta");
expect(reopened.bytes.toString("utf8")).toBe(content);
await expect(
publisher.revalidateCompleted(plan, result),
).resolves.toBeUndefined();
await writeFile(plan.provenancePath, "{}\n");
await expect(publisher.revalidateCompleted(plan, result)).rejects.toThrow(
"changed after publication",
);
});
it("allows parent traversal only inside the deepest bound workspace root", async () => {
const fixture = await createFixture();
const publisher = new SequenceWorkspaceExportPublisher();
await publisher.bindSession(
fixture.sessionId,
fixture.sourcePath,
rootsExtra([fixture.directory, fixture.projectRoot]),
);
const content = "motif\tstart\tend\nA\t1\t4\n";
const declaration = workspaceDeclaration(content, fixture.sessionId, {
format: "tsv",
mediaType: "text/tab-separated-values",
relativePath: "../results/motif-hits.tsv",
});
const plan = await publisher.prepare(declaration);
if (plan == null) throw new Error("Expected workspace plan.");
const result = await publisher.publish(
plan,
Buffer.from(content),
declaration.sha256,
new AbortController().signal,
);
expect(result.outputWorkspacePath).toBe("results/motif-hits.tsv");
await expect(
readFile(
path.join(fixture.projectRoot, "results/motif-hits.tsv"),
"utf8",
),
).resolves.toBe(content);
});
it("fails closed without roots or a source inside the active roots", async () => {
const fixture = await createFixture();
const publisher = new SequenceWorkspaceExportPublisher();
await expect(
publisher.bindSession(
fixture.sessionId,
fixture.sourcePath,
rootsExtra([]),
),
).resolves.toBe(false);
await expect(
publisher.prepare(workspaceDeclaration(">x\nA\n", fixture.sessionId)),
).rejects.toThrow("trusted file metadata");
const outside = await temporaryDirectory();
const outsideSource = path.join(outside, "outside.fasta");
await writeFile(outsideSource, ">outside\nA\n");
await expect(
publisher.bindSession(fixture.sessionId, outsideSource, fixture.extra),
).resolves.toBe(false);
});
it("invalidates a source binding when its exact workspace root is no longer active", async () => {
const fixture = await createFixture();
const activeRoots = [fixture.projectRoot];
const extra = rootsExtra(activeRoots);
const publisher = new SequenceWorkspaceExportPublisher();
await expect(
publisher.bindSession(fixture.sessionId, fixture.sourcePath, extra),
).resolves.toBe(true);
const bindingId = await publisher.preflight(
{
destination: {
base: "opened-source",
kind: "workspace",
relativePath: "exports/active-root.fasta",
},
format: "fasta",
name: "active-root.fasta",
sessionId: fixture.sessionId,
},
extra,
);
activeRoots.splice(0);
await expect(
publisher.assertSourceBinding(fixture.sessionId, bindingId, extra),
).rejects.toThrow("same active workspace root");
});
it("rechecks the active root inside the atomic publication lifecycle", async () => {
const fixture = await createFixture();
const activeRoots = [fixture.projectRoot];
const extra = rootsExtra(activeRoots);
const publisher = new SequenceWorkspaceExportPublisher({
atomicHooks: {
beforeArtifactLink: () => {
activeRoots.splice(0);
},
},
});
await publisher.bindSession(fixture.sessionId, fixture.sourcePath, extra);
const content = ">out\nAC\n";
const declaration = workspaceDeclaration(content, fixture.sessionId);
const plan = await publisher.prepare(
declaration,
new AbortController().signal,
extra,
);
if (plan == null) throw new Error("Expected workspace plan.");
await expect(
publisher.publish(
plan,
Buffer.from(content),
declaration.sha256,
new AbortController().signal,
extra,
),
).rejects.toThrow("same active workspace root");
await expect(readFile(plan.outputPath)).rejects.toMatchObject({
code: "ENOENT",
});
await expect(readFile(plan.provenancePath)).rejects.toMatchObject({
code: "ENOENT",
});
});
it("rejects escape, missing or linked parents, collisions, and format mismatches", async () => {
const fixture = await createFixture();
const publisher = new SequenceWorkspaceExportPublisher();
await publisher.bindSession(
fixture.sessionId,
fixture.sourcePath,
fixture.extra,
);
await expect(
publisher.prepare(
workspaceDeclaration(">x\nA\n", fixture.sessionId, {
relativePath: "../../../escape.fasta",
}),
),
).rejects.toThrow("escapes");
await expect(
publisher.prepare(
workspaceDeclaration(">x\nA\n", fixture.sessionId, {
relativePath: "missing/export.fasta",
}),
),
).rejects.toThrow("must already exist");
await expect(
publisher.prepare(
workspaceDeclaration(">x\nA\n", fixture.sessionId, {
relativePath: "exports/export.csv",
}),
),
).rejects.toThrow("does not match fasta");
const existing = path.join(
fixture.projectRoot,
"data/exports/existing.fasta",
);
await writeFile(existing, "sentinel");
await expect(
publisher.prepare(
workspaceDeclaration(">x\nA\n", fixture.sessionId, {
relativePath: "exports/existing.fasta",
}),
),
).rejects.toThrow("already exists");
const linked = path.join(fixture.projectRoot, "data/linked");
await symlink(
path.resolve(fixture.projectRoot, "results"),
linked,
process.platform === "win32" ? "junction" : "dir",
);
await expect(
publisher.prepare(
workspaceDeclaration(">x\nA\n", fixture.sessionId, {
relativePath: "linked/export.fasta",
}),
),
).rejects.toThrow(/symbolic links|junctions/u);
});
it("detects source changes and leaves no partial pair", async () => {
const fixture = await createFixture();
let mutate = false;
const publisher = new SequenceWorkspaceExportPublisher({
atomicHooks: {
beforeArtifactLink: async () => {
if (mutate) await writeFile(fixture.sourcePath, ">changed\nTT\n");
},
},
});
await publisher.bindSession(
fixture.sessionId,
fixture.sourcePath,
fixture.extra,
);
const declaration = workspaceDeclaration(">out\nAA\n", fixture.sessionId);
const plan = await publisher.prepare(declaration);
if (plan == null) throw new Error("Expected workspace plan.");
mutate = true;
await expect(
publisher.publish(
plan,
Buffer.from(">out\nAA\n"),
declaration.sha256,
new AbortController().signal,
),
).rejects.toThrow("changed");
await expect(readFile(plan.outputPath)).rejects.toMatchObject({
code: "ENOENT",
});
await expect(readFile(plan.provenancePath)).rejects.toMatchObject({
code: "ENOENT",
});
});
it("detects an in-place source rewrite even when size and mtime are restored", async () => {
const fixture = await createFixture();
const publisher = new SequenceWorkspaceExportPublisher();
await publisher.bindSession(
fixture.sessionId,
fixture.sourcePath,
fixture.extra,
);
const declaration = workspaceDeclaration(">out\nAA\n", fixture.sessionId);
const plan = await publisher.prepare(declaration);
if (plan == null) throw new Error("Expected workspace plan.");
const originalStat = await stat(fixture.sourcePath);
await writeFile(fixture.sourcePath, ">mutate\nTGCA\n");
await utimes(fixture.sourcePath, originalStat.atime, originalStat.mtime);
await expect(publisher.assertPlanCurrent(plan)).rejects.toThrow("changed");
});
it("detects a same-content target swap before committing provenance", async () => {
const fixture = await createFixture();
let artifactPath = "";
const publisher = new SequenceWorkspaceExportPublisher({
atomicHooks: {
beforeSidecarLink: async () => {
const bytes = await readFile(artifactPath);
await rm(artifactPath);
await writeFile(artifactPath, bytes);
},
},
});
await publisher.bindSession(
fixture.sessionId,
fixture.sourcePath,
fixture.extra,
);
const content = ">swapped\nAC\n";
const declaration = workspaceDeclaration(content, fixture.sessionId, {
relativePath: "exports/swapped.fasta",
});
const plan = await publisher.prepare(declaration);
if (plan == null) throw new Error("Expected workspace plan.");
artifactPath = plan.outputPath;
await expect(
publisher.publish(
plan,
Buffer.from(content),
declaration.sha256,
new AbortController().signal,
),
).rejects.toThrow("target changed during commit");
await expect(readFile(plan.outputPath, "utf8")).resolves.toBe(content);
await expect(readFile(plan.provenancePath)).rejects.toMatchObject({
code: "ENOENT",
});
});
it("rejects hardlink aliases and publishes exactly once under races", async () => {
const fixture = await createFixture();
const publisher = new SequenceWorkspaceExportPublisher();
await publisher.bindSession(
fixture.sessionId,
fixture.sourcePath,
fixture.extra,
);
const alias = path.join(fixture.projectRoot, "data/exports/alias.fasta");
await link(fixture.sourcePath, alias);
await expect(
publisher.prepare(
workspaceDeclaration(">x\nA\n", fixture.sessionId, {
relativePath: "exports/alias.fasta",
}),
),
).rejects.toThrow(/changed|already exists/u);
await rm(alias);
await expect(
publisher.bindSession(
fixture.sessionId,
fixture.sourcePath,
fixture.extra,
),
).resolves.toBe(true);
const content = ">race\nAC\n";
const declaration = workspaceDeclaration(content, fixture.sessionId, {
relativePath: "exports/race.fasta",
});
const [firstPlan, secondPlan] = await Promise.all([
publisher.prepare(declaration),
publisher.prepare({ ...declaration, uploadId: randomUUID() }),
]);
if (firstPlan == null || secondPlan == null) {
throw new Error("Expected workspace plans.");
}
const settled = await Promise.allSettled([
publisher.publish(
firstPlan,
Buffer.from(content),
declaration.sha256,
new AbortController().signal,
),
publisher.publish(
secondPlan,
Buffer.from(content),
declaration.sha256,
new AbortController().signal,
),
]);
expect(settled.filter(({ status }) => status === "fulfilled")).toHaveLength(
1,
);
expect(settled.filter(({ status }) => status === "rejected")).toHaveLength(
1,
);
expect(settled.find(({ status }) => status === "rejected")).toMatchObject({
reason: expect.objectContaining({
message: expect.stringContaining("already exists"),
}),
});
});
it("publishes concurrent exports to distinct destinations independently", async () => {
const fixture = await createFixture();
const publisher = new SequenceWorkspaceExportPublisher();
await publisher.bindSession(
fixture.sessionId,
fixture.sourcePath,
fixture.extra,
);
const firstContent = ">first\nAC\n";
const secondContent = ">second\nGT\n";
const firstDeclaration = workspaceDeclaration(
firstContent,
fixture.sessionId,
{ relativePath: "exports/first.fasta" },
);
const secondDeclaration = workspaceDeclaration(
secondContent,
fixture.sessionId,
{ relativePath: "exports/second.fasta" },
);
const [firstPlan, secondPlan] = await Promise.all([
publisher.prepare(firstDeclaration),
publisher.prepare(secondDeclaration),
]);
if (firstPlan == null || secondPlan == null) {
throw new Error("Expected workspace plans.");
}
const [firstResult, secondResult] = await Promise.all([
publisher.publish(
firstPlan,
Buffer.from(firstContent),
firstDeclaration.sha256,
new AbortController().signal,
),
publisher.publish(
secondPlan,
Buffer.from(secondContent),
secondDeclaration.sha256,
new AbortController().signal,
),
]);
expect(firstResult.outputWorkspacePath).toBe("data/exports/first.fasta");
expect(secondResult.outputWorkspacePath).toBe("data/exports/second.fasta");
await expect(readFile(firstPlan.outputPath, "utf8")).resolves.toBe(
firstContent,
);
await expect(readFile(secondPlan.outputPath, "utf8")).resolves.toBe(
secondContent,
);
});
it("lists bounded source-relative pages, rejects stale cursors, and omits links", async () => {
const fixture = await createFixture();
await Promise.all([
writeFile(path.join(fixture.projectRoot, "data/a.txt"), "a"),
writeFile(path.join(fixture.projectRoot, "data/b.txt"), "bb"),
]);
await symlink(
path.resolve(fixture.projectRoot, "results"),
path.join(fixture.projectRoot, "data/linked-results"),
process.platform === "win32" ? "junction" : "dir",
);
const publisher = new SequenceWorkspaceExportPublisher();
await publisher.bindSession(
fixture.sessionId,
fixture.sourcePath,
fixture.extra,
);
const first = await publisher.listDirectory(
{
candidate: { format: "fasta", name: "derived.fasta" },
directory: ".",
limit: 2,
sessionId: fixture.sessionId,
},
fixture.extra,
);
expect(first.entries).toEqual([
{ kind: "file", name: "a.txt", relativePath: "a.txt", size: 1 },
{ kind: "file", name: "b.txt", relativePath: "b.txt", size: 2 },
]);
expect(first.nextCursor).toEqual(expect.any(String));
expect(first.omittedEntries).toBe(1);
expect(first.directory).toMatchObject({
breadcrumbs: [
{ label: "Workspace", relativePath: "..", workspacePath: "." },
{ label: "data", relativePath: ".", workspacePath: "data" },
],
parentRelativePath: "..",
relativePath: ".",
sourceDirectoryWorkspacePath: "data",
workspacePath: "data",
});
expect(first.candidate).toEqual({
exactAvailable: true,
exactWorkspacePath: "data/derived.fasta",
name: "derived.fasta",
nextVersionName: "derived.fasta",
nextVersionWorkspacePath: "data/derived.fasta",
});
expect(JSON.stringify(first)).not.toContain(fixture.directory);
const second = await publisher.listDirectory({
cursor: first.nextCursor,
directory: ".",
limit: 2,
sessionId: fixture.sessionId,
});
expect(second.entries.map(({ name }) => name)).toEqual([
"exports",
"family.aln-fasta",
]);
await writeFile(path.join(fixture.projectRoot, "data/changed.txt"), "new");
await expect(
publisher.listDirectory({
cursor: first.nextCursor,
directory: ".",
limit: 2,
sessionId: fixture.sessionId,
}),
).rejects.toThrow("stale or invalid");
await expect(
publisher.listDirectory({
directory: "../../..",
limit: 10,
sessionId: fixture.sessionId,
}),
).rejects.toThrow("escapes");
});
it("creates one child exclusively and rolls it back when the root binding changes", async () => {
const fixture = await createFixture();
const publisher = new SequenceWorkspaceExportPublisher();
await publisher.bindSession(
fixture.sessionId,
fixture.sourcePath,
fixture.extra,
);
await expect(
publisher.createDirectory(
{
name: "analysis",
parentDirectory: ".",
sessionId: fixture.sessionId,
},
fixture.extra,
),
).resolves.toEqual({
name: "analysis",
relativePath: "analysis",
workspacePath: "data/analysis",
});
await expect(
publisher.createDirectory({
name: "analysis",
parentDirectory: ".",
sessionId: fixture.sessionId,
}),
).rejects.toThrow("already exists");
const activeRoots = [fixture.projectRoot];
let rootRequests = 0;
const changingExtra = {
async sendRequest() {
rootRequests += 1;
return {
roots:
rootRequests < 3
? activeRoots.map((root) => ({ uri: pathToFileURL(root).href }))
: [],
};
},
} as RootsRequestExtra;
const changingPublisher = new SequenceWorkspaceExportPublisher();
await changingPublisher.bindSession(
fixture.sessionId,
fixture.sourcePath,
changingExtra,
);
await expect(
changingPublisher.createDirectory(
{
name: "rolled-back",
parentDirectory: ".",
sessionId: fixture.sessionId,
},
changingExtra,
),
).rejects.toThrow("same active workspace root");
await expect(
readdir(path.join(fixture.projectRoot, "data")),
).resolves.not.toContain("rolled-back");
});
it("selects deterministic versions and fails after the bounded candidate set", async () => {
const fixture = await createFixture();
const publisher = new SequenceWorkspaceExportPublisher();
await publisher.bindSession(
fixture.sessionId,
fixture.sourcePath,
fixture.extra,
);
const exportsDirectory = path.join(fixture.projectRoot, "data/exports");
await Promise.all([
writeFile(path.join(exportsDirectory, "version.fasta"), "occupied"),
writeFile(
path.join(exportsDirectory, "version-2.fasta.provenance.json"),
"occupied",
),
]);
const content = ">versioned\nAC\n";
const declaration = workspaceDeclaration(content, fixture.sessionId, {
collisionPolicy: "next-version",
relativePath: "exports/version.fasta",
});
const plan = await publisher.prepare(declaration);
if (plan == null) throw new Error("Expected workspace plan.");
expect(plan.name).toBe("version-3.fasta");
const result = await publisher.publish(
plan,
Buffer.from(content),
declaration.sha256,
new AbortController().signal,
);
expect(result.outputWorkspacePath).toBe("data/exports/version-3.fasta");
await Promise.all(
Array.from({ length: 100 }, (_, index) => {
const suffix = index === 0 ? "" : `-${index + 1}`;
return writeFile(
path.join(exportsDirectory, `exhausted${suffix}.fasta`),
"occupied",
);
}),
);
await expect(
publisher.prepare(
workspaceDeclaration(content, fixture.sessionId, {
collisionPolicy: "next-version",
relativePath: "exports/exhausted.fasta",
}),
),
).rejects.toThrow("within 100 attempts");
});
it("publishes simultaneous next-version saves without overwriting either pair", async () => {
const fixture = await createFixture();
const publisher = new SequenceWorkspaceExportPublisher();
await publisher.bindSession(
fixture.sessionId,
fixture.sourcePath,
fixture.extra,
);
const content = ">race\nAC\n";
const declaration = workspaceDeclaration(content, fixture.sessionId, {
collisionPolicy: "next-version",
relativePath: "exports/concurrent.fasta",
});
const [firstPlan, secondPlan] = await Promise.all([
publisher.prepare(declaration),
publisher.prepare({ ...declaration, uploadId: randomUUID() }),
]);
if (firstPlan == null || secondPlan == null) {
throw new Error("Expected workspace plans.");
}
const results = await Promise.all([
publisher.publish(
firstPlan,
Buffer.from(content),
declaration.sha256,
new AbortController().signal,
),
publisher.publish(
secondPlan,
Buffer.from(content),
declaration.sha256,
new AbortController().signal,
),
]);
expect(
results.map(({ outputWorkspacePath }) => outputWorkspacePath).sort(),
).toEqual([
"data/exports/concurrent-2.fasta",
"data/exports/concurrent.fasta",
]);
for (const result of results) {
await expect(
readFile(
path.join(fixture.projectRoot, result.outputWorkspacePath),
"utf8",
),
).resolves.toBe(content);
await expect(
readFile(
path.join(fixture.projectRoot, result.provenanceWorkspacePath),
"utf8",
),
).resolves.toContain(result.outputWorkspacePath);
}
});
it("rolls back an artifact-side race before retrying the next version", async () => {
const fixture = await createFixture();
let firstSidecarPath = "";
let injectCollision = true;
const publisher = new SequenceWorkspaceExportPublisher({
atomicHooks: {
beforeSidecarLink: async () => {
if (!injectCollision) return;
injectCollision = false;
await writeFile(firstSidecarPath, "external-sentinel");
},
},
});
await publisher.bindSession(
fixture.sessionId,
fixture.sourcePath,
fixture.extra,
);
const content = ">rollback\nAC\n";
const declaration = workspaceDeclaration(content, fixture.sessionId, {
collisionPolicy: "next-version",
relativePath: "exports/rollback.fasta",
});
const plan = await publisher.prepare(declaration);
if (plan == null) throw new Error("Expected workspace plan.");
firstSidecarPath = plan.provenancePath;
const result = await publisher.publish(
plan,
Buffer.from(content),
declaration.sha256,
new AbortController().signal,
);
expect(result.outputWorkspacePath).toBe("data/exports/rollback-2.fasta");
await expect(
readFile(path.join(fixture.projectRoot, "data/exports/rollback.fasta")),
).rejects.toMatchObject({ code: "ENOENT" });
await expect(readFile(firstSidecarPath, "utf8")).resolves.toBe(
"external-sentinel",
);
});
it("rejects a root identity swap before publication", async () => {
const fixture = await createFixture();
const publisher = new SequenceWorkspaceExportPublisher();
await publisher.bindSession(
fixture.sessionId,
fixture.sourcePath,
fixture.extra,
);
const declaration = workspaceDeclaration(">out\nA\n", fixture.sessionId);
const plan = await publisher.prepare(declaration);
if (plan == null) throw new Error("Expected workspace plan.");
const moved = `${fixture.projectRoot}-moved`;
await rename(fixture.projectRoot, moved);
await mkdir(fixture.projectRoot);
await expect(publisher.assertPlanCurrent(plan)).rejects.toThrow(
/source or root/u,
);
});
});
async function createFixture() {
const directory = await temporaryDirectory();
const projectRoot = path.join(directory, "project");
const sourceDirectory = path.join(projectRoot, "data");
await Promise.all([
mkdir(path.join(sourceDirectory, "exports"), { recursive: true }),
mkdir(path.join(projectRoot, "results"), { recursive: true }),
]);
const sourcePath = path.join(sourceDirectory, "family.aln-fasta");
const sourceContent = ">source\nACGT\n";
await writeFile(sourcePath, sourceContent);
return {
directory,
extra: rootsExtra([projectRoot]),
projectRoot,
sessionId: randomUUID(),
sourceContent,
sourcePath,
};
}
function rootsExtra(roots: Array<string>): RootsRequestExtra {
return {
async sendRequest() {
return {
roots: roots.map((root) => ({ uri: pathToFileURL(root).href })),
};
},
} as RootsRequestExtra;
}
function workspaceDeclaration(
content: string,
sessionId: string,
overrides: {
collisionPolicy?: "exact" | "next-version";
format?: SequenceWorkbenchPayloadDeclaration["format"];
mediaType?: string;
relativePath?: string;
} = {},
): SequenceWorkbenchPayloadDeclaration {
const relativePath = overrides.relativePath ?? "exports/output.fasta";
return {
byteLength: Buffer.byteLength(content),
callerId: randomUUID(),
commandId: randomUUID(),
destination: {
base: "opened-source",
kind: "workspace",
relativePath,
...(overrides.collisionPolicy == null
? {}
: { collisionPolicy: overrides.collisionPolicy }),
},
format: overrides.format ?? "fasta",
kind: "artifact",
mediaType: overrides.mediaType ?? "text/x-fasta",
name: relativePath.split("/").at(-1) ?? "output.fasta",
provenance: {
engine: "sequence-viewer-export-v1",
parameters: { scope: "visible" },
sourceRevision: 7,
},
sessionId,
sha256: createHash("sha256").update(content).digest("hex"),
uploadId: randomUUID(),
};
}
async function temporaryDirectory(): Promise<string> {
const directory = await mkdtemp(
path.join(os.tmpdir(), "sequence-workspace-export-"),
);
temporaryDirectories.push(directory);
return directory;
}
SHA-256: 89b00d1a8326866dd074bff1e11845d250119717d7e5753a5b5941317eee4cfa