Payload-owner guard finds its package root from the file; refusals pinned in the decode tests

The guard test counted its package root from the compiled layout and failed under tsx and for a one-file src; it now walks up to
the package.json. The browser's non-messagepack refusal and the cache's codec-and-formatter refusal are pinned by message.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
This commit is contained in:
Meta Vens 2026-10-11 10:31:08 +02:00
commit 294469e300
4 changed files with 27 additions and 8 deletions

View file

@ -31,3 +31,9 @@ test("a payload is read by its definition's formatter, a codec's, or as a plain
// Without the definition the codec payload is its positional array, which is why a caller that holds one passes it.
assert.deepEqual(decodeDocumentPayload(undefined, encode(["a", 1])), ["a", 1]);
});
test("a definition that declares both a codec and a formatter is refused where its payload is read", () => {
const both = { ...codec, formatter: formatted.formatter } as typeof codec;
assert.throws(() => decodeDocumentPayload(both, encode(["a", 1])), (error: Error) =>
error.message === 'CultCache document type "t.codec" declares both a codec and a formatter.');
});

View file

@ -982,3 +982,8 @@ test("decodeCultNetPayload reads a payload through the formatter it is given, an
assert.deepEqual(decodeCultNetPayload<{ count: number }>(record, formatter), { count: 7 });
assert.deepEqual(decodeCultNetPayload<number[]>(record), [7]);
});
test("decodeCultNetPayload refuses a payload that is not messagepack, naming the encoding and not the payload", () => {
const record = { schemaId: "t.v0", recordKey: "k", payloadEncoding: "json", payload: encodeWireValue("secret-value") } as unknown as CultNetRawDocumentRecord;
assert.throws(() => decodeCultNetPayload(record), (error: Error) => error.message === "Unsupported CultNet document payload 'json'.");
});

View file

@ -1,6 +1,6 @@
import assert from "node:assert/strict";
import { readdirSync, readFileSync } from "node:fs";
import { join } from "node:path";
import { existsSync, readdirSync, readFileSync } from "node:fs";
import { dirname, join } from "node:path";
import { fileURLToPath } from "node:url";
import test from "node:test";
@ -10,7 +10,11 @@ import test from "node:test";
// Limits: a text scan. It reads the package's src files for the module specifier and the manifest for the dependency
// name. It does not follow a re-export from another package, a specifier assembled at run time, or a hand-written
// decoder; the dependency absence is what makes the specifier unresolvable here when the workspace does not hoist it.
const root = fileURLToPath(new URL("../../", import.meta.url));
// The package root: the nearest directory above this file (compiled or run in place) that holds a package.json.
function packageRoot(from: string): string {
return existsSync(join(from, "package.json")) ? from : packageRoot(dirname(from));
}
const root = packageRoot(dirname(fileURLToPath(import.meta.url)));
function sourceFiles(dir: string): string[] {
return readdirSync(dir, { withFileTypes: true }).flatMap((entry) =>
@ -23,7 +27,7 @@ test("no source file imports msgpack and the manifest does not list it", () => {
assert.equal(manifest[section]?.["@msgpack/msgpack"], undefined, section);
}
const files = sourceFiles(join(root, "src"));
assert.ok(files.length > 5, "fixture: the scan reads the package's sources");
assert.ok(files.length >= 1, "fixture: the scan reads the package's sources");
const offenders = files.filter((file) => /@msgpack\/msgpack/.test(readFileSync(file, "utf8")));
assert.deepEqual(offenders, []);
});

View file

@ -1,6 +1,6 @@
import assert from "node:assert/strict";
import { readdirSync, readFileSync } from "node:fs";
import { join } from "node:path";
import { existsSync, readdirSync, readFileSync } from "node:fs";
import { dirname, join } from "node:path";
import test from "node:test";
// A document payload is decoded by cultcache-ts alone (decodeDocumentPayload); every other value on a wire goes through
@ -9,7 +9,11 @@ import test from "node:test";
// Limits: a text scan. It reads the package's src files for the module specifier and the manifest for the dependency
// name. It does not follow a re-export from another package, a specifier assembled at run time, or a hand-written
// decoder; the dependency absence is what makes the specifier unresolvable here when the workspace does not hoist it.
const root = join(__dirname, "..", "..");
// The package root: the nearest directory above this file (compiled or run in place) that holds a package.json.
function packageRoot(from: string): string {
return existsSync(join(from, "package.json")) ? from : packageRoot(dirname(from));
}
const root = packageRoot(__dirname);
function sourceFiles(dir: string): string[] {
return readdirSync(dir, { withFileTypes: true }).flatMap((entry) =>
@ -22,7 +26,7 @@ test("no source file imports msgpack and the manifest does not list it", () => {
assert.equal(manifest[section]?.["@msgpack/msgpack"], undefined, section);
}
const files = sourceFiles(join(root, "src"));
assert.ok(files.length > 5, "fixture: the scan reads the package's sources");
assert.ok(files.length >= 1, "fixture: the scan reads the package's sources");
const offenders = files.filter((file) => /@msgpack\/msgpack/.test(readFileSync(file, "utf8")));
assert.deepEqual(offenders, []);
});