@tanstack/ai-sandbox
Version:
Provider-agnostic sandbox layer for TanStack AI — run harness adapters inside isolated sandboxes (defineSandbox, defineWorkspace, withSandbox) with a uniform SandboxHandle, workspace bootstrap, policy, and resumable lifecycle.
453 lines (452 loc) • 14.6 kB
JavaScript
import { describe, expect, it } from "vitest";
//#region src/testkit/checkpoint-conformance.ts
var writers = /* @__PURE__ */ new WeakMap();
async function writerFor(store, threadId) {
let storeWriters = writers.get(store);
if (!storeWriters) {
storeWriters = /* @__PURE__ */ new Map();
writers.set(store, storeWriters);
}
let writer = storeWriters.get(threadId);
if (!writer) {
writer = store.acquireWriter(threadId);
storeWriters.set(threadId, writer);
}
return writer;
}
async function append(store, input) {
return store.append({
...input,
writer: await writerFor(store, input.checkpoint.threadId)
});
}
async function deleteHead(store, input) {
return store.deleteHead({
...input,
writer: await writerFor(store, input.threadId)
});
}
async function expectThreadState(store, staleCheckpointId, expected) {
expect(await store.getHead("thread-a")).toBe(expected.head);
expect(await store.list("thread-a")).toEqual(expected.list);
expect(await store.get(staleCheckpointId)).toEqual(expected.checkpoint);
expect(await store.listBlobReferences()).toEqual(expected.references);
}
function checkpoint(id, parentCheckpointId = null, threadId = "thread-a") {
const hash = (Number(id.replace(/\D/g, "")) || 1).toString(16).padStart(64, "0");
return {
id,
threadId,
parentCheckpointId,
createdAt: Number(id.replace(/\D/g, "")) || 1,
reason: "automatic",
files: [{
path: `${id}.txt`,
kind: "file",
blobKey: `sandbox-files/sha256/${hash}`,
size: 1
}],
conversation: [{
role: "user",
content: id
}],
artifacts: []
};
}
function runSandboxCheckpointStoreConformance(name, makeStore, options) {
describe(`SandboxCheckpointStore conformance: ${name}`, () => {
it("returns null and an empty list for an unknown thread", async () => {
const store = await makeStore(options);
expect(await store.get("missing")).toBeNull();
expect(await store.getHead("missing-thread")).toBeNull();
expect(await store.list("missing-thread")).toEqual([]);
});
it("appends a root and then a parent-linked checkpoint", async () => {
const store = await makeStore(options);
await expect(append(store, {
checkpoint: checkpoint("1"),
expectedHeadId: null
})).resolves.toEqual({ headId: "1" });
await expect(append(store, {
checkpoint: checkpoint("2", "1"),
expectedHeadId: "1"
})).resolves.toEqual({ headId: "2" });
expect(await store.getHead("thread-a")).toBe("2");
expect((await store.list("thread-a")).map((entry) => entry.id)).toEqual(["1", "2"]);
});
it("enforces expected-head and parent compare-and-swap rules", async () => {
const store = await makeStore(options);
await append(store, {
checkpoint: checkpoint("1"),
expectedHeadId: null
});
await expect(append(store, {
checkpoint: checkpoint("2"),
expectedHeadId: null
})).rejects.toMatchObject({ code: "SANDBOX_SNAPSHOT_STALE_HEAD" });
await expect(append(store, {
checkpoint: checkpoint("3"),
expectedHeadId: "1"
})).rejects.toMatchObject({ code: "SANDBOX_SNAPSHOT_PARENT_MISMATCH" });
});
it("rejects duplicate checkpoint ids", async () => {
const store = await makeStore(options);
await append(store, {
checkpoint: checkpoint("1"),
expectedHeadId: null
});
await expect(append(store, {
checkpoint: checkpoint("1"),
expectedHeadId: "1"
})).rejects.toMatchObject({ code: "SANDBOX_SNAPSHOT_DUPLICATE_ID" });
});
it("isolates checkpoints and heads by thread", async () => {
const store = await makeStore(options);
await append(store, {
checkpoint: checkpoint("a", null, "thread-a"),
expectedHeadId: null
});
await append(store, {
checkpoint: checkpoint("b", null, "thread-b"),
expectedHeadId: null
});
expect(await store.getHead("thread-a")).toBe("a");
expect(await store.getHead("thread-b")).toBe("b");
expect((await store.list("thread-a")).map((entry) => entry.id)).toEqual(["a"]);
expect((await store.list("thread-b")).map((entry) => entry.id)).toEqual(["b"]);
});
it("lists checkpoints by createdAt and then checkpoint id", async () => {
const store = await makeStore(options);
const first = {
...checkpoint("z"),
createdAt: 2
};
const second = {
...checkpoint("a", "z"),
createdAt: 1
};
const third = {
...checkpoint("b", "a"),
createdAt: 1
};
await append(store, {
checkpoint: first,
expectedHeadId: null
});
await append(store, {
checkpoint: second,
expectedHeadId: "z"
});
await append(store, {
checkpoint: third,
expectedHeadId: "a"
});
expect((await store.list("thread-a")).map((entry) => entry.id)).toEqual([
"a",
"b",
"z"
]);
});
it("orders checkpoint ids and blob keys by UTF-8 bytes", async () => {
const store = await makeStore(options);
const ids = [
"é",
"a",
"B",
"😀"
];
const keys = [
"1",
"2",
"3",
"4"
].map((value) => `sandbox-files/sha256/${value.padStart(64, "0")}`);
let parent = null;
for (const [index, id] of ids.entries()) {
const blobKey = keys[index];
if (!blobKey) throw new Error(`Missing blob key for '${id}'`);
await append(store, {
checkpoint: {
...checkpoint(id, parent),
files: [{
path: `${id}.txt`,
kind: "file",
blobKey,
size: 1
}]
},
expectedHeadId: parent
});
parent = id;
}
expect((await store.list("thread-a")).map((entry) => entry.id)).toEqual([
"B",
"a",
"é",
"😀"
]);
expect((await store.listBlobReferences()).map((entry) => entry.key)).toEqual([
`sandbox-files/sha256/${"0".repeat(63)}1`,
`sandbox-files/sha256/${"0".repeat(63)}2`,
`sandbox-files/sha256/${"0".repeat(63)}3`,
`sandbox-files/sha256/${"0".repeat(63)}4`
]);
});
it("rejects malformed Unicode checkpoint ids and blob keys", async () => {
const store = await makeStore(options);
const malformed = "\ud800";
await expect(append(store, {
checkpoint: checkpoint(malformed),
expectedHeadId: null
})).rejects.toMatchObject({ code: "SANDBOX_SNAPSHOT_INVALID_ID" });
await expect(append(store, {
checkpoint: {
...checkpoint("root"),
files: [{
path: "root.txt",
kind: "file",
blobKey: `sandbox-files/sha256/${malformed}${"0".repeat(63)}`,
size: 1
}]
},
expectedHeadId: null
})).rejects.toMatchObject({ code: "SANDBOX_SNAPSHOT_INVALID_ENTRY" });
});
it.each([
NaN,
Number.POSITIVE_INFINITY,
Number.NEGATIVE_INFINITY
])("rejects non-finite createdAt without changing state: %s", async (createdAt) => {
const store = await makeStore(options);
const before = {
head: await store.getHead("thread-a"),
list: await store.list("thread-a"),
references: await store.listBlobReferences()
};
await expect(append(store, {
checkpoint: {
...checkpoint("invalid"),
createdAt
},
expectedHeadId: null
})).rejects.toMatchObject({ code: "SANDBOX_SNAPSHOT_INVALID_ENTRY" });
expect(await store.getHead("thread-a")).toBe(before.head);
expect(await store.list("thread-a")).toEqual(before.list);
expect(await store.listBlobReferences()).toEqual(before.references);
});
it("keeps checkpoints immutable and reference counts distinct blob keys", async () => {
const store = await makeStore(options);
const value = {
...checkpoint("1"),
files: [...checkpoint("1").files, {
path: "same.txt",
kind: "file",
blobKey: `sandbox-files/sha256/${"0".repeat(63)}1`,
size: 1
}]
};
await append(store, {
checkpoint: value,
expectedHeadId: null
});
const inputFile = value.files[0];
if (!inputFile) throw new Error("Expected input file");
inputFile.path = "input-mutated";
const loaded = await store.get("1");
expect(loaded).not.toBe(value);
if (!loaded) throw new Error("Expected stored checkpoint");
const loadedFile = loaded.files[0];
if (!loadedFile) throw new Error("Expected stored file");
expect(loadedFile.path).toBe("1.txt");
loadedFile.path = "changed";
expect((await store.get("1"))?.files[0]?.path).toBe("1.txt");
const listedFile = (await store.list("thread-a"))[0]?.files[0];
if (!listedFile) throw new Error("Expected listed file");
listedFile.path = "list-mutated";
expect((await store.list("thread-a"))[0]?.files[0]?.path).toBe("1.txt");
expect(await store.listBlobReferences()).toEqual([{
key: `sandbox-files/sha256/${"0".repeat(63)}1`,
references: 1
}]);
});
it("counts one reference per checkpoint for shared blob keys", async () => {
const store = await makeStore(options);
const shared = `sandbox-files/sha256/${"f".repeat(64)}`;
await append(store, {
checkpoint: {
...checkpoint("1"),
files: [{
path: "a",
kind: "file",
blobKey: shared,
size: 1
}]
},
expectedHeadId: null
});
await append(store, {
checkpoint: {
...checkpoint("2", "1"),
files: [{
path: "b",
kind: "file",
blobKey: shared,
size: 1
}]
},
expectedHeadId: "1"
});
expect(await store.listBlobReferences()).toEqual([{
key: shared,
references: 2
}]);
await deleteHead(store, {
threadId: "thread-a",
checkpointId: "2"
});
expect(await store.listBlobReferences()).toEqual([{
key: shared,
references: 1
}]);
});
it("allows one non-waiting writer lease per thread", async () => {
const store = await makeStore(options);
const lease = await store.acquireWriter("thread-a");
try {
await expect(store.acquireWriter("thread-a")).rejects.toMatchObject({ code: "SANDBOX_SNAPSHOT_WRITER_CONFLICT" });
const secondLease = await store.acquireWriter("thread-b");
try {
expect(secondLease).toBeDefined();
} finally {
await secondLease.release();
}
} finally {
await lease.release();
}
await (await store.acquireWriter("thread-a")).release();
});
it("extends a lease when renew succeeds", async () => {
const config = options ?? {};
let current = config.now?.() ?? 1e3;
const lease = await (await makeStore({
...config,
now: () => current
})).acquireWriter("thread-a");
const originalExpiry = lease.expiresAt;
current += lease.renewAfterMs;
await expect(lease.renew()).resolves.toEqual({ expiresAt: current + (config.leaseDurationMs ?? 12e4) });
expect(lease.expiresAt).toBeGreaterThan(originalExpiry);
await lease.release();
});
it("does not let a stale lease release a replacement lease", async () => {
const config = options ?? {};
let current = config.now?.() ?? 1e3;
const store = await makeStore({
...config,
now: () => current
});
const old = await store.acquireWriter("thread-a");
current += (config.leaseDurationMs ?? 12e4) + 1;
const replacement = await store.acquireWriter("thread-a");
await old.release();
await expect(store.acquireWriter("thread-a")).rejects.toMatchObject({ code: "SANDBOX_SNAPSHOT_WRITER_CONFLICT" });
await replacement.release();
});
it("rejects stale leases after expiry takeover without changing state", async () => {
const config = options ?? {};
let current = config.now?.() ?? Date.now();
const takeoverStore = await makeStore({
...config,
now: () => current
});
const old = await takeoverStore.acquireWriter("thread-a");
await takeoverStore.append({
checkpoint: checkpoint("root"),
expectedHeadId: null,
writer: old
});
current += (config.leaseDurationMs ?? 12e4) + 1;
const beforeExpiry = {
head: await takeoverStore.getHead("thread-a"),
list: await takeoverStore.list("thread-a"),
checkpoint: await takeoverStore.get("root"),
references: await takeoverStore.listBlobReferences()
};
await expect(old.renew()).rejects.toMatchObject({ code: "SANDBOX_SNAPSHOT_WRITER_LOST" });
await expect(takeoverStore.append({
checkpoint: checkpoint("stale", "root"),
expectedHeadId: "root",
writer: old
})).rejects.toMatchObject({ code: "SANDBOX_SNAPSHOT_WRITER_LOST" });
await expectThreadState(takeoverStore, "stale", {
...beforeExpiry,
checkpoint: null
});
await expect(takeoverStore.deleteHead({
threadId: "thread-a",
checkpointId: "root",
writer: old
})).rejects.toMatchObject({ code: "SANDBOX_SNAPSHOT_WRITER_LOST" });
await expectThreadState(takeoverStore, "root", beforeExpiry);
const next = await takeoverStore.acquireWriter("thread-a");
expect(next.fence).toBeGreaterThan(old.fence);
const before = {
head: await takeoverStore.getHead("thread-a"),
list: await takeoverStore.list("thread-a"),
checkpoint: await takeoverStore.get("root"),
references: await takeoverStore.listBlobReferences()
};
await expect(old.renew()).rejects.toMatchObject({ code: "SANDBOX_SNAPSHOT_WRITER_LOST" });
await expect(takeoverStore.append({
checkpoint: checkpoint("stale", "root"),
expectedHeadId: "root",
writer: old
})).rejects.toMatchObject({ code: "SANDBOX_SNAPSHOT_WRITER_LOST" });
await expectThreadState(takeoverStore, "stale", {
...before,
checkpoint: null
});
await expect(takeoverStore.deleteHead({
threadId: "thread-a",
checkpointId: "root",
writer: old
})).rejects.toMatchObject({ code: "SANDBOX_SNAPSHOT_WRITER_LOST" });
await expectThreadState(takeoverStore, "root", before);
await old.release();
await expectThreadState(takeoverStore, "stale", {
...before,
checkpoint: null
});
await next.release();
});
it("deletes only the current head and transitions to its parent", async () => {
const store = await makeStore(options);
await append(store, {
checkpoint: checkpoint("1"),
expectedHeadId: null
});
await append(store, {
checkpoint: checkpoint("2", "1"),
expectedHeadId: "1"
});
await expect(deleteHead(store, {
threadId: "thread-a",
checkpointId: "1"
})).rejects.toMatchObject({ code: "SANDBOX_SNAPSHOT_NOT_HEAD" });
await deleteHead(store, {
threadId: "thread-a",
checkpointId: "2"
});
expect(await store.getHead("thread-a")).toBe("1");
await deleteHead(store, {
threadId: "thread-a",
checkpointId: "1"
});
expect(await store.getHead("thread-a")).toBeNull();
expect(await store.listBlobReferences()).toEqual([]);
});
});
}
//#endregion
export { runSandboxCheckpointStoreConformance };
//# sourceMappingURL=checkpoint-conformance.js.map